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

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

Issue 791553007: suggest fields rather than synthetic getters (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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';
15 import 'package:analyzer/src/generated/utilities_dart.dart'; 16 import 'package:analyzer/src/generated/utilities_dart.dart';
16 17
18 final DYNAMIC = 'dynamic';
19 final DartType NO_RETURN_TYPE = new _NoReturnType();
Paul Berry 2015/01/12 17:29:20 _LocalVisitor (pkg/analysis_server/lib/src/service
danrubel 2015/01/12 19:01:13 That is definitely my long term intent, but these
Paul Berry 2015/01/12 19:02:55 Ah, ok. I understand now. In that case, lgtm as
20
17 /** 21 /**
18 * Create a suggestion based upon the given imported element. 22 * Create a suggestion based upon the given imported element.
19 */ 23 */
20 CompletionSuggestion createElementSuggestion(Element element, 24 CompletionSuggestion createElementSuggestion(Element element, {int relevance:
21 {int relevance: COMPLETION_RELEVANCE_DEFAULT}) { 25 COMPLETION_RELEVANCE_DEFAULT}) {
22 String completion = element.displayName; 26 String completion = element.displayName;
23 CompletionSuggestion suggestion = new CompletionSuggestion( 27 CompletionSuggestion suggestion = new CompletionSuggestion(
24 CompletionSuggestionKind.INVOCATION, 28 CompletionSuggestionKind.INVOCATION,
25 element.isDeprecated ? COMPLETION_RELEVANCE_LOW : relevance, 29 element.isDeprecated ? COMPLETION_RELEVANCE_LOW : relevance,
26 completion, 30 completion,
27 completion.length, 31 completion.length,
28 0, 32 0,
29 element.isDeprecated, 33 element.isDeprecated,
30 false); 34 false);
31 35
32 suggestion.element = newElement_fromEngine(element); 36 suggestion.element = newElement_fromEngine(element);
33 37
34 DartType type; 38 DartType type;
35 if (element is FunctionElement) { 39 if (element is ExecutableElement) {
36 type = element.returnType; 40 type = element.returnType;
37 } else if (element is PropertyAccessorElement && element.isGetter) { 41 } else if (element is VariableElement) {
38 type = element.returnType;
39 } else if (element is TopLevelVariableElement) {
40 type = element.type; 42 type = element.type;
43 } else {
44 type = NO_RETURN_TYPE;
41 } 45 }
42 if (type != null) { 46 suggestion.returnType = _nameForType(type);
43 String name = type.displayName;
44 if (name != null && name.length > 0 && name != 'dynamic') {
45 suggestion.returnType = name;
46 }
47 }
48 return suggestion; 47 return suggestion;
49 } 48 }
50 49
51 /** 50 /**
52 * Call the given function with each non-null non-empty inherited type name 51 * Call the given function with each non-null non-empty inherited type name
53 * that is defined in the given class. 52 * that is defined in the given class.
54 */ 53 */
55 visitInheritedTypeNames(ClassDeclaration node, void inherited(String name)) { 54 visitInheritedTypeNames(ClassDeclaration node, void inherited(String name)) {
56 55
57 void visit(TypeName type) { 56 void visit(TypeName type) {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 todo.add(classNode); 120 todo.add(classNode);
122 } else { 121 } else {
123 imported(name); 122 imported(name);
124 } 123 }
125 } 124 }
126 }); 125 });
127 } 126 }
128 } 127 }
129 128
130 /** 129 /**
130 * Return the name for the given type.
131 */
132 String _nameForType(DartType type) {
133 if (type == NO_RETURN_TYPE) {
134 return null;
135 }
136 if (type == null) {
137 return DYNAMIC;
138 }
139 String name = type.displayName;
140 if (name == null || name.length <= 0) {
141 return DYNAMIC;
142 }
143 //TODO (danrubel) include type arguments ??
144 return name;
145 }
146
147 /**
131 * This class visits elements in a class and provides suggestions based upon 148 * This class visits elements in a class and provides suggestions based upon
132 * the visible members in that class. Clients should call 149 * the visible members in that class. Clients should call
133 * [ClassElementSuggestionBuilder.suggestionsFor]. 150 * [ClassElementSuggestionBuilder.suggestionsFor].
134 */ 151 */
135 class ClassElementSuggestionBuilder extends _AbstractSuggestionBuilder { 152 class ClassElementSuggestionBuilder extends _AbstractSuggestionBuilder {
136 final bool staticOnly; 153 final bool staticOnly;
137 154
138 ClassElementSuggestionBuilder(DartCompletionRequest request, bool staticOnly) 155 ClassElementSuggestionBuilder(DartCompletionRequest request, bool staticOnly)
139 : super(request, CompletionSuggestionKind.INVOCATION), 156 : super(request, CompletionSuggestionKind.INVOCATION),
140 this.staticOnly = staticOnly; 157 this.staticOnly = staticOnly;
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 visitPropertyAccessorElement(PropertyAccessorElement element) { 195 visitPropertyAccessorElement(PropertyAccessorElement element) {
179 if (staticOnly && !element.isStatic) { 196 if (staticOnly && !element.isStatic) {
180 return; 197 return;
181 } 198 }
182 if (element.isGetter) { 199 if (element.isGetter) {
183 _addElementSuggestion( 200 _addElementSuggestion(
184 element, 201 element,
185 element.returnType, 202 element.returnType,
186 element.enclosingElement); 203 element.enclosingElement);
187 } else if (element.isSetter) { 204 } else if (element.isSetter) {
188 _addElementSuggestion( 205 _addElementSuggestion(element, NO_RETURN_TYPE, element.enclosingElement);
189 element,
190 element.returnType,
191 element.enclosingElement);
192 } 206 }
193 } 207 }
194 208
195 /** 209 /**
196 * Add suggestions for the visible members in the given class 210 * Add suggestions for the visible members in the given class
197 */ 211 */
198 static void suggestionsFor(DartCompletionRequest request, Element element, 212 static void suggestionsFor(DartCompletionRequest request, Element element,
199 {bool staticOnly: false}) { 213 {bool staticOnly: false}) {
200 if (element == DynamicElementImpl.instance) { 214 if (element == DynamicElementImpl.instance) {
201 element = request.cache.objectClassElement; 215 element = request.cache.objectClassElement;
(...skipping 11 matching lines...) Expand all
213 * [LibraryElementSuggestionBuilder.suggestionsFor]. 227 * [LibraryElementSuggestionBuilder.suggestionsFor].
214 */ 228 */
215 class LibraryElementSuggestionBuilder extends _AbstractSuggestionBuilder { 229 class LibraryElementSuggestionBuilder extends _AbstractSuggestionBuilder {
216 230
217 LibraryElementSuggestionBuilder(DartCompletionRequest request, 231 LibraryElementSuggestionBuilder(DartCompletionRequest request,
218 CompletionSuggestionKind kind) 232 CompletionSuggestionKind kind)
219 : super(request, kind); 233 : super(request, kind);
220 234
221 @override 235 @override
222 visitClassElement(ClassElement element) { 236 visitClassElement(ClassElement element) {
223 _addElementSuggestion(element, null, null); 237 _addElementSuggestion(element, NO_RETURN_TYPE, null);
224 } 238 }
225 239
226 @override 240 @override
227 visitCompilationUnitElement(CompilationUnitElement element) { 241 visitCompilationUnitElement(CompilationUnitElement element) {
228 element.visitChildren(this); 242 element.visitChildren(this);
229 } 243 }
230 244
231 @override 245 @override
232 visitElement(Element element) { 246 visitElement(Element element) {
233 // ignored 247 // ignored
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 element, 319 element,
306 element.returnType, 320 element.returnType,
307 element.enclosingElement); 321 element.enclosingElement);
308 } 322 }
309 323
310 @override 324 @override
311 visitElement(Element element) { 325 visitElement(Element element) {
312 // ignored 326 // ignored
313 } 327 }
314 } 328 }
315
316 /** 329 /**
317 * Common interface implemented by suggestion builders. 330 * Common interface implemented by suggestion builders.
318 */ 331 */
319 abstract class SuggestionBuilder { 332 abstract class SuggestionBuilder {
320 /** 333 /**
321 * Compute suggestions and return `true` if building is complete, 334 * Compute suggestions and return `true` if building is complete,
322 * or `false` if [computeFull] should be called. 335 * or `false` if [computeFull] should be called.
323 */ 336 */
324 bool computeFast(AstNode node); 337 bool computeFast(AstNode node);
325 338
326 /** 339 /**
327 * Return a future that computes the suggestions given a fully resolved AST. 340 * Return a future that computes the suggestions given a fully resolved AST.
328 * The future returns `true` if suggestions were added, else `false`. 341 * The future returns `true` if suggestions were added, else `false`.
329 */ 342 */
330 Future<bool> computeFull(AstNode node); 343 Future<bool> computeFull(AstNode node);
331 } 344 }
332 345
333 /** 346 /**
334 * Common superclass for sharing behavior 347 * Common superclass for sharing behavior
335 */ 348 */
336 class _AbstractSuggestionBuilder extends GeneralizingElementVisitor { 349 class _AbstractSuggestionBuilder extends GeneralizingElementVisitor {
337 final DartCompletionRequest request; 350 final DartCompletionRequest request;
338 final CompletionSuggestionKind kind; 351 final CompletionSuggestionKind kind;
339 final Set<String> _completions = new Set<String>(); 352 final Set<String> _completions = new Set<String>();
340 353
341 _AbstractSuggestionBuilder(this.request, this.kind); 354 _AbstractSuggestionBuilder(this.request, this.kind);
342 355
356 /**
357 * Add a suggestion based upon the given element.
358 */
343 void _addElementSuggestion(Element element, DartType type, 359 void _addElementSuggestion(Element element, DartType type,
344 ClassElement enclosingElement) { 360 ClassElement enclosingElement) {
345 if (element.isSynthetic) { 361 if (element.isSynthetic) {
346 return; 362 return;
347 } 363 }
348 if (element.isPrivate) { 364 if (element.isPrivate) {
349 LibraryElement elementLibrary = element.library; 365 LibraryElement elementLibrary = element.library;
350 LibraryElement unitLibrary = request.unit.element.library; 366 LibraryElement unitLibrary = request.unit.element.library;
351 if (elementLibrary != unitLibrary) { 367 if (elementLibrary != unitLibrary) {
352 return; 368 return;
353 } 369 }
354 } 370 }
355 String completion = element.displayName; 371 String completion = element.displayName;
356 if (completion == null || 372 if (completion == null ||
357 completion.length <= 0 || 373 completion.length <= 0 ||
358 !_completions.add(completion)) { 374 !_completions.add(completion)) {
359 return; 375 return;
360 } 376 }
361 bool isDeprecated = element.isDeprecated; 377 bool isDeprecated = element.isDeprecated;
362 CompletionSuggestion suggestion = new CompletionSuggestion( 378 CompletionSuggestion suggestion = new CompletionSuggestion(
363 kind, 379 kind,
364 isDeprecated ? COMPLETION_RELEVANCE_LOW : COMPLETION_RELEVANCE_DEFAULT, 380 isDeprecated ? COMPLETION_RELEVANCE_LOW : COMPLETION_RELEVANCE_DEFAULT,
365 completion, 381 completion,
366 completion.length, 382 completion.length,
367 0, 383 0,
368 isDeprecated, 384 isDeprecated,
369 false); 385 false);
370 suggestion.element = protocol.newElement_fromEngine(element); 386 suggestion.element = protocol.newElement_fromEngine(element);
371 if (suggestion.element != null) {
372 if (element is FieldElement) {
373 suggestion.element.kind = protocol.ElementKind.GETTER;
374 suggestion.element.returnType =
375 element.type != null ? element.type.displayName : 'dynamic';
376 }
377 }
378 if (enclosingElement != null) { 387 if (enclosingElement != null) {
379 suggestion.declaringType = enclosingElement.displayName; 388 suggestion.declaringType = enclosingElement.displayName;
380 } 389 }
381 if (type != null) { 390 suggestion.returnType = _nameForType(type);
382 String typeName = type.displayName;
383 if (typeName != null && typeName.length > 0 && typeName != 'dynamic') {
384 suggestion.returnType = typeName;
385 }
386 }
387 if (element is ExecutableElement && element is! PropertyAccessorElement) { 391 if (element is ExecutableElement && element is! PropertyAccessorElement) {
388 suggestion.parameterNames = element.parameters.map( 392 suggestion.parameterNames = element.parameters.map(
389 (ParameterElement parameter) => parameter.name).toList(); 393 (ParameterElement parameter) => parameter.name).toList();
390 suggestion.parameterTypes = element.parameters.map( 394 suggestion.parameterTypes = element.parameters.map(
391 (ParameterElement parameter) => parameter.type.displayName).toList(); 395 (ParameterElement parameter) => parameter.type.displayName).toList();
392 suggestion.requiredParameterCount = element.parameters.where( 396 suggestion.requiredParameterCount = element.parameters.where(
393 (ParameterElement parameter) => 397 (ParameterElement parameter) =>
394 parameter.parameterKind == ParameterKind.REQUIRED).length; 398 parameter.parameterKind == ParameterKind.REQUIRED).length;
395 suggestion.hasNamedParameters = element.parameters.any( 399 suggestion.hasNamedParameters = element.parameters.any(
396 (ParameterElement parameter) => parameter.parameterKind == ParameterKi nd.NAMED); 400 (ParameterElement parameter) => parameter.parameterKind == ParameterKi nd.NAMED);
397 } 401 }
398 request.suggestions.add(suggestion); 402 request.suggestions.add(suggestion);
399 } 403 }
400 } 404 }
405
406 class _NoReturnType extends DartType {
407
408 @override
409 String get displayName => name;
410
411 @override
412 Element get element => null;
413
414 @override
415 bool get isBottom => false;
416
417 @override
418 bool get isDartCoreFunction => false;
419
420 @override
421 bool get isDynamic => false;
422
423 @override
424 bool get isObject => false;
425
426 @override
427 bool get isUndefined => false;
428
429 @override
430 bool get isVoid => false;
431
432 @override
433 String get name => 'NoReturnType';
434
435 @override
436 DartType getLeastUpperBound(DartType type) => this;
437
438 @override
439 bool isAssignableTo(DartType type) => type is _NoReturnType;
440
441 @override
442 bool isMoreSpecificThan(DartType type) => false;
443
444 @override
445 bool isSubtypeOf(DartType type) => false;
446
447 @override
448 bool isSupertypeOf(DartType type) => false;
449
450 @override
451 DartType substitute2(List<DartType> argumentTypes,
452 List<DartType> parameterTypes) =>
453 this;
454 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698