| // Copyright (c) 2017, 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'; |
| import 'package:async_helper/async_helper.dart'; |
| import 'package:compiler/src/common.dart'; |
| import 'package:compiler/src/compiler.dart'; |
| import 'package:compiler/src/diagnostics/diagnostic_listener.dart'; |
| import 'package:compiler/src/elements/elements.dart'; |
| import 'package:compiler/src/elements/entities.dart'; |
| import 'package:compiler/src/kernel/element_map.dart'; |
| import 'package:compiler/src/kernel/kernel_backend_strategy.dart'; |
| import 'package:compiler/src/resolution/access_semantics.dart'; |
| import 'package:compiler/src/resolution/send_structure.dart'; |
| import 'package:compiler/src/tree/nodes.dart' as ast; |
| import 'package:expect/expect.dart'; |
| import 'package:kernel/ast.dart' as ir; |
| import '../equivalence/id_equivalence.dart'; |
| import '../equivalence/id_equivalence_helper.dart'; |
| |
| const List<String> dataDirectories = const <String>[ |
| '../closure/data', |
| '../inference/data', |
| ]; |
| |
| main() { |
| asyncTest(() async { |
| for (String path in dataDirectories) { |
| Directory dataDir = new Directory.fromUri(Platform.script.resolve(path)); |
| await for (FileSystemEntity entity in dataDir.list()) { |
| print('Checking ${entity.uri}'); |
| String annotatedCode = |
| await new File.fromUri(entity.uri).readAsString(); |
| IdData data1 = await computeData( |
| annotatedCode, computeAstMemberData, compileFromSource); |
| IdData data2 = await computeData( |
| annotatedCode, computeIrMemberData, compileFromDill); |
| data1.actualMap.forEach((Id id, String value1) { |
| String value2 = data2.actualMap[id]; |
| if (value1 != value2) { |
| reportHere(data1.compiler.reporter, data1.sourceSpanMap[id], |
| '$id: from source:${value1},from dill:${value2}'); |
| } |
| Expect.equals(value1, value2, 'Value mismatch for $id'); |
| }); |
| data2.actualMap.forEach((Id id, String value2) { |
| String value1 = data1.actualMap[id]; |
| if (value1 != value2) { |
| reportHere(data2.compiler.reporter, data2.sourceSpanMap[id], |
| '$id: from source:${value1},from dill:${value2}'); |
| } |
| Expect.equals(value1, value2, 'Value mismatch for $id'); |
| }); |
| } |
| } |
| }); |
| } |
| |
| /// Compute a descriptive mapping of the [Id]s in [_member] as a |
| /// [MemberElement]. |
| /// |
| /// Fills [actualMap] with the data and [sourceSpanMap] with the source spans |
| /// for the data origin. |
| void computeAstMemberData(Compiler compiler, MemberEntity _member, |
| Map<Id, String> actualMap, Map<Id, SourceSpan> sourceSpanMap, |
| {bool verbose: false}) { |
| MemberElement member = _member; |
| ResolvedAst resolvedAst = member.resolvedAst; |
| if (resolvedAst.kind != ResolvedAstKind.PARSED) return; |
| new ResolvedAstComputer( |
| compiler.reporter, actualMap, sourceSpanMap, resolvedAst) |
| .run(); |
| } |
| |
| /// Mixin used for0computing a descriptive mapping of the [Id]s in a member. |
| class ComputerMixin { |
| String computeMemberName(String className, String memberName) { |
| if (className != null) { |
| return 'member:$className.$memberName'; |
| } |
| return 'member:$memberName'; |
| } |
| |
| String computeLocalName(String localName) { |
| return 'local:$localName'; |
| } |
| |
| String computeDynamicGetName(String propertyName) { |
| return 'dynamic-get:$propertyName'; |
| } |
| |
| String computeDynamicInvokeName(String propertyName) { |
| return 'dynamic-invoke:$propertyName'; |
| } |
| } |
| |
| /// AST visitor for computing a descriptive mapping of the [Id]s in a member. |
| class ResolvedAstComputer extends AbstractResolvedAstComputer |
| with ComputerMixin { |
| ResolvedAstComputer(DiagnosticReporter reporter, Map<Id, String> actualMap, |
| Map<Id, SourceSpan> spannableMap, ResolvedAst resolvedAst) |
| : super(reporter, actualMap, spannableMap, resolvedAst); |
| |
| @override |
| String computeNodeValue(ast.Node node, AstElement element) { |
| if (element != null && element.isLocal) { |
| return computeLocalName(element.name); |
| } |
| if (node is ast.Send) { |
| dynamic sendStructure = elements.getSendStructure(node); |
| if (sendStructure == null) return null; |
| |
| String getDynamicName() { |
| switch (sendStructure.semantics.kind) { |
| case AccessKind.DYNAMIC_PROPERTY: |
| DynamicAccess access = sendStructure.semantics; |
| return access.name.text; |
| default: |
| return null; |
| } |
| } |
| |
| switch (sendStructure.kind) { |
| case SendStructureKind.GET: |
| String dynamicName = getDynamicName(); |
| if (dynamicName != null) return computeDynamicGetName(dynamicName); |
| break; |
| case SendStructureKind.INVOKE: |
| String dynamicName = getDynamicName(); |
| if (dynamicName != null) return computeDynamicInvokeName(dynamicName); |
| break; |
| default: |
| } |
| } |
| return '<unknown:$node>'; |
| } |
| |
| @override |
| String computeElementValue(AstElement element) { |
| return computeMemberName(element.enclosingClass?.name, element.name); |
| } |
| } |
| |
| /// Compute a descriptive mapping of the [Id]s in [member] as a kernel based |
| /// member. |
| /// |
| /// Fills [actualMap] with the data and [sourceSpanMap] with the source spans |
| /// for the data origin. |
| void computeIrMemberData(Compiler compiler, MemberEntity member, |
| Map<Id, String> actualMap, Map<Id, Spannable> spannableMap, |
| {bool verbose: false}) { |
| KernelBackendStrategy backendStrategy = compiler.backendStrategy; |
| KernelToElementMapForBuilding elementMap = backendStrategy.elementMap; |
| MemberDefinition definition = elementMap.getMemberDefinition(member); |
| assert(definition.kind == MemberKind.regular, |
| failedAt(member, "Unexpected member definition $definition")); |
| new IrComputer(actualMap, spannableMap).run(definition.node); |
| } |
| |
| /// IR visitor for computing a descriptive mapping of the [Id]s in a member. |
| class IrComputer extends AbstractIrComputer with ComputerMixin { |
| IrComputer(Map<Id, String> actualMap, Map<Id, SourceSpan> spannableMap) |
| : super(actualMap, spannableMap); |
| |
| @override |
| String computeNodeValue(ir.TreeNode node) { |
| if (node is ir.VariableDeclaration) { |
| return computeLocalName(node.name); |
| } else if (node is ir.FunctionDeclaration) { |
| return computeLocalName(node.variable.name); |
| } else if (node is ir.FunctionExpression) { |
| return computeLocalName(''); |
| } else if (node is ir.MethodInvocation) { |
| return computeDynamicInvokeName(node.name.name); |
| } else if (node is ir.PropertyGet) { |
| return computeDynamicGetName(node.name.name); |
| } |
| return '<unknown:$node>'; |
| } |
| |
| @override |
| String computeMemberValue(ir.Member member) { |
| return computeMemberName(member.enclosingClass?.name, member.name.name); |
| } |
| } |