Chromium Code Reviews| Index: pkg/analysis_server/lib/src/services/completion/completion_target.dart |
| diff --git a/pkg/analysis_server/lib/src/services/completion/completion_target.dart b/pkg/analysis_server/lib/src/services/completion/completion_target.dart |
| index 3ae98ba26d45eade0e3e4f17ca7191804e079cef..c8dc4e9f8caf65df22d1ab4fc59fddd12f71c3fc 100644 |
| --- a/pkg/analysis_server/lib/src/services/completion/completion_target.dart |
| +++ b/pkg/analysis_server/lib/src/services/completion/completion_target.dart |
| @@ -1,5 +1,23 @@ |
| import 'package:analyzer/src/generated/ast.dart'; |
| +import 'package:analyzer/src/generated/element.dart'; |
| import 'package:analyzer/src/generated/scanner.dart'; |
| +import 'package:analyzer/src/generated/utilities_dart.dart'; |
| + |
| +int _computeArgIndex(AstNode containingNode, Object entity) { |
| + var argList = containingNode; |
| + if (argList is ArgumentList) { |
| + NodeList<Expression> args = argList.arguments; |
| + for (int index = 0; index < args.length; ++index) { |
| + if (entity == args[index]) { |
| + return index; |
| + } |
| + } |
| + if (args.isEmpty) { |
| + return 0; |
| + } |
| + } |
| + return null; |
| +} |
| /** |
| * A CompletionTarget represents an edge in the parse tree which connects an |
| @@ -79,6 +97,12 @@ class CompletionTarget { |
| final Object entity; |
| /** |
| + * If the target is an argument in an [ArgumentList], then this is the index |
| + * of the argument in the list, otherwise this is `null`. |
| + */ |
| + final int argIndex; |
| + |
| + /** |
| * Compute the appropriate [CompletionTarget] for the given [offset] within |
| * the [compilationUnit]. |
| */ |
| @@ -164,7 +188,51 @@ class CompletionTarget { |
| * Create a [CompletionTarget] holding the given [containingNode] and |
| * [entity]. |
| */ |
| - CompletionTarget._(this.containingNode, this.entity); |
| + CompletionTarget._(AstNode containingNode, Object entity) |
| + : this.containingNode = containingNode, |
| + this.entity = entity, |
| + this.argIndex = _computeArgIndex(containingNode, entity); |
| + |
| + /** |
| + * Return `true` if the target is a functional argument in an argument list. |
| + * The target [AstNode] hierarchy *must* be resolved for this to work. |
| + */ |
| + bool isFunctionalArgument() { |
| + if (argIndex == null) { |
| + return false; |
| + } |
| + AstNode argList = containingNode; |
| + if (argList is! ArgumentList) { |
| + return false; |
| + } |
| + AstNode parent = argList.parent; |
| + if (parent is InstanceCreationExpression) { |
| + parent.constructorName; |
|
scheglov
2015/03/05 20:51:09
Remove this?
danrubel
2015/03/05 21:23:40
Good eyes! Done.
|
| + DartType instType = parent.bestType; |
| + if (instType != null) { |
| + Element intTypeElem = instType.element; |
| + if (intTypeElem is ClassElement) { |
| + SimpleIdentifier constructorName = parent.constructorName.name; |
| + ConstructorElement constructor = constructorName != null |
| + ? intTypeElem.getNamedConstructor(constructorName.name) |
| + : intTypeElem.unnamedConstructor; |
| + return constructor != null && |
| + _isFunctionalParameter(constructor.parameters, argIndex); |
| + } |
| + } |
| + } else if (parent is MethodInvocation) { |
| + SimpleIdentifier methodName = parent.methodName; |
| + if (methodName != null) { |
| + Element methodElem = methodName.bestElement; |
| + if (methodElem is MethodElement) { |
| + return _isFunctionalParameter(methodElem.parameters, argIndex); |
| + } else if (methodElem is FunctionElement) { |
| + return _isFunctionalParameter(methodElem.parameters, argIndex); |
| + } |
| + } |
| + } |
| + return false; |
| + } |
| /** |
| * Determine whether [node] could possibly be the [entity] for a |
| @@ -205,4 +273,22 @@ class CompletionTarget { |
| return false; |
| } |
| } |
| + |
| + /** |
| + * Return `true` if the parameter is a functional parameter. |
| + */ |
| + static bool _isFunctionalParameter( |
| + List<ParameterElement> parameters, int paramIndex) { |
| + if (paramIndex < parameters.length) { |
| + ParameterElement param = parameters[paramIndex]; |
| + DartType paramType = param.type; |
| + if (param.parameterKind == ParameterKind.NAMED) { |
| + // TODO(danrubel) handle named parameters |
| + return false; |
| + } else { |
| + return paramType is FunctionType || paramType is FunctionTypeAlias; |
| + } |
| + } |
| + return false; |
| + } |
| } |