Version 2.15.0-186.0.dev

Merge commit '198dc4307516ec4b4db4facfbd6924193a721ed3' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/pubspec.yaml b/pkg/_fe_analyzer_shared/pubspec.yaml
index 8d97c49..0e1fea0 100644
--- a/pkg/_fe_analyzer_shared/pubspec.yaml
+++ b/pkg/_fe_analyzer_shared/pubspec.yaml
@@ -1,5 +1,5 @@
 name: _fe_analyzer_shared
-version: 27.0.0
+version: 28.0.0
 description: Logic that is shared between the front_end and analyzer packages.
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/_fe_analyzer_shared
 
diff --git a/pkg/analysis_server/lib/src/cider/fixes.dart b/pkg/analysis_server/lib/src/cider/fixes.dart
index e17d1cc..b3898bd 100644
--- a/pkg/analysis_server/lib/src/cider/fixes.dart
+++ b/pkg/analysis_server/lib/src/cider/fixes.dart
@@ -5,11 +5,13 @@
 import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
 import 'package:analysis_server/src/services/correction/change_workspace.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
 import 'package:analysis_server/src/services/correction/fix_internal.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/instrumentation/service.dart';
 import 'package:analyzer/source/line_info.dart';
 import 'package:analyzer/src/dart/analysis/performance_logger.dart';
+import 'package:analyzer/src/dart/micro/library_graph.dart' as cider;
 import 'package:analyzer/src/dart/micro/resolve_file.dart';
 
 class CiderErrorFixes {
@@ -50,7 +52,7 @@
             workspace,
             resolvedUnit,
             error,
-            (name) => const [],
+            _topLevelDeclarations,
           );
 
           var fixes = await DartFixContributor().computeFixes(context);
@@ -65,4 +67,33 @@
 
     return result;
   }
+
+  List<TopLevelDeclaration> _topLevelDeclarations(String name) {
+    var result = <TopLevelDeclaration>[];
+    var files = _fileResolver.getFilesWithTopLevelDeclarations(name);
+    for (var fileWithKind in files) {
+      void addDeclaration(TopLevelDeclarationKind kind) {
+        var file = fileWithKind.file;
+        result.add(
+          TopLevelDeclaration(file.path, file.uri, kind, name, false),
+        );
+      }
+
+      switch (fileWithKind.kind) {
+        case cider.FileTopLevelDeclarationKind.extension:
+          addDeclaration(TopLevelDeclarationKind.extension);
+          break;
+        case cider.FileTopLevelDeclarationKind.function:
+          addDeclaration(TopLevelDeclarationKind.function);
+          break;
+        case cider.FileTopLevelDeclarationKind.type:
+          addDeclaration(TopLevelDeclarationKind.type);
+          break;
+        case cider.FileTopLevelDeclarationKind.variable:
+          addDeclaration(TopLevelDeclarationKind.variable);
+          break;
+      }
+    }
+    return result;
+  }
 }
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_trailing_comma.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_trailing_comma.dart
new file mode 100644
index 0000000..c66a0a1
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_trailing_comma.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+
+class AddTrailingComma extends CorrectionProducer {
+  @override
+  bool get canBeAppliedInBulk => true;
+
+  @override
+  bool get canBeAppliedToFile => true;
+
+  @override
+  FixKind get fixKind => DartFixKind.ADD_TRAILING_COMMA;
+
+  @override
+  FixKind get multiFixKind => DartFixKind.ADD_TRAILING_COMMA_MULTI;
+
+  @override
+  Future<void> compute(ChangeBuilder builder) async {
+    final node = this.node;
+    if (node is! ArgumentList) return;
+    final parent = node.parent;
+    if (parent == null) return;
+
+    await builder.addDartFileEdit(file, (builder) {
+      builder.addSimpleInsertion(node.arguments.last.end, ',');
+    });
+  }
+
+  /// Return an instance of this class. Used as a tear-off in `FixProcessor`.
+  static AddTrailingComma newInstance() => AddTrailingComma();
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_into_block_body.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_into_block_body.dart
index 8ec13f6..dbbea0b 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_into_block_body.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_into_block_body.dart
@@ -5,71 +5,105 @@
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/source/source_range.dart';
 import 'package:analyzer/src/dart/ast/extensions.dart';
 import 'package:analyzer_plugin/utilities/assist/assist.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
-import 'package:analyzer_plugin/utilities/range_factory.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+
+import '../fix.dart';
 
 class ConvertIntoBlockBody extends CorrectionProducer {
   @override
   AssistKind get assistKind => DartAssistKind.CONVERT_INTO_BLOCK_BODY;
 
   @override
-  Future<void> compute(ChangeBuilder builder) async {
-    var body = getEnclosingFunctionBody();
-    // prepare expression body
-    if (body is! ExpressionFunctionBody || body.isGenerator) {
-      return;
-    }
+  FixKind get fixKind => DartFixKind.CONVERT_INTO_BLOCK_BODY;
 
+  @override
+  Future<void> compute(ChangeBuilder builder) async {
+    final body = getEnclosingFunctionBody();
+    if (body == null || body.isGenerator) return;
+
+    List<String>? codeLines;
+
+    if (body is ExpressionFunctionBody) {
+      codeLines = _getCodeForFunctionBody(body);
+    } else if (body is EmptyFunctionBody) {
+      codeLines = _getCodeForEmptyBody(body);
+    }
+    if (codeLines == null) return;
+
+    // prepare prefix
+    var prefix = utils.getNodePrefix(body.parent!);
+    var indent = utils.getIndent(1);
+    var start = body.beginToken.previous!.end;
+    var length = body.end - start;
+
+    await builder.addDartFileEdit(file, (builder) {
+      builder.addReplacement(SourceRange(start, length), (builder) {
+        builder.write(' ');
+        if (body.isAsynchronous) {
+          builder.write('async ');
+        }
+        builder.write('{');
+        for (var line in codeLines!) {
+          builder.write('$eol$prefix$indent');
+          builder.write(line);
+        }
+        builder.selectHere();
+        builder.write('$eol$prefix}');
+      });
+    });
+  }
+
+  List<String>? _getCodeForEmptyBody(EmptyFunctionBody body) {
+    var functionElement = _getFunctionElement(body.parent);
+    if (functionElement == null) return null;
+
+    var lines = ['// TODO: implement ${functionElement.name}'];
+
+    var returnValueType = functionElement.returnType;
+    if (!returnValueType.isVoid) {
+      lines.add('throw UnimplementedError();');
+    }
+    return lines;
+  }
+
+  List<String>? _getCodeForFunctionBody(ExpressionFunctionBody body) {
     var returnValue = body.expression;
 
     // Return expressions can be quite large, e.g. Flutter build() methods.
     // It is surprising to see this Quick Assist deep in the function body.
     if (selectionOffset >= returnValue.offset) {
-      return;
-    }
-
-    DartType? getFunctionReturnType() {
-      var parent = body.parent;
-      if (parent is MethodDeclaration) {
-        return parent.declaredElement?.returnType;
-      } else if (parent is ConstructorDeclaration) {
-        return parent.declaredElement?.returnType;
-      } else if (parent is FunctionExpression) {
-        return parent.declaredElement?.returnType;
-      }
       return null;
     }
 
-    var functionReturnType = getFunctionReturnType();
-    if (functionReturnType == null) {
-      return;
-    }
+    var functionElement = _getFunctionElement(body.parent);
+    if (functionElement == null) return null;
+
     var returnValueType = returnValue.typeOrThrow;
     var returnValueCode = utils.getNodeText(returnValue);
-    // prepare prefix
-    var prefix = utils.getNodePrefix(body.parent!);
-    var indent = utils.getIndent(1);
+    var returnCode = '';
+    if (!returnValueType.isVoid &&
+        !returnValueType.isBottom &&
+        !functionElement.returnType.isVoid) {
+      returnCode = 'return ';
+    }
+    returnCode += '$returnValueCode;';
+    return [returnCode];
+  }
 
-    await builder.addDartFileEdit(file, (builder) {
-      builder.addReplacement(range.node(body), (builder) {
-        if (body.isAsynchronous) {
-          builder.write('async ');
-        }
-        builder.write('{$eol$prefix$indent');
-        if (!returnValueType.isVoid &&
-            !returnValueType.isBottom &&
-            !functionReturnType.isVoid) {
-          builder.write('return ');
-        }
-        builder.write(returnValueCode);
-        builder.write(';');
-        builder.selectHere();
-        builder.write('$eol$prefix}');
-      });
-    });
+  ExecutableElement? _getFunctionElement(AstNode? node) {
+    if (node is MethodDeclaration) {
+      return node.declaredElement;
+    } else if (node is ConstructorDeclaration) {
+      return node.declaredElement;
+    } else if (node is FunctionExpression) {
+      return node.declaredElement;
+    }
+    return null;
   }
 
   /// Return an instance of this class. Used as a tear-off in `AssistProcessor`.
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index dd5593b..c9ec3cf 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -244,6 +244,16 @@
     DartFixKindPriority.IN_FILE,
     "Add 'break' everywhere in file",
   );
+  static const ADD_TRAILING_COMMA = FixKind(
+    'dart.fix.add.trailingComma',
+    DartFixKindPriority.DEFAULT,
+    'Add trailing comma',
+  );
+  static const ADD_TRAILING_COMMA_MULTI = FixKind(
+    'dart.fix.add.trailingComma.multi',
+    DartFixKindPriority.IN_FILE,
+    'Add trailing commas everywhere in file',
+  );
   static const ADD_TYPE_ANNOTATION = FixKind(
     'dart.fix.add.typeAnnotation',
     DartFixKindPriority.DEFAULT,
@@ -289,6 +299,11 @@
     DartFixKindPriority.DEFAULT,
     'Convert to child:',
   );
+  static const CONVERT_INTO_BLOCK_BODY = FixKind(
+    'dart.fix.convert.bodyToBlock',
+    DartFixKindPriority.DEFAULT,
+    'Convert to block body',
+  );
   static const CONVERT_FOR_EACH_TO_FOR_LOOP = FixKind(
     'dart.fix.convert.toForLoop',
     DartFixKindPriority.DEFAULT,
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 7454202..6e50224 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -29,6 +29,7 @@
 import 'package:analysis_server/src/services/correction/dart/add_static.dart';
 import 'package:analysis_server/src/services/correction/dart/add_super_constructor_invocation.dart';
 import 'package:analysis_server/src/services/correction/dart/add_switch_case_break.dart';
+import 'package:analysis_server/src/services/correction/dart/add_trailing_comma.dart';
 import 'package:analysis_server/src/services/correction/dart/add_type_annotation.dart';
 import 'package:analysis_server/src/services/correction/dart/change_argument_name.dart';
 import 'package:analysis_server/src/services/correction/dart/change_to.dart';
@@ -40,6 +41,7 @@
 import 'package:analysis_server/src/services/correction/dart/convert_documentation_into_line.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_flutter_child.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_flutter_children.dart';
+import 'package:analysis_server/src/services/correction/dart/convert_into_block_body.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_into_is_not.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_map_from_iterable_to_for_literal.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_quotes.dart';
@@ -94,6 +96,7 @@
 import 'package:analysis_server/src/services/correction/dart/move_type_arguments_to_class.dart';
 import 'package:analysis_server/src/services/correction/dart/organize_imports.dart';
 import 'package:analysis_server/src/services/correction/dart/qualify_reference.dart';
+import 'package:analysis_server/src/services/correction/dart/remove_abstract.dart';
 import 'package:analysis_server/src/services/correction/dart/remove_annotation.dart';
 import 'package:analysis_server/src/services/correction/dart/remove_argument.dart';
 import 'package:analysis_server/src/services/correction/dart/remove_await.dart';
@@ -181,8 +184,6 @@
 import 'package:analyzer_plugin/utilities/change_builder/conflicting_edit_exception.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart' hide FixContributor;
 
-import 'dart/remove_abstract.dart';
-
 /// A function that can be executed to create a multi-correction producer.
 typedef MultiProducerGenerator = MultiCorrectionProducer Function();
 
@@ -553,6 +554,9 @@
     LintNames.sort_child_properties_last: [
       SortChildPropertyLast.newInstance,
     ],
+    LintNames.require_trailing_commas: [
+      AddTrailingComma.newInstance,
+    ],
     LintNames.type_annotate_public_apis: [
       // TODO(brianwilkerson) Consider applying in bulk.
       AddTypeAnnotation.newInstance,
@@ -797,7 +801,7 @@
       CreateMixin.newInstance,
     ],
     CompileTimeErrorCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER: [
-      CreateMissingOverrides.newInstance,
+      ConvertIntoBlockBody.newInstance,
       CreateNoSuchMethod.newInstance,
       MakeClassAbstract.newInstance,
     ],
@@ -1249,6 +1253,9 @@
     ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE: [
       AddTypeAnnotation.newInstance,
     ],
+    ParserErrorCode.MISSING_FUNCTION_BODY: [
+      ConvertIntoBlockBody.newInstance,
+    ],
     ParserErrorCode.VAR_AS_TYPE_NAME: [
       ReplaceVarWithDynamic.newInstance,
     ],
diff --git a/pkg/analysis_server/lib/src/services/linter/lint_names.dart b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
index e7db85a..b43b980 100644
--- a/pkg/analysis_server/lib/src/services/linter/lint_names.dart
+++ b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
@@ -104,6 +104,7 @@
   static const String prefer_typing_uninitialized_variables =
       'prefer_typing_uninitialized_variables';
   static const String prefer_void_to_null = 'prefer_void_to_null';
+  static const String require_trailing_commas = 'require_trailing_commas';
   static const String sized_box_for_whitespace = 'sized_box_for_whitespace';
   static const String slash_for_doc_comments = 'slash_for_doc_comments';
   static const String sort_child_properties_last = 'sort_child_properties_last';
diff --git a/pkg/analysis_server/test/src/cider/fixes_test.dart b/pkg/analysis_server/test/src/cider/fixes_test.dart
index 4e57e14..ff775e5 100644
--- a/pkg/analysis_server/test/src/cider/fixes_test.dart
+++ b/pkg/analysis_server/test/src/cider/fixes_test.dart
@@ -72,6 +72,128 @@
 ''');
   }
 
+  Future<void> test_importLibrary_withClass() async {
+    var a_path = '/workspace/dart/test/lib/a.dart';
+    newFile(a_path, content: r'''
+class Test {}
+''');
+    fileResolver.resolve(path: a_path);
+
+    await _compute(r'''
+void f(Test a) {}^
+''');
+
+    assertHasFix(DartFixKind.IMPORT_LIBRARY_PROJECT1, r'''
+import 'a.dart';
+
+void f(Test a) {}
+''');
+  }
+
+  Future<void> test_importLibrary_withEnum() async {
+    var a_path = '/workspace/dart/test/lib/a.dart';
+    newFile(a_path, content: r'''
+enum Test {a, b, c}
+''');
+    fileResolver.resolve(path: a_path);
+
+    await _compute(r'''
+void f(Test a) {}^
+''');
+
+    assertHasFix(DartFixKind.IMPORT_LIBRARY_PROJECT1, r'''
+import 'a.dart';
+
+void f(Test a) {}
+''');
+  }
+
+  Future<void> test_importLibrary_withExtension() async {
+    var a_path = '/workspace/dart/test/lib/a.dart';
+    newFile(a_path, content: r'''
+extension E on int {
+  void foo() {}
+}
+''');
+    fileResolver.resolve(path: a_path);
+
+    await _compute(r'''
+void f() {
+  E(0).foo();^
+}
+''');
+
+    assertHasFix(DartFixKind.IMPORT_LIBRARY_PROJECT1, r'''
+import 'a.dart';
+
+void f() {
+  E(0).foo();
+}
+''');
+  }
+
+  Future<void> test_importLibrary_withFunction() async {
+    var a_path = '/workspace/dart/test/lib/a.dart';
+    newFile(a_path, content: r'''
+void foo() {}
+''');
+    fileResolver.resolve(path: a_path);
+
+    await _compute(r'''
+void f() {
+  foo();^
+}
+''');
+
+    assertHasFix(DartFixKind.IMPORT_LIBRARY_PROJECT1, r'''
+import 'a.dart';
+
+void f() {
+  foo();
+}
+''');
+  }
+
+  Future<void> test_importLibrary_withMixin() async {
+    var a_path = '/workspace/dart/test/lib/a.dart';
+    newFile(a_path, content: r'''
+mixin Test {}
+''');
+    fileResolver.resolve(path: a_path);
+
+    await _compute(r'''
+void f(Test a) {}^
+''');
+
+    assertHasFix(DartFixKind.IMPORT_LIBRARY_PROJECT1, r'''
+import 'a.dart';
+
+void f(Test a) {}
+''');
+  }
+
+  Future<void> test_importLibrary_withTopLevelVariable() async {
+    var a_path = '/workspace/dart/test/lib/a.dart';
+    newFile(a_path, content: r'''
+var a = 0;
+''');
+    fileResolver.resolve(path: a_path);
+
+    await _compute(r'''
+void f() {
+  a;^
+}
+''');
+
+    assertHasFix(DartFixKind.IMPORT_LIBRARY_PROJECT1, r'''
+import 'a.dart';
+
+void f() {
+  a;
+}
+''');
+  }
+
   Future<void> test_insertSemicolon() async {
     await _compute(r'''
 var v = 0^
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_trailing_comma_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_trailing_comma_test.dart
new file mode 100644
index 0000000..bf7c774
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_trailing_comma_test.dart
@@ -0,0 +1,89 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test/expect.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(AddTrailingCommaBulkTest);
+    defineReflectiveTests(AddTrailingCommaInFileTest);
+    defineReflectiveTests(AddTrailingCommaTest);
+  });
+}
+
+@reflectiveTest
+class AddTrailingCommaBulkTest extends BulkFixProcessorTest {
+  @override
+  String get lintCode => LintNames.require_trailing_commas;
+
+  Future<void> test_bulk() async {
+    await resolveTestCode('''
+Object f(a, b) {
+  f(f('a',
+      'b'), 'b');
+  return a;
+}
+''');
+    await assertHasFix('''
+Object f(a, b) {
+  f(f('a',
+      'b',), 'b',);
+  return a;
+}
+''');
+  }
+}
+
+@reflectiveTest
+class AddTrailingCommaInFileTest extends FixInFileProcessorTest {
+  Future<void> test_File() async {
+    createAnalysisOptionsFile(lints: [LintNames.require_trailing_commas]);
+    await resolveTestCode(r'''
+Object f(a, b) {
+  f(f('a',
+      'b'), 'b');
+  return a;
+}
+''');
+    var fixes = await getFixesForFirstError();
+    expect(fixes, hasLength(1));
+    assertProduces(fixes.first, r'''
+Object f(a, b) {
+  f(f('a',
+      'b',), 'b',);
+  return a;
+}
+''');
+  }
+}
+
+@reflectiveTest
+class AddTrailingCommaTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.ADD_TRAILING_COMMA;
+
+  @override
+  String get lintCode => LintNames.require_trailing_commas;
+
+  Future<void> test_comma() async {
+    await resolveTestCode('''
+void f(a, b) {
+  f('a',
+    'b');
+}
+''');
+    await assertHasFix('''
+void f(a, b) {
+  f('a',
+    'b',);
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_into_block_body_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_into_block_body_test.dart
new file mode 100644
index 0000000..8d2f3e8
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_into_block_body_test.dart
@@ -0,0 +1,79 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ConvertIntoBlockBodyTest);
+  });
+}
+
+@reflectiveTest
+class ConvertIntoBlockBodyTest extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.CONVERT_INTO_BLOCK_BODY;
+
+  Future<void> test_function() async {
+    await resolveTestCode('''
+void f();
+''');
+    await assertHasFix('''
+void f() {
+  // TODO: implement f
+}
+''');
+  }
+
+  Future<void> test_method_Never() async {
+    await resolveTestCode('''
+class A {
+  Never m();
+}
+''');
+    await assertHasFix('''
+class A {
+  Never m() {
+    // TODO: implement m
+    throw UnimplementedError();
+  }
+}
+''');
+  }
+
+  Future<void> test_method_nonVoid() async {
+    await resolveTestCode('''
+class A {
+  String m(int i);
+}
+''');
+    await assertHasFix('''
+class A {
+  String m(int i) {
+    // TODO: implement m
+    throw UnimplementedError();
+  }
+}
+''');
+  }
+
+  Future<void> test_method_void() async {
+    await resolveTestCode('''
+class A {
+  void m();
+}
+''');
+    await assertHasFix('''
+class A {
+  void m() {
+    // TODO: implement m
+  }
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
index 7422ec8..fb32189 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
@@ -35,6 +35,7 @@
 import 'add_super_constructor_invocation_test.dart'
     as add_super_constructor_invocation;
 import 'add_switch_case_break_test.dart' as add_switch_case_break;
+import 'add_trailing_comma_test.dart' as add_trailing_comma;
 import 'add_type_annotation_test.dart' as add_type_annotation;
 import 'analysis_options/test_all.dart' as analysis_options;
 import 'bulk_fix_processor_test.dart' as bulk_fix_processor;
@@ -49,6 +50,7 @@
 import 'convert_flutter_child_test.dart' as convert_flutter_child;
 import 'convert_flutter_children_test.dart' as convert_flutter_children;
 import 'convert_for_each_to_for_loop_test.dart' as convert_for_each_to_for_loop;
+import 'convert_into_block_body_test.dart' as convert_into_block_body;
 import 'convert_into_expression_body_test.dart' as convert_into_expression_body;
 import 'convert_into_is_not_test.dart' as convert_into_is_not;
 import 'convert_quotes_test.dart' as convert_quotes;
@@ -232,6 +234,7 @@
     add_static.main();
     add_super_constructor_invocation.main();
     add_switch_case_break.main();
+    add_trailing_comma.main();
     add_type_annotation.main();
     analysis_options.main();
     bulk_fix_processor.main();
@@ -244,6 +247,7 @@
     convert_flutter_child.main();
     convert_flutter_children.main();
     convert_for_each_to_for_loop.main();
+    convert_into_block_body.main();
     convert_into_expression_body.main();
     convert_into_is_not.main();
     convert_quotes.main();
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 7007543..26adc7d 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,6 @@
+## 2.5.0
+* Updated `MockSdk` to include more declarations.
+
 ## 2.4.0
 * Deprecated `ResourceProvider.getModificationTimes()`.
 * Deprecated `MemoryResourceProvider.newDummyLink()`.
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
index a235cbb..07f0e0e 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
@@ -1375,6 +1375,7 @@
   static const HintCode INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER = HintCode(
     'INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER',
     "The member '{0}' can only be used for overriding.",
+    hasPublishedDocs: true,
   );
 
   /**
@@ -1488,6 +1489,7 @@
   static const HintCode INVALID_VISIBLE_FOR_OVERRIDING_ANNOTATION = HintCode(
     'INVALID_VISIBLE_FOR_OVERRIDING_ANNOTATION',
     "The declaration '{0}' is annotated with 'visibleForOverriding'. Because '{0}' isn't an interface member that could be overridden, the annotation is meaningless.",
+    hasPublishedDocs: true,
   );
 
   /**
@@ -1910,6 +1912,7 @@
     'NULL_ARGUMENT_TO_NON_NULL_TYPE',
     "'{0}' shouldn't be called with a null argument for the non-nullable type argument '{1}'.",
     correctionMessage: "Try adding a non-null argument.",
+    hasPublishedDocs: true,
   );
 
   /**
@@ -2379,6 +2382,7 @@
     "Tearing off a constructor requires the 'constructor-tearoffs' language feature.",
     correctionMessage:
         "Try updating your pubspec.yaml to set the minimum SDK constraint to 2.15 or higher, and running 'pub get'.",
+    hasPublishedDocs: true,
   );
 
   /**
@@ -2558,6 +2562,7 @@
     'SDK_VERSION_GT_GT_GT_OPERATOR',
     "The operator '>>>' wasn't supported until version 2.14.0, but this code is required to be able to run on earlier versions.",
     correctionMessage: "Try updating the SDK constraints.",
+    hasPublishedDocs: true,
   );
 
   /**
@@ -3053,6 +3058,7 @@
   static const HintCode UNDEFINED_REFERENCED_PARAMETER = HintCode(
     'UNDEFINED_REFERENCED_PARAMETER',
     "The parameter '{0}' is not defined by '{1}'.",
+    hasPublishedDocs: true,
   );
 
   /**
@@ -3205,6 +3211,7 @@
     'UNNECESSARY_IMPORT',
     "The import of '{0}' is unnecessary because all of the used elements are also provided by the import of '{1}'.",
     correctionMessage: "Try removing the import directive.",
+    hasPublishedDocs: true,
   );
 
   /**
@@ -3363,6 +3370,7 @@
   static const HintCode UNNECESSARY_QUESTION_MARK = HintCode(
     'UNNECESSARY_QUESTION_MARK',
     "The '?' is unnecessary because '{0}' is nullable without it.",
+    hasPublishedDocs: true,
   );
 
   /**
@@ -3810,6 +3818,7 @@
     "The value of '{0}' should be used.",
     correctionMessage:
         "Try using the result by invoking a member, passing it to a function, or returning it from this function.",
+    hasPublishedDocs: true,
   );
 
   /**
@@ -3826,6 +3835,7 @@
     "'{0}' should be used. {1}.",
     correctionMessage:
         "Try using the result by invoking a member, passing it to a function, or returning it from this function.",
+    hasPublishedDocs: true,
     uniqueName: 'UNUSED_RESULT_WITH_MESSAGE',
   );
 
@@ -3892,6 +3902,7 @@
     'USE_OF_NATIVE_EXTENSION',
     "Dart native extensions are deprecated and aren’t available in Dart 2.15.",
     correctionMessage: "Try using dart:ffi for C interop.",
+    hasPublishedDocs: true,
   );
 
   /// Initialize a newly created error code to have the given [name].
diff --git a/pkg/analyzer/lib/src/dart/micro/library_graph.dart b/pkg/analyzer/lib/src/dart/micro/library_graph.dart
index cbee620..328c16a 100644
--- a/pkg/analyzer/lib/src/dart/micro/library_graph.dart
+++ b/pkg/analyzer/lib/src/dart/micro/library_graph.dart
@@ -88,6 +88,7 @@
   late bool _exists;
   late List<int> _apiSignature;
   late UnlinkedUnit2 unlinked2;
+  late TopLevelDeclarations topLevelDeclarations;
   Uint8List? informativeBytes;
   LibraryCycle? _libraryCycle;
 
@@ -274,9 +275,18 @@
           informativeBytes = informativeData!.bytes;
         });
 
+        var decoded = CiderUnlinkedUnit.fromBuffer(unlinkedBytes!);
+        unlinked2 = decoded.unlinkedUnit!;
+
+        var unitDeclarations = decoded.topLevelDeclarations!;
+        topLevelDeclarations = TopLevelDeclarations(
+          extensionNames: unitDeclarations.extensionNames.toList(),
+          functionNames: unitDeclarations.functionNames.toList(),
+          typeNames: unitDeclarations.typeNames.toList(),
+          variableNames: unitDeclarations.variableNames.toList(),
+        );
+
         performance.run('prefetch', (_) {
-          var decoded = CiderUnlinkedUnit.fromBuffer(unlinkedBytes!);
-          unlinked2 = decoded.unlinkedUnit!;
           _prefetchDirectReferences(unlinked2);
         });
       }
@@ -493,6 +503,32 @@
         ),
       );
     }
+
+    var declaredExtensions = <String>[];
+    var declaredFunctions = <String>[];
+    var declaredTypes = <String>[];
+    var declaredVariables = <String>[];
+    for (var declaration in unit.declarations) {
+      if (declaration is ClassDeclaration) {
+        declaredTypes.add(declaration.name.name);
+      } else if (declaration is EnumDeclaration) {
+        declaredTypes.add(declaration.name.name);
+      } else if (declaration is ExtensionDeclaration) {
+        var name = declaration.name;
+        if (name != null) {
+          declaredExtensions.add(name.name);
+        }
+      } else if (declaration is FunctionDeclaration) {
+        declaredFunctions.add(declaration.name.name);
+      } else if (declaration is MixinDeclaration) {
+        declaredTypes.add(declaration.name.name);
+      } else if (declaration is TopLevelVariableDeclaration) {
+        for (var variable in declaration.variables.variables) {
+          declaredVariables.add(variable.name.name);
+        }
+      }
+    }
+
     var unlinkedBuilder = UnlinkedUnit2Builder(
       apiSignature: computeUnlinkedApiSignature(unit),
       exports: exports,
@@ -505,7 +541,15 @@
       lineStarts: unit.lineInfo!.lineStarts,
     );
     return CiderUnlinkedUnitBuilder(
-        contentDigest: digest, unlinkedUnit: unlinkedBuilder);
+      contentDigest: digest,
+      unlinkedUnit: unlinkedBuilder,
+      topLevelDeclarations: CiderUnitTopLevelDeclarationsBuilder(
+        extensionNames: declaredExtensions,
+        functionNames: declaredFunctions,
+        typeNames: declaredTypes,
+        variableNames: declaredVariables,
+      ),
+    );
   }
 
   static UnlinkedNamespaceDirectiveBuilder _serializeNamespaceDirective(
@@ -712,6 +756,44 @@
     return result;
   }
 
+  /// Return files that have a top-level declaration with the [name].
+  List<FileWithTopLevelDeclaration> getFilesWithTopLevelDeclarations(
+    String name,
+  ) {
+    var result = <FileWithTopLevelDeclaration>[];
+
+    for (var file in _pathToFile.values) {
+      void addDeclaration(
+        List<String> names,
+        FileTopLevelDeclarationKind kind,
+      ) {
+        if (names.contains(name)) {
+          result.add(
+            FileWithTopLevelDeclaration(file: file, kind: kind),
+          );
+        }
+      }
+
+      addDeclaration(
+        file.topLevelDeclarations.extensionNames,
+        FileTopLevelDeclarationKind.extension,
+      );
+      addDeclaration(
+        file.topLevelDeclarations.functionNames,
+        FileTopLevelDeclarationKind.function,
+      );
+      addDeclaration(
+        file.topLevelDeclarations.typeNames,
+        FileTopLevelDeclarationKind.type,
+      );
+      addDeclaration(
+        file.topLevelDeclarations.variableNames,
+        FileTopLevelDeclarationKind.variable,
+      );
+    }
+    return result;
+  }
+
   String? getPathForUri(Uri uri) {
     var source = _sourceFactory.forUri2(uri);
     if (source == null) {
@@ -789,6 +871,20 @@
   }
 }
 
+/// The kind in [FileWithTopLevelDeclaration].
+enum FileTopLevelDeclarationKind { extension, function, type, variable }
+
+/// The data structure for top-level declarations response.
+class FileWithTopLevelDeclaration {
+  final FileState file;
+  final FileTopLevelDeclarationKind kind;
+
+  FileWithTopLevelDeclaration({
+    required this.file,
+    required this.kind,
+  });
+}
+
 /// Information about libraries that reference each other, so form a cycle.
 class LibraryCycle {
   /// The libraries that belong to this cycle.
@@ -824,6 +920,26 @@
   }
 }
 
+/// Kind of a top-level declaration.
+///
+/// We don't need it to be precise, just enough to support quick fixes.
+enum TopLevelDeclarationKind { type, extension, function, variable }
+
+/// Information about a single top-level declaration.
+class TopLevelDeclarations {
+  final List<String> extensionNames;
+  final List<String> functionNames;
+  final List<String> typeNames;
+  final List<String> variableNames;
+
+  TopLevelDeclarations({
+    required this.extensionNames,
+    required this.functionNames,
+    required this.typeNames,
+    required this.variableNames,
+  });
+}
+
 class _FakeSource implements Source {
   @override
   final String fullName;
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index daf5dbd..21dc0ef 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -313,6 +313,17 @@
     });
   }
 
+  /// Return files that have a top-level declaration with the [name].
+  List<FileWithTopLevelDeclaration> getFilesWithTopLevelDeclarations(
+    String name,
+  ) {
+    final fsState = this.fsState;
+    if (fsState == null) {
+      return const [];
+    }
+    return fsState.getFilesWithTopLevelDeclarations(name);
+  }
+
   LibraryElement getLibraryByUri({
     required String uriStr,
     OperationPerformanceImpl? performance,
diff --git a/pkg/analyzer/lib/src/error/codes.g.dart b/pkg/analyzer/lib/src/error/codes.g.dart
index 38bf0a3..dd11f38 100644
--- a/pkg/analyzer/lib/src/error/codes.g.dart
+++ b/pkg/analyzer/lib/src/error/codes.g.dart
@@ -3137,6 +3137,7 @@
     "Required named parameters can't have a default value.",
     correctionMessage:
         "Try removing either the default value or the 'required' modifier.",
+    hasPublishedDocs: true,
   );
 
   /**
@@ -5411,6 +5412,7 @@
     "A method tear-off on a receiver whose type is 'dynamic' can't have type arguments.",
     correctionMessage:
         "Specify the type of the receiver, or remove the type arguments from the method tear-off.",
+    hasPublishedDocs: true,
   );
 
   /**
@@ -6478,6 +6480,7 @@
     'INSTANTIATE_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER',
     "Type aliases that expand to a type parameter can't be instantiated.",
     correctionMessage: "Try replacing it with a class.",
+    hasPublishedDocs: true,
   );
 
   /**
@@ -6690,6 +6693,7 @@
     "Constant values from a deferred library can't be used in annotations.",
     correctionMessage:
         "Try moving the constant from the deferred library, or removing 'deferred' from the import.",
+    hasPublishedDocs: true,
   );
 
   /**
@@ -10588,6 +10592,7 @@
   static const CompileTimeErrorCode NOT_BINARY_OPERATOR = CompileTimeErrorCode(
     'NOT_BINARY_OPERATOR',
     "'{0}' isn't a binary operator.",
+    hasPublishedDocs: true,
   );
 
   /**
@@ -12313,6 +12318,7 @@
     'REDIRECT_TO_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER',
     "A redirecting constructor can't redirect to a type alias that expands to a type parameter.",
     correctionMessage: "Try replacing it with a class.",
+    hasPublishedDocs: true,
   );
 
   /**
@@ -13084,6 +13090,7 @@
     "A generative constructor of an abstract class can't be torn off.",
     correctionMessage:
         "Try tearing off a constructor of a concrete class, or a non-generative constructor.",
+    hasPublishedDocs: true,
   );
 
   /**
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 6db5b7f..e59c7f2 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -3633,10 +3633,226 @@
   String toString() => convert.json.encode(toJson());
 }
 
+class CiderUnitTopLevelDeclarationsBuilder extends Object
+    with _CiderUnitTopLevelDeclarationsMixin
+    implements idl.CiderUnitTopLevelDeclarations {
+  List<String>? _extensionNames;
+  List<String>? _functionNames;
+  List<String>? _typeNames;
+  List<String>? _variableNames;
+
+  @override
+  List<String> get extensionNames => _extensionNames ??= <String>[];
+
+  set extensionNames(List<String> value) {
+    this._extensionNames = value;
+  }
+
+  @override
+  List<String> get functionNames => _functionNames ??= <String>[];
+
+  set functionNames(List<String> value) {
+    this._functionNames = value;
+  }
+
+  @override
+  List<String> get typeNames => _typeNames ??= <String>[];
+
+  set typeNames(List<String> value) {
+    this._typeNames = value;
+  }
+
+  @override
+  List<String> get variableNames => _variableNames ??= <String>[];
+
+  set variableNames(List<String> value) {
+    this._variableNames = value;
+  }
+
+  CiderUnitTopLevelDeclarationsBuilder(
+      {List<String>? extensionNames,
+      List<String>? functionNames,
+      List<String>? typeNames,
+      List<String>? variableNames})
+      : _extensionNames = extensionNames,
+        _functionNames = functionNames,
+        _typeNames = typeNames,
+        _variableNames = variableNames;
+
+  /// Flush [informative] data recursively.
+  void flushInformative() {}
+
+  /// Accumulate non-[informative] data into [signature].
+  void collectApiSignature(api_sig.ApiSignature signatureSink) {
+    var extensionNames = this._extensionNames;
+    if (extensionNames == null) {
+      signatureSink.addInt(0);
+    } else {
+      signatureSink.addInt(extensionNames.length);
+      for (var x in extensionNames) {
+        signatureSink.addString(x);
+      }
+    }
+    var functionNames = this._functionNames;
+    if (functionNames == null) {
+      signatureSink.addInt(0);
+    } else {
+      signatureSink.addInt(functionNames.length);
+      for (var x in functionNames) {
+        signatureSink.addString(x);
+      }
+    }
+    var typeNames = this._typeNames;
+    if (typeNames == null) {
+      signatureSink.addInt(0);
+    } else {
+      signatureSink.addInt(typeNames.length);
+      for (var x in typeNames) {
+        signatureSink.addString(x);
+      }
+    }
+    var variableNames = this._variableNames;
+    if (variableNames == null) {
+      signatureSink.addInt(0);
+    } else {
+      signatureSink.addInt(variableNames.length);
+      for (var x in variableNames) {
+        signatureSink.addString(x);
+      }
+    }
+  }
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    fb.Offset? offset_extensionNames;
+    fb.Offset? offset_functionNames;
+    fb.Offset? offset_typeNames;
+    fb.Offset? offset_variableNames;
+    var extensionNames = _extensionNames;
+    if (!(extensionNames == null || extensionNames.isEmpty)) {
+      offset_extensionNames = fbBuilder.writeList(
+          extensionNames.map((b) => fbBuilder.writeString(b)).toList());
+    }
+    var functionNames = _functionNames;
+    if (!(functionNames == null || functionNames.isEmpty)) {
+      offset_functionNames = fbBuilder.writeList(
+          functionNames.map((b) => fbBuilder.writeString(b)).toList());
+    }
+    var typeNames = _typeNames;
+    if (!(typeNames == null || typeNames.isEmpty)) {
+      offset_typeNames = fbBuilder
+          .writeList(typeNames.map((b) => fbBuilder.writeString(b)).toList());
+    }
+    var variableNames = _variableNames;
+    if (!(variableNames == null || variableNames.isEmpty)) {
+      offset_variableNames = fbBuilder.writeList(
+          variableNames.map((b) => fbBuilder.writeString(b)).toList());
+    }
+    fbBuilder.startTable();
+    if (offset_extensionNames != null) {
+      fbBuilder.addOffset(0, offset_extensionNames);
+    }
+    if (offset_functionNames != null) {
+      fbBuilder.addOffset(1, offset_functionNames);
+    }
+    if (offset_typeNames != null) {
+      fbBuilder.addOffset(2, offset_typeNames);
+    }
+    if (offset_variableNames != null) {
+      fbBuilder.addOffset(3, offset_variableNames);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _CiderUnitTopLevelDeclarationsReader
+    extends fb.TableReader<_CiderUnitTopLevelDeclarationsImpl> {
+  const _CiderUnitTopLevelDeclarationsReader();
+
+  @override
+  _CiderUnitTopLevelDeclarationsImpl createObject(
+          fb.BufferContext bc, int offset) =>
+      _CiderUnitTopLevelDeclarationsImpl(bc, offset);
+}
+
+class _CiderUnitTopLevelDeclarationsImpl extends Object
+    with _CiderUnitTopLevelDeclarationsMixin
+    implements idl.CiderUnitTopLevelDeclarations {
+  final fb.BufferContext _bc;
+  final int _bcOffset;
+
+  _CiderUnitTopLevelDeclarationsImpl(this._bc, this._bcOffset);
+
+  List<String>? _extensionNames;
+  List<String>? _functionNames;
+  List<String>? _typeNames;
+  List<String>? _variableNames;
+
+  @override
+  List<String> get extensionNames {
+    return _extensionNames ??= const fb.ListReader<String>(fb.StringReader())
+        .vTableGet(_bc, _bcOffset, 0, const <String>[]);
+  }
+
+  @override
+  List<String> get functionNames {
+    return _functionNames ??= const fb.ListReader<String>(fb.StringReader())
+        .vTableGet(_bc, _bcOffset, 1, const <String>[]);
+  }
+
+  @override
+  List<String> get typeNames {
+    return _typeNames ??= const fb.ListReader<String>(fb.StringReader())
+        .vTableGet(_bc, _bcOffset, 2, const <String>[]);
+  }
+
+  @override
+  List<String> get variableNames {
+    return _variableNames ??= const fb.ListReader<String>(fb.StringReader())
+        .vTableGet(_bc, _bcOffset, 3, const <String>[]);
+  }
+}
+
+abstract class _CiderUnitTopLevelDeclarationsMixin
+    implements idl.CiderUnitTopLevelDeclarations {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    var local_extensionNames = extensionNames;
+    if (local_extensionNames.isNotEmpty) {
+      _result["extensionNames"] = local_extensionNames;
+    }
+    var local_functionNames = functionNames;
+    if (local_functionNames.isNotEmpty) {
+      _result["functionNames"] = local_functionNames;
+    }
+    var local_typeNames = typeNames;
+    if (local_typeNames.isNotEmpty) {
+      _result["typeNames"] = local_typeNames;
+    }
+    var local_variableNames = variableNames;
+    if (local_variableNames.isNotEmpty) {
+      _result["variableNames"] = local_variableNames;
+    }
+    return _result;
+  }
+
+  @override
+  Map<String, Object?> toMap() => {
+        "extensionNames": extensionNames,
+        "functionNames": functionNames,
+        "typeNames": typeNames,
+        "variableNames": variableNames,
+      };
+
+  @override
+  String toString() => convert.json.encode(toJson());
+}
+
 class CiderUnlinkedUnitBuilder extends Object
     with _CiderUnlinkedUnitMixin
     implements idl.CiderUnlinkedUnit {
   List<int>? _contentDigest;
+  CiderUnitTopLevelDeclarationsBuilder? _topLevelDeclarations;
   UnlinkedUnit2Builder? _unlinkedUnit;
 
   @override
@@ -3649,6 +3865,15 @@
   }
 
   @override
+  CiderUnitTopLevelDeclarationsBuilder? get topLevelDeclarations =>
+      _topLevelDeclarations;
+
+  /// Top-level declarations of the unit.
+  set topLevelDeclarations(CiderUnitTopLevelDeclarationsBuilder? value) {
+    this._topLevelDeclarations = value;
+  }
+
+  @override
   UnlinkedUnit2Builder? get unlinkedUnit => _unlinkedUnit;
 
   /// Unlinked summary of the compilation unit.
@@ -3657,12 +3882,16 @@
   }
 
   CiderUnlinkedUnitBuilder(
-      {List<int>? contentDigest, UnlinkedUnit2Builder? unlinkedUnit})
+      {List<int>? contentDigest,
+      CiderUnitTopLevelDeclarationsBuilder? topLevelDeclarations,
+      UnlinkedUnit2Builder? unlinkedUnit})
       : _contentDigest = contentDigest,
+        _topLevelDeclarations = topLevelDeclarations,
         _unlinkedUnit = unlinkedUnit;
 
   /// Flush [informative] data recursively.
   void flushInformative() {
+    _topLevelDeclarations?.flushInformative();
     _unlinkedUnit?.flushInformative();
   }
 
@@ -3677,6 +3906,8 @@
         signatureSink.addInt(x);
       }
     }
+    signatureSink.addBool(this._topLevelDeclarations != null);
+    this._topLevelDeclarations?.collectApiSignature(signatureSink);
     signatureSink.addBool(this._unlinkedUnit != null);
     this._unlinkedUnit?.collectApiSignature(signatureSink);
   }
@@ -3688,11 +3919,16 @@
 
   fb.Offset finish(fb.Builder fbBuilder) {
     fb.Offset? offset_contentDigest;
+    fb.Offset? offset_topLevelDeclarations;
     fb.Offset? offset_unlinkedUnit;
     var contentDigest = _contentDigest;
     if (!(contentDigest == null || contentDigest.isEmpty)) {
       offset_contentDigest = fbBuilder.writeListUint32(contentDigest);
     }
+    var topLevelDeclarations = _topLevelDeclarations;
+    if (topLevelDeclarations != null) {
+      offset_topLevelDeclarations = topLevelDeclarations.finish(fbBuilder);
+    }
     var unlinkedUnit = _unlinkedUnit;
     if (unlinkedUnit != null) {
       offset_unlinkedUnit = unlinkedUnit.finish(fbBuilder);
@@ -3701,8 +3937,11 @@
     if (offset_contentDigest != null) {
       fbBuilder.addOffset(0, offset_contentDigest);
     }
+    if (offset_topLevelDeclarations != null) {
+      fbBuilder.addOffset(1, offset_topLevelDeclarations);
+    }
     if (offset_unlinkedUnit != null) {
-      fbBuilder.addOffset(1, offset_unlinkedUnit);
+      fbBuilder.addOffset(2, offset_unlinkedUnit);
     }
     return fbBuilder.endTable();
   }
@@ -3730,6 +3969,7 @@
   _CiderUnlinkedUnitImpl(this._bc, this._bcOffset);
 
   List<int>? _contentDigest;
+  idl.CiderUnitTopLevelDeclarations? _topLevelDeclarations;
   idl.UnlinkedUnit2? _unlinkedUnit;
 
   @override
@@ -3739,9 +3979,16 @@
   }
 
   @override
+  idl.CiderUnitTopLevelDeclarations? get topLevelDeclarations {
+    return _topLevelDeclarations ??=
+        const _CiderUnitTopLevelDeclarationsReader()
+            .vTableGetOrNull(_bc, _bcOffset, 1);
+  }
+
+  @override
   idl.UnlinkedUnit2? get unlinkedUnit {
     return _unlinkedUnit ??=
-        const _UnlinkedUnit2Reader().vTableGetOrNull(_bc, _bcOffset, 1);
+        const _UnlinkedUnit2Reader().vTableGetOrNull(_bc, _bcOffset, 2);
   }
 }
 
@@ -3753,6 +4000,10 @@
     if (local_contentDigest.isNotEmpty) {
       _result["contentDigest"] = local_contentDigest;
     }
+    var local_topLevelDeclarations = topLevelDeclarations;
+    if (local_topLevelDeclarations != null) {
+      _result["topLevelDeclarations"] = local_topLevelDeclarations.toJson();
+    }
     var local_unlinkedUnit = unlinkedUnit;
     if (local_unlinkedUnit != null) {
       _result["unlinkedUnit"] = local_unlinkedUnit.toJson();
@@ -3763,6 +4014,7 @@
   @override
   Map<String, Object?> toMap() => {
         "contentDigest": contentDigest,
+        "topLevelDeclarations": topLevelDeclarations,
         "unlinkedUnit": unlinkedUnit,
       };
 
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index 75c773b..18b2f2a 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -422,14 +422,28 @@
   signature:[uint] (id: 0);
 }
 
+/// Top-level declarations in a compilation unit.
+table CiderUnitTopLevelDeclarations {
+  extensionNames:[string] (id: 0);
+
+  functionNames:[string] (id: 1);
+
+  typeNames:[string] (id: 2);
+
+  variableNames:[string] (id: 3);
+}
+
 /// Information about a compilation unit, contains the content hash
 /// and unlinked summary.
 table CiderUnlinkedUnit {
   /// The hash signature of the contents of the file.
   contentDigest:[uint] (id: 0);
 
+  /// Top-level declarations of the unit.
+  topLevelDeclarations:CiderUnitTopLevelDeclarations (id: 1);
+
   /// Unlinked summary of the compilation unit.
-  unlinkedUnit:UnlinkedUnit2 (id: 1);
+  unlinkedUnit:UnlinkedUnit2 (id: 2);
 }
 
 table DiagnosticMessage {
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index ee5b366..d715b69 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -463,6 +463,21 @@
   List<int> get signature;
 }
 
+/// Top-level declarations in a compilation unit.
+abstract class CiderUnitTopLevelDeclarations extends base.SummaryClass {
+  @Id(0)
+  List<String> get extensionNames;
+
+  @Id(1)
+  List<String> get functionNames;
+
+  @Id(2)
+  List<String> get typeNames;
+
+  @Id(3)
+  List<String> get variableNames;
+}
+
 /// Information about a compilation unit, contains the content hash
 /// and unlinked summary.
 @TopLevel('CUUN')
@@ -474,8 +489,12 @@
   @Id(0)
   List<int> get contentDigest;
 
-  /// Unlinked summary of the compilation unit.
+  /// Top-level declarations of the unit.
   @Id(1)
+  CiderUnitTopLevelDeclarations? get topLevelDeclarations;
+
+  /// Unlinked summary of the compilation unit.
+  @Id(2)
   UnlinkedUnit2? get unlinkedUnit;
 }
 
diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml
index 50e2280..268f0cf 100644
--- a/pkg/analyzer/messages.yaml
+++ b/pkg/analyzer/messages.yaml
@@ -2923,6 +2923,7 @@
   DEFAULT_VALUE_ON_REQUIRED_PARAMETER:
     problemMessage: "Required named parameters can't have a default value."
     correctionMessage: "Try removing either the default value or the 'required' modifier."
+    hasPublishedDocs: true
     comment: No parameters.
     documentation: |-
       #### Description
@@ -4797,6 +4798,7 @@
   GENERIC_METHOD_TYPE_INSTANTIATION_ON_DYNAMIC:
     problemMessage: "A method tear-off on a receiver whose type is 'dynamic' can't have type arguments."
     correctionMessage: Specify the type of the receiver, or remove the type arguments from the method tear-off.
+    hasPublishedDocs: true
     comment: No parameters.
     documentation: |-
       #### Description
@@ -5706,6 +5708,7 @@
   INSTANTIATE_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER:
     problemMessage: "Type aliases that expand to a type parameter can't be instantiated."
     correctionMessage: Try replacing it with a class.
+    hasPublishedDocs: true
     comment: No parameters.
     documentation: |-
       #### Description
@@ -5887,6 +5890,7 @@
   INVALID_ANNOTATION_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY:
     problemMessage: "Constant values from a deferred library can't be used in annotations."
     correctionMessage: "Try moving the constant from the deferred library, or removing 'deferred' from the import."
+    hasPublishedDocs: true
     comment: No parameters.
     documentation: |-
       #### Description
@@ -9129,6 +9133,7 @@
       Replace the name with the name of a type.
   NOT_BINARY_OPERATOR:
     problemMessage: "'{0}' isn't a binary operator."
+    hasPublishedDocs: true
     comment: |-
       Parameters:
       0: the name of the operator that is not a binary operator.
@@ -10609,6 +10614,7 @@
   REDIRECT_TO_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER:
     problemMessage: "A redirecting constructor can't redirect to a type alias that expands to a type parameter."
     correctionMessage: Try replacing it with a class.
+    hasPublishedDocs: true
     comment: No parameters.
     documentation: |-
       #### Description
@@ -11473,6 +11479,7 @@
   TEAROFF_OF_GENERATIVE_CONSTRUCTOR_OF_ABSTRACT_CLASS:
     problemMessage: "A generative constructor of an abstract class can't be torn off."
     correctionMessage: Try tearing off a constructor of a concrete class, or a non-generative constructor.
+    hasPublishedDocs: true
     comment: No parameters.
     documentation: |-
       #### Description
@@ -15047,6 +15054,7 @@
       1: the name of the defining class
   INVALID_USE_OF_VISIBLE_FOR_OVERRIDING_MEMBER:
     problemMessage: "The member '{0}' can only be used for overriding."
+    hasPublishedDocs: true
     comment: |-
       Parameters:
       0: the name of the member
@@ -15158,6 +15166,7 @@
       ```
   INVALID_VISIBLE_FOR_OVERRIDING_ANNOTATION:
     problemMessage: "The declaration '{0}' is annotated with 'visibleForOverriding'. Because '{0}' isn't an interface member that could be overridden, the annotation is meaningless."
+    hasPublishedDocs: true
     comment: No parameters.
     documentation: |-
       #### Description
@@ -15534,6 +15543,7 @@
   NULL_ARGUMENT_TO_NON_NULL_TYPE:
     problemMessage: "'{0}' shouldn't be called with a null argument for the non-nullable type argument '{1}'."
     correctionMessage: Try adding a non-null argument.
+    hasPublishedDocs: true
     comment: |-
       Parameters:
       0: the name of the method being invoked
@@ -15847,6 +15857,7 @@
   SDK_VERSION_CONSTRUCTOR_TEAROFFS:
     problemMessage: "Tearing off a constructor requires the 'constructor-tearoffs' language feature."
     correctionMessage: "Try updating your pubspec.yaml to set the minimum SDK constraint to 2.15 or higher, and running 'pub get'."
+    hasPublishedDocs: true
     comment: |-
       No parameters.
 
@@ -16014,6 +16025,7 @@
   SDK_VERSION_GT_GT_GT_OPERATOR:
     problemMessage: "The operator '>>>' wasn't supported until version 2.14.0, but this code is required to be able to run on earlier versions."
     correctionMessage: Try updating the SDK constraints.
+    hasPublishedDocs: true
     comment: No parameters.
     documentation: |-
       #### Description
@@ -16483,6 +16495,7 @@
       ```
   UNDEFINED_REFERENCED_PARAMETER:
     problemMessage: "The parameter '{0}' is not defined by '{1}'."
+    hasPublishedDocs: true
     comment: |-
       Parameters:
       0: the name of the undefined parameter
@@ -16602,6 +16615,7 @@
   UNNECESSARY_IMPORT:
     problemMessage: "The import of '{0}' is unnecessary because all of the used elements are also provided by the import of '{1}'."
     correctionMessage: Try removing the import directive.
+    hasPublishedDocs: true
     comment: |-
       Parameters:
       0: the uri that is not necessary
@@ -16764,6 +16778,7 @@
     comment: No parameters.
   UNNECESSARY_QUESTION_MARK:
     problemMessage: "The '?' is unnecessary because '{0}' is nullable without it."
+    hasPublishedDocs: true
     comment: |-
       Parameters:
       0: the name of the type
@@ -17126,6 +17141,7 @@
   UNUSED_RESULT:
     problemMessage: "The value of '{0}' should be used."
     correctionMessage: Try using the result by invoking a member, passing it to a function, or returning it from this function.
+    hasPublishedDocs: true
     comment: |-
       Parameters:
       0: the name of the annotated method, property or function
@@ -17200,6 +17216,7 @@
     sharedName: UNUSED_RESULT
     problemMessage: "'{0}' should be used. {1}."
     correctionMessage: Try using the result by invoking a member, passing it to a function, or returning it from this function.
+    hasPublishedDocs: true
     comment: |-
       The result of invoking a method, property, or function annotated with
       `@useResult` must be used (assigned, passed to a function as an argument,
@@ -17245,6 +17262,7 @@
   USE_OF_NATIVE_EXTENSION:
     problemMessage: Dart native extensions are deprecated and aren’t available in Dart 2.15.
     correctionMessage: "Try using dart:ffi for C interop."
+    hasPublishedDocs: true
     comment: No parameters.
     documentation: |-
       #### Description
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 8497bb1..b717171 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 2.4.0
+version: 2.5.0
 description: This package provides a library that performs static analysis of Dart code.
 homepage: https://github.com/dart-lang/sdk/tree/main/pkg/analyzer
 
@@ -7,7 +7,7 @@
   sdk: '>=2.14.0 <3.0.0'
 
 dependencies:
-  _fe_analyzer_shared: ^27.0.0
+  _fe_analyzer_shared: ^28.0.0
   cli_util: ^0.3.0
   collection: ^1.15.0
   convert: ^3.0.0
@@ -25,7 +25,7 @@
     path: ../analyzer_utilities
   args: ^2.0.0
   async: ^2.5.0
-  linter: any
+  linter: ^1.12.0
   matcher: ^0.12.10
   test: ^1.16.0
   test_reflective_loader: ^0.2.0
diff --git a/pkg/dev_compiler/lib/src/kernel/module_metadata.dart b/pkg/dev_compiler/lib/src/kernel/module_metadata.dart
index 5669874..416f0d8 100644
--- a/pkg/dev_compiler/lib/src/kernel/module_metadata.dart
+++ b/pkg/dev_compiler/lib/src/kernel/module_metadata.dart
@@ -2,9 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
-/// Module metadata format version
+/// Module metadata format version.
 ///
 /// Module reader always creates the current version but is able to read
 /// metadata files with later versions as long as the changes are backward
@@ -22,10 +20,10 @@
     this.patchVersion,
   );
 
-  /// Current metadata version
+  /// The current metadata version.
   ///
-  /// Version follows simple semantic versioning format 'major.minor.patch'
-  /// See https://semver.org
+  /// Version follows simple semantic versioning format 'major.minor.patch'.
+  /// See: https://semver.org
   ///
   /// TODO(annagrin): create metadata package, make version the same as the
   /// metadata package version, automate updating with the package update
@@ -34,7 +32,7 @@
   /// Current metadata version created by the reader
   String get version => '$majorVersion.$minorVersion.$patchVersion';
 
-  /// Is this metadata version compatible with the given version
+  /// True if this metadata version is compatible with [version].
   ///
   /// The minor and patch version changes never remove any fields that current
   /// version supports, so the reader can create current metadata version from
@@ -55,28 +53,27 @@
   }
 }
 
-/// Library metadata
+/// Metadata used by the debugger to describe a library.
 ///
-/// Represents library metadata used in the debugger,
-/// supports reading from and writing to json
+/// Supports reading from and writing to json.
 /// See: https://goto.google.com/dart-web-debugger-metadata
 class LibraryMetadata {
   /// Library name as defined in pubspec.yaml
   final String name;
 
-  /// Library importUri
+  /// URI used to import the library.
   ///
-  /// Example package:path/path.dart
+  /// Example: package:path/path.dart
   final String importUri;
 
-  /// Library fileUri
+  /// File URI for the library.
   ///
-  /// Example file:///path/to/path/path.dart
+  /// Example: file:///path/to/path/path.dart
   final String fileUri;
 
-  /// All file uris from the library
+  /// All file URIs (include part files) from the library.
   ///
-  /// Can be relative paths to the directory of the fileUri
+  /// Can be relative paths to the directory of the fileUri.
   final List<String> partUris;
 
   LibraryMetadata(this.name, this.importUri, this.fileUri, this.partUris);
@@ -98,37 +95,35 @@
   }
 }
 
-/// Module metadata
+/// Metadata used by the debugger to describe a module.
 ///
-/// Represents module metadata used in the debugger,
-/// supports reading from and writing to json
+/// Supports reading from and writing to json.
 /// See: https://goto.google.com/dart-web-debugger-metadata
 class ModuleMetadata {
-  /// Metadata format version
-  String version;
+  /// The version of this metadata.
+  final String version;
 
-  /// Module name
+  /// Name of the js module created by the compiler.
   ///
-  /// Used as a name of the js module created by the compiler and
-  /// as key to store and load modules in the debugger and the browser
+  /// Used as a key to store and load modules in the debugger and the browser.
   final String name;
 
-  /// Name of the function enclosing the module
+  /// Name of the function enclosing the module.
   ///
-  /// Used by debugger to determine the top dart scope
+  /// Used by debugger to determine the top dart scope.
   final String closureName;
 
-  /// Source map uri
+  /// URI of the source map for this module.
   final String sourceMapUri;
 
-  /// Module uri
+  /// URI of the module.
   final String moduleUri;
 
-  /// The uri where DDC wrote a full .dill file for this module.
+  /// The URI where DDC wrote a full .dill file for this module.
   ///
-  /// Can be `null` if the module was compiled without the option to output the
-  /// .dill fle.
-  final String fullDillUri;
+  /// Will be `null` when the module was compiled without the option to output
+  /// the .dill fle.
+  final String? fullDillUri;
 
   final Map<String, LibraryMetadata> libraries = {};
 
@@ -138,14 +133,13 @@
 
   ModuleMetadata(this.name, this.closureName, this.sourceMapUri, this.moduleUri,
       this.fullDillUri, this.soundNullSafety,
-      {this.version}) {
-    version ??= ModuleMetadataVersion.current.version;
-  }
+      {String? version})
+      : version = version ??= ModuleMetadataVersion.current.version;
 
-  /// Add [library] to metadata
+  /// Add [library] to this metadata.
   ///
-  /// Used for filling the metadata in the compiler or for reading from
-  /// stored metadata files.
+  /// Used for filling the metadata in the compiler or for reading from stored
+  /// metadata files.
   void addLibrary(LibraryMetadata library) {
     if (!libraries.containsKey(library.importUri)) {
       libraries[library.importUri] = library;
@@ -165,9 +159,8 @@
         moduleUri = json['moduleUri'] as String,
         fullDillUri = json['fullDillUri'] as String,
         soundNullSafety = json['soundNullSafety'] as bool {
-    var fileVersion = json['version'] as String;
     if (!ModuleMetadataVersion.current.isCompatibleWith(version)) {
-      throw Exception('Unsupported metadata version $fileVersion');
+      throw Exception('Unsupported metadata version $version');
     }
 
     for (var l in json['libraries'] as List<dynamic>) {
diff --git a/pkg/dev_compiler/test/module_metadata_test.dart b/pkg/dev_compiler/test/module_metadata_test.dart
index 9d6c862..e3a74e0 100644
--- a/pkg/dev_compiler/test/module_metadata_test.dart
+++ b/pkg/dev_compiler/test/module_metadata_test.dart
@@ -2,19 +2,17 @@
 // 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.9
-
 import 'dart:convert';
 import 'dart:io';
 
 import 'package:dev_compiler/src/kernel/module_metadata.dart';
 import 'package:test/test.dart';
 
-// Test creating, reading and writing debugger metadata
+/// Test creating, reading and writing debugger metadata.
 void main() {
   group('Module metadata', () {
-    Directory tempDir;
-    File file;
+    late Directory tempDir;
+    late File file;
 
     setUpAll(() {
       var systemTempDir = Directory.systemTemp;
@@ -28,16 +26,16 @@
     });
 
     test('create, write, and read', () async {
-      // create metadata
+      // Create metadata.
       var version = ModuleMetadataVersion.current.version;
       var module = createMetadata(version);
       testMetadataFields(module, version);
 
-      // write metadata
+      // Write metadata.
       file.writeAsBytesSync(utf8.encode(json.encode(module)));
       expect(file.existsSync(), true);
 
-      // read metadata
+      // Read metadata.
       var moduleJson = json.decode(utf8.decode(file.readAsBytesSync()));
       var newModule =
           ModuleMetadata.fromJson(moduleJson as Map<String, dynamic>);
@@ -45,7 +43,7 @@
     });
 
     test('read later backward-compatible patch version', () async {
-      // create metadata with next patch version
+      // Create metadata with next patch version.
       var version = ModuleMetadataVersion(
               ModuleMetadataVersion.current.majorVersion,
               ModuleMetadataVersion.current.minorVersion,
@@ -54,11 +52,11 @@
 
       var module = createMetadata(version);
 
-      // write metadata
+      // Write metadata.
       file.writeAsBytesSync(utf8.encode(json.encode(module)));
       expect(file.existsSync(), true);
 
-      // read metadata
+      // Read metadata.
       var moduleJson = json.decode(utf8.decode(file.readAsBytesSync()));
       var newModule =
           ModuleMetadata.fromJson(moduleJson as Map<String, dynamic>);
@@ -66,7 +64,7 @@
     });
 
     test('read later backward-compatible minor version', () async {
-      // create metadata with next minor version
+      // Create metadata with next minor version.
       var version = ModuleMetadataVersion(
               ModuleMetadataVersion.current.majorVersion,
               ModuleMetadataVersion.current.minorVersion + 1,
@@ -74,11 +72,11 @@
           .version;
       var module = createMetadata(version);
 
-      // write metadata
+      // Write metadata.
       file.writeAsBytesSync(utf8.encode(json.encode(module)));
       expect(file.existsSync(), true);
 
-      // read metadata
+      // Read metadata.
       var moduleJson = json.decode(utf8.decode(file.readAsBytesSync()));
       var newModule =
           ModuleMetadata.fromJson(moduleJson as Map<String, dynamic>);
@@ -86,7 +84,7 @@
     });
 
     test('fail to read later non-backward-compatible major version', () async {
-      // create metadata with next minor version
+      // Create metadata with next minor version.
       var version = ModuleMetadataVersion(
               ModuleMetadataVersion.current.majorVersion + 1,
               ModuleMetadataVersion.current.minorVersion + 1,
@@ -94,13 +92,13 @@
           .version;
       var module = createMetadata(version);
 
-      // write metadata
+      // Write metadata.
       file.writeAsBytesSync(utf8.encode(json.encode(module)));
       expect(file.existsSync(), true);
 
-      // try read metadata, expect to fail
+      // Try read metadata, expect to fail.
       var moduleJson = json.decode(utf8.decode(file.readAsBytesSync()));
-      ModuleMetadata newModule;
+      ModuleMetadata? newModule;
       try {
         newModule = ModuleMetadata.fromJson(moduleJson as Map<String, dynamic>);
       } catch (e) {
@@ -120,7 +118,7 @@
       'file:///source/library/lib/test.dart', ['src/test2.dart']));
 
 void testMetadataFields(ModuleMetadata module, String version) {
-  // reader always creates current metadata version
+  // Reader always creates current metadata version.
   expect(module.version, version);
   expect(module.name, 'module');
   expect(module.closureName, 'closure');
@@ -130,8 +128,7 @@
   expect(module.soundNullSafety, true);
 
   var libUri = module.libraries.keys.first;
-  var lib = module.libraries[libUri];
-
+  var lib = module.libraries[libUri]!;
   expect(libUri, 'package:library/test.dart');
   expect(lib.name, 'library');
   expect(lib.importUri, 'package:library/test.dart');
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index 0515336..a46cadc 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -180,7 +180,6 @@
   ClassTable* class_table = isolate->group()->class_table();
 
   Class& klass = Class::Handle(zone);
-  Closure& closure = Closure::Handle(zone);
 
   bool error_found = false;
   Function& erroneous_closure_function = Function::Handle(zone);
@@ -205,8 +204,12 @@
       ObjectPtr raw = working_set.RemoveLast();
 
       const intptr_t cid = raw->GetClassId();
+      // Keep the list in sync with the one in message_snapshot.cc
       switch (cid) {
-        // List below matches the one in raw_object_snapshot.cc
+        case kRegExpCid:
+          // Can be shared, need to be explicitly listed to prevent inspection.
+          continue;
+
 #define MESSAGE_SNAPSHOT_ILLEGAL(type)                                         \
   case k##type##Cid:                                                           \
     error_message =                                                            \
@@ -214,27 +217,15 @@
     error_found = true;                                                        \
     break;
 
-        MESSAGE_SNAPSHOT_ILLEGAL(DynamicLibrary);
-        MESSAGE_SNAPSHOT_ILLEGAL(MirrorReference);
-        MESSAGE_SNAPSHOT_ILLEGAL(Pointer);
-        MESSAGE_SNAPSHOT_ILLEGAL(ReceivePort);
-        MESSAGE_SNAPSHOT_ILLEGAL(RegExp);
-        MESSAGE_SNAPSHOT_ILLEGAL(StackTrace);
-        MESSAGE_SNAPSHOT_ILLEGAL(UserTag);
+          MESSAGE_SNAPSHOT_ILLEGAL(FunctionType);
+          MESSAGE_SNAPSHOT_ILLEGAL(MirrorReference);
+          MESSAGE_SNAPSHOT_ILLEGAL(ReceivePort);
+          MESSAGE_SNAPSHOT_ILLEGAL(StackTrace);
+          MESSAGE_SNAPSHOT_ILLEGAL(UserTag);
 
-        case kClosureCid: {
-          closure = Closure::RawCast(raw);
-          FunctionPtr func = closure.function();
-          // We only allow closure of top level methods or static functions in a
-          // class to be sent in isolate messages.
-          if (!Function::IsImplicitStaticClosureFunction(func)) {
-            // All other closures are errors.
-            erroneous_closure_function = func;
-            error_found = true;
-            break;
-          }
-          break;
-        }
+          MESSAGE_SNAPSHOT_ILLEGAL(DynamicLibrary);
+          MESSAGE_SNAPSHOT_ILLEGAL(Pointer);
+
         default:
           if (cid >= kNumPredefinedCids) {
             klass = class_table->At(cid);
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index 9878a02..703be40 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -3995,7 +3995,6 @@
     case 'NativeEntryData':
       return M.ObjectPoolEntryKind.nativeEntryData;
     case 'NativeFunction':
-    case 'NativeFunctionWrapper':
       return M.ObjectPoolEntryKind.nativeEntry;
   }
   throw new Exception('Unknown ObjectPoolEntryKind ($kind)');
diff --git a/runtime/observatory_2/lib/src/service/object.dart b/runtime/observatory_2/lib/src/service/object.dart
index 5e220dc..a8d3c89 100644
--- a/runtime/observatory_2/lib/src/service/object.dart
+++ b/runtime/observatory_2/lib/src/service/object.dart
@@ -4008,7 +4008,6 @@
     case 'NativeEntryData':
       return M.ObjectPoolEntryKind.nativeEntryData;
     case 'NativeFunction':
-    case 'NativeFunctionWrapper':
       return M.ObjectPoolEntryKind.nativeEntry;
   }
   throw new Exception('Unknown ObjectPoolEntryKind ($kind)');
diff --git a/runtime/tests/vm/dart/sendandexit_test.dart b/runtime/tests/vm/dart/sendandexit_test.dart
index 235a3c2..a67858e 100644
--- a/runtime/tests/vm/dart/sendandexit_test.dart
+++ b/runtime/tests/vm/dart/sendandexit_test.dart
@@ -12,6 +12,9 @@
 
 import "package:expect/expect.dart";
 
+import "isolates/fast_object_copy2_test.dart"
+    show sharableObjects, copyableClosures;
+
 doNothingWorker(data) {}
 
 spawnWorker(worker, data) async {
@@ -23,17 +26,6 @@
   return await completer.future;
 }
 
-verifyCantSendAnonymousClosure() async {
-  final receivePort = ReceivePort();
-  Expect.throws(
-      () => Isolate.exit(receivePort.sendPort, () {}),
-      (e) =>
-          e.toString() ==
-          'Invalid argument: "Illegal argument in isolate message : '
-              '(object is a closure - Function \'<anonymous closure>\': static.)"');
-  receivePort.close();
-}
-
 class NativeWrapperClass extends NativeFieldWrapperClass1 {}
 
 verifyCantSendNative() async {
@@ -50,23 +42,40 @@
   final receivePort = ReceivePort();
   Expect.throws(
       () => Isolate.exit(receivePort.sendPort, receivePort),
-      // closure is encountered first before we reach ReceivePort instance
       (e) => e.toString().startsWith(
           'Invalid argument: "Illegal argument in isolate message : '
-          '(object is a closure - Function \''));
+          '(object is a ReceivePort)\"'));
   receivePort.close();
 }
 
-verifyCantSendRegexp() async {
-  final receivePort = ReceivePort();
-  final regexp = RegExp("");
-  Expect.throws(
-      () => Isolate.exit(receivePort.sendPort, regexp),
-      (e) =>
-          e.toString() ==
-          'Invalid argument: '
-              '"Illegal argument in isolate message : (object is a RegExp)"');
-  receivePort.close();
+sendShareable(SendPort sendPort) {
+  Isolate.exit(sendPort, sharableObjects);
+}
+
+verifyCanSendShareable() async {
+  final port = ReceivePort();
+  final inbox = StreamIterator<dynamic>(port);
+  final isolate = await Isolate.spawn(sendShareable, port.sendPort);
+
+  await inbox.moveNext();
+  final result = inbox.current;
+  Expect.equals(sharableObjects.length, result.length);
+  port.close();
+}
+
+sendCopyable(SendPort sendPort) {
+  Isolate.exit(sendPort, copyableClosures);
+}
+
+verifyCanSendCopyableClosures() async {
+  final port = ReceivePort();
+  final inbox = StreamIterator<dynamic>(port);
+  final isolate = await Isolate.spawn(sendCopyable, port.sendPort);
+
+  await inbox.moveNext();
+  final result = inbox.current;
+  Expect.equals(copyableClosures.length, result.length);
+  port.close();
 }
 
 add(a, b) => a + b;
@@ -75,16 +84,6 @@
   Isolate.exit(sendPort, add);
 }
 
-verifyCanSendStaticMethod() async {
-  final port = ReceivePort();
-  final inbox = StreamIterator<dynamic>(port);
-  final isolate = await Isolate.spawn(worker, port.sendPort);
-
-  await inbox.moveNext();
-  Expect.equals(5, (inbox.current)(2, 3));
-  port.close();
-}
-
 verifyExitMessageIsPostedLast() async {
   final port = ReceivePort();
   final inbox = new StreamIterator<dynamic>(port);
@@ -108,10 +107,9 @@
 }
 
 main() async {
-  await verifyCantSendAnonymousClosure();
   await verifyCantSendNative();
   await verifyCantSendReceivePort();
-  await verifyCantSendRegexp();
-  await verifyCanSendStaticMethod();
+  await verifyCanSendShareable();
+  await verifyCanSendCopyableClosures();
   await verifyExitMessageIsPostedLast();
 }
diff --git a/runtime/tests/vm/dart_2/sendandexit_test.dart b/runtime/tests/vm/dart_2/sendandexit_test.dart
index 3ee64fe..f72712f 100644
--- a/runtime/tests/vm/dart_2/sendandexit_test.dart
+++ b/runtime/tests/vm/dart_2/sendandexit_test.dart
@@ -14,6 +14,9 @@
 
 import "package:expect/expect.dart";
 
+import "isolates/fast_object_copy2_test.dart"
+    show sharableObjects, copyableClosures;
+
 doNothingWorker(data) {}
 
 spawnWorker(worker, data) async {
@@ -25,17 +28,6 @@
   return await completer.future;
 }
 
-verifyCantSendAnonymousClosure() async {
-  final receivePort = ReceivePort();
-  Expect.throws(
-      () => Isolate.exit(receivePort.sendPort, () {}),
-      (e) =>
-          e.toString() ==
-          'Invalid argument: "Illegal argument in isolate message : '
-              '(object is a closure - Function \'<anonymous closure>\': static.)"');
-  receivePort.close();
-}
-
 class NativeWrapperClass extends NativeFieldWrapperClass1 {}
 
 verifyCantSendNative() async {
@@ -52,23 +44,40 @@
   final receivePort = ReceivePort();
   Expect.throws(
       () => Isolate.exit(receivePort.sendPort, receivePort),
-      // closure is encountered first before we reach ReceivePort instance
       (e) => e.toString().startsWith(
           'Invalid argument: "Illegal argument in isolate message : '
-          '(object is a closure - Function \''));
+          '(object is a ReceivePort)\"'));
   receivePort.close();
 }
 
-verifyCantSendRegexp() async {
-  final receivePort = ReceivePort();
-  final regexp = RegExp("");
-  Expect.throws(
-      () => Isolate.exit(receivePort.sendPort, regexp),
-      (e) =>
-          e.toString() ==
-          'Invalid argument: '
-              '"Illegal argument in isolate message : (object is a RegExp)"');
-  receivePort.close();
+sendShareable(SendPort sendPort) {
+  Isolate.exit(sendPort, sharableObjects);
+}
+
+verifyCanSendShareable() async {
+  final port = ReceivePort();
+  final inbox = StreamIterator<dynamic>(port);
+  final isolate = await Isolate.spawn(sendShareable, port.sendPort);
+
+  await inbox.moveNext();
+  final result = inbox.current;
+  Expect.equals(sharableObjects.length, result.length);
+  port.close();
+}
+
+sendCopyable(SendPort sendPort) {
+  Isolate.exit(sendPort, copyableClosures);
+}
+
+verifyCanSendCopyableClosures() async {
+  final port = ReceivePort();
+  final inbox = StreamIterator<dynamic>(port);
+  final isolate = await Isolate.spawn(sendCopyable, port.sendPort);
+
+  await inbox.moveNext();
+  final result = inbox.current;
+  Expect.equals(copyableClosures.length, result.length);
+  port.close();
 }
 
 add(a, b) => a + b;
@@ -77,16 +86,6 @@
   Isolate.exit(sendPort, add);
 }
 
-verifyCanSendStaticMethod() async {
-  final port = ReceivePort();
-  final inbox = StreamIterator<dynamic>(port);
-  final isolate = await Isolate.spawn(worker, port.sendPort);
-
-  await inbox.moveNext();
-  Expect.equals(5, (inbox.current)(2, 3));
-  port.close();
-}
-
 verifyExitMessageIsPostedLast() async {
   final port = ReceivePort();
   final inbox = new StreamIterator<dynamic>(port);
@@ -110,10 +109,9 @@
 }
 
 main() async {
-  await verifyCantSendAnonymousClosure();
   await verifyCantSendNative();
   await verifyCantSendReceivePort();
-  await verifyCantSendRegexp();
-  await verifyCanSendStaticMethod();
+  await verifyCanSendShareable();
+  await verifyCanSendCopyableClosures();
   await verifyExitMessageIsPostedLast();
 }
diff --git a/runtime/vm/app_snapshot.cc b/runtime/vm/app_snapshot.cc
index 85e1bcb..c2c8b3d 100644
--- a/runtime/vm/app_snapshot.cc
+++ b/runtime/vm/app_snapshot.cc
@@ -2340,8 +2340,7 @@
             s->Write<intptr_t>(entry.raw_value_);
             break;
           }
-          case ObjectPool::EntryType::kNativeFunction:
-          case ObjectPool::EntryType::kNativeFunctionWrapper: {
+          case ObjectPool::EntryType::kNativeFunction: {
             // Write nothing. Will initialize with the lazy link entry.
             break;
           }
diff --git a/runtime/vm/compiler/assembler/assembler_base.cc b/runtime/vm/compiler/assembler/assembler_base.cc
index 9dbd0ff..07d7285 100644
--- a/runtime/vm/compiler/assembler/assembler_base.cc
+++ b/runtime/vm/compiler/assembler/assembler_base.cc
@@ -414,14 +414,6 @@
       label->address(), ObjectPoolBuilderEntry::kNativeFunction, patchable));
 }
 
-intptr_t ObjectPoolBuilder::FindNativeFunctionWrapper(
-    const ExternalLabel* label,
-    ObjectPoolBuilderEntry::Patchability patchable) {
-  return FindObject(ObjectPoolBuilderEntry(
-      label->address(), ObjectPoolBuilderEntry::kNativeFunctionWrapper,
-      patchable));
-}
-
 bool ObjectPoolBuilder::TryCommitToParent() {
   ASSERT(parent_ != nullptr);
   if (parent_->CurrentLength() != base_index_) {
diff --git a/runtime/vm/compiler/assembler/object_pool_builder.h b/runtime/vm/compiler/assembler/object_pool_builder.h
index e33ded6..7ceb222 100644
--- a/runtime/vm/compiler/assembler/object_pool_builder.h
+++ b/runtime/vm/compiler/assembler/object_pool_builder.h
@@ -29,7 +29,6 @@
     kTaggedObject,
     kImmediate,
     kNativeFunction,
-    kNativeFunctionWrapper,
 
     // Used only during AOT snapshot serialization/deserialization.
     // Denotes kImmediate entry with
@@ -166,9 +165,6 @@
   intptr_t FindImmediate(uword imm);
   intptr_t FindNativeFunction(const ExternalLabel* label,
                               ObjectPoolBuilderEntry::Patchability patchable);
-  intptr_t FindNativeFunctionWrapper(
-      const ExternalLabel* label,
-      ObjectPoolBuilderEntry::Patchability patchable);
 
   intptr_t CurrentLength() const {
     return object_pool_.length() + used_from_parent_.length();
diff --git a/runtime/vm/message_snapshot.cc b/runtime/vm/message_snapshot.cc
index ac2eef3..97196b1 100644
--- a/runtime/vm/message_snapshot.cc
+++ b/runtime/vm/message_snapshot.cc
@@ -3110,6 +3110,8 @@
         IllegalObject(*object, chars);
       }
     }
+
+    // Keep the list in sync with the one in lib/isolate.cc
 #define ILLEGAL(type)                                                          \
   if (cid == k##type##Cid) {                                                   \
     IllegalObject(*object,                                                     \
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index d793156..1fa6c99 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -14704,8 +14704,7 @@
         break;
       }
       case compiler::ObjectPoolBuilderEntry::kImmediate:
-      case compiler::ObjectPoolBuilderEntry::kNativeFunction:
-      case compiler::ObjectPoolBuilderEntry::kNativeFunctionWrapper: {
+      case compiler::ObjectPoolBuilderEntry::kNativeFunction: {
         compiler::ObjectPoolBuilderEntry entry(RawValueAt(i), type, patchable);
         builder->AddObject(entry);
         break;
@@ -14741,8 +14740,6 @@
       } else {
         THR_Print("0x%" Px " (native function)\n", pc);
       }
-    } else if (TypeAt(i) == EntryType::kNativeFunctionWrapper) {
-      THR_Print("0x%" Px " (native function wrapper)\n", RawValueAt(i));
     } else {
       THR_Print("0x%" Px " (raw)\n", RawValueAt(i));
     }
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index 1685ebf..f7fe7fe 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -722,11 +722,6 @@
           jsentry.AddProperty("kind", "NativeFunction");
           jsentry.AddProperty64("value", imm);
           break;
-        case ObjectPool::EntryType::kNativeFunctionWrapper:
-          imm = RawValueAt(i);
-          jsentry.AddProperty("kind", "NativeFunctionWrapper");
-          jsentry.AddProperty64("value", imm);
-          break;
         default:
           UNREACHABLE();
       }
diff --git a/sdk/lib/async/async.dart b/sdk/lib/async/async.dart
index 00b7fc6..0b16dae 100644
--- a/sdk/lib/async/async.dart
+++ b/sdk/lib/async/async.dart
@@ -73,7 +73,7 @@
 /// Another common use of streams is for user-generated events
 /// in a web app: The following code listens for mouse clicks on a button.
 /// ```dart import:html
-/// querySelector('#myButton').onClick.forEach((_) => print('Click.'));
+/// querySelector('#myButton')!.onClick.forEach((_) => print('Click.'));
 /// ```
 /// ## Other resources
 ///
diff --git a/sdk/lib/async/deferred_load.dart b/sdk/lib/async/deferred_load.dart
index 81d9f80..98dda08 100644
--- a/sdk/lib/async/deferred_load.dart
+++ b/sdk/lib/async/deferred_load.dart
@@ -6,9 +6,8 @@
 
 /// Indicates that loading of [libraryName] is deferred.
 ///
-/// This class is obsolete. Instead use the syntax:
-/// ```dart
-/// import "library.dart" deferred as prefix;
+/// This class is obsolete. Instead prefer the `deferred as` import directive
+/// syntax.
 /// ```
 @Deprecated("Dart sdk v. 1.8")
 class DeferredLibrary {
diff --git a/sdk/lib/core/list.dart b/sdk/lib/core/list.dart
index 8ac4701..1c51340 100644
--- a/sdk/lib/core/list.dart
+++ b/sdk/lib/core/list.dart
@@ -690,7 +690,6 @@
   /// ```dart
   /// var words = ['fee', 'fi', 'fo', 'fum'];
   /// var map = words.asMap();  // {0: fee, 1: fi, 2: fo, 3: fum}
-  /// map[0] + map[1];   // 'feefi';
   /// map.keys.toList(); // [0, 1, 2, 3]
   /// ```
   Map<int, E> asMap();
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 59b3461..5d53fb1 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -12997,7 +12997,7 @@
   }
 
   @pragma('dart2js:tryInline')
-  void setAttribute(String name, String value) {
+  void setAttribute(String name, Object value) {
     // TODO(41258): Delete these assertions after forcing strong mode.
     // Protect [name] against string conversion to "null" or "undefined".
     assert(name != null, 'Attribute name cannot be null');
@@ -13006,7 +13006,7 @@
   }
 
   @pragma('dart2js:tryInline')
-  void setAttributeNS(String? namespaceURI, String name, String value) {
+  void setAttributeNS(String? namespaceURI, String name, Object value) {
     // TODO(41258): Delete these assertions after forcing strong mode.
     // Protect [name] against string conversion to "null" or "undefined".
     assert(name != null, 'Attribute name cannot be null');
@@ -14860,10 +14860,10 @@
   void _scrollTo_3(num? x, y) native;
 
   @JSName('setAttribute')
-  void _setAttribute(String name, String value) native;
+  void _setAttribute(String name, Object value) native;
 
   @JSName('setAttributeNS')
-  void _setAttributeNS(String? namespaceURI, String name, String value) native;
+  void _setAttributeNS(String? namespaceURI, String name, Object value) native;
 
   void setPointerCapture(int pointerId) native;
 
diff --git a/sdk/lib/io/io.dart b/sdk/lib/io/io.dart
index 4cad26d..f504810 100644
--- a/sdk/lib/io/io.dart
+++ b/sdk/lib/io/io.dart
@@ -184,7 +184,7 @@
 /// To read text synchronously from the command line
 /// (the program blocks waiting for user to type information):
 /// ```dart
-/// String inputText = stdin.readLineSync();
+/// String? inputText = stdin.readLineSync();
 /// ```
 /// {@category VM}
 library dart.io;
diff --git a/tools/VERSION b/tools/VERSION
index 8f9bd6b..aa707b0 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 15
 PATCH 0
-PRERELEASE 185
+PRERELEASE 186
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/dom/idl/dart/dart.idl b/tools/dom/idl/dart/dart.idl
index b33dc8d..699473c 100644
--- a/tools/dom/idl/dart/dart.idl
+++ b/tools/dom/idl/dart/dart.idl
@@ -521,10 +521,16 @@
     [DartName=start2] void start(optional double when);
 };
 
-// Remove operation requestFullscreen only use webKitRequestFullscreen.
 [DartSupplemental]
 interface Element : Node {
+    // Remove operation requestFullscreen only use webKitRequestFullscreen.
     [DartSuppress] void requestFullscreen();
+    // setAttribute and setAttributeNS can take in non-string values that are
+    // then converted to strings.
+    [DartSuppress] void setAttribute(DOMString name, DOMString value);
+    [DartSuppress] void setAttributeNS(DOMString? namespaceURI, DOMString name, DOMString value);
+    void setAttribute(DOMString name, object value);
+    void setAttributeNS(DOMString? namespaceURI, DOMString name, object value);
 };
 
 [DartSupplemental]
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index fadfc3b..5f39f92 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -645,7 +645,7 @@
   }
 
   @pragma('dart2js:tryInline')
-  void setAttribute(String name, String value) {
+  void setAttribute(String name, Object value) {
 $if NNBD
     // TODO(41258): Delete these assertions after forcing strong mode.
 $endif
@@ -656,7 +656,7 @@
   }
 
   @pragma('dart2js:tryInline')
-  void setAttributeNS(String$NULLABLE namespaceURI, String name, String value) {
+  void setAttributeNS(String$NULLABLE namespaceURI, String name, Object value) {
 $if NNBD
     // TODO(41258): Delete these assertions after forcing strong mode.
 $endif