| 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/plugin/protocol/protocol.dart' as protocol | |
| 10 show Element, ElementKind; | |
| 11 import 'package:analysis_server/plugin/protocol/protocol.dart' | |
| 12 hide Element, ElementKind; | |
| 13 import 'package:analysis_server/src/services/completion/dart_completion_manager.
dart'; | |
| 14 import 'package:analysis_server/src/services/completion/local_declaration_visito
r.dart'; | |
| 15 import 'package:analysis_server/src/services/completion/local_suggestion_builder
.dart'; | |
| 16 import 'package:analysis_server/src/services/completion/optype.dart'; | |
| 17 import 'package:analyzer/src/generated/ast.dart'; | |
| 18 import 'package:analyzer/src/generated/utilities_dart.dart'; | |
| 19 | |
| 20 /** | |
| 21 * A contributor for calculating `completion.getSuggestions` request results | |
| 22 * for the local library in which the completion is requested. | |
| 23 */ | |
| 24 class LocalReferenceContributor extends DartCompletionContributor { | |
| 25 @override | |
| 26 bool computeFast(DartCompletionRequest request) { | |
| 27 // Don't suggest in comments. | |
| 28 if (request.target.isCommentText) { | |
| 29 return true; | |
| 30 } | |
| 31 | |
| 32 OpType optype = request.optype; | |
| 33 | |
| 34 // Collect suggestions from the specific child [AstNode] that contains | |
| 35 // the completion offset and all of its parents recursively. | |
| 36 if (!optype.isPrefixed) { | |
| 37 if (optype.includeReturnValueSuggestions || | |
| 38 optype.includeTypeNameSuggestions || | |
| 39 optype.includeVoidReturnSuggestions) { | |
| 40 _LocalVisitor localVisitor = | |
| 41 new _LocalVisitor(request, request.offset, optype); | |
| 42 localVisitor.visit(request.target.containingNode); | |
| 43 } | |
| 44 } | |
| 45 | |
| 46 // If target is an argument in an argument list | |
| 47 // then suggestions may need to be adjusted | |
| 48 return request.target.argIndex == null; | |
| 49 } | |
| 50 | |
| 51 @override | |
| 52 Future<bool> computeFull(DartCompletionRequest request) { | |
| 53 _updateSuggestions(request); | |
| 54 return new Future.value(false); | |
| 55 } | |
| 56 | |
| 57 /** | |
| 58 * If target is a function argument, suggest identifiers not invocations | |
| 59 */ | |
| 60 void _updateSuggestions(DartCompletionRequest request) { | |
| 61 if (request.target.isFunctionalArgument()) { | |
| 62 request.convertInvocationsToIdentifiers(); | |
| 63 } | |
| 64 } | |
| 65 } | |
| 66 | |
| 67 /** | |
| 68 * A visitor for collecting suggestions from the most specific child [AstNode] | |
| 69 * that contains the completion offset to the [CompilationUnit]. | |
| 70 */ | |
| 71 class _LocalVisitor extends LocalDeclarationVisitor { | |
| 72 final DartCompletionRequest request; | |
| 73 final OpType optype; | |
| 74 int privateMemberRelevance = DART_RELEVANCE_DEFAULT; | |
| 75 | |
| 76 _LocalVisitor(this.request, int offset, this.optype) : super(offset) { | |
| 77 includeLocalInheritedTypes = !optype.inStaticMethodBody; | |
| 78 if (request.replacementLength > 0) { | |
| 79 var contents = request.context.getContents(request.source); | |
| 80 if (contents != null && | |
| 81 contents.data != null && | |
| 82 contents.data.startsWith('_', request.replacementOffset)) { | |
| 83 // If user typed identifier starting with '_' | |
| 84 // then do not suppress the relevance of private members | |
| 85 privateMemberRelevance = null; | |
| 86 } | |
| 87 } | |
| 88 } | |
| 89 | |
| 90 @override | |
| 91 void declaredClass(ClassDeclaration declaration) { | |
| 92 if (optype.includeTypeNameSuggestions) { | |
| 93 _addSuggestion( | |
| 94 declaration.name, NO_RETURN_TYPE, protocol.ElementKind.CLASS, | |
| 95 isAbstract: declaration.isAbstract, | |
| 96 isDeprecated: isDeprecated(declaration)); | |
| 97 } | |
| 98 } | |
| 99 | |
| 100 @override | |
| 101 void declaredClassTypeAlias(ClassTypeAlias declaration) { | |
| 102 if (optype.includeTypeNameSuggestions) { | |
| 103 _addSuggestion(declaration.name, NO_RETURN_TYPE, | |
| 104 protocol.ElementKind.CLASS_TYPE_ALIAS, | |
| 105 isAbstract: true, isDeprecated: isDeprecated(declaration)); | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 @override | |
| 110 void declaredEnum(EnumDeclaration declaration) { | |
| 111 if (optype.includeTypeNameSuggestions) { | |
| 112 _addSuggestion( | |
| 113 declaration.name, NO_RETURN_TYPE, protocol.ElementKind.ENUM, | |
| 114 isDeprecated: isDeprecated(declaration)); | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 @override | |
| 119 void declaredField(FieldDeclaration fieldDecl, VariableDeclaration varDecl) { | |
| 120 if (optype.includeReturnValueSuggestions && | |
| 121 (!optype.inStaticMethodBody || fieldDecl.isStatic)) { | |
| 122 CompletionSuggestion suggestion = | |
| 123 createFieldSuggestion(request.source, fieldDecl, varDecl); | |
| 124 if (suggestion != null) { | |
| 125 request.addSuggestion(suggestion); | |
| 126 } | |
| 127 } | |
| 128 } | |
| 129 | |
| 130 @override | |
| 131 void declaredFunction(FunctionDeclaration declaration) { | |
| 132 if (optype.includeReturnValueSuggestions || | |
| 133 optype.includeVoidReturnSuggestions) { | |
| 134 TypeName typeName = declaration.returnType; | |
| 135 protocol.ElementKind elemKind; | |
| 136 int relevance = DART_RELEVANCE_DEFAULT; | |
| 137 if (declaration.isGetter) { | |
| 138 elemKind = protocol.ElementKind.GETTER; | |
| 139 relevance = DART_RELEVANCE_LOCAL_ACCESSOR; | |
| 140 } else if (declaration.isSetter) { | |
| 141 if (!optype.includeVoidReturnSuggestions) { | |
| 142 return; | |
| 143 } | |
| 144 elemKind = protocol.ElementKind.SETTER; | |
| 145 typeName = NO_RETURN_TYPE; | |
| 146 relevance = DART_RELEVANCE_LOCAL_ACCESSOR; | |
| 147 } else { | |
| 148 if (!optype.includeVoidReturnSuggestions && _isVoid(typeName)) { | |
| 149 return; | |
| 150 } | |
| 151 elemKind = protocol.ElementKind.FUNCTION; | |
| 152 relevance = DART_RELEVANCE_LOCAL_FUNCTION; | |
| 153 } | |
| 154 _addSuggestion(declaration.name, typeName, elemKind, | |
| 155 isDeprecated: isDeprecated(declaration), | |
| 156 param: declaration.functionExpression.parameters, | |
| 157 relevance: relevance); | |
| 158 } | |
| 159 } | |
| 160 | |
| 161 @override | |
| 162 void declaredFunctionTypeAlias(FunctionTypeAlias declaration) { | |
| 163 if (optype.includeTypeNameSuggestions) { | |
| 164 // TODO (danrubel) determine parameters and return type | |
| 165 _addSuggestion(declaration.name, declaration.returnType, | |
| 166 protocol.ElementKind.FUNCTION_TYPE_ALIAS, | |
| 167 isAbstract: true, isDeprecated: isDeprecated(declaration)); | |
| 168 } | |
| 169 } | |
| 170 | |
| 171 @override | |
| 172 void declaredLabel(Label label, bool isCaseLabel) { | |
| 173 // ignored | |
| 174 } | |
| 175 | |
| 176 @override | |
| 177 void declaredLocalVar(SimpleIdentifier id, TypeName typeName) { | |
| 178 if (optype.includeReturnValueSuggestions) { | |
| 179 _addSuggestion(id, typeName, protocol.ElementKind.LOCAL_VARIABLE, | |
| 180 relevance: DART_RELEVANCE_LOCAL_VARIABLE); | |
| 181 } | |
| 182 } | |
| 183 | |
| 184 @override | |
| 185 void declaredMethod(MethodDeclaration declaration) { | |
| 186 if ((optype.includeReturnValueSuggestions || | |
| 187 optype.includeVoidReturnSuggestions) && | |
| 188 (!optype.inStaticMethodBody || declaration.isStatic)) { | |
| 189 protocol.ElementKind elemKind; | |
| 190 FormalParameterList param; | |
| 191 TypeName typeName = declaration.returnType; | |
| 192 int relevance = DART_RELEVANCE_DEFAULT; | |
| 193 if (declaration.isGetter) { | |
| 194 elemKind = protocol.ElementKind.GETTER; | |
| 195 param = null; | |
| 196 relevance = DART_RELEVANCE_LOCAL_ACCESSOR; | |
| 197 } else if (declaration.isSetter) { | |
| 198 if (!optype.includeVoidReturnSuggestions) { | |
| 199 return; | |
| 200 } | |
| 201 elemKind = protocol.ElementKind.SETTER; | |
| 202 typeName = NO_RETURN_TYPE; | |
| 203 relevance = DART_RELEVANCE_LOCAL_ACCESSOR; | |
| 204 } else { | |
| 205 if (!optype.includeVoidReturnSuggestions && _isVoid(typeName)) { | |
| 206 return; | |
| 207 } | |
| 208 elemKind = protocol.ElementKind.METHOD; | |
| 209 param = declaration.parameters; | |
| 210 relevance = DART_RELEVANCE_LOCAL_METHOD; | |
| 211 } | |
| 212 _addSuggestion(declaration.name, typeName, elemKind, | |
| 213 isAbstract: declaration.isAbstract, | |
| 214 isDeprecated: isDeprecated(declaration), | |
| 215 classDecl: declaration.parent, | |
| 216 param: param, | |
| 217 relevance: relevance); | |
| 218 } | |
| 219 } | |
| 220 | |
| 221 @override | |
| 222 void declaredParam(SimpleIdentifier id, TypeName typeName) { | |
| 223 if (optype.includeReturnValueSuggestions) { | |
| 224 _addSuggestion(id, typeName, protocol.ElementKind.PARAMETER, | |
| 225 relevance: DART_RELEVANCE_PARAMETER); | |
| 226 } | |
| 227 } | |
| 228 | |
| 229 @override | |
| 230 void declaredTopLevelVar( | |
| 231 VariableDeclarationList varList, VariableDeclaration varDecl) { | |
| 232 if (optype.includeReturnValueSuggestions) { | |
| 233 _addSuggestion( | |
| 234 varDecl.name, varList.type, protocol.ElementKind.TOP_LEVEL_VARIABLE, | |
| 235 isDeprecated: isDeprecated(varList) || isDeprecated(varDecl), | |
| 236 relevance: DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE); | |
| 237 } | |
| 238 } | |
| 239 | |
| 240 void _addParameterInfo( | |
| 241 CompletionSuggestion suggestion, FormalParameterList parameters) { | |
| 242 var paramList = parameters.parameters; | |
| 243 suggestion.parameterNames = paramList | |
| 244 .map((FormalParameter param) => param.identifier.name) | |
| 245 .toList(); | |
| 246 suggestion.parameterTypes = paramList.map((FormalParameter param) { | |
| 247 TypeName type = null; | |
| 248 if (param is DefaultFormalParameter) { | |
| 249 NormalFormalParameter child = param.parameter; | |
| 250 if (child is SimpleFormalParameter) { | |
| 251 type = child.type; | |
| 252 } else if (child is FieldFormalParameter) { | |
| 253 type = child.type; | |
| 254 } | |
| 255 } | |
| 256 if (param is SimpleFormalParameter) { | |
| 257 type = param.type; | |
| 258 } else if (param is FieldFormalParameter) { | |
| 259 type = param.type; | |
| 260 } | |
| 261 if (type == null) { | |
| 262 return 'dynamic'; | |
| 263 } | |
| 264 Identifier typeId = type.name; | |
| 265 if (typeId == null) { | |
| 266 return 'dynamic'; | |
| 267 } | |
| 268 return typeId.name; | |
| 269 }).toList(); | |
| 270 suggestion.requiredParameterCount = paramList | |
| 271 .where((FormalParameter param) => param is! DefaultFormalParameter) | |
| 272 .length; | |
| 273 suggestion.hasNamedParameters = paramList | |
| 274 .any((FormalParameter param) => param.kind == ParameterKind.NAMED); | |
| 275 } | |
| 276 | |
| 277 void _addSuggestion( | |
| 278 SimpleIdentifier id, TypeName typeName, protocol.ElementKind elemKind, | |
| 279 {bool isAbstract: false, | |
| 280 bool isDeprecated: false, | |
| 281 ClassDeclaration classDecl, | |
| 282 FormalParameterList param, | |
| 283 int relevance: DART_RELEVANCE_DEFAULT}) { | |
| 284 CompletionSuggestion suggestion = createSuggestion( | |
| 285 id, isDeprecated, relevance, typeName, | |
| 286 classDecl: classDecl); | |
| 287 if (suggestion != null) { | |
| 288 if (privateMemberRelevance != null && | |
| 289 suggestion.completion.startsWith('_')) { | |
| 290 suggestion.relevance = privateMemberRelevance; | |
| 291 } | |
| 292 request.addSuggestion(suggestion); | |
| 293 suggestion.element = createElement(request.source, elemKind, id, | |
| 294 isAbstract: isAbstract, | |
| 295 isDeprecated: isDeprecated, | |
| 296 parameters: param != null ? param.toSource() : null, | |
| 297 returnType: typeName); | |
| 298 if ((elemKind == protocol.ElementKind.METHOD || | |
| 299 elemKind == protocol.ElementKind.FUNCTION) && | |
| 300 param != null) { | |
| 301 _addParameterInfo(suggestion, param); | |
| 302 } | |
| 303 } | |
| 304 } | |
| 305 | |
| 306 bool _isVoid(TypeName returnType) { | |
| 307 if (returnType != null) { | |
| 308 Identifier id = returnType.name; | |
| 309 if (id != null && id.name == 'void') { | |
| 310 return true; | |
| 311 } | |
| 312 } | |
| 313 return false; | |
| 314 } | |
| 315 } | |
| OLD | NEW |