Compute 'executableElement' and 'parameterElement' in CompletionTarget.

R=brianwilkerson@google.com

Change-Id: I58904548a034cf927d9205bdbba3be9014c49328
Reviewed-on: https://dart-review.googlesource.com/c/92539
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
index b53b2d2..4c4b692 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
@@ -32,52 +32,6 @@
 }
 
 /**
- * If the containing [node] is an argument list
- * or named expression in an argument list
- * then return the simple identifier for the method, constructor, or annotation
- * to which the argument list is associated
- */
-SimpleIdentifier _getTargetId(AstNode node) {
-  if (node is NamedExpression) {
-    return _getTargetId(node.parent);
-  }
-  if (node is ArgumentList) {
-    AstNode parent = node.parent;
-    if (parent is MethodInvocation) {
-      return parent.methodName;
-    }
-    if (parent is InstanceCreationExpression) {
-      ConstructorName constructorName = parent.constructorName;
-      if (constructorName != null) {
-        if (constructorName.name != null) {
-          return constructorName.name;
-        }
-        Identifier typeName = constructorName.type.name;
-        if (typeName is SimpleIdentifier) {
-          return typeName;
-        }
-        if (typeName is PrefixedIdentifier) {
-          return typeName.identifier;
-        }
-      }
-    }
-    if (parent is Annotation) {
-      SimpleIdentifier name = parent.constructorName;
-      if (name == null) {
-        Identifier parentName = parent.name;
-        if (parentName is SimpleIdentifier) {
-          return parentName;
-        } else if (parentName is PrefixedIdentifier) {
-          return parentName.identifier;
-        }
-      }
-      return name;
-    }
-  }
-  return null;
-}
-
-/**
  * Determine if the completion target is at the end of the list of arguments.
  */
 bool _isAppendingToArgList(DartCompletionRequest request) {
@@ -193,35 +147,13 @@
     this.request = request;
     this.suggestions = <CompletionSuggestion>[];
 
-    // Determine if the target is in an argument list
-    // for a method or a constructor or an annotation
-    SimpleIdentifier targetId = _getTargetId(request.target.containingNode);
-    if (targetId == null) {
-      return const <CompletionSuggestion>[];
-    }
-    Element elem = targetId.staticElement;
-    if (elem == null) {
+    var executable = request.target.executableElement;
+    if (executable == null) {
       return const <CompletionSuggestion>[];
     }
 
-    // Generate argument list suggestion based upon the type of element
-    if (elem is ClassElement) {
-      _addSuggestions(elem.unnamedConstructor?.parameters);
-      return suggestions;
-    }
-    if (elem is ConstructorElement) {
-      _addSuggestions(elem.parameters);
-      return suggestions;
-    }
-    if (elem is FunctionElement) {
-      _addSuggestions(elem.parameters);
-      return suggestions;
-    }
-    if (elem is MethodElement) {
-      _addSuggestions(elem.parameters);
-      return suggestions;
-    }
-    return const <CompletionSuggestion>[];
+    _addSuggestions(executable.parameters);
+    return suggestions;
   }
 
   void _addDefaultParamSuggestions(Iterable<ParameterElement> parameters,
diff --git a/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart b/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
index fa3edbe..2449bb7 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
@@ -123,6 +123,19 @@
   final int argIndex;
 
   /**
+   * If the target is an argument in an [ArgumentList], then this is the
+   * invoked [ExecutableElement], otherwise this is `null`.
+   */
+  ExecutableElement _executableElement;
+
+  /**
+   * If the target is an argument in an [ArgumentList], then this is the
+   * corresponding [ParameterElement] in the invoked [ExecutableElement],
+   * otherwise this is `null`.
+   */
+  ParameterElement _parameterElement;
+
+  /**
    * Compute the appropriate [CompletionTarget] for the given [offset] within
    * the [compilationUnit].
    *
@@ -250,6 +263,38 @@
             _computeDroppedToken(containingNode, entity, offset);
 
   /**
+   * If the target is an argument in an argument list, and the invocation is
+   * resolved, return the invoked [ExecutableElement].
+   */
+  ExecutableElement get executableElement {
+    if (_executableElement == null) {
+      var argumentList = containingNode;
+      if (argumentList is NamedExpression) {
+        argumentList = argumentList.parent;
+      }
+      if (argumentList is! ArgumentList) {
+        return null;
+      }
+
+      var invocation = argumentList.parent;
+
+      Element executable;
+      if (invocation is Annotation) {
+        executable = invocation.element;
+      } else if (invocation is InstanceCreationExpression) {
+        executable = invocation.constructorName.staticElement;
+      } else if (invocation is MethodInvocation) {
+        executable = invocation.methodName.staticElement;
+      }
+
+      if (executable is ExecutableElement) {
+        _executableElement = executable;
+      }
+    }
+    return _executableElement;
+  }
+
+  /**
    * Return `true` if the [containingNode] is a cascade
    * and the completion insertion is not between the two dots.
    * For example, `..d^` and `..^d` are considered a cascade
@@ -267,6 +312,21 @@
   }
 
   /**
+   * If the target is an argument in an argument list, and the invocation is
+   * resolved, return the corresponding [ParameterElement].
+   */
+  ParameterElement get parameterElement {
+    if (_parameterElement == null) {
+      var executable = executableElement;
+      if (executable != null) {
+        _parameterElement = _getParameterElement(
+            executable.parameters, containingNode, argIndex);
+      }
+    }
+    return _parameterElement;
+  }
+
+  /**
    * Return a source range that represents the region of text that should be
    * replaced when a suggestion based on this target is selected, given that the
    * completion was requested at the given [requestOffset].
@@ -328,63 +388,9 @@
   /**
    * Return `true` if the target is a functional argument in an argument list.
    * The target [AstNode] hierarchy *must* be resolved for this to work.
-   * See [maybeFunctionalArgument].
    */
   bool isFunctionalArgument() {
-    if (!maybeFunctionalArgument()) {
-      return false;
-    }
-    AstNode parent = containingNode.parent;
-    if (parent is ArgumentList) {
-      parent = parent.parent;
-    }
-    if (parent is InstanceCreationExpression) {
-      DartType instType = parent.staticType;
-      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, containingNode);
-        }
-      }
-    } else if (parent is MethodInvocation) {
-      SimpleIdentifier methodName = parent.methodName;
-      if (methodName != null) {
-        Element methodElem = methodName.staticElement;
-        if (methodElem is MethodElement) {
-          return _isFunctionalParameter(
-              methodElem.parameters, argIndex, containingNode);
-        } else if (methodElem is FunctionElement) {
-          return _isFunctionalParameter(
-              methodElem.parameters, argIndex, containingNode);
-        }
-      }
-    }
-    return false;
-  }
-
-  /**
-   * Return `true` if the target maybe a functional argument in an argument list.
-   * This is used in determining whether the target [AstNode] hierarchy
-   * needs to be resolved so that [isFunctionalArgument] will work.
-   */
-  bool maybeFunctionalArgument() {
-    if (argIndex != null) {
-      if (containingNode is ArgumentList) {
-        return true;
-      }
-      if (containingNode is NamedExpression) {
-        if (containingNode.parent is ArgumentList) {
-          return true;
-        }
-      }
-    }
-    return false;
+    return parameterElement?.type is FunctionType;
   }
 
   static int _computeArgIndex(AstNode containingNode, Object entity) {
@@ -501,6 +507,32 @@
   }
 
   /**
+   * Return the [ParameterElement] that corresponds to the given [argumentNode]
+   * at the given [argumentIndex].
+   */
+  static ParameterElement _getParameterElement(
+    List<ParameterElement> parameters,
+    AstNode argumentNode,
+    int argumentIndex,
+  ) {
+    if (argumentNode is NamedExpression) {
+      var name = argumentNode.name?.label?.name;
+      for (var parameter in parameters) {
+        if (parameter.name == name) {
+          return parameter;
+        }
+      }
+      return null;
+    }
+
+    if (argumentIndex < parameters.length) {
+      return parameters[argumentIndex];
+    }
+
+    return null;
+  }
+
+  /**
    * Determine whether [node] could possibly be the [entity] for a
    * [CompletionTarget] associated with the given [offset].
    */
@@ -554,27 +586,4 @@
       return false;
     }
   }
-
-  /**
-   * Return `true` if the parameter is a functional parameter.
-   */
-  static bool _isFunctionalParameter(List<ParameterElement> parameters,
-      int paramIndex, AstNode containingNode) {
-    DartType paramType;
-    if (paramIndex < parameters.length) {
-      ParameterElement param = parameters[paramIndex];
-      if (param.isNamed) {
-        if (containingNode is NamedExpression) {
-          String name = containingNode.name?.label?.name;
-          param = parameters.firstWhere(
-              (ParameterElement param) => param.isNamed && param.name == name,
-              orElse: () => null);
-          paramType = param?.type;
-        }
-      } else {
-        paramType = param.type;
-      }
-    }
-    return paramType is FunctionType;
-  }
 }
diff --git a/pkg/analyzer_plugin/test/src/utilities/completion/completion_target_test.dart b/pkg/analyzer_plugin/test/src/utilities/completion/completion_target_test.dart
index be5c5f8..8d38adf 100644
--- a/pkg/analyzer_plugin/test/src/utilities/completion/completion_target_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/completion/completion_target_test.dart
@@ -4,10 +4,10 @@
 
 import 'dart:async';
 
-import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/generated/parser.dart' as analyzer;
-import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/test_utilities/find_element.dart';
 import 'package:analyzer_plugin/src/utilities/completion/completion_target.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -16,605 +16,977 @@
 
 main() {
   defineReflectiveSuite(() {
+    defineReflectiveTests(ArgumentListCompletionTargetTest);
     defineReflectiveTests(CompletionTargetTest);
   });
 }
 
 @reflectiveTest
-class CompletionTargetTest extends AbstractContextTest {
-  Source testSource;
-  int completionOffset;
-  CompletionTarget target;
+class ArgumentListCompletionTargetTest extends _Base {
+  test_Annotation_named() async {
+    await createTarget('''
+class Foo {
+  const Foo({int a, String b});
+}
 
-  bool get usingFastaParser => analyzer.Parser.useFasta;
-
-  Future<void> addTestSource(String content) async {
-    expect(completionOffset, isNull, reason: 'Call addTestSource exactly once');
-    completionOffset = content.indexOf('^');
-    expect(completionOffset, isNot(equals(-1)), reason: 'missing ^');
-    int nextOffset = content.indexOf('^', completionOffset + 1);
-    expect(nextOffset, equals(-1), reason: 'too many ^');
-    content = content.substring(0, completionOffset) +
-        content.substring(completionOffset + 1);
-    testSource = addSource('/test.dart', content);
-    ResolvedUnitResult result = await driver.getResult(testSource.fullName);
-    target = new CompletionTarget.forOffset(result.unit, completionOffset);
+@Foo(b: ^)
+main() {}
+''');
+    assertTarget(
+      '',
+      'b: ',
+      argIndex: 0,
+      expectedExecutable: 'Foo.<init>: ({a: int, b: String}) → Foo',
+      expectedParameter: 'b: String',
+    );
   }
 
-  Future<void> assertTarget(entityText, nodeText,
-      {int argIndex: null,
-      bool isFunctionalArgument: false,
-      String droppedToken}) async {
-    void assertCommon() {
-      expect(target.entity.toString(), entityText, reason: 'entity');
-      expect(target.containingNode.toString(), nodeText,
-          reason: 'containingNode');
-      expect(target.argIndex, argIndex, reason: 'argIndex');
-      expect(target.droppedToken?.toString(), droppedToken ?? isNull,
-          reason: 'droppedToken');
-    }
+  test_Annotation_positional() async {
+    await createTarget('''
+class Foo {
+  const Foo(int a);
+}
 
-    // Assert with parsed unit
-    assertCommon();
-    ResolvedUnitResult result = await driver.getResult(testSource.fullName);
-    target = new CompletionTarget.forOffset(result.unit, completionOffset);
-    // Assert more with resolved unit
-    assertCommon();
-    expect(target.isFunctionalArgument(), isFunctionalArgument);
+@Foo(^)
+main() {}
+''');
+    assertTarget(
+      ')',
+      '()',
+      argIndex: 0,
+      expectedExecutable: 'Foo.<init>: (int) → Foo',
+      expectedParameter: 'a: int',
+    );
   }
 
-  test_ArgumentList_InstanceCreationExpression() async {
-    // ArgumentList  InstanceCreationExpression  Block
-    await addTestSource('main() {new Foo(^)}');
-    await assertTarget(')', '()', argIndex: 0);
+  test_InstanceCreationExpression_explicitNew_unresolved() async {
+    await createTarget('''
+main() {
+  new Foo(^)
+}
+''');
+    assertTarget(')', '()', argIndex: 0);
   }
 
-  test_ArgumentList_InstanceCreationExpression2() async {
-    // ArgumentList  InstanceCreationExpression  Block
-    await addTestSource('main() {new Foo(a,^)}');
-    await assertTarget(')', '(a)', argIndex: 1);
+  test_InstanceCreationExpression_generic_explicitTypeArgument() async {
+    await createTarget('''
+class Foo<T> {
+  Foo(T a, T b);
+}
+
+main() {
+  Foo<int>(^)
+}
+''');
+    assertTarget(
+      ')',
+      '()',
+      argIndex: 0,
+      expectedExecutable: 'Foo.<init>: (int, int) → Foo<int>',
+      expectedParameter: 'a: int',
+    );
   }
 
-  test_ArgumentList_InstanceCreationExpression_functionArg2() async {
-    // ArgumentList  InstanceCreationExpression  Block
-    await addTestSource('main() {new B(^)} class B{B(f()){}}');
-    await assertTarget(')', '()', argIndex: 0, isFunctionalArgument: true);
+  test_InstanceCreationExpression_generic_inferredTypeArgument() async {
+    await createTarget('''
+class Foo<T> {
+  Foo(T a, T b);
+}
+
+main() {
+  Foo(false, ^)
+}
+''');
+    assertTarget(
+      ')',
+      '(false)',
+      argIndex: 1,
+      expectedExecutable: 'Foo.<init>: (bool, bool) → Foo<bool>',
+      expectedParameter: 'b: bool',
+    );
   }
 
-  test_ArgumentList_InstanceCreationExpression_functionArg3() async {
-    // ArgumentList  InstanceCreationExpression  Block
-    await addTestSource('main() {new B(1, f: ^)} class B{B(int i, {f()}){}}');
-    await assertTarget('', 'f: ', argIndex: 1, isFunctionalArgument: true);
+  test_InstanceCreationExpression_named() async {
+    await createTarget('''
+class Foo {
+  Foo({int a, String b, double c});
+}
+
+main() {
+  Foo(b: ^)
+}
+''');
+    assertTarget(
+      '',
+      'b: ',
+      argIndex: 0,
+      expectedExecutable: 'Foo.<init>: ({a: int, b: String, c: double}) → Foo',
+      expectedParameter: 'b: String',
+    );
   }
 
-  test_ArgumentList_MethodInvocation() async {
-    // ArgumentList  MethodInvocation  Block
-    await addTestSource('main() {foo(^)}');
-    await assertTarget(')', '()', argIndex: 0);
+  test_InstanceCreationExpression_named_unresolved() async {
+    await createTarget('''
+class Foo {
+  Foo({int a});
+}
+
+main() {
+  Foo(b: ^)
+}
+''');
+    assertTarget(
+      '',
+      'b: ',
+      argIndex: 0,
+      expectedExecutable: 'Foo.<init>: ({a: int}) → Foo',
+    );
   }
 
-  test_ArgumentList_MethodInvocation2() async {
-    // ArgumentList  MethodInvocation  Block
-    await addTestSource('main() {foo(^n)}');
-    await assertTarget('n', '(n)', argIndex: 0);
+  test_InstanceCreationExpression_namedConstructor() async {
+    await createTarget('''
+class Foo {
+  Foo.named(int a, String b, double c);
+}
+
+main() {
+  Foo.named(0, ^)
+}
+''');
+    assertTarget(
+      ')',
+      '(0)',
+      argIndex: 1,
+      expectedExecutable: 'Foo.named: (int, String, double) → Foo',
+      expectedParameter: 'b: String',
+    );
   }
 
-  test_ArgumentList_MethodInvocation3() async {
-    // ArgumentList  MethodInvocation  Block
-    await addTestSource('main() {foo(n^)}');
-    await assertTarget('n', '(n)', argIndex: 0);
+  test_InstanceCreationExpression_positional() async {
+    await createTarget('''
+class Foo {
+  Foo(int a);
+}
+
+main() {
+  Foo(^)
+}
+''');
+    assertTarget(
+      ')',
+      '()',
+      argIndex: 0,
+      expectedExecutable: 'Foo.<init>: (int) → Foo',
+      expectedParameter: 'a: int',
+    );
   }
 
-  test_ArgumentList_MethodInvocation3a() async {
-    // ArgumentList  MethodInvocation  Block
-    await addTestSource('main() {foo((n)^)}');
-    await assertTarget(')', '((n))', argIndex: 0);
+  test_InstanceCreationExpression_positional_isFunctional() async {
+    await createTarget('''
+class Foo {
+  Foo(int Function(String) f);
+}
+
+main() {
+  Foo(^)
+}
+''');
+    assertTarget(
+      ')',
+      '()',
+      argIndex: 0,
+      expectedExecutable: 'Foo.<init>: ((String) → int) → Foo',
+      expectedParameter: 'f: (String) → int',
+      isFunctionalArgument: true,
+    );
   }
 
-  test_ArgumentList_MethodInvocation4() async {
-    // ArgumentList  MethodInvocation  Block
-    await addTestSource('main() {foo(n,^)}');
-    await assertTarget(')', '(n)', argIndex: 1);
+  test_InstanceCreationExpression_positional_noParameter0() async {
+    await createTarget('''
+class Foo {}
+
+main() {
+  Foo(^)
+}
+''');
+    assertTarget(
+      ')',
+      '()',
+      argIndex: 0,
+      expectedExecutable: 'Foo.<init>: () → Foo',
+    );
   }
 
-  test_ArgumentList_MethodInvocation_functionArg() async {
-    // ArgumentList  MethodInvocation  Block
-    await addTestSource('main() {foo(^)} foo(f()) {}');
-    await assertTarget(')', '()', argIndex: 0, isFunctionalArgument: true);
+  test_InstanceCreationExpression_positional_noParameter1() async {
+    await createTarget('''
+class Foo {}
+
+main() {
+  Foo(a, ^)
+}
+''');
+    assertTarget(
+      ')',
+      '(a)',
+      argIndex: 1,
+      expectedExecutable: 'Foo.<init>: () → Foo',
+    );
   }
 
-  test_ArgumentList_MethodInvocation_functionArg2() async {
-    // ArgumentList  MethodInvocation  Block
-    await addTestSource('main() {new B().boo(^)} class B{boo(f()){}}');
-    await assertTarget(')', '()', argIndex: 0, isFunctionalArgument: true);
+  test_MethodInvocation_named() async {
+    await createTarget('''
+int foo({int a, String b, double c}) {}
+
+main() {
+  foo(b: ^)
+}
+''');
+    assertTarget(
+      '',
+      'b: ',
+      argIndex: 0,
+      expectedExecutable: 'foo: ({a: int, b: String, c: double}) → int',
+      expectedParameter: 'b: String',
+    );
   }
 
-  test_ArgumentList_MethodInvocation_functionArg3() async {
-    // ArgumentList  MethodInvocation  Block
-    await addTestSource('main() {foo(f: ^)} foo({f()}) {}');
-    await assertTarget('', 'f: ', argIndex: 0, isFunctionalArgument: true);
+  test_MethodInvocation_named_isFunctional() async {
+    await createTarget('''
+int foo({int Function(String) f}) {}
+
+main() {
+  foo(f: ^)
+}
+''');
+    assertTarget(
+      '',
+      'f: ',
+      argIndex: 0,
+      expectedExecutable: 'foo: ({f: (String) → int}) → int',
+      expectedParameter: 'f: (String) → int',
+      isFunctionalArgument: true,
+    );
   }
 
-  test_ArgumentList_MethodInvocation_functionArg4() async {
-    // ArgumentList  MethodInvocation  Block
-    await addTestSource('main() {new B().boo(f: ^)} class B{boo({f()}){}}');
-    await assertTarget('', 'f: ', argIndex: 0, isFunctionalArgument: true);
+  test_MethodInvocation_named_unresolved() async {
+    await createTarget('''
+int foo({int a}) {}
+
+main() {
+  foo(b: ^)
+}
+''');
+    assertTarget(
+      '',
+      'b: ',
+      argIndex: 0,
+      expectedExecutable: 'foo: ({a: int}) → int',
+    );
   }
 
+  test_MethodInvocation_positional2() async {
+    await createTarget('''
+int foo(int a, String b) {}
+
+main() {
+  foo(0, ^)
+}
+''');
+    assertTarget(
+      ')',
+      '(0)',
+      argIndex: 1,
+      expectedExecutable: 'foo: (int, String) → int',
+      expectedParameter: 'b: String',
+    );
+  }
+
+  test_MethodInvocation_positional_isFunctional() async {
+    await createTarget('''
+int foo(int Function(String) f) {}
+
+main() {
+  foo(^)
+}
+''');
+    assertTarget(
+      ')',
+      '()',
+      argIndex: 0,
+      expectedExecutable: 'foo: ((String) → int) → int',
+      expectedParameter: 'f: (String) → int',
+      isFunctionalArgument: true,
+    );
+  }
+
+  test_MethodInvocation_positional_isFunctional2() async {
+    await createTarget('''
+class C {
+  int foo(int Function(String) f) {}
+}
+
+main(C c) {
+  c.foo(^)
+}
+''');
+    assertTarget(
+      ')',
+      '()',
+      argIndex: 0,
+      expectedExecutable: 'C.foo: ((String) → int) → int',
+      expectedParameter: 'f: (String) → int',
+      isFunctionalArgument: true,
+    );
+  }
+
+  test_MethodInvocation_positional_withPrefix() async {
+    await createTarget('''
+int foo(int a, String b) {}
+
+main() {
+  foo(n^)
+}
+''');
+    assertTarget(
+      'n',
+      '(n)',
+      argIndex: 0,
+      expectedExecutable: 'foo: (int, String) → int',
+      expectedParameter: 'a: int',
+    );
+  }
+
+  test_MethodInvocation_positional_withPrefix2() async {
+    await createTarget('''
+int foo(int a, String b) {}
+
+main() {
+  foo((n)^)
+}
+''');
+    assertTarget(
+      ')',
+      '((n))',
+      argIndex: 0,
+      expectedExecutable: 'foo: (int, String) → int',
+      expectedParameter: 'a: int',
+    );
+  }
+
+  test_MethodInvocation_positional_withSuffix() async {
+    await createTarget('''
+int foo(int a, String b) {}
+
+main() {
+  foo(^n)
+}
+''');
+    assertTarget(
+      'n',
+      '(n)',
+      argIndex: 0,
+      expectedExecutable: 'foo: (int, String) → int',
+      expectedParameter: 'a: int',
+    );
+  }
+
+  test_MethodInvocation_unresolved() async {
+    await createTarget('''
+main() {
+  foo(^)
+}
+''');
+    assertTarget(')', '()', argIndex: 0);
+  }
+
+  test_not_ListLiteral() async {
+    await createTarget('''
+main() {
+  print([^]);
+}
+''');
+    expect(target.argIndex, isNull);
+    expect(target.executableElement, isNull);
+    expect(target.parameterElement, isNull);
+  }
+}
+
+@reflectiveTest
+class CompletionTargetTest extends _Base {
   test_AsExpression_identifier() async {
     // SimpleIdentifier  TypeName  AsExpression
-    await addTestSource(
+    await createTarget(
         'class A {var b; X _c; foo() {var a; (a^ as String).foo();}');
-    await assertTarget('a as String', '(a as String)');
+    assertTarget('a as String', '(a as String)');
   }
 
   test_AsExpression_keyword() async {
     // SimpleIdentifier  TypeName  AsExpression
-    await addTestSource(
+    await createTarget(
         'class A {var b; X _c; foo() {var a; (a ^as String).foo();}');
-    await assertTarget('as', 'a as String');
+    assertTarget('as', 'a as String');
   }
 
   test_AsExpression_keyword2() async {
     // SimpleIdentifier  TypeName  AsExpression
-    await addTestSource(
+    await createTarget(
         'class A {var b; X _c; foo() {var a; (a a^s String).foo();}');
-    await assertTarget('as', 'a as String');
+    assertTarget('as', 'a as String');
   }
 
   test_AsExpression_keyword3() async {
     // SimpleIdentifier  TypeName  AsExpression
-    await addTestSource(
+    await createTarget(
         'class A {var b; X _c; foo() {var a; (a as^ String).foo();}');
-    await assertTarget('as', 'a as String');
+    assertTarget('as', 'a as String');
   }
 
   test_AsExpression_type() async {
     // SimpleIdentifier  TypeName  AsExpression
-    await addTestSource(
+    await createTarget(
         'class A {var b; X _c; foo() {var a; (a as ^String).foo();}');
-    await assertTarget('String', 'a as String');
+    assertTarget('String', 'a as String');
   }
 
   test_Block() async {
     // Block
-    await addTestSource('main() {^}');
-    await assertTarget('}', '{}');
+    await createTarget('main() {^}');
+    assertTarget('}', '{}');
   }
 
   test_Block_keyword() async {
-    await addTestSource(
+    await createTarget(
         'class C { static C get instance => null; } main() {C.in^}');
-    await assertTarget('in', 'C.in');
+    assertTarget('in', 'C.in');
   }
 
   test_Block_keyword2() async {
-    await addTestSource(
+    await createTarget(
         'class C { static C get instance => null; } main() {C.i^n}');
-    await assertTarget('in', 'C.in');
+    assertTarget('in', 'C.in');
   }
 
   test_FormalParameter_partialType() async {
     // SimpleIdentifier  PrefixedIdentifier  TypeName
-    await addTestSource('foo(b.^ f) { }');
-    await assertTarget('f', 'b.f');
+    await createTarget('foo(b.^ f) { }');
+    assertTarget('f', 'b.f');
   }
 
   test_FormalParameter_partialType2() async {
     // SimpleIdentifier  PrefixedIdentifier  TypeName
-    await addTestSource('foo(b.z^ f) { }');
-    await assertTarget('z', 'b.z');
+    await createTarget('foo(b.z^ f) { }');
+    assertTarget('z', 'b.z');
   }
 
   test_FormalParameter_partialType3() async {
     // SimpleIdentifier  PrefixedIdentifier  TypeName
-    await addTestSource('foo(b.^) { }');
-    await assertTarget('', 'b.');
+    await createTarget('foo(b.^) { }');
+    assertTarget('', 'b.');
   }
 
   test_FormalParameterList() async {
     // Token  FormalParameterList  FunctionExpression
-    await addTestSource('foo(^) { }');
-    await assertTarget(')', '()');
+    await createTarget('foo(^) { }');
+    assertTarget(')', '()');
   }
 
   test_FunctionDeclaration_inLineComment() async {
     // Comment  CompilationUnit
-    await addTestSource('''
+    await createTarget('''
       // normal comment ^
       zoo(z) { } String name;''');
-    await assertTarget('// normal comment ', 'zoo(z) {} String name;');
+    assertTarget('// normal comment ', 'zoo(z) {} String name;');
   }
 
   test_FunctionDeclaration_inLineComment2() async {
     // Comment  CompilationUnit
-    await addTestSource('''
+    await createTarget('''
       // normal ^comment
       zoo(z) { } String name;''');
-    await assertTarget('// normal comment', 'zoo(z) {} String name;');
+    assertTarget('// normal comment', 'zoo(z) {} String name;');
   }
 
   test_FunctionDeclaration_inLineComment3() async {
     // Comment  CompilationUnit
-    await addTestSource('''
+    await createTarget('''
       // normal comment ^
       // normal comment 2
       zoo(z) { } String name;''');
-    await assertTarget('// normal comment ', 'zoo(z) {} String name;');
+    assertTarget('// normal comment ', 'zoo(z) {} String name;');
   }
 
   test_FunctionDeclaration_inLineComment4() async {
     // Comment  CompilationUnit
-    await addTestSource('''
+    await createTarget('''
       // normal comment
       // normal comment 2^
       zoo(z) { } String name;''');
-    await assertTarget('// normal comment 2', 'zoo(z) {} String name;');
+    assertTarget('// normal comment 2', 'zoo(z) {} String name;');
   }
 
   test_FunctionDeclaration_inLineDocComment() async {
     // Comment  FunctionDeclaration  CompilationUnit
-    await addTestSource('''
+    await createTarget('''
       /// some dartdoc ^
       zoo(z) { } String name;''');
-    await assertTarget('/// some dartdoc ', '');
+    assertTarget('/// some dartdoc ', '');
     expect(target.containingNode is Comment, isTrue);
     expect(target.containingNode.parent.toSource(), 'zoo(z) {}');
   }
 
   test_FunctionDeclaration_inLineDocComment2() async {
     // Comment  FunctionDeclaration  CompilationUnit
-    await addTestSource('''
+    await createTarget('''
       /// some ^dartdoc
       zoo(z) { } String name;''');
-    await assertTarget('/// some dartdoc', '');
+    assertTarget('/// some dartdoc', '');
     expect(target.containingNode is Comment, isTrue);
     expect(target.containingNode.parent.toSource(), 'zoo(z) {}');
   }
 
   test_FunctionDeclaration_inStarComment() async {
     // Comment  CompilationUnit
-    await addTestSource('/* ^ */ zoo(z) {} String name;');
-    await assertTarget('/*  */', 'zoo(z) {} String name;');
+    await createTarget('/* ^ */ zoo(z) {} String name;');
+    assertTarget('/*  */', 'zoo(z) {} String name;');
   }
 
   test_FunctionDeclaration_inStarComment2() async {
     // Comment  CompilationUnit
-    await addTestSource('/*  *^/ zoo(z) {} String name;');
-    await assertTarget('/*  */', 'zoo(z) {} String name;');
+    await createTarget('/*  *^/ zoo(z) {} String name;');
+    assertTarget('/*  */', 'zoo(z) {} String name;');
   }
 
   test_FunctionDeclaration_inStarDocComment() async {
     // Comment  FunctionDeclaration  CompilationUnit
-    await addTestSource('/** ^ */ zoo(z) { } String name;');
-    await assertTarget('/**  */', '');
+    await createTarget('/** ^ */ zoo(z) { } String name;');
+    assertTarget('/**  */', '');
     expect(target.containingNode is Comment, isTrue);
     expect(target.containingNode.parent.toSource(), 'zoo(z) {}');
   }
 
   test_FunctionDeclaration_inStarDocComment2() async {
     // Comment  FunctionDeclaration  CompilationUnit
-    await addTestSource('/**  *^/ zoo(z) { } String name;');
-    await assertTarget('/**  */', '');
+    await createTarget('/**  *^/ zoo(z) { } String name;');
+    assertTarget('/**  */', '');
     expect(target.containingNode is Comment, isTrue);
     expect(target.containingNode.parent.toSource(), 'zoo(z) {}');
   }
 
   test_FunctionDeclaration_returnType() async {
     // CompilationUnit
-    await addTestSource('^ zoo(z) { } String name;');
-    await assertTarget('zoo(z) {}', 'zoo(z) {} String name;');
+    await createTarget('^ zoo(z) { } String name;');
+    assertTarget('zoo(z) {}', 'zoo(z) {} String name;');
   }
 
   test_FunctionDeclaration_returnType_afterLineComment() async {
     // FunctionDeclaration  CompilationUnit
-    await addTestSource('''
+    await createTarget('''
       // normal comment
       ^ zoo(z) {} String name;''');
-    await assertTarget('zoo(z) {}', 'zoo(z) {} String name;');
+    assertTarget('zoo(z) {}', 'zoo(z) {} String name;');
   }
 
   test_FunctionDeclaration_returnType_afterLineComment2() async {
     // FunctionDeclaration  CompilationUnit
     // TOD(danrubel) left align all test source
-    await addTestSource('''
+    await createTarget('''
 // normal comment
 ^ zoo(z) {} String name;''');
-    await assertTarget('zoo(z) {}', 'zoo(z) {} String name;');
+    assertTarget('zoo(z) {}', 'zoo(z) {} String name;');
   }
 
   test_FunctionDeclaration_returnType_afterLineDocComment() async {
     // SimpleIdentifier  FunctionDeclaration  CompilationUnit
-    await addTestSource('''
+    await createTarget('''
       /// some dartdoc
       ^ zoo(z) { } String name; ''');
-    await assertTarget('zoo', 'zoo(z) {}');
+    assertTarget('zoo', 'zoo(z) {}');
   }
 
   test_FunctionDeclaration_returnType_afterLineDocComment2() async {
     // SimpleIdentifier  FunctionDeclaration  CompilationUnit
-    await addTestSource('''
+    await createTarget('''
 /// some dartdoc
 ^ zoo(z) { } String name;''');
-    await assertTarget('zoo', 'zoo(z) {}');
+    assertTarget('zoo', 'zoo(z) {}');
   }
 
   test_FunctionDeclaration_returnType_afterStarComment() async {
     // CompilationUnit
-    await addTestSource('/* */ ^ zoo(z) { } String name;');
-    await assertTarget('zoo(z) {}', 'zoo(z) {} String name;');
+    await createTarget('/* */ ^ zoo(z) { } String name;');
+    assertTarget('zoo(z) {}', 'zoo(z) {} String name;');
   }
 
   test_FunctionDeclaration_returnType_afterStarComment2() async {
     // CompilationUnit
-    await addTestSource('/* */^ zoo(z) { } String name;');
-    await assertTarget('zoo(z) {}', 'zoo(z) {} String name;');
+    await createTarget('/* */^ zoo(z) { } String name;');
+    assertTarget('zoo(z) {}', 'zoo(z) {} String name;');
   }
 
   test_FunctionDeclaration_returnType_afterStarDocComment() async {
     // FunctionDeclaration  CompilationUnit
-    await addTestSource('/** */ ^ zoo(z) { } String name;');
-    await assertTarget('zoo', 'zoo(z) {}');
+    await createTarget('/** */ ^ zoo(z) { } String name;');
+    assertTarget('zoo', 'zoo(z) {}');
   }
 
   test_FunctionDeclaration_returnType_afterStarDocComment2() async {
     // FunctionDeclaration  CompilationUnit
-    await addTestSource('/** */^ zoo(z) { } String name;');
-    await assertTarget('zoo', 'zoo(z) {}');
+    await createTarget('/** */^ zoo(z) { } String name;');
+    assertTarget('zoo', 'zoo(z) {}');
   }
 
   test_IfStatement_droppedToken() async {
     // Comment  ClassDeclaration  CompilationUnit
-    await addTestSource('main() { if (v i^) }');
+    await createTarget('main() { if (v i^) }');
     if (usingFastaParser) {
-      await assertTarget(')', 'if (v) ;', droppedToken: 'i');
+      assertTarget(')', 'if (v) ;', droppedToken: 'i');
     } else {
-      await assertTarget('i;', 'if (v) i;');
+      assertTarget('i;', 'if (v) i;');
     }
   }
 
   test_InstanceCreationExpression_identifier() async {
     // InstanceCreationExpression  ExpressionStatement  Block
-    await addTestSource('class C {foo(){var f; {var x;} new ^C();}}');
-    await assertTarget('C', 'new C()');
+    await createTarget('class C {foo(){var f; {var x;} new ^C();}}');
+    assertTarget('C', 'new C()');
   }
 
   test_InstanceCreationExpression_keyword() async {
     // InstanceCreationExpression  ExpressionStatement  Block
-    await addTestSource('class C {foo(){var f; {var x;} new^ }}');
-    await assertTarget('new ();', '{var f; {var x;} new ();}');
+    await createTarget('class C {foo(){var f; {var x;} new^ }}');
+    assertTarget('new ();', '{var f; {var x;} new ();}');
   }
 
   test_InstanceCreationExpression_keyword2() async {
     // InstanceCreationExpression  ExpressionStatement  Block
-    await addTestSource('class C {foo(){var f; {var x;} new^ C();}}');
-    await assertTarget('new C();', '{var f; {var x;} new C();}');
+    await createTarget('class C {foo(){var f; {var x;} new^ C();}}');
+    assertTarget('new C();', '{var f; {var x;} new C();}');
   }
 
   test_MapLiteralEntry() async {
     // MapLiteralEntry  MapLiteral  VariableDeclaration
-    await addTestSource('foo = {^');
+    await createTarget('foo = {^');
     // fasta scanner inserts synthetic closing '}'
-    await assertTarget('}', '{}');
+    assertTarget('}', '{}');
   }
 
   @failingTest
   test_MapLiteralEntry1() async {
     // MapLiteralEntry  MapLiteral  VariableDeclaration
-    await addTestSource('foo = {T^');
-    await assertTarget('T : ', '{T : }');
+    await createTarget('foo = {T^');
+    assertTarget('T : ', '{T : }');
   }
 
   test_MapLiteralEntry2() async {
     // SimpleIdentifier  MapLiteralEntry  MapLiteral  VariableDeclaration
-    await addTestSource('foo = {7:T^};');
-    await assertTarget('T', '7 : T');
+    await createTarget('foo = {7:T^};');
+    assertTarget('T', '7 : T');
   }
 
   test_MethodDeclaration_inLineComment() async {
     // Comment  ClassDeclaration  CompilationUnit
-    await addTestSource('''
+    await createTarget('''
       class C2 {
         // normal comment ^
         zoo(z) { } String name; }''');
-    await assertTarget(
-        '// normal comment ', 'class C2 {zoo(z) {} String name;}');
+    assertTarget('// normal comment ', 'class C2 {zoo(z) {} String name;}');
   }
 
   test_MethodDeclaration_inLineComment2() async {
     // Comment  ClassDeclaration  CompilationUnit
-    await addTestSource('''
+    await createTarget('''
       class C2 {
         // normal ^comment
         zoo(z) { } String name; }''');
-    await assertTarget(
-        '// normal comment', 'class C2 {zoo(z) {} String name;}');
+    assertTarget('// normal comment', 'class C2 {zoo(z) {} String name;}');
   }
 
   test_MethodDeclaration_inLineComment3() async {
     // Comment  ClassDeclaration  CompilationUnit
-    await addTestSource('''
+    await createTarget('''
       class C2 {
         // normal comment ^
         // normal comment 2
         zoo(z) { } String name; }''');
-    await assertTarget(
-        '// normal comment ', 'class C2 {zoo(z) {} String name;}');
+    assertTarget('// normal comment ', 'class C2 {zoo(z) {} String name;}');
   }
 
   test_MethodDeclaration_inLineComment4() async {
     // Comment  ClassDeclaration  CompilationUnit
-    await addTestSource('''
+    await createTarget('''
       class C2 {
         // normal comment
         // normal comment 2^
         zoo(z) { } String name; }''');
-    await assertTarget(
-        '// normal comment 2', 'class C2 {zoo(z) {} String name;}');
+    assertTarget('// normal comment 2', 'class C2 {zoo(z) {} String name;}');
   }
 
   test_MethodDeclaration_inLineDocComment() async {
     // Comment  MethodDeclaration  ClassDeclaration  CompilationUnit
-    await addTestSource('''
+    await createTarget('''
       class C2 {
         /// some dartdoc ^
         zoo(z) { } String name; }''');
-    await assertTarget('/// some dartdoc ', '');
+    assertTarget('/// some dartdoc ', '');
     expect(target.containingNode is Comment, isTrue);
     expect(target.containingNode.parent.toSource(), 'zoo(z) {}');
   }
 
   test_MethodDeclaration_inLineDocComment2() async {
     // Comment  MethodDeclaration  ClassDeclaration  CompilationUnit
-    await addTestSource('''
+    await createTarget('''
       class C2 {
         /// some ^dartdoc
         zoo(z) { } String name; }''');
-    await assertTarget('/// some dartdoc', '');
+    assertTarget('/// some dartdoc', '');
     expect(target.containingNode is Comment, isTrue);
     expect(target.containingNode.parent.toSource(), 'zoo(z) {}');
   }
 
   test_MethodDeclaration_inStarComment() async {
     // Comment  ClassDeclaration  CompilationUnit
-    await addTestSource('class C2 {/* ^ */ zoo(z) {} String name;}');
-    await assertTarget('/*  */', 'class C2 {zoo(z) {} String name;}');
+    await createTarget('class C2 {/* ^ */ zoo(z) {} String name;}');
+    assertTarget('/*  */', 'class C2 {zoo(z) {} String name;}');
   }
 
   test_MethodDeclaration_inStarComment2() async {
     // Comment  ClassDeclaration  CompilationUnit
-    await addTestSource('class C2 {/*  *^/ zoo(z) {} String name;}');
-    await assertTarget('/*  */', 'class C2 {zoo(z) {} String name;}');
+    await createTarget('class C2 {/*  *^/ zoo(z) {} String name;}');
+    assertTarget('/*  */', 'class C2 {zoo(z) {} String name;}');
   }
 
   test_MethodDeclaration_inStarDocComment() async {
     // Comment  MethodDeclaration  ClassDeclaration  CompilationUnit
-    await addTestSource('class C2 {/** ^ */ zoo(z) { } String name; }');
-    await assertTarget('/**  */', '');
+    await createTarget('class C2 {/** ^ */ zoo(z) { } String name; }');
+    assertTarget('/**  */', '');
     expect(target.containingNode is Comment, isTrue);
     expect(target.containingNode.parent.toSource(), 'zoo(z) {}');
   }
 
   test_MethodDeclaration_inStarDocComment2() async {
     // Comment  MethodDeclaration  ClassDeclaration  CompilationUnit
-    await addTestSource('class C2 {/**  *^/ zoo(z) { } String name; }');
-    await assertTarget('/**  */', '');
+    await createTarget('class C2 {/**  *^/ zoo(z) { } String name; }');
+    assertTarget('/**  */', '');
     expect(target.containingNode is Comment, isTrue);
     expect(target.containingNode.parent.toSource(), 'zoo(z) {}');
   }
 
   test_MethodDeclaration_returnType() async {
     // ClassDeclaration  CompilationUnit
-    await addTestSource('class C2 {^ zoo(z) { } String name; }');
-    await assertTarget('zoo(z) {}', 'class C2 {zoo(z) {} String name;}');
+    await createTarget('class C2 {^ zoo(z) { } String name; }');
+    assertTarget('zoo(z) {}', 'class C2 {zoo(z) {} String name;}');
   }
 
   test_MethodDeclaration_returnType_afterLineComment() async {
     // MethodDeclaration  ClassDeclaration  CompilationUnit
-    await addTestSource('''
+    await createTarget('''
       class C2 {
         // normal comment
         ^ zoo(z) {} String name;}''');
-    await assertTarget('zoo(z) {}', 'class C2 {zoo(z) {} String name;}');
+    assertTarget('zoo(z) {}', 'class C2 {zoo(z) {} String name;}');
   }
 
   test_MethodDeclaration_returnType_afterLineComment2() async {
     // MethodDeclaration  ClassDeclaration  CompilationUnit
     // TOD(danrubel) left align all test source
-    await addTestSource('''
+    await createTarget('''
 class C2 {
   // normal comment
 ^ zoo(z) {} String name;}''');
-    await assertTarget('zoo(z) {}', 'class C2 {zoo(z) {} String name;}');
+    assertTarget('zoo(z) {}', 'class C2 {zoo(z) {} String name;}');
   }
 
   test_MethodDeclaration_returnType_afterLineDocComment() async {
     // SimpleIdentifier  MethodDeclaration  ClassDeclaration  CompilationUnit
-    await addTestSource('''
+    await createTarget('''
       class C2 {
         /// some dartdoc
         ^ zoo(z) { } String name; }''');
-    await assertTarget('zoo', 'zoo(z) {}');
+    assertTarget('zoo', 'zoo(z) {}');
   }
 
   test_MethodDeclaration_returnType_afterLineDocComment2() async {
     // SimpleIdentifier  MethodDeclaration  ClassDeclaration  CompilationUnit
-    await addTestSource('''
+    await createTarget('''
 class C2 {
   /// some dartdoc
 ^ zoo(z) { } String name; }''');
-    await assertTarget('zoo', 'zoo(z) {}');
+    assertTarget('zoo', 'zoo(z) {}');
   }
 
   test_MethodDeclaration_returnType_afterStarComment() async {
     // ClassDeclaration  CompilationUnit
-    await addTestSource('class C2 {/* */ ^ zoo(z) { } String name; }');
-    await assertTarget('zoo(z) {}', 'class C2 {zoo(z) {} String name;}');
+    await createTarget('class C2 {/* */ ^ zoo(z) { } String name; }');
+    assertTarget('zoo(z) {}', 'class C2 {zoo(z) {} String name;}');
   }
 
   test_MethodDeclaration_returnType_afterStarComment2() async {
     // ClassDeclaration  CompilationUnit
-    await addTestSource('class C2 {/* */^ zoo(z) { } String name; }');
-    await assertTarget('zoo(z) {}', 'class C2 {zoo(z) {} String name;}');
+    await createTarget('class C2 {/* */^ zoo(z) { } String name; }');
+    assertTarget('zoo(z) {}', 'class C2 {zoo(z) {} String name;}');
   }
 
   test_MethodDeclaration_returnType_afterStarDocComment() async {
     // MethodDeclaration  ClassDeclaration  CompilationUnit
-    await addTestSource('class C2 {/** */ ^ zoo(z) { } String name; }');
-    await assertTarget('zoo', 'zoo(z) {}');
+    await createTarget('class C2 {/** */ ^ zoo(z) { } String name; }');
+    assertTarget('zoo', 'zoo(z) {}');
   }
 
   test_MethodDeclaration_returnType_afterStarDocComment2() async {
     // MethodDeclaration  ClassDeclaration  CompilationUnit
-    await addTestSource('class C2 {/** */^ zoo(z) { } String name; }');
-    await assertTarget('zoo', 'zoo(z) {}');
+    await createTarget('class C2 {/** */^ zoo(z) { } String name; }');
+    assertTarget('zoo', 'zoo(z) {}');
   }
 
   test_SwitchStatement_c() async {
     // Token('c') SwitchStatement
-    await addTestSource('main() { switch(x) {c^} }');
-    await assertTarget('}', 'switch (x) {}', droppedToken: 'c');
+    await createTarget('main() { switch(x) {c^} }');
+    assertTarget('}', 'switch (x) {}', droppedToken: 'c');
   }
 
   test_SwitchStatement_c2() async {
     // Token('c') SwitchStatement
-    await addTestSource('main() { switch(x) { c^ } }');
-    await assertTarget('}', 'switch (x) {}', droppedToken: 'c');
+    await createTarget('main() { switch(x) { c^ } }');
+    assertTarget('}', 'switch (x) {}', droppedToken: 'c');
   }
 
   test_SwitchStatement_empty() async {
     // SwitchStatement
-    await addTestSource('main() { switch(x) {^} }');
-    await assertTarget('}', 'switch (x) {}');
+    await createTarget('main() { switch(x) {^} }');
+    assertTarget('}', 'switch (x) {}');
   }
 
   test_SwitchStatement_empty2() async {
     // SwitchStatement
-    await addTestSource('main() { switch(x) { ^ } }');
-    await assertTarget('}', 'switch (x) {}');
+    await createTarget('main() { switch(x) { ^ } }');
+    assertTarget('}', 'switch (x) {}');
   }
 
   test_TypeArgumentList() async {
     // TypeName  TypeArgumentList  TypeName
-    await addTestSource('main() { C<^> c; }');
-    await assertTarget('', '<>');
+    await createTarget('main() { C<^> c; }');
+    assertTarget('', '<>');
   }
 
   test_TypeArgumentList2() async {
     // TypeName  TypeArgumentList  TypeName
-    await addTestSource('main() { C<C^> c; }');
-    await assertTarget('C', '<C>');
+    await createTarget('main() { C<C^> c; }');
+    assertTarget('C', '<C>');
   }
 
   test_VariableDeclaration_lhs_identifier_after() async {
     // VariableDeclaration  VariableDeclarationList
-    await addTestSource('main() {int b^ = 1;}');
-    await assertTarget('b = 1', 'int b = 1');
+    await createTarget('main() {int b^ = 1;}');
+    assertTarget('b = 1', 'int b = 1');
   }
 
   test_VariableDeclaration_lhs_identifier_before() async {
     // VariableDeclaration  VariableDeclarationList
-    await addTestSource('main() {int ^b = 1;}');
-    await assertTarget('b = 1', 'int b = 1');
+    await createTarget('main() {int ^b = 1;}');
+    assertTarget('b = 1', 'int b = 1');
+  }
+}
+
+class _Base extends AbstractContextTest {
+  int offset;
+  CompletionTarget target;
+  FindElement findElement;
+
+  bool get usingFastaParser => analyzer.Parser.useFasta;
+
+  void assertTarget(
+    String entityText,
+    String nodeText, {
+    int argIndex: null,
+    String droppedToken,
+    bool isFunctionalArgument: false,
+    String expectedExecutable,
+    String expectedParameter,
+  }) {
+    expect(
+      target.entity.toString(),
+      entityText,
+      reason: 'entity',
+    );
+
+    expect(
+      target.containingNode.toString(),
+      nodeText,
+      reason: 'containingNode',
+    );
+
+    expect(
+      target.argIndex,
+      argIndex,
+      reason: 'argIndex',
+    );
+
+    expect(
+      target.droppedToken?.toString(),
+      droppedToken ?? isNull,
+      reason: 'droppedToken',
+    );
+
+    var actualExecutable = target.executableElement;
+    if (expectedExecutable == null) {
+      expect(actualExecutable, isNull);
+    } else {
+      expect(_executableStr(actualExecutable), expectedExecutable);
+    }
+
+    var actualParameter = target.parameterElement;
+    if (expectedParameter == null) {
+      expect(actualParameter, isNull);
+    } else {
+      expect(_parameterStr(actualParameter), expectedParameter);
+    }
+
+    expect(target.isFunctionalArgument(), isFunctionalArgument);
+  }
+
+  Future<void> createTarget(String content) async {
+    expect(offset, isNull, reason: 'Call createTarget exactly once');
+
+    offset = content.indexOf('^');
+    expect(offset, isNot(equals(-1)), reason: 'missing ^');
+
+    int nextOffset = content.indexOf('^', offset + 1);
+    expect(nextOffset, equals(-1), reason: 'too many ^');
+
+    content = content.substring(0, offset) + content.substring(offset + 1);
+
+    var path = convertPath('/home/test/lib/test.dart');
+    newFile(path, content: content);
+
+    var result = await driver.getResult(path);
+    findElement = FindElement(result.unit);
+
+    target = new CompletionTarget.forOffset(result.unit, offset);
+  }
+
+  static String _executableNameStr(ExecutableElement executable) {
+    var executableEnclosing = executable.enclosingElement;
+    if (executableEnclosing is CompilationUnitElement) {
+      return executable.name;
+    } else if (executable is ConstructorElement) {
+      if (executable.name == '') {
+        return '${executableEnclosing.name}.<init>';
+      } else {
+        return '${executableEnclosing.name}.${executable.name}';
+      }
+    } else if (executable is MethodElement) {
+      return '${executableEnclosing.name}.${executable.name}';
+    }
+    fail('Unexpected element: $executable');
+  }
+
+  static String _executableStr(ExecutableElement element) {
+    var executableStr = _executableNameStr(element);
+
+    return '$executableStr: ${element.type}';
+  }
+
+  static String _parameterStr(ParameterElement element) {
+    return '${element.name}: ${element.type}';
   }
 }