| OLD | NEW |
| 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(); |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |