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'; | 9 import 'package:analysis_server/src/protocol.dart' as protocol show Element, Ele
mentKind; |
| 10 import 'package:analysis_server/src/protocol.dart' hide Element, ElementKind; |
10 import 'package:analysis_server/src/services/completion/dart_completion_manager.
dart'; | 11 import 'package:analysis_server/src/services/completion/dart_completion_manager.
dart'; |
11 import 'package:analyzer/src/generated/ast.dart'; | 12 import 'package:analyzer/src/generated/ast.dart'; |
| 13 import 'package:analyzer/src/generated/scanner.dart'; |
12 | 14 |
13 /** | 15 /** |
14 * A computer for calculating `completion.getSuggestions` request results | 16 * A computer for calculating `completion.getSuggestions` request results |
15 * for the local library in which the completion is requested. | 17 * for the local library in which the completion is requested. |
16 */ | 18 */ |
17 class LocalComputer extends DartCompletionComputer { | 19 class LocalComputer extends DartCompletionComputer { |
18 | 20 |
19 @override | 21 @override |
20 bool computeFast(DartCompletionRequest request) { | 22 bool computeFast(DartCompletionRequest request) { |
21 | 23 |
(...skipping 14 matching lines...) Expand all Loading... |
36 // include results from part files that are included in the library | 38 // include results from part files that are included in the library |
37 return new Future.value(false); | 39 return new Future.value(false); |
38 } | 40 } |
39 } | 41 } |
40 | 42 |
41 /** | 43 /** |
42 * A visitor for collecting suggestions from the most specific child [AstNode] | 44 * A visitor for collecting suggestions from the most specific child [AstNode] |
43 * that contains the completion offset to the [CompilationUnit]. | 45 * that contains the completion offset to the [CompilationUnit]. |
44 */ | 46 */ |
45 class _LocalVisitor extends GeneralizingAstVisitor<dynamic> { | 47 class _LocalVisitor extends GeneralizingAstVisitor<dynamic> { |
| 48 static const DYNAMIC = 'dynamic'; |
| 49 |
| 50 static final TypeName NO_RETURN_TYPE = new TypeName( |
| 51 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, '', 0)), |
| 52 null); |
| 53 |
| 54 static final TypeName STACKTRACE_TYPE = new TypeName( |
| 55 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, 'StackTrace', 0
)), |
| 56 null); |
| 57 |
46 final DartCompletionRequest request; | 58 final DartCompletionRequest request; |
47 | 59 |
48 _LocalVisitor(this.request); | 60 _LocalVisitor(this.request); |
49 | 61 |
50 @override | 62 @override |
51 visitBlock(Block node) { | 63 visitBlock(Block node) { |
52 node.statements.forEach((Statement stmt) { | 64 node.statements.forEach((Statement stmt) { |
53 if (stmt.offset < request.offset) { | 65 if (stmt.offset < request.offset) { |
54 if (stmt is LabeledStatement) { | 66 if (stmt is LabeledStatement) { |
55 stmt.labels.forEach((Label label) { | 67 stmt.labels.forEach((Label label) { |
56 // _addSuggestion(label.label, CompletionSuggestionKind.LABEL); | 68 // _addSuggestion(label.label, CompletionSuggestionKind.LABEL); |
57 }); | 69 }); |
58 } else if (stmt is VariableDeclarationStatement) { | 70 } else if (stmt is VariableDeclarationStatement) { |
59 VariableDeclarationList varList = stmt.variables; | 71 var varList = stmt.variables; |
60 if (varList != null) { | 72 if (varList != null) { |
61 varList.variables.forEach((VariableDeclaration varDecl) { | 73 varList.variables.forEach((VariableDeclaration varDecl) { |
62 if (varDecl.end < request.offset) { | 74 if (varDecl.end < request.offset) { |
63 _addSuggestion( | 75 _addLocalVarSuggestion(varDecl.name, varList.type); |
64 varDecl.name, | |
65 CompletionSuggestionKind.LOCAL_VARIABLE, | |
66 varList.type, | |
67 null); | |
68 } | 76 } |
69 }); | 77 }); |
70 } | 78 } |
71 } | 79 } |
72 } | 80 } |
73 }); | 81 }); |
74 visitNode(node); | 82 visitNode(node); |
75 } | 83 } |
76 | 84 |
77 @override | 85 @override |
78 visitCatchClause(CatchClause node) { | 86 visitCatchClause(CatchClause node) { |
79 _addSuggestion( | 87 _addParamSuggestion(node.exceptionParameter, node.exceptionType); |
80 node.exceptionParameter, | 88 CompletionSuggestion suggestion = |
81 CompletionSuggestionKind.PARAMETER, | 89 _addParamSuggestion(node.stackTraceParameter, STACKTRACE_TYPE); |
82 node.exceptionType, | |
83 null); | |
84 // TODO (danrubel) add stack trace types | |
85 _addSuggestion( | |
86 node.stackTraceParameter, | |
87 CompletionSuggestionKind.PARAMETER, | |
88 null, | |
89 null); | |
90 visitNode(node); | 90 visitNode(node); |
91 } | 91 } |
92 | 92 |
93 @override | 93 @override |
94 visitClassDeclaration(ClassDeclaration node) { | 94 visitClassDeclaration(ClassDeclaration node) { |
95 node.members.forEach((ClassMember classMbr) { | 95 node.members.forEach((ClassMember classMbr) { |
96 if (classMbr is FieldDeclaration) { | 96 if (classMbr is FieldDeclaration) { |
97 _addVarListSuggestions( | 97 _addFieldSuggestions(node, classMbr); |
98 classMbr.fields, | |
99 CompletionSuggestionKind.FIELD, | |
100 node); | |
101 } else if (classMbr is MethodDeclaration) { | 98 } else if (classMbr is MethodDeclaration) { |
102 _addSuggestion( | 99 _addMethodSuggestion(node, classMbr); |
103 classMbr.name, | |
104 CompletionSuggestionKind.METHOD_NAME, | |
105 classMbr.returnType, | |
106 node); | |
107 } | 100 } |
108 }); | 101 }); |
109 visitNode(node); | 102 visitNode(node); |
110 } | 103 } |
111 | 104 |
112 @override | 105 @override |
113 visitCompilationUnit(CompilationUnit node) { | 106 visitCompilationUnit(CompilationUnit node) { |
114 node.directives.forEach((Directive directive) { | 107 node.directives.forEach((Directive directive) { |
115 if (directive is ImportDirective) { | 108 if (directive is ImportDirective) { |
116 _addSuggestion( | 109 _addLibraryPrefixSuggestion(directive); |
117 directive.prefix, | |
118 CompletionSuggestionKind.LIBRARY_PREFIX, | |
119 null, | |
120 null); | |
121 } | 110 } |
122 }); | 111 }); |
123 node.declarations.forEach((Declaration declaration) { | 112 node.declarations.forEach((Declaration declaration) { |
124 if (declaration is ClassDeclaration) { | 113 if (declaration is ClassDeclaration) { |
125 _addSuggestion( | 114 _addClassSuggestion(declaration); |
126 declaration.name, | |
127 CompletionSuggestionKind.CLASS, | |
128 null, | |
129 null); | |
130 } else if (declaration is EnumDeclaration) { | 115 } else if (declaration is EnumDeclaration) { |
131 // _addSuggestion(d.name, CompletionSuggestionKind.ENUM); | 116 // _addSuggestion(d.name, CompletionSuggestionKind.ENUM); |
132 } else if (declaration is FunctionDeclaration) { | 117 } else if (declaration is FunctionDeclaration) { |
133 _addSuggestion( | 118 _addFunctionSuggestion(declaration); |
134 declaration.name, | |
135 CompletionSuggestionKind.FUNCTION, | |
136 declaration.returnType, | |
137 null); | |
138 } else if (declaration is TopLevelVariableDeclaration) { | 119 } else if (declaration is TopLevelVariableDeclaration) { |
139 _addVarListSuggestions( | 120 _addTopLevelVarSuggestions(declaration.variables); |
140 declaration.variables, | |
141 CompletionSuggestionKind.TOP_LEVEL_VARIABLE, | |
142 null); | |
143 } else if (declaration is ClassTypeAlias) { | 121 } else if (declaration is ClassTypeAlias) { |
144 _addSuggestion( | 122 _addSuggestion( |
145 declaration.name, | 123 declaration.name, |
146 CompletionSuggestionKind.CLASS_ALIAS, | 124 CompletionSuggestionKind.CLASS_ALIAS, |
147 null, | 125 null, |
148 null); | 126 null); |
149 } else if (declaration is FunctionTypeAlias) { | 127 } else if (declaration is FunctionTypeAlias) { |
150 _addSuggestion( | 128 _addSuggestion( |
151 declaration.name, | 129 declaration.name, |
152 CompletionSuggestionKind.FUNCTION_TYPE_ALIAS, | 130 CompletionSuggestionKind.FUNCTION_TYPE_ALIAS, |
(...skipping 11 matching lines...) Expand all Loading... |
164 // TODO (danrubel) suggest possible names for variable declaration | 142 // TODO (danrubel) suggest possible names for variable declaration |
165 // based upon variable type | 143 // based upon variable type |
166 return; | 144 return; |
167 } | 145 } |
168 } | 146 } |
169 visitNode(node); | 147 visitNode(node); |
170 } | 148 } |
171 | 149 |
172 @override | 150 @override |
173 visitForEachStatement(ForEachStatement node) { | 151 visitForEachStatement(ForEachStatement node) { |
174 // TODO (danrubel) supply type of local variable | 152 SimpleIdentifier id; |
175 _addSuggestion( | 153 TypeName type; |
176 node.identifier, | 154 DeclaredIdentifier loopVar = node.loopVariable; |
177 CompletionSuggestionKind.LOCAL_VARIABLE, | 155 if (loopVar != null) { |
178 null, | 156 id = loopVar.identifier; |
179 null); | 157 type = loopVar.type; |
| 158 } else { |
| 159 id = node.identifier; |
| 160 type = null; |
| 161 } |
| 162 _addLocalVarSuggestion(id, type); |
180 visitNode(node); | 163 visitNode(node); |
181 } | 164 } |
182 | 165 |
183 @override | 166 @override |
184 visitForStatement(ForStatement node) { | 167 visitForStatement(ForStatement node) { |
185 _addVarListSuggestions( | 168 var varList = node.variables; |
186 node.variables, | 169 if (varList != null) { |
187 CompletionSuggestionKind.LOCAL_VARIABLE, | 170 varList.variables.forEach((VariableDeclaration varDecl) { |
188 null); | 171 _addLocalVarSuggestion(varDecl.name, varList.type); |
| 172 }); |
| 173 } |
189 visitNode(node); | 174 visitNode(node); |
190 } | 175 } |
191 | 176 |
192 @override | 177 @override |
193 visitFunctionDeclaration(FunctionDeclaration node) { | 178 visitFunctionDeclaration(FunctionDeclaration node) { |
194 // This is added by the compilation unit containing it | 179 // This is added by the compilation unit containing it |
195 //_addSuggestion(node.name, CompletionSuggestionKind.FUNCTION); | 180 //_addSuggestion(node.name, CompletionSuggestionKind.FUNCTION); |
196 visitNode(node); | 181 visitNode(node); |
197 } | 182 } |
198 | 183 |
(...skipping 18 matching lines...) Expand all Loading... |
217 visitVariableDeclaration(VariableDeclaration node) { | 202 visitVariableDeclaration(VariableDeclaration node) { |
218 // Do not add suggestions if editing the name in a var declaration | 203 // Do not add suggestions if editing the name in a var declaration |
219 SimpleIdentifier name = node.name; | 204 SimpleIdentifier name = node.name; |
220 if (name == null || | 205 if (name == null || |
221 name.offset < request.offset || | 206 name.offset < request.offset || |
222 request.offset > name.end) { | 207 request.offset > name.end) { |
223 visitNode(node); | 208 visitNode(node); |
224 } | 209 } |
225 } | 210 } |
226 | 211 |
| 212 void _addClassSuggestion(ClassDeclaration declaration) { |
| 213 CompletionSuggestion suggestion = |
| 214 _addSuggestion(declaration.name, CompletionSuggestionKind.CLASS, null, n
ull); |
| 215 if (suggestion != null) { |
| 216 suggestion.element = _createElement( |
| 217 protocol.ElementKind.CLASS, |
| 218 declaration.name, |
| 219 NO_RETURN_TYPE, |
| 220 declaration.isAbstract, |
| 221 _isDeprecated(declaration.metadata)); |
| 222 } |
| 223 } |
| 224 |
| 225 void _addFieldSuggestions(ClassDeclaration node, FieldDeclaration fieldDecl) { |
| 226 bool isDeprecated = _isDeprecated(fieldDecl.metadata); |
| 227 fieldDecl.fields.variables.forEach((VariableDeclaration varDecl) { |
| 228 CompletionSuggestion suggestion = _addSuggestion( |
| 229 varDecl.name, |
| 230 CompletionSuggestionKind.GETTER, |
| 231 fieldDecl.fields.type, |
| 232 node); |
| 233 if (suggestion != null) { |
| 234 suggestion.element = _createElement( |
| 235 protocol.ElementKind.GETTER, |
| 236 varDecl.name, |
| 237 fieldDecl.fields.type, |
| 238 false, |
| 239 isDeprecated || _isDeprecated(varDecl.metadata)); |
| 240 } |
| 241 }); |
| 242 } |
| 243 |
| 244 void _addFunctionSuggestion(FunctionDeclaration declaration) { |
| 245 CompletionSuggestion suggestion = _addSuggestion( |
| 246 declaration.name, |
| 247 CompletionSuggestionKind.FUNCTION, |
| 248 declaration.returnType, |
| 249 null); |
| 250 if (suggestion != null) { |
| 251 suggestion.element = _createElement( |
| 252 protocol.ElementKind.FUNCTION, |
| 253 declaration.name, |
| 254 declaration.returnType, |
| 255 false, |
| 256 _isDeprecated(declaration.metadata)); |
| 257 } |
| 258 } |
| 259 |
| 260 void _addLibraryPrefixSuggestion(ImportDirective directive) { |
| 261 CompletionSuggestion suggestion = _addSuggestion( |
| 262 directive.prefix, |
| 263 CompletionSuggestionKind.LIBRARY_PREFIX, |
| 264 null, |
| 265 null); |
| 266 if (suggestion != null) { |
| 267 suggestion.element = _createElement( |
| 268 protocol.ElementKind.LIBRARY, |
| 269 directive.prefix, |
| 270 NO_RETURN_TYPE, |
| 271 false, |
| 272 false); |
| 273 } |
| 274 } |
| 275 |
| 276 void _addLocalVarSuggestion(SimpleIdentifier id, TypeName returnType) { |
| 277 CompletionSuggestion suggestion = |
| 278 _addSuggestion(id, CompletionSuggestionKind.LOCAL_VARIABLE, returnType,
null); |
| 279 if (suggestion != null) { |
| 280 suggestion.element = _createElement( |
| 281 protocol.ElementKind.LOCAL_VARIABLE, |
| 282 id, |
| 283 returnType, |
| 284 false, |
| 285 false); |
| 286 } |
| 287 } |
| 288 |
| 289 void _addMethodSuggestion(ClassDeclaration node, MethodDeclaration classMbr) { |
| 290 protocol.ElementKind kind; |
| 291 CompletionSuggestionKind csKind; |
| 292 if (classMbr.isGetter) { |
| 293 kind = protocol.ElementKind.GETTER; |
| 294 csKind = CompletionSuggestionKind.GETTER; |
| 295 } else if (classMbr.isSetter) { |
| 296 kind = protocol.ElementKind.SETTER; |
| 297 csKind = CompletionSuggestionKind.SETTER; |
| 298 } else { |
| 299 kind = protocol.ElementKind.METHOD; |
| 300 csKind = CompletionSuggestionKind.METHOD; |
| 301 } |
| 302 CompletionSuggestion suggestion = |
| 303 _addSuggestion(classMbr.name, csKind, classMbr.returnType, node); |
| 304 suggestion.element = _createElement( |
| 305 kind, |
| 306 classMbr.name, |
| 307 classMbr.returnType, |
| 308 classMbr.isAbstract, |
| 309 _isDeprecated(classMbr.metadata)); |
| 310 } |
| 311 |
227 void _addParamListSuggestions(FormalParameterList paramList) { | 312 void _addParamListSuggestions(FormalParameterList paramList) { |
228 if (paramList != null) { | 313 if (paramList != null) { |
229 paramList.parameters.forEach((FormalParameter param) { | 314 paramList.parameters.forEach((FormalParameter param) { |
230 NormalFormalParameter normalParam; | 315 NormalFormalParameter normalParam; |
231 if (param is DefaultFormalParameter) { | 316 if (param is DefaultFormalParameter) { |
232 normalParam = param.parameter; | 317 normalParam = param.parameter; |
233 } else if (param is NormalFormalParameter) { | 318 } else if (param is NormalFormalParameter) { |
234 normalParam = param; | 319 normalParam = param; |
235 } | 320 } |
236 TypeName type = null; | 321 TypeName type = null; |
237 if (normalParam is FieldFormalParameter) { | 322 if (normalParam is FieldFormalParameter) { |
238 type = normalParam.type; | 323 type = normalParam.type; |
239 } else if (normalParam is FunctionTypedFormalParameter) { | 324 } else if (normalParam is FunctionTypedFormalParameter) { |
240 type = normalParam.returnType; | 325 type = normalParam.returnType; |
241 } else if (normalParam is SimpleFormalParameter) { | 326 } else if (normalParam is SimpleFormalParameter) { |
242 type = normalParam.type; | 327 type = normalParam.type; |
243 } | 328 } |
244 _addSuggestion( | 329 _addParamSuggestion(param.identifier, type); |
245 param.identifier, | |
246 CompletionSuggestionKind.PARAMETER, | |
247 type, | |
248 null); | |
249 }); | 330 }); |
250 } | 331 } |
251 } | 332 } |
252 | 333 |
253 void _addSuggestion(SimpleIdentifier id, CompletionSuggestionKind kind, | 334 CompletionSuggestion _addParamSuggestion(SimpleIdentifier identifier, |
254 TypeName typeName, ClassDeclaration classDecl) { | 335 TypeName type) { |
| 336 CompletionSuggestion suggestion = |
| 337 _addSuggestion(identifier, CompletionSuggestionKind.PARAMETER, type, nul
l); |
| 338 if (suggestion != null) { |
| 339 suggestion.element = |
| 340 _createElement(protocol.ElementKind.PARAMETER, identifier, type, false
, false); |
| 341 } |
| 342 return suggestion; |
| 343 } |
| 344 |
| 345 CompletionSuggestion _addSuggestion(SimpleIdentifier id, |
| 346 CompletionSuggestionKind kind, TypeName typeName, ClassDeclaration classDe
cl) { |
255 if (id != null) { | 347 if (id != null) { |
256 String completion = id.name; | 348 String completion = id.name; |
257 if (completion != null && completion.length > 0) { | 349 if (completion != null && completion.length > 0) { |
258 CompletionSuggestion suggestion = new CompletionSuggestion( | 350 CompletionSuggestion suggestion = new CompletionSuggestion( |
259 kind, | 351 kind, |
260 CompletionRelevance.DEFAULT, | 352 CompletionRelevance.DEFAULT, |
261 completion, | 353 completion, |
262 completion.length, | 354 completion.length, |
263 0, | 355 0, |
264 false, | 356 false, |
(...skipping 10 matching lines...) Expand all Loading... |
275 if (typeName != null) { | 367 if (typeName != null) { |
276 Identifier identifier = typeName.name; | 368 Identifier identifier = typeName.name; |
277 if (identifier != null) { | 369 if (identifier != null) { |
278 String name = identifier.name; | 370 String name = identifier.name; |
279 if (name != null && name.length > 0) { | 371 if (name != null && name.length > 0) { |
280 suggestion.returnType = name; | 372 suggestion.returnType = name; |
281 } | 373 } |
282 } | 374 } |
283 } | 375 } |
284 request.suggestions.add(suggestion); | 376 request.suggestions.add(suggestion); |
| 377 return suggestion; |
285 } | 378 } |
286 } | 379 } |
| 380 return null; |
| 381 } |
| 382 |
| 383 void _addTopLevelVarSuggestions(VariableDeclarationList varList) { |
| 384 if (varList != null) { |
| 385 bool isDeprecated = _isDeprecated(varList.metadata); |
| 386 varList.variables.forEach((VariableDeclaration varDecl) { |
| 387 CompletionSuggestion suggestion = _addSuggestion( |
| 388 varDecl.name, |
| 389 CompletionSuggestionKind.TOP_LEVEL_VARIABLE, |
| 390 varList.type, |
| 391 null); |
| 392 if (suggestion != null) { |
| 393 suggestion.element = _createElement( |
| 394 protocol.ElementKind.TOP_LEVEL_VARIABLE, |
| 395 varDecl.name, |
| 396 varList.type, |
| 397 false, |
| 398 isDeprecated || _isDeprecated(varDecl.metadata)); |
| 399 } |
| 400 }); |
| 401 } |
287 } | 402 } |
288 | 403 |
289 void _addVarListSuggestions(VariableDeclarationList variables, | 404 /** |
290 CompletionSuggestionKind kind, ClassDeclaration classDecl) { | 405 * Create a new protocol Element for inclusion in a completion suggestion. |
291 variables.variables.forEach((VariableDeclaration varDecl) { | 406 */ |
292 _addSuggestion(varDecl.name, kind, variables.type, classDecl); | 407 protocol.Element _createElement(protocol.ElementKind kind, |
293 }); | 408 SimpleIdentifier id, TypeName returnType, bool isAbstract, bool isDeprecat
ed) { |
| 409 String name = id.name; |
| 410 int flags = protocol.Element.makeFlags( |
| 411 isAbstract: isAbstract, |
| 412 isDeprecated: isDeprecated, |
| 413 isPrivate: Identifier.isPrivateName(name)); |
| 414 return new protocol.Element( |
| 415 kind, |
| 416 name, |
| 417 flags, |
| 418 returnType: _nameForType(returnType)); |
| 419 } |
| 420 |
| 421 /** |
| 422 * Return `true` if the @deprecated annotation is present |
| 423 */ |
| 424 bool _isDeprecated(NodeList<Annotation> metadata) => |
| 425 metadata != null && |
| 426 metadata.any( |
| 427 (Annotation a) => a.name is SimpleIdentifier && a.name.name == 'de
precated'); |
| 428 |
| 429 /** |
| 430 * Return the name for the given type. |
| 431 */ |
| 432 String _nameForType(TypeName type) { |
| 433 if (type == NO_RETURN_TYPE) { |
| 434 return null; |
| 435 } |
| 436 if (type == null) { |
| 437 return DYNAMIC; |
| 438 } |
| 439 Identifier id = type.name; |
| 440 if (id == null) { |
| 441 return DYNAMIC; |
| 442 } |
| 443 String name = id.name; |
| 444 if (name == null || name.length <= 0) { |
| 445 return DYNAMIC; |
| 446 } |
| 447 TypeArgumentList typeArgs = type.typeArguments; |
| 448 if (typeArgs != null) { |
| 449 //TODO (danrubel) include type arguments |
| 450 } |
| 451 return name; |
294 } | 452 } |
295 } | 453 } |
OLD | NEW |