blob: 83e5bbf52913aee2c856bbd1c3efd69cbc9ce0a7 [file] [log] [blame]
// 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';
import 'package:_fe_analyzer_shared/src/testing/id_testing.dart';
import 'package:front_end/src/api_prototype/experimental_flags.dart';
import 'package:front_end/src/fasta/builder/class_builder.dart';
import 'package:front_end/src/fasta/builder/extension_builder.dart';
import 'package:front_end/src/fasta/builder/formal_parameter_builder.dart';
import 'package:front_end/src/fasta/builder/library_builder.dart';
import 'package:front_end/src/fasta/builder/member_builder.dart';
import 'package:front_end/src/fasta/builder/type_builder.dart';
import 'package:front_end/src/fasta/builder/type_variable_builder.dart';
import 'package:front_end/src/fasta/source/source_function_builder.dart';
import 'package:front_end/src/fasta/source/source_library_builder.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 ExtensionsDataComputer(), [
new TestConfig(cfeMarker, 'cfe',
librariesSpecificationUri: createUriForFileName('libraries.json'),
allowedExperimentalFlags: const AllowedExperimentalFlags())
]));
}
class ExtensionsDataComputer extends DataComputer<Features> {
const ExtensionsDataComputer();
@override
void computeMemberData(
TestConfig config,
InternalCompilerResult compilerResult,
Member member,
Map<Id, ActualData<Features>> actualMap,
{bool? verbose}) {
member.accept(new ExtensionsDataExtractor(compilerResult, actualMap));
}
@override
void computeClassData(
TestConfig config,
InternalCompilerResult compilerResult,
Class cls,
Map<Id, ActualData<Features>> actualMap,
{bool? verbose}) {
new ExtensionsDataExtractor(compilerResult, actualMap).computeForClass(cls);
}
@override
void computeLibraryData(
TestConfig config,
InternalCompilerResult compilerResult,
Library library,
Map<Id, ActualData<Features>> actualMap,
{bool? verbose}) {
new ExtensionsDataExtractor(compilerResult, actualMap)
.computeForLibrary(library);
}
@override
void computeExtensionData(
TestConfig config,
InternalCompilerResult compilerResult,
Extension extension,
Map<Id, ActualData<Features>> actualMap,
{bool? verbose}) {
new ExtensionsDataExtractor(compilerResult, actualMap)
.computeForExtension(extension);
}
@override
bool get supportsErrors => true;
@override
Features computeErrorData(TestConfig config, InternalCompilerResult compiler,
Id id, List<FormattedMessage> errors) {
Features features = new Features();
for (FormattedMessage error in errors) {
if (error.problemMessage.contains(',')) {
// TODO(johnniwinther): Support escaping of , in Features.
features.addElement(Tags.errors, error.code);
} else {
features.addElement(Tags.errors, error.problemMessage);
}
}
return features;
}
@override
DataInterpreter<Features> get dataValidator =>
const FeaturesDataInterpreter();
}
class Tags {
static const String builderName = 'builder-name';
static const String builderTypeParameters = 'builder-type-params';
static const String builderSupertype = 'builder-supertype';
static const String builderInterfaces = 'builder-interfaces';
static const String builderOnTypes = 'builder-onTypes';
static const String builderOnType = 'builder-onType';
static const String builderRequiredParameters = 'builder-params';
static const String builderPositionalParameters = 'builder-pos-params';
static const String builderNamedParameters = 'builder-named-params';
static const String builderScope = 'scope';
static const String clsName = 'cls-name';
static const String clsTypeParameters = 'cls-type-params';
static const String clsSupertype = 'cls-supertype';
static const String clsInterfaces = 'cls-interfaces';
static const String extensionName = 'extension-name';
static const String extensionTypeParameters = 'extension-type-params';
static const String extensionOnType = 'extension-onType';
static const String extensionMembers = 'extension-members';
static const String memberName = 'member-name';
static const String memberTypeParameters = 'member-type-params';
static const String memberRequiredParameters = 'member-params';
static const String memberPositionalParameters = 'member-pos-params';
static const String memberNamedParameters = 'member-named-params';
static const String errors = 'errors';
static const String hasThis = 'this';
}
class ExtensionsDataExtractor extends CfeDataExtractor<Features> {
ExtensionsDataExtractor(InternalCompilerResult compilerResult,
Map<Id, ActualData<Features>> actualMap)
: super(compilerResult, actualMap);
@override
Features computeLibraryValue(Id id, Library library) {
Features features = new Features();
SourceLibraryBuilder libraryBuilder =
lookupLibraryBuilder(compilerResult, library) as SourceLibraryBuilder;
libraryBuilder.forEachExtensionInScope((ExtensionBuilder extension) {
LibraryBuilder library = extension.parent as LibraryBuilder;
String libraryPrefix = '';
if (library != libraryBuilder) {
libraryPrefix = '${library.fileUri.pathSegments.last}.';
}
features.addElement(Tags.builderScope, '$libraryPrefix${extension.name}');
});
return features;
}
@override
Features? computeClassValue(Id id, Class cls) {
ClassBuilder clsBuilder =
lookupClassBuilder(compilerResult, cls) as ClassBuilder;
if (!clsBuilder.isExtension) {
return null;
}
Features features = new Features();
features[Tags.builderName] = clsBuilder.name;
if (clsBuilder.typeVariables != null) {
for (TypeVariableBuilder typeVariable in clsBuilder.typeVariables!) {
features.addElement(Tags.builderTypeParameters,
typeVariableBuilderToText(typeVariable));
}
}
if (clsBuilder.supertypeBuilder != null) {
features[Tags.builderSupertype] =
clsBuilder.supertypeBuilder!.name as String;
}
if (clsBuilder.interfaceBuilders != null) {
for (TypeBuilder superinterface in clsBuilder.interfaceBuilders!) {
features.addElement(Tags.builderInterfaces, superinterface.name);
}
}
if (clsBuilder.onTypes != null) {
for (TypeBuilder onType in clsBuilder.onTypes!) {
features.addElement(Tags.builderOnTypes, typeBuilderToText(onType));
}
}
features[Tags.clsName] = cls.name;
for (TypeParameter typeParameter in cls.typeParameters) {
features.addElement(
Tags.clsTypeParameters, typeParameterToText(typeParameter));
}
if (cls.supertype != null) {
features[Tags.clsSupertype] = cls.supertype!.classNode.name;
}
for (Supertype superinterface in cls.implementedTypes) {
features.addElement(Tags.clsInterfaces, superinterface.classNode.name);
}
return features;
}
@override
Features? computeExtensionValue(Id id, Extension extension) {
ExtensionBuilder extensionBuilder =
lookupExtensionBuilder(compilerResult, extension)!;
if (!extensionBuilder.isExtension) {
return null;
}
Features features = new Features();
features[Tags.builderName] = extensionBuilder.name;
if (extensionBuilder.typeParameters != null) {
for (TypeVariableBuilder typeVariable
in extensionBuilder.typeParameters!) {
features.addElement(Tags.builderTypeParameters,
typeVariableBuilderToText(typeVariable));
}
}
features[Tags.builderOnType] = typeBuilderToText(extensionBuilder.onType);
features[Tags.extensionName] = extension.name;
features[Tags.extensionOnType] = typeToText(extension.onType);
for (TypeParameter typeParameter in extension.typeParameters) {
features.addElement(
Tags.extensionTypeParameters, typeParameterToText(typeParameter));
}
for (ExtensionMemberDescriptor descriptor in extension.members) {
features.addElement(
Tags.extensionMembers, extensionMethodDescriptorToText(descriptor));
}
return features;
}
@override
Features? computeMemberValue(Id id, Member member) {
if (!member.isExtensionMember) {
return null;
}
MemberBuilder memberBuilder = lookupMemberBuilder(compilerResult, member)!;
Features features = new Features();
features[Tags.builderName] = memberBuilder.name;
if (memberBuilder is SourceFunctionBuilder) {
if (memberBuilder.formals != null) {
for (FormalParameterBuilder parameter in memberBuilder.formals!) {
if (parameter.isRequired) {
features.addElement(Tags.builderRequiredParameters, parameter.name);
} else if (parameter.isPositional) {
features.addElement(
Tags.builderPositionalParameters, parameter.name);
} else {
assert(parameter.isNamed);
features.addElement(Tags.builderNamedParameters, parameter.name);
}
}
features.markAsUnsorted(Tags.builderRequiredParameters);
features.markAsUnsorted(Tags.builderPositionalParameters);
features.markAsUnsorted(Tags.builderNamedParameters);
}
if (memberBuilder.typeVariables != null) {
for (TypeVariableBuilder typeVariable in memberBuilder.typeVariables!) {
features.addElement(Tags.builderTypeParameters,
typeVariableBuilderToText(typeVariable));
}
features.markAsUnsorted(Tags.builderTypeParameters);
}
}
features[Tags.memberName] = getMemberName(member);
if (member.function != null) {
for (int index = 0;
index < member.function!.positionalParameters.length;
index++) {
VariableDeclaration parameter =
member.function!.positionalParameters[index];
if (index < member.function!.requiredParameterCount) {
features.addElement(Tags.memberRequiredParameters, parameter.name);
} else {
features.addElement(Tags.memberPositionalParameters, parameter.name);
}
}
for (VariableDeclaration parameter in member.function!.namedParameters) {
features.addElement(Tags.memberNamedParameters, parameter.name);
}
features.markAsUnsorted(Tags.memberRequiredParameters);
features.markAsUnsorted(Tags.memberPositionalParameters);
features.markAsUnsorted(Tags.memberNamedParameters);
for (TypeParameter typeParameter in member.function!.typeParameters) {
features.addElement(
Tags.memberTypeParameters, typeParameterToText(typeParameter));
}
features.markAsUnsorted(Tags.memberTypeParameters);
}
return features;
}
@override
Features? computeNodeValue(Id id, TreeNode node) {
if (node is ThisExpression) {
Features features = new Features();
features.add(Tags.hasThis);
return features;
}
return null;
}
}