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 |