| 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 |