Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(111)

Side by Side Diff: pkg/analyzer/lib/src/generated/declaration_resolver.dart

Issue 2419633002: Rewrite DeclarationResolver to match declarations to elements by order rather than offset. (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698