Version 2.11.0-255.0.dev

Merge commit '4be43f44306290241c1af19296a2651c92404d97' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/accessor.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/accessor.dart
new file mode 100644
index 0000000..0d17244
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/accessor.dart
@@ -0,0 +1,136 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/fix/data_driven/parameter_reference.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+
+/// A class that can be used to access a value from a target.
+abstract class Accessor {
+  /// Return the result of using this accessor to access a value from the
+  /// [target].
+  AccessorResult getValue(Object target);
+}
+
+/// The result of using an accessor to get a result.
+abstract class AccessorResult {
+  /// Initialize a newly created result.
+  const AccessorResult();
+
+  /// Return `true` if the accessor returned a valid result.
+  bool get isValid;
+
+  /// Return the result of the accessor if it was valid.
+  ///
+  /// Throws a `StateError` if the accessor did not return a valid result.
+  Object get result;
+}
+
+/// An accessor that returns a specific argument from an argument list.
+class ArgumentAccessor extends Accessor {
+  /// The parameter corresponding to the argument from the original invocation.
+  final ParameterReference parameter;
+
+  /// Initialize a newly created accessor to access the argument that
+  /// corresponds to the given [parameter].
+  ArgumentAccessor(this.parameter) : assert(parameter != null);
+
+  @override
+  AccessorResult getValue(Object target) {
+    if (target is AstNode) {
+      var argumentList = _getArgumentList(target);
+      if (argumentList != null) {
+        var argument = parameter.argumentFrom(argumentList);
+        if (argument != null) {
+          return ValidResult(argument);
+        }
+      }
+    }
+    return const InvalidResult();
+  }
+
+  /// Return the argument list associated with the [node].
+  ArgumentList _getArgumentList(AstNode node) {
+    if (node is Annotation) {
+      return node.arguments;
+    } else if (node is ExtensionOverride) {
+      return node.argumentList;
+    } else if (node is InstanceCreationExpression) {
+      return node.argumentList;
+    } else if (node is InvocationExpression) {
+      return node.argumentList;
+    } else if (node is RedirectingConstructorInvocation) {
+      return node.argumentList;
+    } else if (node is SuperConstructorInvocation) {
+      return node.argumentList;
+    }
+    return null;
+  }
+}
+
+/// A representation of an invalid result.
+class InvalidResult implements AccessorResult {
+  /// Initialize a newly created invalid result.
+  const InvalidResult();
+
+  @override
+  bool get isValid => false;
+
+  @override
+  Object get result => throw StateError('Cannot access an invalid result');
+}
+
+/// An accessor that returns a specific type argument from a type argument list.
+class TypeArgumentAccessor extends Accessor {
+  /// The index of the type argument.
+  final int index;
+
+  /// Initialize a newly created accessor to access the type argument at the
+  /// given [index].
+  TypeArgumentAccessor(this.index) : assert(index != null);
+
+  @override
+  AccessorResult getValue(Object target) {
+    if (target is AstNode) {
+      var typeArgumentList = _getTypeArgumentList(target);
+      if (typeArgumentList != null) {
+        var arguments = typeArgumentList.arguments;
+        if (arguments.length > index) {
+          var argument = arguments[index];
+          if (argument != null) {
+            return ValidResult(argument);
+          }
+        }
+      }
+    }
+    return const InvalidResult();
+  }
+
+  /// Return the type argument list associated with the [node].
+  TypeArgumentList _getTypeArgumentList(AstNode node) {
+    if (node is ExtensionOverride) {
+      return node.typeArguments;
+    } else if (node is InstanceCreationExpression) {
+      return node.constructorName.type.typeArguments;
+    } else if (node is InvocationExpression) {
+      return node.typeArguments;
+    } else if (node is NamedType) {
+      return node.typeArguments;
+    } else if (node is TypedLiteral) {
+      return node.typeArguments;
+    }
+    return null;
+  }
+}
+
+/// A representation of a valid result.
+class ValidResult implements AccessorResult {
+  @override
+  final Object result;
+
+  /// Initialize a newly created valid result.
+  ValidResult(this.result);
+
+  @override
+  bool get isValid => true;
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/add_type_parameter.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/add_type_parameter.dart
index 936237a..6fbcad4 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/add_type_parameter.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/add_type_parameter.dart
@@ -50,7 +50,7 @@
   @override
   _Data validate(DataDrivenFix fix) {
     var node = fix.node;
-    var context = TemplateContext(node, fix.utils);
+    var context = TemplateContext(getInvocation(node), fix.utils);
     if (node is NamedType) {
       // wrong_number_of_type_arguments
       // wrong_number_of_type_arguments_constructor
@@ -101,7 +101,7 @@
 
   void _applyToTypeArguments(
       DartFileEditBuilder builder, DataDrivenFix fix, _TypeArgumentData data) {
-    var context = TemplateContext(fix.node, fix.utils);
+    var context = TemplateContext(getInvocation(fix.node), fix.utils);
     var typeArguments = data.typeArguments;
     if (typeArguments == null) {
       // Adding the first type argument.
@@ -130,7 +130,7 @@
 
   void _applyToTypeParameters(
       DartFileEditBuilder builder, DataDrivenFix fix, _TypeParameterData data) {
-    var context = TemplateContext(fix.node, fix.utils);
+    var context = TemplateContext(getInvocation(fix.node), fix.utils);
 
     void writeParameter(DartEditBuilder builder) {
       builder.write(name);
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/change.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/change.dart
index f73f6ae..39b5db6 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/change.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/change.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/src/services/correction/dart/data_driven.dart';
+import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
 
 /// The behavior common to all of the changes used to construct a transform.
@@ -12,6 +13,36 @@
   /// [validate] method.
   void apply(DartFileEditBuilder builder, DataDrivenFix fix, D data);
 
+  /// Return the invocation containing the given [node]. The invocation will be
+  /// either an instance creation expression, function invocation, method
+  /// invocation, or an extension override.
+  AstNode getInvocation(AstNode node) {
+    if (node is ArgumentList) {
+      return node.parent;
+    } else if (node is InstanceCreationExpression ||
+        node is InvocationExpression) {
+      return node;
+    } else if (node is SimpleIdentifier) {
+      var parent = node.parent;
+      if (parent is ConstructorName) {
+        var grandparent = parent.parent;
+        if (grandparent is InstanceCreationExpression) {
+          return grandparent;
+        }
+      } else if (parent is MethodInvocation && parent.methodName == node) {
+        return parent;
+      }
+    } else if (node is TypeArgumentList) {
+      var parent = node.parent;
+      if (parent is InvocationExpression) {
+        return parent;
+      } else if (parent is ExtensionOverride) {
+        return parent;
+      }
+    }
+    return null;
+  }
+
   /// Validate that this change can be applied. Return the data to be passed to
   /// [apply] if the change can be applied, or `null` if it can't be applied.
   D validate(DataDrivenFix fix);
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/modify_parameters.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/modify_parameters.dart
index a2c627e..452db16 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/modify_parameters.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/modify_parameters.dart
@@ -96,7 +96,7 @@
         builder.write(': ');
       }
       parameter.argumentValue
-          .writeOn(builder, TemplateContext(argumentList, fix.utils));
+          .writeOn(builder, TemplateContext(argumentList.parent, fix.utils));
     }
 
     var insertionRanges = argumentsToInsert.contiguousSubRanges.toList();
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
index 9632f4c..86ea95b 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analysis_server/src/services/correction/fix/data_driven/accessor.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/add_type_parameter.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/change.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/code_template.dart';
@@ -361,7 +362,8 @@
         // The error has already been reported.
         return null;
       }
-      return ArgumentExpression(PositionalParameterReference(index));
+      return CodeFragment(
+          [ArgumentAccessor(PositionalParameterReference(index))]);
     }
     var nameNode = node.valueAt(_nameKey);
     if (nameNode != null) {
@@ -372,7 +374,7 @@
         // The error has already been reported.
         return null;
       }
-      return ArgumentExpression(NamedParameterReference(name));
+      return CodeFragment([ArgumentAccessor(NamedParameterReference(name))]);
     }
     // TODO(brianwilkerson) Report the missing YAML.
     return null;
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/value_generator.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/value_generator.dart
index 3bfb639..659bb47 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/value_generator.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/value_generator.dart
@@ -2,74 +2,48 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analysis_server/src/services/correction/fix/data_driven/accessor.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/code_template.dart';
-import 'package:analysis_server/src/services/correction/fix/data_driven/parameter_reference.dart';
 import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
+import 'package:analyzer_plugin/utilities/range_factory.dart';
 
 /// Use a specified argument from an invocation as the value of a template
 /// variable.
-class ArgumentExpression extends ValueGenerator {
-  /// The parameter corresponding to the argument from the original invocation,
-  /// or `null` if the value of the argument can't be taken from the original
-  /// invocation.
-  final ParameterReference parameter;
+class CodeFragment extends ValueGenerator {
+  /// The accessor used to access the code fragment.
+  final List<Accessor> accessors;
 
-  /// Initialize a newly created extractor to extract the argument that
-  /// corresponds to the given [parameter].
-  ArgumentExpression(this.parameter) : assert(parameter != null);
+  /// Initialize a newly created extractor to extract a code fragment.
+  CodeFragment(this.accessors);
 
   @override
   bool validate(TemplateContext context) {
-    var argumentList = _getArgumentList(context.node);
-    if (argumentList == null) {
-      return false;
-    }
-    var expression = parameter.argumentFrom(argumentList);
-    if (expression != null) {
-      return false;
+    Object target = context.node;
+    for (var accessor in accessors) {
+      var result = accessor.getValue(target);
+      if (!result.isValid) {
+        return false;
+      }
+      target = result.result;
     }
     return true;
   }
 
   @override
   void writeOn(DartEditBuilder builder, TemplateContext context) {
-    var argumentList = _getArgumentList(context.node);
-    if (argumentList != null) {
-      var expression = parameter.argumentFrom(argumentList);
-      if (expression != null) {
-        builder.write(context.utils.getNodeText(expression));
-      }
+    Object target = context.node;
+    for (var accessor in accessors) {
+      target = accessor.getValue(target).result;
     }
-  }
-
-  /// Return the argument list associated with the given [node].
-  ArgumentList _getArgumentList(AstNode node) {
-    if (node is ArgumentList) {
-      return node;
-    } else if (node is InvocationExpression) {
-      return node.argumentList;
-    } else if (node is InstanceCreationExpression) {
-      return node.argumentList;
-    } else if (node is SimpleIdentifier) {
-      var parent = node.parent;
-      if (parent is ConstructorName) {
-        var grandparent = parent.parent;
-        if (grandparent is InstanceCreationExpression) {
-          return grandparent.argumentList;
-        }
-      } else if (parent is MethodInvocation && parent.methodName == node) {
-        return parent.argumentList;
-      }
-    } else if (node is TypeArgumentList) {
-      var parent = node.parent;
-      if (parent is InvocationExpression) {
-        return parent.argumentList;
-      } else if (parent is ExtensionOverride) {
-        return parent.argumentList;
-      }
+    if (target is AstNode) {
+      builder.write(context.utils.getRangeText(range.node(target)));
+    } else if (target is DartType) {
+      builder.writeType(target);
+    } else {
+      throw UnsupportedError('Unexpected result of ${target.runtimeType}');
     }
-    return null;
   }
 }
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/code_template_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/code_template_test.dart
index 4802e4a..22a45ab 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/code_template_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/code_template_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analysis_server/src/services/correction/fix/data_driven/accessor.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/code_template.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/parameter_reference.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/value_generator.dart';
@@ -90,6 +91,6 @@
 
   TemplateText _text(String text) => TemplateText(text);
 
-  TemplateVariable _variable(int index) =>
-      TemplateVariable(ArgumentExpression(PositionalParameterReference(index)));
+  TemplateVariable _variable(int index) => TemplateVariable(
+      CodeFragment([ArgumentAccessor(PositionalParameterReference(index))]));
 }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
index 84bd57b..0e526cb 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analysis_server/src/services/correction/fix/data_driven/accessor.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/add_type_parameter.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/code_template.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/element_matcher.dart';
@@ -63,8 +64,7 @@
     expect(modification.isPositional, false);
     var components = modification.argumentValue.components;
     expect(components, hasLength(1));
-    var value =
-        (components[0] as TemplateVariable).generator as ArgumentExpression;
+    var value = _accessor(components[0]) as ArgumentAccessor;
     var parameter = value.parameter as PositionalParameterReference;
     expect(parameter.index, 1);
   }
@@ -135,8 +135,7 @@
     expect(modification.isPositional, false);
     var components = modification.argumentValue.components;
     expect(components, hasLength(1));
-    var value =
-        (components[0] as TemplateVariable).generator as ArgumentExpression;
+    var value = _accessor(components[0]) as ArgumentAccessor;
     var parameter = value.parameter as PositionalParameterReference;
     expect(parameter.index, 1);
   }
@@ -177,8 +176,7 @@
     expect(modification.isPositional, true);
     var components = modification.argumentValue.components;
     expect(components, hasLength(1));
-    var value =
-        (components[0] as TemplateVariable).generator as ArgumentExpression;
+    var value = _accessor(components[0]) as ArgumentAccessor;
     var parameter = value.parameter as PositionalParameterReference;
     expect(parameter.index, 1);
   }
@@ -222,13 +220,11 @@
     expect(modification.isPositional, true);
     var components = modification.argumentValue.components;
     expect(components, hasLength(4));
-    var extractorA =
-        (components[0] as TemplateVariable).generator as ArgumentExpression;
+    var extractorA = _accessor(components[0]) as ArgumentAccessor;
     var parameterA = extractorA.parameter as PositionalParameterReference;
     expect(parameterA.index, 1);
     expect((components[1] as TemplateText).text, '(');
-    var extractorB =
-        (components[2] as TemplateVariable).generator as ArgumentExpression;
+    var extractorB = _accessor(components[2]) as ArgumentAccessor;
     var parameterB = extractorB.parameter as PositionalParameterReference;
     expect(parameterB.index, 2);
     expect((components[3] as TemplateText).text, ')');
@@ -304,8 +300,7 @@
 
     var components = change.argumentValue.components;
     expect(components, hasLength(1));
-    var value =
-        (components[0] as TemplateVariable).generator as ArgumentExpression;
+    var value = _accessor(components[0]) as ArgumentAccessor;
     var parameter = value.parameter as NamedParameterReference;
     expect(parameter.name, 'p');
   }
@@ -348,8 +343,7 @@
 
     var argumentComponents = change.argumentValue.components;
     expect(argumentComponents, hasLength(1));
-    var value = (argumentComponents[0] as TemplateVariable).generator
-        as ArgumentExpression;
+    var value = _accessor(argumentComponents[0]) as ArgumentAccessor;
     var parameter = value.parameter as PositionalParameterReference;
     expect(parameter.index, 2);
   }
@@ -562,6 +556,10 @@
     expect(rename.newName, 'B');
   }
 
+  /// Return the first accessor from the given [component].
+  Accessor _accessor(TemplateComponent component) =>
+      ((component as TemplateVariable).generator as CodeFragment).accessors[0];
+
   ElementMatcher _matcher(String name) =>
       ElementMatcher(importedUris: uris, name: name);
 
diff --git a/tools/VERSION b/tools/VERSION
index b4ad066..5ab24c7 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 11
 PATCH 0
-PRERELEASE 254
+PRERELEASE 255
 PRERELEASE_PATCH 0
\ No newline at end of file