| 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.computer.dart.local; | 5 library services.completion.computer.dart.local; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:analysis_server/src/protocol.dart' as protocol show Element, | 9 import 'package:analysis_server/src/protocol.dart' as protocol show Element, |
| 10 ElementKind; | 10 ElementKind; |
| 11 import 'package:analysis_server/src/protocol.dart' hide 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'; | 12 import 'package:analysis_server/src/services/completion/dart_completion_manager.
dart'; |
| 13 import 'package:analysis_server/src/services/completion/suggestion_builder.dart'
; | 13 import 'package:analysis_server/src/services/completion/local_declaration_visito
r.dart'; |
| 14 import 'package:analyzer/src/generated/ast.dart'; | 14 import 'package:analyzer/src/generated/ast.dart'; |
| 15 import 'package:analyzer/src/generated/scanner.dart'; | 15 import 'package:analyzer/src/generated/scanner.dart'; |
| 16 | 16 |
| 17 /** | 17 /** |
| 18 * A computer for calculating `completion.getSuggestions` request results | 18 * A computer for calculating `completion.getSuggestions` request results |
| 19 * for the local library in which the completion is requested. | 19 * for the local library in which the completion is requested. |
| 20 */ | 20 */ |
| 21 class LocalComputer extends DartCompletionComputer { | 21 class LocalComputer extends DartCompletionComputer { |
| 22 | 22 |
| 23 @override | 23 @override |
| 24 bool computeFast(DartCompletionRequest request) { | 24 bool computeFast(DartCompletionRequest request) { |
| 25 | 25 |
| 26 // Find the specific child [AstNode] that contains the completion offset | 26 // Collect suggestions from the specific child [AstNode] that contains |
| 27 // and collect suggestions starting with that node | 27 // the completion offset and all of its parents recursively. |
| 28 request.node.accept(new _LocalVisitor(request)); | 28 request.node.accept(new _LocalVisitor(request, request.offset)); |
| 29 | 29 |
| 30 // If the unit is not a part and does not reference any parts | 30 // If the unit is not a part and does not reference any parts |
| 31 // then work is complete | 31 // then work is complete |
| 32 return !request.unit.directives.any( | 32 return !request.unit.directives.any( |
| 33 (Directive directive) => | 33 (Directive directive) => |
| 34 directive is PartOfDirective || directive is PartDirective); | 34 directive is PartOfDirective || directive is PartDirective); |
| 35 } | 35 } |
| 36 | 36 |
| 37 @override | 37 @override |
| 38 Future<bool> computeFull(DartCompletionRequest request) { | 38 Future<bool> computeFull(DartCompletionRequest request) { |
| 39 // TODO: implement computeFull | 39 // TODO: implement computeFull |
| 40 // include results from part files that are included in the library | 40 // include results from part files that are included in the library |
| 41 return new Future.value(false); | 41 return new Future.value(false); |
| 42 } | 42 } |
| 43 } | 43 } |
| 44 | 44 |
| 45 /** | 45 /** |
| 46 * A visitor for collecting suggestions from the most specific child [AstNode] | 46 * A visitor for collecting suggestions from the most specific child [AstNode] |
| 47 * that contains the completion offset to the [CompilationUnit]. | 47 * that contains the completion offset to the [CompilationUnit]. |
| 48 */ | 48 */ |
| 49 class _LocalVisitor extends GeneralizingAstVisitor<dynamic> { | 49 class _LocalVisitor extends LocalDeclarationVisitor { |
| 50 static const DYNAMIC = 'dynamic'; | 50 static const DYNAMIC = 'dynamic'; |
| 51 | 51 |
| 52 static final TypeName NO_RETURN_TYPE = new TypeName( | 52 static final TypeName NO_RETURN_TYPE = new TypeName( |
| 53 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, '', 0)), | 53 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, '', 0)), |
| 54 null); | 54 null); |
| 55 | 55 |
| 56 static final TypeName STACKTRACE_TYPE = new TypeName( | |
| 57 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, 'StackTrace', 0
)), | |
| 58 null); | |
| 59 | |
| 60 final DartCompletionRequest request; | 56 final DartCompletionRequest request; |
| 61 bool typesOnly = false; | 57 bool typesOnly = false; |
| 62 bool excludeVoidReturn; | 58 bool excludeVoidReturn; |
| 63 | 59 |
| 64 _LocalVisitor(this.request) { | 60 _LocalVisitor(this.request, int offset) : super(offset) { |
| 65 excludeVoidReturn = _computeExcludeVoidReturn(request.node); | 61 excludeVoidReturn = _computeExcludeVoidReturn(request.node); |
| 66 } | 62 } |
| 67 | 63 |
| 68 @override | 64 @override |
| 69 visitBlock(Block node) { | 65 void declaredClass(ClassDeclaration declaration) { |
| 70 node.statements.forEach((Statement stmt) { | |
| 71 if (stmt.offset < request.offset) { | |
| 72 if (stmt is LabeledStatement) { | |
| 73 stmt.labels.forEach((Label label) { | |
| 74 // _addSuggestion(label.label, CompletionSuggestionKind.LABEL); | |
| 75 }); | |
| 76 } else if (stmt is VariableDeclarationStatement) { | |
| 77 var varList = stmt.variables; | |
| 78 if (varList != null) { | |
| 79 varList.variables.forEach((VariableDeclaration varDecl) { | |
| 80 if (varDecl.end < request.offset) { | |
| 81 _addLocalVarSuggestion(varDecl.name, varList.type); | |
| 82 } | |
| 83 }); | |
| 84 } | |
| 85 } | |
| 86 } | |
| 87 }); | |
| 88 visitNode(node); | |
| 89 } | |
| 90 | |
| 91 @override | |
| 92 visitCascadeExpression(CascadeExpression node) { | |
| 93 Expression target = node.target; | |
| 94 // This computer handles the expression | |
| 95 // while InvocationComputer handles the cascade selector | |
| 96 if (target != null && request.offset <= target.end) { | |
| 97 visitNode(node); | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 @override | |
| 102 visitCatchClause(CatchClause node) { | |
| 103 _addParamSuggestion(node.exceptionParameter, node.exceptionType); | |
| 104 _addParamSuggestion(node.stackTraceParameter, STACKTRACE_TYPE); | |
| 105 visitNode(node); | |
| 106 } | |
| 107 | |
| 108 @override | |
| 109 visitClassDeclaration(ClassDeclaration node) { | |
| 110 _addClassDeclarationMembers(node); | |
| 111 visitInheritedTypes(node, (ClassDeclaration classNode) { | |
| 112 _addClassDeclarationMembers(classNode); | |
| 113 }, (String typeName) { | |
| 114 // ignored | |
| 115 }); | |
| 116 visitNode(node); | |
| 117 } | |
| 118 | |
| 119 @override | |
| 120 visitCombinator(Combinator node) { | |
| 121 // Handled by ImportedComputer | |
| 122 } | |
| 123 | |
| 124 @override | |
| 125 visitCompilationUnit(CompilationUnit node) { | |
| 126 node.declarations.forEach((Declaration declaration) { | |
| 127 if (declaration is ClassDeclaration) { | |
| 128 _addClassSuggestion(declaration); | |
| 129 } else if (declaration is EnumDeclaration) { | |
| 130 // _addSuggestion(d.name, CompletionSuggestionKind.ENUM); | |
| 131 } else if (declaration is FunctionDeclaration) { | |
| 132 _addFunctionSuggestion(declaration); | |
| 133 } else if (declaration is TopLevelVariableDeclaration) { | |
| 134 _addTopLevelVarSuggestions(declaration.variables); | |
| 135 } else if (declaration is ClassTypeAlias) { | |
| 136 bool isDeprecated = _isDeprecated(declaration); | |
| 137 CompletionSuggestion suggestion = | |
| 138 _addSuggestion(declaration.name, null, null, isDeprecated); | |
| 139 if (suggestion != null) { | |
| 140 suggestion.element = _createElement( | |
| 141 protocol.ElementKind.CLASS_TYPE_ALIAS, | |
| 142 declaration.name, | |
| 143 null, | |
| 144 NO_RETURN_TYPE, | |
| 145 true, | |
| 146 isDeprecated); | |
| 147 } | |
| 148 } else if (declaration is FunctionTypeAlias) { | |
| 149 bool isDeprecated = _isDeprecated(declaration); | |
| 150 CompletionSuggestion suggestion = | |
| 151 _addSuggestion(declaration.name, declaration.returnType, null, isDep
recated); | |
| 152 if (suggestion != null) { | |
| 153 // TODO (danrubel) determine parameters and return type | |
| 154 suggestion.element = _createElement( | |
| 155 protocol.ElementKind.FUNCTION_TYPE_ALIAS, | |
| 156 declaration.name, | |
| 157 null, | |
| 158 NO_RETURN_TYPE, | |
| 159 true, | |
| 160 isDeprecated); | |
| 161 } | |
| 162 } | |
| 163 }); | |
| 164 } | |
| 165 | |
| 166 @override | |
| 167 visitExpressionStatement(ExpressionStatement node) { | |
| 168 Expression expression = node.expression; | |
| 169 if (expression is SimpleIdentifier) { | |
| 170 if (expression.end < request.offset) { | |
| 171 // TODO (danrubel) suggest possible names for variable declaration | |
| 172 // based upon variable type | |
| 173 return; | |
| 174 } | |
| 175 } | |
| 176 visitNode(node); | |
| 177 } | |
| 178 | |
| 179 @override | |
| 180 visitForEachStatement(ForEachStatement node) { | |
| 181 SimpleIdentifier id; | |
| 182 TypeName type; | |
| 183 DeclaredIdentifier loopVar = node.loopVariable; | |
| 184 if (loopVar != null) { | |
| 185 id = loopVar.identifier; | |
| 186 type = loopVar.type; | |
| 187 } else { | |
| 188 id = node.identifier; | |
| 189 type = null; | |
| 190 } | |
| 191 _addLocalVarSuggestion(id, type); | |
| 192 visitNode(node); | |
| 193 } | |
| 194 | |
| 195 @override | |
| 196 visitForStatement(ForStatement node) { | |
| 197 var varList = node.variables; | |
| 198 if (varList != null) { | |
| 199 varList.variables.forEach((VariableDeclaration varDecl) { | |
| 200 _addLocalVarSuggestion(varDecl.name, varList.type); | |
| 201 }); | |
| 202 } | |
| 203 visitNode(node); | |
| 204 } | |
| 205 | |
| 206 @override | |
| 207 visitFunctionDeclaration(FunctionDeclaration node) { | |
| 208 // This is added by the compilation unit containing it | |
| 209 //_addSuggestion(node.name, CompletionSuggestionKind.FUNCTION); | |
| 210 visitNode(node); | |
| 211 } | |
| 212 | |
| 213 @override | |
| 214 visitFunctionExpression(FunctionExpression node) { | |
| 215 _addParamListSuggestions(node.parameters); | |
| 216 visitNode(node); | |
| 217 } | |
| 218 | |
| 219 @override | |
| 220 visitInterpolationExpression(InterpolationExpression node) { | |
| 221 visitNode(node); | |
| 222 } | |
| 223 | |
| 224 @override | |
| 225 visitMethodDeclaration(MethodDeclaration node) { | |
| 226 _addParamListSuggestions(node.parameters); | |
| 227 visitNode(node); | |
| 228 } | |
| 229 | |
| 230 @override | |
| 231 visitMethodInvocation(MethodInvocation node) { | |
| 232 // InvocationComputer adds suggestions for method selector | |
| 233 Token period = node.period; | |
| 234 if (period != null && period.offset < request.offset) { | |
| 235 ArgumentList argumentList = node.argumentList; | |
| 236 if (argumentList == null || request.offset <= argumentList.offset) { | |
| 237 return; | |
| 238 } | |
| 239 } | |
| 240 visitNode(node); | |
| 241 } | |
| 242 | |
| 243 @override | |
| 244 visitNamespaceDirective(NamespaceDirective node) { | |
| 245 // No suggestions | |
| 246 } | |
| 247 | |
| 248 @override | |
| 249 visitNode(AstNode node) { | |
| 250 node.parent.accept(this); | |
| 251 } | |
| 252 | |
| 253 @override | |
| 254 visitPrefixedIdentifier(PrefixedIdentifier node) { | |
| 255 // InvocationComputer adds suggestions for prefixed elements | |
| 256 // but this computer adds suggestions for the prefix itself | |
| 257 SimpleIdentifier prefix = node.prefix; | |
| 258 if (prefix == null || request.offset <= prefix.end) { | |
| 259 visitNode(node); | |
| 260 } | |
| 261 } | |
| 262 | |
| 263 @override | |
| 264 visitPropertyAccess(PropertyAccess node) { | |
| 265 // InvocationComputer adds suggestions for property access selector | |
| 266 } | |
| 267 | |
| 268 @override | |
| 269 visitStringInterpolation(StringInterpolation node) { | |
| 270 visitNode(node); | |
| 271 } | |
| 272 | |
| 273 @override | |
| 274 visitStringLiteral(StringLiteral node) { | |
| 275 // ignore | |
| 276 } | |
| 277 | |
| 278 @override | |
| 279 visitTypeName(TypeName node) { | |
| 280 // If suggesting completions within a TypeName node | |
| 281 // then limit suggestions to only types | |
| 282 typesOnly = true; | |
| 283 return visitNode(node); | |
| 284 } | |
| 285 | |
| 286 @override | |
| 287 visitVariableDeclaration(VariableDeclaration node) { | |
| 288 // Do not add suggestions if editing the name in a var declaration | |
| 289 SimpleIdentifier name = node.name; | |
| 290 if (name == null || | |
| 291 name.offset < request.offset || | |
| 292 request.offset > name.end) { | |
| 293 visitNode(node); | |
| 294 } | |
| 295 } | |
| 296 | |
| 297 void _addClassDeclarationMembers(ClassDeclaration node) { | |
| 298 node.members.forEach((ClassMember classMbr) { | |
| 299 if (classMbr is FieldDeclaration) { | |
| 300 _addFieldSuggestions(node, classMbr); | |
| 301 } else if (classMbr is MethodDeclaration) { | |
| 302 _addMethodSuggestion(node, classMbr); | |
| 303 } | |
| 304 }); | |
| 305 } | |
| 306 | |
| 307 void _addClassSuggestion(ClassDeclaration declaration) { | |
| 308 bool isDeprecated = _isDeprecated(declaration); | 66 bool isDeprecated = _isDeprecated(declaration); |
| 309 CompletionSuggestion suggestion = | 67 CompletionSuggestion suggestion = |
| 310 _addSuggestion(declaration.name, null, null, isDeprecated); | 68 _addSuggestion(declaration.name, null, null, isDeprecated); |
| 311 if (suggestion != null) { | 69 if (suggestion != null) { |
| 312 suggestion.element = _createElement( | 70 suggestion.element = _createElement( |
| 313 protocol.ElementKind.CLASS, | 71 protocol.ElementKind.CLASS, |
| 314 declaration.name, | 72 declaration.name, |
| 315 null, | 73 null, |
| 316 NO_RETURN_TYPE, | 74 _LocalVisitor.NO_RETURN_TYPE, |
| 317 declaration.isAbstract, | 75 declaration.isAbstract, |
| 318 isDeprecated); | 76 isDeprecated); |
| 319 } | 77 } |
| 320 } | 78 } |
| 321 | 79 |
| 322 void _addFieldSuggestions(ClassDeclaration node, FieldDeclaration fieldDecl) { | 80 @override |
| 81 void declaredClassTypeAlias(ClassTypeAlias declaration) { |
| 82 bool isDeprecated = _isDeprecated(declaration); |
| 83 CompletionSuggestion suggestion = |
| 84 _addSuggestion(declaration.name, null, null, isDeprecated); |
| 85 if (suggestion != null) { |
| 86 suggestion.element = _createElement( |
| 87 protocol.ElementKind.CLASS_TYPE_ALIAS, |
| 88 declaration.name, |
| 89 null, |
| 90 NO_RETURN_TYPE, |
| 91 true, |
| 92 isDeprecated); |
| 93 } |
| 94 } |
| 95 |
| 96 @override |
| 97 void declaredField(FieldDeclaration fieldDecl, VariableDeclaration varDecl) { |
| 323 if (typesOnly) { | 98 if (typesOnly) { |
| 324 return; | 99 return; |
| 325 } | 100 } |
| 326 bool isDeprecated = _isDeprecated(fieldDecl); | 101 bool isDeprecated = _isDeprecated(fieldDecl) || _isDeprecated(varDecl); |
| 327 fieldDecl.fields.variables.forEach((VariableDeclaration varDecl) { | 102 CompletionSuggestion suggestion = _addSuggestion( |
| 328 bool isSingleFieldDeprecated = isDeprecated || _isDeprecated(varDecl); | 103 varDecl.name, |
| 329 CompletionSuggestion suggestion = _addSuggestion( | 104 fieldDecl.fields.type, |
| 105 fieldDecl.parent, |
| 106 isDeprecated); |
| 107 if (suggestion != null) { |
| 108 suggestion.element = _createElement( |
| 109 protocol.ElementKind.GETTER, |
| 330 varDecl.name, | 110 varDecl.name, |
| 111 '()', |
| 331 fieldDecl.fields.type, | 112 fieldDecl.fields.type, |
| 332 node, | 113 false, |
| 333 isSingleFieldDeprecated); | 114 isDeprecated); |
| 334 if (suggestion != null) { | 115 } |
| 335 suggestion.element = _createElement( | |
| 336 protocol.ElementKind.GETTER, | |
| 337 varDecl.name, | |
| 338 '()', | |
| 339 fieldDecl.fields.type, | |
| 340 false, | |
| 341 isSingleFieldDeprecated); | |
| 342 } | |
| 343 }); | |
| 344 } | 116 } |
| 345 | 117 |
| 346 void _addFunctionSuggestion(FunctionDeclaration declaration) { | 118 @override |
| 119 bool visitCascadeExpression(CascadeExpression node) { |
| 120 Expression target = node.target; |
| 121 // This computer handles the expression |
| 122 // while InvocationComputer handles the cascade selector |
| 123 if (target != null && offset <= target.end) { |
| 124 return visitNode(node); |
| 125 } else { |
| 126 return finished; |
| 127 } |
| 128 } |
| 129 |
| 130 @override |
| 131 bool visitNamespaceDirective(NamespaceDirective node) { |
| 132 // No suggestions |
| 133 return finished; |
| 134 } |
| 135 |
| 136 @override |
| 137 bool visitStringLiteral(StringLiteral node) { |
| 138 // ignore |
| 139 return finished; |
| 140 } |
| 141 |
| 142 @override |
| 143 bool visitVariableDeclaration(VariableDeclaration node) { |
| 144 // Do not add suggestions if editing the name in a var declaration |
| 145 SimpleIdentifier name = node.name; |
| 146 if (name == null || name.offset < offset || offset > name.end) { |
| 147 return visitNode(node); |
| 148 } else { |
| 149 return finished; |
| 150 } |
| 151 } |
| 152 |
| 153 @override |
| 154 void declaredFunction(FunctionDeclaration declaration) { |
| 347 if (typesOnly) { | 155 if (typesOnly) { |
| 348 return; | 156 return; |
| 349 } | 157 } |
| 350 if (excludeVoidReturn && _isVoid(declaration.returnType)) { | 158 if (excludeVoidReturn && _isVoid(declaration.returnType)) { |
| 351 return; | 159 return; |
| 352 } | 160 } |
| 353 bool isDeprecated = _isDeprecated(declaration); | 161 bool isDeprecated = _isDeprecated(declaration); |
| 354 CompletionSuggestion suggestion = | 162 CompletionSuggestion suggestion = |
| 355 _addSuggestion(declaration.name, declaration.returnType, null, isDepreca
ted); | 163 _addSuggestion(declaration.name, declaration.returnType, null, isDepreca
ted); |
| 356 if (suggestion != null) { | 164 if (suggestion != null) { |
| 357 suggestion.element = _createElement( | 165 suggestion.element = _createElement( |
| 358 protocol.ElementKind.FUNCTION, | 166 protocol.ElementKind.FUNCTION, |
| 359 declaration.name, | 167 declaration.name, |
| 360 declaration.functionExpression.parameters.toSource(), | 168 declaration.functionExpression.parameters.toSource(), |
| 361 declaration.returnType, | 169 declaration.returnType, |
| 362 false, | 170 false, |
| 363 isDeprecated); | 171 isDeprecated); |
| 364 } | 172 } |
| 365 } | 173 } |
| 366 | 174 |
| 367 void _addLocalVarSuggestion(SimpleIdentifier id, TypeName returnType) { | 175 @override |
| 368 if (typesOnly) { | 176 void declaredFunctionTypeAlias(FunctionTypeAlias declaration) { |
| 369 return; | 177 bool isDeprecated = _isDeprecated(declaration); |
| 370 } | |
| 371 CompletionSuggestion suggestion = | 178 CompletionSuggestion suggestion = |
| 372 _addSuggestion(id, returnType, null, false); | 179 _addSuggestion(declaration.name, declaration.returnType, null, isDepreca
ted); |
| 373 if (suggestion != null) { | 180 if (suggestion != null) { |
| 181 // TODO (danrubel) determine parameters and return type |
| 374 suggestion.element = _createElement( | 182 suggestion.element = _createElement( |
| 375 protocol.ElementKind.LOCAL_VARIABLE, | 183 protocol.ElementKind.FUNCTION_TYPE_ALIAS, |
| 376 id, | 184 declaration.name, |
| 377 null, | 185 null, |
| 378 returnType, | 186 NO_RETURN_TYPE, |
| 379 false, | 187 true, |
| 380 false); | |
| 381 } | |
| 382 } | |
| 383 | |
| 384 void _addMethodSuggestion(ClassDeclaration node, MethodDeclaration classMbr) { | |
| 385 if (typesOnly) { | |
| 386 return; | |
| 387 } | |
| 388 protocol.ElementKind kind; | |
| 389 String parameters; | |
| 390 if (classMbr.isGetter) { | |
| 391 kind = protocol.ElementKind.GETTER; | |
| 392 parameters = '()'; | |
| 393 } else if (classMbr.isSetter) { | |
| 394 if (excludeVoidReturn) { | |
| 395 return; | |
| 396 } | |
| 397 kind = protocol.ElementKind.SETTER; | |
| 398 parameters = '(${classMbr.returnType.toSource()} value)'; | |
| 399 } else { | |
| 400 if (excludeVoidReturn && _isVoid(classMbr.returnType)) { | |
| 401 return; | |
| 402 } | |
| 403 kind = protocol.ElementKind.METHOD; | |
| 404 parameters = classMbr.parameters.toSource(); | |
| 405 } | |
| 406 bool isDeprecated = _isDeprecated(classMbr); | |
| 407 CompletionSuggestion suggestion = | |
| 408 _addSuggestion(classMbr.name, classMbr.returnType, node, isDeprecated); | |
| 409 if (suggestion != null) { | |
| 410 suggestion.element = _createElement( | |
| 411 kind, | |
| 412 classMbr.name, | |
| 413 parameters, | |
| 414 classMbr.returnType, | |
| 415 classMbr.isAbstract, | |
| 416 isDeprecated); | 188 isDeprecated); |
| 417 } | 189 } |
| 418 } | 190 } |
| 419 | 191 |
| 420 void _addParamListSuggestions(FormalParameterList paramList) { | 192 @override |
| 193 void declaredLabel(Label label) { |
| 194 // ignored |
| 195 } |
| 196 |
| 197 @override |
| 198 void declaredLocalVar(SimpleIdentifier name, TypeName type) { |
| 421 if (typesOnly) { | 199 if (typesOnly) { |
| 422 return; | 200 return; |
| 423 } | 201 } |
| 424 if (paramList != null) { | 202 CompletionSuggestion suggestion = _addSuggestion(name, type, null, false); |
| 425 paramList.parameters.forEach((FormalParameter param) { | |
| 426 NormalFormalParameter normalParam; | |
| 427 if (param is DefaultFormalParameter) { | |
| 428 normalParam = param.parameter; | |
| 429 } else if (param is NormalFormalParameter) { | |
| 430 normalParam = param; | |
| 431 } | |
| 432 TypeName type = null; | |
| 433 if (normalParam is FieldFormalParameter) { | |
| 434 type = normalParam.type; | |
| 435 } else if (normalParam is FunctionTypedFormalParameter) { | |
| 436 type = normalParam.returnType; | |
| 437 } else if (normalParam is SimpleFormalParameter) { | |
| 438 type = normalParam.type; | |
| 439 } | |
| 440 _addParamSuggestion(param.identifier, type); | |
| 441 }); | |
| 442 } | |
| 443 } | |
| 444 | |
| 445 void _addParamSuggestion(SimpleIdentifier identifier, TypeName type) { | |
| 446 if (typesOnly) { | |
| 447 return; | |
| 448 } | |
| 449 CompletionSuggestion suggestion = | |
| 450 _addSuggestion(identifier, type, null, false); | |
| 451 if (suggestion != null) { | 203 if (suggestion != null) { |
| 452 suggestion.element = _createElement( | 204 suggestion.element = _createElement( |
| 453 protocol.ElementKind.PARAMETER, | 205 protocol.ElementKind.LOCAL_VARIABLE, |
| 454 identifier, | 206 name, |
| 455 null, | 207 null, |
| 456 type, | 208 type, |
| 457 false, | 209 false, |
| 458 false); | 210 false); |
| 459 } | 211 } |
| 460 } | 212 } |
| 461 | 213 |
| 214 @override |
| 215 void declaredMethod(MethodDeclaration declaration) { |
| 216 if (typesOnly) { |
| 217 return; |
| 218 } |
| 219 protocol.ElementKind kind; |
| 220 String parameters; |
| 221 if (declaration.isGetter) { |
| 222 kind = protocol.ElementKind.GETTER; |
| 223 parameters = '()'; |
| 224 } else if (declaration.isSetter) { |
| 225 if (excludeVoidReturn) { |
| 226 return; |
| 227 } |
| 228 kind = protocol.ElementKind.SETTER; |
| 229 parameters = '(${declaration.returnType.toSource()} value)'; |
| 230 } else { |
| 231 if (excludeVoidReturn && _isVoid(declaration.returnType)) { |
| 232 return; |
| 233 } |
| 234 kind = protocol.ElementKind.METHOD; |
| 235 parameters = declaration.parameters.toSource(); |
| 236 } |
| 237 bool isDeprecated = _isDeprecated(declaration); |
| 238 CompletionSuggestion suggestion = _addSuggestion( |
| 239 declaration.name, |
| 240 declaration.returnType, |
| 241 declaration.parent, |
| 242 isDeprecated); |
| 243 if (suggestion != null) { |
| 244 suggestion.element = _createElement( |
| 245 kind, |
| 246 declaration.name, |
| 247 parameters, |
| 248 declaration.returnType, |
| 249 declaration.isAbstract, |
| 250 isDeprecated); |
| 251 } |
| 252 } |
| 253 |
| 254 @override |
| 255 void declaredParam(SimpleIdentifier name, TypeName type) { |
| 256 if (typesOnly) { |
| 257 return; |
| 258 } |
| 259 CompletionSuggestion suggestion = _addSuggestion(name, type, null, false); |
| 260 if (suggestion != null) { |
| 261 suggestion.element = |
| 262 _createElement(protocol.ElementKind.PARAMETER, name, null, type, false
, false); |
| 263 } |
| 264 } |
| 265 |
| 266 @override |
| 267 void declaredTopLevelVar(VariableDeclarationList varList, |
| 268 VariableDeclaration varDecl) { |
| 269 if (typesOnly) { |
| 270 return; |
| 271 } |
| 272 bool isDeprecated = _isDeprecated(varList) || _isDeprecated(varDecl); |
| 273 CompletionSuggestion suggestion = |
| 274 _addSuggestion(varDecl.name, varList.type, null, isDeprecated); |
| 275 if (suggestion != null) { |
| 276 suggestion.element = _createElement( |
| 277 protocol.ElementKind.TOP_LEVEL_VARIABLE, |
| 278 varDecl.name, |
| 279 null, |
| 280 varList.type, |
| 281 false, |
| 282 isDeprecated); |
| 283 } |
| 284 } |
| 285 |
| 286 @override |
| 287 visitCombinator(Combinator node) { |
| 288 // Handled by CombinatorComputer |
| 289 } |
| 290 |
| 291 @override |
| 292 visitMethodInvocation(MethodInvocation node) { |
| 293 // InvocationComputer adds suggestions for method selector |
| 294 Token period = node.period; |
| 295 if (period != null && period.offset < request.offset) { |
| 296 ArgumentList argumentList = node.argumentList; |
| 297 if (argumentList == null || request.offset <= argumentList.offset) { |
| 298 return; |
| 299 } |
| 300 } |
| 301 visitNode(node); |
| 302 } |
| 303 |
| 304 @override |
| 305 visitPrefixedIdentifier(PrefixedIdentifier node) { |
| 306 // InvocationComputer adds suggestions for prefixed elements |
| 307 // but this computer adds suggestions for the prefix itself |
| 308 SimpleIdentifier prefix = node.prefix; |
| 309 if (prefix == null || request.offset <= prefix.end) { |
| 310 visitNode(node); |
| 311 } |
| 312 } |
| 313 |
| 314 @override |
| 315 visitPropertyAccess(PropertyAccess node) { |
| 316 // InvocationComputer adds suggestions for property access selector |
| 317 } |
| 318 |
| 319 @override |
| 320 visitTypeName(TypeName node) { |
| 321 // If suggesting completions within a TypeName node |
| 322 // then limit suggestions to only types |
| 323 typesOnly = true; |
| 324 return visitNode(node); |
| 325 } |
| 326 |
| 462 CompletionSuggestion _addSuggestion(SimpleIdentifier id, TypeName typeName, | 327 CompletionSuggestion _addSuggestion(SimpleIdentifier id, TypeName typeName, |
| 463 ClassDeclaration classDecl, bool isDeprecated) { | 328 ClassDeclaration classDecl, bool isDeprecated) { |
| 464 if (id != null) { | 329 if (id != null) { |
| 465 String completion = id.name; | 330 String completion = id.name; |
| 466 if (completion != null && completion.length > 0 && completion != '_') { | 331 if (completion != null && completion.length > 0 && completion != '_') { |
| 467 CompletionSuggestion suggestion = new CompletionSuggestion( | 332 CompletionSuggestion suggestion = new CompletionSuggestion( |
| 468 CompletionSuggestionKind.INVOCATION, | 333 CompletionSuggestionKind.INVOCATION, |
| 469 isDeprecated ? CompletionRelevance.LOW : CompletionRelevance.DEFAULT
, | 334 isDeprecated ? CompletionRelevance.LOW : CompletionRelevance.DEFAULT
, |
| 470 completion, | 335 completion, |
| 471 completion.length, | 336 completion.length, |
| (...skipping 18 matching lines...) Expand all Loading... |
| 490 } | 355 } |
| 491 } | 356 } |
| 492 } | 357 } |
| 493 request.suggestions.add(suggestion); | 358 request.suggestions.add(suggestion); |
| 494 return suggestion; | 359 return suggestion; |
| 495 } | 360 } |
| 496 } | 361 } |
| 497 return null; | 362 return null; |
| 498 } | 363 } |
| 499 | 364 |
| 500 void _addTopLevelVarSuggestions(VariableDeclarationList varList) { | |
| 501 if (typesOnly) { | |
| 502 return; | |
| 503 } | |
| 504 if (varList != null) { | |
| 505 bool isDeprecated = _isDeprecated(varList); | |
| 506 varList.variables.forEach((VariableDeclaration varDecl) { | |
| 507 bool isSingleVarDeprecated = isDeprecated || _isDeprecated(varDecl); | |
| 508 CompletionSuggestion suggestion = | |
| 509 _addSuggestion(varDecl.name, varList.type, null, isSingleVarDeprecat
ed); | |
| 510 if (suggestion != null) { | |
| 511 suggestion.element = _createElement( | |
| 512 protocol.ElementKind.TOP_LEVEL_VARIABLE, | |
| 513 varDecl.name, | |
| 514 null, | |
| 515 varList.type, | |
| 516 false, | |
| 517 isSingleVarDeprecated); | |
| 518 } | |
| 519 }); | |
| 520 } | |
| 521 } | |
| 522 | |
| 523 bool _computeExcludeVoidReturn(AstNode node) { | 365 bool _computeExcludeVoidReturn(AstNode node) { |
| 524 if (node is Block) { | 366 if (node is Block) { |
| 525 return false; | 367 return false; |
| 526 } else if (node is SimpleIdentifier) { | 368 } else if (node is SimpleIdentifier) { |
| 527 return node.parent is ExpressionStatement ? false : true; | 369 return node.parent is ExpressionStatement ? false : true; |
| 528 } else { | 370 } else { |
| 529 return true; | 371 return true; |
| 530 } | 372 } |
| 531 } | 373 } |
| 532 | 374 |
| 375 |
| 533 /** | 376 /** |
| 534 * Create a new protocol Element for inclusion in a completion suggestion. | 377 * Create a new protocol Element for inclusion in a completion suggestion. |
| 535 */ | 378 */ |
| 536 protocol.Element _createElement(protocol.ElementKind kind, | 379 protocol.Element _createElement(protocol.ElementKind kind, |
| 537 SimpleIdentifier id, String parameters, TypeName returnType, bool isAbstra
ct, | 380 SimpleIdentifier id, String parameters, TypeName returnType, bool isAbstra
ct, |
| 538 bool isDeprecated) { | 381 bool isDeprecated) { |
| 539 String name = id.name; | 382 String name = id.name; |
| 540 int flags = protocol.Element.makeFlags( | 383 int flags = protocol.Element.makeFlags( |
| 541 isAbstract: isAbstract, | 384 isAbstract: isAbstract, |
| 542 isDeprecated: isDeprecated, | 385 isDeprecated: isDeprecated, |
| 543 isPrivate: Identifier.isPrivateName(name)); | 386 isPrivate: Identifier.isPrivateName(name)); |
| 544 return new protocol.Element( | 387 return new protocol.Element( |
| 545 kind, | 388 kind, |
| 546 name, | 389 name, |
| 547 flags, | 390 flags, |
| 548 parameters: parameters, | 391 parameters: parameters, |
| 549 returnType: _nameForType(returnType)); | 392 returnType: _nameForType(returnType)); |
| 550 } | 393 } |
| 551 | 394 |
| 552 | |
| 553 /** | 395 /** |
| 554 * Return `true` if the @deprecated annotation is present | 396 * Return `true` if the @deprecated annotation is present |
| 555 */ | 397 */ |
| 556 bool _isDeprecated(AnnotatedNode node) { | 398 bool _isDeprecated(AnnotatedNode node) { |
| 557 if (node != null) { | 399 if (node != null) { |
| 558 NodeList<Annotation> metadata = node.metadata; | 400 NodeList<Annotation> metadata = node.metadata; |
| 559 if (metadata != null) { | 401 if (metadata != null) { |
| 560 return metadata.any((Annotation a) { | 402 return metadata.any((Annotation a) { |
| 561 return a.name is SimpleIdentifier && a.name.name == 'deprecated'; | 403 return a.name is SimpleIdentifier && a.name.name == 'deprecated'; |
| 562 }); | 404 }); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 593 if (name == null || name.length <= 0) { | 435 if (name == null || name.length <= 0) { |
| 594 return DYNAMIC; | 436 return DYNAMIC; |
| 595 } | 437 } |
| 596 TypeArgumentList typeArgs = type.typeArguments; | 438 TypeArgumentList typeArgs = type.typeArguments; |
| 597 if (typeArgs != null) { | 439 if (typeArgs != null) { |
| 598 //TODO (danrubel) include type arguments | 440 //TODO (danrubel) include type arguments |
| 599 } | 441 } |
| 600 return name; | 442 return name; |
| 601 } | 443 } |
| 602 } | 444 } |
| OLD | NEW |