| 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 /// Abstract AST visitor for computing data corresponding to a node or element, |
| 85 // and record it with a generic [Id]. |
| 86 abstract class AstDataExtractor extends ast.Visitor { |
| 87 final DiagnosticReporter reporter; |
| 88 final Map<Id, ActualData> actualMap; |
| 89 final ResolvedAst resolvedAst; |
| 90 |
| 91 AstDataExtractor(this.reporter, this.actualMap, this.resolvedAst); |
| 92 |
| 93 /// Implement this to compute the data corresponding to [element]. |
| 94 /// |
| 95 /// If `null` is returned, [element] has no associated data. |
| 96 String computeElementValue(AstElement element); |
| 97 |
| 98 /// Implement this to compute the data corresponding to [node]. If [node] has |
| 99 /// a corresponding [AstElement] this is provided in [element]. |
| 100 /// |
| 101 /// If `null` is returned, [node] has no associated data. |
| 102 String computeNodeValue(ast.Node node, AstElement element); |
| 103 |
| 104 TreeElements get elements => resolvedAst.elements; |
| 105 |
| 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 } |
| 76 | 112 |
| 77 ElementId computeElementId(AstElement element) { | 113 ElementId computeElementId(AstElement element) { |
| 78 String memberName = element.name; | 114 String memberName = element.name; |
| 79 if (element.isSetter) { | 115 if (element.isSetter) { |
| 80 memberName += '='; | 116 memberName += '='; |
| 81 } | 117 } |
| 82 String className = element.enclosingClass?.name; | 118 String className = element.enclosingClass?.name; |
| 83 return new ElementId.internal(memberName, className); | 119 return new ElementId.internal(memberName, className); |
| 84 } | 120 } |
| 85 | 121 |
| 86 NodeId computeAccessId(ast.Send node, AccessSemantics access) { | 122 NodeId computeAccessId(ast.Send node, AccessSemantics access) { |
| 87 switch (access.kind) { | 123 switch (access.kind) { |
| 88 case AccessKind.DYNAMIC_PROPERTY: | 124 case AccessKind.DYNAMIC_PROPERTY: |
| 89 return new NodeId(node.selector.getBeginToken().charOffset); | 125 case AccessKind.LOCAL_VARIABLE: |
| 126 case AccessKind.FINAL_LOCAL_VARIABLE: |
| 127 case AccessKind.LOCAL_FUNCTION: |
| 128 case AccessKind.PARAMETER: |
| 129 case AccessKind.FINAL_PARAMETER: |
| 130 case AccessKind.EXPRESSION: |
| 131 return computeDefaultNodeId(node.selector); |
| 90 default: | 132 default: |
| 91 return null; | 133 return null; |
| 92 } | 134 } |
| 93 } | 135 } |
| 94 | 136 |
| 95 NodeId computeNodeId(ast.Node node, AstElement element) { | 137 void computeForElement(AstElement element) { |
| 96 if (element != null && element.isLocal) { | 138 ElementId id = computeElementId(element); |
| 97 return new NodeId(node.getBeginToken().charOffset); | 139 if (id == null) return; |
| 98 } else if (node is ast.Send) { | 140 String value = computeElementValue(element); |
| 99 dynamic sendStructure = elements.getSendStructure(node); | 141 registerValue(element.sourcePosition, id, value, element); |
| 100 if (sendStructure == null) return null; | 142 } |
| 143 |
| 144 void computeForNode(ast.Node node, NodeId id, [AstElement element]) { |
| 145 if (id == null) return; |
| 146 String value = computeNodeValue(node, element); |
| 147 SourceSpan sourceSpan = computeSourceSpan(node); |
| 148 registerValue(sourceSpan, id, value, element ?? node); |
| 149 } |
| 150 |
| 151 SourceSpan computeSourceSpan(ast.Node node) { |
| 152 return new SourceSpan(resolvedAst.sourceUri, |
| 153 node.getBeginToken().charOffset, node.getEndToken().charEnd); |
| 154 } |
| 155 |
| 156 NodeId computeDefaultNodeId(ast.Node node) { |
| 157 return new NodeId(node.getBeginToken().charOffset); |
| 158 } |
| 159 |
| 160 NodeId computeLoopNodeId(ast.Node node) { |
| 161 return new NodeId(node.getBeginToken().charOffset); |
| 162 } |
| 163 |
| 164 NodeId computeGotoNodeId(ast.Node node) { |
| 165 return new NodeId(node.getBeginToken().charOffset); |
| 166 } |
| 167 |
| 168 void run() { |
| 169 resolvedAst.node.accept(this); |
| 170 } |
| 171 |
| 172 visitNode(ast.Node node) { |
| 173 node.visitChildren(this); |
| 174 } |
| 175 |
| 176 visitVariableDefinitions(ast.VariableDefinitions node) { |
| 177 for (ast.Node child in node.definitions) { |
| 178 AstElement element = elements[child]; |
| 179 if (element == null) { |
| 180 reportHere(reporter, child, 'No element for variable.'); |
| 181 } else if (!element.isLocal) { |
| 182 computeForElement(element); |
| 183 } else { |
| 184 computeForNode(child, computeDefaultNodeId(child), element); |
| 185 } |
| 186 } |
| 187 visitNode(node); |
| 188 } |
| 189 |
| 190 visitFunctionExpression(ast.FunctionExpression node) { |
| 191 AstElement element = elements.getFunctionDefinition(node); |
| 192 if (!element.isLocal) { |
| 193 computeForElement(element); |
| 194 } else { |
| 195 computeForNode(node, computeDefaultNodeId(node), element); |
| 196 } |
| 197 visitNode(node); |
| 198 } |
| 199 |
| 200 visitSend(ast.Send node) { |
| 201 dynamic sendStructure = elements.getSendStructure(node); |
| 202 if (sendStructure != null) { |
| 101 switch (sendStructure.kind) { | 203 switch (sendStructure.kind) { |
| 102 case SendStructureKind.GET: | 204 case SendStructureKind.GET: |
| 103 case SendStructureKind.INVOKE: | 205 case SendStructureKind.INVOKE: |
| 104 return computeAccessId(node, sendStructure.semantics); | 206 case SendStructureKind.BINARY: |
| 207 case SendStructureKind.EQUALS: |
| 208 case SendStructureKind.NOT_EQUALS: |
| 209 computeForNode(node, computeAccessId(node, sendStructure.semantics)); |
| 210 break; |
| 105 default: | 211 default: |
| 106 } | 212 } |
| 107 } | 213 } |
| 108 return null; | 214 visitNode(node); |
| 215 } |
| 216 |
| 217 visitLoop(ast.Loop node) { |
| 218 computeForNode(node, computeLoopNodeId(node)); |
| 219 visitNode(node); |
| 220 } |
| 221 |
| 222 visitGotoStatement(ast.GotoStatement node) { |
| 223 computeForNode(node, computeGotoNodeId(node)); |
| 224 visitNode(node); |
| 109 } | 225 } |
| 110 } | 226 } |
| 111 | 227 |
| 112 /// Visitor that finds the AST node or element corresponding to an [Id]. | 228 /// Abstract IR visitor for computing data corresponding to a node or element, |
| 113 class AstIdFinder extends ast.Visitor with AstEnumeratorMixin { | 229 /// and record it with a generic [Id] |
| 114 Id soughtId; | 230 abstract class IrDataExtractor extends ir.Visitor { |
| 115 var /*AstElement|ast.Node*/ found; | 231 final Map<Id, ActualData> actualMap; |
| 116 final TreeElements elements; | |
| 117 | 232 |
| 118 AstIdFinder(this.elements); | 233 void registerValue( |
| 119 | 234 SourceSpan sourceSpan, Id id, String value, Object object) { |
| 120 /// Visits the subtree of [root] returns the [ast.Node] or [AstElement] | 235 if (value != null) { |
| 121 /// corresponding to [id]. | 236 actualMap[id] = new ActualData(id, value, sourceSpan, object); |
| 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 } | 237 } |
| 134 } | 238 } |
| 135 | 239 |
| 136 visitNode(ast.Node node) { | 240 /// Implement this to compute the data corresponding to [member]. |
| 137 if (found == null) { | 241 /// |
| 138 node.visitChildren(this); | 242 /// If `null` is returned, [member] has no associated data. |
| 139 } | 243 String computeMemberValue(ir.Member member); |
| 140 } | |
| 141 | 244 |
| 142 visitSend(ast.Send node) { | 245 /// Implement this to compute the data corresponding to [node]. |
| 143 if (found == null) { | 246 /// |
| 144 visitNode(node); | 247 /// If `null` is returned, [node] has no associated data. |
| 145 Id id = computeNodeId(node, null); | 248 String computeNodeValue(ir.TreeNode node); |
| 146 if (id == soughtId) { | |
| 147 found = node; | |
| 148 } | |
| 149 } | |
| 150 } | |
| 151 | 249 |
| 152 visitVariableDefinitions(ast.VariableDefinitions node) { | 250 IrDataExtractor(this.actualMap); |
| 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) { | 251 Id computeElementId(ir.Member node) { |
| 195 String className; | 252 String className; |
| 196 if (node.enclosingClass != null) { | 253 if (node.enclosingClass != null) { |
| 197 className = node.enclosingClass.name; | 254 className = node.enclosingClass.name; |
| 198 } | 255 } |
| 199 String memberName = node.name.name; | 256 String memberName = node.name.name; |
| 200 if (node is ir.Procedure && node.kind == ir.ProcedureKind.Setter) { | 257 if (node is ir.Procedure && node.kind == ir.ProcedureKind.Setter) { |
| 201 memberName += '='; | 258 memberName += '='; |
| 202 } | 259 } |
| 203 return new ElementId.internal(memberName, className); | 260 return new ElementId.internal(memberName, className); |
| 204 } | 261 } |
| 205 | 262 |
| 206 Id computeNodeId(ir.TreeNode node) { | 263 void computeForMember(ir.Member member) { |
| 207 if (node is ir.MethodInvocation) { | 264 ElementId id = computeElementId(member); |
| 208 assert(node.fileOffset != ir.TreeNode.noOffset); | 265 if (id == null) return; |
| 209 return new NodeId(node.fileOffset); | 266 String value = computeMemberValue(member); |
| 210 } else if (node is ir.PropertyGet) { | 267 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 } | 268 } |
| 240 | 269 |
| 241 defaultTreeNode(ir.TreeNode node) { | 270 void computeForNode(ir.TreeNode node, NodeId id) { |
| 242 if (found == null) { | 271 if (id == null) return; |
| 243 Id id = computeNodeId(node); | 272 String value = computeNodeValue(node); |
| 244 if (id == soughtId) { | 273 registerValue(computeSourceSpan(node), id, value, node); |
| 245 found = node; | 274 } |
| 246 return; | 275 |
| 247 } | 276 SourceSpan computeSourceSpan(ir.TreeNode node) { |
| 248 node.visitChildren(this); | 277 return new SourceSpan( |
| 249 } | 278 Uri.parse(node.location.file), node.fileOffset, node.fileOffset + 1); |
| 279 } |
| 280 |
| 281 NodeId computeDefaultNodeId(ir.TreeNode node) { |
| 282 assert(node.fileOffset != ir.TreeNode.noOffset); |
| 283 return new NodeId(node.fileOffset); |
| 284 } |
| 285 |
| 286 NodeId computeLoopNodeId(ir.TreeNode node) => computeDefaultNodeId(node); |
| 287 NodeId computeGotoNodeId(ir.TreeNode node) => computeDefaultNodeId(node); |
| 288 |
| 289 void run(ir.Node root) { |
| 290 root.accept(this); |
| 291 } |
| 292 |
| 293 defaultNode(ir.Node node) { |
| 294 node.visitChildren(this); |
| 250 } | 295 } |
| 251 | 296 |
| 252 defaultMember(ir.Member node) { | 297 defaultMember(ir.Member node) { |
| 253 if (found == null) { | 298 computeForMember(node); |
| 254 Id id = computeElementId(node); | 299 super.defaultMember(node); |
| 255 if (id == soughtId) { | 300 } |
| 256 found = node; | 301 |
| 257 return; | 302 visitMethodInvocation(ir.MethodInvocation node) { |
| 258 } | 303 computeForNode(node, computeDefaultNodeId(node)); |
| 259 defaultTreeNode(node); | 304 super.visitMethodInvocation(node); |
| 260 } | 305 } |
| 306 |
| 307 visitPropertyGet(ir.PropertyGet node) { |
| 308 computeForNode(node, computeDefaultNodeId(node)); |
| 309 super.visitPropertyGet(node); |
| 310 } |
| 311 |
| 312 visitVariableDeclaration(ir.VariableDeclaration node) { |
| 313 computeForNode(node, computeDefaultNodeId(node)); |
| 314 super.visitVariableDeclaration(node); |
| 315 } |
| 316 |
| 317 visitFunctionDeclaration(ir.FunctionDeclaration node) { |
| 318 computeForNode(node, computeDefaultNodeId(node)); |
| 319 super.visitFunctionDeclaration(node); |
| 320 } |
| 321 |
| 322 visitFunctionExpression(ir.FunctionExpression node) { |
| 323 computeForNode(node, computeDefaultNodeId(node)); |
| 324 super.visitFunctionExpression(node); |
| 325 } |
| 326 |
| 327 visitVariableGet(ir.VariableGet node) { |
| 328 computeForNode(node, computeDefaultNodeId(node)); |
| 329 super.visitVariableGet(node); |
| 330 } |
| 331 |
| 332 visitDoStatement(ir.DoStatement node) { |
| 333 computeForNode(node, computeLoopNodeId(node)); |
| 334 super.visitDoStatement(node); |
| 335 } |
| 336 |
| 337 visitForStatement(ir.ForStatement node) { |
| 338 computeForNode(node, computeLoopNodeId(node)); |
| 339 super.visitForStatement(node); |
| 340 } |
| 341 |
| 342 visitForInStatement(ir.ForInStatement node) { |
| 343 computeForNode(node, computeLoopNodeId(node)); |
| 344 super.visitForInStatement(node); |
| 345 } |
| 346 |
| 347 visitWhileStatement(ir.WhileStatement node) { |
| 348 computeForNode(node, computeLoopNodeId(node)); |
| 349 super.visitWhileStatement(node); |
| 350 } |
| 351 |
| 352 visitBreakStatement(ir.BreakStatement node) { |
| 353 computeForNode(node, computeGotoNodeId(node)); |
| 354 super.visitBreakStatement(node); |
| 261 } | 355 } |
| 262 } | 356 } |
| OLD | NEW |