OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 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 | 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.resolver; | 5 library analyzer.src.generated.resolver; |
6 | 6 |
7 import 'dart:collection'; | 7 import 'dart:collection'; |
8 | 8 |
9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
10 import 'package:analyzer/dart/ast/token.dart'; | 10 import 'package:analyzer/dart/ast/token.dart'; |
(...skipping 4086 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4097 void visitImportDirective(ImportDirective node) { | 4097 void visitImportDirective(ImportDirective node) { |
4098 _visitDirective(node); | 4098 _visitDirective(node); |
4099 } | 4099 } |
4100 | 4100 |
4101 @override | 4101 @override |
4102 void visitLibraryDirective(LibraryDirective node) { | 4102 void visitLibraryDirective(LibraryDirective node) { |
4103 _visitDirective(node); | 4103 _visitDirective(node); |
4104 } | 4104 } |
4105 | 4105 |
4106 @override | 4106 @override |
4107 void visitPrefixedIdentifier(PrefixedIdentifier node) { | |
4108 // If the prefixed identifier references some A.B, where A is a library | |
4109 // prefix, then we can lookup the associated ImportDirective in | |
4110 // prefixElementMap and remove it from the unusedImports list. | |
4111 SimpleIdentifier prefixIdentifier = node.prefix; | |
4112 Element element = prefixIdentifier.staticElement; | |
4113 if (element is PrefixElement) { | |
4114 List<Element> prefixedElements = | |
4115 usedElements.prefixMap.putIfAbsent(element, () => <Element>[]); | |
4116 prefixedElements.add(node.identifier.staticElement); | |
4117 return; | |
4118 } | |
4119 // Otherwise, pass the prefixed identifier element and name onto | |
4120 // visitIdentifier. | |
4121 _visitIdentifier(element, prefixIdentifier.name); | |
4122 } | |
4123 | |
4124 @override | |
4125 void visitSimpleIdentifier(SimpleIdentifier node) { | 4107 void visitSimpleIdentifier(SimpleIdentifier node) { |
4126 _visitIdentifier(node.staticElement, node.name); | 4108 _visitIdentifier(node, node.staticElement); |
4127 } | 4109 } |
4128 | 4110 |
4129 /** | 4111 /** |
4130 * Visit identifiers used by the given [directive]. | 4112 * Visit identifiers used by the given [directive]. |
4131 */ | 4113 */ |
4132 void _visitDirective(Directive directive) { | 4114 void _visitDirective(Directive directive) { |
4133 directive.documentationComment?.accept(this); | 4115 directive.documentationComment?.accept(this); |
4134 directive.metadata.accept(this); | 4116 directive.metadata.accept(this); |
4135 } | 4117 } |
4136 | 4118 |
4137 void _visitIdentifier(Element element, String name) { | 4119 void _visitIdentifier(SimpleIdentifier identifier, Element element) { |
4138 if (element == null) { | 4120 if (element == null) { |
4139 return; | 4121 return; |
4140 } | 4122 } |
4141 // If the element is multiply defined then call this method recursively for | 4123 // If the element is multiply defined then call this method recursively for |
4142 // each of the conflicting elements. | 4124 // each of the conflicting elements. |
4143 if (element is MultiplyDefinedElement) { | 4125 if (element is MultiplyDefinedElement) { |
4144 MultiplyDefinedElement multiplyDefinedElement = element; | 4126 MultiplyDefinedElement multiplyDefinedElement = element; |
4145 for (Element elt in multiplyDefinedElement.conflictingElements) { | 4127 for (Element elt in multiplyDefinedElement.conflictingElements) { |
4146 _visitIdentifier(elt, name); | 4128 _visitIdentifier(identifier, elt); |
4147 } | 4129 } |
4148 return; | 4130 return; |
4149 } else if (element is PrefixElement) { | 4131 } |
| 4132 |
| 4133 // Record `importPrefix.identifier` into 'prefixMap'. |
| 4134 if (_recordPrefixMap(identifier, element)) { |
| 4135 return; |
| 4136 } |
| 4137 |
| 4138 if (element is PrefixElement) { |
4150 usedElements.prefixMap.putIfAbsent(element, () => <Element>[]); | 4139 usedElements.prefixMap.putIfAbsent(element, () => <Element>[]); |
4151 return; | 4140 return; |
4152 } else if (element.enclosingElement is! CompilationUnitElement) { | 4141 } else if (element.enclosingElement is! CompilationUnitElement) { |
4153 // Identifiers that aren't a prefix element and whose enclosing element | 4142 // Identifiers that aren't a prefix element and whose enclosing element |
4154 // isn't a CompilationUnit are ignored- this covers the case the | 4143 // isn't a CompilationUnit are ignored- this covers the case the |
4155 // identifier is a relative-reference, a reference to an identifier not | 4144 // identifier is a relative-reference, a reference to an identifier not |
4156 // imported by this library. | 4145 // imported by this library. |
4157 return; | 4146 return; |
4158 } | 4147 } |
4159 // Ignore if an unknown library. | 4148 // Ignore if an unknown library. |
4160 LibraryElement containingLibrary = element.library; | 4149 LibraryElement containingLibrary = element.library; |
4161 if (containingLibrary == null) { | 4150 if (containingLibrary == null) { |
4162 return; | 4151 return; |
4163 } | 4152 } |
4164 // Ignore if a local element. | 4153 // Ignore if a local element. |
4165 if (library == containingLibrary) { | 4154 if (library == containingLibrary) { |
4166 return; | 4155 return; |
4167 } | 4156 } |
4168 // Remember the element. | 4157 // Remember the element. |
4169 usedElements.elements.add(element); | 4158 usedElements.elements.add(element); |
4170 } | 4159 } |
| 4160 |
| 4161 /** |
| 4162 * If the given [identifier] is prefixed with a [PrefixElement], fill the |
| 4163 * corresponding `UsedImportedElements.prefixMap` entry and return `true`. |
| 4164 */ |
| 4165 bool _recordPrefixMap(SimpleIdentifier identifier, Element element) { |
| 4166 bool recordIfTargetIsPrefixElement(Expression target) { |
| 4167 if (target is SimpleIdentifier && target.staticElement is PrefixElement) { |
| 4168 List<Element> prefixedElements = usedElements.prefixMap |
| 4169 .putIfAbsent(target.staticElement, () => <Element>[]); |
| 4170 prefixedElements.add(element); |
| 4171 return true; |
| 4172 } |
| 4173 return false; |
| 4174 } |
| 4175 AstNode parent = identifier.parent; |
| 4176 if (parent is MethodInvocation && parent.methodName == identifier) { |
| 4177 return recordIfTargetIsPrefixElement(parent.target); |
| 4178 } |
| 4179 if (parent is PrefixedIdentifier && parent.identifier == identifier) { |
| 4180 return recordIfTargetIsPrefixElement(parent.prefix); |
| 4181 } |
| 4182 return false; |
| 4183 } |
4171 } | 4184 } |
4172 | 4185 |
4173 /** | 4186 /** |
4174 * An [AstVisitor] that fills [UsedLocalElements]. | 4187 * An [AstVisitor] that fills [UsedLocalElements]. |
4175 */ | 4188 */ |
4176 class GatherUsedLocalElementsVisitor extends RecursiveAstVisitor { | 4189 class GatherUsedLocalElementsVisitor extends RecursiveAstVisitor { |
4177 final UsedLocalElements usedElements = new UsedLocalElements(); | 4190 final UsedLocalElements usedElements = new UsedLocalElements(); |
4178 | 4191 |
4179 final LibraryElement _enclosingLibrary; | 4192 final LibraryElement _enclosingLibrary; |
4180 ClassElement _enclosingClass; | 4193 ClassElement _enclosingClass; |
(...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4645 | 4658 |
4646 /** | 4659 /** |
4647 * Report an [HintCode.UNUSED_SHOWN_NAME] hint for each unused shown name. | 4660 * Report an [HintCode.UNUSED_SHOWN_NAME] hint for each unused shown name. |
4648 * | 4661 * |
4649 * Only call this method after all of the compilation units have been visited
by this visitor. | 4662 * Only call this method after all of the compilation units have been visited
by this visitor. |
4650 * | 4663 * |
4651 * @param errorReporter the error reporter used to report the set of [HintCode
.UNUSED_SHOWN_NAME] | 4664 * @param errorReporter the error reporter used to report the set of [HintCode
.UNUSED_SHOWN_NAME] |
4652 * hints | 4665 * hints |
4653 */ | 4666 */ |
4654 void generateUnusedShownNameHints(ErrorReporter reporter) { | 4667 void generateUnusedShownNameHints(ErrorReporter reporter) { |
4655 _unusedShownNamesMap.forEach((ImportDirective importDirective, | 4668 _unusedShownNamesMap.forEach( |
4656 List<SimpleIdentifier> identifiers) { | 4669 (ImportDirective importDirective, List<SimpleIdentifier> identifiers) { |
4657 if (_unusedImports.contains(importDirective)) { | 4670 if (_unusedImports.contains(importDirective)) { |
4658 // This import is actually wholly unused, not just one or more shown nam
es from it. | 4671 // This import is actually wholly unused, not just one or more shown nam
es from it. |
4659 // This is then an "unused import", rather than unused shown names. | 4672 // This is then an "unused import", rather than unused shown names. |
4660 return; | 4673 return; |
4661 } | 4674 } |
4662 for (Identifier identifier in identifiers) { | 4675 for (Identifier identifier in identifiers) { |
4663 reporter.reportErrorForNode(HintCode.UNUSED_SHOWN_NAME, identifier, [ide
ntifier.name]); | 4676 reporter.reportErrorForNode( |
| 4677 HintCode.UNUSED_SHOWN_NAME, identifier, [identifier.name]); |
4664 } | 4678 } |
4665 }); | 4679 }); |
4666 } | 4680 } |
4667 | 4681 |
4668 /** | 4682 /** |
4669 * Remove elements from [_unusedImports] using the given [usedElements]. | 4683 * Remove elements from [_unusedImports] using the given [usedElements]. |
4670 */ | 4684 */ |
4671 void removeUsedElements(UsedImportedElements usedElements) { | 4685 void removeUsedElements(UsedImportedElements usedElements) { |
4672 // Stop if all the imports and shown names are known to be used. | 4686 // Stop if all the imports and shown names are known to be used. |
4673 if (_unusedImports.isEmpty && _unusedShownNamesMap.isEmpty) { | 4687 if (_unusedImports.isEmpty && _unusedShownNamesMap.isEmpty) { |
4674 return; | 4688 return; |
4675 } | 4689 } |
4676 // Process import prefixes. | 4690 // Process import prefixes. |
4677 usedElements.prefixMap.forEach((PrefixElement prefix, List<Element> elements
) { | 4691 usedElements.prefixMap |
| 4692 .forEach((PrefixElement prefix, List<Element> elements) { |
4678 List<ImportDirective> importDirectives = _prefixElementMap[prefix]; | 4693 List<ImportDirective> importDirectives = _prefixElementMap[prefix]; |
4679 if (importDirectives != null) { | 4694 if (importDirectives != null) { |
4680 for (ImportDirective importDirective in importDirectives) { | 4695 for (ImportDirective importDirective in importDirectives) { |
4681 _unusedImports.remove(importDirective); | 4696 _unusedImports.remove(importDirective); |
4682 for (Element element in elements) { | 4697 for (Element element in elements) { |
4683 _removeFromUnusedShownNamesMap(element, importDirective); | 4698 _removeFromUnusedShownNamesMap(element, importDirective); |
4684 } | 4699 } |
4685 } | 4700 } |
4686 } | 4701 } |
4687 }); | 4702 }); |
(...skipping 16 matching lines...) Expand all Loading... |
4704 if (importsLibrary.length == 1) { | 4719 if (importsLibrary.length == 1) { |
4705 ImportDirective usedImportDirective = importsLibrary[0]; | 4720 ImportDirective usedImportDirective = importsLibrary[0]; |
4706 _unusedImports.remove(usedImportDirective); | 4721 _unusedImports.remove(usedImportDirective); |
4707 _removeFromUnusedShownNamesMap(element, usedImportDirective); | 4722 _removeFromUnusedShownNamesMap(element, usedImportDirective); |
4708 continue; | 4723 continue; |
4709 } | 4724 } |
4710 // Otherwise, find import directives using namespaces. | 4725 // Otherwise, find import directives using namespaces. |
4711 String name = element.displayName; | 4726 String name = element.displayName; |
4712 for (ImportDirective importDirective in importsLibrary) { | 4727 for (ImportDirective importDirective in importsLibrary) { |
4713 Namespace namespace = _computeNamespace(importDirective); | 4728 Namespace namespace = _computeNamespace(importDirective); |
4714 if (importDirective.prefix != null) { | |
4715 name = "${importDirective.prefix.name}.$name"; | |
4716 } | |
4717 if (namespace != null && namespace.get(name) != null) { | 4729 if (namespace != null && namespace.get(name) != null) { |
4718 _unusedImports.remove(importDirective); | 4730 _unusedImports.remove(importDirective); |
4719 _removeFromUnusedShownNamesMap(element, importDirective); | 4731 _removeFromUnusedShownNamesMap(element, importDirective); |
4720 } | 4732 } |
4721 } | 4733 } |
4722 } | 4734 } |
4723 } | 4735 } |
4724 | 4736 |
4725 /** | 4737 /** |
4726 * Remove [element] from the list of names shown by [importDirective]. | |
4727 */ | |
4728 void _removeFromUnusedShownNamesMap(Element element, | |
4729 ImportDirective importDirective) { | |
4730 List<SimpleIdentifier> identifiers = _unusedShownNamesMap[importDirective]; | |
4731 if (identifiers == null) { | |
4732 return; | |
4733 } | |
4734 for (Identifier identifier in identifiers) { | |
4735 if (element is PropertyAccessorElement) { | |
4736 // If the getter or setter of a variable is used, then the variable (the | |
4737 // shown name) is used. | |
4738 if (identifier.staticElement == element.variable) { | |
4739 identifiers.remove(identifier); | |
4740 break; | |
4741 } | |
4742 } else { | |
4743 if (identifier.staticElement == element) { | |
4744 identifiers.remove(identifier); | |
4745 break; | |
4746 } | |
4747 } | |
4748 } | |
4749 if (identifiers.isEmpty) { | |
4750 _unusedShownNamesMap.remove(importDirective); | |
4751 } | |
4752 } | |
4753 | |
4754 /** | |
4755 * Recursively add any exported library elements into the [libraryMap]. | 4738 * Recursively add any exported library elements into the [libraryMap]. |
4756 */ | 4739 */ |
4757 void _addAdditionalLibrariesForExports(LibraryElement library, | 4740 void _addAdditionalLibrariesForExports(LibraryElement library, |
4758 ImportDirective importDirective, List<LibraryElement> exportPath) { | 4741 ImportDirective importDirective, List<LibraryElement> exportPath) { |
4759 if (exportPath.contains(library)) { | 4742 if (exportPath.contains(library)) { |
4760 return; | 4743 return; |
4761 } | 4744 } |
4762 exportPath.add(library); | 4745 exportPath.add(library); |
4763 for (LibraryElement exportedLibraryElt in library.exportedLibraries) { | 4746 for (LibraryElement exportedLibraryElt in library.exportedLibraries) { |
4764 _putIntoLibraryMap(exportedLibraryElt, importDirective); | 4747 _putIntoLibraryMap(exportedLibraryElt, importDirective); |
4765 _addAdditionalLibrariesForExports( | 4748 _addAdditionalLibrariesForExports( |
4766 exportedLibraryElt, importDirective, exportPath); | 4749 exportedLibraryElt, importDirective, exportPath); |
4767 } | 4750 } |
4768 } | 4751 } |
4769 | 4752 |
4770 /** | 4753 /** |
| 4754 * Add every shown name from [importDirective] into [_unusedShownNamesMap]. |
| 4755 */ |
| 4756 void _addShownNames(ImportDirective importDirective) { |
| 4757 if (importDirective.combinators == null) { |
| 4758 return; |
| 4759 } |
| 4760 List<SimpleIdentifier> identifiers = new List<SimpleIdentifier>(); |
| 4761 _unusedShownNamesMap[importDirective] = identifiers; |
| 4762 for (Combinator combinator in importDirective.combinators) { |
| 4763 if (combinator is ShowCombinator) { |
| 4764 for (SimpleIdentifier name in combinator.shownNames) { |
| 4765 identifiers.add(name); |
| 4766 } |
| 4767 } |
| 4768 } |
| 4769 } |
| 4770 |
| 4771 /** |
4771 * Lookup and return the [Namespace] from the [_namespaceMap]. | 4772 * Lookup and return the [Namespace] from the [_namespaceMap]. |
4772 * | 4773 * |
4773 * If the map does not have the computed namespace, compute it and cache it in
the map. If | 4774 * If the map does not have the computed namespace, compute it and cache it in
the map. If |
4774 * [importDirective] is not resolved or is not resolvable, `null` is returned. | 4775 * [importDirective] is not resolved or is not resolvable, `null` is returned. |
4775 * | 4776 * |
4776 * @param importDirective the import directive used to compute the returned na
mespace | 4777 * @param importDirective the import directive used to compute the returned na
mespace |
4777 * @return the computed or looked up [Namespace] | 4778 * @return the computed or looked up [Namespace] |
4778 */ | 4779 */ |
4779 Namespace _computeNamespace(ImportDirective importDirective) { | 4780 Namespace _computeNamespace(ImportDirective importDirective) { |
4780 Namespace namespace = _namespaceMap[importDirective]; | 4781 Namespace namespace = _namespaceMap[importDirective]; |
(...skipping 20 matching lines...) Expand all Loading... |
4801 LibraryElement libraryElement, ImportDirective importDirective) { | 4802 LibraryElement libraryElement, ImportDirective importDirective) { |
4802 List<ImportDirective> importList = _libraryMap[libraryElement]; | 4803 List<ImportDirective> importList = _libraryMap[libraryElement]; |
4803 if (importList == null) { | 4804 if (importList == null) { |
4804 importList = new List<ImportDirective>(); | 4805 importList = new List<ImportDirective>(); |
4805 _libraryMap[libraryElement] = importList; | 4806 _libraryMap[libraryElement] = importList; |
4806 } | 4807 } |
4807 importList.add(importDirective); | 4808 importList.add(importDirective); |
4808 } | 4809 } |
4809 | 4810 |
4810 /** | 4811 /** |
4811 * Add every shown name from [importDirective] into [_unusedShownNamesMap]. | 4812 * Remove [element] from the list of names shown by [importDirective]. |
4812 */ | 4813 */ |
4813 void _addShownNames(ImportDirective importDirective) { | 4814 void _removeFromUnusedShownNamesMap( |
4814 if (importDirective.combinators == null) { | 4815 Element element, ImportDirective importDirective) { |
| 4816 List<SimpleIdentifier> identifiers = _unusedShownNamesMap[importDirective]; |
| 4817 if (identifiers == null) { |
4815 return; | 4818 return; |
4816 } | 4819 } |
4817 List<SimpleIdentifier> identifiers = new List<SimpleIdentifier>(); | 4820 for (Identifier identifier in identifiers) { |
4818 _unusedShownNamesMap[importDirective] = identifiers; | 4821 if (element is PropertyAccessorElement) { |
4819 for (Combinator combinator in importDirective.combinators) { | 4822 // If the getter or setter of a variable is used, then the variable (the |
4820 if (combinator is ShowCombinator) { | 4823 // shown name) is used. |
4821 for (SimpleIdentifier name in combinator.shownNames) { | 4824 if (identifier.staticElement == element.variable) { |
4822 identifiers.add(name); | 4825 identifiers.remove(identifier); |
| 4826 break; |
| 4827 } |
| 4828 } else { |
| 4829 if (identifier.staticElement == element) { |
| 4830 identifiers.remove(identifier); |
| 4831 break; |
4823 } | 4832 } |
4824 } | 4833 } |
4825 } | 4834 } |
| 4835 if (identifiers.isEmpty) { |
| 4836 _unusedShownNamesMap.remove(importDirective); |
| 4837 } |
4826 } | 4838 } |
4827 } | 4839 } |
4828 | 4840 |
4829 /** | 4841 /** |
4830 * Maintains and manages contextual type information used for | 4842 * Maintains and manages contextual type information used for |
4831 * inferring types. | 4843 * inferring types. |
4832 */ | 4844 */ |
4833 class InferenceContext { | 4845 class InferenceContext { |
4834 // TODO(leafp): Consider replacing these node properties with a | 4846 // TODO(leafp): Consider replacing these node properties with a |
4835 // hash table help in an instance of this class. | 4847 // hash table help in an instance of this class. |
(...skipping 8244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13080 nonFields.add(node); | 13092 nonFields.add(node); |
13081 return null; | 13093 return null; |
13082 } | 13094 } |
13083 | 13095 |
13084 @override | 13096 @override |
13085 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this); | 13097 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this); |
13086 | 13098 |
13087 @override | 13099 @override |
13088 Object visitWithClause(WithClause node) => null; | 13100 Object visitWithClause(WithClause node) => null; |
13089 } | 13101 } |
OLD | NEW |