Files
sdk/pkg/front_end/test/patching/patching_test.dart
T
Johnni Winther 23d70f6f23 Reland: [cfe] Embed and use allowed experiments in CFE
This CL embeds the sdk_nnbd/lib/_internal/allowed_experiments.json
into the CFE and uses this to allow experiments enabled on a
per library basis. The file is embedded through generated code to
avoid reliance on access to the file itself.

A presubmit check is also added to ensure that the json file and
the generated code are in sync.

This work is in preparation for https://github.com/dart-lang/sdk/issues/41538

This was reverted in https://dart-review.googlesource.com/c/sdk/+/149620
because flutter wasn't prepared for auto-enabling nnbd in dart:* libraries.
This has now been fixed in https://github.com/flutter/engine/pull/18714

Closes #42162

Change-Id: I686ed6feaef8ee066b426068fe2a0f5080bf1713
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/149588
Reviewed-by: Jens Johansen <jensj@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
2020-06-03 08:15:49 +00:00

184 lines
6.2 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/id.dart' show ActualData, Id;
import 'package:_fe_analyzer_shared/src/testing/id_testing.dart'
show DataInterpreter, runTests;
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/class_builder.dart';
import 'package:front_end/src/fasta/builder/member_builder.dart';
import 'package:_fe_analyzer_shared/src/testing/features.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';
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'),
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,
experimentalFlags: experimentalFlags,
allowedExperimentalFlags: allowedExperimentalFlags);
@override
void customizeCompilerOptions(CompilerOptions options, TestData testData) {
options.currentSdkVersion = "2.9999";
}
}
class PatchingDataComputer extends DataComputer<Features> {
const PatchingDataComputer();
@override
void computeMemberData(
TestConfig config,
InternalCompilerResult compilerResult,
Member member,
Map<Id, ActualData<Features>> actualMap,
{bool verbose}) {
member.accept(new PatchingDataExtractor(compilerResult, actualMap));
}
@override
void computeClassData(
TestConfig config,
InternalCompilerResult compilerResult,
Class cls,
Map<Id, ActualData<Features>> actualMap,
{bool verbose}) {
new PatchingDataExtractor(compilerResult, actualMap).computeForClass(cls);
}
@override
void computeLibraryData(
TestConfig config,
InternalCompilerResult compilerResult,
Library library,
Map<Id, ActualData<Features>> actualMap,
{bool verbose}) {
new PatchingDataExtractor(compilerResult, actualMap)
.computeForLibrary(library);
}
@override
bool get supportsErrors => true;
@override
Features computeErrorData(TestConfig config, InternalCompilerResult compiler,
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';
}
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) {
ClassBuilder clsBuilder = lookupClassBuilder(compilerResult, cls);
Features features = new Features();
clsBuilder.scope.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.name;
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);
}
}
MemberBuilderImpl memberBuilder =
lookupMemberBuilder(compilerResult, member, required: false);
MemberBuilder patchMember = memberBuilder?.dataForTesting?.patchForTesting;
if (patchMember != null) {
features.add(Tags.patch);
}
return features;
}
}