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

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

Issue 1882633002: Clean up reporting HintCode.UNUSED_SHOWN_NAME when a prefixed top-level function is invoked. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Added new test. Created 4 years, 8 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 | pkg/analyzer/test/generated/non_hint_code_test.dart » ('j') | 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) 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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/test/generated/non_hint_code_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698