Version 2.12.0-244.0.dev

Merge commit '15cd98f5119833d36a24faab71bb770d8a84450c' into 'dev'
diff --git a/pkg/analysis_server/lib/src/computer/computer_highlights.dart b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
index e2ca9ea..8b4b43a 100644
--- a/pkg/analysis_server/lib/src/computer/computer_highlights.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
@@ -380,7 +380,9 @@
     var type = node.inDeclarationContext()
         ? HighlightRegionType.PARAMETER_DECLARATION
         : HighlightRegionType.PARAMETER_REFERENCE;
-    return _addRegion_node(node, type);
+    var modifiers =
+        node.parent is Label ? {CustomSemanticTokenModifiers.label} : null;
+    return _addRegion_node(node, type, semanticTokenModifiers: modifiers);
   }
 
   bool _addIdentifierRegion_typeParameter(SimpleIdentifier node) {
@@ -459,10 +461,21 @@
     }
   }
 
-  bool _addRegion_node(AstNode node, HighlightRegionType type) {
+  bool _addRegion_node(
+    AstNode node,
+    HighlightRegionType type, {
+    SemanticTokenTypes semanticTokenType,
+    Set<SemanticTokenModifiers> semanticTokenModifiers,
+  }) {
     var offset = node.offset;
     var length = node.length;
-    _addRegion(offset, length, type);
+    _addRegion(
+      offset,
+      length,
+      type,
+      semanticTokenType: semanticTokenType,
+      semanticTokenModifiers: semanticTokenModifiers,
+    );
     return true;
   }
 
diff --git a/pkg/analysis_server/lib/src/lsp/constants.dart b/pkg/analysis_server/lib/src/lsp/constants.dart
index ebc2978..8e751a4 100644
--- a/pkg/analysis_server/lib/src/lsp/constants.dart
+++ b/pkg/analysis_server/lib/src/lsp/constants.dart
@@ -100,15 +100,23 @@
 }
 
 abstract class CustomSemanticTokenModifiers {
-  // A modifier applied to control keywords like if/for/etc. so they can be
-  // coloured differently to other keywords (void, import, etc), matching the
-  // original Dart textmate grammar.
-  // https://github.com/dart-lang/dart-syntax-highlight/blob/84a8e84f79bc917ebd959a4587349c865dc945e0/grammars/dart.json#L244-L261
+  /// A modifier applied to control keywords like if/for/etc. so they can be
+  /// coloured differently to other keywords (void, import, etc), matching the
+  /// original Dart textmate grammar.
+  /// https://github.com/dart-lang/dart-syntax-highlight/blob/84a8e84f79bc917ebd959a4587349c865dc945e0/grammars/dart.json#L244-L261
   static const control = SemanticTokenModifiers('control');
 
+  /// A modifier applied to parameter references to indicate they are the name/label
+  /// to allow theming them differently to the values. For example in the code
+  /// `foo({String a}) => foo(a: a)` the a's will be differentiated as:
+  /// - parameter.declaration
+  /// - parameter.label
+  /// - parameter
+  static const label = SemanticTokenModifiers('label');
+
   /// All custom semantic token modifiers, used to populate the LSP Legend which must
   /// include all used modifiers.
-  static const values = [control];
+  static const values = [control, label];
 }
 
 abstract class CustomSemanticTokenTypes {
diff --git a/pkg/analysis_server/test/lsp/semantic_tokens_test.dart b/pkg/analysis_server/test/lsp/semantic_tokens_test.dart
index 3886184..dfd4324 100644
--- a/pkg/analysis_server/test/lsp/semantic_tokens_test.dart
+++ b/pkg/analysis_server/test/lsp/semantic_tokens_test.dart
@@ -600,6 +600,33 @@
     expect(decoded, equals(expected));
   }
 
+  Future<void> test_namedArguments() async {
+    final content = '''
+    f({String a}) {
+      f(a: a);
+    }    
+    ''';
+
+    final expected = [
+      _Token('f', SemanticTokenTypes.function,
+          [SemanticTokenModifiers.declaration, SemanticTokenModifiers.static]),
+      _Token('String', SemanticTokenTypes.class_),
+      _Token('a', SemanticTokenTypes.parameter,
+          [SemanticTokenModifiers.declaration]),
+      _Token('f', SemanticTokenTypes.function),
+      _Token('a', SemanticTokenTypes.parameter,
+          [CustomSemanticTokenModifiers.label]),
+      _Token('a', SemanticTokenTypes.parameter),
+    ];
+
+    await initialize();
+    await openFile(mainFileUri, withoutMarkers(content));
+
+    final tokens = await getSemanticTokens(mainFileUri);
+    final decoded = decodeSemanticTokens(content, tokens);
+    expect(decoded, equals(expected));
+  }
+
   Future<void> test_range() async {
     final content = '''
     /// class docs
diff --git a/pkg/nnbd_migration/lib/migration_cli.dart b/pkg/nnbd_migration/lib/migration_cli.dart
index 785b5a6..df8da53 100644
--- a/pkg/nnbd_migration/lib/migration_cli.dart
+++ b/pkg/nnbd_migration/lib/migration_cli.dart
@@ -813,25 +813,7 @@
   /// return additional paths that aren't inside the user's project, but doesn't
   /// override this method, then those additional paths will be analyzed but not
   /// migrated.
-  bool shouldBeMigrated(String path) => shouldBeMigrated2(path);
-
-  /// Determines whether a migrated version of the file at [path] should be
-  /// output by the migration too.  May be overridden by a derived class.
-  ///
-  /// This method should return `false` for files that are being considered by
-  /// the migration tool for information only (for example generated files, or
-  /// usages of the code-to-be-migrated by one one of its clients).
-  ///
-  /// By default returns `true` if the file is contained within the context
-  /// root.  This means that if a client overrides [computePathsToProcess] to
-  /// return additional paths that aren't inside the user's project, but doesn't
-  /// override this method, then those additional paths will be analyzed but not
-  /// migrated.
-  ///
-  /// Note: in a future version of the code, this method will be removed;
-  /// clients that are overriding this method should switch to overriding
-  /// [shouldBeMigrated] instead.
-  bool shouldBeMigrated2(String path) {
+  bool shouldBeMigrated(String path) {
     return analysisContext.contextRoot.isAnalyzed(path);
   }
 
diff --git a/pkg/nnbd_migration/lib/src/preview/preview_site.dart b/pkg/nnbd_migration/lib/src/preview/preview_site.dart
index 0a58fbe..9799335 100644
--- a/pkg/nnbd_migration/lib/src/preview/preview_site.dart
+++ b/pkg/nnbd_migration/lib/src/preview/preview_site.dart
@@ -179,6 +179,10 @@
 
     var index = 0;
 
+    // Returns the next line and updates [index].
+    //
+    // After this function returns, [index] points to the character after the
+    // end of the line which was returned.
     String getLine() {
       var nextIndex = code.indexOf('\n', index);
       if (nextIndex < 0) {
@@ -220,24 +224,37 @@
         // [code] consists _only_ of one comment line.
         return '$code$newline$newline// @dart=2.9$newline';
       }
-      line = getLine();
-      lineStart = line.indexOf(_nonWhitespaceChar);
-      while (lineStart >= 0 &&
-          line.length > lineStart + 1 &&
-          line.codeUnitAt(lineStart) == $slash &&
-          line.codeUnitAt(lineStart + 1) == $slash) {
-        // Another comment line.
+      var previousLineIndex = index;
+      while (true) {
+        previousLineIndex = index;
         line = getLine();
-        if (index == length) {
-          // [code] consists _only_ of this block comment.
-          return '$code$newline$newline// @dart=2.9$newline';
-        }
         lineStart = line.indexOf(_nonWhitespaceChar);
+        if (lineStart < 0) {
+          // Line of whitespace; end of block comment.
+          break;
+        }
+        if (line.length <= lineStart + 1) {
+          // Only one character; not a comment; end of block comment.
+          break;
+        }
+        if (line.codeUnitAt(lineStart) == $slash &&
+            line.codeUnitAt(lineStart + 1) == $slash) {
+          // Comment line.
+          if (index == length) {
+            // [code] consists _only_ of this block comment.
+            return '$code$newline$newline// @dart=2.9$newline';
+          }
+          continue;
+        } else {
+          // Non-blank, non-comment line.
+          break;
+        }
       }
-      // [index] points to the start of [line], which is the first
+      // [previousLineIndex] points to the start of [line], which is the first
       // non-comment line following the first comment.
-      return '${code.substring(0, index)}$newline// @dart=2.9$newline$newline'
-          '${code.substring(index)}';
+      return '${code.substring(0, previousLineIndex)}$newline'
+          '// @dart=2.9$newline$newline'
+          '${code.substring(previousLineIndex)}';
     } else {
       // [code] does not start with a block comment.
       return '// @dart=2.9$newline$newline$code';
diff --git a/pkg/nnbd_migration/test/migration_cli_test.dart b/pkg/nnbd_migration/test/migration_cli_test.dart
index 6121240..f065da9 100644
--- a/pkg/nnbd_migration/test/migration_cli_test.dart
+++ b/pkg/nnbd_migration/test/migration_cli_test.dart
@@ -185,9 +185,9 @@
   }
 
   @override
-  bool shouldBeMigrated2(String path) =>
+  bool shouldBeMigrated(String path) =>
       cli._test.overrideShouldBeMigrated?.call(path) ??
-      super.shouldBeMigrated2(path);
+      super.shouldBeMigrated(path);
 
   /// Sorts the paths in [paths] for repeatability of migration tests.
   Set<String> _sortPaths(Set<String> paths) {
diff --git a/pkg/nnbd_migration/test/preview/preview_site_test.dart b/pkg/nnbd_migration/test/preview/preview_site_test.dart
index 9ec1b23f..ca9348c 100644
--- a/pkg/nnbd_migration/test/preview/preview_site_test.dart
+++ b/pkg/nnbd_migration/test/preview/preview_site_test.dart
@@ -156,14 +156,29 @@
   void test_optOutOfNullSafety_commentThenCode() {
     expect(
         IncrementalPlan.optCodeOutOfNullSafety('// comment\n\nvoid main() {}'),
-        equals('// comment\n\n\n// @dart=2.9\n\nvoid main() {}'));
+        equals('// comment\n\n// @dart=2.9\n\n\nvoid main() {}'));
   }
 
   void test_optOutOfNullSafety_commentThenCode_windows() {
     expect(
         IncrementalPlan.optCodeOutOfNullSafety(
             '// comment\r\n\r\nvoid main() {}'),
-        equals('// comment\r\n\r\n\r\n// @dart=2.9\r\n\r\nvoid main() {}'));
+        equals('// comment\r\n\r\n// @dart=2.9\r\n\r\n\r\nvoid main() {}'));
+  }
+
+  void test_optOutOfNullSafety_commentThenDirective() {
+    expect(
+        IncrementalPlan.optCodeOutOfNullSafety(
+            '// comment\nimport "dart:core";'),
+        equals('// comment\n\n// @dart=2.9\n\nimport "dart:core";'));
+  }
+
+  void test_optOutOfNullSafety_commentThenDirective_multiLine() {
+    expect(
+        IncrementalPlan.optCodeOutOfNullSafety(
+            '// comment\n// comment\nimport "dart:core";'),
+        equals(
+            '// comment\n// comment\n\n// @dart=2.9\n\nimport "dart:core";'));
   }
 
   void test_optOutOfNullSafety_empty() {
diff --git a/tools/VERSION b/tools/VERSION
index 2bbd3fd..1113dfc 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 243
+PRERELEASE 244
 PRERELEASE_PATCH 0
\ No newline at end of file