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

Side by Side Diff: pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart

Issue 816233002: refactor/cleanup dart completion cache (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: merge and address comments Created 5 years, 12 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
« no previous file with comments | « no previous file | pkg/analysis_server/test/services/completion/imported_computer_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 services.completion.dart.cache; 5 library services.completion.dart.cache;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:collection'; 8 import 'dart:collection';
9 9
10 import 'package:analysis_server/src/protocol_server.dart' hide Element, 10 import 'package:analysis_server/src/protocol_server.dart' hide Element,
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
74 DartCompletionCache(AnalysisContext context, Source source) 74 DartCompletionCache(AnalysisContext context, Source source)
75 : super(context, source); 75 : super(context, source);
76 76
77 /** 77 /**
78 * Return a hash of the import directives for the cached import info 78 * Return a hash of the import directives for the cached import info
79 * or `null` if nothing has been cached. 79 * or `null` if nothing has been cached.
80 */ 80 */
81 String get importKey => _importKey; 81 String get importKey => _importKey;
82 82
83 /** 83 /**
84 * Return the [ClassElement] for Object.
85 */
86 ClassElement get objectClassElement {
87 if (_objectClassElement == null) {
88 Source coreUri = context.sourceFactory.forUri('dart:core');
89 LibraryElement coreLib = context.getLibraryElement(coreUri);
90 _objectClassElement = coreLib.getType('Object');
91 }
92 return _objectClassElement;
93 }
94
95 /**
84 * Given a resolved compilation unit, compute suggestions based upon the 96 * Given a resolved compilation unit, compute suggestions based upon the
85 * imports and other dart files (e.g. "part" files) in the library containing 97 * imports and other dart files (e.g. "part" files) in the library containing
86 * the given compilation unit. The returned future completes when the cache 98 * the given compilation unit. The returned future completes when the cache
87 * is populated. 99 * is populated.
88 * 100 *
89 * If [shouldWaitForLowPrioritySuggestions] is `true` then the returned 101 * If [shouldWaitForLowPrioritySuggestions] is `true` then the returned
90 * future will complete when the cache is fully populated. If `false`, 102 * future will complete when the cache is fully populated. If `false`,
91 * the returned future will complete sooner, but the cache will not include 103 * the returned future will complete sooner, but the cache will not include
92 * the lower priority suggestions added as a result of a global search. 104 * the lower priority suggestions added as a result of a global search.
93 * In this case, those lower priority suggestions will be added later 105 * In this case, those lower priority suggestions will be added later
(...skipping 13 matching lines...) Expand all
107 assert(unit.element.source == source); 119 assert(unit.element.source == source);
108 120
109 // Exclude elements from local library 121 // Exclude elements from local library
110 // because they are provided by LocalComputer 122 // because they are provided by LocalComputer
111 Set<LibraryElement> excludedLibs = new Set<LibraryElement>(); 123 Set<LibraryElement> excludedLibs = new Set<LibraryElement>();
112 excludedLibs.add(unit.element.enclosingElement); 124 excludedLibs.add(unit.element.enclosingElement);
113 125
114 // Determine the compilation unit defining the library containing 126 // Determine the compilation unit defining the library containing
115 // this compilation unit 127 // this compilation unit
116 List<Source> libraries = context.getLibrariesContaining(source); 128 List<Source> libraries = context.getLibrariesContaining(source);
117 Source libSource = null; 129 assert(libraries != null);
118 Future<CompilationUnit> futureLibUnit; 130 Source libSource = libraries.length > 0 ? libraries[0] : null;
119 if (libraries != null && libraries.length > 0) { 131 Future<CompilationUnit> futureLibUnit = _computeLibUnit(libSource, unit);
120 libSource = libraries[0];
121 if (libSource == source) {
122 // If the sources are the same then we already have the library unit
123 futureLibUnit = new Future.value(unit);
124 } else {
125 // If the sources are different, then get the library unit
126 // to traverse the library directives and cache the imported elements
127 futureLibUnit =
128 context.computeResolvedCompilationUnitAsync(libSource, libSource);
129 }
130 } else {
131 futureLibUnit = new Future.value(null);
132 }
133 132
134 // Include explicitly imported elements 133 // Include implicitly imported dart:core elements
134 _addDartCoreSuggestions();
135
136 // Include explicitly imported and part elements
135 Future futureImportsCached = futureLibUnit.then((CompilationUnit libUnit) { 137 Future futureImportsCached = futureLibUnit.then((CompilationUnit libUnit) {
136 if (libUnit != null) { 138 _addImportedElemSuggestions(libSource, libUnit, excludedLibs);
137 libUnit.directives.forEach((Directive directive) {
138 if (directive is ImportDirective) {
139 ImportElement importElem = directive.element;
140 if (importElem != null && importElem.importedLibrary != null) {
141 if (directive.prefix == null) {
142 Namespace importNamespace =
143 new NamespaceBuilder().createImportNamespaceForDirective(imp ortElem);
144 // Include top level elements
145 importNamespace.definedNames.forEach(
146 (String name, Element elem) {
147 if (elem is ClassElement) {
148 importedClassMap[name] = elem;
149 }
150 addSuggestion(elem, CompletionRelevance.DEFAULT);
151 });
152 } else {
153 // Exclude elements from prefixed imports
154 // because they are provided by InvocationComputer
155 excludedLibs.add(importElem.importedLibrary);
156 _addLibraryPrefixSuggestion(importElem);
157 }
158 }
159 } else if (directive is PartDirective) {
160 CompilationUnitElement partElem = directive.element;
161 if (partElem != null && partElem.source != source) {
162 partElem.accept(new _NonLocalElementCacheVisitor(this));
163 }
164 }
165 });
166 if (libSource != source) {
167 libUnit.element.accept(new _NonLocalElementCacheVisitor(this));
168 }
169 }
170 // Don't wait for search of lower relevance results to complete. 139 // Don't wait for search of lower relevance results to complete.
171 // Set key indicating results are ready, and lower relevance results 140 // Set key indicating results are ready, and lower relevance results
172 // will be added to the cache when the search completes. 141 // will be added to the cache when the search completes.
173 _importKey = _computeImportKey(unit); 142 _importKey = _computeImportKey(unit);
174 return true; 143 return true;
175 }); 144 });
176 145
177 // Include implicitly imported dart:core elements
178 Source coreUri = context.sourceFactory.forUri('dart:core');
179 LibraryElement coreLib = context.getLibraryElement(coreUri);
180 Namespace coreNamespace =
181 new NamespaceBuilder().createPublicNamespaceForLibrary(coreLib);
182 coreNamespace.definedNames.forEach((String name, Element elem) {
183 if (elem is ClassElement) {
184 importedClassMap[name] = elem;
185 }
186 addSuggestion(elem, CompletionRelevance.DEFAULT);
187 });
188 _objectClassElement = importedClassMap['Object'];
189
190 // Add non-imported elements as low relevance 146 // Add non-imported elements as low relevance
191 // after the imported element suggestions have been added 147 // after the imported element suggestions have been added
192 Future<bool> futureAllCached = futureImportsCached.then((_) { 148 Future<bool> futureAllCached = futureImportsCached.then((_) {
193 return searchEngine.searchTopLevelDeclarations( 149 return searchEngine.searchTopLevelDeclarations(
194 '').then((List<SearchMatch> matches) { 150 '').then((List<SearchMatch> matches) {
195 matches.forEach((SearchMatch match) { 151 _addNonImportedElementSuggestions(matches, excludedLibs);
196 if (match.kind == MatchKind.DECLARATION) {
197 Element element = match.element;
198 if (element.isPublic &&
199 !excludedLibs.contains(element.library) &&
200 !_importedCompletions.contains(element.displayName)) {
201 addSuggestion(element, CompletionRelevance.LOW);
202 }
203 }
204 });
205 return true; 152 return true;
206 }); 153 });
207 }); 154 });
208 155
209 return shouldWaitForLowPrioritySuggestions ? 156 return shouldWaitForLowPrioritySuggestions ?
210 futureAllCached : 157 futureAllCached :
211 futureImportsCached; 158 futureImportsCached;
212 } 159 }
213 160
214 /** 161 /**
215 * Return the [ClassElement] for Object.
216 */
217 ClassElement get objectClassElement {
218 if (_objectClassElement == null) {
219 Source coreUri = context.sourceFactory.forUri('dart:core');
220 LibraryElement coreLib = context.getLibraryElement(coreUri);
221 Namespace coreNamespace =
222 new NamespaceBuilder().createPublicNamespaceForLibrary(coreLib);
223 _objectClassElement = coreNamespace.definedNames['Object'];
224 }
225 return _objectClassElement;
226 }
227
228 /**
229 * Return `true` if the import information is cached for the given 162 * Return `true` if the import information is cached for the given
230 * compilation unit. 163 * compilation unit.
231 */ 164 */
232 bool isImportInfoCached(CompilationUnit unit) => 165 bool isImportInfoCached(CompilationUnit unit) =>
233 _importKey != null && _importKey == _computeImportKey(unit); 166 _importKey != null && _importKey == _computeImportKey(unit);
234 167
168 /**
169 * Add suggestions for implicitly imported elements in dart:core.
170 */
171 void _addDartCoreSuggestions() {
172 Source coreUri = context.sourceFactory.forUri('dart:core');
173 LibraryElement coreLib = context.getLibraryElement(coreUri);
174 Namespace coreNamespace =
175 new NamespaceBuilder().createPublicNamespaceForLibrary(coreLib);
176 coreNamespace.definedNames.forEach((String name, Element elem) {
177 if (elem is ClassElement) {
178 importedClassMap[name] = elem;
179 }
180 _addSuggestion(elem, CompletionRelevance.DEFAULT);
181 });
182 }
183
184 /**
185 * Add suggestions for explicitly imported and part elements in the given
186 * library. Add libraries that should not have their elements suggested
187 * even as low priority to [excludedLibs].
188 */
189 void _addImportedElemSuggestions(Source libSource, CompilationUnit libUnit,
190 Set<LibraryElement> excludedLibs) {
191 if (libUnit != null) {
192 libUnit.directives.forEach((Directive directive) {
193 if (directive is ImportDirective) {
194 ImportElement importElem = directive.element;
195 if (importElem != null && importElem.importedLibrary != null) {
196 if (directive.prefix == null) {
197 Namespace importNamespace =
198 new NamespaceBuilder().createImportNamespaceForDirective(impor tElem);
199 // Include top level elements
200 importNamespace.definedNames.forEach((String name, Element elem) {
201 if (elem is ClassElement) {
202 importedClassMap[name] = elem;
203 }
204 _addSuggestion(elem, CompletionRelevance.DEFAULT);
205 });
206 } else {
207 // Exclude elements from prefixed imports
208 // because they are provided by InvocationComputer
209 _addLibraryPrefixSuggestion(importElem);
210 excludedLibs.add(importElem.importedLibrary);
211 }
212 }
213 } else if (directive is PartDirective) {
214 CompilationUnitElement partElem = directive.element;
215 if (partElem != null && partElem.source != source) {
216 partElem.accept(new _NonLocalElementCacheVisitor(this));
217 }
218 }
219 });
220 if (libSource != source) {
221 libUnit.element.accept(new _NonLocalElementCacheVisitor(this));
222 }
223 }
224 }
225
235 void _addLibraryPrefixSuggestion(ImportElement importElem) { 226 void _addLibraryPrefixSuggestion(ImportElement importElem) {
236 CompletionSuggestion suggestion = null; 227 CompletionSuggestion suggestion = null;
237 String completion = importElem.prefix.displayName; 228 String completion = importElem.prefix.displayName;
238 if (completion != null && completion.length > 0) { 229 if (completion != null && completion.length > 0) {
239 suggestion = new CompletionSuggestion( 230 suggestion = new CompletionSuggestion(
240 CompletionSuggestionKind.INVOCATION, 231 CompletionSuggestionKind.INVOCATION,
241 CompletionRelevance.DEFAULT, 232 CompletionRelevance.DEFAULT,
242 completion, 233 completion,
243 completion.length, 234 completion.length,
244 0, 235 0,
245 importElem.isDeprecated, 236 importElem.isDeprecated,
246 false); 237 false);
247 LibraryElement lib = importElem.importedLibrary; 238 LibraryElement lib = importElem.importedLibrary;
248 if (lib != null) { 239 if (lib != null) {
249 suggestion.element = newElement_fromEngine(lib); 240 suggestion.element = newElement_fromEngine(lib);
250 } 241 }
251 libraryPrefixSuggestions.add(suggestion); 242 libraryPrefixSuggestions.add(suggestion);
252 _importedCompletions.add(suggestion.completion); 243 _importedCompletions.add(suggestion.completion);
253 } 244 }
254 } 245 }
255 246
256 void addSuggestion(Element element, CompletionRelevance relevance) { 247 /**
248 * Add suggestions for all top level elements in the context
249 * excluding those elemnents for which suggestions have already been added.
250 */
251 void _addNonImportedElementSuggestions(List<SearchMatch> matches,
252 Set<LibraryElement> excludedLibs) {
253 matches.forEach((SearchMatch match) {
254 if (match.kind == MatchKind.DECLARATION) {
255 Element element = match.element;
256 if (element.isPublic &&
257 !excludedLibs.contains(element.library) &&
258 !_importedCompletions.contains(element.displayName)) {
259 _addSuggestion(element, CompletionRelevance.LOW);
260 }
261 }
262 });
263 }
264
265 /**
266 * Add a suggestion for the given element.
267 */
268 void _addSuggestion(Element element, CompletionRelevance relevance) {
257 269
258 if (element is ExecutableElement) { 270 if (element is ExecutableElement) {
259 if (element.isOperator) { 271 if (element.isOperator) {
260 return; 272 return;
261 } 273 }
262 } 274 }
263 275
264 CompletionSuggestion suggestion = 276 CompletionSuggestion suggestion =
265 createElementSuggestion(element, relevance: relevance); 277 createElementSuggestion(element, relevance: relevance);
266 278
(...skipping 15 matching lines...) Expand all
282 /** 294 /**
283 * Compute the hash of the imports for the given compilation unit. 295 * Compute the hash of the imports for the given compilation unit.
284 */ 296 */
285 String _computeImportKey(CompilationUnit unit) { 297 String _computeImportKey(CompilationUnit unit) {
286 StringBuffer sb = new StringBuffer(); 298 StringBuffer sb = new StringBuffer();
287 unit.directives.forEach((Directive directive) { 299 unit.directives.forEach((Directive directive) {
288 sb.write(directive.toSource()); 300 sb.write(directive.toSource());
289 }); 301 });
290 return sb.toString(); 302 return sb.toString();
291 } 303 }
304
305 /**
306 * Compute the library unit for the given library source,
307 * where the [unit] is the resolved compilation unit associated with [source].
308 */
309 Future<CompilationUnit> _computeLibUnit(Source libSource,
310 CompilationUnit unit) {
311 // If the sources are the same then we already have the library unit
312 if (libSource == source) {
313 return new Future.value(unit);
314 }
315 // If [source] is a part, then compute the library unit
316 if (libSource != null) {
317 return context.computeResolvedCompilationUnitAsync(libSource, libSource);
318 }
319 return new Future.value(null);
320 }
292 } 321 }
293 322
294 /** 323 /**
295 * A visitor for building suggestions based upon the elements defined by 324 * A visitor for building suggestions based upon the elements defined by
296 * a source file contained in the same library but not the same as 325 * a source file contained in the same library but not the same as
297 * the source in which the completions are being requested. 326 * the source in which the completions are being requested.
298 */ 327 */
299 class _NonLocalElementCacheVisitor extends GeneralizingElementVisitor { 328 class _NonLocalElementCacheVisitor extends GeneralizingElementVisitor {
300 final DartCompletionCache cache; 329 final DartCompletionCache cache;
301 330
302 _NonLocalElementCacheVisitor(this.cache); 331 _NonLocalElementCacheVisitor(this.cache);
303 332
304 @override 333 @override
305 void visitClassElement(ClassElement element) { 334 void visitClassElement(ClassElement element) {
306 cache.addSuggestion(element, CompletionRelevance.DEFAULT); 335 cache._addSuggestion(element, CompletionRelevance.DEFAULT);
307 } 336 }
308 337
309 @override 338 @override
310 void visitCompilationUnitElement(CompilationUnitElement element) { 339 void visitCompilationUnitElement(CompilationUnitElement element) {
311 element.visitChildren(this); 340 element.visitChildren(this);
312 } 341 }
313 342
314 @override 343 @override
315 void visitElement(Element element) { 344 void visitElement(Element element) {
316 // ignored 345 // ignored
317 } 346 }
318 347
319 @override 348 @override
320 void visitFunctionElement(FunctionElement element) { 349 void visitFunctionElement(FunctionElement element) {
321 cache.addSuggestion(element, CompletionRelevance.DEFAULT); 350 cache._addSuggestion(element, CompletionRelevance.DEFAULT);
322 } 351 }
323 352
324 @override 353 @override
325 void visitFunctionTypeAliasElement(FunctionTypeAliasElement element) { 354 void visitFunctionTypeAliasElement(FunctionTypeAliasElement element) {
326 cache.addSuggestion(element, CompletionRelevance.DEFAULT); 355 cache._addSuggestion(element, CompletionRelevance.DEFAULT);
327 } 356 }
328 357
329 @override 358 @override
330 void visitTopLevelVariableElement(TopLevelVariableElement element) { 359 void visitTopLevelVariableElement(TopLevelVariableElement element) {
331 cache.addSuggestion(element, CompletionRelevance.DEFAULT); 360 cache._addSuggestion(element, CompletionRelevance.DEFAULT);
332 } 361 }
333 } 362 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analysis_server/test/services/completion/imported_computer_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698