OLD | NEW |
| (Empty) |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 import 'package:compiler/src/elements/elements.dart'; | |
6 import 'package:compiler/src/resolution/access_semantics.dart'; | |
7 import 'package:compiler/src/resolution/send_structure.dart'; | |
8 import 'package:compiler/src/resolution/tree_elements.dart'; | |
9 import 'package:compiler/src/tree/nodes.dart' as ast; | |
10 import 'package:kernel/ast.dart' as ir; | |
11 | |
12 enum IdKind { element, node } | |
13 | |
14 /// Id for a code point or element with type inference information. | |
15 abstract class Id { | |
16 IdKind get kind; | |
17 } | |
18 | |
19 /// Id for an element with type inference information. | |
20 // TODO(johnniwinther): Support local variables, functions and parameters. | |
21 class ElementId implements Id { | |
22 final String className; | |
23 final String memberName; | |
24 | |
25 factory ElementId(String text) { | |
26 int dotPos = text.indexOf('.'); | |
27 if (dotPos != -1) { | |
28 return new ElementId.internal( | |
29 text.substring(dotPos + 1), text.substring(0, dotPos)); | |
30 } else { | |
31 return new ElementId.internal(text); | |
32 } | |
33 } | |
34 | |
35 ElementId.internal(this.memberName, [this.className]); | |
36 | |
37 int get hashCode => className.hashCode * 13 + memberName.hashCode * 17; | |
38 | |
39 bool operator ==(other) { | |
40 if (identical(this, other)) return true; | |
41 if (other is! ElementId) return false; | |
42 return className == other.className && memberName == other.memberName; | |
43 } | |
44 | |
45 IdKind get kind => IdKind.element; | |
46 | |
47 String toString() => | |
48 className != null ? '$className.$memberName' : memberName; | |
49 } | |
50 | |
51 /// Id for a code point with type inference information. | |
52 // TODO(johnniwinther): Create an [NodeId]-based equivalence with the kernel IR. | |
53 class NodeId implements Id { | |
54 final int value; | |
55 | |
56 const NodeId(this.value); | |
57 | |
58 int get hashCode => value.hashCode; | |
59 | |
60 bool operator ==(other) { | |
61 if (identical(this, other)) return true; | |
62 if (other is! NodeId) return false; | |
63 return value == other.value; | |
64 } | |
65 | |
66 IdKind get kind => IdKind.node; | |
67 | |
68 String toString() => value.toString(); | |
69 } | |
70 | |
71 abstract class AstEnumeratorMixin { | |
72 TreeElements get elements; | |
73 | |
74 ElementId computeElementId(AstElement element) { | |
75 String memberName = element.name; | |
76 if (element.isSetter) { | |
77 memberName += '='; | |
78 } | |
79 String className = element.enclosingClass?.name; | |
80 return new ElementId.internal(memberName, className); | |
81 } | |
82 | |
83 NodeId computeAccessId(ast.Send node, AccessSemantics access) { | |
84 switch (access.kind) { | |
85 case AccessKind.DYNAMIC_PROPERTY: | |
86 return new NodeId(node.selector.getBeginToken().charOffset); | |
87 default: | |
88 return new NodeId(node.getBeginToken().charOffset); | |
89 } | |
90 } | |
91 | |
92 NodeId computeNodeId(ast.Send node) { | |
93 dynamic sendStructure = elements.getSendStructure(node); | |
94 if (sendStructure == null) return null; | |
95 switch (sendStructure.kind) { | |
96 case SendStructureKind.GET: | |
97 case SendStructureKind.INVOKE: | |
98 case SendStructureKind.INCOMPATIBLE_INVOKE: | |
99 return computeAccessId(node, sendStructure.semantics); | |
100 default: | |
101 return new NodeId(node.getBeginToken().charOffset); | |
102 } | |
103 } | |
104 } | |
105 | |
106 /// Visitor that finds the AST node or element corresponding to an [Id]. | |
107 class AstIdFinder extends ast.Visitor with AstEnumeratorMixin { | |
108 Id soughtId; | |
109 var /*AstElement|ast.Node*/ found; | |
110 final TreeElements elements; | |
111 | |
112 AstIdFinder(this.elements); | |
113 | |
114 /// Visits the subtree of [root] returns the [ast.Node] or [AstElement] | |
115 /// corresponding to [id]. | |
116 /*AstElement|ast.Node*/ find(ast.Node root, Id id) { | |
117 soughtId = id; | |
118 root.accept(this); | |
119 var result = found; | |
120 found = null; | |
121 return result; | |
122 } | |
123 | |
124 visit(ast.Node node) { | |
125 if (found == null) { | |
126 node?.accept(this); | |
127 } | |
128 } | |
129 | |
130 visitNode(ast.Node node) { | |
131 if (found == null) { | |
132 node.visitChildren(this); | |
133 } | |
134 } | |
135 | |
136 visitSend(ast.Send node) { | |
137 if (found == null) { | |
138 visitNode(node); | |
139 Id id = computeNodeId(node); | |
140 if (id == soughtId) { | |
141 found = node; | |
142 } | |
143 } | |
144 } | |
145 | |
146 visitVariableDefinitions(ast.VariableDefinitions node) { | |
147 if (found == null) { | |
148 for (ast.Node child in node.definitions) { | |
149 AstElement element = elements[child]; | |
150 if (element != null) { | |
151 Id id = computeElementId(element); | |
152 if (id == soughtId) { | |
153 found = element; | |
154 return; | |
155 } | |
156 } | |
157 } | |
158 visitNode(node); | |
159 } | |
160 } | |
161 | |
162 visitFunctionExpression(ast.FunctionExpression node) { | |
163 if (found == null) { | |
164 AstElement element = elements.getFunctionDefinition(node); | |
165 if (element != null) { | |
166 Id id = computeElementId(element); | |
167 if (id == soughtId) { | |
168 found = element; | |
169 return; | |
170 } | |
171 } | |
172 visitNode(node); | |
173 } | |
174 } | |
175 } | |
176 | |
177 abstract class IrEnumeratorMixin { | |
178 Id computeElementId(ir.Member node) { | |
179 String className; | |
180 if (node.enclosingClass != null) { | |
181 className = node.enclosingClass.name; | |
182 } | |
183 String memberName = node.name.name; | |
184 if (node is ir.Procedure && node.kind == ir.ProcedureKind.Setter) { | |
185 memberName += '='; | |
186 } | |
187 return new ElementId.internal(memberName, className); | |
188 } | |
189 | |
190 Id computeNodeId(ir.Node node) { | |
191 if (node is ir.MethodInvocation) { | |
192 assert(node.fileOffset != ir.TreeNode.noOffset); | |
193 return new NodeId(node.fileOffset); | |
194 } else if (node is ir.PropertyGet) { | |
195 assert(node.fileOffset != ir.TreeNode.noOffset); | |
196 return new NodeId(node.fileOffset); | |
197 } | |
198 return null; | |
199 } | |
200 } | |
201 | |
202 /// Visitor that finds the IR node corresponding to an [Id]. | |
203 class IrIdFinder extends ir.Visitor with IrEnumeratorMixin { | |
204 Id soughtId; | |
205 ir.Node found; | |
206 | |
207 /// Visits the subtree of [root] returns the [ir.Node] corresponding to [id]. | |
208 ir.Node find(ir.Node root, Id id) { | |
209 soughtId = id; | |
210 root.accept(this); | |
211 var result = found; | |
212 found = null; | |
213 return result; | |
214 } | |
215 | |
216 defaultNode(ir.Node node) { | |
217 if (found == null) { | |
218 Id id = computeNodeId(node); | |
219 if (id == soughtId) { | |
220 found = node; | |
221 return; | |
222 } | |
223 node.visitChildren(this); | |
224 } | |
225 } | |
226 | |
227 defaultMember(ir.Member node) { | |
228 if (found == null) { | |
229 Id id = computeElementId(node); | |
230 if (id == soughtId) { | |
231 found = node; | |
232 return; | |
233 } | |
234 defaultNode(node); | |
235 } | |
236 } | |
237 } | |
OLD | NEW |