Chromium Code Reviews| Index: pkg/analysis_server/lib/src/services/completion/invocation_computer.dart |
| diff --git a/pkg/analysis_server/lib/src/services/completion/invocation_computer.dart b/pkg/analysis_server/lib/src/services/completion/invocation_computer.dart |
| index f6e68d5e2007a9c96ceff03b07825df6eef573d2..5f23164e8a3df33e99e4e2843404269861ac8623 100644 |
| --- a/pkg/analysis_server/lib/src/services/completion/invocation_computer.dart |
| +++ b/pkg/analysis_server/lib/src/services/completion/invocation_computer.dart |
| @@ -7,6 +7,7 @@ library services.completion.computer.dart.invocation; |
| import 'dart:async'; |
| import 'package:analysis_server/src/services/completion/dart_completion_manager.dart'; |
| +import 'package:analysis_server/src/services/completion/local_declaration_visitor.dart'; |
| import 'package:analysis_server/src/services/completion/optype.dart'; |
| import 'package:analysis_server/src/services/completion/suggestion_builder.dart'; |
| import 'package:analyzer/src/generated/ast.dart'; |
| @@ -121,6 +122,119 @@ class _InvocationAstVisitor extends GeneralizingAstVisitor<SuggestionBuilder> { |
| } |
| /** |
| + * An [AstVisitor] which looks for a declaration with the given name |
| + * and if found, tries to determine a type for that declaration. |
| + */ |
| +class _LocalBestTypeVisitor extends LocalDeclarationVisitor { |
| + |
| + /** |
| + * The name for the declaration to be found. |
| + */ |
| + final String targetName; |
| + |
| + /** |
| + * The best type for the found declaration, |
| + * or `null` if no declaration found or failed to determine a type. |
| + */ |
| + DartType typeFound; |
| + |
| + /** |
| + * Construct a new instance to search for a declaration |
| + */ |
| + _LocalBestTypeVisitor(this.targetName, int offset) : super(offset); |
| + |
| + @override |
| + void declaredClass(ClassDeclaration declaration) { |
| + if (declaration.name.name == targetName) { |
| + finished = true; |
|
scheglov
2015/02/27 17:59:13
BTW, it might be slightly more efficient to throw
danrubel
2015/02/27 18:42:00
Good point. I'll look at that in a subsequent CL.
danrubel
2015/02/27 21:05:09
https://codereview.chromium.org/967643002/
|
| + // no type |
| + } |
| + } |
| + |
| + @override |
| + void declaredClassTypeAlias(ClassTypeAlias declaration) { |
| + if (declaration.name.name == targetName) { |
| + finished = true; |
| + // no type |
| + } |
| + } |
| + |
| + @override |
| + void declaredField(FieldDeclaration fieldDecl, VariableDeclaration varDecl) { |
| + if (varDecl.name.name == targetName) { |
| + finished = true; |
| + // Type provided by the element in computeFull above |
| + } |
| + } |
| + |
| + @override |
| + void declaredFunction(FunctionDeclaration declaration) { |
| + if (declaration.name.name == targetName) { |
| + finished = true; |
| + TypeName typeName = declaration.returnType; |
| + if (typeName != null) { |
| + typeFound = typeName.type; |
| + } |
| + } |
| + } |
| + |
| + @override |
| + void declaredFunctionTypeAlias(FunctionTypeAlias declaration) { |
| + if (declaration.name.name == targetName) { |
| + finished = true; |
| + TypeName typeName = declaration.returnType; |
| + if (typeName != null) { |
| + typeFound = typeName.type; |
| + } |
| + } |
| + } |
| + |
| + @override |
| + void declaredLabel(Label label, bool isCaseLabel) { |
| + if (label.label.name == targetName) { |
| + finished = true; |
| + // no type |
| + } |
| + } |
| + |
| + @override |
| + void declaredLocalVar(SimpleIdentifier name, TypeName type) { |
| + if (name.name == targetName) { |
| + finished = true; |
| + typeFound = name.bestType; |
| + } |
| + } |
| + |
| + @override |
| + void declaredMethod(MethodDeclaration declaration) { |
| + if (declaration.name.name == targetName) { |
| + finished = true; |
| + TypeName typeName = declaration.returnType; |
| + if (typeName != null) { |
| + typeFound = typeName.type; |
| + } |
| + } |
| + } |
| + |
| + @override |
| + void declaredParam(SimpleIdentifier name, TypeName type) { |
| + if (name.name == targetName) { |
| + finished = true; |
| + // Type provided by the element in computeFull above |
| + } |
| + } |
| + |
| + @override |
| + void declaredTopLevelVar(VariableDeclarationList varList, |
| + VariableDeclaration varDecl) { |
| + if (varDecl.name.name == targetName) { |
| + finished = true; |
| + // Type provided by the element in computeFull above |
| + } |
| + } |
| +} |
| + |
| +/** |
| * An [Element] visitor for determining the appropriate invocation/access |
| * suggestions based upon the element for which the completion is requested. |
| */ |
| @@ -151,12 +265,25 @@ class _PrefixedIdentifierSuggestionBuilder extends |
| if (prefix != null) { |
| Element element = prefix.bestElement; |
| DartType type = prefix.bestType; |
| - if (element is! ClassElement && type != null && !type.isDynamic) { |
| - InterfaceTypeSuggestionBuilder.suggestionsFor( |
| - request, |
| - type); |
| - return new Future.value(true); |
| - } else if (element != null) { |
| + if (element is! ClassElement) { |
| + if (type == null || type.isDynamic) { |
| + // |
| + // Given `g. int y = 0;`, the parser interprets `g` as a prefixed |
| + // identifier with no type. |
| + // If the user is requesting completions for `g`, |
| + // then check for a function, getter, or similar with a type. |
| + // |
| + _LocalBestTypeVisitor visitor = |
| + new _LocalBestTypeVisitor(prefix.name, request.offset); |
| + prefix.accept(visitor); |
| + type = visitor.typeFound; |
| + } |
| + if (type != null && !type.isDynamic) { |
| + InterfaceTypeSuggestionBuilder.suggestionsFor(request, type); |
| + return new Future.value(true); |
| + } |
| + } |
| + if (element != null) { |
| return element.accept(this); |
| } |
| } |
| @@ -188,7 +315,7 @@ class _PrefixedIdentifierSuggestionBuilder extends |
| // once that accessor is implemented and available in Dart |
| bool modified = false; |
| // Find the import directive with the given prefix |
| - request.unit.directives.forEach((Directive directive) { |
| + for (Directive directive in request.unit.directives) { |
| if (directive is ImportDirective) { |
| if (directive.prefix != null) { |
| if (directive.prefix.name == element.name) { |
| @@ -202,7 +329,7 @@ class _PrefixedIdentifierSuggestionBuilder extends |
| } |
| } |
| } |
| - }); |
| + }; |
| return new Future.value(modified); |
| } |