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/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 |