Version 2.15.0-169.0.dev

Merge commit '765a6cf282e6b26d842a736127fdac59a1c18bc0' into 'dev'
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 48a5828..fc93703 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -127,8 +127,8 @@
 
     def HasFormatErrors(filename: str = None, contents: str = None):
         # Don't look for formatting errors in multitests. Since those are very
-        # sensitive to whitespace, many cannot be formatted with dartfmt without
-        # breaking them.
+        # sensitive to whitespace, many cannot be reformatted without breaking
+        # them.
         if filename and filename.endswith('_test.dart'):
             with open(filename) as f:
                 contents = f.read()
@@ -179,7 +179,7 @@
             lineSep = " ^\n"
         return [
             output_api.PresubmitError(
-                'File output does not match dartfmt.\n'
+                'File output does not match dart format.\n'
                 'Fix these issues with:\n'
                 '%s format %s%s' %
                 (dart, lineSep, lineSep.join(unformatted_files)))
diff --git a/benchmarks/IsolateJson/dart/IsolateJson.dart b/benchmarks/IsolateJson/dart/IsolateJson.dart
index 5b5a9ee..9717f34 100644
--- a/benchmarks/IsolateJson/dart/IsolateJson.dart
+++ b/benchmarks/IsolateJson/dart/IsolateJson.dart
@@ -10,8 +10,6 @@
 
 import 'package:benchmark_harness/benchmark_harness.dart' show BenchmarkBase;
 
-import 'runtime/tests/vm/dart/export_sendAndExit_helper.dart' show sendAndExit;
-
 class JsonDecodingBenchmark {
   JsonDecodingBenchmark(this.name,
       {required this.sample,
@@ -80,7 +78,7 @@
 Future<void> jsonDecodingIsolate(JsonDecodeRequest request) async {
   final result = json.decode(utf8.decode(request.encodedJson));
   if (request.useSendAndExit) {
-    sendAndExit(request.sendPort, result);
+    Isolate.exit(request.sendPort, result);
   } else {
     request.sendPort.send(result);
   }
diff --git a/benchmarks/IsolateJson/dart/runtime/tests/vm/dart/export_sendAndExit_helper.dart b/benchmarks/IsolateJson/dart/runtime/tests/vm/dart/export_sendAndExit_helper.dart
deleted file mode 100644
index 75628d6..0000000
--- a/benchmarks/IsolateJson/dart/runtime/tests/vm/dart/export_sendAndExit_helper.dart
+++ /dev/null
@@ -1 +0,0 @@
-export 'dart:_internal' show sendAndExit;
diff --git a/benchmarks/IsolateJson/dart2/IsolateJson.dart b/benchmarks/IsolateJson/dart2/IsolateJson.dart
index 46ac6ca..a78b95d 100644
--- a/benchmarks/IsolateJson/dart2/IsolateJson.dart
+++ b/benchmarks/IsolateJson/dart2/IsolateJson.dart
@@ -13,8 +13,6 @@
 import 'package:benchmark_harness/benchmark_harness.dart' show BenchmarkBase;
 import 'package:meta/meta.dart';
 
-import 'runtime/tests/vm/dart/export_sendAndExit_helper.dart' show sendAndExit;
-
 class JsonDecodingBenchmark {
   JsonDecodingBenchmark(this.name,
       {@required this.sample,
@@ -83,7 +81,7 @@
 Future<void> jsonDecodingIsolate(JsonDecodeRequest request) async {
   final result = json.decode(utf8.decode(request.encodedJson));
   if (request.useSendAndExit) {
-    sendAndExit(request.sendPort, result);
+    Isolate.exit(request.sendPort, result);
   } else {
     request.sendPort.send(result);
   }
diff --git a/benchmarks/IsolateJson/dart2/runtime/tests/vm/dart/export_sendAndExit_helper.dart b/benchmarks/IsolateJson/dart2/runtime/tests/vm/dart/export_sendAndExit_helper.dart
deleted file mode 100644
index 75628d6..0000000
--- a/benchmarks/IsolateJson/dart2/runtime/tests/vm/dart/export_sendAndExit_helper.dart
+++ /dev/null
@@ -1 +0,0 @@
-export 'dart:_internal' show sendAndExit;
diff --git a/pkg/analysis_server/lib/src/g3/fixes.dart b/pkg/analysis_server/lib/src/g3/fixes.dart
new file mode 100644
index 0000000..51c05f4
--- /dev/null
+++ b/pkg/analysis_server/lib/src/g3/fixes.dart
@@ -0,0 +1,207 @@
+// 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/plugin/edit/fix/fix_core.dart';
+import 'package:analysis_server/src/protocol_server.dart' show SourceEdit;
+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_internal.dart';
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/error/error.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/overlay_file_system.dart';
+import 'package:analyzer/instrumentation/service.dart';
+import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
+import 'package:analyzer/src/dart/error/lint_codes.dart';
+import 'package:collection/collection.dart';
+
+/// The root of a set of classes that support testing for lint fixes.
+///
+/// These classes work as a sequence:
+/// 1. Create this tested with necessary SDK and package config.
+/// 2. Configure any overlays on top of the file system with [updateFile].
+/// 3. Request fixes for a file using [fixesForSingleLint].
+/// 4. Use the [LintFixTesterWithFixes] to check how many fixes there are.
+/// 5. If there is a single fix, use [LintFixTesterWithSingleFix] to verify
+///    the fixed content for specific files.
+class LintFixTester {
+  final OverlayResourceProvider _resourceProvider;
+  final String sdkPath;
+  final String? packageConfigPath;
+
+  /// If `false`, then we have already computed lints for this tester,
+  /// and updating the file system (as much as we can observe it) should
+  /// not be allowed.
+  bool _canUpdateResourceProvider = true;
+
+  LintFixTester({
+    required ResourceProvider resourceProvider,
+    required this.sdkPath,
+    required this.packageConfigPath,
+  }) : _resourceProvider = OverlayResourceProvider(resourceProvider);
+
+  /// Prepare fixes for a single lint in the file with the [path]
+  ///
+  /// If [inFile] is `false`, there must be exactly one diagnostic in the file,
+  /// and it is a lint.
+  ///
+  /// If [inFile] is `true`, there must be one or more diagnostics, but all
+  /// of them must have the same error code, and it must be a lint.
+  ///
+  /// Throws [StateError] if an expectation is not satisfied.
+  Future<LintFixTesterWithFixes> fixesForSingleLint({
+    required String path,
+    required bool inFile,
+  }) async {
+    _canUpdateResourceProvider = true;
+
+    var collection = AnalysisContextCollectionImpl(
+      includedPaths: [path],
+      resourceProvider: _resourceProvider,
+      sdkPath: sdkPath,
+      packagesFile: packageConfigPath,
+    );
+    var analysisContext = collection.contextFor(path);
+    var analysisSession = analysisContext.currentSession;
+
+    var unitResult = await analysisSession.getResolvedUnit(path);
+    unitResult as ResolvedUnitResult;
+
+    AnalysisError error;
+    var errors = unitResult.errors;
+    if (inFile) {
+      var groups = errors.groupListsBy((error) => error.errorCode);
+      if (groups.length != 1) {
+        throw StateError(
+          'Exactly one error code expected:'
+          '\n$errors\n${groups.keys.toList()}',
+        );
+      }
+      error = errors.first;
+    } else {
+      if (errors.length != 1) {
+        throw StateError('Exactly one lint expected: $errors');
+      }
+      error = errors.single;
+    }
+
+    if (error.errorCode is! LintCode) {
+      throw StateError('A lint expected: $errors');
+    }
+
+    var workspace = DartChangeWorkspace([analysisSession]);
+    var context = DartFixContextImpl(
+      InstrumentationService.NULL_SERVICE,
+      workspace,
+      unitResult,
+      error,
+      (name) => const [],
+    );
+
+    List<Fix> fixes;
+    if (inFile) {
+      var fixInFileProcessor = FixInFileProcessor(context);
+      fixes = await fixInFileProcessor.compute();
+    } else {
+      fixes = await FixProcessor(context).compute();
+      fixes.removeWhere(
+        (fix) =>
+            fix.kind == DartFixKind.IGNORE_ERROR_LINE ||
+            fix.kind == DartFixKind.IGNORE_ERROR_FILE,
+      );
+    }
+
+    return LintFixTesterWithFixes(parent: this, fixes: fixes);
+  }
+
+  /// Update the view on the file system so that the final with the [path]
+  /// is considered to have the given [content]. The actual file system is
+  /// not changed.
+  ///
+  /// This method should not be used after any analysis is performed, such
+  /// as invocation of [fixesForSingleLint], will throw [StateError].
+  void updateFile({
+    required String path,
+    required String content,
+  }) {
+    if (!_canUpdateResourceProvider) {
+      throw StateError('Diagnostics were already computed.');
+    }
+
+    _resourceProvider.setOverlay(
+      path,
+      content: content,
+      modificationStamp: 0,
+    );
+  }
+}
+
+class LintFixTesterWithFixes {
+  final LintFixTester _parent;
+  final List<Fix> fixes;
+
+  LintFixTesterWithFixes({
+    required LintFixTester parent,
+    required this.fixes,
+  }) : _parent = parent;
+
+  void assertNoFixes() {
+    if (fixes.isNotEmpty) {
+      throw StateError('Must have exactly zero fixes: $fixes');
+    }
+  }
+
+  LintFixTesterWithSingleFix assertSingleFix() {
+    if (fixes.length != 1) {
+      throw StateError('Must have exactly one fix: $fixes');
+    }
+
+    return LintFixTesterWithSingleFix(
+      parent: this,
+      fix: fixes.single,
+    );
+  }
+}
+
+class LintFixTesterWithSingleFix {
+  final LintFixTesterWithFixes _parent;
+  final Fix fix;
+
+  LintFixTesterWithSingleFix({
+    required LintFixTesterWithFixes parent,
+    required this.fix,
+  }) : _parent = parent;
+
+  void assertFixedContentOfFile({
+    required String path,
+    required String fixedContent,
+  }) {
+    var fileEdits = fix.change.edits;
+    var fileEdit = fileEdits.singleWhere(
+      (fileEdit) => fileEdit.file == path,
+    );
+
+    var resourceProvider = _parent._parent._resourceProvider;
+    var file = resourceProvider.getFile(path);
+    var fileContent = file.readAsStringSync();
+
+    var actualFixedContent = SourceEdit.applySequence(
+      fileContent,
+      fileEdit.edits,
+    );
+    if (actualFixedContent != fixedContent) {
+      throw StateError('Not expected content:\n$actualFixedContent');
+    }
+  }
+
+  void assertNoFileEdit({required String path}) {
+    var fileEdits = fix.change.edits;
+    var filtered = fileEdits.where(
+      (fileEdit) => fileEdit.file == path,
+    );
+    if (filtered.isNotEmpty) {
+      throw StateError('Expected no edit for $path: $fix');
+    }
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/make_field_public.dart b/pkg/analysis_server/lib/src/services/correction/dart/make_field_public.dart
new file mode 100644
index 0000000..16025e4
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/dart/make_field_public.dart
@@ -0,0 +1,82 @@
+// 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/change_builder/change_builder_dart.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:analyzer_plugin/utilities/range_factory.dart';
+
+class MakeFieldPublic extends CorrectionProducer {
+  late String _fieldName;
+
+  @override
+  List<Object>? get fixArguments => [_fieldName];
+
+  @override
+  FixKind get fixKind => DartFixKind.MAKE_FIELD_PUBLIC;
+
+  @override
+  Future<void> compute(ChangeBuilder builder) async {
+    var node = this.node;
+    if (node is! SimpleIdentifier) {
+      return;
+    }
+    var getterName = node.name;
+    _fieldName = '_$getterName';
+    var parent = node.parent;
+    if (parent is MethodDeclaration && parent.name == node && parent.isGetter) {
+      var container = parent.parent;
+      if (container is ClassOrMixinDeclaration) {
+        var members = container.members;
+        MethodDeclaration? setter;
+        VariableDeclaration? field;
+        for (var member in members) {
+          if (member is MethodDeclaration &&
+              member.name.name == getterName &&
+              member.isSetter) {
+            setter = member;
+          } else if (member is FieldDeclaration) {
+            for (var variable in member.fields.variables) {
+              if (variable.name.name == _fieldName) {
+                field = variable;
+              }
+            }
+          }
+        }
+        if (setter == null || field == null) {
+          return;
+        }
+        await builder.addDartFileEdit(file, (builder) {
+          builder.addSimpleReplacement(range.node(field!.name), getterName);
+          builder.removeMember(members, parent);
+          builder.removeMember(members, setter!);
+        });
+      }
+    }
+  }
+
+  /// Return an instance of this class. Used as a tear-off in `FixProcessor`.
+  static MakeFieldPublic newInstance() => MakeFieldPublic();
+}
+
+extension on DartFileEditBuilder {
+  void removeMember(NodeList<ClassMember> members, ClassMember member) {
+    // TODO(brianwilkerson) Consider moving this to DartFileEditBuilder.
+    var index = members.indexOf(member);
+    if (index == 0) {
+      if (members.length == 1) {
+        // TODO(brianwilkerson) Remove the whitespace before and after the
+        //  member.
+        addDeletion(range.node(member));
+      } else {
+        addDeletion(range.startStart(member, members[index + 1]));
+      }
+    } else {
+      addDeletion(range.endEnd(members[index - 1], member));
+    }
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index c9a98b8..8bdf4f5 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -671,6 +671,11 @@
     DartFixKindPriority.DEFAULT,
     "Make field '{0}' not final",
   );
+  static const MAKE_FIELD_PUBLIC = FixKind(
+    'dart.fix.makeFieldPublic',
+    DartFixKindPriority.DEFAULT,
+    "Make field '{0}' public",
+  );
   static const MAKE_FINAL = FixKind(
     'dart.fix.makeFinal',
     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 ab54076..e1a0b22 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -86,6 +86,7 @@
 import 'package:analysis_server/src/services/correction/dart/make_class_abstract.dart';
 import 'package:analysis_server/src/services/correction/dart/make_conditional_on_debug_mode.dart';
 import 'package:analysis_server/src/services/correction/dart/make_field_not_final.dart';
+import 'package:analysis_server/src/services/correction/dart/make_field_public.dart';
 import 'package:analysis_server/src/services/correction/dart/make_final.dart';
 import 'package:analysis_server/src/services/correction/dart/make_return_type_nullable.dart';
 import 'package:analysis_server/src/services/correction/dart/make_variable_not_final.dart';
@@ -571,6 +572,9 @@
     LintNames.unnecessary_final: [
       ReplaceFinalWithVar.newInstance,
     ],
+    LintNames.unnecessary_getters_setters: [
+      MakeFieldPublic.newInstance,
+    ],
     LintNames.unnecessary_lambdas: [
       ReplaceWithTearOff.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 cfdea77..c614c89 100644
--- a/pkg/analysis_server/lib/src/services/linter/lint_names.dart
+++ b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
@@ -115,6 +115,8 @@
   static const String unnecessary_constructor_name =
       'unnecessary_constructor_name';
   static const String unnecessary_final = 'unnecessary_final';
+  static const String unnecessary_getters_setters =
+      'unnecessary_getters_setters';
   static const String unnecessary_lambdas = 'unnecessary_lambdas';
   static const String unnecessary_new = 'unnecessary_new';
   static const String unnecessary_null_in_if_null_operators =
diff --git a/pkg/analysis_server/test/src/g3/fixes_test.dart b/pkg/analysis_server/test/src/g3/fixes_test.dart
new file mode 100644
index 0000000..430ac37b
--- /dev/null
+++ b/pkg/analysis_server/test/src/g3/fixes_test.dart
@@ -0,0 +1,201 @@
+// 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/g3/fixes.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer/src/test_utilities/mock_sdk.dart';
+import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
+import 'package:linter/src/rules.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(G3FixesTest);
+  });
+}
+
+@reflectiveTest
+class G3FixesTest with ResourceProviderMixin {
+  void setUp() {
+    registerLintRules();
+    MockSdk(resourceProvider: resourceProvider);
+  }
+
+  Future<void> test_awaitOnlyFutures() async {
+    await _assertHasLintFix(
+      codeWithLint: r'''
+void f() async {
+  await 0;
+}
+''',
+      lintName: LintNames.await_only_futures,
+      fixedCode: r'''
+void f() async {
+  0;
+}
+''',
+    );
+  }
+
+  Future<void> test_awaitOnlyFutures_inFile() async {
+    await _assertHasLintFix(
+      inFile: true,
+      codeWithLint: r'''
+void f() async {
+  await 0;
+  await 1;
+}
+''',
+      lintName: LintNames.await_only_futures,
+      fixedCode: r'''
+void f() async {
+  0;
+  1;
+}
+''',
+    );
+  }
+
+  Future<void> test_emptyCatches_noFinally() async {
+    await _assertNoLintFix(
+      codeWithLint: r'''
+void f() {
+  try {
+  } catch (e) {}
+}
+''',
+      lintName: LintNames.empty_catches,
+    );
+  }
+
+  Future<void> test_emptyConstructorBodies() async {
+    await _assertHasLintFix(
+      codeWithLint: r'''
+class C {
+  C() {}
+}
+''',
+      lintName: LintNames.empty_constructor_bodies,
+      fixedCode: r'''
+class C {
+  C();
+}
+''',
+    );
+  }
+
+  Future<void> test_invalid_moreThanOneDiagnostic() async {
+    expect(() async {
+      await _assertHasLintFix(
+        codeWithLint: '0 1',
+        lintName: LintNames.avoid_empty_else,
+        fixedCode: '',
+      );
+    }, throwsStateError);
+  }
+
+  Future<void> test_invalid_noDiagnostics() async {
+    expect(() async {
+      await _assertHasLintFix(
+        codeWithLint: '',
+        lintName: LintNames.avoid_empty_else,
+        fixedCode: '',
+      );
+    }, throwsStateError);
+  }
+
+  Future<void> test_invalid_notLint() async {
+    expect(() async {
+      await _assertHasLintFix(
+        codeWithLint: '42',
+        lintName: LintNames.avoid_empty_else,
+        fixedCode: '',
+      );
+    }, throwsStateError);
+  }
+
+  Future<void> _assertHasLintFix({
+    required String codeWithLint,
+    required String lintName,
+    required String fixedCode,
+    bool inFile = false,
+  }) async {
+    _enableLint(lintName);
+
+    var tester = LintFixTester(
+      resourceProvider: resourceProvider,
+      sdkPath: sdkRoot,
+      packageConfigPath: null,
+    );
+
+    var path = convertPath('/home/test/lib/test.dart');
+    tester.updateFile(
+      path: path,
+      content: codeWithLint,
+    );
+
+    var testerWithFixes = await tester.fixesForSingleLint(
+      path: path,
+      inFile: inFile,
+    );
+
+    var singleFix = testerWithFixes.assertSingleFix();
+    singleFix.assertFixedContentOfFile(
+      path: path,
+      fixedContent: fixedCode,
+    );
+  }
+
+  Future<void> _assertNoLintFix({
+    required String codeWithLint,
+    required String lintName,
+    bool inFile = false,
+  }) async {
+    _enableLint(lintName);
+
+    var tester = LintFixTester(
+      resourceProvider: resourceProvider,
+      sdkPath: sdkRoot,
+      packageConfigPath: null,
+    );
+
+    var path = convertPath('/home/test/lib/test.dart');
+    tester.updateFile(
+      path: path,
+      content: codeWithLint,
+    );
+
+    var testerWithFixes = await tester.fixesForSingleLint(
+      path: path,
+      inFile: inFile,
+    );
+
+    testerWithFixes.assertNoFixes();
+  }
+
+  void _enableLint(String lintName) {
+    _writeAnalysisOptionsFile(
+      lints: [lintName],
+    );
+  }
+
+  /// Write an analysis options file based on the given arguments.
+  /// TODO(scheglov) Use AnalysisOptionsFileConfig
+  void _writeAnalysisOptionsFile({
+    List<String>? lints,
+  }) {
+    var buffer = StringBuffer();
+
+    if (lints != null) {
+      buffer.writeln('linter:');
+      buffer.writeln('  rules:');
+      for (var lint in lints) {
+        buffer.writeln('    - $lint');
+      }
+    }
+
+    newFile('/home/test/analysis_options.yaml', content: buffer.toString());
+  }
+}
diff --git a/pkg/analysis_server/test/src/g3/test_all.dart b/pkg/analysis_server/test/src/g3/test_all.dart
new file mode 100644
index 0000000..2050c81
--- /dev/null
+++ b/pkg/analysis_server/test/src/g3/test_all.dart
@@ -0,0 +1,13 @@
+// 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:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fixes_test.dart' as fixes;
+
+void main() {
+  defineReflectiveSuite(() {
+    fixes.main();
+  });
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/make_field_public_test.dart b/pkg/analysis_server/test/src/services/correction/fix/make_field_public_test.dart
new file mode 100644
index 0000000..3b95f2c
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/make_field_public_test.dart
@@ -0,0 +1,42 @@
+// 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_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(MakeFieldPublicTest);
+  });
+}
+
+@reflectiveTest
+class MakeFieldPublicTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.MAKE_FIELD_PUBLIC;
+
+  @override
+  String get lintCode => LintNames.unnecessary_getters_setters;
+
+  Future<void> test_class() async {
+    await resolveTestCode('''
+class C {
+  int _f = 0;
+
+  int get f => _f;
+
+  void set f(int p) => _f = p;
+}
+''');
+    await assertHasFix('''
+class C {
+  int f = 0;
+}
+''');
+  }
+}
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 0fbbd97..0fea0a6 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
@@ -106,6 +106,7 @@
 import 'make_conditional_on_debug_mode_test.dart'
     as make_conditional_on_debug_mode;
 import 'make_field_not_final_test.dart' as make_field_not_final;
+import 'make_field_public_test.dart' as make_field_public;
 import 'make_final_test.dart' as make_final;
 import 'make_return_type_nullable_test.dart' as make_return_type_nullable;
 import 'make_variable_not_final_test.dart' as make_variable_not_final;
@@ -294,6 +295,7 @@
     make_class_abstract.main();
     make_conditional_on_debug_mode.main();
     make_field_not_final.main();
+    make_field_public.main();
     make_final.main();
     make_return_type_nullable.main();
     make_variable_not_final.main();
diff --git a/pkg/analysis_server/test/src/test_all.dart b/pkg/analysis_server/test/src/test_all.dart
index 0cb76aa..85dd930 100644
--- a/pkg/analysis_server/test/src/test_all.dart
+++ b/pkg/analysis_server/test/src/test_all.dart
@@ -9,6 +9,7 @@
 import 'domain_abstract_test.dart' as domain_abstract;
 import 'domains/test_all.dart' as domains;
 import 'flutter/test_all.dart' as flutter;
+import 'g3/test_all.dart' as g3;
 import 'lsp/test_all.dart' as lsp;
 import 'plugin/test_all.dart' as plugin;
 import 'server/test_all.dart' as server;
@@ -22,6 +23,7 @@
     domain_abstract.main();
     domains.main();
     flutter.main();
+    g3.main();
     lsp.main();
     plugin.main();
     server.main();
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 4978d9e..919a698 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -1523,11 +1523,13 @@
     CollectionElement thenElement = node.thenElement;
     flowAnalysis.flow?.ifStatement_thenBegin(condition, node);
     thenElement.accept(this);
+    nullSafetyDeadCodeVerifier.flowEnd(thenElement);
 
     var elseElement = node.elseElement;
     if (elseElement != null) {
       flowAnalysis.flow?.ifStatement_elseBegin();
       elseElement.accept(this);
+      nullSafetyDeadCodeVerifier.flowEnd(elseElement);
     }
 
     flowAnalysis.flow?.ifStatement_end(elseElement != null);
diff --git a/pkg/analyzer/test/src/dart/resolution/type_inference/map_literal_test.dart b/pkg/analyzer/test/src/dart/resolution/type_inference/map_literal_test.dart
index 894f8a9..2d38f07 100644
--- a/pkg/analyzer/test/src/dart/resolution/type_inference/map_literal_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/type_inference/map_literal_test.dart
@@ -82,7 +82,7 @@
   var v = {...?a, if (b) throw 0: throw 0};
 }
 ''', [
-      error(HintCode.DEAD_CODE, 99, 9),
+      error(HintCode.DEAD_CODE, 99, 7),
     ]);
     assertType(setOrMapLiteral('{...'), 'Map<Never, Never>');
   }
@@ -107,7 +107,7 @@
   var v = {...?a, if (b) throw 0: throw 0};
 }
 ''', [
-      error(HintCode.DEAD_CODE, 112, 9),
+      error(HintCode.DEAD_CODE, 112, 7),
     ]);
     assertType(setOrMapLiteral('{...'), 'Map<Never, Never>');
   }
diff --git a/pkg/analyzer/test/src/diagnostics/dead_code_test.dart b/pkg/analyzer/test/src/diagnostics/dead_code_test.dart
index 92f1995..e2ba5bb 100644
--- a/pkg/analyzer/test/src/diagnostics/dead_code_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/dead_code_test.dart
@@ -338,6 +338,29 @@
     ]);
   }
 
+  test_deadBlock_ifElement() async {
+    await assertErrorsInCode(r'''
+f() {
+  [
+    if (false) 2,
+  ];
+}''', [
+      error(HintCode.DEAD_CODE, 25, 1),
+    ]);
+  }
+
+  test_deadBlock_ifElement_else() async {
+    await assertErrorsInCode(r'''
+f() {
+  [
+    if (true) 2
+    else 3,
+  ];
+}''', [
+      error(HintCode.DEAD_CODE, 35, 1),
+    ]);
+  }
+
   test_deadBlock_while() async {
     await assertErrorsInCode(r'''
 f() {
diff --git a/pkg/analyzer/test/src/diagnostics/non_constant_map_element_test.dart b/pkg/analyzer/test/src/diagnostics/non_constant_map_element_test.dart
index 35beee6..88f45a7 100644
--- a/pkg/analyzer/test/src/diagnostics/non_constant_map_element_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/non_constant_map_element_test.dart
@@ -85,7 +85,7 @@
   const {1: null, if (isTrue) null: null else null: null};
 }
 ''', [
-      error(HintCode.DEAD_CODE, 83, 12),
+      error(HintCode.DEAD_CODE, 83, 10),
     ]);
   }
 
diff --git a/pkg/compiler/lib/src/kernel/transformations/late_lowering.dart b/pkg/compiler/lib/src/kernel/transformations/late_lowering.dart
index c88b7b7..18b56dc 100644
--- a/pkg/compiler/lib/src/kernel/transformations/late_lowering.dart
+++ b/pkg/compiler/lib/src/kernel/transformations/late_lowering.dart
@@ -42,10 +42,6 @@
   // pair).
   final Map<Field, Field> _backingInstanceFields = {};
 
-  // TODO(fishythefish): Remove this when [FieldInitializer] maintains a correct
-  // [Reference] to its [Field].
-  final Map<Procedure, Field> _getterToField = {};
-
   Member? _contextMember;
 
   LateLowering(this._coreTypes, CompilerOptions? _options)
@@ -151,7 +147,6 @@
     assert(_variableCells.isEmpty);
     _fieldCells.clear();
     _backingInstanceFields.clear();
-    _getterToField.clear();
   }
 
   void enterFunction() {
@@ -364,17 +359,19 @@
     Uri fileUri = field.fileUri;
     Name name = field.name;
     String nameText = name.text;
+    Name mangledName = _mangleFieldName(field);
     DartType type = field.type;
     Expression? initializer = field.initializer;
     Class enclosingClass = field.enclosingClass!;
 
-    Name mangledName = _mangleFieldName(field);
+    field.fieldReference.canonicalName?.unbind();
     Field backingField = Field.mutable(mangledName,
         type: type,
         initializer: StaticInvocation(_coreTypes.createSentinelMethod,
             Arguments(const [], types: [type])..fileOffset = fileOffset)
           ..fileOffset = fileOffset,
-        fileUri: fileUri)
+        fileUri: fileUri,
+        fieldReference: field.fieldReference)
       ..fileOffset = fileOffset
       ..isNonNullableByDefault = true
       ..isInternalImplementation = true;
@@ -485,7 +482,6 @@
       ..fileOffset = fileOffset
       ..isNonNullableByDefault = true;
     enclosingClass.addProcedure(getter);
-    _getterToField[getter] = backingField;
 
     VariableDeclaration setterValue = VariableDeclaration('value', type: type)
       ..fileOffset = fileOffset;
@@ -552,25 +548,4 @@
 
     return field;
   }
-
-  TreeNode transformFieldInitializer(
-      FieldInitializer initializer, Member contextMember) {
-    _contextMember = contextMember;
-
-    // If the [Field] has been lowered, we can't use `node.field` to retrieve it
-    // because the `getterReference` of the original field now points to the new
-    // getter for the backing field.
-    // TODO(fishythefish): Clean this up when [FieldInitializer] maintains a
-    // correct [Reference] to its [Field].
-    NamedNode node = initializer.fieldReference.node!;
-    Field backingField;
-    if (node is Field) {
-      if (!_shouldLowerInstanceField(node)) return initializer;
-      backingField = _backingInstanceField(node);
-    } else {
-      backingField = _getterToField[node]!;
-    }
-    return FieldInitializer(backingField, initializer.value)
-      ..fileOffset = initializer.fileOffset;
-  }
 }
diff --git a/pkg/compiler/lib/src/kernel/transformations/lowering.dart b/pkg/compiler/lib/src/kernel/transformations/lowering.dart
index 2d3b374..234eac1 100644
--- a/pkg/compiler/lib/src/kernel/transformations/lowering.dart
+++ b/pkg/compiler/lib/src/kernel/transformations/lowering.dart
@@ -85,10 +85,4 @@
     node.transformChildren(this);
     return _lateLowering.transformField(node, _currentMember!);
   }
-
-  @override
-  TreeNode visitFieldInitializer(FieldInitializer node) {
-    node.transformChildren(this);
-    return _lateLowering.transformFieldInitializer(node, _currentMember!);
-  }
 }
diff --git a/pkg/dart2js_info/tool/update_proto.sh b/pkg/dart2js_info/tool/update_proto.sh
index c784edd..559f87d 100755
--- a/pkg/dart2js_info/tool/update_proto.sh
+++ b/pkg/dart2js_info/tool/update_proto.sh
@@ -10,4 +10,4 @@
 fi
 
 protoc --proto_path="." --dart_out=lib/src/proto info.proto
-dartfmt -w lib/src/proto
+dart format lib/src/proto
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index f8c0bb5..0515336 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -272,36 +272,37 @@
   return obj.ptr();
 }
 
-DEFINE_NATIVE_ENTRY(SendPortImpl_sendAndExitInternal_, 0, 2) {
-  GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
-  if (!PortMap::IsReceiverInThisIsolateGroup(port.Id(), isolate->group())) {
-    const auto& error =
-        String::Handle(String::New("sendAndExit is only supported across "
-                                   "isolates spawned via spawnFunction."));
-    Exceptions::ThrowArgumentError(error);
-    UNREACHABLE();
-  }
+DEFINE_NATIVE_ENTRY(Isolate_exit_, 0, 2) {
+  GET_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
+  if (!port.IsNull()) {
+    GET_NATIVE_ARGUMENT(Instance, obj, arguments->NativeArgAt(1));
+    if (!PortMap::IsReceiverInThisIsolateGroup(port.Id(), isolate->group())) {
+      const auto& error =
+          String::Handle(String::New("exit with final message is only allowed "
+                                     "for isolates in one isolate group."));
+      Exceptions::ThrowArgumentError(error);
+      UNREACHABLE();
+    }
 
-  GET_NON_NULL_NATIVE_ARGUMENT(Instance, obj, arguments->NativeArgAt(1));
-
-  Object& validated_result = Object::Handle(zone);
-  const Object& msg_obj = Object::Handle(zone, obj.ptr());
-  validated_result = ValidateMessageObject(zone, isolate, msg_obj);
-  // msg_array = [
-  //     <message>,
-  //     <collection-lib-objects-to-rehash>,
-  //     <core-lib-objects-to-rehash>,
-  // ]
-  const Array& msg_array = Array::Handle(zone, Array::New(3));
-  msg_array.SetAt(0, msg_obj);
-  if (validated_result.IsUnhandledException()) {
-    Exceptions::PropagateError(Error::Cast(validated_result));
-    UNREACHABLE();
+    Object& validated_result = Object::Handle(zone);
+    const Object& msg_obj = Object::Handle(zone, obj.ptr());
+    validated_result = ValidateMessageObject(zone, isolate, msg_obj);
+    // msg_array = [
+    //     <message>,
+    //     <collection-lib-objects-to-rehash>,
+    //     <core-lib-objects-to-rehash>,
+    // ]
+    const Array& msg_array = Array::Handle(zone, Array::New(3));
+    msg_array.SetAt(0, msg_obj);
+    if (validated_result.IsUnhandledException()) {
+      Exceptions::PropagateError(Error::Cast(validated_result));
+      UNREACHABLE();
+    }
+    PersistentHandle* handle =
+        isolate->group()->api_state()->AllocatePersistentHandle();
+    handle->set_ptr(msg_array);
+    isolate->bequeath(std::unique_ptr<Bequest>(new Bequest(handle, port.Id())));
   }
-  PersistentHandle* handle =
-      isolate->group()->api_state()->AllocatePersistentHandle();
-  handle->set_ptr(msg_array);
-  isolate->bequeath(std::unique_ptr<Bequest>(new Bequest(handle, port.Id())));
   Isolate::KillIfExists(isolate, Isolate::LibMsgId::kKillMsg);
   // Drain interrupts before running so any IMMEDIATE operations on the current
   // isolate happen synchronously.
diff --git a/runtime/observatory/tests/service/object_graph_vm_test.dart b/runtime/observatory/tests/service/object_graph_vm_test.dart
index 8a8e7ec..5ab5fe9 100644
--- a/runtime/observatory/tests/service/object_graph_vm_test.dart
+++ b/runtime/observatory/tests/service/object_graph_vm_test.dart
@@ -90,7 +90,9 @@
       int internalSum = 0;
       int externalSum = 0;
       for (SnapshotObject instance in klass.instances) {
-        if (instance == graph.root || instance.klass.name.contains("Isolate")) {
+        if (instance == graph.root ||
+            instance.klass.name.contains("Isolate") ||
+            instance.klass.name.contains("Read-Only Pages")) {
           // The root and fake root subdivisions have 0 self size.
           expect(instance.internalSize, greaterThanOrEqualTo(0));
           expect(instance.externalSize, greaterThanOrEqualTo(0));
@@ -122,7 +124,9 @@
     int internalSum = 0;
     int externalSum = 0;
     for (SnapshotObject instance in graph.objects) {
-      if (instance == graph.root || instance.klass.name.contains("Isolate")) {
+      if (instance == graph.root ||
+          instance.klass.name.contains("Isolate") ||
+          instance.klass.name.contains("Read-Only Pages")) {
         // The root and fake root subdivisions have 0 self size.
         expect(instance.internalSize, greaterThanOrEqualTo(0));
         expect(instance.externalSize, greaterThanOrEqualTo(0));
diff --git a/runtime/observatory_2/tests/service_2/object_graph_vm_test.dart b/runtime/observatory_2/tests/service_2/object_graph_vm_test.dart
index 81be62e..6e35ba2 100644
--- a/runtime/observatory_2/tests/service_2/object_graph_vm_test.dart
+++ b/runtime/observatory_2/tests/service_2/object_graph_vm_test.dart
@@ -90,7 +90,9 @@
       int internalSum = 0;
       int externalSum = 0;
       for (SnapshotObject instance in klass.instances) {
-        if (instance == graph.root || instance.klass.name.contains("Isolate")) {
+        if (instance == graph.root ||
+            instance.klass.name.contains("Isolate") ||
+            instance.klass.name.contains("Read-Only Pages")) {
           // The root and fake root subdivisions have 0 self size.
           expect(instance.internalSize, greaterThanOrEqualTo(0));
           expect(instance.externalSize, greaterThanOrEqualTo(0));
@@ -122,7 +124,9 @@
     int internalSum = 0;
     int externalSum = 0;
     for (SnapshotObject instance in graph.objects) {
-      if (instance == graph.root || instance.klass.name.contains("Isolate")) {
+      if (instance == graph.root ||
+          instance.klass.name.contains("Isolate") ||
+          instance.klass.name.contains("Read-Only Pages")) {
         // The root and fake root subdivisions have 0 self size.
         expect(instance.internalSize, greaterThanOrEqualTo(0));
         expect(instance.externalSize, greaterThanOrEqualTo(0));
diff --git a/runtime/tests/vm/dart/isolates/internal.dart b/runtime/tests/vm/dart/isolates/internal.dart
deleted file mode 100644
index ec854b0..0000000
--- a/runtime/tests/vm/dart/isolates/internal.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:io';
-import 'dart:isolate';
-import 'dart:async';
-import 'dart:_internal' as dart_internal;
-
-extension SendPortSendAndExit on SendPort {
-  void sendAndExit(var message) {
-    dart_internal.sendAndExit(this, message);
-  }
-}
diff --git a/runtime/tests/vm/dart/isolates/ring_gc_sendAndExit_test.dart b/runtime/tests/vm/dart/isolates/ring_gc_sendAndExit_test.dart
index 74b6820..a50d9e8 100644
--- a/runtime/tests/vm/dart/isolates/ring_gc_sendAndExit_test.dart
+++ b/runtime/tests/vm/dart/isolates/ring_gc_sendAndExit_test.dart
@@ -24,7 +24,7 @@
   final ring = await Ring.create(numIsolates);
 
   // Let each node produce a tree, send it to it's neighbour and let it return
-  // the one it received (via sendAndExit).
+  // the one it received (via Isolate.exit).
   final results = await ring.runAndClose((int id) => Worker(id));
   Expect.equals(numIsolates, results.length);
 
diff --git a/runtime/tests/vm/dart/isolates/test_utils.dart b/runtime/tests/vm/dart/isolates/test_utils.dart
index 7c5da81..3268cc1 100644
--- a/runtime/tests/vm/dart/isolates/test_utils.dart
+++ b/runtime/tests/vm/dart/isolates/test_utils.dart
@@ -6,8 +6,6 @@
 import 'dart:io';
 import 'dart:isolate';
 
-import 'internal.dart';
-
 export '../../../../../benchmarks/IsolateFibonacci/dart/IsolateFibonacci.dart'
   show fibonacciRecursive;
 
@@ -102,7 +100,7 @@
         case Command.kRunAndClose:
           final RingElement re = args[1];
           final SendPort nextNeighbor = args[2];
-          port.sendAndExit(await re.run(nextNeighbor, siData));
+          Isolate.exit(port, await re.run(nextNeighbor, siData));
           break;
         case Command.kClose:
           port.send('done');
diff --git a/runtime/tests/vm/dart/sendandexit_test.dart b/runtime/tests/vm/dart/sendandexit_test.dart
index 58e02c6..235a3c2 100644
--- a/runtime/tests/vm/dart/sendandexit_test.dart
+++ b/runtime/tests/vm/dart/sendandexit_test.dart
@@ -4,9 +4,8 @@
 //
 // VMOptions=--enable-isolate-groups
 //
-// Validates functionality of sendAndExit.
+// Validates functionality of Isolate.exit().
 
-import 'dart:_internal' show sendAndExit;
 import 'dart:async';
 import 'dart:isolate';
 import 'dart:nativewrappers';
@@ -27,7 +26,7 @@
 verifyCantSendAnonymousClosure() async {
   final receivePort = ReceivePort();
   Expect.throws(
-      () => sendAndExit(receivePort.sendPort, () {}),
+      () => Isolate.exit(receivePort.sendPort, () {}),
       (e) =>
           e.toString() ==
           'Invalid argument: "Illegal argument in isolate message : '
@@ -40,7 +39,7 @@
 verifyCantSendNative() async {
   final receivePort = ReceivePort();
   Expect.throws(
-      () => sendAndExit(receivePort.sendPort, NativeWrapperClass()),
+      () => Isolate.exit(receivePort.sendPort, NativeWrapperClass()),
       (e) => e.toString().startsWith('Invalid argument: '
           '"Illegal argument in isolate message : '
           '(object extends NativeWrapper'));
@@ -50,7 +49,7 @@
 verifyCantSendReceivePort() async {
   final receivePort = ReceivePort();
   Expect.throws(
-      () => sendAndExit(receivePort.sendPort, receivePort),
+      () => 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 : '
@@ -62,7 +61,7 @@
   final receivePort = ReceivePort();
   final regexp = RegExp("");
   Expect.throws(
-      () => sendAndExit(receivePort.sendPort, regexp),
+      () => Isolate.exit(receivePort.sendPort, regexp),
       (e) =>
           e.toString() ==
           'Invalid argument: '
@@ -73,7 +72,7 @@
 add(a, b) => a + b;
 
 worker(SendPort sendPort) async {
-  sendAndExit(sendPort, add);
+  Isolate.exit(sendPort, add);
 }
 
 verifyCanSendStaticMethod() async {
diff --git a/runtime/tests/vm/dart_2/isolates/internal.dart b/runtime/tests/vm/dart_2/isolates/internal.dart
deleted file mode 100644
index 1742a43..0000000
--- a/runtime/tests/vm/dart_2/isolates/internal.dart
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// @dart = 2.9
-
-import 'dart:io';
-import 'dart:isolate';
-import 'dart:async';
-import 'dart:_internal' as dart_internal;
-
-extension SendPortSendAndExit on SendPort {
-  void sendAndExit(var message) {
-    dart_internal.sendAndExit(this, message);
-  }
-}
diff --git a/runtime/tests/vm/dart_2/isolates/ring_gc_sendAndExit_test.dart b/runtime/tests/vm/dart_2/isolates/ring_gc_sendAndExit_test.dart
index 56b636c..2c7011c 100644
--- a/runtime/tests/vm/dart_2/isolates/ring_gc_sendAndExit_test.dart
+++ b/runtime/tests/vm/dart_2/isolates/ring_gc_sendAndExit_test.dart
@@ -26,7 +26,7 @@
   final ring = await Ring.create(numIsolates);
 
   // Let each node produce a tree, send it to it's neighbour and let it return
-  // the one it received (via sendAndExit).
+  // the one it received (via Isolate.exit()).
   final results = await ring.runAndClose((int id) => Worker(id));
   Expect.equals(numIsolates, results.length);
 
diff --git a/runtime/tests/vm/dart_2/isolates/test_utils.dart b/runtime/tests/vm/dart_2/isolates/test_utils.dart
index 0c93f3d..a57bb41 100644
--- a/runtime/tests/vm/dart_2/isolates/test_utils.dart
+++ b/runtime/tests/vm/dart_2/isolates/test_utils.dart
@@ -8,8 +8,6 @@
 import 'dart:io';
 import 'dart:isolate';
 
-import 'internal.dart';
-
 export '../../../../../benchmarks/IsolateFibonacci/dart2/IsolateFibonacci.dart'
   show fibonacciRecursive;
 
@@ -104,7 +102,7 @@
         case Command.kRunAndClose:
           final RingElement re = args[1];
           final SendPort nextNeighbor = args[2];
-          port.sendAndExit(await re.run(nextNeighbor, siData));
+          Isolate.exit(port, await re.run(nextNeighbor, siData));
           break;
         case Command.kClose:
           port.send('done');
diff --git a/runtime/tests/vm/dart_2/sendandexit_test.dart b/runtime/tests/vm/dart_2/sendandexit_test.dart
index f64b1ee..3ee64fe 100644
--- a/runtime/tests/vm/dart_2/sendandexit_test.dart
+++ b/runtime/tests/vm/dart_2/sendandexit_test.dart
@@ -4,11 +4,10 @@
 //
 // VMOptions=--enable-isolate-groups
 //
-// Validates functionality of sendAndExit.
+// Validates functionality of Isolate.exit().
 
 // @dart = 2.9
 
-import 'dart:_internal' show sendAndExit;
 import 'dart:async';
 import 'dart:isolate';
 import 'dart:nativewrappers';
@@ -29,7 +28,7 @@
 verifyCantSendAnonymousClosure() async {
   final receivePort = ReceivePort();
   Expect.throws(
-      () => sendAndExit(receivePort.sendPort, () {}),
+      () => Isolate.exit(receivePort.sendPort, () {}),
       (e) =>
           e.toString() ==
           'Invalid argument: "Illegal argument in isolate message : '
@@ -42,7 +41,7 @@
 verifyCantSendNative() async {
   final receivePort = ReceivePort();
   Expect.throws(
-      () => sendAndExit(receivePort.sendPort, NativeWrapperClass()),
+      () => Isolate.exit(receivePort.sendPort, NativeWrapperClass()),
       (e) => e.toString().startsWith('Invalid argument: '
           '"Illegal argument in isolate message : '
           '(object extends NativeWrapper'));
@@ -52,7 +51,7 @@
 verifyCantSendReceivePort() async {
   final receivePort = ReceivePort();
   Expect.throws(
-      () => sendAndExit(receivePort.sendPort, receivePort),
+      () => 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 : '
@@ -64,7 +63,7 @@
   final receivePort = ReceivePort();
   final regexp = RegExp("");
   Expect.throws(
-      () => sendAndExit(receivePort.sendPort, regexp),
+      () => Isolate.exit(receivePort.sendPort, regexp),
       (e) =>
           e.toString() ==
           'Invalid argument: '
@@ -75,7 +74,7 @@
 add(a, b) => a + b;
 
 worker(SendPort sendPort) async {
-  sendAndExit(sendPort, add);
+  Isolate.exit(sendPort, add);
 }
 
 verifyCanSendStaticMethod() async {
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 4911d25..6f6d67d 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -65,7 +65,6 @@
   V(SendPortImpl_get_id, 1)                                                    \
   V(SendPortImpl_get_hashcode, 1)                                              \
   V(SendPortImpl_sendInternal_, 2)                                             \
-  V(SendPortImpl_sendAndExitInternal_, 2)                                      \
   V(Smi_bitNegate, 1)                                                          \
   V(Smi_bitLength, 1)                                                          \
   V(Mint_bitNegate, 1)                                                         \
@@ -316,12 +315,13 @@
   V(Int32x4_setFlagZ, 2)                                                       \
   V(Int32x4_setFlagW, 2)                                                       \
   V(Int32x4_select, 3)                                                         \
+  V(Isolate_exit_, 2)                                                          \
+  V(Isolate_getCurrentRootUriStr, 0)                                           \
+  V(Isolate_getDebugName, 1)                                                   \
+  V(Isolate_getPortAndCapabilitiesOfCurrentIsolate, 0)                         \
+  V(Isolate_sendOOB, 2)                                                        \
   V(Isolate_spawnFunction, 10)                                                 \
   V(Isolate_spawnUri, 12)                                                      \
-  V(Isolate_getPortAndCapabilitiesOfCurrentIsolate, 0)                         \
-  V(Isolate_getCurrentRootUriStr, 0)                                           \
-  V(Isolate_sendOOB, 2)                                                        \
-  V(Isolate_getDebugName, 1)                                                   \
   V(GrowableList_allocate, 2)                                                  \
   V(GrowableList_getIndexed, 2)                                                \
   V(GrowableList_setIndexed, 3)                                                \
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 863880e..bed2681 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -756,11 +756,10 @@
 TEST_CASE(DartAPI_EnsureUnwindErrorHandled_WhenSendAndExit) {
   const char* kScriptChars = R"(
 import 'dart:isolate';
-import 'dart:_internal' show sendAndExit;
 
 sendAndExitNow() {
   final receivePort = ReceivePort();
-  sendAndExit(receivePort.sendPort, true);
+  Isolate.exit(receivePort.sendPort, true);
 }
 
 @pragma("vm:external-name", "Test_nativeFunc")
diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc
index dfa116b..8a1cd87 100644
--- a/runtime/vm/object_graph.cc
+++ b/runtime/vm/object_graph.cc
@@ -849,6 +849,47 @@
   DISALLOW_COPY_AND_ASSIGN(Pass1Visitor);
 };
 
+class CountImagePageRefs : public ObjectVisitor {
+ public:
+  CountImagePageRefs() : ObjectVisitor() {}
+
+  void VisitObject(ObjectPtr obj) {
+    if (obj->IsPseudoObject()) return;
+    count_++;
+  }
+  intptr_t count() const { return count_; }
+
+ private:
+  intptr_t count_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(CountImagePageRefs);
+};
+
+class WriteImagePageRefs : public ObjectVisitor {
+ public:
+  explicit WriteImagePageRefs(HeapSnapshotWriter* writer)
+      : ObjectVisitor(), writer_(writer) {}
+
+  void VisitObject(ObjectPtr obj) {
+    if (obj->IsPseudoObject()) return;
+#if defined(DEBUG)
+    count_++;
+#endif
+    writer_->WriteUnsigned(writer_->GetObjectId(obj));
+  }
+#if defined(DEBUG)
+  intptr_t count() const { return count_; }
+#endif
+
+ private:
+  HeapSnapshotWriter* const writer_;
+#if defined(DEBUG)
+  intptr_t count_ = 0;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(WriteImagePageRefs);
+};
+
 enum NonReferenceDataTags {
   kNoData = 0,
   kNullData,
@@ -865,9 +906,10 @@
 
 enum ExtraCids {
   kRootExtraCid = 1,  // 1-origin
-  kIsolateExtraCid = 2,
+  kImagePageExtraCid = 2,
+  kIsolateExtraCid = 3,
 
-  kNumExtraCids = 2,
+  kNumExtraCids = 3,
 };
 
 class Pass2Visitor : public ObjectVisitor,
@@ -1209,7 +1251,16 @@
       WriteUnsigned(0);   // Field count
     }
     {
-      ASSERT(kIsolateExtraCid == 2);
+      ASSERT(kImagePageExtraCid == 2);
+      WriteUnsigned(0);              // Flags
+      WriteUtf8("Read-Only Pages");  // Name
+      WriteUtf8("");                 // Library name
+      WriteUtf8("");                 // Library uri
+      WriteUtf8("");                 // Reserved
+      WriteUnsigned(0);              // Field count
+    }
+    {
+      ASSERT(kIsolateExtraCid == 3);
       WriteUnsigned(0);      // Flags
       WriteUtf8("Isolate");  // Name
       WriteUtf8("");         // Library name
@@ -1226,7 +1277,7 @@
         WriteUtf8("");  // Reserved
       }
     }
-    ASSERT(kNumExtraCids == 2);
+    ASSERT(kNumExtraCids == 3);
     for (intptr_t cid = 1; cid <= class_count_; cid++) {
       if (!class_table->HasValidClassAt(cid)) {
         WriteUnsigned(0);  // Flags
@@ -1320,21 +1371,34 @@
   SetupCountingPages();
 
   intptr_t num_isolates = 0;
+  intptr_t num_image_objects = 0;
   {
     Pass1Visitor visitor(this);
 
     // Root "objects".
-    ++object_count_;
-    isolate_group()->VisitSharedPointers(&visitor);
-    isolate_group()->ForEachIsolate(
-        [&](Isolate* isolate) {
-          ++object_count_;
-          isolate->VisitObjectPointers(&visitor,
-                                       ValidationPolicy::kDontValidateFrames);
-          ++num_isolates;
-        },
-        /*at_safepoint=*/true);
-    CountReferences(num_isolates);
+    {
+      ++object_count_;
+      isolate_group()->VisitSharedPointers(&visitor);
+    }
+    {
+      ++object_count_;
+      CountImagePageRefs visitor;
+      H->old_space()->VisitObjectsImagePages(&visitor);
+      num_image_objects = visitor.count();
+      CountReferences(num_image_objects);
+    }
+    {
+      isolate_group()->ForEachIsolate(
+          [&](Isolate* isolate) {
+            ++object_count_;
+            isolate->VisitObjectPointers(&visitor,
+                                         ValidationPolicy::kDontValidateFrames);
+            ++num_isolates;
+          },
+          /*at_safepoint=*/true);
+    }
+    CountReferences(1);             // Root -> Image Pages
+    CountReferences(num_isolates);  // Root -> Isolate
 
     // Heap objects.
     iteration.IterateVMIsolateObjects(&visitor);
@@ -1357,13 +1421,24 @@
       WriteUnsigned(kNoData);
       visitor.DoCount();
       isolate_group()->VisitSharedPointers(&visitor);
-      visitor.CountExtraRefs(num_isolates);
+      visitor.CountExtraRefs(num_isolates + 1);
       visitor.DoWrite();
       isolate_group()->VisitSharedPointers(&visitor);
+      visitor.WriteExtraRef(2);  // Root -> Image Pages
       for (intptr_t i = 0; i < num_isolates; i++) {
-        visitor.WriteExtraRef(i + 2);  // 0 = sentinel, 1 = root, 2+ = isolates
+        // 0 = sentinel, 1 = root, 2 = image pages, 2+ = isolates
+        visitor.WriteExtraRef(i + 3);
       }
     }
+    {
+      WriteUnsigned(kImagePageExtraCid);
+      WriteUnsigned(0);  // shallowSize
+      WriteUnsigned(kNoData);
+      WriteUnsigned(num_image_objects);
+      WriteImagePageRefs visitor(this);
+      H->old_space()->VisitObjectsImagePages(&visitor);
+      DEBUG_ASSERT(visitor.count() == num_image_objects);
+    }
     isolate_group()->ForEachIsolate(
         [&](Isolate* isolate) {
           WriteUnsigned(kIsolateExtraCid);
@@ -1395,10 +1470,13 @@
     // Identity hash codes
     Pass3Visitor visitor(this);
 
-    // Handle root object.
-    WriteUnsigned(0);
-    isolate_group()->ForEachIsolate([&](Isolate* isolate) { WriteUnsigned(0); },
-                                    /*at_safepoint=*/true);
+    WriteUnsigned(0);  // Root fake object.
+    WriteUnsigned(0);  // Image pages fake object.
+    isolate_group()->ForEachIsolate(
+        [&](Isolate* isolate) {
+          WriteUnsigned(0);  // Isolate fake object.
+        },
+        /*at_safepoint=*/true);
 
     // Handle visit rest of the objects.
     iteration.IterateVMIsolateObjects(&visitor);
diff --git a/sdk/lib/_http/http.dart b/sdk/lib/_http/http.dart
index d303412..b7b1f50 100644
--- a/sdk/lib/_http/http.dart
+++ b/sdk/lib/_http/http.dart
@@ -2063,7 +2063,7 @@
   /// Using the [IOSink] methods (e.g., [write] and [add]) has no effect after
   /// the request has been aborted
   ///
-  /// ```dart
+  /// ```dart import:async
   /// HttpClientRequst request = ...
   /// request.write();
   /// Timer(Duration(seconds: 1), () {
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/isolate_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/isolate_patch.dart
index 6799347..0d12311 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/isolate_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/isolate_patch.dart
@@ -77,6 +77,10 @@
 
   @patch
   void removeErrorListener(SendPort port) => _unsupported();
+
+  @patch
+  static Never exit([SendPort? finalMessagePort, Object? message]) =>
+      _unsupported();
 }
 
 /** Default factory for receive ports. */
diff --git a/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart b/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart
index 1c0b053..2bb2fa1 100644
--- a/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart
@@ -106,6 +106,11 @@
   void removeErrorListener(SendPort port) {
     throw new UnsupportedError("Isolate.removeErrorListener");
   }
+
+  @patch
+  static Never exit([SendPort? finalMessagePort, Object? message]) {
+    throw new UnsupportedError("Isolate.exit");
+  }
 }
 
 @patch
diff --git a/sdk/lib/_internal/vm/lib/internal_patch.dart b/sdk/lib/_internal/vm/lib/internal_patch.dart
index 421fb4d..569b91c 100644
--- a/sdk/lib/_internal/vm/lib/internal_patch.dart
+++ b/sdk/lib/_internal/vm/lib/internal_patch.dart
@@ -178,9 +178,6 @@
 @pragma("vm:external-name", "Internal_nativeEffect")
 external void _nativeEffect(Object object);
 
-@pragma("vm:external-name", "SendPortImpl_sendAndExitInternal_")
-external void sendAndExit(SendPort sendPort, var message);
-
 // Collection of functions which should only be used for testing purposes.
 abstract class VMInternalsForTesting {
   // This function can be used by tests to enforce garbage collection.
diff --git a/sdk/lib/_internal/vm/lib/isolate_patch.dart b/sdk/lib/_internal/vm/lib/isolate_patch.dart
index b7bf498..37fb390 100644
--- a/sdk/lib/_internal/vm/lib/isolate_patch.dart
+++ b/sdk/lib/_internal/vm/lib/isolate_patch.dart
@@ -645,6 +645,13 @@
 
   @pragma("vm:external-name", "Isolate_getCurrentRootUriStr")
   external static String _getCurrentRootUriStr();
+
+  @pragma("vm:external-name", "Isolate_exit_")
+  external static Never _exit(SendPort? finalMessagePort, Object? message);
+
+  static Never exit([SendPort? finalMessagePort, Object? message]) {
+    _exit(finalMessagePort, message);
+  }
 }
 
 @patch
diff --git a/sdk/lib/async/async.dart b/sdk/lib/async/async.dart
index 33df08e..00b7fc6 100644
--- a/sdk/lib/async/async.dart
+++ b/sdk/lib/async/async.dart
@@ -32,7 +32,7 @@
 /// Many methods in the Dart libraries return `Future`s when
 /// performing tasks. For example, when binding an `HttpServer`
 /// to a host and port, the `bind()` method returns a Future.
-/// ```dart
+/// ```dart import:io
 ///  HttpServer.bind('127.0.0.1', 4444)
 ///      .then((server) => print('${server.isBroadcast}'))
 ///      .catchError(print);
@@ -60,7 +60,7 @@
 /// the stream has finished.
 /// Further functionality is provided on [Stream], implemented by calling
 /// [Stream.listen] to get the actual data.
-/// ```dart
+/// ```dart import:io import:convert
 /// Stream<List<int>> stream = File('quotes.txt').openRead();
 /// stream.transform(utf8.decoder).forEach(print);
 /// ```
@@ -72,7 +72,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
+/// ```dart import:html
 /// querySelector('#myButton').onClick.forEach((_) => print('Click.'));
 /// ```
 /// ## Other resources
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index f663b08..c587536 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -738,7 +738,7 @@
   ///
   /// This method is equivalent to:
   /// ```dart
-  /// Future<T> whenComplete(action()) {
+  /// Future<T> whenComplete(action() {
   ///   return this.then((v) {
   ///     var f2 = action();
   ///     if (f2 is Future) return f2.then((_) => v);
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index 2083510..3f12cb3 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -2059,7 +2059,7 @@
   /// [StreamTransformer.bind] API and can be used when the transformation is
   /// available as a stream-to-stream function.
   ///
-  /// ```dart
+  /// ```dart import:convert
   /// final splitDecoded = StreamTransformer<List<int>, String>.fromBind(
   ///     (stream) => stream.transform(utf8.decoder).transform(LineSplitter()));
   /// ```
diff --git a/sdk/lib/convert/convert.dart b/sdk/lib/convert/convert.dart
index 081f006..b1a1cea 100644
--- a/sdk/lib/convert/convert.dart
+++ b/sdk/lib/convert/convert.dart
@@ -34,7 +34,7 @@
 /// as it's read from a file,
 /// The second is an instance of [LineSplitter],
 /// which splits the data on newline boundaries.
-/// ```dart
+/// ```dart import:io
 /// var lineNumber = 1;
 /// var stream = File('quotes.txt').openRead();
 ///
diff --git a/sdk/lib/io/io.dart b/sdk/lib/io/io.dart
index 84ad5f9..4cad26d 100644
--- a/sdk/lib/io/io.dart
+++ b/sdk/lib/io/io.dart
@@ -111,7 +111,7 @@
 /// and listens for the data on the returned web socket.
 /// For example, here's a mini server that listens for 'ws' data
 /// on a WebSocket:
-/// ```dart
+/// ```dart import:async
 /// runZoned(() async {
 ///   var server = await HttpServer.bind('127.0.0.1', 4040);
 ///   server.listen((HttpRequest req) async {
@@ -140,7 +140,7 @@
 /// Use [ServerSocket] on the server side and [Socket] on the client.
 /// The server creates a listening socket using the `bind()` method and
 /// then listens for incoming connections on the socket. For example:
-/// ```dart
+/// ```dart import:convert
 /// ServerSocket.bind('127.0.0.1', 4041)
 ///   .then((serverSocket) {
 ///     serverSocket.listen((socket) {
diff --git a/sdk/lib/io/platform.dart b/sdk/lib/io/platform.dart
index 2d0ca6e..39d5a11 100644
--- a/sdk/lib/io/platform.dart
+++ b/sdk/lib/io/platform.dart
@@ -43,7 +43,7 @@
 ///
 /// You can get the name of the operating system as a string with the
 /// [operatingSystem] getter. You can also use one of the static boolean
-/// getters: [isMacOS], [isLinux], and [isWindows].
+/// getters: [isMacOS], [isLinux], [isWindows], etc.
 /// ```dart
 /// import 'dart:io' show Platform;
 ///
@@ -77,6 +77,17 @@
   static String get localeName => _Platform.localeName();
 
   /// A string representing the operating system or platform.
+  ///
+  /// Possible values include:
+  ///   "android"
+  ///   "fuchsia"
+  ///   "ios"
+  ///   "linux"
+  ///   "macos"
+  ///   "windows"
+  ///
+  /// Note that this list may change over time so platform-specific logic
+  /// should be guarded by the appropriate boolean getter e.g. [isMacOS].
   static String get operatingSystem => _operatingSystem;
 
   /// A string representing the version of the operating system or platform.
diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart
index 8a68d10..fc47a29 100644
--- a/sdk/lib/isolate/isolate.dart
+++ b/sdk/lib/isolate/isolate.dart
@@ -553,6 +553,32 @@
     };
     return controller.stream;
   }
+
+  /// Terminates the current isolate synchronously.
+  ///
+  /// This operations is potentially dangerous and should be used judiciously.
+  /// The isolate stops operating *immediately*. It throws if optional [message]
+  /// does not adhere to the limitation on what can be send from one isolate to
+  /// another. It also throws if a [finalMessagePort] is associated with an
+  /// isolate spawned outside of current isolate group, spawned via [spawnUri].
+  ///
+  /// If successful, a call to this method does not return. Pending `finally`
+  /// blocks are not executed, control flow will not go back to the event loop,
+  /// scheduled asynchronous asks will never run, and even pending isolate
+  /// control commands may be ignored. (The isolate will send messages to ports
+  /// already registered using [Isolate.addOnExitListener], but no further Dart
+  /// code will run in the isolate.)
+  ///
+  /// If [finalMessagePort] is provided, and the [message] can be sent through
+  /// it, then the message is sent through that port as the final operation of
+  /// the current isolate. The isolate terminates immediately after
+  /// that [SendPort.send] call returns.
+  ///
+  /// (If the port is a native port, one provided by [ReceivePort.sendPort]
+  /// or [RawReceivePort.sendPort], the system may be able to send this final
+  /// message more efficiently than normal port communication between live
+  /// isolates.)
+  external static Never exit([SendPort? finalMessagePort, Object? message]);
 }
 
 /// Sends messages to its [ReceivePort]s.
diff --git a/tests/corelib/symbol_arbitrary_string_test.dart b/tests/corelib/symbol_arbitrary_string_test.dart
index c4c4d25..ff6cf56 100644
--- a/tests/corelib/symbol_arbitrary_string_test.dart
+++ b/tests/corelib/symbol_arbitrary_string_test.dart
@@ -2,9 +2,9 @@
 // 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.
 
-// Note that this library violates the formatting provided by `dartfmt` in
+// Note that this library violates the formatting provided by `dart format` in
 // a few locations, to verify that `"""...""""z"` can be parsed as two
-// consecutive strings, `dartfmt` will insert whitespace before `"z"`.
+// consecutive strings, `dart format` will insert whitespace before `"z"`.
 
 import 'package:expect/expect.dart';
 
diff --git a/tests/language/async_star/yield_statement_context_test.dart b/tests/language/async_star/yield_statement_context_test.dart
index 7320f02..2b3faa9 100644
--- a/tests/language/async_star/yield_statement_context_test.dart
+++ b/tests/language/async_star/yield_statement_context_test.dart
@@ -51,7 +51,7 @@
 
   test('two labels on same line', () {
     f() async* {
-      // DO NOT RUN dartfmt on this file. The labels should be on the same.
+      // DO NOT RUN dart format on this file. The labels should be on the same.
       // line. Originally VM issue #2238.
       label1: label2: yield 0;
     }
diff --git a/tests/language/null_aware/access_test.dart b/tests/language/null_aware/access_test.dart
index 3307440..6fc1daa 100644
--- a/tests/language/null_aware/access_test.dart
+++ b/tests/language/null_aware/access_test.dart
@@ -132,4 +132,7 @@
   //                                        ^^^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_GETTER
   // [cfe] Member not found: 'hashCode'.
+
+  // (C.staticInt?.floor())! can be assigned to int.
+  int y = (C.staticInt?.floor())!;
 }
diff --git a/tests/language/redirecting/factory_bounds_test.dart b/tests/language/redirecting/factory_bounds_test.dart
index 694062e..fcc2f54 100644
--- a/tests/language/redirecting/factory_bounds_test.dart
+++ b/tests/language/redirecting/factory_bounds_test.dart
@@ -11,7 +11,7 @@
 class Foobar<T> implements Foo<T> {}
 
 class Bar<
-          T // A comment to prevent dartfmt from joining the lines.
+          T // A comment to prevent dart format from joining the lines.
           extends Foo<T>      //# 00: ok
           extends Baz<Foo<T>> //# 01: compile-time error
           extends Foobar<T>   //# 02: compile-time error
@@ -21,7 +21,7 @@
 }
 
 class Qux<
-          T // A comment to prevent dartfmt from joining the lines.
+          T // A comment to prevent dart format from joining the lines.
           extends Foo<T> //# 00: continued
           extends Foo<T> //# 01: continued
           extends Foo<T> //# 02: continued
@@ -33,7 +33,7 @@
 
 class A<T extends int> {
   factory A() = B<
-                  T // A comment to prevent dartfmt from joining the lines.
+                  T // A comment to prevent dart format from joining the lines.
                   , int //# 03: compile-time error
                   , String //# 04: ok
                  >;
diff --git a/tests/language_2/async_star/yield_statement_context_test.dart b/tests/language_2/async_star/yield_statement_context_test.dart
index e512b3f..7e64c9b 100644
--- a/tests/language_2/async_star/yield_statement_context_test.dart
+++ b/tests/language_2/async_star/yield_statement_context_test.dart
@@ -53,7 +53,7 @@
 
   test('two labels on same line', () {
     f() async* {
-      // DO NOT RUN dartfmt on this file. The labels should be on the same.
+      // DO NOT RUN dart format on this file. The labels should be on the same.
       // line. Originally VM issue #2238.
       label1: label2: yield 0;
     }
diff --git a/tests/language_2/redirecting/factory_bounds_test.dart b/tests/language_2/redirecting/factory_bounds_test.dart
index 9fec8bd..f8fcca9 100644
--- a/tests/language_2/redirecting/factory_bounds_test.dart
+++ b/tests/language_2/redirecting/factory_bounds_test.dart
@@ -13,7 +13,7 @@
 class Foobar<T> implements Foo<T> {}
 
 class Bar<
-          T // A comment to prevent dartfmt from joining the lines.
+          T // A comment to prevent dart format from joining the lines.
           extends Foo<T>      //# 00: ok
           extends Baz<Foo<T>> //# 01: compile-time error
           extends Foobar<T>   //# 02: compile-time error
@@ -23,7 +23,7 @@
 }
 
 class Qux<
-          T // A comment to prevent dartfmt from joining the lines.
+          T // A comment to prevent dart format from joining the lines.
           extends Foo<T> //# 00: continued
           extends Foo<T> //# 01: continued
           extends Foo<T> //# 02: continued
@@ -35,7 +35,7 @@
 
 class A<T extends int> {
   factory A() = B<
-                  T // A comment to prevent dartfmt from joining the lines.
+                  T // A comment to prevent dart format from joining the lines.
                   , int //# 03: compile-time error
                   , String //# 04: ok
                  >;
diff --git a/tests/lib/mirrors/invocation_fuzz_test.dart b/tests/lib/mirrors/invocation_fuzz_test.dart
index ea8f546..ed8ba09 100644
--- a/tests/lib/mirrors/invocation_fuzz_test.dart
+++ b/tests/lib/mirrors/invocation_fuzz_test.dart
@@ -20,6 +20,7 @@
 
   // Don't exit the test pre-maturely.
   'dart.io.exit',
+  'dart.isolate.Isolate.exit',
 
   // Don't change the exit code, which may fool the test harness.
   'dart.io.exitCode',
diff --git a/tests/lib_2/mirrors/invocation_fuzz_test.dart b/tests/lib_2/mirrors/invocation_fuzz_test.dart
index 6323806..68360d1 100644
--- a/tests/lib_2/mirrors/invocation_fuzz_test.dart
+++ b/tests/lib_2/mirrors/invocation_fuzz_test.dart
@@ -22,6 +22,7 @@
 
   // Don't exit the test pre-maturely.
   'dart.io.exit',
+  'dart.isolate.Isolate.exit',
 
   // Don't change the exit code, which may fool the test harness.
   'dart.io.exitCode',
diff --git a/tests/standalone/dwarf_stack_trace_invisible_functions_test.dart b/tests/standalone/dwarf_stack_trace_invisible_functions_test.dart
index b7247454..a9fe0f3 100644
--- a/tests/standalone/dwarf_stack_trace_invisible_functions_test.dart
+++ b/tests/standalone/dwarf_stack_trace_invisible_functions_test.dart
@@ -20,7 +20,7 @@
 @pragma("vm:prefer-inline")
 bar() {
   // Keep the 'throw' and its argument on separate lines.
-  throw // force linebreak with dartfmt // LINE_A
+  throw // force linebreak with dart format // LINE_A
       "Hello, Dwarf!";
 }
 
diff --git a/tests/standalone/dwarf_stack_trace_obfuscate_test.dart b/tests/standalone/dwarf_stack_trace_obfuscate_test.dart
index f6b3360..23eb3f9 100644
--- a/tests/standalone/dwarf_stack_trace_obfuscate_test.dart
+++ b/tests/standalone/dwarf_stack_trace_obfuscate_test.dart
@@ -14,7 +14,7 @@
 @pragma("vm:prefer-inline")
 bar() {
   // Keep the 'throw' and its argument on separate lines.
-  throw // force linebreak with dartfmt
+  throw // force linebreak with dart format
       "Hello, Dwarf!";
 }
 
diff --git a/tests/standalone/dwarf_stack_trace_test.dart b/tests/standalone/dwarf_stack_trace_test.dart
index a583d34..970be0e 100644
--- a/tests/standalone/dwarf_stack_trace_test.dart
+++ b/tests/standalone/dwarf_stack_trace_test.dart
@@ -14,7 +14,7 @@
 @pragma("vm:prefer-inline")
 bar() {
   // Keep the 'throw' and its argument on separate lines.
-  throw // force linebreak with dartfmt
+  throw // force linebreak with dart format
       "Hello, Dwarf!";
 }
 
diff --git a/tests/standalone_2/dwarf_stack_trace_invisible_functions_test.dart b/tests/standalone_2/dwarf_stack_trace_invisible_functions_test.dart
index cd912fc..411ebd9 100644
--- a/tests/standalone_2/dwarf_stack_trace_invisible_functions_test.dart
+++ b/tests/standalone_2/dwarf_stack_trace_invisible_functions_test.dart
@@ -22,7 +22,7 @@
 @pragma("vm:prefer-inline")
 bar() {
   // Keep the 'throw' and its argument on separate lines.
-  throw // force linebreak with dartfmt // LINE_A
+  throw // force linebreak with dart format // LINE_A
       "Hello, Dwarf!";
 }
 
diff --git a/tests/standalone_2/dwarf_stack_trace_obfuscate_test.dart b/tests/standalone_2/dwarf_stack_trace_obfuscate_test.dart
index 8614b88..f21fff1 100644
--- a/tests/standalone_2/dwarf_stack_trace_obfuscate_test.dart
+++ b/tests/standalone_2/dwarf_stack_trace_obfuscate_test.dart
@@ -16,7 +16,7 @@
 @pragma("vm:prefer-inline")
 bar() {
   // Keep the 'throw' and its argument on separate lines.
-  throw // force linebreak with dartfmt
+  throw // force linebreak with dart format
       "Hello, Dwarf!";
 }
 
diff --git a/tests/standalone_2/dwarf_stack_trace_test.dart b/tests/standalone_2/dwarf_stack_trace_test.dart
index 75353ee..acc066b 100644
--- a/tests/standalone_2/dwarf_stack_trace_test.dart
+++ b/tests/standalone_2/dwarf_stack_trace_test.dart
@@ -16,7 +16,7 @@
 @pragma("vm:prefer-inline")
 bar() {
   // Keep the 'throw' and its argument on separate lines.
-  throw // force linebreak with dartfmt
+  throw // force linebreak with dart format
       "Hello, Dwarf!";
 }
 
diff --git a/tools/VERSION b/tools/VERSION
index 0fdd90e..4eb2c84 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 15
 PATCH 0
-PRERELEASE 168
+PRERELEASE 169
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/sdks/README b/tools/sdks/README
index b7d766a5..0ef9f68 100644
--- a/tools/sdks/README
+++ b/tools/sdks/README
@@ -7,6 +7,6 @@
 on ARM and ARM64 are also provided.
 
 To upload new versions of these CIPD packages, run "./update.sh" in this
-directory. Because these SDKs are used for the presubmit dartfmt check on
-changed files, they may need to be updated often when dartfmt is changing
+directory. Because these SDKs are used for the presubmit dart format check on
+changed files, they may need to be updated often when dart format is changing
 rapidly. Access to the project-dart-admins Luci auth group is required to do so.
diff --git a/tools/verify_docs/README.md b/tools/verify_docs/README.md
index 13f72bd..cc64017 100644
--- a/tools/verify_docs/README.md
+++ b/tools/verify_docs/README.md
@@ -20,5 +20,36 @@
 
 ## Authoring code samples
 
-TODO(devoncarew): Document the conventions for code samples in the dart: libraries
-and the tools available to configure them.
+### What gets analyzed
+
+This tool will walk all dartdoc api docs looking for code samples in doc comments.
+It will analyze any code sample in a `dart` code fence. For example:
+
+> ```dart
+> print('hello world!');
+> ```
+
+By default, an import for that library is added to the sample being analyzed (i.e.,
+`import 'dart:async";`). Additionally, the code sample is automatically embedded in
+the body of a simple main() method.
+
+### Excluding code samples from analysis
+
+In order to exclude a code sample from analysis, change it to a plain code fence style:
+
+> ```
+> print("I'm not analyzed :(");
+> ```
+
+### Specifying additional imports
+
+In order to reference code from other Dart core libraries, you can either explicitly add
+the import to the code sample - in-line in the sample - or use a directive on the same
+line as the code fence. The directive style looks like:
+
+> ```dart import:async
+> print('hello world ${Timer()}');
+> ```
+
+Multiple imports can be specified like this if desired (i.e., "```dart import:async import:convert").
+
diff --git a/tools/verify_docs/bin/verify_docs.dart b/tools/verify_docs/bin/verify_docs.dart
index ebd4822..8c4fc67 100644
--- a/tools/verify_docs/bin/verify_docs.dart
+++ b/tools/verify_docs/bin/verify_docs.dart
@@ -28,8 +28,10 @@
   print('Validating the dartdoc code samples from the dart: libraries.');
   print('');
   print('To run this tool, run `dart tools/verify_docs/bin/verify_docs.dart`.');
+  print('');
   print('For documentation about how to author dart: code samples,'
       ' see tools/verify_docs/README.md');
+  print('');
 
   final coreLibraries = args.isEmpty
       ? libDir.listSync().whereType<Directory>().toList()
@@ -90,7 +92,6 @@
     return error.errorCode.type == ErrorType.SYNTACTIC_ERROR;
   }).toList();
   if (syntacticErrors.isNotEmpty) {
-    // todo: have a better failure mode
     throw Exception(syntacticErrors);
   }
 
@@ -108,21 +109,22 @@
   return visitor.errors.isEmpty;
 }
 
-/// todo: doc
+/// Visit a compilation unit and collect the list of code samples found in
+/// dartdoc comments.
 class ValidateCommentCodeSamplesVisitor extends GeneralizingAstVisitor {
   final String coreLibName;
   final String filePath;
   final LineInfo lineInfo;
 
+  final List<CodeSample> samples = [];
+  final StringBuffer errors = StringBuffer();
+
   ValidateCommentCodeSamplesVisitor(
     this.coreLibName,
     this.filePath,
     this.lineInfo,
   );
 
-  final List<CodeSample> samples = [];
-  final StringBuffer errors = StringBuffer();
-
   Future process(ParseStringResult parseResult) async {
     // collect code samples
     visitCompilationUnit(parseResult.unit);
@@ -135,7 +137,6 @@
 
   @override
   void visitAnnotatedNode(AnnotatedNode node) {
-    // todo: ignore (or fail?) doc comments on non-public symbols
     _handleDocumentableNode(node);
     super.visitAnnotatedNode(node);
   }
@@ -158,6 +159,11 @@
 
     var offset = text.indexOf(sampleStart);
     while (offset != -1) {
+      // Collect template directives, like "```dart import:async".
+      final codeFenceSuffix = text.substring(
+          offset + sampleStart.length, text.indexOf('\n', offset));
+      final directives = Set.unmodifiable(codeFenceSuffix.trim().split(' '));
+
       offset = text.indexOf('\n', offset) + 1;
       final end = text.indexOf(sampleEnd, offset);
 
@@ -166,13 +172,12 @@
 
       List<String> lines = snippet.split('\n');
 
-      // TODO(devoncarew): Also look for template directives.
-
       samples.add(
         CodeSample(
-          coreLibName,
           lines.map((e) => '  ${cleanDocLine(e)}').join('\n'),
-          commentLineStart +
+          coreLibName: coreLibName,
+          directives: directives,
+          lineStartOffset: commentLineStart +
               text.substring(0, offset - 1).split('\n').length -
               1,
         ),
@@ -183,9 +188,6 @@
   }
 
   Future validateCodeSample(CodeSample sample) async {
-    // TODO(devoncarew): Support <!-- template: none --> ?
-    // TODO(devoncarew): Support <!-- template: main --> ?
-
     final resourceProvider =
         OverlayResourceProvider(PhysicalResourceProvider.INSTANCE);
 
@@ -212,6 +214,12 @@
         text = "main() async {\n${text.trimRight()}\n}\n";
       }
 
+      for (final directive
+          in sample.directives.where((str) => str.startsWith('import:'))) {
+        final libName = directive.substring('import:'.length);
+        text = "import 'dart:$libName';\n$text";
+      }
+
       if (sample.coreLibName != 'internal') {
         text = "import 'dart:${sample.coreLibName}';\n$text";
       }
@@ -227,7 +235,7 @@
       modificationStamp: 0,
     );
 
-    // TODO(devoncarew): refactor to use AnalysisContextCollection to avoid
+    // TODO(devoncarew): Refactor to use AnalysisContextCollection to avoid
     // re-creating analysis contexts.
     final result = await resolveFile2(
       path: sampleFilePath,
@@ -239,8 +247,9 @@
     if (result is ResolvedUnitResult) {
       // Filter out unused imports, since we speculatively add imports to some
       // samples.
-      var errors =
-          result.errors.where((e) => e.errorCode != HintCode.UNUSED_IMPORT);
+      var errors = result.errors.where(
+        (e) => e.errorCode != HintCode.UNUSED_IMPORT,
+      );
 
       // Also, don't worry about 'unused_local_variable' and related; this may
       // be intentional in samples.
@@ -250,8 +259,16 @@
             e.errorCode != HintCode.UNUSED_ELEMENT,
       );
 
+      // Remove warnings about deprecated member use from the same library.
+      errors = errors.where(
+        (e) =>
+            e.errorCode != HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE &&
+            e.errorCode !=
+                HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE_WITH_MESSAGE,
+      );
+
       if (errors.isNotEmpty) {
-        print('$filePath:${sample.lineStart}: ${errors.length} errors');
+        print('$filePath:${sample.lineStartOffset}: ${errors.length} errors');
 
         for (final error in errors) {
           final location = result.lineInfo.getLocation(error.offset);
@@ -290,10 +307,16 @@
 
 class CodeSample {
   final String coreLibName;
+  final Set<String> directives;
   final String text;
-  final int lineStart;
+  final int lineStartOffset;
 
-  CodeSample(this.coreLibName, this.text, this.lineStart);
+  CodeSample(
+    this.text, {
+    required this.coreLibName,
+    this.directives = const {},
+    required this.lineStartOffset,
+  });
 }
 
 String _severity(Severity severity) {