| 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;
|
| + // 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);
|
| }
|
|
|
|
|