Index: tests/compiler/dart2js/equivalence/id_equivalence.dart |
diff --git a/tests/compiler/dart2js/equivalence/id_equivalence.dart b/tests/compiler/dart2js/equivalence/id_equivalence.dart |
index cc0421de795a4c97c0e6178190eabe0f1a3618b6..9d6d5d0cf757eec25868a023e5364c98bfb4b4eb 100644 |
--- a/tests/compiler/dart2js/equivalence/id_equivalence.dart |
+++ b/tests/compiler/dart2js/equivalence/id_equivalence.dart |
@@ -2,6 +2,7 @@ |
// 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 'package:compiler/src/common.dart'; |
import 'package:compiler/src/elements/elements.dart'; |
import 'package:compiler/src/resolution/access_semantics.dart'; |
import 'package:compiler/src/resolution/send_structure.dart'; |
@@ -71,8 +72,43 @@ class NodeId implements Id { |
String toString() => '$kind:$value'; |
} |
-abstract class AstEnumeratorMixin { |
- TreeElements get elements; |
+class ActualData { |
+ final Id id; |
+ final String value; |
+ final SourceSpan sourceSpan; |
+ final Object object; |
+ |
+ ActualData(this.id, this.value, this.sourceSpan, this.object); |
+} |
+ |
+/// Abstract AST visitor for computing data corresponding to a node or element, |
+// and record it with a generic [Id]. |
+abstract class AstDataExtractor extends ast.Visitor { |
+ final DiagnosticReporter reporter; |
+ final Map<Id, ActualData> actualMap; |
+ final ResolvedAst resolvedAst; |
+ |
+ AstDataExtractor(this.reporter, this.actualMap, this.resolvedAst); |
+ |
+ /// Implement this to compute the data corresponding to [element]. |
+ /// |
+ /// If `null` is returned, [element] has no associated data. |
+ String computeElementValue(AstElement element); |
+ |
+ /// Implement this to compute the data corresponding to [node]. If [node] has |
+ /// a corresponding [AstElement] this is provided in [element]. |
+ /// |
+ /// If `null` is returned, [node] has no associated data. |
+ String computeNodeValue(ast.Node node, AstElement element); |
+ |
+ TreeElements get elements => resolvedAst.elements; |
+ |
+ void registerValue( |
+ SourceSpan sourceSpan, Id id, String value, Object object) { |
+ if (value != null) { |
+ actualMap[id] = new ActualData(id, value, sourceSpan, object); |
+ } |
+ } |
ElementId computeElementId(AstElement element) { |
String memberName = element.name; |
@@ -86,111 +122,132 @@ abstract class AstEnumeratorMixin { |
NodeId computeAccessId(ast.Send node, AccessSemantics access) { |
switch (access.kind) { |
case AccessKind.DYNAMIC_PROPERTY: |
- return new NodeId(node.selector.getBeginToken().charOffset); |
+ case AccessKind.LOCAL_VARIABLE: |
+ case AccessKind.FINAL_LOCAL_VARIABLE: |
+ case AccessKind.LOCAL_FUNCTION: |
+ case AccessKind.PARAMETER: |
+ case AccessKind.FINAL_PARAMETER: |
+ case AccessKind.EXPRESSION: |
+ return computeDefaultNodeId(node.selector); |
default: |
return null; |
} |
} |
- NodeId computeNodeId(ast.Node node, AstElement element) { |
- if (element != null && element.isLocal) { |
- return new NodeId(node.getBeginToken().charOffset); |
- } else if (node is ast.Send) { |
- dynamic sendStructure = elements.getSendStructure(node); |
- if (sendStructure == null) return null; |
- switch (sendStructure.kind) { |
- case SendStructureKind.GET: |
- case SendStructureKind.INVOKE: |
- return computeAccessId(node, sendStructure.semantics); |
- default: |
- } |
- } |
- return null; |
+ void computeForElement(AstElement element) { |
+ ElementId id = computeElementId(element); |
+ if (id == null) return; |
+ String value = computeElementValue(element); |
+ registerValue(element.sourcePosition, id, value, element); |
} |
-} |
-/// Visitor that finds the AST node or element corresponding to an [Id]. |
-class AstIdFinder extends ast.Visitor with AstEnumeratorMixin { |
- Id soughtId; |
- var /*AstElement|ast.Node*/ found; |
- final TreeElements elements; |
+ void computeForNode(ast.Node node, NodeId id, [AstElement element]) { |
+ if (id == null) return; |
+ String value = computeNodeValue(node, element); |
+ SourceSpan sourceSpan = computeSourceSpan(node); |
+ registerValue(sourceSpan, id, value, element ?? node); |
+ } |
- AstIdFinder(this.elements); |
+ SourceSpan computeSourceSpan(ast.Node node) { |
+ return new SourceSpan(resolvedAst.sourceUri, |
+ node.getBeginToken().charOffset, node.getEndToken().charEnd); |
+ } |
- /// Visits the subtree of [root] returns the [ast.Node] or [AstElement] |
- /// corresponding to [id]. |
- /*AstElement|ast.Node*/ find(ast.Node root, Id id) { |
- soughtId = id; |
- root.accept(this); |
- var result = found; |
- found = null; |
- return result; |
+ NodeId computeDefaultNodeId(ast.Node node) { |
+ return new NodeId(node.getBeginToken().charOffset); |
} |
- visit(ast.Node node) { |
- if (found == null) { |
- node?.accept(this); |
- } |
+ NodeId computeLoopNodeId(ast.Node node) { |
+ return new NodeId(node.getBeginToken().charOffset); |
} |
- visitNode(ast.Node node) { |
- if (found == null) { |
- node.visitChildren(this); |
- } |
+ NodeId computeGotoNodeId(ast.Node node) { |
+ return new NodeId(node.getBeginToken().charOffset); |
} |
- visitSend(ast.Send node) { |
- if (found == null) { |
- visitNode(node); |
- Id id = computeNodeId(node, null); |
- if (id == soughtId) { |
- found = node; |
- } |
- } |
+ void run() { |
+ resolvedAst.node.accept(this); |
+ } |
+ |
+ visitNode(ast.Node node) { |
+ node.visitChildren(this); |
} |
visitVariableDefinitions(ast.VariableDefinitions node) { |
- if (found == null) { |
- for (ast.Node child in node.definitions) { |
- AstElement element = elements[child]; |
- if (element != null) { |
- Id id; |
- if (element is FieldElement) { |
- id = computeElementId(element); |
- } else { |
- id = computeNodeId(child, element); |
- } |
- if (id == soughtId) { |
- found = element; |
- return; |
- } |
- } |
+ for (ast.Node child in node.definitions) { |
+ AstElement element = elements[child]; |
+ if (element == null) { |
+ reportHere(reporter, child, 'No element for variable.'); |
+ } else if (!element.isLocal) { |
+ computeForElement(element); |
+ } else { |
+ computeForNode(child, computeDefaultNodeId(child), element); |
} |
- visitNode(node); |
} |
+ visitNode(node); |
} |
visitFunctionExpression(ast.FunctionExpression node) { |
- if (found == null) { |
- AstElement element = elements.getFunctionDefinition(node); |
- if (element != null) { |
- Id id; |
- if (element is LocalFunctionElement) { |
- id = computeNodeId(node, element); |
- } else { |
- id = computeElementId(element); |
- } |
- if (id == soughtId) { |
- found = element; |
- return; |
- } |
+ AstElement element = elements.getFunctionDefinition(node); |
+ if (!element.isLocal) { |
+ computeForElement(element); |
+ } else { |
+ computeForNode(node, computeDefaultNodeId(node), element); |
+ } |
+ visitNode(node); |
+ } |
+ |
+ visitSend(ast.Send node) { |
+ dynamic sendStructure = elements.getSendStructure(node); |
+ if (sendStructure != null) { |
+ switch (sendStructure.kind) { |
+ case SendStructureKind.GET: |
+ case SendStructureKind.INVOKE: |
+ case SendStructureKind.BINARY: |
+ case SendStructureKind.EQUALS: |
+ case SendStructureKind.NOT_EQUALS: |
+ computeForNode(node, computeAccessId(node, sendStructure.semantics)); |
+ break; |
+ default: |
} |
- visitNode(node); |
} |
+ visitNode(node); |
+ } |
+ |
+ visitLoop(ast.Loop node) { |
+ computeForNode(node, computeLoopNodeId(node)); |
+ visitNode(node); |
+ } |
+ |
+ visitGotoStatement(ast.GotoStatement node) { |
+ computeForNode(node, computeGotoNodeId(node)); |
+ visitNode(node); |
} |
} |
-abstract class IrEnumeratorMixin { |
+/// Abstract IR visitor for computing data corresponding to a node or element, |
+/// and record it with a generic [Id] |
+abstract class IrDataExtractor extends ir.Visitor { |
+ final Map<Id, ActualData> actualMap; |
+ |
+ void registerValue( |
+ SourceSpan sourceSpan, Id id, String value, Object object) { |
+ if (value != null) { |
+ actualMap[id] = new ActualData(id, value, sourceSpan, object); |
+ } |
+ } |
+ |
+ /// Implement this to compute the data corresponding to [member]. |
+ /// |
+ /// If `null` is returned, [member] has no associated data. |
+ String computeMemberValue(ir.Member member); |
+ |
+ /// Implement this to compute the data corresponding to [node]. |
+ /// |
+ /// If `null` is returned, [node] has no associated data. |
+ String computeNodeValue(ir.TreeNode node); |
+ |
+ IrDataExtractor(this.actualMap); |
Id computeElementId(ir.Member node) { |
String className; |
if (node.enclosingClass != null) { |
@@ -203,60 +260,97 @@ abstract class IrEnumeratorMixin { |
return new ElementId.internal(memberName, className); |
} |
- Id computeNodeId(ir.TreeNode node) { |
- if (node is ir.MethodInvocation) { |
- assert(node.fileOffset != ir.TreeNode.noOffset); |
- return new NodeId(node.fileOffset); |
- } else if (node is ir.PropertyGet) { |
- assert(node.fileOffset != ir.TreeNode.noOffset); |
- return new NodeId(node.fileOffset); |
- } else if (node is ir.VariableDeclaration) { |
- assert(node.fileOffset != ir.TreeNode.noOffset); |
- return new NodeId(node.fileOffset); |
- } else if (node is ir.FunctionExpression) { |
- assert(node.fileOffset != ir.TreeNode.noOffset); |
- return new NodeId(node.fileOffset); |
- } else if (node is ir.FunctionDeclaration) { |
- assert(node.fileOffset != ir.TreeNode.noOffset); |
- return new NodeId(node.fileOffset); |
- } |
- return null; |
+ void computeForMember(ir.Member member) { |
+ ElementId id = computeElementId(member); |
+ if (id == null) return; |
+ String value = computeMemberValue(member); |
+ registerValue(computeSourceSpan(member), id, value, member); |
} |
-} |
-/// Visitor that finds the IR node corresponding to an [Id]. |
-class IrIdFinder extends ir.Visitor with IrEnumeratorMixin { |
- Id soughtId; |
- ir.Node found; |
+ void computeForNode(ir.TreeNode node, NodeId id) { |
+ if (id == null) return; |
+ String value = computeNodeValue(node); |
+ registerValue(computeSourceSpan(node), id, value, node); |
+ } |
- /// Visits the subtree of [root] returns the [ir.Node] corresponding to [id]. |
- ir.Node find(ir.Node root, Id id) { |
- soughtId = id; |
+ SourceSpan computeSourceSpan(ir.TreeNode node) { |
+ return new SourceSpan( |
+ Uri.parse(node.location.file), node.fileOffset, node.fileOffset + 1); |
+ } |
+ |
+ NodeId computeDefaultNodeId(ir.TreeNode node) { |
+ assert(node.fileOffset != ir.TreeNode.noOffset); |
+ return new NodeId(node.fileOffset); |
+ } |
+ |
+ NodeId computeLoopNodeId(ir.TreeNode node) => computeDefaultNodeId(node); |
+ NodeId computeGotoNodeId(ir.TreeNode node) => computeDefaultNodeId(node); |
+ |
+ void run(ir.Node root) { |
root.accept(this); |
- var result = found; |
- found = null; |
- return result; |
} |
- defaultTreeNode(ir.TreeNode node) { |
- if (found == null) { |
- Id id = computeNodeId(node); |
- if (id == soughtId) { |
- found = node; |
- return; |
- } |
- node.visitChildren(this); |
- } |
+ defaultNode(ir.Node node) { |
+ node.visitChildren(this); |
} |
defaultMember(ir.Member node) { |
- if (found == null) { |
- Id id = computeElementId(node); |
- if (id == soughtId) { |
- found = node; |
- return; |
- } |
- defaultTreeNode(node); |
- } |
+ computeForMember(node); |
+ super.defaultMember(node); |
+ } |
+ |
+ visitMethodInvocation(ir.MethodInvocation node) { |
+ computeForNode(node, computeDefaultNodeId(node)); |
+ super.visitMethodInvocation(node); |
+ } |
+ |
+ visitPropertyGet(ir.PropertyGet node) { |
+ computeForNode(node, computeDefaultNodeId(node)); |
+ super.visitPropertyGet(node); |
+ } |
+ |
+ visitVariableDeclaration(ir.VariableDeclaration node) { |
+ computeForNode(node, computeDefaultNodeId(node)); |
+ super.visitVariableDeclaration(node); |
+ } |
+ |
+ visitFunctionDeclaration(ir.FunctionDeclaration node) { |
+ computeForNode(node, computeDefaultNodeId(node)); |
+ super.visitFunctionDeclaration(node); |
+ } |
+ |
+ visitFunctionExpression(ir.FunctionExpression node) { |
+ computeForNode(node, computeDefaultNodeId(node)); |
+ super.visitFunctionExpression(node); |
+ } |
+ |
+ visitVariableGet(ir.VariableGet node) { |
+ computeForNode(node, computeDefaultNodeId(node)); |
+ super.visitVariableGet(node); |
+ } |
+ |
+ visitDoStatement(ir.DoStatement node) { |
+ computeForNode(node, computeLoopNodeId(node)); |
+ super.visitDoStatement(node); |
+ } |
+ |
+ visitForStatement(ir.ForStatement node) { |
+ computeForNode(node, computeLoopNodeId(node)); |
+ super.visitForStatement(node); |
+ } |
+ |
+ visitForInStatement(ir.ForInStatement node) { |
+ computeForNode(node, computeLoopNodeId(node)); |
+ super.visitForInStatement(node); |
+ } |
+ |
+ visitWhileStatement(ir.WhileStatement node) { |
+ computeForNode(node, computeLoopNodeId(node)); |
+ super.visitWhileStatement(node); |
+ } |
+ |
+ visitBreakStatement(ir.BreakStatement node) { |
+ computeForNode(node, computeGotoNodeId(node)); |
+ super.visitBreakStatement(node); |
} |
} |