@@ -25,20 +25,20 @@ class ImportAnalyzer {
25
25
final Set <Element > stayingDeclarations = {};
26
26
27
27
/// A map from the elements referenced by the declarations to be moved to the
28
- /// set of prefixes used to reference those declarations.
29
- final Map <Element , Set <String >> movingReferences = {};
28
+ /// set of imports used to reference those declarations.
29
+ final Map <Element , Set <LibraryImportElement >> movingReferences = {};
30
30
31
31
/// A map from the elements referenced by the declarations that are staying to
32
- /// the set of prefixes used to reference those declarations.
33
- final Map <Element , Set <String >> stayingReferences = {};
32
+ /// the set of imports used to reference those declarations.
33
+ final Map <Element , Set <LibraryImportElement >> stayingReferences = {};
34
34
35
35
/// Analyze the given library [result] to find the declarations and references
36
36
/// being moved and that are staying. The declarations being moved are in the
37
37
/// file at the given [path] in the given [range] .
38
38
ImportAnalyzer (this .result, String path, List <SourceRange > ranges) {
39
39
for (var unit in result.units) {
40
40
var finder = _ReferenceFinder (
41
- _ElementRecorder (this , path == unit.path ? ranges : []));
41
+ unit, _ElementRecorder (this , path == unit.path ? ranges : []));
42
42
unit.unit.accept (finder);
43
43
}
44
44
// Remove references that will be within the same file.
@@ -102,23 +102,27 @@ class _ElementRecorder {
102
102
}
103
103
}
104
104
105
- /// Record that the [element ] is referenced in the library at the
106
- /// [referenceOffset] . [prefix ] is the prefixused to reference the element, or
107
- /// `null` if no prefix was used .
108
- void recordReference (
109
- Element referencedElement, int referenceOffset, PrefixElement ? prefix ) {
105
+ /// Record that [referencedElement ] is referenced in the library at the
106
+ /// [referenceOffset] . [import ] is the specific import used to reference the
107
+ /// including any prefix, show, hide .
108
+ void recordReference (Element referencedElement, int referenceOffset,
109
+ LibraryImportElement ? import ) {
110
110
if (referencedElement is PropertyAccessorElement &&
111
111
referencedElement.isSynthetic) {
112
112
referencedElement = referencedElement.variable;
113
113
}
114
114
if (_isBeingMoved (referenceOffset)) {
115
- var prefixes =
115
+ var imports =
116
116
analyzer.movingReferences.putIfAbsent (referencedElement, () => {});
117
- prefixes.add (prefix? .name ?? '' );
117
+ if (import != null ) {
118
+ imports.add (import);
119
+ }
118
120
} else {
119
- var prefixes =
121
+ var imports =
120
122
analyzer.stayingReferences.putIfAbsent (referencedElement, () => {});
121
- prefixes.add (prefix? .name ?? '' );
123
+ if (import != null ) {
124
+ imports.add (import);
125
+ }
122
126
}
123
127
}
124
128
@@ -139,8 +143,24 @@ class _ReferenceFinder extends RecursiveAstVisitor<void> {
139
143
/// sent.
140
144
final _ElementRecorder recorder;
141
145
146
+ /// The unit being searched for references.
147
+ final ResolvedUnitResult unit;
148
+
149
+ /// A mapping of prefixes to the imports with those prefixes. An
150
+ /// empty string is used for unprefixed imports.
151
+ ///
152
+ /// Library imports are ordered the same as they appear in the source file
153
+ /// (since this is a [LinkedHashSet] ).
154
+ final _importsByPrefix = < String , Set <LibraryImportElement >> {};
155
+
142
156
/// Initialize a newly created finder to send information to the [recorder] .
143
- _ReferenceFinder (this .recorder);
157
+ _ReferenceFinder (this .unit, this .recorder) {
158
+ for (var import in unit.libraryElement.libraryImports) {
159
+ _importsByPrefix
160
+ .putIfAbsent (import.prefix? .element.name ?? '' , () => {})
161
+ .add (import);
162
+ }
163
+ }
144
164
145
165
@override
146
166
void visitAssignmentExpression (AssignmentExpression node) {
@@ -249,6 +269,43 @@ class _ReferenceFinder extends RecursiveAstVisitor<void> {
249
269
super .visitTopLevelVariableDeclaration (node);
250
270
}
251
271
272
+ /// Finds the [LibraryImportElement] that is used to import [element] for use
273
+ /// in [node] .
274
+ LibraryImportElement ? _getImportForElement (AstNode ? node, Element element) {
275
+ var prefix = _getPrefixFromExpression (node)? .name;
276
+ var elementName = element.name;
277
+ // We cannot locate imports for unnamed elements.
278
+ if (elementName == null ) {
279
+ return null ;
280
+ }
281
+
282
+ var import = _importsByPrefix[prefix ?? '' ]? .where ((import) {
283
+ // Check if this import is providing our element with the correct
284
+ // prefix/name.
285
+ var exportedElement = prefix != null
286
+ ? import.namespace.getPrefixed (prefix, elementName)
287
+ : import.namespace.get (elementName);
288
+ return exportedElement == element;
289
+ }).firstOrNull;
290
+
291
+ // Extensions can be used without a prefix, so we can use any import that
292
+ // brings in the extension.
293
+ if (import == null && prefix == null && element is ExtensionElement ) {
294
+ import = _importsByPrefix.values
295
+ .expand ((imports) => imports)
296
+ .where ((import) =>
297
+ // Because we don't know what prefix we're looking for (any is
298
+ // allowed), use the imports own prefix when checking for the
299
+ // element.
300
+ import.namespace.getPrefixed (
301
+ import.prefix? .element.name ?? '' , elementName) ==
302
+ element)
303
+ .firstOrNull;
304
+ }
305
+
306
+ return import;
307
+ }
308
+
252
309
/// Return the prefix used in [node] .
253
310
PrefixElement ? _getPrefixFromExpression (AstNode ? node) {
254
311
if (node is PrefixedIdentifier ) {
@@ -291,8 +348,9 @@ class _ReferenceFinder extends RecursiveAstVisitor<void> {
291
348
if (! element.isInterestingReference) {
292
349
return ;
293
350
}
294
- recorder.recordReference (
295
- element, node.offset, _getPrefixFromExpression (prefixNode));
351
+
352
+ var import = _getImportForElement (prefixNode, element);
353
+ recorder.recordReference (element, node.offset, import);
296
354
}
297
355
}
298
356
0 commit comments