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

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

Issue 811933007: insert parameters when completing imported functions and inherited methods (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: merge Created 5 years, 11 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
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.suggestion.builder; 5 library services.completion.suggestion.builder;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 8
9 import 'package:analysis_server/src/protocol_server.dart' as protocol; 9 import 'package:analysis_server/src/protocol_server.dart' as protocol;
10 import 'package:analysis_server/src/protocol_server.dart' hide Element, 10 import 'package:analysis_server/src/protocol_server.dart' hide Element,
11 ElementKind; 11 ElementKind;
12 import 'package:analysis_server/src/services/completion/dart_completion_manager. dart'; 12 import 'package:analysis_server/src/services/completion/dart_completion_manager. dart';
13 import 'package:analyzer/src/generated/ast.dart'; 13 import 'package:analyzer/src/generated/ast.dart';
14 import 'package:analyzer/src/generated/element.dart'; 14 import 'package:analyzer/src/generated/element.dart';
15 import 'package:analyzer/src/generated/scanner.dart';
16 import 'package:analyzer/src/generated/utilities_dart.dart'; 15 import 'package:analyzer/src/generated/utilities_dart.dart';
17 16
18 final DYNAMIC = 'dynamic'; 17 final DYNAMIC = 'dynamic';
19 final DartType NO_RETURN_TYPE = new _NoReturnType(); 18 final DartType NO_RETURN_TYPE = new _NoReturnType();
20 19
21 /** 20 /**
22 * Create a suggestion based upon the given imported element. 21 * Return a suggestion based upon the given element
22 * or `null` if a suggestion is not appropriate for the given element.
23 */ 23 */
24 CompletionSuggestion createElementSuggestion(Element element, {int relevance: 24 CompletionSuggestion createSuggestion(Element element,
25 COMPLETION_RELEVANCE_DEFAULT}) { 25 {CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
26 int relevance: COMPLETION_RELEVANCE_DEFAULT}) {
27 DartType type;
28 if (element is ExecutableElement) {
29 if (element.isOperator) {
30 return null;
31 }
32 if (element is PropertyAccessorElement && element.isSetter) {
33 type = NO_RETURN_TYPE;
34 } else {
35 type = element.returnType;
36 }
37 } else if (element is VariableElement) {
38 type = element.type;
39 } else if (element is FunctionTypeAliasElement) {
40 type = element.returnType;
41 } else {
42 type = NO_RETURN_TYPE;
43 }
26 String completion = element.displayName; 44 String completion = element.displayName;
45 bool isDeprecated = element.isDeprecated;
27 CompletionSuggestion suggestion = new CompletionSuggestion( 46 CompletionSuggestion suggestion = new CompletionSuggestion(
28 CompletionSuggestionKind.INVOCATION, 47 kind,
29 element.isDeprecated ? COMPLETION_RELEVANCE_LOW : relevance, 48 isDeprecated ? COMPLETION_RELEVANCE_LOW : relevance,
30 completion, 49 completion,
31 completion.length, 50 completion.length,
32 0, 51 0,
33 element.isDeprecated, 52 isDeprecated,
34 false); 53 false);
35 54 suggestion.element = protocol.newElement_fromEngine(element);
36 suggestion.element = newElement_fromEngine(element); 55 if (element is ClassMemberElement) {
37 56 ClassElement enclosingElement = element.enclosingElement;
38 DartType type; 57 if (enclosingElement != null) {
39 if (element is ExecutableElement) { 58 suggestion.declaringType = enclosingElement.displayName;
40 type = element.returnType; 59 }
41 } else if (element is VariableElement) {
42 type = element.type;
43 } else {
44 type = NO_RETURN_TYPE;
45 } 60 }
46 suggestion.returnType = _nameForType(type); 61 suggestion.returnType = _nameForType(type);
62 if (element is ExecutableElement && element is! PropertyAccessorElement) {
63 suggestion.parameterNames = element.parameters.map(
64 (ParameterElement parameter) => parameter.name).toList();
65 suggestion.parameterTypes = element.parameters.map(
66 (ParameterElement parameter) => parameter.type.displayName).toList();
67 suggestion.requiredParameterCount = element.parameters.where(
68 (ParameterElement parameter) =>
69 parameter.parameterKind == ParameterKind.REQUIRED).length;
70 suggestion.hasNamedParameters = element.parameters.any(
71 (ParameterElement parameter) => parameter.parameterKind == ParameterKind .NAMED);
72 }
47 return suggestion; 73 return suggestion;
48 } 74 }
49 75
50 /** 76 /**
51 * Call the given function with each non-null non-empty inherited type name 77 * Call the given function with each non-null non-empty inherited type name
52 * that is defined in the given class. 78 * that is defined in the given class.
53 */ 79 */
54 visitInheritedTypeNames(ClassDeclaration node, void inherited(String name)) { 80 visitInheritedTypeNames(ClassDeclaration node, void inherited(String name)) {
55 81
56 void visit(TypeName type) { 82 void visit(TypeName type) {
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 } 168 }
143 //TODO (danrubel) include type arguments ?? 169 //TODO (danrubel) include type arguments ??
144 return name; 170 return name;
145 } 171 }
146 172
147 /** 173 /**
148 * This class visits elements in a class and provides suggestions based upon 174 * This class visits elements in a class and provides suggestions based upon
149 * the visible members in that class. Clients should call 175 * the visible members in that class. Clients should call
150 * [ClassElementSuggestionBuilder.suggestionsFor]. 176 * [ClassElementSuggestionBuilder.suggestionsFor].
151 */ 177 */
152 class ClassElementSuggestionBuilder extends _AbstractSuggestionBuilder { 178 class ClassElementSuggestionBuilder extends GeneralizingElementVisitor with
179 ElementSuggestionBuilder {
153 final bool staticOnly; 180 final bool staticOnly;
181 final DartCompletionRequest request;
154 182
155 ClassElementSuggestionBuilder(DartCompletionRequest request, bool staticOnly) 183 ClassElementSuggestionBuilder(this.request, bool staticOnly)
156 : super(request, CompletionSuggestionKind.INVOCATION), 184 : this.staticOnly = staticOnly;
157 this.staticOnly = staticOnly; 185
186 @override
187 CompletionSuggestionKind get kind => CompletionSuggestionKind.INVOCATION;
158 188
159 @override 189 @override
160 visitClassElement(ClassElement element) { 190 visitClassElement(ClassElement element) {
161 element.visitChildren(this); 191 element.visitChildren(this);
162 element.allSupertypes.forEach((InterfaceType type) { 192 element.allSupertypes.forEach((InterfaceType type) {
163 type.element.visitChildren(this); 193 type.element.visitChildren(this);
164 }); 194 });
165 } 195 }
166 196
167 @override 197 @override
168 visitElement(Element element) { 198 visitElement(Element element) {
169 // ignored 199 // ignored
170 } 200 }
171 201
172 @override 202 @override
173 visitFieldElement(FieldElement element) { 203 visitFieldElement(FieldElement element) {
174 if (staticOnly && !element.isStatic) { 204 if (staticOnly && !element.isStatic) {
175 return; 205 return;
176 } 206 }
177 _addElementSuggestion(element, element.type, element.enclosingElement); 207 addSuggestion(element);
178 } 208 }
179 209
180 @override 210 @override
181 visitMethodElement(MethodElement element) { 211 visitMethodElement(MethodElement element) {
182 if (staticOnly && !element.isStatic) { 212 if (staticOnly && !element.isStatic) {
183 return; 213 return;
184 } 214 }
185 if (element.isOperator) { 215 if (element.isOperator) {
186 return; 216 return;
187 } 217 }
188 _addElementSuggestion( 218 addSuggestion(element);
189 element,
190 element.returnType,
191 element.enclosingElement);
192 } 219 }
193 220
194 @override 221 @override
195 visitPropertyAccessorElement(PropertyAccessorElement element) { 222 visitPropertyAccessorElement(PropertyAccessorElement element) {
196 if (staticOnly && !element.isStatic) { 223 if (staticOnly && !element.isStatic) {
197 return; 224 return;
198 } 225 }
199 if (element.isGetter) { 226 addSuggestion(element);
200 _addElementSuggestion(
201 element,
202 element.returnType,
203 element.enclosingElement);
204 } else if (element.isSetter) {
205 _addElementSuggestion(element, NO_RETURN_TYPE, element.enclosingElement);
206 }
207 } 227 }
208 228
209 /** 229 /**
210 * Add suggestions for the visible members in the given class 230 * Add suggestions for the visible members in the given class
211 */ 231 */
212 static void suggestionsFor(DartCompletionRequest request, Element element, 232 static void suggestionsFor(DartCompletionRequest request, Element element,
213 {bool staticOnly: false}) { 233 {bool staticOnly: false}) {
214 if (element == DynamicElementImpl.instance) { 234 if (element == DynamicElementImpl.instance) {
215 element = request.cache.objectClassElement; 235 element = request.cache.objectClassElement;
216 } 236 }
217 if (element is ClassElement) { 237 if (element is ClassElement) {
218 return element.accept( 238 return element.accept(
219 new ClassElementSuggestionBuilder(request, staticOnly)); 239 new ClassElementSuggestionBuilder(request, staticOnly));
220 } 240 }
221 } 241 }
222 } 242 }
223 243
224 /** 244 /**
245 * Common mixin for sharing behavior
246 */
247 abstract class ElementSuggestionBuilder {
248
249 /**
250 * Internal collection of completions to prevent duplicate completions.
251 */
252 final Set<String> _completions = new Set<String>();
253
254 /**
255 * Return the kind of suggestions that should be built.
256 */
257 CompletionSuggestionKind get kind;
258
259 /**
260 * Return the request on which the builder is operating.
261 */
262 DartCompletionRequest get request;
263
264 /**
265 * Add a suggestion based upon the given element.
266 */
267 void addSuggestion(Element element) {
268 if (element.isPrivate) {
269 LibraryElement elementLibrary = element.library;
270 LibraryElement unitLibrary = request.unit.element.library;
271 if (elementLibrary != unitLibrary) {
272 return;
273 }
274 }
275 if (element.isSynthetic) {
276 if (element is PropertyAccessorElement || element is FieldElement) {
277 return;
278 }
279 }
280 String completion = element.displayName;
281 if (completion == null ||
282 completion.length <= 0 ||
283 !_completions.add(completion)) {
284 return;
285 }
286 CompletionSuggestion suggestion = createSuggestion(element, kind: kind);
287 if (suggestion != null) {
288 request.suggestions.add(suggestion);
289 }
290 }
291 }
292
293 /**
225 * This class visits elements in a library and provides suggestions based upon 294 * This class visits elements in a library and provides suggestions based upon
226 * the visible members in that library. Clients should call 295 * the visible members in that library. Clients should call
227 * [LibraryElementSuggestionBuilder.suggestionsFor]. 296 * [LibraryElementSuggestionBuilder.suggestionsFor].
228 */ 297 */
229 class LibraryElementSuggestionBuilder extends _AbstractSuggestionBuilder { 298 class LibraryElementSuggestionBuilder extends GeneralizingElementVisitor with
299 ElementSuggestionBuilder {
300 final DartCompletionRequest request;
301 final CompletionSuggestionKind kind;
230 302
231 LibraryElementSuggestionBuilder(DartCompletionRequest request, 303 LibraryElementSuggestionBuilder(this.request, this.kind);
232 CompletionSuggestionKind kind)
233 : super(request, kind);
234 304
235 @override 305 @override
236 visitClassElement(ClassElement element) { 306 visitClassElement(ClassElement element) {
237 _addElementSuggestion(element, NO_RETURN_TYPE, null); 307 addSuggestion(element);
238 } 308 }
239 309
240 @override 310 @override
241 visitCompilationUnitElement(CompilationUnitElement element) { 311 visitCompilationUnitElement(CompilationUnitElement element) {
242 element.visitChildren(this); 312 element.visitChildren(this);
243 } 313 }
244 314
245 @override 315 @override
246 visitElement(Element element) { 316 visitElement(Element element) {
247 // ignored 317 // ignored
248 } 318 }
249 319
250 @override 320 @override
251 visitFunctionElement(FunctionElement element) { 321 visitFunctionElement(FunctionElement element) {
252 _addElementSuggestion(element, element.returnType, null); 322 addSuggestion(element);
253 } 323 }
254 324
255 @override 325 @override
256 visitFunctionTypeAliasElement(FunctionTypeAliasElement element) { 326 visitFunctionTypeAliasElement(FunctionTypeAliasElement element) {
257 _addElementSuggestion(element, element.returnType, null); 327 addSuggestion(element);
258 } 328 }
259 329
260 @override 330 @override
261 visitTopLevelVariableElement(TopLevelVariableElement element) { 331 visitTopLevelVariableElement(TopLevelVariableElement element) {
262 _addElementSuggestion(element, element.type, null); 332 addSuggestion(element);
263 } 333 }
264 334
265 /** 335 /**
266 * Add suggestions for the visible members in the given library 336 * Add suggestions for the visible members in the given library
267 */ 337 */
268 static void suggestionsFor(DartCompletionRequest request, 338 static void suggestionsFor(DartCompletionRequest request,
269 CompletionSuggestionKind kind, LibraryElement library) { 339 CompletionSuggestionKind kind, LibraryElement library) {
270 if (library != null) { 340 if (library != null) {
271 library.visitChildren(new LibraryElementSuggestionBuilder(request, kind)); 341 library.visitChildren(new LibraryElementSuggestionBuilder(request, kind));
272 } 342 }
273 } 343 }
274 } 344 }
275 345
276 /** 346 /**
277 * This class visits elements in a class and provides suggestions based upon 347 * This class visits elements in a class and provides suggestions based upon
278 * the visible named constructors in that class. 348 * the visible named constructors in that class.
279 */ 349 */
280 class NamedConstructorSuggestionBuilder extends _AbstractSuggestionBuilder 350 class NamedConstructorSuggestionBuilder extends GeneralizingElementVisitor with
281 implements SuggestionBuilder { 351 ElementSuggestionBuilder implements SuggestionBuilder {
352 final DartCompletionRequest request;
282 353
283 NamedConstructorSuggestionBuilder(DartCompletionRequest request) 354 NamedConstructorSuggestionBuilder(this.request);
284 : super(request, CompletionSuggestionKind.INVOCATION); 355
356 @override
357 CompletionSuggestionKind get kind => CompletionSuggestionKind.INVOCATION;
285 358
286 @override 359 @override
287 bool computeFast(AstNode node) { 360 bool computeFast(AstNode node) {
288 return false; 361 return false;
289 } 362 }
290 363
291 @override 364 @override
292 Future<bool> computeFull(AstNode node) { 365 Future<bool> computeFull(AstNode node) {
293 if (node is SimpleIdentifier) { 366 if (node is SimpleIdentifier) {
294 node = node.parent; 367 node = node.parent;
(...skipping 13 matching lines...) Expand all
308 return new Future.value(false); 381 return new Future.value(false);
309 } 382 }
310 383
311 @override 384 @override
312 visitClassElement(ClassElement element) { 385 visitClassElement(ClassElement element) {
313 element.visitChildren(this); 386 element.visitChildren(this);
314 } 387 }
315 388
316 @override 389 @override
317 visitConstructorElement(ConstructorElement element) { 390 visitConstructorElement(ConstructorElement element) {
318 _addElementSuggestion( 391 addSuggestion(element);
319 element,
320 element.returnType,
321 element.enclosingElement);
322 } 392 }
323 393
324 @override 394 @override
325 visitElement(Element element) { 395 visitElement(Element element) {
326 // ignored 396 // ignored
327 } 397 }
328 } 398 }
399
329 /** 400 /**
330 * Common interface implemented by suggestion builders. 401 * Common interface implemented by suggestion builders.
331 */ 402 */
332 abstract class SuggestionBuilder { 403 abstract class SuggestionBuilder {
333 /** 404 /**
334 * Compute suggestions and return `true` if building is complete, 405 * Compute suggestions and return `true` if building is complete,
335 * or `false` if [computeFull] should be called. 406 * or `false` if [computeFull] should be called.
336 */ 407 */
337 bool computeFast(AstNode node); 408 bool computeFast(AstNode node);
338 409
339 /** 410 /**
340 * Return a future that computes the suggestions given a fully resolved AST. 411 * Return a future that computes the suggestions given a fully resolved AST.
341 * The future returns `true` if suggestions were added, else `false`. 412 * The future returns `true` if suggestions were added, else `false`.
342 */ 413 */
343 Future<bool> computeFull(AstNode node); 414 Future<bool> computeFull(AstNode node);
344 } 415 }
345 416
346 /**
347 * Common superclass for sharing behavior
348 */
349 class _AbstractSuggestionBuilder extends GeneralizingElementVisitor {
350 final DartCompletionRequest request;
351 final CompletionSuggestionKind kind;
352 final Set<String> _completions = new Set<String>();
353
354 _AbstractSuggestionBuilder(this.request, this.kind);
355
356 /**
357 * Add a suggestion based upon the given element.
358 */
359 void _addElementSuggestion(Element element, DartType type,
360 ClassElement enclosingElement) {
361 if (element.isSynthetic) {
362 return;
363 }
364 if (element.isPrivate) {
365 LibraryElement elementLibrary = element.library;
366 LibraryElement unitLibrary = request.unit.element.library;
367 if (elementLibrary != unitLibrary) {
368 return;
369 }
370 }
371 String completion = element.displayName;
372 if (completion == null ||
373 completion.length <= 0 ||
374 !_completions.add(completion)) {
375 return;
376 }
377 bool isDeprecated = element.isDeprecated;
378 CompletionSuggestion suggestion = new CompletionSuggestion(
379 kind,
380 isDeprecated ? COMPLETION_RELEVANCE_LOW : COMPLETION_RELEVANCE_DEFAULT,
381 completion,
382 completion.length,
383 0,
384 isDeprecated,
385 false);
386 suggestion.element = protocol.newElement_fromEngine(element);
387 if (enclosingElement != null) {
388 suggestion.declaringType = enclosingElement.displayName;
389 }
390 suggestion.returnType = _nameForType(type);
391 if (element is ExecutableElement && element is! PropertyAccessorElement) {
392 suggestion.parameterNames = element.parameters.map(
393 (ParameterElement parameter) => parameter.name).toList();
394 suggestion.parameterTypes = element.parameters.map(
395 (ParameterElement parameter) => parameter.type.displayName).toList();
396 suggestion.requiredParameterCount = element.parameters.where(
397 (ParameterElement parameter) =>
398 parameter.parameterKind == ParameterKind.REQUIRED).length;
399 suggestion.hasNamedParameters = element.parameters.any(
400 (ParameterElement parameter) => parameter.parameterKind == ParameterKi nd.NAMED);
401 }
402 request.suggestions.add(suggestion);
403 }
404 }
405
406 class _NoReturnType extends DartType { 417 class _NoReturnType extends DartType {
407 418
408 @override 419 @override
409 String get displayName => name; 420 String get displayName => name;
410 421
411 @override 422 @override
412 Element get element => null; 423 Element get element => null;
413 424
414 @override 425 @override
415 bool get isBottom => false; 426 bool get isBottom => false;
(...skipping 29 matching lines...) Expand all
445 bool isSubtypeOf(DartType type) => false; 456 bool isSubtypeOf(DartType type) => false;
446 457
447 @override 458 @override
448 bool isSupertypeOf(DartType type) => false; 459 bool isSupertypeOf(DartType type) => false;
449 460
450 @override 461 @override
451 DartType substitute2(List<DartType> argumentTypes, 462 DartType substitute2(List<DartType> argumentTypes,
452 List<DartType> parameterTypes) => 463 List<DartType> parameterTypes) =>
453 this; 464 this;
454 } 465 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698