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/common.dart'; |
6 import 'package:compiler/src/elements/elements.dart'; | 6 import 'package:compiler/src/elements/elements.dart'; |
7 import 'package:compiler/src/resolution/access_semantics.dart'; | 7 import 'package:compiler/src/resolution/access_semantics.dart'; |
8 import 'package:compiler/src/resolution/send_structure.dart'; | 8 import 'package:compiler/src/resolution/send_structure.dart'; |
9 import 'package:compiler/src/resolution/tree_elements.dart'; | 9 import 'package:compiler/src/resolution/tree_elements.dart'; |
10 import 'package:compiler/src/tree/nodes.dart' as ast; | 10 import 'package:compiler/src/tree/nodes.dart' as ast; |
| 11 import 'package:expect/expect.dart'; |
11 import 'package:kernel/ast.dart' as ir; | 12 import 'package:kernel/ast.dart' as ir; |
12 | 13 |
13 enum IdKind { | 14 enum IdKind { |
14 element, | 15 element, |
15 node, | 16 node, |
| 17 invoke, |
| 18 update, |
16 } | 19 } |
17 | 20 |
18 /// Id for a code point or element with type inference information. | 21 /// Id for a code point or element with type inference information. |
19 abstract class Id { | 22 abstract class Id { |
20 IdKind get kind; | 23 IdKind get kind; |
21 } | 24 } |
22 | 25 |
| 26 class IdValue { |
| 27 final Id id; |
| 28 final String value; |
| 29 |
| 30 const IdValue(this.id, this.value); |
| 31 |
| 32 int get hashCode => id.hashCode * 13 + value.hashCode * 17; |
| 33 |
| 34 bool operator ==(other) { |
| 35 if (identical(this, other)) return true; |
| 36 if (other is! IdValue) return false; |
| 37 return id == other.id && value == other.value; |
| 38 } |
| 39 |
| 40 String toString() { |
| 41 switch (id.kind) { |
| 42 case IdKind.element: |
| 43 ElementId elementId = id; |
| 44 return '$elementPrefix${elementId.name}:$value'; |
| 45 case IdKind.node: |
| 46 return value; |
| 47 case IdKind.invoke: |
| 48 return '$invokePrefix$value'; |
| 49 case IdKind.update: |
| 50 return '$updatePrefix$value'; |
| 51 } |
| 52 throw new UnsupportedError("Unexpected id kind: ${id.kind}"); |
| 53 } |
| 54 |
| 55 static const String elementPrefix = "element: "; |
| 56 static const String invokePrefix = "invoke: "; |
| 57 static const String updatePrefix = "update: "; |
| 58 |
| 59 static IdValue decode(int offset, String text) { |
| 60 Id id; |
| 61 String expected; |
| 62 if (text.startsWith(elementPrefix)) { |
| 63 text = text.substring(elementPrefix.length); |
| 64 int colonPos = text.indexOf(':'); |
| 65 id = new ElementId(text.substring(0, colonPos)); |
| 66 expected = text.substring(colonPos + 1); |
| 67 } else if (text.startsWith(invokePrefix)) { |
| 68 id = new NodeId(offset, IdKind.invoke); |
| 69 expected = text.substring(invokePrefix.length); |
| 70 } else if (text.startsWith(updatePrefix)) { |
| 71 id = new NodeId(offset, IdKind.update); |
| 72 expected = text.substring(updatePrefix.length); |
| 73 } else { |
| 74 id = new NodeId(offset, IdKind.node); |
| 75 expected = text; |
| 76 } |
| 77 return new IdValue(id, expected); |
| 78 } |
| 79 } |
| 80 |
23 /// Id for an element with type inference information. | 81 /// Id for an element with type inference information. |
24 // TODO(johnniwinther): Support local variables, functions and parameters. | 82 // TODO(johnniwinther): Support local variables, functions and parameters. |
25 class ElementId implements Id { | 83 class ElementId implements Id { |
26 final String className; | 84 final String className; |
27 final String memberName; | 85 final String memberName; |
28 | 86 |
29 factory ElementId(String text) { | 87 factory ElementId(String text) { |
30 int dotPos = text.indexOf('.'); | 88 int dotPos = text.indexOf('.'); |
31 if (dotPos != -1) { | 89 if (dotPos != -1) { |
32 return new ElementId.internal( | 90 return new ElementId.internal( |
33 text.substring(dotPos + 1), text.substring(0, dotPos)); | 91 text.substring(dotPos + 1), text.substring(0, dotPos)); |
34 } else { | 92 } else { |
35 return new ElementId.internal(text); | 93 return new ElementId.internal(text); |
36 } | 94 } |
37 } | 95 } |
38 | 96 |
39 ElementId.internal(this.memberName, [this.className]); | 97 ElementId.internal(this.memberName, [this.className]); |
40 | 98 |
41 int get hashCode => className.hashCode * 13 + memberName.hashCode * 17; | 99 int get hashCode => className.hashCode * 13 + memberName.hashCode * 17; |
42 | 100 |
43 bool operator ==(other) { | 101 bool operator ==(other) { |
44 if (identical(this, other)) return true; | 102 if (identical(this, other)) return true; |
45 if (other is! ElementId) return false; | 103 if (other is! ElementId) return false; |
46 return className == other.className && memberName == other.memberName; | 104 return className == other.className && memberName == other.memberName; |
47 } | 105 } |
48 | 106 |
49 IdKind get kind => IdKind.element; | 107 IdKind get kind => IdKind.element; |
50 | 108 |
51 String toString() => | 109 String get name => className != null ? '$className.$memberName' : memberName; |
52 className != null ? '$className.$memberName' : memberName; | 110 |
| 111 String toString() => name; |
53 } | 112 } |
54 | 113 |
55 /// Id for a code point with type inference information. | 114 /// Id for a code point with type inference information. |
56 // TODO(johnniwinther): Create an [NodeId]-based equivalence with the kernel IR. | 115 // TODO(johnniwinther): Create an [NodeId]-based equivalence with the kernel IR. |
57 class NodeId implements Id { | 116 class NodeId implements Id { |
58 final int value; | 117 final int value; |
| 118 final IdKind kind; |
59 | 119 |
60 const NodeId(this.value); | 120 const NodeId(this.value, this.kind); |
61 | 121 |
62 int get hashCode => value.hashCode; | 122 int get hashCode => value.hashCode * 13 + kind.hashCode * 17; |
63 | 123 |
64 bool operator ==(other) { | 124 bool operator ==(other) { |
65 if (identical(this, other)) return true; | 125 if (identical(this, other)) return true; |
66 if (other is! NodeId) return false; | 126 if (other is! NodeId) return false; |
67 return value == other.value; | 127 return value == other.value && kind == other.kind; |
68 } | 128 } |
69 | 129 |
70 IdKind get kind => IdKind.node; | |
71 | |
72 String toString() => '$kind:$value'; | 130 String toString() => '$kind:$value'; |
73 } | 131 } |
74 | 132 |
75 class ActualData { | 133 class ActualData { |
76 final Id id; | 134 final IdValue value; |
77 final String value; | |
78 final SourceSpan sourceSpan; | 135 final SourceSpan sourceSpan; |
79 final Object object; | 136 final Object object; |
80 | 137 |
81 ActualData(this.id, this.value, this.sourceSpan, this.object); | 138 ActualData(this.value, this.sourceSpan, this.object); |
| 139 } |
| 140 |
| 141 abstract class DataRegistry { |
| 142 DiagnosticReporter get reporter; |
| 143 Map<Id, ActualData> get actualMap; |
| 144 |
| 145 void registerValue( |
| 146 SourceSpan sourceSpan, Id id, String value, Object object) { |
| 147 if (actualMap.containsKey(id)) { |
| 148 ActualData existingData = actualMap[id]; |
| 149 reportHere(reporter, sourceSpan, |
| 150 "Duplicate id ${id}, value=$value, object=$object"); |
| 151 reportHere( |
| 152 reporter, |
| 153 sourceSpan, |
| 154 "Duplicate id ${id}, value=${existingData.value}, " |
| 155 "object=${existingData.object}"); |
| 156 Expect.fail("Duplicate id $id."); |
| 157 } |
| 158 if (value != null) { |
| 159 actualMap[id] = |
| 160 new ActualData(new IdValue(id, value), sourceSpan, object); |
| 161 } |
| 162 } |
82 } | 163 } |
83 | 164 |
84 /// Abstract AST visitor for computing data corresponding to a node or element, | 165 /// Abstract AST visitor for computing data corresponding to a node or element, |
85 // and record it with a generic [Id]. | 166 // and record it with a generic [Id]. |
86 abstract class AstDataExtractor extends ast.Visitor { | 167 abstract class AstDataExtractor extends ast.Visitor with DataRegistry { |
87 final DiagnosticReporter reporter; | 168 final DiagnosticReporter reporter; |
88 final Map<Id, ActualData> actualMap; | 169 final Map<Id, ActualData> actualMap; |
89 final ResolvedAst resolvedAst; | 170 final ResolvedAst resolvedAst; |
90 | 171 |
91 AstDataExtractor(this.reporter, this.actualMap, this.resolvedAst); | 172 AstDataExtractor(this.reporter, this.actualMap, this.resolvedAst); |
92 | 173 |
93 /// Implement this to compute the data corresponding to [element]. | 174 /// Implement this to compute the data corresponding to [element]. |
94 /// | 175 /// |
95 /// If `null` is returned, [element] has no associated data. | 176 /// If `null` is returned, [element] has no associated data. |
96 String computeElementValue(AstElement element); | 177 String computeElementValue(Id id, AstElement element); |
97 | 178 |
98 /// Implement this to compute the data corresponding to [node]. If [node] has | 179 /// Implement this to compute the data corresponding to [node]. If [node] has |
99 /// a corresponding [AstElement] this is provided in [element]. | 180 /// a corresponding [AstElement] this is provided in [element]. |
100 /// | 181 /// |
101 /// If `null` is returned, [node] has no associated data. | 182 /// If `null` is returned, [node] has no associated data. |
102 String computeNodeValue(ast.Node node, AstElement element); | 183 String computeNodeValue(Id id, ast.Node node, AstElement element); |
103 | 184 |
104 TreeElements get elements => resolvedAst.elements; | 185 TreeElements get elements => resolvedAst.elements; |
105 | 186 |
106 void registerValue( | |
107 SourceSpan sourceSpan, Id id, String value, Object object) { | |
108 if (value != null) { | |
109 actualMap[id] = new ActualData(id, value, sourceSpan, object); | |
110 } | |
111 } | |
112 | |
113 ElementId computeElementId(AstElement element) { | 187 ElementId computeElementId(AstElement element) { |
114 String memberName = element.name; | 188 String memberName = element.name; |
115 if (element.isSetter) { | 189 if (element.isSetter) { |
116 memberName += '='; | 190 memberName += '='; |
117 } | 191 } |
118 String className = element.enclosingClass?.name; | 192 String className = element.enclosingClass?.name; |
119 return new ElementId.internal(memberName, className); | 193 return new ElementId.internal(memberName, className); |
120 } | 194 } |
121 | 195 |
122 NodeId computeAccessId(ast.Send node, AccessSemantics access) { | 196 ast.Node computeAccessPosition(ast.Send node, AccessSemantics access) { |
123 switch (access.kind) { | 197 switch (access.kind) { |
124 case AccessKind.DYNAMIC_PROPERTY: | 198 case AccessKind.DYNAMIC_PROPERTY: |
125 case AccessKind.LOCAL_VARIABLE: | 199 case AccessKind.LOCAL_VARIABLE: |
126 case AccessKind.FINAL_LOCAL_VARIABLE: | 200 case AccessKind.FINAL_LOCAL_VARIABLE: |
127 case AccessKind.LOCAL_FUNCTION: | 201 case AccessKind.LOCAL_FUNCTION: |
128 case AccessKind.PARAMETER: | 202 case AccessKind.PARAMETER: |
129 case AccessKind.FINAL_PARAMETER: | 203 case AccessKind.FINAL_PARAMETER: |
130 case AccessKind.EXPRESSION: | 204 case AccessKind.EXPRESSION: |
131 return computeDefaultNodeId(node.selector); | 205 return node.selector; |
132 default: | 206 default: |
133 return null; | 207 return null; |
134 } | 208 } |
| 209 } |
| 210 |
| 211 ast.Node computeUpdatePosition(ast.Send node, AccessSemantics access) { |
| 212 switch (access.kind) { |
| 213 case AccessKind.DYNAMIC_PROPERTY: |
| 214 case AccessKind.LOCAL_VARIABLE: |
| 215 case AccessKind.PARAMETER: |
| 216 return node.selector; |
| 217 default: |
| 218 return null; |
| 219 } |
135 } | 220 } |
136 | 221 |
137 void computeForElement(AstElement element) { | 222 void computeForElement(AstElement element) { |
138 ElementId id = computeElementId(element); | 223 ElementId id = computeElementId(element); |
139 if (id == null) return; | 224 if (id == null) return; |
140 String value = computeElementValue(element); | 225 String value = computeElementValue(id, element); |
141 registerValue(element.sourcePosition, id, value, element); | 226 registerValue(element.sourcePosition, id, value, element); |
142 } | 227 } |
143 | 228 |
144 void computeForNode(ast.Node node, NodeId id, [AstElement element]) { | 229 void computeForNode(ast.Node node, NodeId id, [AstElement element]) { |
145 if (id == null) return; | 230 if (id == null) return; |
146 String value = computeNodeValue(node, element); | 231 String value = computeNodeValue(id, node, element); |
147 SourceSpan sourceSpan = computeSourceSpan(node); | 232 SourceSpan sourceSpan = computeSourceSpan(node); |
148 registerValue(sourceSpan, id, value, element ?? node); | 233 registerValue(sourceSpan, id, value, element ?? node); |
149 } | 234 } |
150 | 235 |
151 SourceSpan computeSourceSpan(ast.Node node) { | 236 SourceSpan computeSourceSpan(ast.Node node) { |
152 return new SourceSpan(resolvedAst.sourceUri, | 237 return new SourceSpan(resolvedAst.sourceUri, |
153 node.getBeginToken().charOffset, node.getEndToken().charEnd); | 238 node.getBeginToken().charOffset, node.getEndToken().charEnd); |
154 } | 239 } |
155 | 240 |
156 NodeId computeDefaultNodeId(ast.Node node) { | 241 NodeId computeDefaultNodeId(ast.Node node) { |
157 return new NodeId(node.getBeginToken().charOffset); | 242 return new NodeId(node.getBeginToken().charOffset, IdKind.node); |
158 } | 243 } |
159 | 244 |
160 NodeId computeLoopNodeId(ast.Node node) => computeDefaultNodeId(node); | 245 NodeId createAccessId(ast.Node node) { |
| 246 return new NodeId(node.getBeginToken().charOffset, IdKind.node); |
| 247 } |
161 | 248 |
162 NodeId computeGotoNodeId(ast.Node node) => computeDefaultNodeId(node); | 249 NodeId createInvokeId(ast.Node node) { |
| 250 return new NodeId(node.getBeginToken().charOffset, IdKind.invoke); |
| 251 } |
163 | 252 |
164 NodeId computeSwitchNodeId(ast.SwitchStatement node) => | 253 NodeId createUpdateId(ast.Node node) { |
165 computeDefaultNodeId(node); | 254 return new NodeId(node.getBeginToken().charOffset, IdKind.update); |
| 255 } |
166 | 256 |
167 NodeId computeSwitchCaseNodeId(ast.SwitchCase node) { | 257 NodeId createLoopId(ast.Node node) => computeDefaultNodeId(node); |
| 258 |
| 259 NodeId createGotoId(ast.Node node) => computeDefaultNodeId(node); |
| 260 |
| 261 NodeId createSwitchId(ast.SwitchStatement node) => computeDefaultNodeId(node); |
| 262 |
| 263 NodeId createSwitchCaseId(ast.SwitchCase node) { |
168 ast.Node position; | 264 ast.Node position; |
169 for (ast.Node child in node.labelsAndCases) { | 265 for (ast.Node child in node.labelsAndCases) { |
170 if (child.asCaseMatch() != null) { | 266 if (child.asCaseMatch() != null) { |
171 ast.CaseMatch caseMatch = child; | 267 ast.CaseMatch caseMatch = child; |
172 position = caseMatch.expression; | 268 position = caseMatch.expression; |
173 break; | 269 break; |
174 } | 270 } |
175 } | 271 } |
176 return computeDefaultNodeId(position); | 272 return computeDefaultNodeId(position); |
177 } | 273 } |
(...skipping 28 matching lines...) Expand all Loading... |
206 computeForNode(node, computeDefaultNodeId(node), element); | 302 computeForNode(node, computeDefaultNodeId(node), element); |
207 } | 303 } |
208 visitNode(node); | 304 visitNode(node); |
209 } | 305 } |
210 | 306 |
211 visitSend(ast.Send node) { | 307 visitSend(ast.Send node) { |
212 dynamic sendStructure = elements.getSendStructure(node); | 308 dynamic sendStructure = elements.getSendStructure(node); |
213 if (sendStructure != null) { | 309 if (sendStructure != null) { |
214 switch (sendStructure.kind) { | 310 switch (sendStructure.kind) { |
215 case SendStructureKind.GET: | 311 case SendStructureKind.GET: |
| 312 ast.Node position = |
| 313 computeAccessPosition(node, sendStructure.semantics); |
| 314 if (position != null) { |
| 315 computeForNode(node, computeDefaultNodeId(position)); |
| 316 } |
| 317 break; |
216 case SendStructureKind.INVOKE: | 318 case SendStructureKind.INVOKE: |
217 case SendStructureKind.BINARY: | 319 case SendStructureKind.BINARY: |
218 case SendStructureKind.EQUALS: | 320 case SendStructureKind.EQUALS: |
219 case SendStructureKind.NOT_EQUALS: | 321 case SendStructureKind.NOT_EQUALS: |
220 computeForNode(node, computeAccessId(node, sendStructure.semantics)); | 322 ast.Node position = |
| 323 computeAccessPosition(node, sendStructure.semantics); |
| 324 if (position != null) { |
| 325 computeForNode(node, createInvokeId(position)); |
| 326 } |
| 327 break; |
| 328 case SendStructureKind.SET: |
221 break; | 329 break; |
222 default: | 330 default: |
223 } | 331 } |
| 332 } |
| 333 visitNode(node); |
| 334 } |
| 335 |
| 336 visitSendSet(ast.SendSet node) { |
| 337 dynamic sendStructure = elements.getSendStructure(node); |
| 338 if (sendStructure != null) { |
| 339 switch (sendStructure.kind) { |
| 340 case SendStructureKind.SET: |
| 341 ast.Node position = |
| 342 computeUpdatePosition(node, sendStructure.semantics); |
| 343 if (position != null) { |
| 344 computeForNode(node, createUpdateId(position)); |
| 345 } |
| 346 break; |
| 347 case SendStructureKind.POSTFIX: |
| 348 computeForNode(node, createAccessId(node.selector)); |
| 349 computeForNode(node, createInvokeId(node.assignmentOperator)); |
| 350 computeForNode(node, createUpdateId(node.selector)); |
| 351 break; |
| 352 default: |
| 353 } |
224 } | 354 } |
225 visitNode(node); | 355 visitNode(node); |
226 } | 356 } |
227 | 357 |
228 visitLoop(ast.Loop node) { | 358 visitLoop(ast.Loop node) { |
229 computeForNode(node, computeLoopNodeId(node)); | 359 computeForNode(node, createLoopId(node)); |
230 visitNode(node); | 360 visitNode(node); |
231 } | 361 } |
232 | 362 |
233 visitGotoStatement(ast.GotoStatement node) { | 363 visitGotoStatement(ast.GotoStatement node) { |
234 computeForNode(node, computeGotoNodeId(node)); | 364 computeForNode(node, createGotoId(node)); |
235 visitNode(node); | 365 visitNode(node); |
236 } | 366 } |
237 | 367 |
238 visitSwitchStatement(ast.SwitchStatement node) { | 368 visitSwitchStatement(ast.SwitchStatement node) { |
239 computeForNode(node, computeSwitchNodeId(node)); | 369 computeForNode(node, createSwitchId(node)); |
240 visitNode(node); | 370 visitNode(node); |
241 } | 371 } |
242 | 372 |
243 visitSwitchCase(ast.SwitchCase node) { | 373 visitSwitchCase(ast.SwitchCase node) { |
244 computeForNode(node, computeSwitchCaseNodeId(node)); | 374 computeForNode(node, createSwitchCaseId(node)); |
245 visitNode(node); | 375 visitNode(node); |
246 } | 376 } |
247 } | 377 } |
248 | 378 |
249 /// Abstract IR visitor for computing data corresponding to a node or element, | 379 /// Abstract IR visitor for computing data corresponding to a node or element, |
250 /// and record it with a generic [Id] | 380 /// and record it with a generic [Id] |
251 abstract class IrDataExtractor extends ir.Visitor { | 381 abstract class IrDataExtractor extends ir.Visitor with DataRegistry { |
| 382 final DiagnosticReporter reporter; |
252 final Map<Id, ActualData> actualMap; | 383 final Map<Id, ActualData> actualMap; |
253 | 384 |
254 void registerValue( | |
255 SourceSpan sourceSpan, Id id, String value, Object object) { | |
256 if (value != null) { | |
257 actualMap[id] = new ActualData(id, value, sourceSpan, object); | |
258 } | |
259 } | |
260 | |
261 /// Implement this to compute the data corresponding to [member]. | 385 /// Implement this to compute the data corresponding to [member]. |
262 /// | 386 /// |
263 /// If `null` is returned, [member] has no associated data. | 387 /// If `null` is returned, [member] has no associated data. |
264 String computeMemberValue(ir.Member member); | 388 String computeMemberValue(Id id, ir.Member member); |
265 | 389 |
266 /// Implement this to compute the data corresponding to [node]. | 390 /// Implement this to compute the data corresponding to [node]. |
267 /// | 391 /// |
268 /// If `null` is returned, [node] has no associated data. | 392 /// If `null` is returned, [node] has no associated data. |
269 String computeNodeValue(ir.TreeNode node); | 393 String computeNodeValue(Id id, ir.TreeNode node); |
270 | 394 |
271 IrDataExtractor(this.actualMap); | 395 IrDataExtractor(this.reporter, this.actualMap); |
272 Id computeElementId(ir.Member node) { | 396 Id computeElementId(ir.Member node) { |
273 String className; | 397 String className; |
274 if (node.enclosingClass != null) { | 398 if (node.enclosingClass != null) { |
275 className = node.enclosingClass.name; | 399 className = node.enclosingClass.name; |
276 } | 400 } |
277 String memberName = node.name.name; | 401 String memberName = node.name.name; |
278 if (node is ir.Procedure && node.kind == ir.ProcedureKind.Setter) { | 402 if (node is ir.Procedure && node.kind == ir.ProcedureKind.Setter) { |
279 memberName += '='; | 403 memberName += '='; |
280 } | 404 } |
281 return new ElementId.internal(memberName, className); | 405 return new ElementId.internal(memberName, className); |
282 } | 406 } |
283 | 407 |
284 void computeForMember(ir.Member member) { | 408 void computeForMember(ir.Member member) { |
285 ElementId id = computeElementId(member); | 409 ElementId id = computeElementId(member); |
286 if (id == null) return; | 410 if (id == null) return; |
287 String value = computeMemberValue(member); | 411 String value = computeMemberValue(id, member); |
288 registerValue(computeSourceSpan(member), id, value, member); | 412 registerValue(computeSourceSpan(member), id, value, member); |
289 } | 413 } |
290 | 414 |
291 void computeForNode(ir.TreeNode node, NodeId id) { | 415 void computeForNode(ir.TreeNode node, NodeId id) { |
292 if (id == null) return; | 416 if (id == null) return; |
293 String value = computeNodeValue(node); | 417 String value = computeNodeValue(id, node); |
294 registerValue(computeSourceSpan(node), id, value, node); | 418 registerValue(computeSourceSpan(node), id, value, node); |
295 } | 419 } |
296 | 420 |
297 SourceSpan computeSourceSpan(ir.TreeNode node) { | 421 SourceSpan computeSourceSpan(ir.TreeNode node) { |
298 return new SourceSpan( | 422 return new SourceSpan( |
299 Uri.parse(node.location.file), node.fileOffset, node.fileOffset + 1); | 423 Uri.parse(node.location.file), node.fileOffset, node.fileOffset + 1); |
300 } | 424 } |
301 | 425 |
302 NodeId computeDefaultNodeId(ir.TreeNode node) { | 426 NodeId computeDefaultNodeId(ir.TreeNode node) { |
303 assert(node.fileOffset != ir.TreeNode.noOffset); | 427 assert(node.fileOffset != ir.TreeNode.noOffset); |
304 return new NodeId(node.fileOffset); | 428 return new NodeId(node.fileOffset, IdKind.node); |
305 } | 429 } |
306 | 430 |
307 NodeId computeLoopNodeId(ir.TreeNode node) => computeDefaultNodeId(node); | 431 NodeId createInvokeId(ir.TreeNode node) { |
308 NodeId computeGotoNodeId(ir.TreeNode node) => computeDefaultNodeId(node); | 432 assert(node.fileOffset != ir.TreeNode.noOffset); |
309 NodeId computeSwitchNodeId(ir.SwitchStatement node) => | 433 return new NodeId(node.fileOffset, IdKind.invoke); |
310 computeDefaultNodeId(node); | 434 } |
311 NodeId computeSwitchCaseNodeId(ir.SwitchCase node) => | 435 |
312 new NodeId(node.expressionOffsets.first); | 436 NodeId createUpdateId(ir.TreeNode node) { |
| 437 assert(node.fileOffset != ir.TreeNode.noOffset); |
| 438 return new NodeId(node.fileOffset, IdKind.update); |
| 439 } |
| 440 |
| 441 NodeId createLoopId(ir.TreeNode node) => computeDefaultNodeId(node); |
| 442 NodeId createGotoId(ir.TreeNode node) => computeDefaultNodeId(node); |
| 443 NodeId createSwitchId(ir.SwitchStatement node) => computeDefaultNodeId(node); |
| 444 NodeId createSwitchCaseId(ir.SwitchCase node) => |
| 445 new NodeId(node.expressionOffsets.first, IdKind.node); |
313 | 446 |
314 void run(ir.Node root) { | 447 void run(ir.Node root) { |
315 root.accept(this); | 448 root.accept(this); |
316 } | 449 } |
317 | 450 |
318 defaultNode(ir.Node node) { | 451 defaultNode(ir.Node node) { |
319 node.visitChildren(this); | 452 node.visitChildren(this); |
320 } | 453 } |
321 | 454 |
322 defaultMember(ir.Member node) { | 455 defaultMember(ir.Member node) { |
323 computeForMember(node); | 456 computeForMember(node); |
324 super.defaultMember(node); | 457 super.defaultMember(node); |
325 } | 458 } |
326 | 459 |
327 visitMethodInvocation(ir.MethodInvocation node) { | 460 visitMethodInvocation(ir.MethodInvocation node) { |
328 computeForNode(node, computeDefaultNodeId(node)); | 461 computeForNode(node, createInvokeId(node)); |
329 super.visitMethodInvocation(node); | 462 super.visitMethodInvocation(node); |
330 } | 463 } |
331 | 464 |
332 visitPropertyGet(ir.PropertyGet node) { | 465 visitPropertyGet(ir.PropertyGet node) { |
333 computeForNode(node, computeDefaultNodeId(node)); | 466 computeForNode(node, computeDefaultNodeId(node)); |
334 super.visitPropertyGet(node); | 467 super.visitPropertyGet(node); |
335 } | 468 } |
336 | 469 |
337 visitVariableDeclaration(ir.VariableDeclaration node) { | 470 visitVariableDeclaration(ir.VariableDeclaration node) { |
338 computeForNode(node, computeDefaultNodeId(node)); | 471 if (node.parent is! ir.FunctionDeclaration) { |
| 472 computeForNode(node, computeDefaultNodeId(node)); |
| 473 } |
339 super.visitVariableDeclaration(node); | 474 super.visitVariableDeclaration(node); |
340 } | 475 } |
341 | 476 |
342 visitFunctionDeclaration(ir.FunctionDeclaration node) { | 477 visitFunctionDeclaration(ir.FunctionDeclaration node) { |
343 computeForNode(node, computeDefaultNodeId(node)); | 478 computeForNode(node, computeDefaultNodeId(node)); |
344 super.visitFunctionDeclaration(node); | 479 super.visitFunctionDeclaration(node); |
345 } | 480 } |
346 | 481 |
347 visitFunctionExpression(ir.FunctionExpression node) { | 482 visitFunctionExpression(ir.FunctionExpression node) { |
348 computeForNode(node, computeDefaultNodeId(node)); | 483 computeForNode(node, computeDefaultNodeId(node)); |
349 super.visitFunctionExpression(node); | 484 super.visitFunctionExpression(node); |
350 } | 485 } |
351 | 486 |
352 visitVariableGet(ir.VariableGet node) { | 487 visitVariableGet(ir.VariableGet node) { |
353 computeForNode(node, computeDefaultNodeId(node)); | 488 computeForNode(node, computeDefaultNodeId(node)); |
354 super.visitVariableGet(node); | 489 super.visitVariableGet(node); |
355 } | 490 } |
356 | 491 |
| 492 visitPropertySet(ir.PropertySet node) { |
| 493 computeForNode(node, createUpdateId(node)); |
| 494 super.visitPropertySet(node); |
| 495 } |
| 496 |
| 497 visitVariableSet(ir.VariableSet node) { |
| 498 computeForNode(node, createUpdateId(node)); |
| 499 super.visitVariableSet(node); |
| 500 } |
| 501 |
357 visitDoStatement(ir.DoStatement node) { | 502 visitDoStatement(ir.DoStatement node) { |
358 computeForNode(node, computeLoopNodeId(node)); | 503 computeForNode(node, createLoopId(node)); |
359 super.visitDoStatement(node); | 504 super.visitDoStatement(node); |
360 } | 505 } |
361 | 506 |
362 visitForStatement(ir.ForStatement node) { | 507 visitForStatement(ir.ForStatement node) { |
363 computeForNode(node, computeLoopNodeId(node)); | 508 computeForNode(node, createLoopId(node)); |
364 super.visitForStatement(node); | 509 super.visitForStatement(node); |
365 } | 510 } |
366 | 511 |
367 visitForInStatement(ir.ForInStatement node) { | 512 visitForInStatement(ir.ForInStatement node) { |
368 computeForNode(node, computeLoopNodeId(node)); | 513 computeForNode(node, createLoopId(node)); |
369 super.visitForInStatement(node); | 514 super.visitForInStatement(node); |
370 } | 515 } |
371 | 516 |
372 visitWhileStatement(ir.WhileStatement node) { | 517 visitWhileStatement(ir.WhileStatement node) { |
373 computeForNode(node, computeLoopNodeId(node)); | 518 computeForNode(node, createLoopId(node)); |
374 super.visitWhileStatement(node); | 519 super.visitWhileStatement(node); |
375 } | 520 } |
376 | 521 |
377 visitBreakStatement(ir.BreakStatement node) { | 522 visitBreakStatement(ir.BreakStatement node) { |
378 computeForNode(node, computeGotoNodeId(node)); | 523 computeForNode(node, createGotoId(node)); |
379 super.visitBreakStatement(node); | 524 super.visitBreakStatement(node); |
380 } | 525 } |
381 | 526 |
382 visitSwitchStatement(ir.SwitchStatement node) { | 527 visitSwitchStatement(ir.SwitchStatement node) { |
383 computeForNode(node, computeSwitchNodeId(node)); | 528 computeForNode(node, createSwitchId(node)); |
384 super.visitSwitchStatement(node); | 529 super.visitSwitchStatement(node); |
385 } | 530 } |
386 | 531 |
387 visitSwitchCase(ir.SwitchCase node) { | 532 visitSwitchCase(ir.SwitchCase node) { |
388 computeForNode(node, computeSwitchCaseNodeId(node)); | 533 computeForNode(node, createSwitchCaseId(node)); |
389 super.visitSwitchCase(node); | 534 super.visitSwitchCase(node); |
390 } | 535 } |
391 | 536 |
392 visitContinueSwitchStatement(ir.ContinueSwitchStatement node) { | 537 visitContinueSwitchStatement(ir.ContinueSwitchStatement node) { |
393 computeForNode(node, computeGotoNodeId(node)); | 538 computeForNode(node, createGotoId(node)); |
394 super.visitContinueSwitchStatement(node); | 539 super.visitContinueSwitchStatement(node); |
395 } | 540 } |
396 } | 541 } |
OLD | NEW |