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

Side by Side Diff: pkg/analysis_server/lib/src/services/correction/namespace.dart

Issue 481173002: When user renames 'prefix' in 'prefix.Class' she actually wants to rename ImportElement. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Tweak for test - reference ambiguous prefix name. Created 6 years, 4 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 | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library services.src.correction.namespace;
6
7 import 'package:analyzer/src/generated/ast.dart';
8 import 'package:analyzer/src/generated/element.dart';
9 import 'package:analyzer/src/generated/resolver.dart';
10
11
12 /**
13 * Returns the namespace of the given [ExportElement].
14 */
15 Map<String, Element> getExportNamespaceForDirective(ExportElement exp) {
16 Namespace namespace =
17 new NamespaceBuilder().createExportNamespaceForDirective(exp);
18 return namespace.definedNames;
19 }
20
21
22 /**
23 * Returns the export namespace of the given [LibraryElement].
24 */
25 Map<String, Element> getExportNamespaceForLibrary(LibraryElement library) {
26 Namespace namespace =
27 new NamespaceBuilder().createExportNamespaceForLibrary(library);
28 return namespace.definedNames;
29 }
30
31
32 /**
33 * Returns the [Element] exported from the given [LibraryElement].
34 */
35 Element getExportedElement(LibraryElement library, String name) {
36 if (library == null) {
37 return null;
38 }
39 return getExportNamespaceForLibrary(library)[name];
40 }
41
42
43 /**
44 * Returns the [ImportElement] that is referenced by [prefixNode] with
45 * an [PrefixElement], maybe `null`.
46 */
47 ImportElement getImportElement(SimpleIdentifier prefixNode) {
48 if (prefixNode.parent is ImportDirective) {
49 ImportDirective importDirective = prefixNode.parent;
50 return importDirective.element;
51 }
52 ImportElementInfo info = internal_getImportElementInfo(prefixNode);
53 return info != null ? info.element : null;
54 }
55
56 /**
57 * Return the [ImportElement] that declared [prefix] and imports [element].
58 *
59 * [libraryElement] - the [LibraryElement] where reference is.
60 * [prefix] - the import prefix, maybe `null`.
61 * [element] - the referenced element.
62 * [importElementsMap] - the cache of [Element]s imported by [ImportElement]s.
63 */
64 ImportElement internal_getImportElement(LibraryElement libraryElement,
65 String prefix, Element element, Map<ImportElement,
66 Set<Element>> importElementsMap) {
67 // validate Element
68 if (element == null) {
69 return null;
70 }
71 if (element.enclosingElement is! CompilationUnitElement) {
72 return null;
73 }
74 LibraryElement usedLibrary = element.library;
75 // find ImportElement that imports used library with used prefix
76 List<ImportElement> candidates = null;
77 for (ImportElement importElement in libraryElement.imports) {
78 // required library
79 if (importElement.importedLibrary != usedLibrary) {
80 continue;
81 }
82 // required prefix
83 PrefixElement prefixElement = importElement.prefix;
84 if (prefix == null) {
85 if (prefixElement != null) {
86 continue;
87 }
88 } else {
89 if (prefixElement == null) {
90 continue;
91 }
92 if (prefix != prefixElement.name) {
93 continue;
94 }
95 }
96 // no combinators => only possible candidate
97 if (importElement.combinators.length == 0) {
98 return importElement;
99 }
100 // OK, we have candidate
101 if (candidates == null) {
102 candidates = [];
103 }
104 candidates.add(importElement);
105 }
106 // no candidates, probably element is defined in this library
107 if (candidates == null) {
108 return null;
109 }
110 // one candidate
111 if (candidates.length == 1) {
112 return candidates[0];
113 }
114 // ensure that each ImportElement has set of elements
115 for (ImportElement importElement in candidates) {
116 if (importElementsMap.containsKey(importElement)) {
117 continue;
118 }
119 Namespace namespace =
120 new NamespaceBuilder().createImportNamespaceForDirective(importElement);
121 Set<Element> elements = new Set.from(namespace.definedNames.values);
122 importElementsMap[importElement] = elements;
123 }
124 // use import namespace to choose correct one
125 for (ImportElement importElement in importElementsMap.keys) {
126 Set<Element> elements = importElementsMap[importElement];
127 if (elements.contains(element)) {
128 return importElement;
129 }
130 }
131 // not found
132 return null;
133 }
134
135
136 /**
137 * Returns the [ImportElementInfo] with the [ImportElement] that is referenced
138 * by [prefixNode] with a [PrefixElement], maybe `null`.
139 */
140 ImportElementInfo internal_getImportElementInfo(SimpleIdentifier prefixNode) {
141 ImportElementInfo info = new ImportElementInfo();
142 // prepare environment
143 AstNode parent = prefixNode.parent;
144 CompilationUnit unit =
145 prefixNode.getAncestor((node) => node is CompilationUnit);
146 LibraryElement libraryElement = unit.element.library;
147 // prepare used element
148 Element usedElement = null;
149 if (parent is PrefixedIdentifier) {
150 PrefixedIdentifier prefixed = parent;
151 if (prefixed.prefix == prefixNode) {
152 usedElement = prefixed.staticElement;
153 info.periodEnd = prefixed.period.end;
154 }
155 }
156 if (parent is MethodInvocation) {
157 MethodInvocation invocation = parent;
158 if (invocation.target == prefixNode) {
159 usedElement = invocation.methodName.staticElement;
160 info.periodEnd = invocation.period.end;
161 }
162 }
163 // we need used Element
164 if (usedElement == null) {
165 return null;
166 }
167 // find ImportElement
168 String prefix = prefixNode.name;
169 Map<ImportElement, Set<Element>> importElementsMap = {};
170 info.element = internal_getImportElement(
171 libraryElement,
172 prefix,
173 usedElement,
174 importElementsMap);
175 if (info.element == null) {
176 return null;
177 }
178 return info;
179 }
180
181
182 /**
183 * Information about [ImportElement] and place where it is referenced using
184 * [PrefixElement].
185 */
186 class ImportElementInfo {
187 ImportElement element;
188 int periodEnd;
189 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698