Files
sdk/pkg/front_end/test/patching/patching_test.dart
T
Johnni Winther 8ba4a714a5 [cfe] Replace Scope.forEach with iterators
Scope.forEach iterates through the builder immediately mapped in the
scope. For duplicate declarations, this means that it'll give direct access to the last defined declaration and not to the first defined
declaration, which is inconsistent with how we generally handle
duplications. It also doesn't skip builders that are not "owned" by
the scope but merely accessible, which means that we easily have
duplicate handling of patches and augmentations which are part of
both the scope in which the were declared and the scope of the origin.

To normalize the handle of scope, this CL removes Scope.forEach
with iterators that explicit filter what subset of the builder
that we want to have access to. This prepares for the more complex
scope introduced by the augmentation libraries in which all
scopes have access to all declarations from the origin library as
well as other augmentation libraries.

Change-Id: I88bdfb1068fbb4eb9dd6fa3881b86a61104e50e3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/255240
Reviewed-by: Jens Johansen <jensj@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
2022-08-17 12:21:03 +00:00

198 lines
7.0 KiB
Dart

// Copyright (c) 2019, 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' show ActualData, Id;
import 'package:_fe_analyzer_shared/src/testing/id_testing.dart';
import 'package:front_end/src/api_prototype/compiler_options.dart';
import 'package:front_end/src/api_prototype/experimental_flags.dart';
import 'package:front_end/src/fasta/builder/builder.dart';
import 'package:front_end/src/fasta/builder/member_builder.dart';
import 'package:front_end/src/fasta/source/source_class_builder.dart';
import 'package:front_end/src/fasta/source/source_constructor_builder.dart';
import 'package:front_end/src/fasta/source/source_factory_builder.dart';
import 'package:front_end/src/fasta/source/source_member_builder.dart';
import 'package:front_end/src/fasta/source/source_procedure_builder.dart';
import 'package:front_end/src/fasta/scope.dart';
import 'package:front_end/src/testing/id_testing_helper.dart';
import 'package:front_end/src/testing/id_testing_utils.dart';
import 'package:kernel/ast.dart';
Future<void> main(List<String> args) async {
Directory dataDir = new Directory.fromUri(Platform.script.resolve('data'));
await runTests<Features>(dataDir,
args: args,
createUriForFileName: createUriForFileName,
onFailure: onFailure,
runTest: runTestFor(const PatchingDataComputer(), [
new TestConfigWithLanguageVersion(
cfeMarker, 'cfe with libraries specification',
librariesSpecificationUri: createUriForFileName('libraries.json'),
experimentalFlags: {ExperimentalFlag.nonNullable: false},
allowedExperimentalFlags: const AllowedExperimentalFlags()),
new TestConfigWithLanguageVersion(cfeWithNnbdMarker,
'cfe with libraries specification and non-nullable',
librariesSpecificationUri: createUriForFileName('libraries.json'),
experimentalFlags: {ExperimentalFlag.nonNullable: true},
allowedExperimentalFlags: const AllowedExperimentalFlags())
]),
skipMap: {
cfeMarker: [
'opt_in',
'opt_in_patch',
'opt_out',
'opt_out_patch',
]
});
}
class TestConfigWithLanguageVersion extends TestConfig {
TestConfigWithLanguageVersion(String marker, String name,
{Uri? librariesSpecificationUri,
Map<ExperimentalFlag, bool> experimentalFlags = const {},
AllowedExperimentalFlags? allowedExperimentalFlags})
: super(marker, name,
librariesSpecificationUri: librariesSpecificationUri,
explicitExperimentalFlags: experimentalFlags,
allowedExperimentalFlags: allowedExperimentalFlags);
@override
void customizeCompilerOptions(CompilerOptions options, TestData testData) {
options.currentSdkVersion = "2.9999";
}
}
class PatchingDataComputer extends DataComputer<Features> {
const PatchingDataComputer();
@override
void computeMemberData(TestResultData testResultData, Member member,
Map<Id, ActualData<Features>> actualMap,
{bool? verbose}) {
member.accept(
new PatchingDataExtractor(testResultData.compilerResult, actualMap));
}
@override
void computeClassData(TestResultData testResultData, Class cls,
Map<Id, ActualData<Features>> actualMap,
{bool? verbose}) {
new PatchingDataExtractor(testResultData.compilerResult, actualMap)
.computeForClass(cls);
}
@override
void computeLibraryData(TestResultData testResultData, Library library,
Map<Id, ActualData<Features>> actualMap,
{bool? verbose}) {
new PatchingDataExtractor(testResultData.compilerResult, actualMap)
.computeForLibrary(library);
}
@override
bool get supportsErrors => true;
@override
Features computeErrorData(
TestResultData testResultData, Id id, List<FormattedMessage> errors) {
Features features = new Features();
features[Tags.error] = errorsToText(errors);
return features;
}
@override
DataInterpreter<Features> get dataValidator =>
const FeaturesDataInterpreter();
}
class Tags {
static const String scope = 'scope';
static const String kernelMembers = 'kernel-members';
static const String initializers = 'initializers';
static const String error = 'message';
static const String isNonNullableByDefault = 'nnbd';
static const String patch = 'patch';
static const String isAbstract = 'isAbstract';
}
class PatchingDataExtractor extends CfeDataExtractor<Features> {
PatchingDataExtractor(InternalCompilerResult compilerResult,
Map<Id, ActualData<Features>> actualMap)
: super(compilerResult, actualMap);
@override
Features computeLibraryValue(Id id, Library library) {
Features features = new Features();
features[Tags.isNonNullableByDefault] = '${library.isNonNullableByDefault}';
return features;
}
@override
Features computeClassValue(Id id, Class cls) {
SourceClassBuilder clsBuilder =
lookupClassBuilder(compilerResult, cls) as SourceClassBuilder;
Features features = new Features();
if (cls.isAbstract) {
features.add(Tags.isAbstract);
}
clsBuilder.scope
.filteredNameIterator(
includeDuplicates: false, includeAugmentations: false)
.forEach((String name, Builder builder) {
features.addElement(Tags.scope, name);
});
for (Member m in clsBuilder.actualCls.members) {
if (m is Procedure &&
(m.isMemberSignature ||
(m.isForwardingStub && !m.isForwardingSemiStub))) {
// Don't include member signatures.
continue;
}
String name = m.name.text;
if (m is Constructor) {
name = '${m.enclosingClass.name}.${name}';
}
features.addElement(Tags.kernelMembers, name);
}
return features;
}
@override
Features computeMemberValue(Id id, Member member) {
Features features = new Features();
if (member is Constructor) {
for (Initializer initializer in member.initializers) {
String desc = initializer.runtimeType.toString();
if (initializer is FieldInitializer) {
desc = 'FieldInitializer(${getMemberName(initializer.field)})';
}
features.addElement(Tags.initializers, desc);
}
}
SourceMemberBuilder? memberBuilder =
lookupMemberBuilder(compilerResult, member, required: false)
as SourceMemberBuilder?;
List<MemberBuilder>? patchMembers;
if (memberBuilder is SourceProcedureBuilder) {
patchMembers = memberBuilder.patchesForTesting;
}
if (memberBuilder is DeclaredSourceConstructorBuilder) {
patchMembers = memberBuilder.patchesForTesting;
}
if (memberBuilder is SourceFactoryBuilder) {
patchMembers = memberBuilder.patchesForTesting;
}
if (patchMembers != null) {
features.add(Tags.patch);
}
return features;
}
}