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

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

Powered by Google App Engine
This is Rietveld 408576698