// Copyright (c) 2020, 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. // @dart = 2.9 import 'dart:io' show Directory, Platform; import 'package:_fe_analyzer_shared/src/testing/id.dart'; 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:_fe_analyzer_shared/src/testing/features.dart'; import 'package:front_end/src/api_prototype/experimental_flags.dart'; import 'package:front_end/src/base/nnbd_mode.dart'; import 'package:front_end/src/testing/id_extractor.dart'; import 'package:front_end/src/testing/id_testing_helper.dart'; import 'package:front_end/src/testing/id_testing_utils.dart'; import 'package:front_end/src/api_prototype/lowering_predicates.dart'; import 'package:kernel/ast.dart'; import 'package:kernel/src/printer.dart'; import 'package:kernel/target/targets.dart'; const String isNullMarker = 'is-null'; const String sentinelMarker = 'sentinel'; main(List args) async { Directory dataDir = new Directory.fromUri(Platform.script.resolve('data')); await runTests(dataDir, args: args, createUriForFileName: createUriForFileName, onFailure: onFailure, runTest: runTestFor(const PredicateDataComputer(), [ const TestConfig(isNullMarker, 'use is-null', explicitExperimentalFlags: const { ExperimentalFlag.nonNullable: true }, targetFlags: const TargetFlags( forceLateLoweringsForTesting: LateLowering.all, forceLateLoweringSentinelForTesting: false), nnbdMode: NnbdMode.Strong), const TestConfig(sentinelMarker, 'use sentinel', explicitExperimentalFlags: const { ExperimentalFlag.nonNullable: true }, targetFlags: const TargetFlags( forceLateLoweringsForTesting: LateLowering.all, forceLateLoweringSentinelForTesting: true), nnbdMode: NnbdMode.Strong) ])); } class Tags { static const String lateField = 'lateField'; static const String lateFieldName = 'lateFieldName'; static const String lateIsSetField = 'lateIsSetField'; static const String lateFieldGetter = 'lateFieldGetter'; static const String lateFieldSetter = 'lateFieldSetter'; static const String lateFieldTarget = 'lateFieldTarget'; static const String lateFieldInitializer = 'lateFieldInitializer'; static const String lateLocal = 'lateLocal'; static const String lateIsSetLocal = 'lateIsSetLocal'; static const String lateLocalGetter = 'lateLocalGetter'; static const String lateLocalSetter = 'lateLocalSetter'; static const String extensionThis = 'extensionThis'; } class PredicateDataComputer extends DataComputer { const PredicateDataComputer(); /// Function that computes a data mapping for [library]. /// /// Fills [actualMap] with the data. void computeLibraryData( TestConfig config, InternalCompilerResult compilerResult, Library library, Map> actualMap, {bool verbose}) { new PredicateDataExtractor(compilerResult, actualMap) .computeForLibrary(library); } @override void computeMemberData( TestConfig config, InternalCompilerResult compilerResult, Member member, Map> actualMap, {bool verbose}) { member.accept(new PredicateDataExtractor(compilerResult, actualMap)); } @override DataInterpreter get dataValidator => const FeaturesDataInterpreter(); } class PredicateDataExtractor extends CfeDataExtractor { Map featureMap = {}; Map nodeIdMap = {}; PredicateDataExtractor(InternalCompilerResult compilerResult, Map> actualMap) : super(compilerResult, actualMap); @override Features computeLibraryValue(Id id, Library node) { return null; } @override Features computeMemberValue(Id id, Member node) { if (node is Field) { Features features = new Features(); if (isLateLoweredField(node)) { features.add(Tags.lateField); features[Tags.lateFieldName] = extractFieldNameFromLateLoweredField(node).text; } if (isLateLoweredIsSetField(node)) { features.add(Tags.lateIsSetField); features[Tags.lateFieldName] = extractFieldNameFromLateLoweredIsSetField(node).text; } Field target = getLateFieldTarget(node); if (target != null) { features[Tags.lateFieldTarget] = getQualifiedMemberName(target); } Expression initializer = getLateFieldInitializer(node); if (initializer != null) { features[Tags.lateFieldInitializer] = initializer.toText(astTextStrategyForTesting); } return features; } else if (node is Procedure) { Features features = new Features(); if (isLateLoweredFieldGetter(node)) { features.add(Tags.lateFieldGetter); features[Tags.lateFieldName] = extractFieldNameFromLateLoweredFieldGetter(node).text; } if (isLateLoweredFieldSetter(node)) { features.add(Tags.lateFieldSetter); features[Tags.lateFieldName] = extractFieldNameFromLateLoweredFieldSetter(node).text; } Field target = getLateFieldTarget(node); if (target != null) { features[Tags.lateFieldTarget] = getQualifiedMemberName(target); } Expression initializer = getLateFieldInitializer(node); if (initializer != null) { features[Tags.lateFieldInitializer] = initializer.toText(astTextStrategyForTesting); } return features; } return null; } void visitProcedure(Procedure node) { super.visitProcedure(node); nodeIdMap.forEach((String name, NodeId id) { Features features = featureMap[name]; if (features != null) { TreeNode nodeWithOffset = computeTreeNodeWithOffset(node); registerValue( nodeWithOffset.location.file, id.value, id, features, name); } }); nodeIdMap.clear(); featureMap.clear(); } void visitVariableDeclaration(VariableDeclaration node) { String name; String tag; if (isLateLoweredLocal(node)) { name = extractLocalNameFromLateLoweredLocal(node.name); tag = Tags.lateLocal; } else if (isLateLoweredIsSetLocal(node)) { name = extractLocalNameFromLateLoweredIsSet(node.name); tag = Tags.lateIsSetLocal; } else if (isLateLoweredLocalGetter(node)) { name = extractLocalNameFromLateLoweredGetter(node.name); tag = Tags.lateLocalGetter; } else if (isLateLoweredLocalSetter(node)) { name = extractLocalNameFromLateLoweredSetter(node.name); tag = Tags.lateLocalSetter; } else if (isExtensionThis(node)) { name = extractLocalNameForExtensionThis(node.name); tag = Tags.extensionThis; } else if (node.name != null) { name = node.name; } if (name != null) { if (node.fileOffset != TreeNode.noOffset) { nodeIdMap[name] ??= new NodeId(node.fileOffset, IdKind.node); } if (tag != null) { Features features = featureMap[name] ??= new Features(); features.add(tag); } } super.visitVariableDeclaration(node); } @override ActualData mergeData( ActualData value1, ActualData value2) { if ('${value1.value}' == '${value2.value}') { // The extension this parameter is seen twice in the extension method // and the corresponding tearoff. The features are identical, though, so // we just use the first. return value1; } return null; } }