blob: 52077eaeadcd3a81742fe43b21c7a0df1c4e8c47 [file] [log] [blame]
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:io' show Directory, Platform;
import 'package:_fe_analyzer_shared/src/testing/features.dart';
import 'package:_fe_analyzer_shared/src/testing/id.dart';
import 'package:_fe_analyzer_shared/src/testing/id_testing.dart'
show DataInterpreter, ddcMarker, runTests;
import 'package:front_end/src/api_prototype/experimental_flags.dart' as fe;
import 'package:kernel/ast.dart';
import 'package:kernel/dart_scope_calculator.dart';
import 'package:kernel/src/printer.dart' show AstPrinter, AstTextStrategy;
import '../id_testing_helper.dart';
Future<void> main(List<String> args) async {
var dataDir = Directory.fromUri(
Platform.script.resolve('../../../front_end/test/scopes/data'),
);
await runTests<Features>(
dataDir,
args: args,
createUriForFileName: createUriForFileName,
onFailure: onFailure,
runTest: runTestFor(const ScopeDataComputer(), [
DdcTestConfig(
ddcMarker,
'ddc',
experimentalFlags: {fe.ExperimentalFlag.inlineClass: true},
),
]),
);
}
class Tags {
static const String cls = 'class';
static const String member = 'member';
static const String isStatic = 'static';
static const String typeParameter = 'typeParameters';
static const String variables = 'variables';
}
class ScopeDataComputer extends DdcDataComputer<Features> {
const ScopeDataComputer();
@override
void computeMemberData(
DdcTestResultData testResultData,
Member member,
Map<Id, ActualData<Features>> actualMap, {
bool? verbose,
}) {
member.accept(
ScopeDataExtractor(
member.enclosingLibrary,
testResultData.compilerResult,
actualMap,
),
);
}
@override
DataInterpreter<Features> get dataValidator =>
const FeaturesDataInterpreter();
}
class ScopeDataExtractor extends DdcDataExtractor<Features> {
final Library library;
ScopeDataExtractor(this.library, super.compilerResult, super.actualMap);
Component get component => compilerResult.ddcResult.component;
@override
Features? computeNodeValue(Id id, TreeNode node) {
// We use references to a static variable 'x' as the marker for where we
// want to compute the scope.
if (node is StaticGet && node.target.name.text == 'x') {
var location = node.location;
if (location != null) {
final offset = component.getOffset(
library.fileUri,
location.line,
location.column,
);
var scope = DartScopeBuilder2.findScopeFromOffset(
library,
library.fileUri,
offset,
);
var features = Features();
if (scope.cls != null) {
features[Tags.cls] = scope.cls!.name;
}
if (scope.member != null) {
features[Tags.member] = scope.member!.name.text;
}
if (scope.isStatic) {
features.add(Tags.isStatic);
}
for (var typeParameter in scope.typeParameters) {
var printer = AstPrinter(
const AstTextStrategy(
useQualifiedTypeParameterNames: true,
useQualifiedTypeParameterNamesRecurseOnNamedLocalFunctions: true,
includeLibraryNamesInTypes: false,
),
);
printer.writeTypeParameterName(typeParameter);
features.addElement(Tags.typeParameter, printer.getText());
}
for (var variable in scope.variables.keys) {
features.addElement(Tags.variables, variable);
}
return features;
}
}
return super.computeNodeValue(id, node);
}
}