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