Version 2.11.0-154.0.dev

Merge commit '0970586fbe2c40747da2d8abd27b85d76a24a84d' into 'dev'
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 38ffa68..885f1f1 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
@@ -20,7 +20,7 @@
 
   /// The name of the type that the type parameter extends, or `null` if the
   /// type parameter doesn't have a bound.
-  final String extendedType;
+  final CodeTemplate extendedType;
 
   /// The code template used to compute the value of the type argument.
   final CodeTemplate argumentValue;
@@ -31,7 +31,7 @@
       {@required this.index,
       @required this.name,
       @required this.argumentValue,
-      this.extendedType})
+      @required this.extendedType})
       : assert(index >= 0),
         assert(name != null),
         assert(argumentValue != null);
@@ -78,11 +78,18 @@
           typeArguments, argument, parent.argumentList.offset);
     } else if (parent is MethodDeclaration) {
       // invalid_override
+      String bound;
+      if (extendedType != null) {
+        bound = extendedType.generate(node, fix.utils);
+        if (bound == null) {
+          return null;
+        }
+      }
       var typeParameters = parent.typeParameters;
       if (_isInvalidIndex(typeParameters?.typeParameters)) {
         return null;
       }
-      return _TypeParameterData(typeParameters, parent.name.end);
+      return _TypeParameterData(typeParameters, bound, parent.name.end);
     } else if (node is TypeArgumentList && parent is ExtensionOverride) {
       // wrong_number_of_type_arguments_extension
       var argument = argumentValue.generate(node, fix.utils);
@@ -119,10 +126,8 @@
 
   void _applyToTypeParameters(
       DartFileEditBuilder builder, _TypeParameterData data) {
-    // TODO(brianwilkerson) Define a `bound` to use in the declaration of the
-    //  parameter.
     var argumentValue =
-        extendedType == null ? name : '$name extends $extendedType';
+        data.bound == null ? name : '$name extends ${data.bound}';
     var typeParameters = data.typeParameters;
     if (typeParameters == null) {
       // Adding the first type argument.
@@ -172,10 +177,14 @@
   /// or `null` if the first type parameter is being added.
   final TypeParameterList typeParameters;
 
+  /// The bound of the type parameter being added, or `null` if there is no
+  /// bound.
+  final String bound;
+
   /// The offset at which the type parameter list should be inserted if
   /// [typeParameters] is `null`.
   final int newListOffset;
 
   /// Initialize newly created data.
-  _TypeParameterData(this.typeParameters, this.newListOffset);
+  _TypeParameterData(this.typeParameters, this.bound, this.newListOffset);
 }
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 cf09db0..33fde9d 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
@@ -43,6 +43,7 @@
   static const String _elementKey = 'element';
   static const String _enumKey = 'enum';
   static const String _expressionKey = 'expression';
+  static const String _extendsKey = 'extends';
   static const String _extensionKey = 'extension';
   static const String _fieldKey = 'field';
   static const String _functionKey = 'function';
@@ -310,18 +311,24 @@
         ErrorContext(key: _indexKey, parentNode: node));
     var name = _translateString(
         node.valueAt(_nameKey), ErrorContext(key: _nameKey, parentNode: node));
-    // TODO(brianwilkerson) In order to support adding multiple type parameters
-    //  we might need to introduce a `TypeParameterModification` change, similar
-    //  to `ParameterModification`. That becomes more likely if we add support
-    //  for removing type parameters.
+    var extendedType = _translateCodeTemplate(node.valueAt(_extendsKey),
+        ErrorContext(key: _extendsKey, parentNode: node),
+        required: false);
     var argumentValue = _translateCodeTemplate(node.valueAt(_argumentValueKey),
         ErrorContext(key: _argumentValueKey, parentNode: node));
     if (index == null || name == null || argumentValue == null) {
       // The error has already been reported.
       return null;
     }
+    // TODO(brianwilkerson) In order to support adding multiple type parameters
+    //  we might need to introduce a `TypeParameterModification` change, similar
+    //  to `ParameterModification`. That becomes more likely if we add support
+    //  for removing type parameters.
     return AddTypeParameter(
-        index: index, name: name, argumentValue: argumentValue);
+        index: index,
+        name: name,
+        extendedType: extendedType,
+        argumentValue: argumentValue);
   }
 
   /// Translate the [node] into a value extractor. Return the resulting
@@ -383,7 +390,8 @@
   /// Translate the [node] into a code template. Return the resulting template,
   /// or `null` if the [node] does not represent a valid code template. If the
   /// [node] is not valid, use the [context] to report the error.
-  CodeTemplate _translateCodeTemplate(YamlNode node, ErrorContext context) {
+  CodeTemplate _translateCodeTemplate(YamlNode node, ErrorContext context,
+      {bool required = true}) {
     if (node is YamlMap) {
       CodeTemplateKind kind;
       int templateOffset;
@@ -420,7 +428,10 @@
           _extractTemplateComponents(template, extractors, templateOffset);
       return CodeTemplate(kind, components);
     } else if (node == null) {
-      return _reportMissingKey(context);
+      if (required) {
+        _reportMissingKey(context);
+      }
+      return null;
     } else {
       return _reportInvalidValue(node, context, 'Map');
     }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/add_type_parameter_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/add_type_parameter_test.dart
index b2e939d..e83eb02 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/add_type_parameter_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/add_type_parameter_test.dart
@@ -464,9 +464,10 @@
               components: components ?? ['C', 'm']),
           changes: [
             AddTypeParameter(
-                extendedType: extendedType,
                 index: index,
                 name: 'T',
+                extendedType:
+                    extendedType == null ? null : codeTemplate(extendedType),
                 argumentValue: codeTemplate('String')),
           ]);
 }
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 d366700..e634d80 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
@@ -259,6 +259,8 @@
     var change = transform.changes[0] as AddTypeParameter;
     expect(change.index, 0);
     expect(change.name, 'T');
+    expect(change.extendedType, null);
+
     var components = change.argumentValue.components;
     expect(components, hasLength(1));
     var value =
@@ -281,6 +283,8 @@
     - kind: 'addTypeParameter'
       index: 0
       name: 'T'
+      extends:
+        expression: 'Object'
       argumentValue:
         expression: '{% t %}'
         variables:
@@ -296,10 +300,15 @@
     var change = transform.changes[0] as AddTypeParameter;
     expect(change.index, 0);
     expect(change.name, 'T');
-    var components = change.argumentValue.components;
-    expect(components, hasLength(1));
-    var value =
-        (components[0] as TemplateVariable).extractor as ArgumentExtractor;
+
+    var extendsComponents = change.extendedType.components;
+    expect(extendsComponents, hasLength(1));
+    expect((extendsComponents[0] as TemplateText).text, 'Object');
+
+    var argumentComponents = change.argumentValue.components;
+    expect(argumentComponents, hasLength(1));
+    var value = (argumentComponents[0] as TemplateVariable).extractor
+        as ArgumentExtractor;
     var parameter = value.parameter as PositionalParameterReference;
     expect(parameter.index, 2);
   }
diff --git a/pkg/frontend_server/test/frontend_server_test.dart b/pkg/frontend_server/test/frontend_server_test.dart
index 90b4d5f..3bbdeb0 100644
--- a/pkg/frontend_server/test/frontend_server_test.dart
+++ b/pkg/frontend_server/test/frontend_server_test.dart
@@ -882,7 +882,7 @@
 
           file.writeAsStringSync("import 'lib.dart'; main() => foo();\n");
           inputStreamController.add('recompile ${file.path} abc\n'
-                  '${file.path}\n'
+                  '${file.uri}\n'
                   'abc\n'
               .codeUnits);
 
@@ -952,7 +952,7 @@
           var file2 = File('${tempDir.path}/bar.dart')..createSync();
           file2.writeAsStringSync("main() {}\n");
           inputStreamController.add('recompile ${file2.path} abc\n'
-                  '${file2.path}\n'
+                  '${file2.uri}\n'
                   'abc\n'
               .codeUnits);
         } else {
@@ -1059,7 +1059,7 @@
 class BarState extends State<FizzWidget> {}
 """);
           inputStreamController.add('recompile ${file.path} abc\n'
-                  '${file.path}\n'
+                  '${file.uri}\n'
                   'abc\n'
               .codeUnits);
         } else if (count == 1) {
@@ -1092,7 +1092,7 @@
 class BarState extends State<FizzWidget> {}
 """);
           inputStreamController.add('recompile ${file.path} abc\n'
-                  '${file.path}\n'
+                  '${file.uri}\n'
                   'abc\n'
               .codeUnits);
         } else if (count == 2) {
@@ -1126,7 +1126,7 @@
 }
 """);
           inputStreamController.add('recompile ${file.path} abc\n'
-                  '${file.path}\n'
+                  '${file.uri}\n'
                   'abc\n'
               .codeUnits);
         } else if (count == 3) {
@@ -1162,7 +1162,7 @@
 }
 """);
           inputStreamController.add('recompile ${file.path} abc\n'
-                  '${file.path}\n'
+                  '${file.uri}\n'
                   'abc\n'
               .codeUnits);
         } else if (count == 4) {
@@ -1257,7 +1257,7 @@
             inputStreamController.add('reset\n'.codeUnits);
 
             inputStreamController.add('recompile ${fileB.path} abc\n'
-                    '${fileB.path}\n'
+                    '${fileB.uri}\n'
                     'abc\n'
                 .codeUnits);
             break;
@@ -1363,7 +1363,7 @@
             inputStreamController.add('reset\n'.codeUnits);
 
             inputStreamController.add('recompile ${fileB.path} abc\n'
-                    '${fileB.path}\n'
+                    '${fileB.uri}\n'
                     'abc\n'
                 .codeUnits);
             break;
diff --git a/tools/VERSION b/tools/VERSION
index 2a1170e..cc9e234 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 11
 PATCH 0
-PRERELEASE 153
+PRERELEASE 154
 PRERELEASE_PATCH 0
\ No newline at end of file