| Index: pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
|
| diff --git a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
|
| index 3fde4ac6c6605851259f62a4cb70c76f71fdd517..6274b4a451fe2f7427c8ba1821b7780f7f1d0f45 100644
|
| --- a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
|
| +++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
|
| @@ -12,6 +12,10 @@ import 'package:analyzer/src/generated/utilities_dart.dart';
|
|
|
| int _computeArgIndex(AstNode containingNode, Object entity) {
|
| var argList = containingNode;
|
| + if (argList is NamedExpression) {
|
| + entity = argList;
|
| + argList = argList.parent;
|
| + }
|
| if (argList is ArgumentList) {
|
| NodeList<Expression> args = argList.arguments;
|
| for (int index = 0; index < args.length; ++index) {
|
| @@ -137,13 +141,14 @@ class CompletionTarget {
|
| /**
|
| * Compute the appropriate [CompletionTarget] for the given [offset] within
|
| * the [compilationUnit].
|
| - *
|
| + *
|
| * Optionally, start the search from within [entryPoint] instead of using
|
| * the [compilationUnit], which is useful for analyzing ASTs that have no
|
| * [compilationUnit] such as dart expressions within angular templates.
|
| */
|
| factory CompletionTarget.forOffset(
|
| - CompilationUnit compilationUnit, int offset, {AstNode entryPoint}) {
|
| + CompilationUnit compilationUnit, int offset,
|
| + {AstNode entryPoint}) {
|
| // The precise algorithm is as follows. We perform a depth-first search of
|
| // all edges in the parse tree (both those that point to AST nodes and
|
| // those that point to tokens), visiting parents before children. The
|
| @@ -160,7 +165,8 @@ class CompletionTarget {
|
| // to.
|
| entryPoint ??= compilationUnit;
|
| AstNode containingNode = entryPoint;
|
| - outerLoop: while (true) {
|
| + outerLoop:
|
| + while (true) {
|
| if (containingNode is Comment) {
|
| // Comments are handled specially: we descend into any CommentReference
|
| // child node that contains the cursor offset.
|
| @@ -284,6 +290,9 @@ class CompletionTarget {
|
| return false;
|
| }
|
| AstNode parent = containingNode.parent;
|
| + if (parent is ArgumentList) {
|
| + parent = parent.parent;
|
| + }
|
| if (parent is InstanceCreationExpression) {
|
| DartType instType = parent.bestType;
|
| if (instType != null) {
|
| @@ -294,7 +303,8 @@ class CompletionTarget {
|
| ? intTypeElem.getNamedConstructor(constructorName.name)
|
| : intTypeElem.unnamedConstructor;
|
| return constructor != null &&
|
| - _isFunctionalParameter(constructor.parameters, argIndex);
|
| + _isFunctionalParameter(
|
| + constructor.parameters, argIndex, containingNode);
|
| }
|
| }
|
| } else if (parent is MethodInvocation) {
|
| @@ -302,9 +312,11 @@ class CompletionTarget {
|
| if (methodName != null) {
|
| Element methodElem = methodName.bestElement;
|
| if (methodElem is MethodElement) {
|
| - return _isFunctionalParameter(methodElem.parameters, argIndex);
|
| + return _isFunctionalParameter(
|
| + methodElem.parameters, argIndex, containingNode);
|
| } else if (methodElem is FunctionElement) {
|
| - return _isFunctionalParameter(methodElem.parameters, argIndex);
|
| + return _isFunctionalParameter(
|
| + methodElem.parameters, argIndex, containingNode);
|
| }
|
| }
|
| }
|
| @@ -317,14 +329,17 @@ class CompletionTarget {
|
| * needs to be resolved so that [isFunctionalArgument] will work.
|
| */
|
| bool maybeFunctionalArgument() {
|
| - if (argIndex == null) {
|
| - return false;
|
| - }
|
| - AstNode argList = containingNode;
|
| - if (argList is! ArgumentList) {
|
| - return false;
|
| + if (argIndex != null) {
|
| + if (containingNode is ArgumentList) {
|
| + return true;
|
| + }
|
| + if (containingNode is NamedExpression) {
|
| + if (containingNode.parent is ArgumentList) {
|
| + return true;
|
| + }
|
| + }
|
| }
|
| - return true;
|
| + return false;
|
| }
|
|
|
| /**
|
| @@ -420,18 +435,25 @@ class CompletionTarget {
|
| /**
|
| * Return `true` if the parameter is a functional parameter.
|
| */
|
| - static bool _isFunctionalParameter(
|
| - List<ParameterElement> parameters, int paramIndex) {
|
| + static bool _isFunctionalParameter(List<ParameterElement> parameters,
|
| + int paramIndex, AstNode containingNode) {
|
| + DartType paramType;
|
| if (paramIndex < parameters.length) {
|
| ParameterElement param = parameters[paramIndex];
|
| - DartType paramType = param.type;
|
| if (param.parameterKind == ParameterKind.NAMED) {
|
| - // TODO(danrubel) handle named parameters
|
| - return false;
|
| + if (containingNode is NamedExpression) {
|
| + String name = containingNode.name?.label?.name;
|
| + param = parameters.firstWhere(
|
| + (ParameterElement param) =>
|
| + param.parameterKind == ParameterKind.NAMED &&
|
| + param.name == name,
|
| + orElse: () => null);
|
| + paramType = param?.type;
|
| + }
|
| } else {
|
| - return paramType is FunctionType || paramType is FunctionTypeAlias;
|
| + paramType = param.type;
|
| }
|
| }
|
| - return false;
|
| + return paramType is FunctionType || paramType is FunctionTypeAlias;
|
| }
|
| }
|
|
|