OLD | NEW |
---|---|
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'package:compiler/src/common.dart'; | |
5 import 'package:compiler/src/elements/elements.dart'; | 6 import 'package:compiler/src/elements/elements.dart'; |
6 import 'package:compiler/src/resolution/access_semantics.dart'; | 7 import 'package:compiler/src/resolution/access_semantics.dart'; |
7 import 'package:compiler/src/resolution/send_structure.dart'; | 8 import 'package:compiler/src/resolution/send_structure.dart'; |
8 import 'package:compiler/src/resolution/tree_elements.dart'; | 9 import 'package:compiler/src/resolution/tree_elements.dart'; |
9 import 'package:compiler/src/tree/nodes.dart' as ast; | 10 import 'package:compiler/src/tree/nodes.dart' as ast; |
10 import 'package:kernel/ast.dart' as ir; | 11 import 'package:kernel/ast.dart' as ir; |
11 | 12 |
12 enum IdKind { | 13 enum IdKind { |
13 element, | 14 element, |
14 node, | 15 node, |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
64 if (identical(this, other)) return true; | 65 if (identical(this, other)) return true; |
65 if (other is! NodeId) return false; | 66 if (other is! NodeId) return false; |
66 return value == other.value; | 67 return value == other.value; |
67 } | 68 } |
68 | 69 |
69 IdKind get kind => IdKind.node; | 70 IdKind get kind => IdKind.node; |
70 | 71 |
71 String toString() => '$kind:$value'; | 72 String toString() => '$kind:$value'; |
72 } | 73 } |
73 | 74 |
74 abstract class AstEnumeratorMixin { | 75 class ActualData { |
75 TreeElements get elements; | 76 final Id id; |
77 final String value; | |
78 final SourceSpan sourceSpan; | |
79 final Object object; | |
80 | |
81 ActualData(this.id, this.value, this.sourceSpan, this.object); | |
82 } | |
83 | |
84 /// Mixin used for computing [Id] data. | |
85 abstract class ComputerMixin { | |
Siggi Cherem (dart-lang)
2017/08/18 21:20:21
nit: rename to describe what it does and not what
Johnni Winther
2017/08/19 09:30:52
Mixin removed
| |
86 Map<Id, ActualData> get actualMap; | |
87 | |
88 void registerValue( | |
89 SourceSpan sourceSpan, Id id, String value, Object object) { | |
90 if (id != null && value != null) { | |
Siggi Cherem (dart-lang)
2017/08/18 21:20:21
note that you already guard agaisnt null id's on a
Johnni Winther
2017/08/19 09:30:52
Done.
| |
91 actualMap[id] = new ActualData(id, value, sourceSpan, object); | |
92 } | |
93 } | |
94 } | |
95 | |
96 /// Abstract AST visitor for computing [Id] data. | |
Siggi Cherem (dart-lang)
2017/08/18 21:20:21
nit: reword to: visitor for computing data corresp
Johnni Winther
2017/08/19 09:30:52
Done.
| |
97 abstract class AbstractResolvedAstComputer extends ast.Visitor | |
Siggi Cherem (dart-lang)
2017/08/18 21:20:21
other naming ideas:
- AbstractAstDataBuilder and
Johnni Winther
2017/08/19 09:30:52
Extractor it is.
| |
98 with ComputerMixin { | |
99 final DiagnosticReporter reporter; | |
100 final Map<Id, ActualData> actualMap; | |
101 final ResolvedAst resolvedAst; | |
102 | |
103 AbstractResolvedAstComputer(this.reporter, this.actualMap, this.resolvedAst); | |
104 | |
105 TreeElements get elements => resolvedAst.elements; | |
76 | 106 |
77 ElementId computeElementId(AstElement element) { | 107 ElementId computeElementId(AstElement element) { |
78 String memberName = element.name; | 108 String memberName = element.name; |
79 if (element.isSetter) { | 109 if (element.isSetter) { |
80 memberName += '='; | 110 memberName += '='; |
81 } | 111 } |
82 String className = element.enclosingClass?.name; | 112 String className = element.enclosingClass?.name; |
83 return new ElementId.internal(memberName, className); | 113 return new ElementId.internal(memberName, className); |
84 } | 114 } |
85 | 115 |
86 NodeId computeAccessId(ast.Send node, AccessSemantics access) { | 116 NodeId computeAccessId(ast.Send node, AccessSemantics access) { |
87 switch (access.kind) { | 117 switch (access.kind) { |
88 case AccessKind.DYNAMIC_PROPERTY: | 118 case AccessKind.DYNAMIC_PROPERTY: |
89 return new NodeId(node.selector.getBeginToken().charOffset); | 119 case AccessKind.LOCAL_VARIABLE: |
120 case AccessKind.FINAL_LOCAL_VARIABLE: | |
121 case AccessKind.LOCAL_FUNCTION: | |
122 case AccessKind.PARAMETER: | |
123 case AccessKind.FINAL_PARAMETER: | |
124 case AccessKind.EXPRESSION: | |
125 return computeDefaultNodeId(node.selector); | |
90 default: | 126 default: |
91 return null; | 127 return null; |
92 } | 128 } |
93 } | 129 } |
94 | 130 |
95 NodeId computeNodeId(ast.Node node, AstElement element) { | 131 void computeForElement(AstElement element) { |
96 if (element != null && element.isLocal) { | 132 ElementId id = computeElementId(element); |
97 return new NodeId(node.getBeginToken().charOffset); | 133 if (id == null) return; |
98 } else if (node is ast.Send) { | 134 String value = computeElementValue(element); |
99 dynamic sendStructure = elements.getSendStructure(node); | 135 registerValue(element.sourcePosition, id, value, element); |
100 if (sendStructure == null) return null; | 136 } |
137 | |
138 void computeForNode(ast.Node node, NodeId id, [AstElement element]) { | |
139 if (id == null) return; | |
140 String value = computeNodeValue(node, element); | |
141 SourceSpan sourceSpan = computeSourceSpan(node); | |
142 registerValue(sourceSpan, id, value, element ?? node); | |
143 } | |
144 | |
145 SourceSpan computeSourceSpan(ast.Node node) { | |
146 return new SourceSpan(resolvedAst.sourceUri, | |
147 node.getBeginToken().charOffset, node.getEndToken().charEnd); | |
148 } | |
149 | |
150 String computeElementValue(AstElement element); | |
Siggi Cherem (dart-lang)
2017/08/18 21:20:21
let's move these two up and add dart doc on them.
Johnni Winther
2017/08/19 09:30:52
Done.
| |
151 | |
152 String computeNodeValue(ast.Node node, AstElement element); | |
153 | |
154 NodeId computeDefaultNodeId(ast.Node node) { | |
155 return new NodeId(node.getBeginToken().charOffset); | |
156 } | |
157 | |
158 NodeId computeLoopNodeId(ast.Node node) { | |
159 return new NodeId(node.getBeginToken().charOffset); | |
160 } | |
161 | |
162 NodeId computeGotoNodeId(ast.Node node) { | |
163 return new NodeId(node.getBeginToken().charOffset); | |
164 } | |
165 | |
166 void run() { | |
167 resolvedAst.node.accept(this); | |
168 } | |
169 | |
170 visitNode(ast.Node node) { | |
171 node.visitChildren(this); | |
172 } | |
173 | |
174 visitVariableDefinitions(ast.VariableDefinitions node) { | |
175 for (ast.Node child in node.definitions) { | |
176 AstElement element = elements[child]; | |
177 if (element == null) { | |
178 reportHere(reporter, child, 'No element for variable.'); | |
179 } else if (!element.isLocal) { | |
180 computeForElement(element); | |
181 } else { | |
182 computeForNode(child, computeDefaultNodeId(child), element); | |
183 } | |
184 } | |
185 visitNode(node); | |
186 } | |
187 | |
188 visitFunctionExpression(ast.FunctionExpression node) { | |
189 AstElement element = elements.getFunctionDefinition(node); | |
190 if (!element.isLocal) { | |
191 computeForElement(element); | |
192 } else { | |
193 computeForNode(node, computeDefaultNodeId(node), element); | |
194 } | |
195 visitNode(node); | |
196 } | |
197 | |
198 visitSend(ast.Send node) { | |
199 dynamic sendStructure = elements.getSendStructure(node); | |
200 if (sendStructure != null) { | |
101 switch (sendStructure.kind) { | 201 switch (sendStructure.kind) { |
102 case SendStructureKind.GET: | 202 case SendStructureKind.GET: |
103 case SendStructureKind.INVOKE: | 203 case SendStructureKind.INVOKE: |
104 return computeAccessId(node, sendStructure.semantics); | 204 case SendStructureKind.BINARY: |
205 case SendStructureKind.EQUALS: | |
206 case SendStructureKind.NOT_EQUALS: | |
207 computeForNode(node, computeAccessId(node, sendStructure.semantics)); | |
208 break; | |
105 default: | 209 default: |
106 } | 210 } |
107 } | 211 } |
108 return null; | 212 visitNode(node); |
213 } | |
214 | |
215 visitLoop(ast.Loop node) { | |
216 computeForNode(node, computeLoopNodeId(node)); | |
217 visitNode(node); | |
218 } | |
219 | |
220 visitGotoStatement(ast.GotoStatement node) { | |
221 computeForNode(node, computeGotoNodeId(node)); | |
222 visitNode(node); | |
109 } | 223 } |
110 } | 224 } |
111 | 225 |
112 /// Visitor that finds the AST node or element corresponding to an [Id]. | 226 /// Abstract IR visitor for computing [Id] data. |
113 class AstIdFinder extends ast.Visitor with AstEnumeratorMixin { | 227 abstract class AbstractIrComputer extends ir.Visitor with ComputerMixin { |
114 Id soughtId; | 228 final Map<Id, ActualData> actualMap; |
115 var /*AstElement|ast.Node*/ found; | |
116 final TreeElements elements; | |
117 | 229 |
118 AstIdFinder(this.elements); | 230 AbstractIrComputer(this.actualMap); |
119 | |
120 /// Visits the subtree of [root] returns the [ast.Node] or [AstElement] | |
121 /// corresponding to [id]. | |
122 /*AstElement|ast.Node*/ find(ast.Node root, Id id) { | |
123 soughtId = id; | |
124 root.accept(this); | |
125 var result = found; | |
126 found = null; | |
127 return result; | |
128 } | |
129 | |
130 visit(ast.Node node) { | |
131 if (found == null) { | |
132 node?.accept(this); | |
133 } | |
134 } | |
135 | |
136 visitNode(ast.Node node) { | |
137 if (found == null) { | |
138 node.visitChildren(this); | |
139 } | |
140 } | |
141 | |
142 visitSend(ast.Send node) { | |
143 if (found == null) { | |
144 visitNode(node); | |
145 Id id = computeNodeId(node, null); | |
146 if (id == soughtId) { | |
147 found = node; | |
148 } | |
149 } | |
150 } | |
151 | |
152 visitVariableDefinitions(ast.VariableDefinitions node) { | |
153 if (found == null) { | |
154 for (ast.Node child in node.definitions) { | |
155 AstElement element = elements[child]; | |
156 if (element != null) { | |
157 Id id; | |
158 if (element is FieldElement) { | |
159 id = computeElementId(element); | |
160 } else { | |
161 id = computeNodeId(child, element); | |
162 } | |
163 if (id == soughtId) { | |
164 found = element; | |
165 return; | |
166 } | |
167 } | |
168 } | |
169 visitNode(node); | |
170 } | |
171 } | |
172 | |
173 visitFunctionExpression(ast.FunctionExpression node) { | |
174 if (found == null) { | |
175 AstElement element = elements.getFunctionDefinition(node); | |
176 if (element != null) { | |
177 Id id; | |
178 if (element is LocalFunctionElement) { | |
179 id = computeNodeId(node, element); | |
180 } else { | |
181 id = computeElementId(element); | |
182 } | |
183 if (id == soughtId) { | |
184 found = element; | |
185 return; | |
186 } | |
187 } | |
188 visitNode(node); | |
189 } | |
190 } | |
191 } | |
192 | |
193 abstract class IrEnumeratorMixin { | |
194 Id computeElementId(ir.Member node) { | 231 Id computeElementId(ir.Member node) { |
195 String className; | 232 String className; |
196 if (node.enclosingClass != null) { | 233 if (node.enclosingClass != null) { |
197 className = node.enclosingClass.name; | 234 className = node.enclosingClass.name; |
198 } | 235 } |
199 String memberName = node.name.name; | 236 String memberName = node.name.name; |
200 if (node is ir.Procedure && node.kind == ir.ProcedureKind.Setter) { | 237 if (node is ir.Procedure && node.kind == ir.ProcedureKind.Setter) { |
201 memberName += '='; | 238 memberName += '='; |
202 } | 239 } |
203 return new ElementId.internal(memberName, className); | 240 return new ElementId.internal(memberName, className); |
204 } | 241 } |
205 | 242 |
206 Id computeNodeId(ir.TreeNode node) { | 243 void computeForMember(ir.Member member) { |
207 if (node is ir.MethodInvocation) { | 244 ElementId id = computeElementId(member); |
208 assert(node.fileOffset != ir.TreeNode.noOffset); | 245 if (id == null) return; |
209 return new NodeId(node.fileOffset); | 246 String value = computeMemberValue(member); |
210 } else if (node is ir.PropertyGet) { | 247 registerValue(computeSourceSpan(member), id, value, member); |
211 assert(node.fileOffset != ir.TreeNode.noOffset); | |
212 return new NodeId(node.fileOffset); | |
213 } else if (node is ir.VariableDeclaration) { | |
214 assert(node.fileOffset != ir.TreeNode.noOffset); | |
215 return new NodeId(node.fileOffset); | |
216 } else if (node is ir.FunctionExpression) { | |
217 assert(node.fileOffset != ir.TreeNode.noOffset); | |
218 return new NodeId(node.fileOffset); | |
219 } else if (node is ir.FunctionDeclaration) { | |
220 assert(node.fileOffset != ir.TreeNode.noOffset); | |
221 return new NodeId(node.fileOffset); | |
222 } | |
223 return null; | |
224 } | |
225 } | |
226 | |
227 /// Visitor that finds the IR node corresponding to an [Id]. | |
228 class IrIdFinder extends ir.Visitor with IrEnumeratorMixin { | |
229 Id soughtId; | |
230 ir.Node found; | |
231 | |
232 /// Visits the subtree of [root] returns the [ir.Node] corresponding to [id]. | |
233 ir.Node find(ir.Node root, Id id) { | |
234 soughtId = id; | |
235 root.accept(this); | |
236 var result = found; | |
237 found = null; | |
238 return result; | |
239 } | 248 } |
240 | 249 |
241 defaultTreeNode(ir.TreeNode node) { | 250 void computeForNode(ir.TreeNode node, NodeId id) { |
242 if (found == null) { | 251 if (id == null) return; |
243 Id id = computeNodeId(node); | 252 String value = computeNodeValue(node); |
244 if (id == soughtId) { | 253 registerValue(computeSourceSpan(node), id, value, node); |
245 found = node; | 254 } |
246 return; | 255 |
247 } | 256 SourceSpan computeSourceSpan(ir.TreeNode node) { |
248 node.visitChildren(this); | 257 return new SourceSpan( |
249 } | 258 Uri.parse(node.location.file), node.fileOffset, node.fileOffset + 1); |
259 } | |
260 | |
261 String computeMemberValue(ir.Member member); | |
262 | |
263 String computeNodeValue(ir.TreeNode node); | |
264 | |
265 NodeId computeDefaultNodeId(ir.TreeNode node) { | |
266 assert(node.fileOffset != ir.TreeNode.noOffset); | |
267 return new NodeId(node.fileOffset); | |
268 } | |
269 | |
270 NodeId computeLoopNodeId(ir.TreeNode node) => computeDefaultNodeId(node); | |
271 NodeId computeGotoNodeId(ir.TreeNode node) => computeDefaultNodeId(node); | |
272 | |
273 void run(ir.Node root) { | |
274 root.accept(this); | |
275 } | |
276 | |
277 defaultNode(ir.Node node) { | |
278 node.visitChildren(this); | |
250 } | 279 } |
251 | 280 |
252 defaultMember(ir.Member node) { | 281 defaultMember(ir.Member node) { |
253 if (found == null) { | 282 computeForMember(node); |
254 Id id = computeElementId(node); | 283 super.defaultMember(node); |
255 if (id == soughtId) { | 284 } |
256 found = node; | 285 |
257 return; | 286 visitMethodInvocation(ir.MethodInvocation node) { |
258 } | 287 computeForNode(node, computeDefaultNodeId(node)); |
259 defaultTreeNode(node); | 288 super.visitMethodInvocation(node); |
260 } | 289 } |
290 | |
291 visitPropertyGet(ir.PropertyGet node) { | |
292 computeForNode(node, computeDefaultNodeId(node)); | |
293 super.visitPropertyGet(node); | |
294 } | |
295 | |
296 visitVariableDeclaration(ir.VariableDeclaration node) { | |
297 computeForNode(node, computeDefaultNodeId(node)); | |
298 super.visitVariableDeclaration(node); | |
299 } | |
300 | |
301 visitFunctionDeclaration(ir.FunctionDeclaration node) { | |
302 computeForNode(node, computeDefaultNodeId(node)); | |
303 super.visitFunctionDeclaration(node); | |
304 } | |
305 | |
306 visitFunctionExpression(ir.FunctionExpression node) { | |
307 computeForNode(node, computeDefaultNodeId(node)); | |
308 super.visitFunctionExpression(node); | |
309 } | |
310 | |
311 visitVariableGet(ir.VariableGet node) { | |
312 computeForNode(node, computeDefaultNodeId(node)); | |
313 super.visitVariableGet(node); | |
314 } | |
315 | |
316 visitDoStatement(ir.DoStatement node) { | |
317 computeForNode(node, computeLoopNodeId(node)); | |
318 super.visitDoStatement(node); | |
319 } | |
320 | |
321 visitForStatement(ir.ForStatement node) { | |
322 computeForNode(node, computeLoopNodeId(node)); | |
323 super.visitForStatement(node); | |
324 } | |
325 | |
326 visitForInStatement(ir.ForInStatement node) { | |
327 computeForNode(node, computeLoopNodeId(node)); | |
328 super.visitForInStatement(node); | |
329 } | |
330 | |
331 visitWhileStatement(ir.WhileStatement node) { | |
332 computeForNode(node, computeLoopNodeId(node)); | |
333 super.visitWhileStatement(node); | |
334 } | |
335 | |
336 visitBreakStatement(ir.BreakStatement node) { | |
337 computeForNode(node, computeGotoNodeId(node)); | |
338 super.visitBreakStatement(node); | |
261 } | 339 } |
262 } | 340 } |
OLD | NEW |