| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library services.completion.contributor.dart.local; | |
| 6 | |
| 7 import 'dart:async'; | |
| 8 | |
| 9 import 'package:analysis_server/src/protocol.dart' as protocol | |
| 10 show Element, ElementKind; | |
| 11 import 'package:analysis_server/src/protocol.dart' hide Element, ElementKind; | |
| 12 import 'package:analysis_server/src/services/completion/dart_completion_manager.
dart'; | |
| 13 import 'package:analysis_server/src/services/completion/local_declaration_visito
r.dart'; | |
| 14 import 'package:analysis_server/src/services/completion/optype.dart'; | |
| 15 import 'package:analyzer/src/generated/ast.dart'; | |
| 16 import 'package:analyzer/src/generated/scanner.dart'; | |
| 17 import 'package:analyzer/src/generated/utilities_dart.dart'; | |
| 18 | |
| 19 const _DYNAMIC = 'dynamic'; | |
| 20 | |
| 21 final TypeName _NO_RETURN_TYPE = new TypeName( | |
| 22 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, '', 0)), null); | |
| 23 | |
| 24 /** | |
| 25 * Create a new protocol Element for inclusion in a completion suggestion. | |
| 26 */ | |
| 27 protocol.Element _createElement(protocol.ElementKind kind, SimpleIdentifier id, | |
| 28 {String parameters, TypeName returnType, bool isAbstract: false, | |
| 29 bool isDeprecated: false}) { | |
| 30 String name = id != null ? id.name : ''; | |
| 31 int flags = protocol.Element.makeFlags( | |
| 32 isAbstract: isAbstract, | |
| 33 isDeprecated: isDeprecated, | |
| 34 isPrivate: Identifier.isPrivateName(name)); | |
| 35 return new protocol.Element(kind, name, flags, | |
| 36 parameters: parameters, returnType: _nameForType(returnType)); | |
| 37 } | |
| 38 | |
| 39 /** | |
| 40 * Return `true` if the @deprecated annotation is present | |
| 41 */ | |
| 42 bool _isDeprecated(AnnotatedNode node) { | |
| 43 if (node != null) { | |
| 44 NodeList<Annotation> metadata = node.metadata; | |
| 45 if (metadata != null) { | |
| 46 return metadata.any((Annotation a) { | |
| 47 return a.name is SimpleIdentifier && a.name.name == 'deprecated'; | |
| 48 }); | |
| 49 } | |
| 50 } | |
| 51 return false; | |
| 52 } | |
| 53 | |
| 54 /** | |
| 55 * Return the name for the given type. | |
| 56 */ | |
| 57 String _nameForType(TypeName type) { | |
| 58 if (type == _NO_RETURN_TYPE) { | |
| 59 return null; | |
| 60 } | |
| 61 if (type == null) { | |
| 62 return _DYNAMIC; | |
| 63 } | |
| 64 Identifier id = type.name; | |
| 65 if (id == null) { | |
| 66 return _DYNAMIC; | |
| 67 } | |
| 68 String name = id.name; | |
| 69 if (name == null || name.length <= 0) { | |
| 70 return _DYNAMIC; | |
| 71 } | |
| 72 TypeArgumentList typeArgs = type.typeArguments; | |
| 73 if (typeArgs != null) { | |
| 74 //TODO (danrubel) include type arguments | |
| 75 } | |
| 76 return name; | |
| 77 } | |
| 78 | |
| 79 /** | |
| 80 * A contributor for calculating `completion.getSuggestions` request results | |
| 81 * for the local library in which the completion is requested. | |
| 82 */ | |
| 83 class LocalReferenceContributor extends DartCompletionContributor { | |
| 84 @override | |
| 85 bool computeFast(DartCompletionRequest request) { | |
| 86 OpType optype = request.optype; | |
| 87 | |
| 88 // Collect suggestions from the specific child [AstNode] that contains | |
| 89 // the completion offset and all of its parents recursively. | |
| 90 if (optype.includeReturnValueSuggestions || | |
| 91 optype.includeTypeNameSuggestions || | |
| 92 optype.includeVoidReturnSuggestions) { | |
| 93 _LocalVisitor localVisitor = | |
| 94 new _LocalVisitor(request, request.offset, optype); | |
| 95 localVisitor.visit(request.target.containingNode); | |
| 96 } | |
| 97 if (optype.includeStatementLabelSuggestions || | |
| 98 optype.includeCaseLabelSuggestions) { | |
| 99 _LabelVisitor labelVisitor = new _LabelVisitor(request, | |
| 100 optype.includeStatementLabelSuggestions, | |
| 101 optype.includeCaseLabelSuggestions); | |
| 102 labelVisitor.visit(request.target.containingNode); | |
| 103 } | |
| 104 if (optype.includeConstructorSuggestions) { | |
| 105 new _ConstructorVisitor(request).visit(request.target.containingNode); | |
| 106 } | |
| 107 | |
| 108 // If target is an argument in an argument list | |
| 109 // then suggestions may need to be adjusted | |
| 110 return request.target.argIndex == null; | |
| 111 } | |
| 112 | |
| 113 @override | |
| 114 Future<bool> computeFull(DartCompletionRequest request) { | |
| 115 _updateSuggestions(request); | |
| 116 return new Future.value(false); | |
| 117 } | |
| 118 | |
| 119 /** | |
| 120 * If target is a function argument, suggest identifiers not invocations | |
| 121 */ | |
| 122 void _updateSuggestions(DartCompletionRequest request) { | |
| 123 if (request.target.isFunctionalArgument()) { | |
| 124 request.convertInvocationsToIdentifiers(); | |
| 125 } | |
| 126 } | |
| 127 } | |
| 128 | |
| 129 /** | |
| 130 * A visitor for collecting constructor suggestions. | |
| 131 */ | |
| 132 class _ConstructorVisitor extends LocalDeclarationVisitor { | |
| 133 final DartCompletionRequest request; | |
| 134 | |
| 135 _ConstructorVisitor(DartCompletionRequest request) | |
| 136 : super(request.offset), | |
| 137 request = request; | |
| 138 | |
| 139 @override | |
| 140 void declaredClass(ClassDeclaration declaration) { | |
| 141 bool found = false; | |
| 142 for (ClassMember member in declaration.members) { | |
| 143 if (member is ConstructorDeclaration) { | |
| 144 found = true; | |
| 145 _addSuggestion(declaration, member); | |
| 146 } | |
| 147 } | |
| 148 if (!found) { | |
| 149 _addSuggestion(declaration, null); | |
| 150 } | |
| 151 } | |
| 152 | |
| 153 @override | |
| 154 void declaredClassTypeAlias(ClassTypeAlias declaration) { | |
| 155 // TODO: implement declaredClassTypeAlias | |
| 156 } | |
| 157 | |
| 158 @override | |
| 159 void declaredField(FieldDeclaration fieldDecl, VariableDeclaration varDecl) { | |
| 160 // TODO: implement declaredField | |
| 161 } | |
| 162 | |
| 163 @override | |
| 164 void declaredFunction(FunctionDeclaration declaration) { | |
| 165 // TODO: implement declaredFunction | |
| 166 } | |
| 167 | |
| 168 @override | |
| 169 void declaredFunctionTypeAlias(FunctionTypeAlias declaration) { | |
| 170 // TODO: implement declaredFunctionTypeAlias | |
| 171 } | |
| 172 | |
| 173 @override | |
| 174 void declaredLabel(Label label, bool isCaseLabel) { | |
| 175 // TODO: implement declaredLabel | |
| 176 } | |
| 177 | |
| 178 @override | |
| 179 void declaredLocalVar(SimpleIdentifier name, TypeName type) { | |
| 180 // TODO: implement declaredLocalVar | |
| 181 } | |
| 182 | |
| 183 @override | |
| 184 void declaredMethod(MethodDeclaration declaration) { | |
| 185 // TODO: implement declaredMethod | |
| 186 } | |
| 187 | |
| 188 @override | |
| 189 void declaredParam(SimpleIdentifier name, TypeName type) { | |
| 190 // TODO: implement declaredParam | |
| 191 } | |
| 192 | |
| 193 @override | |
| 194 void declaredTopLevelVar( | |
| 195 VariableDeclarationList varList, VariableDeclaration varDecl) { | |
| 196 // TODO: implement declaredTopLevelVar | |
| 197 } | |
| 198 | |
| 199 /** | |
| 200 * For the given class and constructor, | |
| 201 * add a suggestion of the form B(...) or B.name(...). | |
| 202 * If the given constructor is `null` | |
| 203 * then add a default constructor suggestion. | |
| 204 */ | |
| 205 CompletionSuggestion _addSuggestion( | |
| 206 ClassDeclaration classDecl, ConstructorDeclaration constructorDecl) { | |
| 207 SimpleIdentifier elemId; | |
| 208 String completion = classDecl.name.name; | |
| 209 if (constructorDecl != null) { | |
| 210 elemId = constructorDecl.name; | |
| 211 if (elemId != null) { | |
| 212 String name = elemId.name; | |
| 213 if (name != null && name.length > 0) { | |
| 214 completion = '$completion.$name'; | |
| 215 } | |
| 216 } | |
| 217 } | |
| 218 bool isDeprecated = | |
| 219 constructorDecl != null && _isDeprecated(constructorDecl); | |
| 220 List<String> parameterNames = new List<String>(); | |
| 221 List<String> parameterTypes = new List<String>(); | |
| 222 int requiredParameterCount = 0; | |
| 223 bool hasNamedParameters = false; | |
| 224 StringBuffer paramBuf = new StringBuffer(); | |
| 225 paramBuf.write('('); | |
| 226 int paramCount = 0; | |
| 227 if (constructorDecl != null) { | |
| 228 for (FormalParameter param in constructorDecl.parameters.parameters) { | |
| 229 if (paramCount > 0) { | |
| 230 paramBuf.write(', '); | |
| 231 } | |
| 232 String paramName; | |
| 233 String typeName; | |
| 234 if (param is NormalFormalParameter) { | |
| 235 paramName = param.identifier.name; | |
| 236 typeName = _nameForParamType(param); | |
| 237 ++requiredParameterCount; | |
| 238 } else if (param is DefaultFormalParameter) { | |
| 239 NormalFormalParameter childParam = param.parameter; | |
| 240 paramName = childParam.identifier.name; | |
| 241 typeName = _nameForParamType(childParam); | |
| 242 if (param.kind == ParameterKind.NAMED) { | |
| 243 hasNamedParameters = true; | |
| 244 } | |
| 245 if (paramCount == requiredParameterCount) { | |
| 246 paramBuf.write(hasNamedParameters ? '{' : '['); | |
| 247 } | |
| 248 } | |
| 249 parameterNames.add(paramName); | |
| 250 parameterTypes.add(typeName); | |
| 251 paramBuf.write(typeName); | |
| 252 paramBuf.write(' '); | |
| 253 paramBuf.write(paramName); | |
| 254 ++paramCount; | |
| 255 } | |
| 256 } | |
| 257 if (paramCount > requiredParameterCount) { | |
| 258 paramBuf.write(hasNamedParameters ? '}' : ']'); | |
| 259 } | |
| 260 paramBuf.write(')'); | |
| 261 protocol.Element element = _createElement( | |
| 262 protocol.ElementKind.CONSTRUCTOR, elemId, | |
| 263 parameters: paramBuf.toString()); | |
| 264 element.returnType = classDecl.name.name; | |
| 265 CompletionSuggestion suggestion = new CompletionSuggestion( | |
| 266 CompletionSuggestionKind.INVOCATION, | |
| 267 isDeprecated ? DART_RELEVANCE_LOW : DART_RELEVANCE_DEFAULT, completion, | |
| 268 completion.length, 0, isDeprecated, false, | |
| 269 declaringType: classDecl.name.name, | |
| 270 element: element, | |
| 271 parameterNames: parameterNames, | |
| 272 parameterTypes: parameterTypes, | |
| 273 requiredParameterCount: requiredParameterCount, | |
| 274 hasNamedParameters: hasNamedParameters); | |
| 275 request.addSuggestion(suggestion); | |
| 276 return suggestion; | |
| 277 } | |
| 278 | |
| 279 /** | |
| 280 * Determine the name of the type for the given constructor parameter. | |
| 281 */ | |
| 282 String _nameForParamType(NormalFormalParameter param) { | |
| 283 if (param is SimpleFormalParameter) { | |
| 284 return _nameForType(param.type); | |
| 285 } | |
| 286 SimpleIdentifier id = param.identifier; | |
| 287 if (param is FieldFormalParameter && id != null) { | |
| 288 String fieldName = id.name; | |
| 289 AstNode classDecl = param.getAncestor((p) => p is ClassDeclaration); | |
| 290 if (classDecl is ClassDeclaration) { | |
| 291 for (ClassMember member in classDecl.members) { | |
| 292 if (member is FieldDeclaration) { | |
| 293 for (VariableDeclaration field in member.fields.variables) { | |
| 294 if (field.name.name == fieldName) { | |
| 295 return _nameForType(member.fields.type); | |
| 296 } | |
| 297 } | |
| 298 } | |
| 299 } | |
| 300 } | |
| 301 } | |
| 302 return _DYNAMIC; | |
| 303 } | |
| 304 } | |
| 305 | |
| 306 /** | |
| 307 * A visitor for collecting suggestions for break and continue labels. | |
| 308 */ | |
| 309 class _LabelVisitor extends LocalDeclarationVisitor { | |
| 310 final DartCompletionRequest request; | |
| 311 | |
| 312 /** | |
| 313 * True if statement labels should be included as suggestions. | |
| 314 */ | |
| 315 final bool includeStatementLabels; | |
| 316 | |
| 317 /** | |
| 318 * True if case labels should be included as suggestions. | |
| 319 */ | |
| 320 final bool includeCaseLabels; | |
| 321 | |
| 322 _LabelVisitor(DartCompletionRequest request, this.includeStatementLabels, | |
| 323 this.includeCaseLabels) | |
| 324 : super(request.offset), | |
| 325 request = request; | |
| 326 | |
| 327 @override | |
| 328 void declaredClass(ClassDeclaration declaration) { | |
| 329 // ignored | |
| 330 } | |
| 331 | |
| 332 @override | |
| 333 void declaredClassTypeAlias(ClassTypeAlias declaration) { | |
| 334 // ignored | |
| 335 } | |
| 336 | |
| 337 @override | |
| 338 void declaredField(FieldDeclaration fieldDecl, VariableDeclaration varDecl) { | |
| 339 // ignored | |
| 340 } | |
| 341 | |
| 342 @override | |
| 343 void declaredFunction(FunctionDeclaration declaration) { | |
| 344 // ignored | |
| 345 } | |
| 346 | |
| 347 @override | |
| 348 void declaredFunctionTypeAlias(FunctionTypeAlias declaration) { | |
| 349 // ignored | |
| 350 } | |
| 351 | |
| 352 @override | |
| 353 void declaredLabel(Label label, bool isCaseLabel) { | |
| 354 if (isCaseLabel ? includeCaseLabels : includeStatementLabels) { | |
| 355 CompletionSuggestion suggestion = _addSuggestion(label.label); | |
| 356 if (suggestion != null) { | |
| 357 suggestion.element = | |
| 358 _createElement(protocol.ElementKind.LABEL, label.label); | |
| 359 } | |
| 360 } | |
| 361 } | |
| 362 | |
| 363 @override | |
| 364 void declaredLocalVar(SimpleIdentifier name, TypeName type) { | |
| 365 // ignored | |
| 366 } | |
| 367 | |
| 368 @override | |
| 369 void declaredMethod(MethodDeclaration declaration) { | |
| 370 // ignored | |
| 371 } | |
| 372 | |
| 373 @override | |
| 374 void declaredParam(SimpleIdentifier name, TypeName type) { | |
| 375 // ignored | |
| 376 } | |
| 377 | |
| 378 @override | |
| 379 void declaredTopLevelVar( | |
| 380 VariableDeclarationList varList, VariableDeclaration varDecl) { | |
| 381 // ignored | |
| 382 } | |
| 383 | |
| 384 @override | |
| 385 void visitFunctionExpression(FunctionExpression node) { | |
| 386 // Labels are only accessible within the local function, so stop visiting | |
| 387 // once we reach a function boundary. | |
| 388 finished(); | |
| 389 } | |
| 390 | |
| 391 @override | |
| 392 void visitMethodDeclaration(MethodDeclaration node) { | |
| 393 // Labels are only accessible within the local function, so stop visiting | |
| 394 // once we reach a function boundary. | |
| 395 finished(); | |
| 396 } | |
| 397 | |
| 398 CompletionSuggestion _addSuggestion(SimpleIdentifier id) { | |
| 399 if (id != null) { | |
| 400 String completion = id.name; | |
| 401 if (completion != null && completion.length > 0 && completion != '_') { | |
| 402 CompletionSuggestion suggestion = new CompletionSuggestion( | |
| 403 CompletionSuggestionKind.IDENTIFIER, DART_RELEVANCE_DEFAULT, | |
| 404 completion, completion.length, 0, false, false); | |
| 405 request.addSuggestion(suggestion); | |
| 406 return suggestion; | |
| 407 } | |
| 408 } | |
| 409 return null; | |
| 410 } | |
| 411 | |
| 412 /** | |
| 413 * Create a new protocol Element for inclusion in a completion suggestion. | |
| 414 */ | |
| 415 protocol.Element _createElement( | |
| 416 protocol.ElementKind kind, SimpleIdentifier id) { | |
| 417 String name = id.name; | |
| 418 int flags = | |
| 419 protocol.Element.makeFlags(isPrivate: Identifier.isPrivateName(name)); | |
| 420 return new protocol.Element(kind, name, flags); | |
| 421 } | |
| 422 } | |
| 423 | |
| 424 /** | |
| 425 * A visitor for collecting suggestions from the most specific child [AstNode] | |
| 426 * that contains the completion offset to the [CompilationUnit]. | |
| 427 */ | |
| 428 class _LocalVisitor extends LocalDeclarationVisitor { | |
| 429 final DartCompletionRequest request; | |
| 430 final OpType optype; | |
| 431 | |
| 432 _LocalVisitor(this.request, int offset, this.optype) : super(offset); | |
| 433 | |
| 434 @override | |
| 435 void declaredClass(ClassDeclaration declaration) { | |
| 436 if (optype.includeTypeNameSuggestions) { | |
| 437 bool isDeprecated = _isDeprecated(declaration); | |
| 438 CompletionSuggestion suggestion = _addSuggestion(declaration.name, | |
| 439 _NO_RETURN_TYPE, isDeprecated, DART_RELEVANCE_DEFAULT); | |
| 440 if (suggestion != null) { | |
| 441 suggestion.element = _createElement( | |
| 442 protocol.ElementKind.CLASS, declaration.name, | |
| 443 returnType: _NO_RETURN_TYPE, | |
| 444 isAbstract: declaration.isAbstract, | |
| 445 isDeprecated: isDeprecated); | |
| 446 } | |
| 447 } | |
| 448 } | |
| 449 | |
| 450 @override | |
| 451 void declaredClassTypeAlias(ClassTypeAlias declaration) { | |
| 452 if (optype.includeTypeNameSuggestions) { | |
| 453 bool isDeprecated = _isDeprecated(declaration); | |
| 454 CompletionSuggestion suggestion = _addSuggestion(declaration.name, | |
| 455 _NO_RETURN_TYPE, isDeprecated, DART_RELEVANCE_DEFAULT); | |
| 456 if (suggestion != null) { | |
| 457 suggestion.element = _createElement( | |
| 458 protocol.ElementKind.CLASS_TYPE_ALIAS, declaration.name, | |
| 459 returnType: _NO_RETURN_TYPE, | |
| 460 isAbstract: true, | |
| 461 isDeprecated: isDeprecated); | |
| 462 } | |
| 463 } | |
| 464 } | |
| 465 | |
| 466 @override | |
| 467 void declaredField(FieldDeclaration fieldDecl, VariableDeclaration varDecl) { | |
| 468 if (optype.includeReturnValueSuggestions) { | |
| 469 bool isDeprecated = _isDeprecated(fieldDecl) || _isDeprecated(varDecl); | |
| 470 TypeName type = fieldDecl.fields.type; | |
| 471 CompletionSuggestion suggestion = _addSuggestion( | |
| 472 varDecl.name, type, isDeprecated, DART_RELEVANCE_LOCAL_FIELD, | |
| 473 classDecl: fieldDecl.parent); | |
| 474 if (suggestion != null) { | |
| 475 suggestion.element = _createElement( | |
| 476 protocol.ElementKind.FIELD, varDecl.name, | |
| 477 returnType: type, isDeprecated: isDeprecated); | |
| 478 } | |
| 479 } | |
| 480 } | |
| 481 | |
| 482 @override | |
| 483 void declaredFunction(FunctionDeclaration declaration) { | |
| 484 if (optype.includeReturnValueSuggestions || | |
| 485 optype.includeVoidReturnSuggestions) { | |
| 486 TypeName returnType = declaration.returnType; | |
| 487 bool isDeprecated = _isDeprecated(declaration); | |
| 488 protocol.ElementKind kind; | |
| 489 int defaultRelevance = DART_RELEVANCE_DEFAULT; | |
| 490 if (declaration.isGetter) { | |
| 491 kind = protocol.ElementKind.GETTER; | |
| 492 defaultRelevance = DART_RELEVANCE_LOCAL_ACCESSOR; | |
| 493 } else if (declaration.isSetter) { | |
| 494 if (!optype.includeVoidReturnSuggestions) { | |
| 495 return; | |
| 496 } | |
| 497 kind = protocol.ElementKind.SETTER; | |
| 498 returnType = _NO_RETURN_TYPE; | |
| 499 defaultRelevance = DART_RELEVANCE_LOCAL_ACCESSOR; | |
| 500 } else { | |
| 501 if (!optype.includeVoidReturnSuggestions && _isVoid(returnType)) { | |
| 502 return; | |
| 503 } | |
| 504 kind = protocol.ElementKind.FUNCTION; | |
| 505 defaultRelevance = DART_RELEVANCE_LOCAL_FUNCTION; | |
| 506 } | |
| 507 CompletionSuggestion suggestion = _addSuggestion( | |
| 508 declaration.name, returnType, isDeprecated, defaultRelevance); | |
| 509 if (suggestion != null) { | |
| 510 FormalParameterList param = declaration.functionExpression.parameters; | |
| 511 suggestion.element = _createElement(kind, declaration.name, | |
| 512 parameters: param != null ? param.toSource() : null, | |
| 513 returnType: returnType, | |
| 514 isDeprecated: isDeprecated); | |
| 515 if (kind == protocol.ElementKind.FUNCTION) { | |
| 516 _addParameterInfo( | |
| 517 suggestion, declaration.functionExpression.parameters); | |
| 518 } | |
| 519 } | |
| 520 } | |
| 521 } | |
| 522 | |
| 523 @override | |
| 524 void declaredFunctionTypeAlias(FunctionTypeAlias declaration) { | |
| 525 if (optype.includeTypeNameSuggestions) { | |
| 526 bool isDeprecated = _isDeprecated(declaration); | |
| 527 TypeName returnType = declaration.returnType; | |
| 528 CompletionSuggestion suggestion = _addSuggestion( | |
| 529 declaration.name, returnType, isDeprecated, DART_RELEVANCE_DEFAULT); | |
| 530 if (suggestion != null) { | |
| 531 // TODO (danrubel) determine parameters and return type | |
| 532 suggestion.element = _createElement( | |
| 533 protocol.ElementKind.FUNCTION_TYPE_ALIAS, declaration.name, | |
| 534 returnType: returnType, | |
| 535 isAbstract: true, | |
| 536 isDeprecated: isDeprecated); | |
| 537 } | |
| 538 } | |
| 539 } | |
| 540 | |
| 541 @override | |
| 542 void declaredLabel(Label label, bool isCaseLabel) { | |
| 543 // ignored | |
| 544 } | |
| 545 | |
| 546 @override | |
| 547 void declaredLocalVar(SimpleIdentifier name, TypeName type) { | |
| 548 if (optype.includeReturnValueSuggestions) { | |
| 549 CompletionSuggestion suggestion = | |
| 550 _addSuggestion(name, type, false, DART_RELEVANCE_LOCAL_VARIABLE); | |
| 551 if (suggestion != null) { | |
| 552 suggestion.element = _createElement( | |
| 553 protocol.ElementKind.LOCAL_VARIABLE, name, returnType: type); | |
| 554 } | |
| 555 } | |
| 556 } | |
| 557 | |
| 558 @override | |
| 559 void declaredMethod(MethodDeclaration declaration) { | |
| 560 if (optype.includeReturnValueSuggestions || | |
| 561 optype.includeVoidReturnSuggestions) { | |
| 562 protocol.ElementKind kind; | |
| 563 String parameters; | |
| 564 TypeName returnType = declaration.returnType; | |
| 565 int defaultRelevance = DART_RELEVANCE_DEFAULT; | |
| 566 if (declaration.isGetter) { | |
| 567 kind = protocol.ElementKind.GETTER; | |
| 568 parameters = null; | |
| 569 defaultRelevance = DART_RELEVANCE_LOCAL_ACCESSOR; | |
| 570 } else if (declaration.isSetter) { | |
| 571 if (!optype.includeVoidReturnSuggestions) { | |
| 572 return; | |
| 573 } | |
| 574 kind = protocol.ElementKind.SETTER; | |
| 575 returnType = _NO_RETURN_TYPE; | |
| 576 defaultRelevance = DART_RELEVANCE_LOCAL_ACCESSOR; | |
| 577 } else { | |
| 578 if (!optype.includeVoidReturnSuggestions && _isVoid(returnType)) { | |
| 579 return; | |
| 580 } | |
| 581 kind = protocol.ElementKind.METHOD; | |
| 582 parameters = declaration.parameters.toSource(); | |
| 583 defaultRelevance = DART_RELEVANCE_LOCAL_METHOD; | |
| 584 } | |
| 585 bool isDeprecated = _isDeprecated(declaration); | |
| 586 CompletionSuggestion suggestion = _addSuggestion( | |
| 587 declaration.name, returnType, isDeprecated, defaultRelevance, | |
| 588 classDecl: declaration.parent); | |
| 589 if (suggestion != null) { | |
| 590 suggestion.element = _createElement(kind, declaration.name, | |
| 591 parameters: parameters, | |
| 592 returnType: returnType, | |
| 593 isAbstract: declaration.isAbstract, | |
| 594 isDeprecated: isDeprecated); | |
| 595 if (kind == protocol.ElementKind.METHOD) { | |
| 596 _addParameterInfo(suggestion, declaration.parameters); | |
| 597 } | |
| 598 } | |
| 599 } | |
| 600 } | |
| 601 | |
| 602 @override | |
| 603 void declaredParam(SimpleIdentifier name, TypeName type) { | |
| 604 if (optype.includeReturnValueSuggestions) { | |
| 605 CompletionSuggestion suggestion = | |
| 606 _addSuggestion(name, type, false, DART_RELEVANCE_PARAMETER); | |
| 607 if (suggestion != null) { | |
| 608 suggestion.element = _createElement( | |
| 609 protocol.ElementKind.PARAMETER, name, returnType: type); | |
| 610 } | |
| 611 } | |
| 612 } | |
| 613 | |
| 614 @override | |
| 615 void declaredTopLevelVar( | |
| 616 VariableDeclarationList varList, VariableDeclaration varDecl) { | |
| 617 if (optype.includeReturnValueSuggestions) { | |
| 618 bool isDeprecated = _isDeprecated(varList) || _isDeprecated(varDecl); | |
| 619 CompletionSuggestion suggestion = _addSuggestion(varDecl.name, | |
| 620 varList.type, isDeprecated, DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE); | |
| 621 if (suggestion != null) { | |
| 622 suggestion.element = _createElement( | |
| 623 protocol.ElementKind.TOP_LEVEL_VARIABLE, varDecl.name, | |
| 624 returnType: varList.type, isDeprecated: isDeprecated); | |
| 625 } | |
| 626 } | |
| 627 } | |
| 628 | |
| 629 void _addParameterInfo( | |
| 630 CompletionSuggestion suggestion, FormalParameterList parameters) { | |
| 631 var paramList = parameters.parameters; | |
| 632 suggestion.parameterNames = paramList | |
| 633 .map((FormalParameter param) => param.identifier.name) | |
| 634 .toList(); | |
| 635 suggestion.parameterTypes = paramList.map((FormalParameter param) { | |
| 636 TypeName type = null; | |
| 637 if (param is DefaultFormalParameter) { | |
| 638 NormalFormalParameter child = param.parameter; | |
| 639 if (child is SimpleFormalParameter) { | |
| 640 type = child.type; | |
| 641 } else if (child is FieldFormalParameter) { | |
| 642 type = child.type; | |
| 643 } | |
| 644 } | |
| 645 if (param is SimpleFormalParameter) { | |
| 646 type = param.type; | |
| 647 } else if (param is FieldFormalParameter) { | |
| 648 type = param.type; | |
| 649 } | |
| 650 if (type == null) { | |
| 651 return 'dynamic'; | |
| 652 } | |
| 653 Identifier typeId = type.name; | |
| 654 if (typeId == null) { | |
| 655 return 'dynamic'; | |
| 656 } | |
| 657 return typeId.name; | |
| 658 }).toList(); | |
| 659 suggestion.requiredParameterCount = paramList.where( | |
| 660 (FormalParameter param) => param is! DefaultFormalParameter).length; | |
| 661 suggestion.hasNamedParameters = paramList | |
| 662 .any((FormalParameter param) => param.kind == ParameterKind.NAMED); | |
| 663 } | |
| 664 | |
| 665 CompletionSuggestion _addSuggestion(SimpleIdentifier id, TypeName returnType, | |
| 666 bool isDeprecated, int defaultRelevance, {ClassDeclaration classDecl}) { | |
| 667 if (id != null) { | |
| 668 String completion = id.name; | |
| 669 if (completion != null && completion.length > 0 && completion != '_') { | |
| 670 CompletionSuggestion suggestion = new CompletionSuggestion( | |
| 671 CompletionSuggestionKind.INVOCATION, | |
| 672 isDeprecated ? DART_RELEVANCE_LOW : defaultRelevance, completion, | |
| 673 completion.length, 0, isDeprecated, false, | |
| 674 returnType: _nameForType(returnType)); | |
| 675 if (classDecl != null) { | |
| 676 SimpleIdentifier identifier = classDecl.name; | |
| 677 if (identifier != null) { | |
| 678 String name = identifier.name; | |
| 679 if (name != null && name.length > 0) { | |
| 680 suggestion.declaringType = name; | |
| 681 } | |
| 682 } | |
| 683 } | |
| 684 request.addSuggestion(suggestion); | |
| 685 return suggestion; | |
| 686 } | |
| 687 } | |
| 688 return null; | |
| 689 } | |
| 690 | |
| 691 bool _isVoid(TypeName returnType) { | |
| 692 if (returnType != null) { | |
| 693 Identifier id = returnType.name; | |
| 694 if (id != null && id.name == 'void') { | |
| 695 return true; | |
| 696 } | |
| 697 } | |
| 698 return false; | |
| 699 } | |
| 700 } | |
| OLD | NEW |