Version 2.14.0-51.0.dev

Merge commit '3a0a196fed31cf8c03027ef8f56035a0e2532426' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 95c301c..8365209 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -54,6 +54,44 @@
     as an unsigned integer, so `a >>> b` gives the same result as
     `a.toUnsigned(32) >>> b` on the VM.
 
+*   Prior to Dart 2.14, metadata (annotations) were not permitted to be
+    specified with generic type arguments.  This restriction is lifted in Dart
+    Dart 2.14.
+
+    ```dart
+    class C<T> {
+      const C();
+    }
+    @C();      // Previously permitted.
+    @C<int>(); // Previously an error, now permitted.
+    ```
+
+*   Prior to Dart 2.14, generic function types were not permitted as arguments
+    to generic classes or functions, nor to be used as generic bounds.  This
+    restriction is lifted in Dart 2.14.
+
+    ```dart
+    T wrapWithLogging<T>(T f) {
+      if (f is void Function<T>(T x)) {
+        return <S>(S x) {
+          print("Call: f<$S>($x)");
+          var r = f<S>(x);
+          print("Return: $x");
+          return r;
+        } as T;
+      } // More cases here
+      return f;
+    }
+    void foo<T>(T x) {
+      print("Foo!");
+    }
+    void main() {
+      // Previously an error, now permitted.
+      var f = wrapWithLogging<void Function<T>(T)>(foo);
+      f<int>(3);
+    }
+    ```
+
 ## 2.13.0
 
 ### Language
diff --git a/pkg/BUILD.gn b/pkg/BUILD.gn
index 173b32f..49581b5 100644
--- a/pkg/BUILD.gn
+++ b/pkg/BUILD.gn
@@ -2,61 +2,6 @@
 # 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("../utils/create_timestamp.gni")
-
-template("make_third_party_pkg_files_stamp") {
-  assert(defined(invoker.id), "Must define the stamp file id")
-  path = rebase_path("../third_party/pkg")
-  if (defined(invoker.path)) {
-    path = invoker.path
-  }
-  id = invoker.id
-  create_timestamp_file(target_name) {
-    if (defined(invoker.pattern)) {
-      pattern = invoker.pattern
-    }
-    path = path
-    output = "$target_gen_dir/third_party_pkg_files_$id.stamp"
-  }
-}
-
-make_third_party_pkg_files_stamp("make_third_party_pkg_files_0_stamp") {
-  path = rebase_path(".")
-  id = "0"
-}
-
-make_third_party_pkg_files_stamp("make_third_party_pkg_files_1_stamp") {
-  pattern = "[a-k].*"
-  id = "1"
-}
-
-make_third_party_pkg_files_stamp("make_third_party_pkg_files_2_stamp") {
-  pattern = "[l-r].*"
-  id = "2"
-}
-
-make_third_party_pkg_files_stamp("make_third_party_pkg_files_3_stamp") {
-  pattern = "[s-z].*"
-  id = "3"
-}
-
-action("pkg_files_stamp") {
-  deps = [
-    ":make_third_party_pkg_files_0_stamp",
-    ":make_third_party_pkg_files_1_stamp",
-    ":make_third_party_pkg_files_2_stamp",
-    ":make_third_party_pkg_files_3_stamp",
-  ]
-
-  stamp0_outputs = get_target_outputs(":make_third_party_pkg_files_0_stamp")
-  stamp1_outputs = get_target_outputs(":make_third_party_pkg_files_1_stamp")
-  stamp2_outputs = get_target_outputs(":make_third_party_pkg_files_2_stamp")
-  stamp3_outputs = get_target_outputs(":make_third_party_pkg_files_3_stamp")
-
-  inputs = stamp0_outputs + stamp1_outputs + stamp2_outputs + stamp3_outputs
-
-  outputs = [ "$root_gen_dir/pkg_files.stamp" ]
-
-  script = "../tools/create_timestamp_file.py"
-  args = [ rebase_path("$root_gen_dir/pkg_files.stamp") ]
+# TODO(flutter): Remove use.
+group("pkg_files_stamp") {
 }
diff --git a/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart b/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart
index 25d3548..5e3a9c5 100644
--- a/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart
+++ b/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart
@@ -9,13 +9,17 @@
 import 'package:path/path.dart' as path;
 
 /// Return a protocol [Element] corresponding to the given [engine.Element].
-Element convertElement(engine.Element element) {
+Element convertElement(engine.Element element,
+    {required bool withNullability}) {
   var kind = convertElementToElementKind(element);
   var name = getElementDisplayName(element);
   var elementTypeParameters = _getTypeParametersString(element);
-  var aliasedType = getAliasedTypeString(element);
-  var elementParameters = _getParametersString(element);
-  var elementReturnType = getReturnTypeString(element);
+  var aliasedType =
+      getAliasedTypeString(element, withNullability: withNullability);
+  var elementParameters =
+      _getParametersString(element, withNullability: withNullability);
+  var elementReturnType =
+      getReturnTypeString(element, withNullability: withNullability);
   return Element(
     kind,
     name,
@@ -128,7 +132,8 @@
   }
 }
 
-String? _getParametersString(engine.Element element) {
+String? _getParametersString(engine.Element element,
+    {required bool withNullability}) {
   // TODO(scheglov) expose the corresponding feature from ExecutableElement
   List<engine.ParameterElement> parameters;
   if (element is engine.ExecutableElement) {
@@ -171,7 +176,7 @@
     } else if (parameter.hasRequired) {
       sb.write('@required ');
     }
-    parameter.appendToWithoutDelimiters(sb, withNullability: false);
+    parameter.appendToWithoutDelimiters(sb, withNullability: withNullability);
   }
   sb.write(closeOptionalString);
   return '(' + sb.toString() + ')';
diff --git a/pkg/analysis_server/lib/src/computer/computer_folding.dart b/pkg/analysis_server/lib/src/computer/computer_folding.dart
index ccfb4e3..4170ab6 100644
--- a/pkg/analysis_server/lib/src/computer/computer_folding.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_folding.dart
@@ -233,6 +233,14 @@
   }
 
   @override
+  void visitEnumDeclaration(EnumDeclaration node) {
+    _computer._addRegionForAnnotations(node.metadata);
+    _computer._addRegion(
+        node.leftBracket.end, node.rightBracket.offset, FoldingKind.CLASS_BODY);
+    super.visitEnumDeclaration(node);
+  }
+
+  @override
   void visitExportDirective(ExportDirective node) {
     _computer._recordDirective(node);
     super.visitExportDirective(node);
diff --git a/pkg/analysis_server/lib/src/computer/computer_hover.dart b/pkg/analysis_server/lib/src/computer/computer_hover.dart
index ab3ef83..f40542f 100644
--- a/pkg/analysis_server/lib/src/computer/computer_hover.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_hover.dart
@@ -5,6 +5,7 @@
 import 'package:analysis_server/protocol/protocol_generated.dart'
     show HoverInformation;
 import 'package:analysis_server/src/computer/computer_overrides.dart';
+import 'package:analysis_server/src/utilities/extensions/ast.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
@@ -22,10 +23,6 @@
 
   DartUnitHoverComputer(this._dartdocInfo, this._unit, this._offset);
 
-  bool get _isNonNullableByDefault {
-    return _unit.declaredElement?.library.isNonNullableByDefault ?? false;
-  }
-
   /// Returns the computed hover, maybe `null`.
   HoverInformation? compute() {
     var node = NodeLocator(_offset).searchWithin(_unit);
@@ -135,12 +132,13 @@
 
   String? _elementDisplayString(Element? element) {
     return element?.getDisplayString(
-      withNullability: _isNonNullableByDefault,
+      withNullability: _unit.isNonNullableByDefault,
     );
   }
 
   String? _typeDisplayString(DartType? type) {
-    return type?.getDisplayString(withNullability: _isNonNullableByDefault);
+    return type?.getDisplayString(
+        withNullability: _unit.isNonNullableByDefault);
   }
 
   static String? computeDocumentation(
diff --git a/pkg/analysis_server/lib/src/computer/computer_overrides.dart b/pkg/analysis_server/lib/src/computer/computer_overrides.dart
index b3e7bc3..8bf505e 100644
--- a/pkg/analysis_server/lib/src/computer/computer_overrides.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_overrides.dart
@@ -4,6 +4,7 @@
 
 import 'package:analysis_server/src/collections.dart';
 import 'package:analysis_server/src/protocol_server.dart' as proto;
+import 'package:analysis_server/src/utilities/extensions/ast.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 
@@ -57,10 +58,12 @@
       var interfaceElements = overridesResult.interfaceElements;
       if (superElements.isNotEmpty || interfaceElements.isNotEmpty) {
         var superMember = superElements.isNotEmpty
-            ? proto.newOverriddenMember_fromEngine(superElements.first)
+            ? proto.newOverriddenMember_fromEngine(superElements.first,
+                withNullability: _unit.isNonNullableByDefault)
             : null;
         var interfaceMembers = interfaceElements
-            .map((member) => proto.newOverriddenMember_fromEngine(member))
+            .map((member) => proto.newOverriddenMember_fromEngine(member,
+                withNullability: _unit.isNonNullableByDefault))
             .toList();
         _overrides.add(proto.Override(node.offset, node.length,
             superclassMember: superMember,
diff --git a/pkg/analysis_server/lib/src/computer/computer_signature.dart b/pkg/analysis_server/lib/src/computer/computer_signature.dart
index 10354b5..9eb563a 100644
--- a/pkg/analysis_server/lib/src/computer/computer_signature.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_signature.dart
@@ -4,6 +4,7 @@
 
 import 'package:analysis_server/src/computer/computer_hover.dart';
 import 'package:analysis_server/src/protocol_server.dart';
+import 'package:analysis_server/src/utilities/extensions/ast.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/dart/ast/element_locator.dart';
@@ -16,9 +17,11 @@
   final DartdocDirectiveInfo _dartdocInfo;
   final AstNode? _node;
   late ArgumentList _argumentList;
+  final bool _isNonNullableByDefault;
   DartUnitSignatureComputer(
       this._dartdocInfo, CompilationUnit _unit, int _offset)
-      : _node = NodeLocator(_offset).searchWithin(_unit);
+      : _node = NodeLocator(_offset).searchWithin(_unit),
+        _isNonNullableByDefault = _unit.isNonNullableByDefault;
 
   /// The [ArgumentList] node located by [compute].
   ArgumentList get argumentList => _argumentList;
@@ -72,7 +75,7 @@
                     ? ParameterKind.REQUIRED_NAMED
                     : ParameterKind.REQUIRED_POSITIONAL,
         param.displayName,
-        param.type.getDisplayString(withNullability: false),
+        param.type.getDisplayString(withNullability: _isNonNullableByDefault),
         defaultValue: param.defaultValueCode);
   }
 
diff --git a/pkg/analysis_server/lib/src/domains/analysis/occurrences_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/occurrences_dart.dart
index 353bbc8..d11c738 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/occurrences_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/occurrences_dart.dart
@@ -4,6 +4,7 @@
 
 import 'package:analysis_server/plugin/analysis/occurrences/occurrences_core.dart';
 import 'package:analysis_server/src/protocol_server.dart' as protocol;
+import 'package:analysis_server/src/utilities/extensions/ast.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -15,7 +16,8 @@
   unit.accept(visitor);
   visitor.elementsOffsets.forEach((engineElement, offsets) {
     var length = engineElement.nameLength;
-    var serverElement = protocol.convertElement(engineElement);
+    var serverElement = protocol.convertElement(engineElement,
+        withNullability: unit.isNonNullableByDefault);
     var occurrences = protocol.Occurrences(serverElement, offsets, length);
     collector.addOccurrences(occurrences);
   });
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
index 99357b7..5a8d94b 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
@@ -159,6 +159,11 @@
             (options != null ? options['name'] : null) ?? 'NewWidget';
         return success(refactor);
 
+      case RefactoringKind.INLINE_LOCAL_VARIABLE:
+        final refactor =
+            InlineLocalRefactoring(server.searchEngine, result, offset);
+        return success(refactor);
+
       default:
         return error(ServerErrorCodes.InvalidCommandArguments,
             'Unknown RefactoringKind $kind was supplied to $commandName');
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
index 5bbfefc..2d786af 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
@@ -409,6 +409,15 @@
         }
       }
 
+      if (shouldIncludeKind(CodeActionKind.RefactorInline)) {
+        // Inline Local Variable
+        if (InlineLocalRefactoring(server.searchEngine, unit, offset)
+            .isAvailable()) {
+          refactorActions.add(createRefactor(CodeActionKind.RefactorInline,
+              'Inline Local Variable', RefactoringKind.INLINE_LOCAL_VARIABLE));
+        }
+      }
+
       return refactorActions;
     } on InconsistentAnalysisException {
       // If an InconsistentAnalysisException occurs, it's likely the user modified
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
index 3725220..cf29def 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
@@ -215,10 +215,10 @@
           server.getDartdocDirectiveInfoFor(completionRequest.result);
       final dartCompletionRequest = await DartCompletionRequestImpl.from(
           perf, completionRequest, directiveInfo);
+      final target = dartCompletionRequest.target;
 
       if (triggerCharacter != null) {
-        if (!_triggerCharacterValid(
-            offset, triggerCharacter, dartCompletionRequest.target)) {
+        if (!_triggerCharacterValid(offset, triggerCharacter, target)) {
           return success([]);
         }
       }
@@ -256,6 +256,13 @@
           return cancelled();
         }
 
+        /// completeFunctionCalls should be suppressed if the target is an
+        /// invocation that already has an argument list, otherwise we would
+        /// insert dupes.
+        final completeFunctionCalls = _hasExistingArgList(target.entity)
+            ? false
+            : server.clientConfiguration.completeFunctionCalls;
+
         final results = serverSuggestions.map(
           (item) {
             var itemReplacementOffset =
@@ -286,8 +293,7 @@
               // https://github.com/microsoft/vscode-languageserver-node/issues/673
               includeCommitCharacters:
                   server.clientConfiguration.previewCommitCharacters,
-              completeFunctionCalls:
-                  server.clientConfiguration.completeFunctionCalls,
+              completeFunctionCalls: completeFunctionCalls,
             );
           },
         ).toList();
@@ -386,8 +392,7 @@
                       // https://github.com/microsoft/vscode-languageserver-node/issues/673
                       includeCommitCharacters:
                           server.clientConfiguration.previewCommitCharacters,
-                      completeFunctionCalls:
-                          server.clientConfiguration.completeFunctionCalls,
+                      completeFunctionCalls: completeFunctionCalls,
                     ));
             results.addAll(setResults);
           });
@@ -453,6 +458,27 @@
     return success(completionItems);
   }
 
+  /// Returns true if [node] is part of an invocation and already has an argument
+  /// list.
+  bool _hasExistingArgList(Object? node) {
+    // print^('foo');
+    if (node is ast.ExpressionStatement) {
+      node = node.expression;
+    }
+    // super.foo^();
+    if (node is ast.SimpleIdentifier) {
+      node = node.parent;
+    }
+    // new Aaaa.bar^()
+    if (node is ast.ConstructorName) {
+      node = node.parent;
+    }
+    return (node is ast.InvocationExpression &&
+            node.argumentList.length != 0) ||
+        (node is ast.InstanceCreationExpression &&
+            node.argumentList.length != 0);
+  }
+
   Iterable<CompletionItem> _pluginResultsToItems(
     LspClientCapabilities capabilities,
     LineInfo lineInfo,
diff --git a/pkg/analysis_server/lib/src/protocol_server.dart b/pkg/analysis_server/lib/src/protocol_server.dart
index 2492df0..c03f74b 100644
--- a/pkg/analysis_server/lib/src/protocol_server.dart
+++ b/pkg/analysis_server/lib/src/protocol_server.dart
@@ -46,29 +46,32 @@
   change.addEdit(file, isNewFile ? -1 : 0, edit);
 }
 
-String? getAliasedTypeString(engine.Element element) {
+String? getAliasedTypeString(engine.Element element,
+    {required bool withNullability}) {
   if (element is engine.TypeAliasElement) {
     var aliasedType = element.aliasedType;
-    return aliasedType.getDisplayString(withNullability: false);
+    return aliasedType.getDisplayString(withNullability: withNullability);
   }
   return null;
 }
 
-String? getReturnTypeString(engine.Element element) {
+String? getReturnTypeString(engine.Element element,
+    {required bool withNullability}) {
   if (element is engine.ExecutableElement) {
     if (element.kind == engine.ElementKind.SETTER) {
       return null;
     } else {
-      return element.returnType.getDisplayString(withNullability: false);
+      return element.returnType
+          .getDisplayString(withNullability: withNullability);
     }
   } else if (element is engine.VariableElement) {
     var type = element.type;
-    return type.getDisplayString(withNullability: false);
+    return type.getDisplayString(withNullability: withNullability);
   } else if (element is engine.TypeAliasElement) {
     var aliasedType = element.aliasedType;
     if (aliasedType is FunctionType) {
       var returnType = aliasedType.returnType;
-      return returnType.getDisplayString(withNullability: false);
+      return returnType.getDisplayString(withNullability: withNullability);
     }
   }
   return null;
@@ -209,8 +212,9 @@
 }
 
 /// Construct based on an element from the analyzer engine.
-OverriddenMember newOverriddenMember_fromEngine(engine.Element member) {
-  var element = convertElement(member);
+OverriddenMember newOverriddenMember_fromEngine(engine.Element member,
+    {required bool withNullability}) {
+  var element = convertElement(member, withNullability: withNullability);
   var className = member.enclosingElement!.displayName;
   return OverriddenMember(element, className);
 }
@@ -259,8 +263,9 @@
     element = element.enclosingElement.definingCompilationUnit;
   }
 
+  var withNullability = element.library?.isNonNullableByDefault ?? false;
   for (var e in element.withAncestors) {
-    path.add(convertElement(e));
+    path.add(convertElement(e, withNullability: withNullability));
   }
   return path;
 }
diff --git a/pkg/analysis_server/lib/src/search/search_domain.dart b/pkg/analysis_server/lib/src/search/search_domain.dart
index 0ae754c..ac50553 100644
--- a/pkg/analysis_server/lib/src/search/search_domain.dart
+++ b/pkg/analysis_server/lib/src/search/search_domain.dart
@@ -46,7 +46,9 @@
     var result = protocol.SearchFindElementReferencesResult();
     if (element != null) {
       result.id = searchId;
-      result.element = protocol.convertElement(element);
+      var withNullability = element.library?.isNonNullableByDefault ?? false;
+      result.element =
+          protocol.convertElement(element, withNullability: withNullability);
     }
     _sendSearchResult(request, result);
     // search elements
diff --git a/pkg/analysis_server/lib/src/search/type_hierarchy.dart b/pkg/analysis_server/lib/src/search/type_hierarchy.dart
index 422be2e..d558487 100644
--- a/pkg/analysis_server/lib/src/search/type_hierarchy.dart
+++ b/pkg/analysis_server/lib/src/search/type_hierarchy.dart
@@ -45,6 +45,8 @@
     }
   }
 
+  bool get _isNonNullableByDefault => _pivotLibrary.isNonNullableByDefault;
+
   /// Returns the computed type hierarchy, maybe `null`.
   Future<List<TypeHierarchyItem>?> compute() async {
     var pivotClass = _pivotClass;
@@ -80,9 +82,11 @@
       }
       // create a subclass item
       var subMemberElement = _findMemberElement(subElement);
-      subItem = TypeHierarchyItem(convertElement(subElement),
+      subItem = TypeHierarchyItem(
+          convertElement(subElement, withNullability: _isNonNullableByDefault),
           memberElement: subMemberElement != null
-              ? convertElement(subMemberElement)
+              ? convertElement(subMemberElement,
+                  withNullability: _isNonNullableByDefault)
               : null,
           superclass: itemId);
       var subItemId = _items.length;
@@ -116,15 +120,20 @@
       String? displayName;
       if (typeArguments != null && typeArguments.isNotEmpty) {
         var typeArgumentsStr = typeArguments
-            .map((type) => type.getDisplayString(withNullability: false))
+            .map((type) =>
+                type.getDisplayString(withNullability: _isNonNullableByDefault))
             .join(', ');
         displayName = classElement.displayName + '<' + typeArgumentsStr + '>';
       }
       var memberElement = _findMemberElement(classElement);
-      item = TypeHierarchyItem(convertElement(classElement),
+      item = TypeHierarchyItem(
+          convertElement(classElement,
+              withNullability: _isNonNullableByDefault),
           displayName: displayName,
-          memberElement:
-              memberElement != null ? convertElement(memberElement) : null);
+          memberElement: memberElement != null
+              ? convertElement(memberElement,
+                  withNullability: _isNonNullableByDefault)
+              : null);
       _elementItemMap[classElement] = item;
       itemId = _items.length;
       _items.add(item);
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
index d2ce0e3..a7062c3 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
@@ -196,6 +196,9 @@
     return _cachedContainingMemberName;
   }
 
+  bool get _isNonNullableByDefault =>
+      request.libraryElement?.isNonNullableByDefault ?? false;
+
   /// Add a suggestion for an [accessor] declared within a class or extension.
   /// If the accessor is being invoked with a target of `super`, then the
   /// [containingMemberName] should be the name of the member containing the
@@ -633,9 +636,8 @@
       required bool appendComma,
       int? replacementLength}) {
     var name = parameter.name;
-    var type = parameter.type.getDisplayString(
-        withNullability:
-            request.libraryElement?.isNonNullableByDefault ?? false);
+    var type = parameter.type
+        .getDisplayString(withNullability: _isNonNullableByDefault);
 
     var completion = name;
     if (appendColon) {
@@ -688,7 +690,8 @@
         replacementLength: replacementLength);
     if (parameter is FieldFormalParameterElement) {
       _setDocumentation(suggestion, parameter);
-      suggestion.element = convertElement(parameter);
+      suggestion.element =
+          convertElement(parameter, withNullability: _isNonNullableByDefault);
     }
     _add(suggestion);
   }
@@ -747,7 +750,8 @@
         element.hasDeprecated,
         false,
         displayText: displayText);
-    suggestion.element = protocol.convertElement(element);
+    suggestion.element = protocol.convertElement(element,
+        withNullability: _isNonNullableByDefault);
     _add(suggestion);
   }
 
@@ -1016,9 +1020,8 @@
         completion.length, 0, element.hasOrInheritsDeprecated, false);
 
     _setDocumentation(suggestion, element);
-
-    var suggestedElement =
-        suggestion.element = protocol.convertElement(element);
+    var suggestedElement = suggestion.element = protocol.convertElement(element,
+        withNullability: _isNonNullableByDefault);
     if (elementKind != null) {
       suggestedElement.kind = elementKind;
     }
@@ -1026,7 +1029,8 @@
     if (enclosingElement is ClassElement) {
       suggestion.declaringType = enclosingElement.displayName;
     }
-    suggestion.returnType = getReturnTypeString(element);
+    suggestion.returnType =
+        getReturnTypeString(element, withNullability: _isNonNullableByDefault);
     if (element is ExecutableElement && element is! PropertyAccessorElement) {
       suggestion.parameterNames = element.parameters
           .map((ParameterElement parameter) => parameter.name)
@@ -1035,8 +1039,7 @@
           element.parameters.map((ParameterElement parameter) {
         var paramType = parameter.type;
         return paramType.getDisplayString(
-            withNullability:
-                request.libraryElement?.isNonNullableByDefault ?? false);
+            withNullability: _isNonNullableByDefault);
       }).toList();
 
       var requiredParameters = element.parameters
diff --git a/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart b/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart
index 12afe4d..c7577b6 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart
@@ -164,6 +164,26 @@
     return Future.value(change);
   }
 
+  @override
+  bool isAvailable() {
+    return !_checkOffset().hasFatalError;
+  }
+
+  /// Checks if [offset] is a variable that can be inlined.
+  RefactoringStatus _checkOffset() {
+    var offsetNode = NodeLocator(offset).searchWithin(resolveResult.unit);
+    if (offsetNode is! SimpleIdentifier) {
+      return _noLocalVariableStatus();
+    }
+
+    var element = offsetNode.staticElement;
+    if (element is! LocalVariableElement) {
+      return _noLocalVariableStatus();
+    }
+
+    return RefactoringStatus();
+  }
+
   RefactoringStatus _noLocalVariableStatus() {
     return RefactoringStatus.fatal(
       'Local variable declaration or reference must be selected '
diff --git a/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart b/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
index 31e5302..23b8552 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
@@ -210,6 +210,10 @@
 
   /// Returns the name of the variable being inlined.
   String? get variableName;
+
+  /// Return `true` if refactoring is available, possibly without checking all
+  /// initial conditions.
+  bool isAvailable();
 }
 
 /// [Refactoring] to inline an [ExecutableElement].
diff --git a/pkg/analysis_server/lib/src/utilities/extensions/ast.dart b/pkg/analysis_server/lib/src/utilities/extensions/ast.dart
index af573e9..97ab036 100644
--- a/pkg/analysis_server/lib/src/utilities/extensions/ast.dart
+++ b/pkg/analysis_server/lib/src/utilities/extensions/ast.dart
@@ -87,6 +87,14 @@
   }
 }
 
+extension CompilationUnitExtension on CompilationUnit {
+  /// Is `true` if library being analyzed is non-nullable by default.
+  ///
+  /// Will return false if the AST structure has not been resolved.
+  bool get isNonNullableByDefault =>
+      declaredElement?.library.isNonNullableByDefault ?? false;
+}
+
 extension ExpressionExtensions on Expression {
   /// Return `true` if this expression is an invocation of the method `cast`
   /// from either Iterable`, `List`, `Map`, or `Set`.
diff --git a/pkg/analysis_server/test/lsp/code_actions_assists_test.dart b/pkg/analysis_server/test/lsp/code_actions_assists_test.dart
index 07a3194..65eaa13 100644
--- a/pkg/analysis_server/test/lsp/code_actions_assists_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_assists_test.dart
@@ -176,9 +176,8 @@
       },
     );
 
-    final marker = positionFromMarker(content);
     final codeActions = await getCodeActions(mainFileUri.toString(),
-        range: Range(start: marker, end: marker));
+        position: positionFromMarker(content));
     final assist = findEditAction(
         codeActions,
         CodeActionKind('refactor.flutter.wrap.generic'),
@@ -238,9 +237,8 @@
           withDocumentChangesSupport(emptyWorkspaceClientCapabilities),
     );
 
-    final marker = positionFromMarker(content);
     final codeActions = await getCodeActions(mainFileUri.toString(),
-        range: Range(start: marker, end: marker));
+        position: positionFromMarker(content));
     final assist = findEditAction(
         codeActions,
         CodeActionKind('refactor.flutter.wrap.generic'),
diff --git a/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart b/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
index 2a9e372..1d62c11 100644
--- a/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
@@ -374,10 +374,8 @@
           emptyTextDocumentClientCapabilities, [CodeActionKind.QuickFix]),
     );
 
-    final caretPos = positionFromMarker(content);
-
     final codeActions = await getCodeActions(mainFileUri.toString(),
-        range: Range(start: caretPos, end: caretPos));
+        position: positionFromMarker(content));
     final removeNnaAction = findEditActions(codeActions,
         CodeActionKind('quickfix.remove.nonNullAssertion'), "Remove the '!'");
 
diff --git a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
index 3f8055f..8d87a88 100644
--- a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
@@ -18,6 +18,7 @@
     defineReflectiveTests(ExtractMethodRefactorCodeActionsTest);
     defineReflectiveTests(ExtractWidgetRefactorCodeActionsTest);
     defineReflectiveTests(ExtractVariableRefactorCodeActionsTest);
+    defineReflectiveTests(InlineLocalVariableRefactorCodeActionsTest);
   });
 }
 
@@ -510,3 +511,37 @@
     expect(codeAction, isNull);
   }
 }
+
+@reflectiveTest
+class InlineLocalVariableRefactorCodeActionsTest
+    extends AbstractCodeActionsTest {
+  final extractVariableTitle = 'Inline Local Variable';
+
+  Future<void> test_appliesCorrectEdits() async {
+    const content = '''
+void main() {
+  var a^ = 1;
+  print(a);
+  print(a);
+  print(a);
+}
+    ''';
+    const expectedContent = '''
+void main() {
+  print(1);
+  print(1);
+  print(1);
+}
+    ''';
+    newFile(mainFilePath, content: withoutMarkers(content));
+    await initialize();
+
+    final codeActions = await getCodeActions(mainFileUri.toString(),
+        position: positionFromMarker(content));
+    final codeAction = findCommand(
+        codeActions, Commands.performRefactor, extractVariableTitle)!;
+
+    await verifyCodeActionEdits(
+        codeAction, withoutMarkers(content), expectedContent);
+  }
+}
diff --git a/pkg/analysis_server/test/lsp/completion_dart_test.dart b/pkg/analysis_server/test/lsp/completion_dart_test.dart
index d6ba22e..cb21761 100644
--- a/pkg/analysis_server/test/lsp/completion_dart_test.dart
+++ b/pkg/analysis_server/test/lsp/completion_dart_test.dart
@@ -24,6 +24,34 @@
 @reflectiveTest
 class CompletionTest extends AbstractLspAnalysisServerTest
     with CompletionTestMixin {
+  Future<void> checkCompleteFunctionCallInsertText(
+      String content, String completion,
+      {required String insertText, InsertTextFormat? insertTextFormat}) async {
+    await provideConfig(
+      () => initialize(
+        textDocumentCapabilities: withCompletionItemSnippetSupport(
+            emptyTextDocumentClientCapabilities),
+        workspaceCapabilities:
+            withConfigurationSupport(emptyWorkspaceClientCapabilities),
+      ),
+      {'completeFunctionCalls': true},
+    );
+    await openFile(mainFileUri, withoutMarkers(content));
+    final res = await getCompletion(mainFileUri, positionFromMarker(content));
+    final item = res.singleWhere(
+      (c) => c.label == completion,
+      orElse: () =>
+          throw 'Did not find $completion in ${res.map((r) => r.label).toList()}',
+    );
+
+    expect(item.insertTextFormat, equals(insertTextFormat));
+    expect(item.insertText, equals(insertText));
+
+    final textEdit = toTextEdit(item.textEdit!);
+    expect(textEdit.newText, equals(item.insertText));
+    expect(textEdit.range, equals(rangeFromMarkers(content)));
+  }
+
   void expectAutoImportCompletion(List<CompletionItem> items, String file) {
     expect(
       items.singleWhereOrNull(
@@ -138,35 +166,93 @@
     expect(options.allCommitCharacters, equals(dartCompletionCommitCharacters));
   }
 
-  Future<void> test_completeFunctionCalls() async {
-    final content = '''
-    void myFunction(String a, int b, {String c}) {}
+  Future<void> test_completeFunctionCalls_constructor() =>
+      checkCompleteFunctionCallInsertText(
+        '''
+        class Aaaaa {
+          Aaaaa(int a);
+        }
+        void main(int aaa) {
+          var a = new [[Aaa^]]
+        }
+        ''',
+        'Aaaaa(…)',
+        insertTextFormat: InsertTextFormat.Snippet,
+        insertText: r'Aaaaa(${0:a})',
+      );
 
-    main() {
-      [[myFu^]]
-    }
-    ''';
+  Future<void> test_completeFunctionCalls_existingArgList_constructor() =>
+      checkCompleteFunctionCallInsertText(
+        '''
+        class Aaaaa {
+          Aaaaa(int a);
+        }
+        void main(int aaa) {
+          var a = new [[Aaa^]]()
+        }
+        ''',
+        'Aaaaa(…)',
+        insertText: 'Aaaaa',
+      );
 
-    await provideConfig(
-      () => initialize(
-        textDocumentCapabilities: withCompletionItemSnippetSupport(
-            emptyTextDocumentClientCapabilities),
-        workspaceCapabilities:
-            withConfigurationSupport(emptyWorkspaceClientCapabilities),
-      ),
-      {'completeFunctionCalls': true},
-    );
-    await openFile(mainFileUri, withoutMarkers(content));
-    final res = await getCompletion(mainFileUri, positionFromMarker(content));
-    final item = res.singleWhere((c) => c.label == 'myFunction(…)');
-    // Ensure the snippet comes through in the expected format with the expected
-    // placeholders.
-    expect(item.insertTextFormat, equals(InsertTextFormat.Snippet));
-    expect(item.insertText, equals(r'myFunction(${1:a}, ${2:b})'));
-    final textEdit = toTextEdit(item.textEdit!);
-    expect(textEdit.newText, equals(item.insertText));
-    expect(textEdit.range, equals(rangeFromMarkers(content)));
-  }
+  Future<void> test_completeFunctionCalls_existingArgList_expression() =>
+      checkCompleteFunctionCallInsertText(
+        '''
+        int myFunction(String a, int b, {String c}) {
+          var a = [[myFu^]]()
+        }
+        ''',
+        'myFunction(…)',
+        insertText: 'myFunction',
+      );
+
+  Future<void> test_completeFunctionCalls_existingArgList_namedConstructor() =>
+      checkCompleteFunctionCallInsertText(
+        '''
+        class Aaaaa {
+          Aaaaa.foo(int a);
+        }
+        void main() {
+          var a = new Aaaaa.[[foo^]]()
+        }
+        ''',
+        'foo(…)',
+        insertText: 'foo',
+      );
+
+  Future<void> test_completeFunctionCalls_existingArgList_statement() =>
+      checkCompleteFunctionCallInsertText(
+        '''
+        void main(int a) {
+          [[mai^]]()
+        }
+        ''',
+        'main(…)',
+        insertText: 'main',
+      );
+
+  Future<void> test_completeFunctionCalls_existingArgList_suggestionSets() =>
+      checkCompleteFunctionCallInsertText(
+        '''
+        void main(int a) {
+          [[pri^]]()
+        }
+        ''',
+        'print(…)',
+        insertText: 'print',
+      );
+
+  Future<void> test_completeFunctionCalls_expression() =>
+      checkCompleteFunctionCallInsertText(
+        '''
+        int myFunction(String a, int b, {String c}) {
+          var a = [[myFu^]]
+        }
+        ''',
+        'myFunction(…)',
+        insertTextFormat: InsertTextFormat.Snippet,
+        insertText: r'myFunction(${1:a}, ${2:b})',
+      );
 
   Future<void> test_completeFunctionCalls_flutterSetState() async {
     // Flutter's setState method has special handling inside SuggestionBuilder
@@ -215,6 +301,21 @@
     expect(textEdit.range, equals(rangeFromMarkers(content)));
   }
 
+  Future<void> test_completeFunctionCalls_namedConstructor() =>
+      checkCompleteFunctionCallInsertText(
+        '''
+        class Aaaaa {
+          Aaaaa.foo(int a);
+        }
+        void main() {
+          var a = new Aaaaa.[[foo^]]
+        }
+        ''',
+        'foo(…)',
+        insertTextFormat: InsertTextFormat.Snippet,
+        insertText: r'foo(${0:a})',
+      );
+
   Future<void> test_completeFunctionCalls_noRequiredParameters() async {
     final content = '''
     void myFunction({int a}) {}
@@ -269,40 +370,29 @@
     expect(textEdit.newText, equals(item.insertText));
   }
 
-  Future<void> test_completeFunctionCalls_suggestionSets() async {
-    final content = '''
-    main() {
-      [[pri]]^
-    }
-    ''';
+  Future<void> test_completeFunctionCalls_statement() =>
+      checkCompleteFunctionCallInsertText(
+        '''
+        void main(int a) {
+          [[mai^]]
+        }
+        ''',
+        'main(…)',
+        insertTextFormat: InsertTextFormat.Snippet,
+        insertText: r'main(${0:a})',
+      );
 
-    final initialAnalysis = waitForAnalysisComplete();
-    await provideConfig(
-      () => initialize(
-        textDocumentCapabilities: withCompletionItemSnippetSupport(
-            emptyTextDocumentClientCapabilities),
-        workspaceCapabilities: withConfigurationSupport(
-            withApplyEditSupport(emptyWorkspaceClientCapabilities)),
-      ),
-      {'completeFunctionCalls': true},
-    );
-    await openFile(mainFileUri, withoutMarkers(content));
-    await initialAnalysis;
-    final res = await getCompletion(mainFileUri, positionFromMarker(content));
-    final item = res.singleWhere((c) => c.label == 'print(…)');
-    // Ensure the snippet comes through in the expected format with the expected
-    // placeholders.
-    expect(item.insertTextFormat, equals(InsertTextFormat.Snippet));
-    expect(item.insertText, equals(r'print(${0:object})'));
-    expect(item.textEdit, isNull);
-
-    // Ensure the item can be resolved and gets a proper TextEdit.
-    final resolved = await resolveCompletion(item);
-    expect(resolved.textEdit, isNotNull);
-    final textEdit = toTextEdit(resolved.textEdit!);
-    expect(textEdit.newText, equals(item.insertText));
-    expect(textEdit.range, equals(rangeFromMarkers(content)));
-  }
+  Future<void> test_completeFunctionCalls_suggestionSets() =>
+      checkCompleteFunctionCallInsertText(
+        '''
+        void main(int a) {
+          [[pri^]]
+        }
+        ''',
+        'print(…)',
+        insertTextFormat: InsertTextFormat.Snippet,
+        insertText: r'print(${0:object})',
+      );
 
   Future<void> test_completionKinds_default() async {
     newFile(join(projectFolderPath, 'file.dart'));
@@ -2045,4 +2135,23 @@
     expect(textEdit.newText, equals(item.insertText));
     expect(textEdit.range, equals(rangeFromMarkers(content)));
   }
+
+  Future<void> test_nullableTypes() async {
+    final content = '''
+    String? foo(int? a, [int b = 1]) {}
+
+    main() {
+      fo^
+    }
+    ''';
+
+    final initialAnalysis = waitForAnalysisComplete();
+    await initialize();
+    await openFile(mainFileUri, withoutMarkers(content));
+    await initialAnalysis;
+    final res = await getCompletion(mainFileUri, positionFromMarker(content));
+
+    final completion = res.singleWhere((c) => c.label.startsWith('foo'));
+    expect(completion.detail, '(int? a, [int b = 1]) → String?');
+  }
 }
diff --git a/pkg/analysis_server/test/lsp/folding_test.dart b/pkg/analysis_server/test/lsp/folding_test.dart
index 51b2eef..9d35988 100644
--- a/pkg/analysis_server/test/lsp/folding_test.dart
+++ b/pkg/analysis_server/test/lsp/folding_test.dart
@@ -104,6 +104,32 @@
     expect(regions, containsAll(expectedRegions));
   }
 
+  Future<void> test_enum() async {
+    final content = '''
+    enum MyEnum {[[
+      one,
+      two,
+      three
+    ]]}
+    ''';
+
+    final range1 = rangeFromMarkers(content);
+    final expectedRegions = [
+      FoldingRange(
+        startLine: range1.start.line,
+        startCharacter: range1.start.character,
+        endLine: range1.end.line,
+        endCharacter: range1.end.character,
+      )
+    ];
+
+    await initialize();
+    await openFile(mainFileUri, withoutMarkers(content));
+
+    final regions = await getFoldingRegions(mainFileUri);
+    expect(regions, unorderedEquals(expectedRegions));
+  }
+
   Future<void> test_fromPlugins_dartFile() async {
     final pluginAnalyzedFilePath = join(projectFolderPath, 'lib', 'foo.dart');
     final pluginAnalyzedUri = Uri.file(pluginAnalyzedFilePath);
diff --git a/pkg/analysis_server/test/lsp/hover_test.dart b/pkg/analysis_server/test/lsp/hover_test.dart
index 77bb9b5..9abd77a 100644
--- a/pkg/analysis_server/test/lsp/hover_test.dart
+++ b/pkg/analysis_server/test/lsp/hover_test.dart
@@ -13,6 +13,7 @@
 void main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(HoverTest);
+    defineReflectiveTests(HoverWithNullSafetyTest);
   });
 }
 
@@ -265,3 +266,31 @@
     );
   }
 }
+
+@reflectiveTest
+class HoverWithNullSafetyTest extends HoverTest {
+  @override
+  String get testPackageLanguageVersion => latestLanguageVersion;
+
+  Future<void> test_nullableTypes() async {
+    final content = '''
+    String? [[a^bc]];
+    ''';
+
+    final expectedHoverContent = '''
+```dart
+String? abc
+```
+*package:test/main.dart*
+    '''
+        .trim();
+
+    await initialize();
+    await openFile(mainFileUri, withoutMarkers(content));
+    final hover = await getHover(mainFileUri, positionFromMarker(content));
+    expect(hover, isNotNull);
+    expect(hover!.range, equals(rangeFromMarkers(content)));
+    expect(hover.contents, isNotNull);
+    expect(_getStringContents(hover), equals(expectedHoverContent));
+  }
+}
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index 986d755..e5ce594 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -39,10 +39,6 @@
 /// communication to be printed to stdout.
 const debugPrintCommunication = false;
 
-final beginningOfDocument = Range(
-    start: Position(line: 0, character: 0),
-    end: Position(line: 0, character: 0));
-
 abstract class AbstractLspAnalysisServerTest
     with
         ResourceProviderMixin,
@@ -957,13 +953,17 @@
   Future<List<Either2<Command, CodeAction>>> getCodeActions(
     String fileUri, {
     Range? range,
+    Position? position,
     List<CodeActionKind>? kinds,
   }) {
+    range ??= position != null
+        ? Range(start: position, end: position)
+        : startOfDocRange;
     final request = makeRequest(
       Method.textDocument_codeAction,
       CodeActionParams(
         textDocument: TextDocumentIdentifier(uri: fileUri),
-        range: range ?? beginningOfDocument,
+        range: range,
         // TODO(dantup): We may need to revise the tests/implementation when
         // it's clear how we're supposed to handle diagnostics:
         // https://github.com/Microsoft/language-server-protocol/issues/583
diff --git a/pkg/analysis_server/test/lsp/signature_help_test.dart b/pkg/analysis_server/test/lsp/signature_help_test.dart
index 9a6300f..31e1ff3 100644
--- a/pkg/analysis_server/test/lsp/signature_help_test.dart
+++ b/pkg/analysis_server/test/lsp/signature_help_test.dart
@@ -479,12 +479,12 @@
     // This test requires support for the "required" keyword.
     final content = '''
     /// Does foo.
-    foo(String s, {bool b = true, required bool a}) {
+    foo(String s, {bool? b = true, required bool a}) {
       foo(^);
     }
     ''';
 
-    final expectedLabel = 'foo(String s, {bool b = true, required bool a})';
+    final expectedLabel = 'foo(String s, {bool? b = true, required bool a})';
     final expectedDoc = 'Does foo.';
 
     await initialize(
@@ -497,7 +497,7 @@
       expectedDoc,
       [
         ParameterInformation(label: 'String s'),
-        ParameterInformation(label: 'bool b = true'),
+        ParameterInformation(label: 'bool? b = true'),
         ParameterInformation(label: 'required bool a'),
       ],
     );
diff --git a/pkg/analysis_server/test/plugin/protocol_dart_test.dart b/pkg/analysis_server/test/plugin/protocol_dart_test.dart
index e802863..ae69a11 100644
--- a/pkg/analysis_server/test/plugin/protocol_dart_test.dart
+++ b/pkg/analysis_server/test/plugin/protocol_dart_test.dart
@@ -32,7 +32,7 @@
 
     var engineElement = findElement.constructor('myConstructor');
     // create notification Element
-    var element = convertElement(engineElement);
+    var element = convertElement(engineElement, withNullability: false);
     expect(element.parameters, '(int a, {@required int c, int b})');
   }
 
@@ -47,7 +47,7 @@
 
     var engineElement = findElement.constructor('myConstructor');
     // create notification Element
-    var element = convertElement(engineElement);
+    var element = convertElement(engineElement, withNullability: false);
     expect(element.parameters,
         '(int a, {@required int d, @required int c, int b})');
   }
@@ -64,7 +64,7 @@
 
     var engineElement = findElement.constructor('myConstructor');
     // create notification Element
-    var element = convertElement(engineElement);
+    var element = convertElement(engineElement, withNullability: false);
     expect(element.parameters,
         '(int a, {@required int d, @required int c, int b, int a})');
   }
@@ -81,7 +81,7 @@
     {
       var engineElement = findElement.class_('_A');
       // create notification Element
-      var element = convertElement(engineElement);
+      var element = convertElement(engineElement, withNullability: true);
       expect(element.kind, ElementKind.CLASS);
       expect(element.name, '_A');
       expect(element.typeParameters, isNull);
@@ -103,7 +103,7 @@
     {
       var engineElement = findElement.class_('B');
       // create notification Element
-      var element = convertElement(engineElement);
+      var element = convertElement(engineElement, withNullability: true);
       expect(element.kind, ElementKind.CLASS);
       expect(element.name, 'B');
       expect(element.typeParameters, '<K, V>');
@@ -118,7 +118,7 @@
 }''');
     var engineElement = findElement.constructor('myConstructor');
     // create notification Element
-    var element = convertElement(engineElement);
+    var element = convertElement(engineElement, withNullability: true);
     expect(element.kind, ElementKind.CONSTRUCTOR);
     expect(element.name, 'myConstructor');
     expect(element.typeParameters, isNull);
@@ -130,7 +130,7 @@
       expect(location.startLine, 2);
       expect(location.startColumn, 11);
     }
-    expect(element.parameters, '(int a, [String b])');
+    expect(element.parameters, '(int a, [String? b])');
     expect(element.returnType, 'A');
     expect(element.flags, Element.FLAG_CONST);
   }
@@ -145,8 +145,8 @@
 
     var engineElement = findElement.constructor('myConstructor');
     // create notification Element
-    var element = convertElement(engineElement);
-    expect(element.parameters, '(int a, {required int c, int b})');
+    var element = convertElement(engineElement, withNullability: true);
+    expect(element.parameters, '(int a, {required int c, int? b})');
   }
 
   /// Verify parameter re-ordering for required params
@@ -160,9 +160,9 @@
 
     var engineElement = findElement.constructor('myConstructor');
     // create notification Element
-    var element = convertElement(engineElement);
-    expect(
-        element.parameters, '(int a, {required int d, required int c, int b})');
+    var element = convertElement(engineElement, withNullability: true);
+    expect(element.parameters,
+        '(int a, {required int d, required int c, int? b})');
   }
 
   /// Verify parameter re-ordering for required params
@@ -177,7 +177,7 @@
 
     var engineElement = findElement.constructor('myConstructor');
     // create notification Element
-    var element = convertElement(engineElement);
+    var element = convertElement(engineElement, withNullability: true);
     expect(element.parameters,
         '(int a, {required int d, required int c, int b, int a})');
   }
@@ -185,7 +185,7 @@
   void test_dynamic() {
     var engineElement = engine.DynamicElementImpl.instance;
     // create notification Element
-    var element = convertElement(engineElement);
+    var element = convertElement(engineElement, withNullability: true);
     expect(element.kind, ElementKind.UNKNOWN);
     expect(element.name, 'dynamic');
     expect(element.location, isNull);
@@ -203,7 +203,7 @@
       var engineElement = findElement.enum_('_E1');
       expect(engineElement.hasDeprecated, isTrue);
       // create notification Element
-      var element = convertElement(engineElement);
+      var element = convertElement(engineElement, withNullability: true);
       expect(element.kind, ElementKind.ENUM);
       expect(element.name, '_E1');
       expect(element.typeParameters, isNull);
@@ -224,7 +224,7 @@
     {
       var engineElement = findElement.enum_('E2');
       // create notification Element
-      var element = convertElement(engineElement);
+      var element = convertElement(engineElement, withNullability: true);
       expect(element.kind, ElementKind.ENUM);
       expect(element.name, 'E2');
       expect(element.typeParameters, isNull);
@@ -240,7 +240,7 @@
     {
       var engineElement = findElement.field('one');
       // create notification Element
-      var element = convertElement(engineElement);
+      var element = convertElement(engineElement, withNullability: true);
       expect(element.kind, ElementKind.ENUM_CONSTANT);
       expect(element.name, 'one');
       {
@@ -264,7 +264,7 @@
     {
       var engineElement = findElement.field('three');
       // create notification Element
-      var element = convertElement(engineElement);
+      var element = convertElement(engineElement, withNullability: true);
       expect(element.kind, ElementKind.ENUM_CONSTANT);
       expect(element.name, 'three');
       {
@@ -282,7 +282,7 @@
     {
       var engineElement = findElement.field('index', of: 'E2');
       // create notification Element
-      var element = convertElement(engineElement);
+      var element = convertElement(engineElement, withNullability: true);
       expect(element.kind, ElementKind.FIELD);
       expect(element.name, 'index');
       {
@@ -300,7 +300,7 @@
     {
       var engineElement = findElement.field('values', of: 'E2');
       // create notification Element
-      var element = convertElement(engineElement);
+      var element = convertElement(engineElement, withNullability: true);
       expect(element.kind, ElementKind.FIELD);
       expect(element.name, 'values');
       {
@@ -324,7 +324,7 @@
 }''');
     var engineElement = findElement.field('myField');
     // create notification Element
-    var element = convertElement(engineElement);
+    var element = convertElement(engineElement, withNullability: true);
     expect(element.kind, ElementKind.FIELD);
     expect(element.name, 'myField');
     {
@@ -346,7 +346,7 @@
 ''');
     var engineElement = findElement.typeAlias('F');
     // create notification Element
-    var element = convertElement(engineElement);
+    var element = convertElement(engineElement, withNullability: true);
     expect(element.kind, ElementKind.TYPE_ALIAS);
     expect(element.name, 'F');
     expect(element.typeParameters, '<T>');
@@ -369,7 +369,7 @@
 ''');
     var engineElement = findElement.typeAlias('F');
     // create notification Element
-    var element = convertElement(engineElement);
+    var element = convertElement(engineElement, withNullability: true);
     expect(element.kind, ElementKind.TYPE_ALIAS);
     expect(element.name, 'F');
     expect(element.typeParameters, '<out T>');
@@ -393,7 +393,7 @@
 ''');
     var engineElement = findElement.typeAlias('F');
     // create notification Element
-    var element = convertElement(engineElement);
+    var element = convertElement(engineElement, withNullability: true);
     expect(element.kind, ElementKind.TYPE_ALIAS);
     expect(element.name, 'F');
     expect(element.typeParameters, '<T>');
@@ -418,7 +418,7 @@
 }''');
     var engineElement = findElement.getter('myGetter');
     // create notification Element
-    var element = convertElement(engineElement);
+    var element = convertElement(engineElement, withNullability: true);
     expect(element.kind, ElementKind.GETTER);
     expect(element.name, 'myGetter');
     {
@@ -444,7 +444,7 @@
 }''');
     var engineElement = findElement.label('myLabel');
     // create notification Element
-    var element = convertElement(engineElement);
+    var element = convertElement(engineElement, withNullability: true);
     expect(element.kind, ElementKind.LABEL);
     expect(element.name, 'myLabel');
     {
@@ -469,7 +469,7 @@
 }''');
     var engineElement = findElement.method('myMethod');
     // create notification Element
-    var element = convertElement(engineElement);
+    var element = convertElement(engineElement, withNullability: true);
     expect(element.kind, ElementKind.METHOD);
     expect(element.name, 'myMethod');
     {
@@ -480,7 +480,7 @@
       expect(location.startLine, 2);
       expect(location.startColumn, 23);
     }
-    expect(element.parameters, '(int a, {String b, int c})');
+    expect(element.parameters, '(int a, {String? b, int? c})');
     expect(element.returnType, 'List<String>');
     expect(element.flags, Element.FLAG_STATIC);
   }
@@ -492,7 +492,7 @@
     {
       var engineElement = findElement.mixin('A');
       // create notification Element
-      var element = convertElement(engineElement);
+      var element = convertElement(engineElement, withNullability: true);
       expect(element.kind, ElementKind.MIXIN);
       expect(element.name, 'A');
       expect(element.typeParameters, isNull);
@@ -516,7 +516,7 @@
 }''');
     var engineElement = findElement.setter('mySetter');
     // create notification Element
-    var element = convertElement(engineElement);
+    var element = convertElement(engineElement, withNullability: true);
     expect(element.kind, ElementKind.SETTER);
     expect(element.name, 'mySetter');
     {
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 497e8c9..b72acd8 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -186,7 +186,6 @@
   CompileTimeErrorCode.FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR,
   CompileTimeErrorCode.FIELD_INITIALIZING_FORMAL_NOT_ASSIGNABLE,
   CompileTimeErrorCode.FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR,
-  CompileTimeErrorCode.FINAL_INITIALIZED_MULTIPLE_TIMES,
   CompileTimeErrorCode.FINAL_NOT_INITIALIZED,
   CompileTimeErrorCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1,
   CompileTimeErrorCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2,
diff --git a/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart b/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
index 80b996d..83eacb7 100644
--- a/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
@@ -130,9 +130,9 @@
     isEnabledByDefault: IsEnabledByDefault.generic_metadata,
     isExpired: IsExpired.generic_metadata,
     documentation:
-        'Allow annotations to accept type arguments; also allow generic function types as type arguments',
+        'Allow annotations to accept type arguments; also allow generic function types as type arguments.',
     experimentalReleaseVersion: null,
-    releaseVersion: null,
+    releaseVersion: Version.parse('2.14.0'),
   );
 
   static final non_nullable = ExperimentalFeature(
@@ -225,7 +225,7 @@
   static const bool extension_types = false;
 
   /// Default state of the experiment "generic-metadata"
-  static const bool generic_metadata = false;
+  static const bool generic_metadata = true;
 
   /// Default state of the experiment "non-nullable"
   static const bool non_nullable = true;
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index 6cd2625..d70224e 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -3168,8 +3168,8 @@
   static const CompileTimeErrorCode DUPLICATE_FIELD_FORMAL_PARAMETER =
       CompileTimeErrorCode(
           'DUPLICATE_FIELD_FORMAL_PARAMETER',
-          "The field '{0}' can't be referenced in multiple initializing "
-              "parameters in the same constructor.",
+          "The field '{0}' can't be initialized by multiple parameters in the "
+              "same constructor.",
           correction: "Try removing one of the parameters, or "
               "using different fields.");
 
@@ -4654,19 +4654,6 @@
           hasPublishedDocs: true);
 
   /**
-   * 5 Variables: It is a compile-time error if a final instance variable that
-   * has is initialized by means of an initializing formal of a constructor is
-   * also initialized elsewhere in the same constructor.
-   *
-   * Parameters:
-   * 0: the name of the field in question
-   */
-  static const CompileTimeErrorCode FINAL_INITIALIZED_MULTIPLE_TIMES =
-      CompileTimeErrorCode('FINAL_INITIALIZED_MULTIPLE_TIMES',
-          "'{0}' is a final field and so can only be set once.",
-          correction: "Try removing all but one of the initializations.");
-
-  /**
    * Parameters:
    * 0: the name of the uninitialized final variable
    */
diff --git a/pkg/analyzer/lib/src/error/constructor_fields_verifier.dart b/pkg/analyzer/lib/src/error/constructor_fields_verifier.dart
index 260bbb6..b1a079a 100644
--- a/pkg/analyzer/lib/src/error/constructor_fields_verifier.dart
+++ b/pkg/analyzer/lib/src/error/constructor_fields_verifier.dart
@@ -219,13 +219,7 @@
             );
           }
         } else if (state == _InitState.initInFieldFormal) {
-          if (fieldElement.isFinal || fieldElement.isConst) {
-            _errorReporter.reportErrorForNode(
-              CompileTimeErrorCode.FINAL_INITIALIZED_MULTIPLE_TIMES,
-              parameter.identifier,
-              [fieldElement.displayName],
-            );
-          }
+          // Reported in DuplicateDefinitionVerifier._checkDuplicateIdentifier
         }
       }
     }
diff --git a/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart b/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart
index eb3d6c6..f5e4f33 100644
--- a/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart
+++ b/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart
@@ -384,14 +384,7 @@
 
     var previous = getterScope[name];
     if (previous != null) {
-      if (_isGetterSetterPair(element, previous)) {
-        // OK
-      } else if (element is FieldFormalParameterElement &&
-          previous is FieldFormalParameterElement &&
-          element.field != null &&
-          element.field!.isFinal) {
-        // Reported as CompileTimeErrorCode.FINAL_INITIALIZED_MULTIPLE_TIMES.
-      } else {
+      if (!_isGetterSetterPair(element, previous)) {
         _errorReporter.reportErrorForNode(
           getError(previous, element),
           identifier,
diff --git a/pkg/analyzer/lib/src/services/available_declarations.dart b/pkg/analyzer/lib/src/services/available_declarations.dart
index 577424b..d4cd689 100644
--- a/pkg/analyzer/lib/src/services/available_declarations.dart
+++ b/pkg/analyzer/lib/src/services/available_declarations.dart
@@ -1346,8 +1346,9 @@
     String? docSummary;
 
     void setDartDoc(AnnotatedNode node) {
-      if (node.documentationComment != null) {
-        var rawText = getCommentNodeRawText(node.documentationComment);
+      var docComment = node.documentationComment;
+      if (docComment != null) {
+        var rawText = getCommentNodeRawText(docComment);
         docComplete = getDartDocPlainText(rawText);
         docSummary = getDartDocSummary(docComplete);
       } else {
diff --git a/pkg/analyzer/lib/src/util/comment.dart b/pkg/analyzer/lib/src/util/comment.dart
index cb295c6..ae3ebf9 100644
--- a/pkg/analyzer/lib/src/util/comment.dart
+++ b/pkg/analyzer/lib/src/util/comment.dart
@@ -8,10 +8,22 @@
 String? getCommentNodeRawText(Comment? node) {
   if (node == null) return null;
 
-  return node.tokens
-      .map((token) => token.lexeme)
-      .join('\n')
-      .replaceAll('\r\n', '\n');
+  var tokens = node.tokens;
+  var count = tokens.length;
+  if (count == 1) {
+    // The comment might be a block-style doc comment with embedded end-of-line
+    // markers.
+    return tokens[0].lexeme.replaceAll('\r\n', '\n');
+  }
+
+  var buffer = StringBuffer();
+  for (var i = 0; i < count; i++) {
+    if (i > 0) {
+      buffer.write('\n');
+    }
+    buffer.write(tokens[i].lexeme);
+  }
+  return buffer.toString();
 }
 
 /// Return the plain text from the given DartDoc [rawText], without delimiters.
@@ -19,11 +31,13 @@
   if (rawText == null) return null;
 
   // Remove /** */.
+  var isBlock = false;
   if (rawText.startsWith('/**')) {
+    isBlock = true;
     rawText = rawText.substring(3);
-  }
-  if (rawText.endsWith('*/')) {
-    rawText = rawText.substring(0, rawText.length - 2);
+    if (rawText.endsWith('*/')) {
+      rawText = rawText.substring(0, rawText.length - 2);
+    }
   }
   rawText = rawText.trim();
 
@@ -32,12 +46,12 @@
   var lines = rawText.split('\n');
   for (var line in lines) {
     line = line.trim();
-    if (line.startsWith('*')) {
+    if (isBlock && line.startsWith('*')) {
       line = line.substring(1);
       if (line.startsWith(' ')) {
         line = line.substring(1);
       }
-    } else if (line.startsWith('///')) {
+    } else if (!isBlock && line.startsWith('///')) {
       line = line.substring(3);
       if (line.startsWith(' ')) {
         line = line.substring(1);
@@ -54,12 +68,18 @@
 
 /// Return the DartDoc summary, i.e. the portion before the first empty line.
 String? getDartDocSummary(String? completeText) {
-  if (completeText == null) return null;
-
-  var result = StringBuffer();
+  if (completeText == null) {
+    return null;
+  }
   var lines = completeText.split('\n');
-  for (var line in lines) {
-    if (result.isNotEmpty) {
+  int count = lines.length;
+  if (count == 1) {
+    return lines[0];
+  }
+  var result = StringBuffer();
+  for (var i = 0; i < count; i++) {
+    var line = lines[i];
+    if (i > 0) {
       if (line.isEmpty) {
         return result.toString();
       }
diff --git a/pkg/analyzer/lib/src/workspace/bazel_watcher.dart b/pkg/analyzer/lib/src/workspace/bazel_watcher.dart
index 81d20db..50ceb0c 100644
--- a/pkg/analyzer/lib/src/workspace/bazel_watcher.dart
+++ b/pkg/analyzer/lib/src/workspace/bazel_watcher.dart
@@ -33,7 +33,7 @@
   final List<String> _candidates;
 
   /// The time of last modification of the file under [_validPath].
-  int? _lastModified;
+  _TimestampAndLength? _lastModified;
 
   /// The resource provider used for polling the files.
   final ResourceProvider _provider;
@@ -47,7 +47,7 @@
   /// Checks if the file corresponding to the watched path has changed and
   /// returns the event or `null` if nothing changed.
   WatchEvent? poll() {
-    int? modified;
+    _TimestampAndLength? modified;
     if (_validPath == null) {
       var info = _pollAll();
       if (info != null) {
@@ -72,6 +72,7 @@
     } else if (_lastModified != null && modified != _lastModified) {
       result = WatchEvent(ChangeType.MODIFY, _validPath!);
     }
+
     _lastModified = modified;
     return result;
   }
@@ -107,10 +108,12 @@
 
   /// Returns the modified time of the path or `null` if the file does not
   /// exist.
-  int? _pollOne(String path) {
+  _TimestampAndLength? _pollOne(String path) {
     try {
       var file = _provider.getFile(path);
-      return file.modificationStamp;
+      var timestamp = file.modificationStamp;
+      var length = file.lengthSync;
+      return _TimestampAndLength(timestamp, length);
     } on FileSystemException catch (_) {
       // File doesn't exist, so return null.
       return null;
@@ -403,7 +406,7 @@
 
 class FileInfo {
   String path;
-  int modified;
+  _TimestampAndLength modified;
   FileInfo(this.path, this.modified);
 }
 
@@ -549,3 +552,36 @@
 
   _PerWorkspaceData(this.trigger, this.pollSubscription);
 }
+
+/// Stores the timestamp of a file and its length.
+///
+/// This turns out to be important for tracking files that change a lot, like
+/// the `command.log` that we use to detect the finished build.  Bazel writes to
+/// the file continuously and because the resolution of a timestamp is pretty
+/// low, it's quite possible to receive the same timestamp even though the file
+/// has changed.  We use its length to remedy that.  It's not perfect (for that
+/// we'd have to compute the hash), but it should be reasonable trade-off (to
+/// avoid any performance impact from reading and hashing the file).
+class _TimestampAndLength {
+  final int timestamp;
+  final int length;
+  _TimestampAndLength(this.timestamp, this.length);
+
+  @override
+  int get hashCode =>
+      // We don't really need to compute hashes, just check the equality. But
+      // throw in case someone expects this to work.
+      throw UnimplementedError(
+          '_TimestampAndLength.hashCode has not been implemented yet');
+
+  @override
+  bool operator ==(Object other) {
+    if (other is! _TimestampAndLength) return false;
+    return timestamp == other.timestamp && length == other.length;
+  }
+
+  // For debugging only.
+  @override
+  String toString() =>
+      '_TimestampAndLength(timestamp=$timestamp, length=$length)';
+}
diff --git a/pkg/analyzer/test/src/dart/resolution/generic_type_alias_test.dart b/pkg/analyzer/test/src/dart/resolution/generic_type_alias_test.dart
index 0cd0ac8..60b6def 100644
--- a/pkg/analyzer/test/src/dart/resolution/generic_type_alias_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/generic_type_alias_test.dart
@@ -194,6 +194,7 @@
 
   test_genericFunctionTypeCannotBeTypeArgument_def_class() async {
     await assertErrorsInCode(r'''
+// @dart=2.12
 class C<T> {}
 
 typedef G = Function<S>();
@@ -201,23 +202,25 @@
 C<G>? x;
 ''', [
       error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
-          45, 1),
+          59, 1),
     ]);
   }
 
   test_genericFunctionTypeCannotBeTypeArgument_literal_class() async {
     await assertErrorsInCode(r'''
+// @dart=2.12
 class C<T> {}
 
 C<Function<S>()>? x;
 ''', [
       error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
-          17, 13),
+          31, 13),
     ]);
   }
 
   test_genericFunctionTypeCannotBeTypeArgument_literal_function() async {
     await assertErrorsInCode(r'''
+// @dart=2.12
 void f<T>(T) {}
 
 main() {
@@ -225,12 +228,13 @@
 }
 ''', [
       error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
-          30, 13),
+          44, 13),
     ]);
   }
 
   test_genericFunctionTypeCannotBeTypeArgument_literal_functionType() async {
     await assertErrorsInCode(r'''
+// @dart=2.12
 late T Function<T>(T?) f;
 
 main() {
@@ -238,12 +242,13 @@
 }
 ''', [
       error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
-          40, 13),
+          54, 13),
     ]);
   }
 
   test_genericFunctionTypeCannotBeTypeArgument_literal_method() async {
     await assertErrorsInCode(r'''
+// @dart=2.12
 class C {
   void f<T>(T) {}
 }
@@ -253,18 +258,19 @@
 }
 ''', [
       error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
-          52, 13),
+          66, 13),
     ]);
   }
 
   test_genericFunctionTypeCannotBeTypeArgument_literal_typedef() async {
     await assertErrorsInCode(r'''
+// @dart=2.12
 typedef T F<T>(T t);
 
 F<Function<S>()>? x;
 ''', [
       error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
-          24, 13),
+          38, 13),
     ]);
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/duplicate_field_formal_parameter_test.dart b/pkg/analyzer/test/src/diagnostics/duplicate_field_formal_parameter_test.dart
index 0d10113..586709e 100644
--- a/pkg/analyzer/test/src/diagnostics/duplicate_field_formal_parameter_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/duplicate_field_formal_parameter_test.dart
@@ -37,6 +37,17 @@
     ]);
   }
 
+  test_optional_positional_final() async {
+    await assertErrorsInCode(r'''
+class A {
+  final x;
+  A([this.x = 1, this.x = 2]) {}
+}
+''', [
+      error(CompileTimeErrorCode.DUPLICATE_FIELD_FORMAL_PARAMETER, 43, 1),
+    ]);
+  }
+
   test_required_named() async {
     await assertErrorsInCode(r'''
 class A {
@@ -58,4 +69,15 @@
       error(CompileTimeErrorCode.DUPLICATE_FIELD_FORMAL_PARAMETER, 36, 1),
     ]);
   }
+
+  test_required_positional_final() async {
+    await assertErrorsInCode(r'''
+class A {
+  final x;
+  A(this.x, this.x) {}
+}
+''', [
+      error(CompileTimeErrorCode.DUPLICATE_FIELD_FORMAL_PARAMETER, 38, 1),
+    ]);
+  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/final_initialized_multiple_times_test.dart b/pkg/analyzer/test/src/diagnostics/final_initialized_multiple_times_test.dart
deleted file mode 100644
index d860ffe..0000000
--- a/pkg/analyzer/test/src/diagnostics/final_initialized_multiple_times_test.dart
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2019, 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:analyzer/src/error/codes.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-import '../dart/resolution/context_collection_resolution.dart';
-
-main() {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(FinalInitializedMultipleTimesTest);
-  });
-}
-
-@reflectiveTest
-class FinalInitializedMultipleTimesTest extends PubPackageResolutionTest {
-  test_initializingFormals_withDefaultValues() async {
-    await assertErrorsInCode(r'''
-class A {
-  final x;
-  A([this.x = 1, this.x = 2]) {}
-}
-''', [
-      error(CompileTimeErrorCode.FINAL_INITIALIZED_MULTIPLE_TIMES, 43, 1),
-    ]);
-  }
-
-  test_initializingFormals_withoutDefaultValues() async {
-    await assertErrorsInCode(r'''
-class A {
-  final x;
-  A(this.x, this.x) {}
-}
-''', [
-      error(CompileTimeErrorCode.FINAL_INITIALIZED_MULTIPLE_TIMES, 38, 1),
-    ]);
-  }
-}
diff --git a/pkg/analyzer/test/src/diagnostics/generic_function_type_cannot_be_bound_test.dart b/pkg/analyzer/test/src/diagnostics/generic_function_type_cannot_be_bound_test.dart
index 583a9a5..02c4641 100644
--- a/pkg/analyzer/test/src/diagnostics/generic_function_type_cannot_be_bound_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/generic_function_type_cannot_be_bound_test.dart
@@ -72,26 +72,29 @@
 
   test_class() async {
     await assertErrorsInCode(r'''
+// @dart=2.12
 class C<T extends S Function<S>(S)> {
 }
 ''', [
-      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_BOUND, 18, 16),
+      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_BOUND, 32, 16),
     ]);
   }
 
   test_genericFunction() async {
     await assertErrorsInCode(r'''
+// @dart=2.12
 late T Function<T extends S Function<S>(S)>(T) fun;
 ''', [
-      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_BOUND, 26, 16),
+      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_BOUND, 40, 16),
     ]);
   }
 
   test_genericFunctionTypedef() async {
     await assertErrorsInCode(r'''
+// @dart=2.12
 typedef foo = T Function<T extends S Function<S>(S)>(T t);
 ''', [
-      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_BOUND, 35, 16),
+      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_BOUND, 49, 16),
     ]);
   }
 
@@ -103,9 +106,10 @@
 
   test_typedef() async {
     await assertErrorsInCode(r'''
+// @dart=2.12
 typedef T foo<T extends S Function<S>(S)>(T t);
 ''', [
-      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_BOUND, 24, 16),
+      error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_BOUND, 38, 16),
     ]);
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index b3e249e..46d80bd 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -207,8 +207,6 @@
     as field_initializing_formal_not_assignable;
 import 'final_initialized_in_delcaration_and_constructor_test.dart'
     as final_initialized_in_declaration_and_constructor;
-import 'final_initialized_multiple_times_test.dart'
-    as final_initialized_multiple_times;
 import 'final_not_initialized_constructor_test.dart'
     as final_not_initialized_constructor;
 import 'final_not_initialized_test.dart' as final_not_initialized;
@@ -820,7 +818,6 @@
     final_initialized_in_declaration_and_constructor.main();
     field_initialized_in_initializer_and_declaration.main();
     field_initialized_in_parameter_and_initializer.main();
-    final_initialized_multiple_times.main();
     field_initializer_factory_constructor.main();
     field_initializer_in_struct.main();
     field_initializer_not_assignable.main();
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
index 767c77a..2ca67b4 100644
--- a/pkg/analyzer/tool/diagnostics/diagnostics.md
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -156,7 +156,7 @@
 
 [definiteAssignmentSpec](https://github.com/dart-lang/language/blob/master/resources/type-system/flow-analysis.md)
 
-### Mixin Application
+### Mixin application
 
 A _mixin application_ is the class created when a mixin is applied to a class.
 For example, consider the following declarations:
diff --git a/pkg/analyzer/tool/diagnostics/generate.dart b/pkg/analyzer/tool/diagnostics/generate.dart
index b95e8dc..c19400f 100644
--- a/pkg/analyzer/tool/diagnostics/generate.dart
+++ b/pkg/analyzer/tool/diagnostics/generate.dart
@@ -547,7 +547,7 @@
 
 [definiteAssignmentSpec](https://github.com/dart-lang/language/blob/master/resources/type-system/flow-analysis.md)
 
-### Mixin Application
+### Mixin application
 
 A _mixin application_ is the class created when a mixin is applied to a class.
 For example, consider the following declarations:
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 4f00c21..7288f48 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -94,6 +94,7 @@
   static const String useMultiSourceInfo = '--use-multi-source-info';
   static const String useNewSourceInfo = '--use-new-source-info';
   static const String useOldRti = '--use-old-rti';
+  static const String useSimpleLoadIds = '--simple-load-ids';
   static const String verbose = '--verbose';
   static const String verbosity = '--verbosity';
   static const String progress = '--show-internal-progress';
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 2a18b23..1dcfde0 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -581,6 +581,7 @@
     new OptionHandler(Flags.useMultiSourceInfo, passThrough),
     new OptionHandler(Flags.useNewSourceInfo, passThrough),
     new OptionHandler(Flags.useOldRti, passThrough),
+    new OptionHandler(Flags.useSimpleLoadIds, passThrough),
     new OptionHandler(Flags.testMode, passThrough),
     new OptionHandler('${Flags.dumpSsa}=.+', passThrough),
     new OptionHandler('${Flags.cfeInvocationModes}=.+', passThrough),
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index 974e8a0..f3f6bac 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -670,15 +670,27 @@
   }
 
   void _setupImportNames() {
+    // If useSimpleLoadIds is true then we use a monotonically increasing number
+    // to generate loadIds. Otherwise, we will use the user provided names.
+    bool useIds = compiler.options.useSimpleLoadIds;
+    var allDeferredImports = _allDeferredImports.toList();
+    if (useIds) {
+      // Sort for a canonical order of [ImportEntity]s.
+      allDeferredImports.sort(_compareImportEntities);
+    }
+    int nextDeferId = 0;
     Set<String> usedImportNames = {};
-
-    for (ImportEntity import in _allDeferredImports) {
+    for (ImportEntity import in allDeferredImports) {
       String result = computeImportDeferName(import, compiler);
       assert(result != null);
-      // Note: tools that process the json file to build multi-part initial load
-      // bundles depend on the fact that makeUnique appends only digits, or a
-      // period followed by digits.
-      importDeferName[import] = makeUnique(result, usedImportNames, '.');
+      if (useIds) {
+        importDeferName[import] = (++nextDeferId).toString();
+      } else {
+        // Note: tools that process the json file to build multi-part initial load
+        // bundles depend on the fact that makeUnique appends only digits, or a
+        // period followed by digits.
+        importDeferName[import] = makeUnique(result, usedImportNames, '.');
+      }
     }
   }
 
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index 43a92cb..f3b99c9 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -352,6 +352,9 @@
   /// (experimental)
   bool useNewSourceInfo = false;
 
+  /// Whether or not use simple load ids.
+  bool useSimpleLoadIds = false;
+
   /// Enable verbose printing during compilation. Includes a time-breakdown
   /// between phases at the end.
   bool verbose = false;
@@ -524,6 +527,7 @@
           !_hasOption(options, Flags.noFrequencyBasedMinification)
       ..useMultiSourceInfo = _hasOption(options, Flags.useMultiSourceInfo)
       ..useNewSourceInfo = _hasOption(options, Flags.useNewSourceInfo)
+      ..useSimpleLoadIds = _hasOption(options, Flags.useSimpleLoadIds)
       ..verbose = _hasOption(options, Flags.verbose)
       ..reportPrimaryMetrics = _hasOption(options, Flags.reportMetrics)
       ..reportSecondaryMetrics = _hasOption(options, Flags.reportAllMetrics)
diff --git a/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart b/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
index 42d985f..3a1e2c8 100644
--- a/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
+++ b/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
@@ -83,7 +83,7 @@
   ExperimentalFlag.controlFlowCollections: true,
   ExperimentalFlag.extensionMethods: true,
   ExperimentalFlag.extensionTypes: false,
-  ExperimentalFlag.genericMetadata: false,
+  ExperimentalFlag.genericMetadata: true,
   ExperimentalFlag.nonNullable: true,
   ExperimentalFlag.nonfunctionTypeAliases: true,
   ExperimentalFlag.setLiterals: true,
diff --git a/runtime/vm/experimental_features.cc b/runtime/vm/experimental_features.cc
index 162f8c8..18c32a0 100644
--- a/runtime/vm/experimental_features.cc
+++ b/runtime/vm/experimental_features.cc
@@ -18,7 +18,7 @@
 
 bool GetExperimentalFeatureDefault(ExperimentalFeature feature) {
   constexpr bool kFeatureValues[] = {
-      true, true, true, true, true, true, true, true,
+      true, true, true, true, true, true, true, true, true,
   };
   ASSERT(static_cast<size_t>(feature) < ARRAY_SIZE(kFeatureValues));
   return kFeatureValues[static_cast<int>(feature)];
@@ -26,10 +26,15 @@
 
 const char* GetExperimentalFeatureName(ExperimentalFeature feature) {
   constexpr const char* kFeatureNames[] = {
-      "nonfunction-type-aliases", "non-nullable",
-      "extension-methods",        "constant-update-2018",
-      "control-flow-collections", "set-literals",
-      "spread-collections",       "triple-shift",
+      "nonfunction-type-aliases",
+      "non-nullable",
+      "extension-methods",
+      "constant-update-2018",
+      "control-flow-collections",
+      "generic-metadata",
+      "set-literals",
+      "spread-collections",
+      "triple-shift",
   };
   ASSERT(static_cast<size_t>(feature) < ARRAY_SIZE(kFeatureNames));
   return kFeatureNames[static_cast<int>(feature)];
diff --git a/runtime/vm/experimental_features.h b/runtime/vm/experimental_features.h
index 0bb9e50..ba0588d 100644
--- a/runtime/vm/experimental_features.h
+++ b/runtime/vm/experimental_features.h
@@ -19,6 +19,7 @@
   extension_methods,
   constant_update_2018,
   control_flow_collections,
+  generic_metadata,
   set_literals,
   spread_collections,
   triple_shift,
diff --git a/tests/language/constructor/duplicate_initializers_test.dart b/tests/language/constructor/duplicate_initializers_test.dart
index 4f6699e..a521279 100644
--- a/tests/language/constructor/duplicate_initializers_test.dart
+++ b/tests/language/constructor/duplicate_initializers_test.dart
@@ -25,7 +25,7 @@
    Class.two_fields(this.field_
     , this.field_
     //     ^^^^^^
-    // [analyzer] COMPILE_TIME_ERROR.FINAL_INITIALIZED_MULTIPLE_TIMES
+    // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_FIELD_FORMAL_PARAMETER
     // [cfe] 'field_' was already initialized by this constructor.
     //     ^
     // [cfe] Duplicated parameter name 'field_'.
diff --git a/tests/language/generic/function_type_as_type_argument_test.dart b/tests/language/generic/function_type_as_type_argument_test.dart
index c59dce7..e932d53 100644
--- a/tests/language/generic/function_type_as_type_argument_test.dart
+++ b/tests/language/generic/function_type_as_type_argument_test.dart
@@ -4,6 +4,8 @@
 //
 // VMOptions=--reify-generic-functions
 
+// @dart=2.12
+
 import "package:expect/expect.dart";
 
 T foo<T>(T i) => i;
diff --git a/tests/language/generic/metadata_in_function_body_test.dart b/tests/language/generic/metadata_in_function_body_test.dart
index e6be65f..8b64190 100644
--- a/tests/language/generic/metadata_in_function_body_test.dart
+++ b/tests/language/generic/metadata_in_function_body_test.dart
@@ -2,6 +2,8 @@
 // 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.
 
+// @dart=2.12
+
 // Check that annotations inside function bodies cannot use type arguments, but
 // can be raw.
 
diff --git a/tests/language/generic/metadata_test.dart b/tests/language/generic/metadata_test.dart
index a6a5ad8..70156d6 100644
--- a/tests/language/generic/metadata_test.dart
+++ b/tests/language/generic/metadata_test.dart
@@ -2,6 +2,8 @@
 // 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.
 
+// @dart=2.12
+
 // Check that annotations cannot use type arguments, but can be raw.
 
 class C<T> {
diff --git a/tests/language/generic_methods/generic_function_result_test.dart b/tests/language/generic_methods/generic_function_result_test.dart
index 41d4742..569c2f9 100644
--- a/tests/language/generic_methods/generic_function_result_test.dart
+++ b/tests/language/generic_methods/generic_function_result_test.dart
@@ -2,6 +2,8 @@
 // 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.
 
+// @dart=2.12
+
 // Verify that function type parameter S can be resolved in bar's result type.
 // Verify that generic function types are not allowed as type arguments.
 
diff --git a/tests/language/regress/regress33479_test.dart b/tests/language/regress/regress33479_test.dart
index a825b94..38b558c3 100644
--- a/tests/language/regress/regress33479_test.dart
+++ b/tests/language/regress/regress33479_test.dart
@@ -1,11 +1,9 @@
 class Hest<TypeX extends Fisk> {}
 //                       ^^^^
 // [analyzer] COMPILE_TIME_ERROR.NOT_INSTANTIATED_BOUND
-//         ^
-// [cfe] Type variables can't have generic function types in their bounds.
 
 typedef Fisk = void Function // don't merge lines
-// [error line 7, column 1, length 346]
+// [error line 5, column 1, length 346]
 // [analyzer] COMPILE_TIME_ERROR.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
 //      ^
 // [cfe] Generic type 'Fisk' can't be used without type arguments in the bounds of its own type variables. It is referenced indirectly through 'Hest'.
@@ -15,6 +13,4 @@
 
 main() {
   Hest hest = new Hest();
-//                ^
-// [cfe] Generic function type 'void Function<TypeY>()' inferred as a type argument.
 }
diff --git a/tests/language_2/constructor/duplicate_initializers_test.dart b/tests/language_2/constructor/duplicate_initializers_test.dart
index c787657..d98d23d 100644
--- a/tests/language_2/constructor/duplicate_initializers_test.dart
+++ b/tests/language_2/constructor/duplicate_initializers_test.dart
@@ -27,7 +27,7 @@
    Class.two_fields(this.field_
     , this.field_
     //     ^^^^^^
-    // [analyzer] COMPILE_TIME_ERROR.FINAL_INITIALIZED_MULTIPLE_TIMES
+    // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_FIELD_FORMAL_PARAMETER
     // [cfe] 'field_' was already initialized by this constructor.
     //     ^
     // [cfe] Duplicated parameter name 'field_'.
diff --git a/tests/language_2/generic/metadata_in_function_body_test.dart b/tests/language_2/generic/metadata_in_function_body_test.dart
index 1b7fe3c..d98f743 100644
--- a/tests/language_2/generic/metadata_in_function_body_test.dart
+++ b/tests/language_2/generic/metadata_in_function_body_test.dart
@@ -7,6 +7,8 @@
 // Check that annotations inside function bodies cannot use type arguments, but
 // can be raw.
 
+// @dart=2.11
+
 class C<T> {
   const C();
 }
diff --git a/tests/language_2/generic/metadata_test.dart b/tests/language_2/generic/metadata_test.dart
index 18d6b86..4a4dcad 100644
--- a/tests/language_2/generic/metadata_test.dart
+++ b/tests/language_2/generic/metadata_test.dart
@@ -6,6 +6,8 @@
 
 // Check that annotations cannot use type arguments, but can be raw.
 
+// @dart=2.11
+
 class C<T> {
   const C();
 }
diff --git a/tests/language_2/generic_methods/generic_function_result_test.dart b/tests/language_2/generic_methods/generic_function_result_test.dart
index 9e24263..d291d2d 100644
--- a/tests/language_2/generic_methods/generic_function_result_test.dart
+++ b/tests/language_2/generic_methods/generic_function_result_test.dart
@@ -7,6 +7,8 @@
 // Verify that function type parameter S can be resolved in bar's result type.
 // Verify that generic function types are not allowed as type arguments.
 
+// @dart=2.11
+
 import "package:expect/expect.dart";
 
 int foo
diff --git a/tests/lib/mirrors/metadata_allowed_values_test.dart b/tests/lib/mirrors/metadata_allowed_values_test.dart
index 3204730..85937ff 100644
--- a/tests/lib/mirrors/metadata_allowed_values_test.dart
+++ b/tests/lib/mirrors/metadata_allowed_values_test.dart
@@ -47,11 +47,6 @@
   G.named(this.field);
 }
 
-@H<int>() // //# 05: compile-time error
-class H<T> {
-  const H();
-}
-
 @I[0] // //# 06: compile-time error
 class I {}
 
@@ -187,7 +182,6 @@
   reflectClass(E).metadata;
   reflectClass(F).metadata;
   reflectClass(G).metadata;
-  reflectClass(H).metadata;
   reflectClass(I).metadata;
   reflectClass(J).metadata;
   reflectClass(K).metadata;
diff --git a/tools/VERSION b/tools/VERSION
index cc9e6ba..e11b2c9 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 14
 PATCH 0
-PRERELEASE 50
+PRERELEASE 51
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/experimental_features.yaml b/tools/experimental_features.yaml
index 1881ab6..acc2a15 100644
--- a/tools/experimental_features.yaml
+++ b/tools/experimental_features.yaml
@@ -116,9 +116,6 @@
   value-class:
     help: "Value class"
 
-  generic-metadata:
-    help: "Allow annotations to accept type arguments; also allow generic function types as type arguments"
-
   extension-types:
     help: "Extension Types"
 
@@ -164,6 +161,12 @@
     enabledIn: '2.0.0'
     expired: true
 
+  generic-metadata:
+    help: >-
+      Allow annotations to accept type arguments;
+      also allow generic function types as type arguments.
+    enabledIn: '2.14.0'
+
   set-literals:
     help: "Set Literals"
     enabledIn: '2.0.0'
diff --git a/utils/analysis_server/BUILD.gn b/utils/analysis_server/BUILD.gn
index 29c34d9..d8d0cea 100644
--- a/utils/analysis_server/BUILD.gn
+++ b/utils/analysis_server/BUILD.gn
@@ -4,13 +4,6 @@
 
 import("../application_snapshot.gni")
 
-analysis_server_files = exec_script("../../tools/list_dart_files.py",
-                                    [
-                                      "absolute",
-                                      rebase_path("../../pkg/analysis_server"),
-                                    ],
-                                    "list lines")
-
 application_snapshot("analysis_server") {
   main_dart = "../../pkg/analysis_server/bin/server.dart"
   training_args = [
@@ -19,5 +12,4 @@
     # "--sdk=" + rebase_path("../../sdk/"),
     # "--train-using=" + rebase_path("../../pkg/analyzer_cli")
   ]
-  inputs = analysis_server_files
 }
diff --git a/utils/application_snapshot.gni b/utils/application_snapshot.gni
index 890c108..7ecdf28 100644
--- a/utils/application_snapshot.gni
+++ b/utils/application_snapshot.gni
@@ -85,12 +85,15 @@
     deps = extra_deps + [
              "$_dart_root/runtime/vm:kernel_platform_files($host_toolchain)",
              "$_dart_root/runtime/vm:vm_platform",
+             "$_dart_root/utils/gen_kernel:bootstrap_gen_kernel",
            ]
-    gen_kernel_script = "$_dart_root/pkg/vm/bin/gen_kernel.dart"
+    gen_kernel_kernel =
+        get_label_info("$_dart_root/utils/gen_kernel:bootstrap_gen_kernel",
+                       "target_gen_dir") + "/bootstrap_gen_kernel.dill"
     platform_dill = "$root_out_dir/vm_platform_strong.dill"
 
     inputs = extra_inputs + [
-               gen_kernel_script,
+               gen_kernel_kernel,
                platform_dill,
                main_dart,
                dot_packages,
@@ -99,18 +102,13 @@
     outputs = [ output ]
 
     depfile = "$output.d"
-    abs_depfile = rebase_path(depfile)
-    rebased_output = rebase_path(output, root_build_dir)
 
     vm_args = [
-      "--depfile=$abs_depfile",
-      "--depfile_output_filename=$rebased_output",
-
       # Ensure gen_kernel.dart will use this SDK hash when consuming/producing kernel.
       "-Dsdk_hash=$sdk_hash",
     ]
 
-    script = gen_kernel_script
+    script = gen_kernel_kernel
 
     args = [
       "--packages=" + rebase_path(dot_packages),
@@ -118,7 +116,8 @@
       "--no-aot",
       "--no-embed-sources",
       "--no-link-platform",
-      "--output=" + rebase_path(output),
+      "--output=" + rebase_path(output, root_build_dir),
+      "--depfile=" + rebase_path(depfile),
 
       # Ensure the compiled appliation (e.g. kernel-service, frontend-server,
       # ...) will use this SDK hash when consuming/producing kernel.
diff --git a/utils/bazel/BUILD.gn b/utils/bazel/BUILD.gn
index 774f301..6f6d3da 100644
--- a/utils/bazel/BUILD.gn
+++ b/utils/bazel/BUILD.gn
@@ -7,5 +7,4 @@
 application_snapshot("kernel_worker") {
   main_dart = "kernel_worker.dart"
   training_args = [ "--help" ]
-  deps = [ "../../pkg:pkg_files_stamp" ]
 }
diff --git a/utils/dartanalyzer/BUILD.gn b/utils/dartanalyzer/BUILD.gn
index 78c84b0..0c007ab 100644
--- a/utils/dartanalyzer/BUILD.gn
+++ b/utils/dartanalyzer/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("../../build/dart/dart_action.gni")
 import("../application_snapshot.gni")
+import("../create_timestamp.gni")
 
 group("dartanalyzer") {
   deps = [
@@ -12,13 +13,6 @@
   ]
 }
 
-analyzer_files = exec_script("../../tools/list_dart_files.py",
-                             [
-                               "absolute",
-                               rebase_path("../../pkg/analyzer"),
-                             ],
-                             "list lines")
-
 application_snapshot("generate_dartanalyzer_snapshot") {
   main_dart = "../../pkg/analyzer_cli/bin/analyzer.dart"
   training_args = [
@@ -31,21 +25,21 @@
   name = "dartanalyzer"
 }
 
-sdk_lib_files = exec_script("../../tools/list_dart_files.py",
-                            [
-                              "absolute",
-                              rebase_path("../../sdk/lib"),
-                            ],
-                            "list lines")
+sdk_root = "../../sdk"
+
+create_timestamp_file("sdk_lib_files") {
+  path = rebase_path("$sdk_root/lib")
+  output = "$target_gen_dir/sdk_lib_files.stamp"
+}
 
 dart_action("generate_summary_strong") {
   deps = [
+    ":sdk_lib_files",
     "../../sdk:copy_libraries",
     "../../sdk:write_version_file",
   ]
   script = "../../pkg/analyzer/tool/summary/build_sdk_summaries.dart"
   packages = "../../.packages"
-  inputs = sdk_lib_files + analyzer_files
   output = "$root_gen_dir/strong.sum"
   outputs = [ output ]
   vm_args = [ "-Dsdk_hash=$sdk_hash" ]
diff --git a/utils/dartdev/BUILD.gn b/utils/dartdev/BUILD.gn
index c7d8c12..7f33d99 100644
--- a/utils/dartdev/BUILD.gn
+++ b/utils/dartdev/BUILD.gn
@@ -4,13 +4,6 @@
 
 import("../application_snapshot.gni")
 
-dartdev_files = exec_script("../../tools/list_dart_files.py",
-                            [
-                              "absolute",
-                              rebase_path("../../pkg/dartdev"),
-                            ],
-                            "list lines")
-
 group("dartdev") {
   public_deps = [
     ":copy_dartdev_kernel",
@@ -30,7 +23,6 @@
   main_dart = "../../pkg/dartdev/bin/dartdev.dart"
   training_args = []
   deps = [ "../dds:dds" ]
-  inputs = dartdev_files
   output = "$root_gen_dir/dartdev.dill"
 }
 
@@ -45,6 +37,5 @@
   main_dart = "../../pkg/dartdev/bin/dartdev.dart"
   training_args = [ "--help" ]
   deps = [ "../dds:dds" ]
-  inputs = dartdev_files
   output = "$root_gen_dir/dartdev.dart.snapshot"
 }
diff --git a/utils/dartdevc/BUILD.gn b/utils/dartdevc/BUILD.gn
index 9b9f07c..74c0cc3 100644
--- a/utils/dartdevc/BUILD.gn
+++ b/utils/dartdevc/BUILD.gn
@@ -40,27 +40,6 @@
 
 sdk_root = "../../sdk"
 
-sdk_lib_files = exec_script("../../tools/list_dart_files.py",
-                            [
-                              "absolute",
-                              rebase_path("$sdk_root/lib"),
-                            ],
-                            "list lines")
-
-compiler_files = exec_script("../../tools/list_dart_files.py",
-                             [
-                               "absolute",
-                               rebase_path("../../pkg/compiler"),
-                             ],
-                             "list lines")
-
-dev_compiler_files = exec_script("../../tools/list_dart_files.py",
-                                 [
-                                   "absolute",
-                                   rebase_path("../../pkg/dev_compiler"),
-                                 ],
-                                 "list lines")
-
 template("dart2js_compile") {
   assert(defined(invoker.main), "Must specify the main file")
   main = invoker.main
@@ -70,12 +49,12 @@
   abs_output = rebase_path(out)
 
   prebuilt_dart_action(target_name) {
-    deps = [ "../compiler:compile_dart2js_platform" ]
+    deps = invoker.deps + [ "../compiler:compile_dart2js_platform" ]
 
-    inputs = sdk_lib_files + compiler_files + dev_compiler_files + [
-               "$root_out_dir/dart2js_platform.dill",
-               "$root_out_dir/dart2js_outline.dill",
-             ]
+    inputs = [
+      "$root_out_dir/dart2js_platform.dill",
+      "$root_out_dir/dart2js_outline.dill",
+    ]
     outputs = [ out ]
 
     script = "../../pkg/compiler/lib/src/dart2js.dart"
@@ -97,6 +76,7 @@
 dart2js_compile("stack_trace_mapper") {
   main = rebase_path("../../pkg/dev_compiler/web/stack_trace_mapper.dart")
   out = "$root_out_dir/dev_compiler/build/web/dart_stack_trace_mapper.js"
+  deps = [ ":dartdevc_files_stamp" ]
 }
 
 # Builds everything needed to run dartdevc tests using test.dart.
@@ -180,16 +160,11 @@
     deps = [
       ":dartdevc_files_stamp",
       platform_dep,
-
-      # TODO(sigmund): depend only on the compiler and the actual files in the
-      # package
-      "../../pkg:pkg_files_stamp",
     ]
 
     inputs = [
       sdk_outline,
       "$target_gen_dir/dartdevc_files.stamp",
-      "$root_gen_dir/pkg_files.stamp",
     ]
 
     outputs = [
@@ -327,17 +302,9 @@
   }
 
   prebuilt_dart_action(target_name) {
-    deps = [
-      ":dartdevc_files_stamp",
-      "../../pkg:pkg_files_stamp",
-      platform_dep,
-    ]
+    deps = [ platform_dep ]
 
-    inputs = [
-      "$target_gen_dir/dartdevc_files.stamp",
-      "$root_gen_dir/pkg_files.stamp",
-      platform_input,
-    ]
+    inputs = [ platform_input ]
 
     outputs = [
       "$js_gen_dir/amd/dart_sdk.js",
diff --git a/utils/dds/BUILD.gn b/utils/dds/BUILD.gn
index dd76925..2a5d36f 100644
--- a/utils/dds/BUILD.gn
+++ b/utils/dds/BUILD.gn
@@ -4,13 +4,6 @@
 
 import("../application_snapshot.gni")
 
-dds_files = exec_script("../../tools/list_dart_files.py",
-                        [
-                          "absolute",
-                          rebase_path("../../pkg/dds"),
-                        ],
-                        "list lines")
-
 group("dds") {
   public_deps = [ ":copy_dds_snapshot" ]
 }
@@ -25,6 +18,5 @@
 application_snapshot("generate_dds_snapshot") {
   main_dart = "../../pkg/dds/bin/dds.dart"
   training_args = []
-  inputs = dds_files
   output = "$root_gen_dir/dds.dart.snapshot"
 }
diff --git a/utils/gen_kernel/BUILD.gn b/utils/gen_kernel/BUILD.gn
index a1417bb..0df5722 100644
--- a/utils/gen_kernel/BUILD.gn
+++ b/utils/gen_kernel/BUILD.gn
@@ -2,6 +2,43 @@
 # 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("../../build/dart/dart_action.gni")
+import("../../sdk_args.gni")
+
+_dart_root = get_path_info("../..", "abspath")
+
+prebuilt_dart_action("bootstrap_gen_kernel") {
+  deps = [
+    "$_dart_root/runtime/vm:kernel_platform_files($host_toolchain)",
+    "$_dart_root/runtime/vm:vm_platform",
+  ]
+  gen_kernel_script = "$_dart_root/pkg/vm/bin/gen_kernel.dart"
+  platform_dill = "$root_out_dir/vm_platform_strong.dill"
+  dot_packages = rebase_path("$_dart_root/.packages")
+
+  inputs = [
+    gen_kernel_script,
+    platform_dill,
+    dot_packages,
+  ]
+  output = "$target_gen_dir/bootstrap_gen_kernel.dill"
+  outputs = [ output ]
+
+  depfile = "$output.d"
+  vm_args = [
+    "--snapshot-kind=kernel",
+    "--snapshot=" + rebase_path(output, root_build_dir),
+    "--depfile=" + rebase_path(depfile),
+
+    # Ensure gen_kernel.dart will use this SDK hash when consuming/producing kernel.
+    "-Dsdk_hash=$sdk_hash",
+
+    "--packages=" + rebase_path(dot_packages),
+  ]
+  script = gen_kernel_script
+  args = []
+}
+
 import("../application_snapshot.gni")
 
 application_snapshot("gen_kernel") {