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

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

Issue 743543002: Extract incremental resolver classes into separate files. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
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.
4
5 library engine.incremental_resolver;
6
7 import 'dart:collection';
8
9 import 'ast.dart';
10 import 'element.dart';
11 import 'error.dart';
12 import 'java_engine.dart';
13 import 'resolver.dart';
14 import 'scanner.dart';
15 import 'source.dart';
16
17
18 /**
19 * Instances of the class [DeclarationMatcher] determine whether the element
20 * model defined by a given AST structure matches an existing element model.
21 */
22 class DeclarationMatcher extends RecursiveAstVisitor<Object> {
23 /**
24 * The compilation unit containing the AST nodes being visited.
25 */
26 CompilationUnitElement _enclosingUnit;
27
28 /**
29 * The function type alias containing the AST nodes being visited, or `null` i f we are not
30 * in the scope of a function type alias.
31 */
32 FunctionTypeAliasElement _enclosingAlias;
33
34 /**
35 * The class containing the AST nodes being visited, or `null` if we are not i n the scope of
36 * a class.
37 */
38 ClassElement _enclosingClass;
39
40 /**
41 * The method or function containing the AST nodes being visited, or `null` if we are not in
42 * the scope of a method or function.
43 */
44 ExecutableElement _enclosingExecutable;
45
46 /**
47 * The parameter containing the AST nodes being visited, or `null` if we are n ot in the
48 * scope of a parameter.
49 */
50 ParameterElement _enclosingParameter;
51
52 /**
53 * A set containing all of the elements in the element model that were defined by the old AST node
54 * corresponding to the AST node being visited.
55 */
56 HashSet<Element> _allElements = new HashSet<Element>();
57
58 /**
59 * A set containing all of the elements in the element model that were defined by the old AST node
60 * corresponding to the AST node being visited that have not already been matc hed to nodes in the
61 * AST structure being visited.
62 */
63 HashSet<Element> _unmatchedElements = new HashSet<Element>();
64
65 /**
66 * Return `true` if the declarations within the given AST structure define an element model
67 * that is equivalent to the corresponding elements rooted at the given elemen t.
68 *
69 * @param node the AST structure being compared to the element model
70 * @param element the root of the element model being compared to the AST stru cture
71 * @return `true` if the AST structure defines the same elements as those in t he given
72 * element model
73 */
74 bool matches(AstNode node, Element element) {
75 _captureEnclosingElements(element);
76 _gatherElements(element);
77 try {
78 node.accept(this);
79 } on _DeclarationMismatchException catch (exception) {
80 return false;
81 }
82 return _unmatchedElements.isEmpty;
83 }
84
85 void processElement(Element element) {
86 if (element == null) {
87 throw new _DeclarationMismatchException();
88 }
89 if (!_allElements.contains(element)) {
90 throw new _DeclarationMismatchException();
91 }
92 _unmatchedElements.remove(element);
93 }
94
95 @override
96 Object visitCatchClause(CatchClause node) {
97 SimpleIdentifier exceptionParameter = node.exceptionParameter;
98 if (exceptionParameter != null) {
99 List<LocalVariableElement> localVariables =
100 _enclosingExecutable.localVariables;
101 LocalVariableElement exceptionElement =
102 _findIdentifier(localVariables, exceptionParameter);
103 processElement(exceptionElement);
104 SimpleIdentifier stackTraceParameter = node.stackTraceParameter;
105 if (stackTraceParameter != null) {
106 LocalVariableElement stackTraceElement =
107 _findIdentifier(localVariables, stackTraceParameter);
108 processElement(stackTraceElement);
109 }
110 }
111 return super.visitCatchClause(node);
112 }
113
114 @override
115 Object visitClassDeclaration(ClassDeclaration node) {
116 ClassElement outerClass = _enclosingClass;
117 try {
118 SimpleIdentifier className = node.name;
119 _enclosingClass = _findIdentifier(_enclosingUnit.types, className);
120 processElement(_enclosingClass);
121 if (!_hasConstructor(node)) {
122 ConstructorElement constructor = _enclosingClass.unnamedConstructor;
123 if (constructor.isSynthetic) {
124 processElement(constructor);
125 }
126 }
127 return super.visitClassDeclaration(node);
128 } finally {
129 _enclosingClass = outerClass;
130 }
131 }
132
133 @override
134 Object visitClassTypeAlias(ClassTypeAlias node) {
135 ClassElement outerClass = _enclosingClass;
136 try {
137 SimpleIdentifier className = node.name;
138 _enclosingClass = _findIdentifier(_enclosingUnit.types, className);
139 processElement(_enclosingClass);
140 return super.visitClassTypeAlias(node);
141 } finally {
142 _enclosingClass = outerClass;
143 }
144 }
145
146 @override
147 Object visitCompilationUnit(CompilationUnit node) {
148 processElement(_enclosingUnit);
149 return super.visitCompilationUnit(node);
150 }
151
152 @override
153 Object visitConstructorDeclaration(ConstructorDeclaration node) {
154 ExecutableElement outerExecutable = _enclosingExecutable;
155 try {
156 SimpleIdentifier constructorName = node.name;
157 if (constructorName == null) {
158 _enclosingExecutable = _enclosingClass.unnamedConstructor;
159 } else {
160 _enclosingExecutable =
161 _enclosingClass.getNamedConstructor(constructorName.name);
162 }
163 processElement(_enclosingExecutable);
164 return super.visitConstructorDeclaration(node);
165 } finally {
166 _enclosingExecutable = outerExecutable;
167 }
168 }
169
170 @override
171 Object visitDeclaredIdentifier(DeclaredIdentifier node) {
172 SimpleIdentifier variableName = node.identifier;
173 LocalVariableElement element =
174 _findIdentifier(_enclosingExecutable.localVariables, variableName);
175 processElement(element);
176 return super.visitDeclaredIdentifier(node);
177 }
178
179 @override
180 Object visitDefaultFormalParameter(DefaultFormalParameter node) {
181 SimpleIdentifier parameterName = node.parameter.identifier;
182 ParameterElement element = _getElementForParameter(node, parameterName);
183 Expression defaultValue = node.defaultValue;
184 if (defaultValue != null) {
185 ExecutableElement outerExecutable = _enclosingExecutable;
186 try {
187 if (element == null) {
188 // TODO(brianwilkerson) Report this internal error.
189 } else {
190 _enclosingExecutable = element.initializer;
191 }
192 defaultValue.accept(this);
193 } finally {
194 _enclosingExecutable = outerExecutable;
195 }
196 processElement(_enclosingExecutable);
197 }
198 ParameterElement outerParameter = _enclosingParameter;
199 try {
200 _enclosingParameter = element;
201 processElement(_enclosingParameter);
202 return super.visitDefaultFormalParameter(node);
203 } finally {
204 _enclosingParameter = outerParameter;
205 }
206 }
207
208 @override
209 Object visitEnumDeclaration(EnumDeclaration node) {
210 ClassElement enclosingEnum =
211 _findIdentifier(_enclosingUnit.enums, node.name);
212 processElement(enclosingEnum);
213 List<FieldElement> constants = enclosingEnum.fields;
214 for (EnumConstantDeclaration constant in node.constants) {
215 FieldElement constantElement = _findIdentifier(constants, constant.name);
216 processElement(constantElement);
217 }
218 return super.visitEnumDeclaration(node);
219 }
220
221 @override
222 Object visitExportDirective(ExportDirective node) {
223 String uri = _getStringValue(node.uri);
224 if (uri != null) {
225 LibraryElement library = _enclosingUnit.library;
226 ExportElement exportElement = _findExport(
227 library.exports,
228 _enclosingUnit.context.sourceFactory.resolveUri(_enclosingUnit.source, uri));
229 processElement(exportElement);
230 }
231 return super.visitExportDirective(node);
232 }
233
234 @override
235 Object visitFieldFormalParameter(FieldFormalParameter node) {
236 if (node.parent is! DefaultFormalParameter) {
237 SimpleIdentifier parameterName = node.identifier;
238 ParameterElement element = _getElementForParameter(node, parameterName);
239 ParameterElement outerParameter = _enclosingParameter;
240 try {
241 _enclosingParameter = element;
242 processElement(_enclosingParameter);
243 return super.visitFieldFormalParameter(node);
244 } finally {
245 _enclosingParameter = outerParameter;
246 }
247 } else {
248 return super.visitFieldFormalParameter(node);
249 }
250 }
251
252 @override
253 Object visitFunctionDeclaration(FunctionDeclaration node) {
254 ExecutableElement outerExecutable = _enclosingExecutable;
255 try {
256 SimpleIdentifier functionName = node.name;
257 Token property = node.propertyKeyword;
258 if (property == null) {
259 if (_enclosingExecutable != null) {
260 _enclosingExecutable =
261 _findIdentifier(_enclosingExecutable.functions, functionName);
262 } else {
263 _enclosingExecutable =
264 _findIdentifier(_enclosingUnit.functions, functionName);
265 }
266 } else {
267 PropertyAccessorElement accessor =
268 _findIdentifier(_enclosingUnit.accessors, functionName);
269 if ((property as KeywordToken).keyword == Keyword.SET) {
270 accessor = accessor.variable.setter;
271 }
272 _enclosingExecutable = accessor;
273 }
274 processElement(_enclosingExecutable);
275 return super.visitFunctionDeclaration(node);
276 } finally {
277 _enclosingExecutable = outerExecutable;
278 }
279 }
280
281 @override
282 Object visitFunctionExpression(FunctionExpression node) {
283 if (node.parent is! FunctionDeclaration) {
284 FunctionElement element =
285 _findAtOffset(_enclosingExecutable.functions, node.beginToken.offset);
286 processElement(element);
287 }
288 ExecutableElement outerExecutable = _enclosingExecutable;
289 try {
290 _enclosingExecutable = node.element;
291 processElement(_enclosingExecutable);
292 return super.visitFunctionExpression(node);
293 } finally {
294 _enclosingExecutable = outerExecutable;
295 }
296 }
297
298 @override
299 Object visitFunctionTypeAlias(FunctionTypeAlias node) {
300 FunctionTypeAliasElement outerAlias = _enclosingAlias;
301 try {
302 SimpleIdentifier aliasName = node.name;
303 _enclosingAlias =
304 _findIdentifier(_enclosingUnit.functionTypeAliases, aliasName);
305 processElement(_enclosingAlias);
306 return super.visitFunctionTypeAlias(node);
307 } finally {
308 _enclosingAlias = outerAlias;
309 }
310 }
311
312 @override
313 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
314 if (node.parent is! DefaultFormalParameter) {
315 SimpleIdentifier parameterName = node.identifier;
316 ParameterElement element = _getElementForParameter(node, parameterName);
317 ParameterElement outerParameter = _enclosingParameter;
318 try {
319 _enclosingParameter = element;
320 processElement(_enclosingParameter);
321 return super.visitFunctionTypedFormalParameter(node);
322 } finally {
323 _enclosingParameter = outerParameter;
324 }
325 } else {
326 return super.visitFunctionTypedFormalParameter(node);
327 }
328 }
329
330 @override
331 Object visitImportDirective(ImportDirective node) {
332 String uri = _getStringValue(node.uri);
333 if (uri != null) {
334 LibraryElement library = _enclosingUnit.library;
335 ImportElement importElement = _findImport(
336 library.imports,
337 _enclosingUnit.context.sourceFactory.resolveUri(_enclosingUnit.source, uri),
338 node.prefix);
339 processElement(importElement);
340 }
341 return super.visitImportDirective(node);
342 }
343
344 @override
345 Object visitLabeledStatement(LabeledStatement node) {
346 for (Label label in node.labels) {
347 SimpleIdentifier labelName = label.label;
348 LabelElement element =
349 _findIdentifier(_enclosingExecutable.labels, labelName);
350 processElement(element);
351 }
352 return super.visitLabeledStatement(node);
353 }
354
355 @override
356 Object visitMethodDeclaration(MethodDeclaration node) {
357 ExecutableElement outerExecutable = _enclosingExecutable;
358 try {
359 Token property = node.propertyKeyword;
360 SimpleIdentifier methodName = node.name;
361 String nameOfMethod = methodName.name;
362 if (nameOfMethod == TokenType.MINUS.lexeme &&
363 node.parameters.parameters.length == 0) {
364 nameOfMethod = "unary-";
365 }
366 if (property == null) {
367 _enclosingExecutable = _findWithNameAndOffset(
368 _enclosingClass.methods,
369 nameOfMethod,
370 methodName.offset);
371 methodName.staticElement = _enclosingExecutable;
372 } else {
373 PropertyAccessorElement accessor =
374 _findIdentifier(_enclosingClass.accessors, methodName);
375 if ((property as KeywordToken).keyword == Keyword.SET) {
376 accessor = accessor.variable.setter;
377 methodName.staticElement = accessor;
378 }
379 _enclosingExecutable = accessor;
380 }
381 processElement(_enclosingExecutable);
382 return super.visitMethodDeclaration(node);
383 } finally {
384 _enclosingExecutable = outerExecutable;
385 }
386 }
387
388 @override
389 Object visitPartDirective(PartDirective node) {
390 String uri = _getStringValue(node.uri);
391 if (uri != null) {
392 Source partSource =
393 _enclosingUnit.context.sourceFactory.resolveUri(_enclosingUnit.source, uri);
394 CompilationUnitElement element =
395 _findPart(_enclosingUnit.library.parts, partSource);
396 processElement(element);
397 }
398 return super.visitPartDirective(node);
399 }
400
401 @override
402 Object visitSimpleFormalParameter(SimpleFormalParameter node) {
403 if (node.parent is! DefaultFormalParameter) {
404 SimpleIdentifier parameterName = node.identifier;
405 ParameterElement element = _getElementForParameter(node, parameterName);
406 ParameterElement outerParameter = _enclosingParameter;
407 try {
408 _enclosingParameter = element;
409 processElement(_enclosingParameter);
410 return super.visitSimpleFormalParameter(node);
411 } finally {
412 _enclosingParameter = outerParameter;
413 }
414 } else {
415 }
416 return super.visitSimpleFormalParameter(node);
417 }
418
419 @override
420 Object visitSwitchCase(SwitchCase node) {
421 for (Label label in node.labels) {
422 SimpleIdentifier labelName = label.label;
423 LabelElement element =
424 _findIdentifier(_enclosingExecutable.labels, labelName);
425 processElement(element);
426 }
427 return super.visitSwitchCase(node);
428 }
429
430 @override
431 Object visitSwitchDefault(SwitchDefault node) {
432 for (Label label in node.labels) {
433 SimpleIdentifier labelName = label.label;
434 LabelElement element =
435 _findIdentifier(_enclosingExecutable.labels, labelName);
436 processElement(element);
437 }
438 return super.visitSwitchDefault(node);
439 }
440
441 @override
442 Object visitTypeParameter(TypeParameter node) {
443 SimpleIdentifier parameterName = node.name;
444 TypeParameterElement element = null;
445 if (_enclosingClass != null) {
446 element = _findIdentifier(_enclosingClass.typeParameters, parameterName);
447 } else if (_enclosingAlias != null) {
448 element = _findIdentifier(_enclosingAlias.typeParameters, parameterName);
449 }
450 processElement(element);
451 return super.visitTypeParameter(node);
452 }
453
454 @override
455 Object visitVariableDeclaration(VariableDeclaration node) {
456 VariableElement element = null;
457 SimpleIdentifier variableName = node.name;
458 if (_enclosingExecutable != null) {
459 element =
460 _findIdentifier(_enclosingExecutable.localVariables, variableName);
461 }
462 if (element == null && _enclosingClass != null) {
463 element = _findIdentifier(_enclosingClass.fields, variableName);
464 }
465 if (element == null && _enclosingUnit != null) {
466 element = _findIdentifier(_enclosingUnit.topLevelVariables, variableName);
467 }
468 Expression initializer = node.initializer;
469 if (initializer != null) {
470 ExecutableElement outerExecutable = _enclosingExecutable;
471 try {
472 if (element == null) {
473 // TODO(brianwilkerson) Report this internal error.
474 } else {
475 _enclosingExecutable = element.initializer;
476 }
477 processElement(element);
478 processElement(_enclosingExecutable);
479 return super.visitVariableDeclaration(node);
480 } finally {
481 _enclosingExecutable = outerExecutable;
482 }
483 }
484 return super.visitVariableDeclaration(node);
485 }
486
487 /**
488 * Given that the comparison is to begin with the given element, capture the e nclosing elements
489 * that might be used while performing the comparison.
490 *
491 * @param element the element corresponding to the AST structure to be compare d
492 */
493 void _captureEnclosingElements(Element element) {
494 Element parent =
495 element is CompilationUnitElement ? element : element.enclosingElement;
496 while (parent != null) {
497 if (parent is CompilationUnitElement) {
498 _enclosingUnit = parent as CompilationUnitElement;
499 } else if (parent is ClassElement) {
500 if (_enclosingClass == null) {
501 _enclosingClass = parent as ClassElement;
502 }
503 } else if (parent is FunctionTypeAliasElement) {
504 if (_enclosingAlias == null) {
505 _enclosingAlias = parent as FunctionTypeAliasElement;
506 }
507 } else if (parent is ExecutableElement) {
508 if (_enclosingExecutable == null) {
509 _enclosingExecutable = parent as ExecutableElement;
510 }
511 } else if (parent is ParameterElement) {
512 if (_enclosingParameter == null) {
513 _enclosingParameter = parent as ParameterElement;
514 }
515 }
516 parent = parent.enclosingElement;
517 }
518 }
519
520 /**
521 * Return the element in the given array of elements that was created for the declaration at the
522 * given offset. This method should only be used when there is no name
523 *
524 * @param elements the elements of the appropriate kind that exist in the curr ent context
525 * @param offset the offset of the name of the element to be returned
526 * @return the element at the given offset
527 */
528 Element _findAtOffset(List<Element> elements, int offset) =>
529 _findWithNameAndOffset(elements, "", offset);
530
531 /**
532 * Return the export element from the given array whose library has the given source, or
533 * `null` if there is no such export.
534 *
535 * @param exports the export elements being searched
536 * @param source the source of the library associated with the export element to being searched
537 * for
538 * @return the export element whose library has the given source
539 */
540 ExportElement _findExport(List<ExportElement> exports, Source source) {
541 for (ExportElement export in exports) {
542 if (export.exportedLibrary.source == source) {
543 return export;
544 }
545 }
546 return null;
547 }
548
549 /**
550 * Return the element in the given array of elements that was created for the declaration with the
551 * given name.
552 *
553 * @param elements the elements of the appropriate kind that exist in the curr ent context
554 * @param identifier the name node in the declaration of the element to be ret urned
555 * @return the element created for the declaration with the given name
556 */
557 Element _findIdentifier(List<Element> elements,
558 SimpleIdentifier identifier) =>
559 _findWithNameAndOffset(elements, identifier.name, identifier.offset);
560
561 /**
562 * Return the import element from the given array whose library has the given source and that has
563 * the given prefix, or `null` if there is no such import.
564 *
565 * @param imports the import elements being searched
566 * @param source the source of the library associated with the import element to being searched
567 * for
568 * @param prefix the prefix with which the library was imported
569 * @return the import element whose library has the given source and prefix
570 */
571 ImportElement _findImport(List<ImportElement> imports, Source source,
572 SimpleIdentifier prefix) {
573 for (ImportElement element in imports) {
574 if (element.importedLibrary.source == source) {
575 PrefixElement prefixElement = element.prefix;
576 if (prefix == null) {
577 if (prefixElement == null) {
578 return element;
579 }
580 } else {
581 if (prefixElement != null &&
582 prefix.name == prefixElement.displayName) {
583 return element;
584 }
585 }
586 }
587 }
588 return null;
589 }
590
591 /**
592 * Return the element for the part with the given source, or `null` if there i s no element
593 * for the given source.
594 *
595 * @param parts the elements for the parts
596 * @param partSource the source for the part whose element is to be returned
597 * @return the element for the part with the given source
598 */
599 CompilationUnitElement _findPart(List<CompilationUnitElement> parts,
600 Source partSource) {
601 for (CompilationUnitElement part in parts) {
602 if (part.source == partSource) {
603 return part;
604 }
605 }
606 return null;
607 }
608
609 /**
610 * Return the element in the given array of elements that was created for the declaration with the
611 * given name at the given offset.
612 *
613 * @param elements the elements of the appropriate kind that exist in the curr ent context
614 * @param name the name of the element to be returned
615 * @param offset the offset of the name of the element to be returned
616 * @return the element with the given name and offset
617 */
618 Element _findWithNameAndOffset(List<Element> elements, String name,
619 int offset) {
620 for (Element element in elements) {
621 if (element.displayName == name && element.nameOffset == offset) {
622 return element;
623 }
624 }
625 return null;
626 }
627
628 void _gatherElements(Element element) {
629 element.accept(new _ElementsGatherer(this));
630 }
631
632 /**
633 * Search the most closely enclosing list of parameters for a parameter with t he given name.
634 *
635 * @param node the node defining the parameter with the given name
636 * @param parameterName the name of the parameter being searched for
637 * @return the element representing the parameter with that name
638 */
639 ParameterElement _getElementForParameter(FormalParameter node,
640 SimpleIdentifier parameterName) {
641 List<ParameterElement> parameters = null;
642 if (_enclosingParameter != null) {
643 parameters = _enclosingParameter.parameters;
644 }
645 if (parameters == null && _enclosingExecutable != null) {
646 parameters = _enclosingExecutable.parameters;
647 }
648 if (parameters == null && _enclosingAlias != null) {
649 parameters = _enclosingAlias.parameters;
650 }
651 return parameters == null ?
652 null :
653 _findIdentifier(parameters, parameterName);
654 }
655
656 /**
657 * Return the value of the given string literal, or `null` if the string is no t a constant
658 * string without any string interpolation.
659 *
660 * @param literal the string literal whose value is to be returned
661 * @return the value of the given string literal
662 */
663 String _getStringValue(StringLiteral literal) {
664 if (literal is StringInterpolation) {
665 return null;
666 }
667 return literal.stringValue;
668 }
669
670 /**
671 * Return `true` if the given class defines at least one constructor.
672 *
673 * @param node the class being tested
674 * @return `true` if the class defines at least one constructor
675 */
676 bool _hasConstructor(ClassDeclaration node) {
677 for (ClassMember member in node.members) {
678 if (member is ConstructorDeclaration) {
679 return true;
680 }
681 }
682 return false;
683 }
684 }
685
686
687 /**
688 * Instances of the class [IncrementalResolver] resolve the smallest portion of
689 * an AST structure that we currently know how to resolve.
690 */
691 class IncrementalResolver {
692 /**
693 * The element for the library containing the compilation unit being visited.
694 */
695 final LibraryElement _definingLibrary;
696
697 /**
698 * The source representing the compilation unit being visited.
699 */
700 final Source _source;
701
702 /**
703 * The object used to access the types from the core library.
704 */
705 final TypeProvider _typeProvider;
706
707 /**
708 * The error listener that will be informed of any errors that are found durin g resolution.
709 */
710 final AnalysisErrorListener _errorListener;
711
712 /**
713 * Initialize a newly created incremental resolver to resolve a node in the gi ven source in the
714 * given library, reporting errors to the given error listener.
715 *
716 * @param definingLibrary the element for the library containing the compilati on unit being
717 * visited
718 * @param source the source representing the compilation unit being visited
719 * @param typeProvider the object used to access the types from the core libra ry
720 * @param errorListener the error listener that will be informed of any errors that are found
721 * during resolution
722 */
723 IncrementalResolver(this._definingLibrary, this._source, this._typeProvider,
724 this._errorListener);
725
726 /**
727 * Resolve the given node, reporting any errors or warnings to the given liste ner.
728 *
729 * @param node the root of the AST structure to be resolved
730 * @throws AnalysisException if the node could not be resolved
731 */
732 void resolve(AstNode node) {
733 AstNode rootNode = _findResolutionRoot(node);
734 Scope scope = ScopeBuilder.scopeFor(rootNode, _errorListener);
735 if (_elementModelChanged(rootNode.parent)) {
736 throw new AnalysisException("Cannot resolve node: element model changed");
737 }
738 _resolveTypes(node, scope);
739 _resolveVariables(node, scope);
740 _resolveReferences(node, scope);
741 }
742
743 /**
744 * Return `true` if the given node can be resolved independently of any other nodes.
745 *
746 * <b>Note:</b> This method needs to be kept in sync with [ScopeBuilder.scopeF orAstNode].
747 *
748 * @param node the node being tested
749 * @return `true` if the given node can be resolved independently of any other nodes
750 */
751 bool _canBeResolved(AstNode node) =>
752 node is ClassDeclaration ||
753 node is ClassTypeAlias ||
754 node is CompilationUnit ||
755 node is ConstructorDeclaration ||
756 node is FunctionDeclaration ||
757 node is FunctionTypeAlias ||
758 node is MethodDeclaration;
759
760 /**
761 * Return `true` if the portion of the element model defined by the given node has changed.
762 *
763 * @param node the node defining the portion of the element model being tested
764 * @return `true` if the element model defined by the given node has changed
765 * @throws AnalysisException if the correctness of the element model cannot be determined
766 */
767 bool _elementModelChanged(AstNode node) {
768 Element element = _getElement(node);
769 if (element == null) {
770 throw new AnalysisException(
771 "Cannot resolve node: a ${node.runtimeType} does not define an element ");
772 }
773 DeclarationMatcher matcher = new DeclarationMatcher();
774 return !matcher.matches(node, element);
775 }
776
777 /**
778 * Starting at the given node, find the smallest AST node that can be resolved independently of
779 * any other nodes. Return the node that was found.
780 *
781 * @param node the node at which the search is to begin
782 * @return the smallest AST node that can be resolved independently of any oth er nodes
783 * @throws AnalysisException if there is no such node
784 */
785 AstNode _findResolutionRoot(AstNode node) {
786 AstNode result = node;
787 AstNode parent = result.parent;
788 while (parent != null && !_canBeResolved(parent)) {
789 result = parent;
790 parent = result.parent;
791 }
792 if (parent == null) {
793 throw new AnalysisException("Cannot resolve node: no resolvable node");
794 }
795 return result;
796 }
797
798 /**
799 * Return the element defined by the given node, or `null` if the node does no t define an
800 * element.
801 *
802 * @param node the node defining the element to be returned
803 * @return the element defined by the given node
804 */
805 Element _getElement(AstNode node) {
806 if (node is Declaration) {
807 return node.element;
808 } else if (node is CompilationUnit) {
809 return node.element;
810 }
811 return null;
812 }
813
814 void _resolveReferences(AstNode node, Scope scope) {
815 ResolverVisitor visitor = new ResolverVisitor.con3(
816 _definingLibrary,
817 _source,
818 _typeProvider,
819 scope,
820 _errorListener);
821 node.accept(visitor);
822 }
823
824 void _resolveTypes(AstNode node, Scope scope) {
825 TypeResolverVisitor visitor = new TypeResolverVisitor.con3(
826 _definingLibrary,
827 _source,
828 _typeProvider,
829 scope,
830 _errorListener);
831 node.accept(visitor);
832 }
833
834 void _resolveVariables(AstNode node, Scope scope) {
835 VariableResolverVisitor visitor = new VariableResolverVisitor.con2(
836 _definingLibrary,
837 _source,
838 _typeProvider,
839 scope,
840 _errorListener);
841 node.accept(visitor);
842 }
843 }
844
845
846 /**
847 * Instances of the class [ScopeBuilder] build the scope for a given node in an
848 * AST structure. At the moment, this class only handles top-level and
849 * class-level declarations.
850 */
851 class ScopeBuilder {
852 /**
853 * The listener to which analysis errors will be reported.
854 */
855 final AnalysisErrorListener _errorListener;
856
857 /**
858 * Initialize a newly created scope builder to generate a scope that will repo rt errors to the
859 * given listener.
860 *
861 * @param errorListener the listener to which analysis errors will be reported
862 */
863 ScopeBuilder(this._errorListener);
864
865 /**
866 * Return the scope in which the given AST structure should be resolved.
867 *
868 * <b>Note:</b> This method needs to be kept in sync with
869 * [IncrementalResolver.canBeResolved].
870 *
871 * @param node the root of the AST structure to be resolved
872 * @return the scope in which the given AST structure should be resolved
873 * @throws AnalysisException if the AST structure has not been resolved or is not part of a
874 * [CompilationUnit]
875 */
876 Scope _scopeForAstNode(AstNode node) {
877 if (node is CompilationUnit) {
878 return _scopeForCompilationUnit(node);
879 }
880 AstNode parent = node.parent;
881 if (parent == null) {
882 throw new AnalysisException(
883 "Cannot create scope: node is not part of a CompilationUnit");
884 }
885 Scope scope = _scopeForAstNode(parent);
886 if (node is ClassDeclaration) {
887 ClassElement element = node.element;
888 if (element == null) {
889 throw new AnalysisException(
890 "Cannot build a scope for an unresolved class");
891 }
892 scope = new ClassScope(new TypeParameterScope(scope, element), element);
893 } else if (node is ClassTypeAlias) {
894 ClassElement element = node.element;
895 if (element == null) {
896 throw new AnalysisException(
897 "Cannot build a scope for an unresolved class type alias");
898 }
899 scope = new ClassScope(new TypeParameterScope(scope, element), element);
900 } else if (node is ConstructorDeclaration) {
901 ConstructorElement element = node.element;
902 if (element == null) {
903 throw new AnalysisException(
904 "Cannot build a scope for an unresolved constructor");
905 }
906 FunctionScope functionScope = new FunctionScope(scope, element);
907 functionScope.defineParameters();
908 scope = functionScope;
909 } else if (node is FunctionDeclaration) {
910 ExecutableElement element = node.element;
911 if (element == null) {
912 throw new AnalysisException(
913 "Cannot build a scope for an unresolved function");
914 }
915 FunctionScope functionScope = new FunctionScope(scope, element);
916 functionScope.defineParameters();
917 scope = functionScope;
918 } else if (node is FunctionTypeAlias) {
919 scope = new FunctionTypeScope(scope, node.element);
920 } else if (node is MethodDeclaration) {
921 ExecutableElement element = node.element;
922 if (element == null) {
923 throw new AnalysisException(
924 "Cannot build a scope for an unresolved method");
925 }
926 FunctionScope functionScope = new FunctionScope(scope, element);
927 functionScope.defineParameters();
928 scope = functionScope;
929 }
930 return scope;
931 }
932
933 Scope _scopeForCompilationUnit(CompilationUnit node) {
934 CompilationUnitElement unitElement = node.element;
935 if (unitElement == null) {
936 throw new AnalysisException(
937 "Cannot create scope: compilation unit is not resolved");
938 }
939 LibraryElement libraryElement = unitElement.library;
940 if (libraryElement == null) {
941 throw new AnalysisException(
942 "Cannot create scope: compilation unit is not part of a library");
943 }
944 return new LibraryScope(libraryElement, _errorListener);
945 }
946
947 /**
948 * Return the scope in which the given AST structure should be resolved.
949 *
950 * @param node the root of the AST structure to be resolved
951 * @param errorListener the listener to which analysis errors will be reported
952 * @return the scope in which the given AST structure should be resolved
953 * @throws AnalysisException if the AST structure has not been resolved or is not part of a
954 * [CompilationUnit]
955 */
956 static Scope scopeFor(AstNode node, AnalysisErrorListener errorListener) {
957 if (node == null) {
958 throw new AnalysisException("Cannot create scope: node is null");
959 } else if (node is CompilationUnit) {
960 ScopeBuilder builder = new ScopeBuilder(errorListener);
961 return builder._scopeForAstNode(node);
962 }
963 AstNode parent = node.parent;
964 if (parent == null) {
965 throw new AnalysisException(
966 "Cannot create scope: node is not part of a CompilationUnit");
967 }
968 ScopeBuilder builder = new ScopeBuilder(errorListener);
969 return builder._scopeForAstNode(parent);
970 }
971 }
972
973
974 /**
975 * Instances of the class [_DeclarationMismatchException] represent an exception
976 * that is thrown when the element model defined by a given AST structure does
977 * not match an existing element model.
978 */
979 class _DeclarationMismatchException {
980 }
981
982
983 class _ElementsGatherer extends GeneralizingElementVisitor {
984 final DeclarationMatcher matcher;
985
986 _ElementsGatherer(this.matcher);
987
988 @override
989 visitElement(Element element) {
990 matcher._allElements.add(element);
991 matcher._unmatchedElements.add(element);
992 super.visitElement(element);
993 }
994 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/generated/engine.dart ('k') | pkg/analyzer/lib/src/generated/resolver.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698