OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 library analyzer.src.generated.declaration_resolver; | 5 library analyzer.src.generated.declaration_resolver; |
6 | 6 |
7 import 'dart:collection'; | |
8 | |
9 import 'package:analyzer/dart/ast/ast.dart'; | 7 import 'package:analyzer/dart/ast/ast.dart'; |
10 import 'package:analyzer/dart/ast/token.dart'; | 8 import 'package:analyzer/dart/ast/token.dart'; |
11 import 'package:analyzer/dart/ast/visitor.dart'; | 9 import 'package:analyzer/dart/ast/visitor.dart'; |
12 import 'package:analyzer/dart/element/element.dart'; | 10 import 'package:analyzer/dart/element/element.dart'; |
13 import 'package:analyzer/dart/element/visitor.dart'; | |
14 import 'package:analyzer/exception/exception.dart'; | 11 import 'package:analyzer/exception/exception.dart'; |
15 import 'package:analyzer/src/dart/element/element.dart'; | 12 import 'package:analyzer/src/dart/element/element.dart'; |
16 | 13 |
17 /** | 14 /** |
18 * A visitor that resolves declarations in an AST structure to already built | 15 * A visitor that resolves declarations in an AST structure to already built |
19 * elements. | 16 * elements. |
20 * | 17 * |
21 * The resulting AST must have everything resolved that would have been resolved | 18 * The resulting AST must have everything resolved that would have been resolved |
22 * by a [CompilationUnitBuilder] (that is, must be a valid [RESOLVED_UNIT1]). | 19 * by a [CompilationUnitBuilder] (that is, must be a valid [RESOLVED_UNIT1]). |
23 * This class must not assume that the [CompilationUnitElement] passed to it is | 20 * This class must not assume that the [CompilationUnitElement] passed to it is |
24 * any more complete than a [COMPILATION_UNIT_ELEMENT]. | 21 * any more complete than a [COMPILATION_UNIT_ELEMENT]. |
25 */ | 22 */ |
26 class DeclarationResolver extends RecursiveAstVisitor<Object> | 23 class DeclarationResolver extends RecursiveAstVisitor<Object> { |
27 with _ExistingElementResolver { | |
28 /** | 24 /** |
29 * The elements that are reachable from the compilation unit element. When a | 25 * The compilation unit containing the AST nodes being visited. |
30 * compilation unit has been resolved, this set should be empty. | |
31 */ | 26 */ |
32 Set<Element> _expectedElements; | 27 CompilationUnitElementImpl _enclosingUnit; |
33 | 28 |
34 /** | 29 /** |
35 * The function type alias containing the AST nodes being visited, or `null` | 30 * The [ElementWalker] we are using to keep track of progress through the |
36 * if we are not in the scope of a function type alias. | 31 * element model. |
37 */ | 32 */ |
38 FunctionTypeAliasElement _enclosingAlias; | 33 ElementWalker _walker; |
39 | |
40 /** | |
41 * The class containing the AST nodes being visited, or `null` if we are not | |
42 * in the scope of a class. | |
43 */ | |
44 ClassElement _enclosingClass; | |
45 | |
46 /** | |
47 * The method or function containing the AST nodes being visited, or `null` if | |
48 * we are not in the scope of a method or function. | |
49 */ | |
50 ExecutableElement _enclosingExecutable; | |
51 | |
52 /** | |
53 * The parameter containing the AST nodes being visited, or `null` if we are | |
54 * not in the scope of a parameter. | |
55 */ | |
56 ParameterElement _enclosingParameter; | |
57 | 34 |
58 /** | 35 /** |
59 * Resolve the declarations within the given compilation [unit] to the | 36 * Resolve the declarations within the given compilation [unit] to the |
60 * elements rooted at the given [element]. Throw an [ElementMismatchException] | 37 * elements rooted at the given [element]. Throw an [ElementMismatchException] |
61 * if the element model and compilation unit do not match each other. | 38 * if the element model and compilation unit do not match each other. |
62 */ | 39 */ |
63 void resolve(CompilationUnit unit, CompilationUnitElement element) { | 40 void resolve(CompilationUnit unit, CompilationUnitElement element) { |
64 _ElementGatherer gatherer = new _ElementGatherer(); | |
65 element.accept(gatherer); | |
66 _expectedElements = gatherer.elements; | |
67 _enclosingUnit = element; | 41 _enclosingUnit = element; |
68 _expectedElements.remove(element); | 42 _walker = new ElementWalker.forCompilationUnit(element); |
69 unit.element = element; | 43 unit.element = element; |
70 unit.accept(this); | 44 try { |
71 _validateResolution(); | 45 unit.accept(this); |
| 46 _walker.validate(); |
| 47 } on Error catch (e, st) { |
| 48 throw new _ElementMismatchException( |
| 49 element, _walker.element, new CaughtException(e, st)); |
| 50 } |
72 } | 51 } |
73 | 52 |
74 @override | 53 @override |
75 Object visitCatchClause(CatchClause node) { | 54 Object visitCatchClause(CatchClause node) { |
76 SimpleIdentifier exceptionParameter = node.exceptionParameter; | 55 SimpleIdentifier exceptionParameter = node.exceptionParameter; |
77 if (exceptionParameter != null) { | 56 if (exceptionParameter != null) { |
78 List<LocalVariableElement> localVariables = | 57 _match(exceptionParameter, _walker.getVariable()); |
79 _enclosingExecutable.localVariables; | |
80 _findIdentifier(localVariables, exceptionParameter); | |
81 SimpleIdentifier stackTraceParameter = node.stackTraceParameter; | 58 SimpleIdentifier stackTraceParameter = node.stackTraceParameter; |
82 if (stackTraceParameter != null) { | 59 if (stackTraceParameter != null) { |
83 _findIdentifier(localVariables, stackTraceParameter); | 60 _match(stackTraceParameter, _walker.getVariable()); |
84 } | 61 } |
85 } | 62 } |
86 return super.visitCatchClause(node); | 63 return super.visitCatchClause(node); |
87 } | 64 } |
88 | 65 |
89 @override | 66 @override |
90 Object visitClassDeclaration(ClassDeclaration node) { | 67 Object visitClassDeclaration(ClassDeclaration node) { |
91 ClassElement outerClass = _enclosingClass; | 68 ClassElement element = _match(node.name, _walker.getClass()); |
92 try { | 69 _walk(new ElementWalker.forClass(element), () { |
93 SimpleIdentifier className = node.name; | |
94 _enclosingClass = _findIdentifier(_enclosingUnit.types, className); | |
95 super.visitClassDeclaration(node); | 70 super.visitClassDeclaration(node); |
96 _resolveMetadata(node, node.metadata, _enclosingClass); | 71 }); |
97 return null; | 72 _resolveMetadata(node, node.metadata, element); |
98 } finally { | 73 return null; |
99 _enclosingClass = outerClass; | |
100 } | |
101 } | 74 } |
102 | 75 |
103 @override | 76 @override |
104 Object visitClassTypeAlias(ClassTypeAlias node) { | 77 Object visitClassTypeAlias(ClassTypeAlias node) { |
105 ClassElement outerClass = _enclosingClass; | 78 ClassElement element = _match(node.name, _walker.getClass()); |
106 try { | 79 _walk(new ElementWalker.forClass(element), () { |
107 SimpleIdentifier className = node.name; | |
108 _enclosingClass = _findIdentifier(_enclosingUnit.types, className); | |
109 super.visitClassTypeAlias(node); | 80 super.visitClassTypeAlias(node); |
110 _resolveMetadata(node, node.metadata, _enclosingClass); | 81 }); |
111 return null; | 82 _resolveMetadata(node, node.metadata, element); |
112 } finally { | 83 return null; |
113 _enclosingClass = outerClass; | |
114 } | |
115 } | 84 } |
116 | 85 |
117 @override | 86 @override |
118 Object visitConstructorDeclaration(ConstructorDeclaration node) { | 87 Object visitConstructorDeclaration(ConstructorDeclaration node) { |
119 ExecutableElement outerExecutable = _enclosingExecutable; | 88 ConstructorElement element = _match(node.name, _walker.getConstructor()); |
120 try { | 89 _walk(new ElementWalker.forExecutable(element), () { |
121 SimpleIdentifier constructorName = node.name; | 90 node.element = element; |
122 if (constructorName == null) { | |
123 _enclosingExecutable = _enclosingClass.unnamedConstructor; | |
124 if (_enclosingExecutable == null) { | |
125 _mismatch('Could not find default constructor', node); | |
126 } | |
127 } else { | |
128 _enclosingExecutable = | |
129 _enclosingClass.getNamedConstructor(constructorName.name); | |
130 if (_enclosingExecutable == null) { | |
131 _mismatch( | |
132 'Could not find constructor element with name "${constructorName.n
ame}', | |
133 node); | |
134 } | |
135 constructorName.staticElement = _enclosingExecutable; | |
136 } | |
137 _expectedElements.remove(_enclosingExecutable); | |
138 node.element = _enclosingExecutable as ConstructorElement; | |
139 super.visitConstructorDeclaration(node); | 91 super.visitConstructorDeclaration(node); |
140 _resolveMetadata(node, node.metadata, _enclosingExecutable); | 92 }); |
141 return null; | 93 _resolveMetadata(node, node.metadata, element); |
142 } finally { | 94 return null; |
143 _enclosingExecutable = outerExecutable; | |
144 } | |
145 } | 95 } |
146 | 96 |
147 @override | 97 @override |
148 Object visitDeclaredIdentifier(DeclaredIdentifier node) { | 98 Object visitDeclaredIdentifier(DeclaredIdentifier node) { |
149 SimpleIdentifier variableName = node.identifier; | 99 VariableElement element = _match(node.identifier, _walker.getVariable()); |
150 Element element = | |
151 _findIdentifier(_enclosingExecutable.localVariables, variableName); | |
152 super.visitDeclaredIdentifier(node); | 100 super.visitDeclaredIdentifier(node); |
153 _resolveMetadata(node, node.metadata, element); | 101 _resolveMetadata(node, node.metadata, element); |
154 return null; | 102 return null; |
155 } | 103 } |
156 | 104 |
157 @override | 105 @override |
158 Object visitDefaultFormalParameter(DefaultFormalParameter node) { | 106 Object visitDefaultFormalParameter(DefaultFormalParameter node) { |
159 SimpleIdentifier parameterName = node.parameter.identifier; | 107 ParameterElement element = |
160 ParameterElement element = _getElementForParameter(node, parameterName); | 108 _match(node.parameter.identifier, _walker.getParameter()); |
161 Expression defaultValue = node.defaultValue; | 109 Expression defaultValue = node.defaultValue; |
162 if (defaultValue != null) { | 110 if (defaultValue != null) { |
163 ExecutableElement outerExecutable = _enclosingExecutable; | 111 _walk(new ElementWalker.forExecutable(element.initializer), () { |
164 try { | |
165 _enclosingExecutable = element.initializer; | |
166 defaultValue.accept(this); | 112 defaultValue.accept(this); |
167 } finally { | 113 }); |
168 _enclosingExecutable = outerExecutable; | |
169 } | |
170 } | 114 } |
171 ParameterElement outerParameter = _enclosingParameter; | 115 _walk(new ElementWalker.forParameter(element), () { |
172 try { | |
173 _enclosingParameter = element; | |
174 super.visitDefaultFormalParameter(node); | 116 super.visitDefaultFormalParameter(node); |
175 _resolveMetadata(node, node.metadata, element); | 117 }); |
176 return null; | 118 _resolveMetadata(node, node.metadata, element); |
177 } finally { | 119 return null; |
178 _enclosingParameter = outerParameter; | |
179 } | |
180 } | 120 } |
181 | 121 |
182 @override | 122 @override |
183 Object visitEnumDeclaration(EnumDeclaration node) { | 123 Object visitEnumDeclaration(EnumDeclaration node) { |
184 ClassElement enclosingEnum = | 124 ClassElement element = _match(node.name, _walker.getEnum()); |
185 _findIdentifier(_enclosingUnit.enums, node.name); | 125 _walk(new ElementWalker.forClass(element), () { |
186 List<FieldElement> constants = enclosingEnum.fields; | 126 for (EnumConstantDeclaration constant in node.constants) { |
187 for (EnumConstantDeclaration constant in node.constants) { | 127 _match(constant.name, _walker.getVariable()); |
188 _findIdentifier(constants, constant.name); | 128 } |
189 } | 129 super.visitEnumDeclaration(node); |
190 super.visitEnumDeclaration(node); | 130 }); |
191 _resolveMetadata(node, node.metadata, enclosingEnum); | 131 _resolveMetadata(node, node.metadata, element); |
192 return null; | 132 return null; |
193 } | 133 } |
194 | 134 |
195 @override | 135 @override |
196 Object visitExportDirective(ExportDirective node) { | 136 Object visitExportDirective(ExportDirective node) { |
197 super.visitExportDirective(node); | 137 super.visitExportDirective(node); |
198 _resolveAnnotations( | 138 _resolveAnnotations( |
199 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); | 139 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); |
200 return null; | 140 return null; |
201 } | 141 } |
202 | 142 |
203 @override | 143 @override |
204 Object visitFieldDeclaration(FieldDeclaration node) { | 144 Object visitFieldDeclaration(FieldDeclaration node) { |
205 super.visitFieldDeclaration(node); | 145 super.visitFieldDeclaration(node); |
206 _resolveMetadata(node, node.metadata, node.fields.variables[0].element); | 146 _resolveMetadata(node, node.metadata, node.fields.variables[0].element); |
207 return null; | 147 return null; |
208 } | 148 } |
209 | 149 |
210 @override | 150 @override |
211 Object visitFieldFormalParameter(FieldFormalParameter node) { | 151 Object visitFieldFormalParameter(FieldFormalParameter node) { |
212 if (node.parent is! DefaultFormalParameter) { | 152 if (node.parent is! DefaultFormalParameter) { |
213 SimpleIdentifier parameterName = node.identifier; | 153 ParameterElement element = |
214 ParameterElement element = _getElementForParameter(node, parameterName); | 154 _match(node.identifier, _walker.getParameter()); |
215 ParameterElement outerParameter = _enclosingParameter; | 155 _walk(new ElementWalker.forParameter(element), () { |
216 try { | |
217 _enclosingParameter = element; | |
218 super.visitFieldFormalParameter(node); | 156 super.visitFieldFormalParameter(node); |
219 _resolveMetadata(node, node.metadata, element); | 157 }); |
220 return null; | 158 _resolveMetadata(node, node.metadata, element); |
221 } finally { | 159 return null; |
222 _enclosingParameter = outerParameter; | |
223 } | |
224 } else { | 160 } else { |
225 return super.visitFieldFormalParameter(node); | 161 return super.visitFieldFormalParameter(node); |
226 } | 162 } |
227 } | 163 } |
228 | 164 |
229 @override | 165 @override |
230 Object visitFunctionDeclaration(FunctionDeclaration node) { | 166 Object visitFunctionDeclaration(FunctionDeclaration node) { |
231 ExecutableElement outerExecutable = _enclosingExecutable; | 167 SimpleIdentifier functionName = node.name; |
232 try { | 168 Token property = node.propertyKeyword; |
233 SimpleIdentifier functionName = node.name; | 169 ExecutableElement element; |
234 Token property = node.propertyKeyword; | 170 if (property == null) { |
235 if (property == null) { | 171 element = _match(functionName, _walker.getFunction()); |
236 if (_enclosingExecutable != null) { | 172 } else { |
237 _enclosingExecutable = | 173 if (_walker.element is ExecutableElement) { |
238 _findIdentifier(_enclosingExecutable.functions, functionName); | 174 element = _match(functionName, _walker.getFunction()); |
239 } else { | 175 } else if (property.keyword == Keyword.GET) { |
240 _enclosingExecutable = | 176 element = _match(functionName, _walker.getAccessor()); |
241 _findIdentifier(_enclosingUnit.functions, functionName); | |
242 } | |
243 } else { | 177 } else { |
244 if (_enclosingExecutable != null) { | 178 assert(property.keyword == Keyword.SET); |
245 _enclosingExecutable = | 179 element = _match(functionName, _walker.getAccessor(), |
246 _findIdentifier(_enclosingExecutable.functions, functionName); | 180 elementName: functionName.name + '='); |
247 } else { | |
248 List<PropertyAccessorElement> accessors; | |
249 if (_enclosingClass != null) { | |
250 accessors = _enclosingClass.accessors; | |
251 } else { | |
252 accessors = _enclosingUnit.accessors; | |
253 } | |
254 PropertyAccessorElement accessor; | |
255 if (property.keyword == Keyword.GET) { | |
256 accessor = _findIdentifier(accessors, functionName); | |
257 } else if (property.keyword == Keyword.SET) { | |
258 accessor = _findWithNameAndOffset(accessors, functionName, | |
259 functionName.name + '=', functionName.offset); | |
260 _expectedElements.remove(accessor); | |
261 functionName.staticElement = accessor; | |
262 } | |
263 _enclosingExecutable = accessor; | |
264 } | |
265 } | 181 } |
266 node.functionExpression.element = _enclosingExecutable; | 182 } |
| 183 node.functionExpression.element = element; |
| 184 _walk(new ElementWalker.forExecutable(element), () { |
267 super.visitFunctionDeclaration(node); | 185 super.visitFunctionDeclaration(node); |
268 _resolveMetadata(node, node.metadata, _enclosingExecutable); | 186 }); |
269 return null; | 187 _resolveMetadata(node, node.metadata, element); |
270 } finally { | 188 return null; |
271 _enclosingExecutable = outerExecutable; | |
272 } | |
273 } | 189 } |
274 | 190 |
275 @override | 191 @override |
276 Object visitFunctionExpression(FunctionExpression node) { | 192 Object visitFunctionExpression(FunctionExpression node) { |
277 if (node.parent is! FunctionDeclaration) { | 193 if (node.parent is! FunctionDeclaration) { |
278 FunctionElement element = _findAtOffset( | 194 FunctionElement element = _walker.getFunction(); |
279 _enclosingExecutable.functions, node, node.beginToken.offset); | |
280 _expectedElements.remove(element); | |
281 node.element = element; | 195 node.element = element; |
282 } | 196 _walk(new ElementWalker.forExecutable(element), () { |
283 ExecutableElement outerExecutable = _enclosingExecutable; | 197 super.visitFunctionExpression(node); |
284 try { | 198 }); |
285 _enclosingExecutable = node.element; | 199 return null; |
| 200 } else { |
286 return super.visitFunctionExpression(node); | 201 return super.visitFunctionExpression(node); |
287 } finally { | |
288 _enclosingExecutable = outerExecutable; | |
289 } | 202 } |
290 } | 203 } |
291 | 204 |
292 @override | 205 @override |
293 Object visitFunctionTypeAlias(FunctionTypeAlias node) { | 206 Object visitFunctionTypeAlias(FunctionTypeAlias node) { |
294 FunctionTypeAliasElement outerAlias = _enclosingAlias; | 207 FunctionTypeAliasElement element = _match(node.name, _walker.getTypedef()); |
295 try { | 208 _walk(new ElementWalker.forTypedef(element), () { |
296 SimpleIdentifier aliasName = node.name; | |
297 _enclosingAlias = | |
298 _findIdentifier(_enclosingUnit.functionTypeAliases, aliasName); | |
299 super.visitFunctionTypeAlias(node); | 209 super.visitFunctionTypeAlias(node); |
300 _resolveMetadata(node, node.metadata, _enclosingAlias); | 210 }); |
301 return null; | 211 _resolveMetadata(node, node.metadata, element); |
302 } finally { | 212 return null; |
303 _enclosingAlias = outerAlias; | |
304 } | |
305 } | 213 } |
306 | 214 |
307 @override | 215 @override |
308 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { | 216 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { |
309 if (node.parent is! DefaultFormalParameter) { | 217 if (node.parent is! DefaultFormalParameter) { |
310 SimpleIdentifier parameterName = node.identifier; | 218 ParameterElement element = |
311 ParameterElement element = _getElementForParameter(node, parameterName); | 219 _match(node.identifier, _walker.getParameter()); |
312 ParameterElement outerParameter = _enclosingParameter; | 220 _walk(new ElementWalker.forParameter(element), () { |
313 try { | |
314 _enclosingParameter = element; | |
315 super.visitFunctionTypedFormalParameter(node); | 221 super.visitFunctionTypedFormalParameter(node); |
316 _resolveMetadata(node, node.metadata, _enclosingParameter); | 222 }); |
317 return null; | 223 _resolveMetadata(node, node.metadata, element); |
318 } finally { | 224 return null; |
319 _enclosingParameter = outerParameter; | |
320 } | |
321 } else { | 225 } else { |
322 return super.visitFunctionTypedFormalParameter(node); | 226 return super.visitFunctionTypedFormalParameter(node); |
323 } | 227 } |
324 } | 228 } |
325 | 229 |
326 @override | 230 @override |
327 Object visitImportDirective(ImportDirective node) { | 231 Object visitImportDirective(ImportDirective node) { |
328 super.visitImportDirective(node); | 232 super.visitImportDirective(node); |
329 _resolveAnnotations( | 233 _resolveAnnotations( |
330 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); | 234 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); |
331 return null; | 235 return null; |
332 } | 236 } |
333 | 237 |
334 @override | 238 @override |
335 Object visitLabeledStatement(LabeledStatement node) { | 239 Object visitLabeledStatement(LabeledStatement node) { |
336 for (Label label in node.labels) { | 240 for (Label label in node.labels) { |
337 SimpleIdentifier labelName = label.label; | 241 _match(label.label, _walker.getLabel()); |
338 _findIdentifier(_enclosingExecutable.labels, labelName); | |
339 } | 242 } |
340 return super.visitLabeledStatement(node); | 243 return super.visitLabeledStatement(node); |
341 } | 244 } |
342 | 245 |
343 @override | 246 @override |
344 Object visitLibraryDirective(LibraryDirective node) { | 247 Object visitLibraryDirective(LibraryDirective node) { |
345 super.visitLibraryDirective(node); | 248 super.visitLibraryDirective(node); |
346 _resolveAnnotations( | 249 _resolveAnnotations( |
347 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); | 250 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); |
348 return null; | 251 return null; |
349 } | 252 } |
350 | 253 |
351 @override | 254 @override |
352 Object visitMethodDeclaration(MethodDeclaration node) { | 255 Object visitMethodDeclaration(MethodDeclaration node) { |
353 ExecutableElement outerExecutable = _enclosingExecutable; | 256 Token property = node.propertyKeyword; |
354 try { | 257 SimpleIdentifier methodName = node.name; |
355 Token property = node.propertyKeyword; | 258 String nameOfMethod = methodName.name; |
356 SimpleIdentifier methodName = node.name; | 259 ExecutableElement element; |
357 String nameOfMethod = methodName.name; | 260 if (property == null) { |
358 if (property == null) { | 261 String elementName = nameOfMethod == '-' && |
359 String elementName = nameOfMethod == '-' && | 262 node.parameters != null && |
360 node.parameters != null && | 263 node.parameters.parameters.isEmpty |
361 node.parameters.parameters.isEmpty | 264 ? 'unary-' |
362 ? 'unary-' | 265 : nameOfMethod; |
363 : nameOfMethod; | 266 element = |
364 _enclosingExecutable = _findWithNameAndOffset(_enclosingClass.methods, | 267 _match(methodName, _walker.getFunction(), elementName: elementName); |
365 methodName, elementName, methodName.offset); | 268 } else { |
366 _expectedElements.remove(_enclosingExecutable); | 269 if (property.keyword == Keyword.GET) { |
367 methodName.staticElement = _enclosingExecutable; | 270 element = _match(methodName, _walker.getAccessor()); |
368 } else { | 271 } else { |
369 PropertyAccessorElement accessor; | 272 assert(property.keyword == Keyword.SET); |
370 if (property.keyword == Keyword.GET) { | 273 element = _match(methodName, _walker.getAccessor(), |
371 accessor = _findIdentifier(_enclosingClass.accessors, methodName); | 274 elementName: nameOfMethod + '='); |
372 } else if (property.keyword == Keyword.SET) { | |
373 accessor = _findWithNameAndOffset(_enclosingClass.accessors, | |
374 methodName, nameOfMethod + '=', methodName.offset); | |
375 _expectedElements.remove(accessor); | |
376 methodName.staticElement = accessor; | |
377 } | |
378 _enclosingExecutable = accessor; | |
379 } | 275 } |
| 276 } |
| 277 _walk(new ElementWalker.forExecutable(element), () { |
380 super.visitMethodDeclaration(node); | 278 super.visitMethodDeclaration(node); |
381 _resolveMetadata(node, node.metadata, _enclosingExecutable); | 279 }); |
382 return null; | 280 _resolveMetadata(node, node.metadata, element); |
383 } finally { | 281 return null; |
384 _enclosingExecutable = outerExecutable; | |
385 } | |
386 } | 282 } |
387 | 283 |
388 @override | 284 @override |
389 Object visitPartDirective(PartDirective node) { | 285 Object visitPartDirective(PartDirective node) { |
390 super.visitPartDirective(node); | 286 super.visitPartDirective(node); |
391 _resolveAnnotations( | 287 _resolveAnnotations( |
392 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); | 288 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); |
393 return null; | 289 return null; |
394 } | 290 } |
395 | 291 |
396 @override | 292 @override |
397 Object visitPartOfDirective(PartOfDirective node) { | 293 Object visitPartOfDirective(PartOfDirective node) { |
398 node.element = _enclosingUnit.library; | 294 node.element = _enclosingUnit.library; |
399 return super.visitPartOfDirective(node); | 295 return super.visitPartOfDirective(node); |
400 } | 296 } |
401 | 297 |
402 @override | 298 @override |
403 Object visitSimpleFormalParameter(SimpleFormalParameter node) { | 299 Object visitSimpleFormalParameter(SimpleFormalParameter node) { |
404 if (node.parent is! DefaultFormalParameter) { | 300 if (node.parent is! DefaultFormalParameter) { |
405 SimpleIdentifier parameterName = node.identifier; | 301 ParameterElement element = |
406 ParameterElement element = _getElementForParameter(node, parameterName); | 302 _match(node.identifier, _walker.getParameter()); |
407 ParameterElement outerParameter = _enclosingParameter; | 303 _walk(new ElementWalker.forParameter(element), () { |
408 try { | |
409 _enclosingParameter = element; | |
410 super.visitSimpleFormalParameter(node); | 304 super.visitSimpleFormalParameter(node); |
411 _resolveMetadata(node, node.metadata, element); | 305 }); |
412 return null; | 306 _resolveMetadata(node, node.metadata, element); |
413 } finally { | 307 return null; |
414 _enclosingParameter = outerParameter; | 308 } else { |
415 } | 309 return super.visitSimpleFormalParameter(node); |
416 } else {} | 310 } |
417 return super.visitSimpleFormalParameter(node); | |
418 } | 311 } |
419 | 312 |
420 @override | 313 @override |
421 Object visitSwitchCase(SwitchCase node) { | 314 Object visitSwitchCase(SwitchCase node) { |
422 for (Label label in node.labels) { | 315 for (Label label in node.labels) { |
423 SimpleIdentifier labelName = label.label; | 316 _match(label.label, _walker.getLabel()); |
424 _findIdentifier(_enclosingExecutable.labels, labelName); | |
425 } | 317 } |
426 return super.visitSwitchCase(node); | 318 return super.visitSwitchCase(node); |
427 } | 319 } |
428 | 320 |
429 @override | 321 @override |
430 Object visitSwitchDefault(SwitchDefault node) { | 322 Object visitSwitchDefault(SwitchDefault node) { |
431 for (Label label in node.labels) { | 323 for (Label label in node.labels) { |
432 SimpleIdentifier labelName = label.label; | 324 _match(label.label, _walker.getLabel()); |
433 _findIdentifier(_enclosingExecutable.labels, labelName); | |
434 } | 325 } |
435 return super.visitSwitchDefault(node); | 326 return super.visitSwitchDefault(node); |
436 } | 327 } |
437 | 328 |
438 @override | 329 @override |
439 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { | 330 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { |
440 super.visitTopLevelVariableDeclaration(node); | 331 super.visitTopLevelVariableDeclaration(node); |
441 _resolveMetadata(node, node.metadata, node.variables.variables[0].element); | 332 _resolveMetadata(node, node.metadata, node.variables.variables[0].element); |
442 return null; | 333 return null; |
443 } | 334 } |
444 | 335 |
445 @override | 336 @override |
446 Object visitTypeParameter(TypeParameter node) { | 337 Object visitTypeParameter(TypeParameter node) { |
447 SimpleIdentifier parameterName = node.name; | 338 Element element = _match(node.name, _walker.getTypeParameter()); |
448 Element element = null; | |
449 if (_enclosingExecutable != null) { | |
450 element = _findIdentifier( | |
451 _enclosingExecutable.typeParameters, parameterName, | |
452 required: false); | |
453 } | |
454 if (element == null) { | |
455 if (_enclosingClass != null) { | |
456 element = | |
457 _findIdentifier(_enclosingClass.typeParameters, parameterName); | |
458 } else if (_enclosingAlias != null) { | |
459 element = | |
460 _findIdentifier(_enclosingAlias.typeParameters, parameterName); | |
461 } | |
462 } | |
463 if (element == null) { | |
464 String name = parameterName.name; | |
465 int offset = parameterName.offset; | |
466 _mismatch( | |
467 'Could not find type parameter with name "$name" at $offset', node); | |
468 } | |
469 super.visitTypeParameter(node); | 339 super.visitTypeParameter(node); |
470 _resolveMetadata(node, node.metadata, element); | 340 _resolveMetadata(node, node.metadata, element); |
471 return null; | 341 return null; |
472 } | 342 } |
473 | 343 |
474 @override | 344 @override |
475 Object visitVariableDeclaration(VariableDeclaration node) { | 345 Object visitVariableDeclaration(VariableDeclaration node) { |
476 VariableElement element = null; | 346 VariableElement element = _match(node.name, _walker.getVariable()); |
477 SimpleIdentifier variableName = node.name; | |
478 if (_enclosingExecutable != null) { | |
479 element = _findIdentifier( | |
480 _enclosingExecutable.localVariables, variableName, | |
481 required: false); | |
482 } | |
483 if (element == null && _enclosingClass != null) { | |
484 element = _findIdentifier(_enclosingClass.fields, variableName, | |
485 required: false); | |
486 } | |
487 if (element == null && _enclosingUnit != null) { | |
488 element = _findIdentifier(_enclosingUnit.topLevelVariables, variableName); | |
489 } | |
490 Expression initializer = node.initializer; | 347 Expression initializer = node.initializer; |
491 if (initializer != null) { | 348 if (initializer != null) { |
492 ExecutableElement outerExecutable = _enclosingExecutable; | 349 _walk(new ElementWalker.forExecutable(element.initializer), () { |
493 try { | 350 super.visitVariableDeclaration(node); |
494 _enclosingExecutable = element.initializer; | 351 }); |
495 return super.visitVariableDeclaration(node); | 352 return null; |
496 } finally { | 353 } else { |
497 _enclosingExecutable = outerExecutable; | 354 return super.visitVariableDeclaration(node); |
498 } | |
499 } | 355 } |
500 return super.visitVariableDeclaration(node); | |
501 } | 356 } |
502 | 357 |
503 @override | 358 @override |
504 Object visitVariableDeclarationList(VariableDeclarationList node) { | 359 Object visitVariableDeclarationList(VariableDeclarationList node) { |
505 super.visitVariableDeclarationList(node); | 360 super.visitVariableDeclarationList(node); |
506 if (node.parent is! FieldDeclaration && | 361 if (node.parent is! FieldDeclaration && |
507 node.parent is! TopLevelVariableDeclaration) { | 362 node.parent is! TopLevelVariableDeclaration) { |
508 _resolveMetadata(node, node.metadata, node.variables[0].element); | 363 _resolveMetadata(node, node.metadata, node.variables[0].element); |
509 } | 364 } |
510 return null; | 365 return null; |
511 } | 366 } |
512 | 367 |
513 /** | 368 /** |
514 * Return the element in the given list of [elements] that was created for the | 369 * Updates [identifier] to point to [element], after ensuring that the |
515 * declaration at the given [offset]. Throw an [ElementMismatchException] if | 370 * element has the expected name. |
516 * an element at that offset cannot be found. | |
517 * | 371 * |
518 * This method should only be used when there is no name associated with the | 372 * If no [elementName] is given, it defaults to the name of the [identifier] |
519 * node. | 373 * (or the empty string if [identifier] is `null`). |
| 374 * |
| 375 * If [identifier] is `null`, nothing is updated, but the element name is |
| 376 * still checked. |
520 */ | 377 */ |
521 Element _findAtOffset(List<Element> elements, AstNode node, int offset) => | 378 Element/*=E*/ _match/*<E extends Element>*/( |
522 _findWithNameAndOffset(elements, node, '', offset); | 379 SimpleIdentifier identifier, Element/*=E*/ element, |
523 | 380 {String elementName}) { |
524 /** | 381 elementName ??= identifier?.name ?? ''; |
525 * Return the element in the given list of [elements] that was created for the | 382 if (element.name != elementName) { |
526 * declaration with the given [identifier]. As a side-effect, associate the | 383 throw new StateError( |
527 * returned element with the identifier. Throw an [ElementMismatchException] | 384 'Expected an element matching `$elementName`, got `${element.name}`'); |
528 * if an element corresponding to the identifier cannot be found unless | 385 } |
529 * [required] is `false`, in which case return `null`. | 386 identifier?.staticElement = element; |
530 */ | |
531 Element _findIdentifier(List<Element> elements, SimpleIdentifier identifier, | |
532 {bool required: true}) { | |
533 Element element = _findWithNameAndOffset( | |
534 elements, identifier, identifier.name, identifier.offset, | |
535 required: required); | |
536 _expectedElements.remove(element); | |
537 identifier.staticElement = element; | |
538 return element; | 387 return element; |
539 } | 388 } |
540 | 389 |
541 /** | 390 /** |
542 * Return the element in the given list of [elements] that was created for the | |
543 * declaration with the given [name] at the given [offset]. Throw an | |
544 * [ElementMismatchException] if an element corresponding to the identifier | |
545 * cannot be found unless [required] is `false`, in which case return `null`. | |
546 */ | |
547 Element _findWithNameAndOffset( | |
548 List<Element> elements, AstNode node, String name, int offset, | |
549 {bool required: true}) { | |
550 int length = elements.length; | |
551 for (int i = 0; i < length; i++) { | |
552 Element element = elements[i]; | |
553 if (element.nameOffset == offset && element.name == name) { | |
554 return element; | |
555 } | |
556 } | |
557 if (!required) { | |
558 return null; | |
559 } | |
560 for (int i = 0; i < length; i++) { | |
561 Element element = elements[i]; | |
562 if (element.name == name) { | |
563 _mismatch( | |
564 'Found element with name "$name" at ${element.nameOffset}, ' | |
565 'but expected offset of $offset', | |
566 node); | |
567 } | |
568 if (element.nameOffset == offset) { | |
569 _mismatch( | |
570 'Found element with name "${element.name}" at $offset, ' | |
571 'but expected element with name "$name"', | |
572 node); | |
573 } | |
574 } | |
575 _mismatch('Could not find element with name "$name" at $offset', node); | |
576 return null; // Never reached | |
577 } | |
578 | |
579 /** | |
580 * Search the most closely enclosing list of parameter elements for a | |
581 * parameter, defined by the given [node], with the given [parameterName]. | |
582 * Return the element that was found, or throw an [ElementMismatchException] | |
583 * if an element corresponding to the identifier cannot be found. | |
584 */ | |
585 ParameterElement _getElementForParameter( | |
586 FormalParameter node, SimpleIdentifier parameterName) { | |
587 List<ParameterElement> parameters = null; | |
588 if (_enclosingParameter != null) { | |
589 parameters = _enclosingParameter.parameters; | |
590 } | |
591 if (parameters == null && _enclosingExecutable != null) { | |
592 parameters = _enclosingExecutable.parameters; | |
593 } | |
594 if (parameters == null && _enclosingAlias != null) { | |
595 parameters = _enclosingAlias.parameters; | |
596 } | |
597 if (parameters == null) { | |
598 StringBuffer buffer = new StringBuffer(); | |
599 buffer.writeln('Could not find parameter in enclosing scope'); | |
600 buffer.writeln( | |
601 '(_enclosingParameter == null) == ${_enclosingParameter == null}'); | |
602 buffer.writeln( | |
603 '(_enclosingExecutable == null) == ${_enclosingExecutable == null}'); | |
604 buffer.writeln('(_enclosingAlias == null) == ${_enclosingAlias == null}'); | |
605 _mismatch(buffer.toString(), parameterName); | |
606 } | |
607 return _findIdentifier(parameters, parameterName); | |
608 } | |
609 | |
610 /** | |
611 * Associate each of the annotation [nodes] with the corresponding | 391 * Associate each of the annotation [nodes] with the corresponding |
612 * [ElementAnnotation] in [annotations]. If there is a problem, report it | 392 * [ElementAnnotation] in [annotations]. If there is a problem, report it |
613 * against the given [parent] node. | 393 * against the given [parent] node. |
614 */ | 394 */ |
615 void _resolveAnnotations(AstNode parent, NodeList<Annotation> nodes, | 395 void _resolveAnnotations(AstNode parent, NodeList<Annotation> nodes, |
616 List<ElementAnnotation> annotations) { | 396 List<ElementAnnotation> annotations) { |
617 int nodeCount = nodes.length; | 397 int nodeCount = nodes.length; |
618 if (nodeCount != annotations.length) { | 398 if (nodeCount != annotations.length) { |
619 _mismatch( | 399 throw new StateError('Found $nodeCount annotation nodes and ' |
620 'Found $nodeCount annotation nodes and ' | 400 '${annotations.length} element annotations'); |
621 '${annotations.length} element annotations', | |
622 parent); | |
623 } | 401 } |
624 for (int i = 0; i < nodeCount; i++) { | 402 for (int i = 0; i < nodeCount; i++) { |
625 nodes[i].elementAnnotation = annotations[i]; | 403 nodes[i].elementAnnotation = annotations[i]; |
626 } | 404 } |
627 } | 405 } |
628 | 406 |
629 /** | 407 /** |
630 * If [element] is not `null`, associate each of the annotation [nodes] with | 408 * If [element] is not `null`, associate each of the annotation [nodes] with |
631 * the corresponding [ElementAnnotation] in [element.metadata]. If there is a | 409 * the corresponding [ElementAnnotation] in [element.metadata]. If there is a |
632 * problem, report it against the given [parent] node. | 410 * problem, report it against the given [parent] node. |
633 * | 411 * |
634 * If [element] is `null`, do nothing--this allows us to be robust in the | 412 * If [element] is `null`, do nothing--this allows us to be robust in the |
635 * case where we are operating on an element model that hasn't been fully | 413 * case where we are operating on an element model that hasn't been fully |
636 * built. | 414 * built. |
637 */ | 415 */ |
638 void _resolveMetadata( | 416 void _resolveMetadata( |
639 AstNode parent, NodeList<Annotation> nodes, Element element) { | 417 AstNode parent, NodeList<Annotation> nodes, Element element) { |
640 if (element != null) { | 418 if (element != null) { |
641 _resolveAnnotations(parent, nodes, element.metadata); | 419 _resolveAnnotations(parent, nodes, element.metadata); |
642 } | 420 } |
643 } | 421 } |
644 | 422 |
645 /** | 423 /** |
646 * Throw an exception if there are non-synthetic elements in the element model | 424 * Recurses through the element model and AST, verifying that all elements are |
647 * that were not associated with an AST node. | 425 * matched. |
648 */ | 426 * |
649 void _validateResolution() { | 427 * Executes [callback] with [_walker] pointing to the given [walker] (which |
650 if (_expectedElements.isNotEmpty) { | 428 * should be a new instance of [ElementWalker]). Once [callback] returns, |
651 StringBuffer buffer = new StringBuffer(); | 429 * uses [ElementWalker.validate] to verify that all expected elements have |
652 buffer.write(_expectedElements.length); | 430 * been matched. |
653 buffer.writeln(' unmatched elements found:'); | 431 */ |
654 for (Element element in _expectedElements) { | 432 void _walk(ElementWalker walker, void callback()) { |
655 buffer.write(' '); | 433 ElementWalker outerWalker = _walker; |
656 buffer.writeln(element); | 434 _walker = walker; |
657 } | 435 callback(); |
658 throw new _ElementMismatchException(buffer.toString()); | 436 walker.validate(); |
659 } | 437 _walker = outerWalker; |
660 } | 438 } |
661 } | 439 } |
662 | 440 |
663 /** | 441 /** |
664 * A visitor that can be used to collect all of the non-synthetic elements in an | 442 * Keeps track of the set of non-synthetic child elements of an element, |
665 * element model. | 443 * yielding them one at a time in response to "get" method calls. |
666 */ | 444 */ |
667 class _ElementGatherer extends GeneralizingElementVisitor { | 445 class ElementWalker { |
668 /** | 446 /** |
669 * The set in which the elements are collected. | 447 * The element whose child elements are being walked. |
670 */ | 448 */ |
671 final Set<Element> elements = new HashSet<Element>(); | 449 final Element element; |
672 | 450 |
673 /** | 451 List<PropertyAccessorElement> _accessors; |
674 * Initialize the visitor. | 452 int _accessorIndex = 0; |
675 */ | 453 List<ClassElement> _classes; |
676 _ElementGatherer(); | 454 int _classIndex = 0; |
677 | 455 List<ConstructorElement> _constructors; |
678 @override | 456 int _constructorIndex = 0; |
679 void visitElement(Element element) { | 457 List<ClassElement> _enums; |
680 if (!element.isSynthetic) { | 458 int _enumIndex = 0; |
681 elements.add(element); | 459 List<ExecutableElement> _functions; |
| 460 int _functionIndex = 0; |
| 461 List<LabelElement> _labels; |
| 462 int _labelIndex = 0; |
| 463 List<ParameterElement> _parameters; |
| 464 int _parameterIndex = 0; |
| 465 List<FunctionTypeAliasElement> _typedefs; |
| 466 int _typedefIndex = 0; |
| 467 List<TypeParameterElement> _typeParameters; |
| 468 int _typeParameterIndex = 0; |
| 469 List<VariableElement> _variables; |
| 470 int _variableIndex = 0; |
| 471 |
| 472 /** |
| 473 * Creates an [ElementWalker] which walks the child elements of a class |
| 474 * element. |
| 475 */ |
| 476 ElementWalker.forClass(ClassElement element) |
| 477 : element = element, |
| 478 _accessors = element.accessors.where(_isNotSynthetic).toList(), |
| 479 _constructors = element.isMixinApplication |
| 480 ? null |
| 481 : element.constructors.where(_isNotSynthetic).toList(), |
| 482 _functions = element.methods, |
| 483 _typeParameters = element.typeParameters, |
| 484 _variables = element.fields.where(_isNotSynthetic).toList(); |
| 485 |
| 486 /** |
| 487 * Creates an [ElementWalker] which walks the child elements of a compilation |
| 488 * unit element. |
| 489 */ |
| 490 ElementWalker.forCompilationUnit(CompilationUnitElement compilationUnit) |
| 491 : element = compilationUnit, |
| 492 _accessors = compilationUnit.accessors.where(_isNotSynthetic).toList(), |
| 493 _classes = compilationUnit.types, |
| 494 _enums = compilationUnit.enums, |
| 495 _functions = compilationUnit.functions, |
| 496 _typedefs = compilationUnit.functionTypeAliases, |
| 497 _variables = |
| 498 compilationUnit.topLevelVariables.where(_isNotSynthetic).toList(); |
| 499 |
| 500 /** |
| 501 * Creates an [ElementWalker] which walks the child elements of a compilation |
| 502 * unit element. |
| 503 */ |
| 504 ElementWalker.forExecutable(ExecutableElement element) |
| 505 : element = element, |
| 506 _functions = element.functions, |
| 507 _labels = element.labels, |
| 508 _parameters = element.parameters, |
| 509 _typeParameters = element.typeParameters, |
| 510 _variables = element.localVariables; |
| 511 |
| 512 /** |
| 513 * Creates an [ElementWalker] which walks the child elements of a parameter |
| 514 * element. |
| 515 */ |
| 516 ElementWalker.forParameter(ParameterElement element) |
| 517 : element = element, |
| 518 _parameters = element.parameters; |
| 519 |
| 520 /** |
| 521 * Creates an [ElementWalker] which walks the child elements of a typedef |
| 522 * element. |
| 523 */ |
| 524 ElementWalker.forTypedef(FunctionTypeAliasElement element) |
| 525 : element = element, |
| 526 _parameters = element.parameters, |
| 527 _typeParameters = element.typeParameters; |
| 528 |
| 529 /** |
| 530 * Returns the next non-synthetic child of [element] which is an accessor; |
| 531 * throws an [IndexError] if there are no more. |
| 532 */ |
| 533 PropertyAccessorElement getAccessor() => _accessors[_accessorIndex++]; |
| 534 |
| 535 /** |
| 536 * Returns the next non-synthetic child of [element] which is a class; throws |
| 537 * an [IndexError] if there are no more. |
| 538 */ |
| 539 ClassElement getClass() => _classes[_classIndex++]; |
| 540 |
| 541 /** |
| 542 * Returns the next non-synthetic child of [element] which is a constructor; |
| 543 * throws an [IndexError] if there are no more. |
| 544 */ |
| 545 ConstructorElement getConstructor() => _constructors[_constructorIndex++]; |
| 546 |
| 547 /** |
| 548 * Returns the next non-synthetic child of [element] which is an enum; throws |
| 549 * an [IndexError] if there are no more. |
| 550 */ |
| 551 ClassElement getEnum() => _enums[_enumIndex++]; |
| 552 |
| 553 /** |
| 554 * Returns the next non-synthetic child of [element] which is a top level |
| 555 * function, method, or local function; throws an [IndexError] if there are no |
| 556 * more. |
| 557 */ |
| 558 ExecutableElement getFunction() => _functions[_functionIndex++]; |
| 559 |
| 560 /** |
| 561 * Returns the next non-synthetic child of [element] which is a label; throws |
| 562 * an [IndexError] if there are no more. |
| 563 */ |
| 564 LabelElement getLabel() => _labels[_labelIndex++]; |
| 565 |
| 566 /** |
| 567 * Returns the next non-synthetic child of [element] which is a parameter; |
| 568 * throws an [IndexError] if there are no more. |
| 569 */ |
| 570 ParameterElement getParameter() => _parameters[_parameterIndex++]; |
| 571 |
| 572 /** |
| 573 * Returns the next non-synthetic child of [element] which is a typedef; |
| 574 * throws an [IndexError] if there are no more. |
| 575 */ |
| 576 FunctionTypeAliasElement getTypedef() => _typedefs[_typedefIndex++]; |
| 577 |
| 578 /** |
| 579 * Returns the next non-synthetic child of [element] which is a type |
| 580 * parameter; throws an [IndexError] if there are no more. |
| 581 */ |
| 582 TypeParameterElement getTypeParameter() => |
| 583 _typeParameters[_typeParameterIndex++]; |
| 584 |
| 585 /** |
| 586 * Returns the next non-synthetic child of [element] which is a top level |
| 587 * variable, field, or local variable; throws an [IndexError] if there are no |
| 588 * more. |
| 589 */ |
| 590 VariableElement getVariable() => _variables[_variableIndex++]; |
| 591 |
| 592 /** |
| 593 * Verifies that all non-synthetic children of [element] have been obtained |
| 594 * from their corresponding "get" method calls; if not, throws a [StateError]. |
| 595 */ |
| 596 void validate() { |
| 597 void check(List<Element> elements, int index) { |
| 598 if (elements != null && elements.length != index) { |
| 599 throw new StateError( |
| 600 'Unmatched ${elements[index].runtimeType} ${elements[index]}'); |
| 601 } |
682 } | 602 } |
683 super.visitElement(element); | 603 |
| 604 check(_accessors, _accessorIndex); |
| 605 check(_classes, _classIndex); |
| 606 check(_constructors, _constructorIndex); |
| 607 check(_enums, _enumIndex); |
| 608 check(_functions, _functionIndex); |
| 609 check(_labels, _labelIndex); |
| 610 check(_parameters, _parameterIndex); |
| 611 check(_typedefs, _typedefIndex); |
| 612 check(_typeParameters, _typeParameterIndex); |
| 613 check(_variables, _variableIndex); |
684 } | 614 } |
| 615 |
| 616 static bool _isNotSynthetic(Element e) => !e.isSynthetic; |
685 } | 617 } |
686 | 618 |
687 class _ElementMismatchException extends AnalysisException { | 619 class _ElementMismatchException extends AnalysisException { |
688 /** | 620 /** |
689 * Initialize a newly created exception to have the given [message] and | 621 * Creates an exception to refer to the given [compilationUnit], [element], |
690 * [cause]. | 622 * and [cause]. |
691 */ | 623 */ |
692 _ElementMismatchException(String message, [CaughtException cause = null]) | 624 _ElementMismatchException( |
693 : super(message, cause); | 625 CompilationUnitElement compilationUnit, Element element, |
| 626 [CaughtException cause = null]) |
| 627 : super('Element mismatch in $compilationUnit at $element', cause); |
694 } | 628 } |
695 | |
696 /** | |
697 * A mixin for classes that use an existing element model to resolve a portion | |
698 * of an AST structure. | |
699 */ | |
700 class _ExistingElementResolver { | |
701 /** | |
702 * The compilation unit containing the AST nodes being visited. | |
703 */ | |
704 CompilationUnitElementImpl _enclosingUnit; | |
705 | |
706 /** | |
707 * Throw an [ElementMismatchException] to report that the element model and th
e | |
708 * AST do not match. The [message] will have the path to the given [node] | |
709 * appended to it. | |
710 */ | |
711 void _mismatch(String message, AstNode node) { | |
712 StringBuffer buffer = new StringBuffer(); | |
713 buffer.write('Mismatch in '); | |
714 buffer.write(runtimeType); | |
715 buffer.write(' while resolving '); | |
716 buffer.writeln(_enclosingUnit?.source?.fullName); | |
717 buffer.writeln(message); | |
718 buffer.write('Path to root:'); | |
719 String separator = ' '; | |
720 AstNode parent = node; | |
721 while (parent != null) { | |
722 buffer.write(separator); | |
723 buffer.write(parent.runtimeType.toString()); | |
724 separator = ', '; | |
725 parent = parent.parent; | |
726 } | |
727 throw new _ElementMismatchException(buffer.toString()); | |
728 } | |
729 } | |
OLD | NEW |