@@ -18,26 +18,56 @@ class GatherUsedImportedElementsVisitor extends RecursiveAstVisitor {
1818
1919 GatherUsedImportedElementsVisitor (this .library);
2020
21+ @override
22+ void visitBinaryExpression (BinaryExpression node) {
23+ _recordIfExtensionMember (node.staticElement);
24+ return super .visitBinaryExpression (node);
25+ }
26+
2127 @override
2228 void visitExportDirective (ExportDirective node) {
2329 _visitDirective (node);
2430 }
2531
32+ @override
33+ void visitFunctionExpressionInvocation (FunctionExpressionInvocation node) {
34+ _recordIfExtensionMember (node.staticElement);
35+ return super .visitFunctionExpressionInvocation (node);
36+ }
37+
2638 @override
2739 void visitImportDirective (ImportDirective node) {
2840 _visitDirective (node);
2941 }
3042
43+ @override
44+ void visitIndexExpression (IndexExpression node) {
45+ _recordIfExtensionMember (node.staticElement);
46+ return super .visitIndexExpression (node);
47+ }
48+
3149 @override
3250 void visitLibraryDirective (LibraryDirective node) {
3351 _visitDirective (node);
3452 }
3553
54+ @override
55+ void visitPrefixExpression (PrefixExpression node) {
56+ _recordIfExtensionMember (node.staticElement);
57+ return super .visitPrefixExpression (node);
58+ }
59+
3660 @override
3761 void visitSimpleIdentifier (SimpleIdentifier node) {
3862 _visitIdentifier (node, node.staticElement);
3963 }
4064
65+ void _recordIfExtensionMember (Element element) {
66+ if (element != null && element.enclosingElement is ExtensionElement ) {
67+ _recordUsedExtension (element.enclosingElement);
68+ }
69+ }
70+
4171 /// If the given [identifier] is prefixed with a [PrefixElement] , fill the
4272 /// corresponding `UsedImportedElements.prefixMap` entry and return `true` .
4373 bool _recordPrefixMap (SimpleIdentifier identifier, Element element) {
@@ -61,6 +91,29 @@ class GatherUsedImportedElementsVisitor extends RecursiveAstVisitor {
6191 return false ;
6292 }
6393
94+ void _recordUsedElement (Element element) {
95+ // Ignore if an unknown library.
96+ LibraryElement containingLibrary = element.library;
97+ if (containingLibrary == null ) {
98+ return ;
99+ }
100+ // Ignore if a local element.
101+ if (library == containingLibrary) {
102+ return ;
103+ }
104+ // Remember the element.
105+ usedElements.elements.add (element);
106+ }
107+
108+ void _recordUsedExtension (ExtensionElement extension ) {
109+ // Ignore if a local element.
110+ if (library == extension .library) {
111+ return ;
112+ }
113+ // Remember the element.
114+ usedElements.usedExtensions.add (extension );
115+ }
116+
64117 /// Visit identifiers used by the given [directive] .
65118 void _visitDirective (Directive directive) {
66119 directive.documentationComment? .accept (this );
@@ -71,44 +124,28 @@ class GatherUsedImportedElementsVisitor extends RecursiveAstVisitor {
71124 if (element == null ) {
72125 return ;
73126 }
74- // If the element is multiply defined then call this method recursively for
75- // each of the conflicting elements.
76- if (element is MultiplyDefinedElement ) {
127+ // Record `importPrefix.identifier` into 'prefixMap'.
128+ if (_recordPrefixMap (identifier, element)) {
129+ return ;
130+ }
131+ Element enclosingElement = element.enclosingElement;
132+ if (enclosingElement is CompilationUnitElement ) {
133+ _recordUsedElement (element);
134+ } else if (enclosingElement is ExtensionElement ) {
135+ _recordUsedExtension (enclosingElement);
136+ return ;
137+ } else if (element is PrefixElement ) {
138+ usedElements.prefixMap.putIfAbsent (element, () => < Element > []);
139+ } else if (element is MultiplyDefinedElement ) {
140+ // If the element is multiply defined then call this method recursively
141+ // for each of the conflicting elements.
77142 List <Element > conflictingElements = element.conflictingElements;
78143 int length = conflictingElements.length;
79144 for (int i = 0 ; i < length; i++ ) {
80145 Element elt = conflictingElements[i];
81146 _visitIdentifier (identifier, elt);
82147 }
83- return ;
84- }
85-
86- // Record `importPrefix.identifier` into 'prefixMap'.
87- if (_recordPrefixMap (identifier, element)) {
88- return ;
89- }
90-
91- if (element is PrefixElement ) {
92- usedElements.prefixMap.putIfAbsent (element, () => < Element > []);
93- return ;
94- } else if (element.enclosingElement is ! CompilationUnitElement ) {
95- // Identifiers that aren't a prefix element and whose enclosing element
96- // isn't a CompilationUnit are ignored- this covers the case the
97- // identifier is a relative-reference, a reference to an identifier not
98- // imported by this library.
99- return ;
100- }
101- // Ignore if an unknown library.
102- LibraryElement containingLibrary = element.library;
103- if (containingLibrary == null ) {
104- return ;
105148 }
106- // Ignore if a local element.
107- if (library == containingLibrary) {
108- return ;
109- }
110- // Remember the element.
111- usedElements.elements.add (element);
112149 }
113150}
114151
@@ -381,6 +418,22 @@ class ImportsVerifier {
381418 }
382419 }
383420 }
421+ // Process extension elements.
422+ for (ExtensionElement extensionElement in usedElements.usedExtensions) {
423+ // Stop if all the imports and shown names are known to be used.
424+ if (_unusedImports.isEmpty && _unusedShownNamesMap.isEmpty) {
425+ return ;
426+ }
427+ // Find import directives using namespaces.
428+ String name = extensionElement.name;
429+ for (ImportDirective importDirective in _allImports) {
430+ Namespace namespace = _computeNamespace (importDirective);
431+ if (namespace? .get (name) == extensionElement) {
432+ _unusedImports.remove (importDirective);
433+ _removeFromUnusedShownNamesMap (extensionElement, importDirective);
434+ }
435+ }
436+ }
384437 }
385438
386439 /// Add duplicate shown and hidden names from [directive] into
@@ -492,11 +545,12 @@ class ImportsVerifier {
492545/// A container with information about used imports prefixes and used imported
493546/// elements.
494547class UsedImportedElements {
495- /// The map of referenced [PrefixElement] s and the [Element] s that they
496- /// prefix.
497- final Map <PrefixElement , List <Element >> prefixMap =
498- new HashMap <PrefixElement , List <Element >>();
548+ /// The map of referenced prefix elements and the elements that they prefix.
549+ final Map <PrefixElement , List <Element >> prefixMap = {};
550+
551+ /// The set of referenced top-level elements.
552+ final Set <Element > elements = {};
499553
500- /// The set of referenced top-level [Element] s .
501- final Set <Element > elements = new HashSet < Element >() ;
554+ /// The set of extensions defining members that are referenced .
555+ final Set <ExtensionElement > usedExtensions = {} ;
502556}
0 commit comments