Version 2.19.0-45.0.dev

Merge commit 'b7edb69e974d630122e73f13ddeb425728dc3537' into 'dev'
diff --git a/DEPS b/DEPS
index aad6a1a..1ad3427 100644
--- a/DEPS
+++ b/DEPS
@@ -135,11 +135,10 @@
   "path_rev": "9955b27b9bb98d87591208e19eb01c51d29fd467",
   "ply_rev": "604b32590ffad5cbb82e4afef1d305512d06ae93",
   "pool_rev": "fa84ddd0e39f45bf3f09dcc5d6b9fbdda7820fef",
-  "protobuf_rev": "a840335449e6a2a9617d2ebe5ecd0d577e071248",
+  "protobuf_rev": "9aad6aadcc0fc616051c7e0eaef78c26b3dd7b60",
   "pub_rev": "9bf4289d6fd5d6872a8929d6312bbd7098f3ea9c", # manually rev'd
   "pub_semver_rev": "5c0b4bfd5ca57fe16f1319c581dc8c882e9b8cb2",
   "root_certificates_rev": "692f6d6488af68e0121317a9c2c9eb393eb0ee50",
-  "rust_revision": "b7856f695d65a8ebc846754f97d15814bcb1c244",
   "shelf_rev": "0371a64bd3b99044ee3158bacf8813bba735a9c7",
   "source_map_stack_trace_rev": "72dbf21a33293b2b8434d0a9751e36f9463981ac",
   "source_maps_rev": "e93565b43a7b6b367789de8ffba969c4ebeeb317",
@@ -556,23 +555,12 @@
       "dep_type": "cipd",
   },
 
-  Var("dart_root") + "/buildtools/" + Var("host_os") + "-" + Var("host_cpu") + "/rust": {
-      "packages": [
-          {
-              "package": "fuchsia/rust/${{platform}}",
-              "version": "git_revision:" + Var("rust_revision"),
-          },
-      ],
-      "condition": "(host_os == 'linux' or host_os == 'mac') and host_cpu == 'x64'",
-      "dep_type": "cipd",
-  },
-
   # Update from https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/gn
   Var("dart_root") + "/third_party/fuchsia/sdk/mac": {
     "packages": [
       {
       "package": "fuchsia/sdk/gn/mac-amd64",
-      "version": "git_revision:c9bdf5da65647923cb79c391824434125cb00bbe"
+      "version": "git_revision:8658717573be7924d71b88c3d404ea2b4ca4984b"
       }
     ],
     "condition": 'host_os == "mac" and host_cpu == "x64"',
@@ -582,7 +570,7 @@
     "packages": [
       {
       "package": "fuchsia/sdk/gn/linux-amd64",
-      "version": "git_revision:c9bdf5da65647923cb79c391824434125cb00bbe"
+      "version": "git_revision:8658717573be7924d71b88c3d404ea2b4ca4984b"
       }
     ],
     "condition": 'host_os == "linux" and host_cpu == "x64"',
diff --git a/pkg/analysis_server/lib/src/computer/computer_call_hierarchy.dart b/pkg/analysis_server/lib/src/computer/computer_call_hierarchy.dart
index ceb8a33..ca17b51 100644
--- a/pkg/analysis_server/lib/src/computer/computer_call_hierarchy.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_call_hierarchy.dart
@@ -478,7 +478,11 @@
 
   @override
   void visitPrefixedIdentifier(PrefixedIdentifier node) {
-    collect(node.identifier);
+    // Don't collect prefixed identifiers that are just type names. We only
+    // want invocations and tear-offs.
+    if (node.parent is! NamedType) {
+      collect(node.identifier);
+    }
     super.visitPrefixedIdentifier(node);
   }
 
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
index f9cbe3b..956e51e 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
@@ -19,7 +19,8 @@
 import 'package:analysis_server/src/services/completion/yaml/fix_data_generator.dart';
 import 'package:analysis_server/src/services/completion/yaml/pubspec_generator.dart';
 import 'package:analysis_server/src/services/completion/yaml/yaml_completion_generator.dart';
-import 'package:analysis_server/src/services/snippets/dart/snippet_manager.dart';
+import 'package:analysis_server/src/services/snippets/dart_snippet_request.dart';
+import 'package:analysis_server/src/services/snippets/snippet_manager.dart';
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/analysis/session.dart';
 import 'package:analyzer/dart/ast/ast.dart' as ast;
diff --git a/pkg/analysis_server/lib/src/lsp/mapping.dart b/pkg/analysis_server/lib/src/lsp/mapping.dart
index d7ada24..34e7274 100644
--- a/pkg/analysis_server/lib/src/lsp/mapping.dart
+++ b/pkg/analysis_server/lib/src/lsp/mapping.dart
@@ -17,7 +17,7 @@
 import 'package:analysis_server/src/lsp/source_edits.dart';
 import 'package:analysis_server/src/protocol_server.dart' as server
     hide AnalysisError;
-import 'package:analysis_server/src/services/snippets/dart/snippet_manager.dart';
+import 'package:analysis_server/src/services/snippets/snippet.dart';
 import 'package:analyzer/dart/analysis/results.dart' as server;
 import 'package:analyzer/error/error.dart' as server;
 import 'package:analyzer/source/line_info.dart' as server;
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart b/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
index 96a232c..388e79e 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
@@ -32,10 +32,6 @@
 
 /// An object that can compute a correction (fix or assist) in a Dart file.
 abstract class CorrectionProducer extends SingleCorrectionProducer {
-  /// Return the code style options for the current context.
-  CodeStyleOptions get codeStyleOptions =>
-      sessionHelper.session.analysisContext.analysisOptions.codeStyleOptions;
-
   /// Return the type for the class `bool` from `dart:core`.
   DartType get coreTypeBool => resolvedResult.typeProvider.boolType;
 
@@ -390,6 +386,9 @@
   /// Return `true` if the fixes are being built for the bulk-fix request.
   bool get applyingBulkFixes => _context.applyingBulkFixes;
 
+  CodeStyleOptions get codeStyleOptions =>
+      sessionHelper.session.analysisContext.analysisOptions.codeStyleOptions;
+
   /// The most deeply nested node that completely covers the highlight region of
   /// the diagnostic, or `null` if there is no diagnostic or if such a node does
   /// not exist.
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/assign_to_local_variable.dart b/pkg/analysis_server/lib/src/services/correction/dart/assign_to_local_variable.dart
index 3b00724..90aacb1 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/assign_to_local_variable.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/assign_to_local_variable.dart
@@ -6,7 +6,6 @@
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/name_suggestion.dart';
-import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analysis_server/src/utilities/extensions/ast.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/ast/extensions.dart';
@@ -19,7 +18,7 @@
   AssistKind get assistKind => DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE;
 
   String get _declarationKeyword {
-    if (_isLintEnabled(LintNames.prefer_final_locals)) {
+    if (codeStyleOptions.makeLocalsFinal) {
       return 'final';
     } else {
       return 'var';
@@ -75,11 +74,6 @@
     }
   }
 
-  bool _isLintEnabled(String name) {
-    var analysisOptions = unit.declaredElement?.context.analysisOptions;
-    return analysisOptions?.isLintEnabled(name) ?? false;
-  }
-
   /// Return `true` if the given [statement] resulted from a recovery case that
   /// would make the change create even worse errors than the original code.
   static bool _hasPrecedingStatementRecovery(Statement statement) {
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart b/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart
index 5d333c2..d066710 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart
@@ -7,7 +7,6 @@
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analysis_server/src/services/correction/namespace.dart';
-import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analysis_server/src/utilities/extensions/element.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -220,7 +219,7 @@
         _ImportAbsoluteLibrary(fixKind, library),
       ]);
     }
-    if (isLintEnabled(LintNames.prefer_relative_imports)) {
+    if (codeStyleOptions.useRelativeUris) {
       return Stream.fromIterable([
         _ImportRelativeLibrary(fixKind, library),
         _ImportAbsoluteLibrary(fixKind, library),
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
index ac4fb50..5f2bacf 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
@@ -8,11 +8,11 @@
 import 'package:analysis_server/src/services/correction/name_suggestion.dart';
 import 'package:analysis_server/src/services/correction/status.dart';
 import 'package:analysis_server/src/services/correction/util.dart';
-import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analysis_server/src/services/refactoring/naming_conventions.dart';
 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
 import 'package:analysis_server/src/services/refactoring/refactoring_internal.dart';
 import 'package:analysis_server/src/utilities/strings.dart';
+import 'package:analyzer/dart/analysis/code_style_options.dart';
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -61,6 +61,9 @@
     utils = CorrectionUtils(resolveResult);
   }
 
+  CodeStyleOptions get codeStyleOptions =>
+      resolveResult.session.analysisContext.analysisOptions.codeStyleOptions;
+
   String get file => resolveResult.path;
 
   @override
@@ -73,7 +76,7 @@
   String get _declarationKeyword {
     if (_isPartOfConstantExpression(singleExpression)) {
       return 'const';
-    } else if (_isLintEnabled(LintNames.prefer_final_locals)) {
+    } else if (codeStyleOptions.makeLocalsFinal) {
       return 'final';
     } else {
       return 'var';
@@ -437,11 +440,6 @@
     return null;
   }
 
-  bool _isLintEnabled(String name) {
-    var analysisOptions = unitElement.context.analysisOptions;
-    return analysisOptions.isLintEnabled(name);
-  }
-
   bool _isPartOfConstantExpression(AstNode? node) {
     if (node == null) {
       return false;
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart
index c85b15d..b8b519c 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart
@@ -408,6 +408,9 @@
     builder.addInsertion(_enclosingUnitMember!.end, (builder) {
       builder.writeln();
       builder.writeln();
+      var useSuperParameters = _featureSet.isEnabled(Feature.super_parameters);
+      var paramsToInitialize =
+          _parameters.where((p) => p.constructorName != p.name).toList();
       builder.writeClassDeclaration(
         name,
         superclass: classStatelessWidget!.instantiate(
@@ -425,15 +428,19 @@
 
               // Add the required `key` parameter.
               builder.write('    ');
-              builder.writeParameter(
-                'key',
-                type: classKey!.instantiate(
-                  typeArguments: const [],
-                  nullabilitySuffix: _isNonNullable
-                      ? NullabilitySuffix.question
-                      : NullabilitySuffix.star,
-                ),
-              );
+              if (useSuperParameters) {
+                builder.write('super.key');
+              } else {
+                builder.writeParameter(
+                  'key',
+                  type: classKey!.instantiate(
+                    typeArguments: const [],
+                    nullabilitySuffix: _isNonNullable
+                        ? NullabilitySuffix.question
+                        : NullabilitySuffix.star,
+                  ),
+                );
+              }
               builder.writeln(',');
 
               // Add parameters for fields, local, and method parameters.
@@ -459,17 +466,25 @@
 
               builder.write('  }');
             },
-            initializerWriter: () {
-              for (var parameter in _parameters) {
-                if (parameter.constructorName != parameter.name) {
-                  builder.write(parameter.name);
-                  builder.write(' = ');
-                  builder.write(parameter.constructorName);
-                  builder.write(', ');
-                }
-              }
-              builder.write('super(key: key)');
-            },
+            initializerWriter: useSuperParameters && paramsToInitialize.isEmpty
+                ? null
+                : () {
+                    for (var i = 0; i < paramsToInitialize.length; ++i) {
+                      var parameter = paramsToInitialize[i];
+                      if (i > 0) {
+                        builder.write(', ');
+                      }
+                      builder.write(parameter.name);
+                      builder.write(' = ');
+                      builder.write(parameter.constructorName);
+                    }
+                    if (!useSuperParameters) {
+                      if (paramsToInitialize.isNotEmpty) {
+                        builder.write(', ');
+                      }
+                      builder.write('super(key: key)');
+                    }
+                  },
           );
           builder.writeln();
           builder.writeln();
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/class_declaration.dart b/pkg/analysis_server/lib/src/services/snippets/dart/class_declaration.dart
new file mode 100644
index 0000000..aa126db
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/dart/class_declaration.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2022, 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/snippets/snippet.dart';
+import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+
+/// Produces a [Snippet] that creates a class definition.
+class ClassDeclaration extends DartSnippetProducer {
+  static const prefix = 'class';
+  static const label = 'class';
+
+  ClassDeclaration(super.request);
+
+  @override
+  Future<Snippet> compute() async {
+    final builder = ChangeBuilder(session: request.analysisSession);
+    final indent = utils.getLinePrefix(request.offset);
+
+    await builder.addDartFileEdit(request.filePath, (builder) {
+      builder.addReplacement(request.replacementRange, (builder) {
+        void writeIndented(String string) => builder.write('$indent$string');
+        builder.write('class ');
+        builder.addSimpleLinkedEdit('className', 'ClassName');
+        builder.writeln(' {');
+        writeIndented('  ');
+        builder.selectHere();
+        builder.writeln();
+        writeIndented('}');
+      });
+    });
+
+    return Snippet(
+      prefix,
+      label,
+      'Insert a class definition.',
+      builder.sourceChange,
+    );
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/dart_snippet_producers.dart b/pkg/analysis_server/lib/src/services/snippets/dart/dart_snippet_producers.dart
deleted file mode 100644
index b943eda..0000000
--- a/pkg/analysis_server/lib/src/services/snippets/dart/dart_snippet_producers.dart
+++ /dev/null
@@ -1,588 +0,0 @@
-// Copyright (c) 2022, 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/util.dart';
-import 'package:analysis_server/src/services/linter/lint_names.dart';
-import 'package:analysis_server/src/services/snippets/dart/snippet_manager.dart';
-import 'package:analyzer/dart/analysis/features.dart';
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/dart/element/nullability_suffix.dart';
-import 'package:analyzer/src/dart/analysis/session_helper.dart';
-import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/lint/linter.dart' show LinterContextImpl;
-import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
-
-/// Produces a [Snippet] that creates a Class definition.
-class DartClassSnippetProducer extends DartSnippetProducer {
-  static const prefix = 'class';
-  static const label = 'class';
-
-  DartClassSnippetProducer._(super.request);
-
-  @override
-  Future<Snippet> compute() async {
-    final builder = ChangeBuilder(session: request.analysisSession);
-    final indent = utils.getLinePrefix(request.offset);
-
-    await builder.addDartFileEdit(request.filePath, (builder) {
-      builder.addReplacement(request.replacementRange, (builder) {
-        void writeIndented(String string) => builder.write('$indent$string');
-        builder.write('class ');
-        builder.addSimpleLinkedEdit('className', 'ClassName');
-        builder.writeln(' {');
-        writeIndented('  ');
-        builder.selectHere();
-        builder.writeln();
-        writeIndented('}');
-      });
-    });
-
-    return Snippet(
-      prefix,
-      label,
-      'Insert a class definition.',
-      builder.sourceChange,
-    );
-  }
-
-  static DartClassSnippetProducer newInstance(DartSnippetRequest request) =>
-      DartClassSnippetProducer._(request);
-}
-
-/// Produces a [Snippet] that creates a `do while` loop.
-class DartDoWhileLoopSnippetProducer extends DartSnippetProducer {
-  static const prefix = 'do';
-  static const label = 'do while';
-
-  DartDoWhileLoopSnippetProducer._(super.request);
-
-  @override
-  Future<Snippet> compute() async {
-    final builder = ChangeBuilder(session: request.analysisSession);
-    final indent = utils.getLinePrefix(request.offset);
-
-    await builder.addDartFileEdit(request.filePath, (builder) {
-      builder.addReplacement(request.replacementRange, (builder) {
-        void writeIndented(String string) => builder.write('$indent$string');
-        builder.writeln('do {');
-        writeIndented('  ');
-        builder.selectHere();
-        builder.writeln();
-        writeIndented('} while (');
-        builder.addSimpleLinkedEdit('condition', 'condition');
-        builder.write(');');
-      });
-    });
-
-    return Snippet(
-      prefix,
-      label,
-      'Insert a do-while loop.',
-      builder.sourceChange,
-    );
-  }
-
-  static DartDoWhileLoopSnippetProducer newInstance(
-          DartSnippetRequest request) =>
-      DartDoWhileLoopSnippetProducer._(request);
-}
-
-/// Produces a [Snippet] that creates a `for in` loop.
-class DartForInLoopSnippetProducer extends DartSnippetProducer {
-  static const prefix = 'forin';
-  static const label = 'for in';
-
-  DartForInLoopSnippetProducer._(super.request);
-
-  @override
-  Future<Snippet> compute() async {
-    final builder = ChangeBuilder(session: request.analysisSession);
-    final indent = utils.getLinePrefix(request.offset);
-    final varOrFinal =
-        isLintEnabled(LintNames.prefer_final_locals) ? 'final' : 'var';
-
-    await builder.addDartFileEdit(request.filePath, (builder) {
-      builder.addReplacement(request.replacementRange, (builder) {
-        void writeIndented(String string) => builder.write('$indent$string');
-        builder.write('for ($varOrFinal ');
-        builder.addSimpleLinkedEdit('elementName', 'element');
-        builder.write(' in ');
-        builder.addSimpleLinkedEdit('collectionName', 'collection');
-        builder.writeln(') {');
-        writeIndented('  ');
-        builder.selectHere();
-        builder.writeln();
-        writeIndented('}');
-      });
-    });
-
-    return Snippet(
-      prefix,
-      label,
-      'Insert a for-in loop.',
-      builder.sourceChange,
-    );
-  }
-
-  static DartForInLoopSnippetProducer newInstance(DartSnippetRequest request) =>
-      DartForInLoopSnippetProducer._(request);
-}
-
-/// Produces a [Snippet] that creates a `for` loop.
-class DartForLoopSnippetProducer extends DartSnippetProducer {
-  static const prefix = 'for';
-  static const label = 'for';
-
-  DartForLoopSnippetProducer._(super.request);
-
-  @override
-  Future<Snippet> compute() async {
-    final builder = ChangeBuilder(session: request.analysisSession);
-    final indent = utils.getLinePrefix(request.offset);
-
-    await builder.addDartFileEdit(request.filePath, (builder) {
-      builder.addReplacement(request.replacementRange, (builder) {
-        void writeIndented(String string) => builder.write('$indent$string');
-        builder.write('for (var i = 0; i < ');
-        builder.addSimpleLinkedEdit('count', 'count');
-        builder.writeln('; i++) {');
-        writeIndented('  ');
-        builder.selectHere();
-        builder.writeln();
-        writeIndented('}');
-      });
-    });
-
-    return Snippet(
-      prefix,
-      label,
-      'Insert a for loop.',
-      builder.sourceChange,
-    );
-  }
-
-  static DartForLoopSnippetProducer newInstance(DartSnippetRequest request) =>
-      DartForLoopSnippetProducer._(request);
-}
-
-/// Produces a [Snippet] that creates a function definition.
-class DartFunctionSnippetProducer extends DartSnippetProducer {
-  static const prefix = 'fun';
-  static const label = 'fun';
-
-  DartFunctionSnippetProducer._(super.request);
-
-  @override
-  Future<Snippet> compute() async {
-    final builder = ChangeBuilder(session: request.analysisSession);
-    final indent = utils.getLinePrefix(request.offset);
-
-    await builder.addDartFileEdit(request.filePath, (builder) {
-      builder.addReplacement(request.replacementRange, (builder) {
-        void writeIndented(String string) => builder.write('$indent$string');
-
-        builder.addSimpleLinkedEdit('returnType', 'void');
-        builder.write(' ');
-        builder.addSimpleLinkedEdit('name', 'name');
-        builder.write('(');
-        builder.addSimpleLinkedEdit('params', 'params');
-        builder.writeln(') {');
-        writeIndented('  ');
-        builder.selectHere();
-        builder.writeln();
-        writeIndented('}');
-      });
-    });
-
-    return Snippet(
-      prefix,
-      label,
-      'Insert a function definition.',
-      builder.sourceChange,
-    );
-  }
-
-  static DartFunctionSnippetProducer newInstance(DartSnippetRequest request) =>
-      DartFunctionSnippetProducer._(request);
-}
-
-/// Produces a [Snippet] that creates an if/else statement.
-class DartIfElseSnippetProducer extends DartSnippetProducer {
-  static const prefix = 'ife';
-  static const label = 'ife';
-
-  DartIfElseSnippetProducer._(super.request);
-
-  @override
-  Future<Snippet> compute() async {
-    final builder = ChangeBuilder(session: request.analysisSession);
-    final indent = utils.getLinePrefix(request.offset);
-
-    await builder.addDartFileEdit(request.filePath, (builder) {
-      builder.addReplacement(request.replacementRange, (builder) {
-        void writeIndented(String string) => builder.write('$indent$string');
-        void writeIndentedln(String string) =>
-            builder.writeln('$indent$string');
-        builder.write('if (');
-        builder.addSimpleLinkedEdit('condition', 'condition');
-        builder.writeln(') {');
-        writeIndented('  ');
-        builder.selectHere();
-        builder.writeln();
-        writeIndentedln('} else {');
-        writeIndentedln('  ');
-        writeIndented('}');
-      });
-    });
-
-    return Snippet(
-      prefix,
-      label,
-      'Insert an if/else statement.',
-      builder.sourceChange,
-    );
-  }
-
-  static DartIfElseSnippetProducer newInstance(DartSnippetRequest request) =>
-      DartIfElseSnippetProducer._(request);
-}
-
-/// Produces a [Snippet] that creates an if statement.
-class DartIfSnippetProducer extends DartSnippetProducer {
-  static const prefix = 'if';
-  static const label = 'if';
-
-  DartIfSnippetProducer._(super.request);
-
-  @override
-  Future<Snippet> compute() async {
-    final builder = ChangeBuilder(session: request.analysisSession);
-    final indent = utils.getLinePrefix(request.offset);
-
-    await builder.addDartFileEdit(request.filePath, (builder) {
-      builder.addReplacement(request.replacementRange, (builder) {
-        void writeIndented(String string) => builder.write('$indent$string');
-        builder.write('if (');
-        builder.addSimpleLinkedEdit('condition', 'condition');
-        builder.writeln(') {');
-        writeIndented('  ');
-        builder.selectHere();
-        builder.writeln();
-        writeIndented('}');
-      });
-    });
-
-    return Snippet(
-      prefix,
-      label,
-      'Insert an if statement.',
-      builder.sourceChange,
-    );
-  }
-
-  static DartIfSnippetProducer newInstance(DartSnippetRequest request) =>
-      DartIfSnippetProducer._(request);
-}
-
-/// Produces a [Snippet] that creates a top-level `main` function.
-///
-/// A `List<String> args` parameter will be included when generating inside a
-/// file in `bin` or `tool` folders.
-class DartMainFunctionSnippetProducer extends DartSnippetProducer {
-  static const prefix = 'main';
-  static const label = 'main()';
-
-  DartMainFunctionSnippetProducer._(super.request);
-
-  /// Whether to insert a `List<String> args` parameter in the generated
-  /// function.
-  ///
-  /// The parameter is suppressed for any known test directories.
-  bool get _insertArgsParameter => !isInTestDirectory;
-
-  @override
-  Future<Snippet> compute() async {
-    final builder = ChangeBuilder(session: request.analysisSession);
-
-    final typeProvider = request.unit.typeProvider;
-    final listString = typeProvider.listType(typeProvider.stringType);
-
-    await builder.addDartFileEdit(request.filePath, (builder) {
-      builder.addReplacement(request.replacementRange, (builder) {
-        builder.writeFunctionDeclaration(
-          'main',
-          returnType: VoidTypeImpl.instance,
-          parameterWriter: _insertArgsParameter
-              ? () => builder.writeParameter('args', type: listString)
-              : null,
-          bodyWriter: () {
-            builder.writeln('{');
-            builder.write('  ');
-            builder.selectHere();
-            builder.writeln();
-            builder.write('}');
-          },
-        );
-      });
-    });
-
-    return Snippet(
-      prefix,
-      label,
-      'Insert a main function, used as an entry point.',
-      builder.sourceChange,
-    );
-  }
-
-  static DartMainFunctionSnippetProducer newInstance(
-          DartSnippetRequest request) =>
-      DartMainFunctionSnippetProducer._(request);
-}
-
-abstract class DartSnippetProducer extends SnippetProducer {
-  final AnalysisSessionHelper sessionHelper;
-  final CorrectionUtils utils;
-  final LibraryElement libraryElement;
-  final bool useSuperParams;
-
-  DartSnippetProducer(super.request)
-      : sessionHelper = AnalysisSessionHelper(request.analysisSession),
-        utils = CorrectionUtils(request.unit),
-        libraryElement = request.unit.libraryElement,
-        useSuperParams = request.unit.libraryElement.featureSet
-            .isEnabled(Feature.super_parameters);
-
-  bool get isInTestDirectory {
-    final path = request.unit.path;
-    return LinterContextImpl.testDirectories
-        .any((testDir) => path.contains(testDir));
-  }
-
-  /// The nullable suffix to use in this library.
-  NullabilitySuffix get nullableSuffix => libraryElement.isNonNullableByDefault
-      ? NullabilitySuffix.question
-      : NullabilitySuffix.none;
-
-  bool isLintEnabled(String name) {
-    var analysisOptions = sessionHelper.session.analysisContext.analysisOptions;
-    return analysisOptions.isLintEnabled(name);
-  }
-}
-
-/// Produces a [Snippet] that creates an if statement.
-class DartSwitchSnippetProducer extends DartSnippetProducer {
-  static const prefix = 'switch';
-  static const label = 'switch case';
-
-  DartSwitchSnippetProducer._(super.request);
-
-  @override
-  Future<Snippet> compute() async {
-    final builder = ChangeBuilder(session: request.analysisSession);
-    final indent = utils.getLinePrefix(request.offset);
-
-    await builder.addDartFileEdit(request.filePath, (builder) {
-      builder.addReplacement(request.replacementRange, (builder) {
-        void writeIndented(String string) => builder.write('$indent$string');
-        void writeIndentedln(String string) =>
-            builder.writeln('$indent$string');
-        builder.write('switch (');
-        builder.addSimpleLinkedEdit('expression', 'expression');
-        builder.writeln(') {');
-        writeIndented('  case ');
-        builder.addSimpleLinkedEdit('value', 'value');
-        builder.writeln(':');
-        writeIndented('    ');
-        builder.selectHere();
-        builder.writeln();
-        writeIndentedln('    break;');
-        writeIndentedln('  default:');
-        writeIndented('}');
-      });
-    });
-
-    return Snippet(
-      prefix,
-      label,
-      'Insert a switch statement.',
-      builder.sourceChange,
-    );
-  }
-
-  static DartSwitchSnippetProducer newInstance(DartSnippetRequest request) =>
-      DartSwitchSnippetProducer._(request);
-}
-
-/// Produces a [Snippet] that creates a `test()` block.
-class DartTestBlockSnippetProducer extends DartSnippetProducer {
-  static const prefix = 'test';
-  static const label = 'test';
-
-  DartTestBlockSnippetProducer._(super.request);
-
-  @override
-  Future<Snippet> compute() async {
-    final builder = ChangeBuilder(session: request.analysisSession);
-    final indent = utils.getLinePrefix(request.offset);
-
-    await builder.addDartFileEdit(request.filePath, (builder) {
-      builder.addReplacement(request.replacementRange, (builder) {
-        void writeIndented(String string) => builder.write('$indent$string');
-        builder.write("test('");
-        builder.addSimpleLinkedEdit('testName', 'test name');
-        builder.writeln("', () {");
-        writeIndented('  ');
-        builder.selectHere();
-        builder.writeln();
-        writeIndented('});');
-      });
-    });
-
-    return Snippet(
-      prefix,
-      label,
-      'Insert a test block.',
-      builder.sourceChange,
-    );
-  }
-
-  @override
-  Future<bool> isValid() async {
-    if (!await super.isValid()) {
-      return false;
-    }
-
-    return isInTestDirectory;
-  }
-
-  static DartTestBlockSnippetProducer newInstance(DartSnippetRequest request) =>
-      DartTestBlockSnippetProducer._(request);
-}
-
-/// Produces a [Snippet] that creates a `test()` block.
-class DartTestGroupBlockSnippetProducer extends DartSnippetProducer {
-  static const prefix = 'group';
-  static const label = 'group';
-
-  DartTestGroupBlockSnippetProducer._(super.request);
-
-  @override
-  Future<Snippet> compute() async {
-    final builder = ChangeBuilder(session: request.analysisSession);
-    final indent = utils.getLinePrefix(request.offset);
-
-    await builder.addDartFileEdit(request.filePath, (builder) {
-      builder.addReplacement(request.replacementRange, (builder) {
-        void writeIndented(String string) => builder.write('$indent$string');
-        builder.write("group('");
-        builder.addSimpleLinkedEdit('groupName', 'group name');
-        builder.writeln("', () {");
-        writeIndented('  ');
-        builder.selectHere();
-        builder.writeln();
-        writeIndented('});');
-      });
-    });
-
-    return Snippet(
-      prefix,
-      label,
-      'Insert a test group block.',
-      builder.sourceChange,
-    );
-  }
-
-  @override
-  Future<bool> isValid() async {
-    if (!await super.isValid()) {
-      return false;
-    }
-
-    return isInTestDirectory;
-  }
-
-  static DartTestGroupBlockSnippetProducer newInstance(
-          DartSnippetRequest request) =>
-      DartTestGroupBlockSnippetProducer._(request);
-}
-
-/// Produces a [Snippet] that creates a try/catch statement.
-class DartTryCatchSnippetProducer extends DartSnippetProducer {
-  static const prefix = 'try';
-  static const label = 'try';
-
-  DartTryCatchSnippetProducer._(super.request);
-
-  @override
-  Future<Snippet> compute() async {
-    final builder = ChangeBuilder(session: request.analysisSession);
-    final indent = utils.getLinePrefix(request.offset);
-
-    await builder.addDartFileEdit(request.filePath, (builder) {
-      builder.addReplacement(request.replacementRange, (builder) {
-        void writeIndented(String string) => builder.write('$indent$string');
-        void writeIndentedln(String string) =>
-            builder.writeln('$indent$string');
-        builder.writeln('try {');
-        writeIndented('  ');
-        builder.selectHere();
-        builder.writeln();
-        writeIndented('} catch (');
-        builder.addLinkedEdit('exceptionName', (builder) {
-          builder.write('e');
-        });
-        builder.writeln(') {');
-        writeIndentedln('  ');
-        writeIndented('}');
-      });
-    });
-
-    return Snippet(
-      prefix,
-      label,
-      'Insert a try/catch statement.',
-      builder.sourceChange,
-    );
-  }
-
-  static DartTryCatchSnippetProducer newInstance(DartSnippetRequest request) =>
-      DartTryCatchSnippetProducer._(request);
-}
-
-/// Produces a [Snippet] that creates a `while` loop.
-class DartWhileLoopSnippetProducer extends DartSnippetProducer {
-  static const prefix = 'while';
-  static const label = 'while';
-
-  DartWhileLoopSnippetProducer._(super.request);
-
-  @override
-  Future<Snippet> compute() async {
-    final builder = ChangeBuilder(session: request.analysisSession);
-    final indent = utils.getLinePrefix(request.offset);
-
-    await builder.addDartFileEdit(request.filePath, (builder) {
-      builder.addReplacement(request.replacementRange, (builder) {
-        void writeIndented(String string) => builder.write('$indent$string');
-        builder.write('while (');
-        builder.addSimpleLinkedEdit('condition', 'condition');
-        builder.writeln(') {');
-        writeIndented('  ');
-        builder.selectHere();
-        builder.writeln();
-        writeIndented('}');
-      });
-    });
-
-    return Snippet(
-      prefix,
-      label,
-      'Insert a while loop.',
-      builder.sourceChange,
-    );
-  }
-
-  static DartWhileLoopSnippetProducer newInstance(DartSnippetRequest request) =>
-      DartWhileLoopSnippetProducer._(request);
-}
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/do_statement.dart b/pkg/analysis_server/lib/src/services/snippets/dart/do_statement.dart
new file mode 100644
index 0000000..4a58903
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/dart/do_statement.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2022, 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/snippets/snippet.dart';
+import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+
+/// Produces a [Snippet] that creates a `do while` loop.
+class DoStatement extends DartSnippetProducer {
+  static const prefix = 'do';
+  static const label = 'do while';
+
+  DoStatement(super.request);
+
+  @override
+  Future<Snippet> compute() async {
+    final builder = ChangeBuilder(session: request.analysisSession);
+    final indent = utils.getLinePrefix(request.offset);
+
+    await builder.addDartFileEdit(request.filePath, (builder) {
+      builder.addReplacement(request.replacementRange, (builder) {
+        void writeIndented(String string) => builder.write('$indent$string');
+        builder.writeln('do {');
+        writeIndented('  ');
+        builder.selectHere();
+        builder.writeln();
+        writeIndented('} while (');
+        builder.addSimpleLinkedEdit('condition', 'condition');
+        builder.write(');');
+      });
+    });
+
+    return Snippet(
+      prefix,
+      label,
+      'Insert a do-while loop.',
+      builder.sourceChange,
+    );
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/flutter_snippet_producers.dart b/pkg/analysis_server/lib/src/services/snippets/dart/flutter_snippet_producers.dart
deleted file mode 100644
index 9644c99..0000000
--- a/pkg/analysis_server/lib/src/services/snippets/dart/flutter_snippet_producers.dart
+++ /dev/null
@@ -1,416 +0,0 @@
-// Copyright (c) 2022, 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/snippets/dart/dart_snippet_producers.dart';
-import 'package:analysis_server/src/services/snippets/dart/snippet_manager.dart';
-import 'package:analysis_server/src/utilities/flutter.dart';
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/dart/element/nullability_suffix.dart';
-import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/dart/element/type.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:meta/meta.dart';
-
-abstract class FlutterSnippetProducer extends DartSnippetProducer {
-  final flutter = Flutter.instance;
-
-  late ClassElement? classWidget;
-  late ClassElement? classContainer;
-
-  FlutterSnippetProducer(super.request);
-
-  @override
-  @mustCallSuper
-  Future<bool> isValid() async {
-    if ((classWidget = await _getClass('Widget')) == null) {
-      return false;
-    }
-
-    if ((classContainer = await _getClass('Container')) == null) {
-      return false;
-    }
-
-    return super.isValid();
-  }
-
-  Future<ClassElement?> _getClass(String name) =>
-      sessionHelper.getClass(flutter.widgetsUri, name);
-
-  DartType _getType(
-    ClassElement classElement, [
-    NullabilitySuffix nullabilitySuffix = NullabilitySuffix.none,
-  ]) =>
-      classElement.instantiate(
-        typeArguments: const [],
-        nullabilitySuffix: nullabilitySuffix,
-      );
-}
-
-/// Produces a [Snippet] that creates a Flutter StatefulWidget and related State
-/// class.
-class FlutterStatefulWidgetSnippetProducer extends FlutterSnippetProducer
-    with FlutterWidgetSnippetProducerMixin {
-  static const prefix = 'stful';
-  static const label = 'Flutter Stateful Widget';
-
-  late ClassElement? classStatefulWidget;
-  late ClassElement? classState;
-  @override
-  late ClassElement? classBuildContext;
-  @override
-  late ClassElement? classKey;
-
-  FlutterStatefulWidgetSnippetProducer._(super.request);
-
-  @override
-  Future<Snippet> compute() async {
-    final builder = ChangeBuilder(session: request.analysisSession);
-
-    // Checked by isValid().
-    final classStatefulWidget = this.classStatefulWidget!;
-    final classState = this.classState!;
-
-    await builder.addDartFileEdit(request.filePath, (builder) {
-      builder.addReplacement(request.replacementRange, (builder) {
-        // Write the StatefulWidget class
-        builder.writeClassDeclaration(
-          widgetClassName,
-          nameGroupName: 'name',
-          superclass: _getType(classStatefulWidget),
-          membersWriter: () {
-            writeWidgetConstructor(builder);
-            builder.writeln();
-            builder.writeln();
-
-            writeCreateStateMethod(builder);
-          },
-        );
-        builder.writeln();
-        builder.writeln();
-
-        // Write the State class.
-        builder.write('class _');
-        builder.addSimpleLinkedEdit('name', widgetClassName);
-        builder.write('State extends ');
-        builder.writeReference(classState);
-        builder.write('<');
-        builder.addSimpleLinkedEdit('name', widgetClassName);
-        builder.writeln('> {');
-        {
-          writeBuildMethod(builder);
-        }
-        builder.write('}');
-      });
-    });
-
-    return Snippet(
-      prefix,
-      label,
-      'Insert a Flutter StatefulWidget.',
-      builder.sourceChange,
-    );
-  }
-
-  @override
-  Future<bool> isValid() async {
-    if (!await super.isValid()) {
-      return false;
-    }
-
-    if ((classStatefulWidget = await _getClass('StatefulWidget')) == null ||
-        (classState = await _getClass('State')) == null ||
-        (classBuildContext = await _getClass('BuildContext')) == null ||
-        (classKey = await _getClass('Key')) == null) {
-      return false;
-    }
-
-    return true;
-  }
-
-  static FlutterStatefulWidgetSnippetProducer newInstance(
-          DartSnippetRequest request) =>
-      FlutterStatefulWidgetSnippetProducer._(request);
-}
-
-/// Produces a [Snippet] that creates a Flutter StatefulWidget with a
-/// AnimationController and related State class.
-class FlutterStatefulWidgetWithAnimationControllerSnippetProducer
-    extends FlutterSnippetProducer with FlutterWidgetSnippetProducerMixin {
-  static const prefix = 'stanim';
-  static const label = 'Flutter Widget with AnimationController';
-
-  late ClassElement? classStatefulWidget;
-  late ClassElement? classState;
-  @override
-  late ClassElement? classBuildContext;
-  @override
-  late ClassElement? classKey;
-  late ClassElement? classAnimationController;
-  late ClassElement? classSingleTickerProviderStateMixin;
-
-  FlutterStatefulWidgetWithAnimationControllerSnippetProducer._(super.request);
-
-  @override
-  Future<Snippet> compute() async {
-    final builder = ChangeBuilder(session: request.analysisSession);
-
-    // Checked by isValid().
-    final classStatefulWidget = this.classStatefulWidget!;
-    final classState = this.classState!;
-    final classAnimationController = this.classAnimationController!;
-    final classSingleTickerProviderStateMixin =
-        this.classSingleTickerProviderStateMixin!;
-
-    await builder.addDartFileEdit(request.filePath, (builder) {
-      builder.addReplacement(request.replacementRange, (builder) {
-        // Write the StatefulWidget class
-        builder.writeClassDeclaration(
-          widgetClassName,
-          nameGroupName: 'name',
-          superclass: _getType(classStatefulWidget),
-          membersWriter: () {
-            writeWidgetConstructor(builder);
-            builder.writeln();
-            builder.writeln();
-
-            writeCreateStateMethod(builder);
-          },
-        );
-        builder.writeln();
-        builder.writeln();
-
-        // Write the State class.
-        builder.write('class _');
-        builder.addSimpleLinkedEdit('name', widgetClassName);
-        builder.write('State extends ');
-        builder.writeReference(classState);
-        builder.write('<');
-        builder.addSimpleLinkedEdit('name', widgetClassName);
-        builder.writeln('>');
-        builder.write('    with ');
-        builder.writeReference(classSingleTickerProviderStateMixin);
-        builder.writeln(' {');
-        builder.write('  late ');
-        builder.writeReference(classAnimationController);
-        builder.writeln(' _controller;');
-        builder.writeln();
-        {
-          // Add the initState method.
-          builder.writeln('  @override');
-          builder.write('  ');
-          builder.writeFunctionDeclaration(
-            'initState',
-            returnType: VoidTypeImpl.instance,
-            bodyWriter: () {
-              builder.writeln('{');
-              builder.writeln('    super.initState();');
-              builder.write('    _controller = ');
-              builder.writeReference(classAnimationController);
-              builder.writeln('(vsync: this);');
-              builder.writeln('  }');
-            },
-          );
-        }
-        builder.writeln();
-        {
-          // Add the dispose method.
-          builder.writeln('  @override');
-          builder.write('  ');
-          builder.writeFunctionDeclaration(
-            'dispose',
-            returnType: VoidTypeImpl.instance,
-            bodyWriter: () {
-              builder.writeln('{');
-              builder.writeln('    _controller.dispose();');
-              builder.writeln('    super.dispose();');
-              builder.writeln('  }');
-            },
-          );
-        }
-        builder.writeln();
-        {
-          writeBuildMethod(builder);
-        }
-        builder.write('}');
-      });
-    });
-
-    return Snippet(
-      prefix,
-      label,
-      'Insert a Flutter StatefulWidget with an AnimationController.',
-      builder.sourceChange,
-    );
-  }
-
-  @override
-  Future<bool> isValid() async {
-    if (!await super.isValid()) {
-      return false;
-    }
-
-    if ((classStatefulWidget = await _getClass('StatefulWidget')) == null ||
-        (classState = await _getClass('State')) == null ||
-        (classBuildContext = await _getClass('BuildContext')) == null ||
-        (classKey = await _getClass('Key')) == null ||
-        (classAnimationController = await _getClass('AnimationController')) ==
-            null ||
-        (classSingleTickerProviderStateMixin =
-                await _getClass('SingleTickerProviderStateMixin')) ==
-            null) {
-      return false;
-    }
-
-    return true;
-  }
-
-  static FlutterStatefulWidgetWithAnimationControllerSnippetProducer
-      newInstance(DartSnippetRequest request) =>
-          FlutterStatefulWidgetWithAnimationControllerSnippetProducer._(
-              request);
-}
-
-/// Produces a [Snippet] that creates a Flutter StatelessWidget.
-class FlutterStatelessWidgetSnippetProducer extends FlutterSnippetProducer
-    with FlutterWidgetSnippetProducerMixin {
-  static const prefix = 'stless';
-  static const label = 'Flutter Stateless Widget';
-
-  late ClassElement? classStatelessWidget;
-  @override
-  late ClassElement? classBuildContext;
-  @override
-  late ClassElement? classKey;
-
-  FlutterStatelessWidgetSnippetProducer._(super.request);
-
-  @override
-  Future<Snippet> compute() async {
-    final builder = ChangeBuilder(session: request.analysisSession);
-
-    // Checked by isValid().
-    final classStatelessWidget = this.classStatelessWidget!;
-
-    await builder.addDartFileEdit(request.filePath, (builder) {
-      builder.addReplacement(request.replacementRange, (builder) {
-        builder.writeClassDeclaration(
-          widgetClassName,
-          nameGroupName: 'name',
-          superclass: _getType(classStatelessWidget),
-          membersWriter: () {
-            writeWidgetConstructor(builder);
-            builder.writeln();
-            builder.writeln();
-
-            writeBuildMethod(builder);
-          },
-        );
-      });
-    });
-
-    return Snippet(
-      prefix,
-      label,
-      'Insert a Flutter StatelessWidget.',
-      builder.sourceChange,
-    );
-  }
-
-  @override
-  Future<bool> isValid() async {
-    if (!await super.isValid()) {
-      return false;
-    }
-
-    if ((classStatelessWidget = await _getClass('StatelessWidget')) == null ||
-        (classBuildContext = await _getClass('BuildContext')) == null ||
-        (classKey = await _getClass('Key')) == null) {
-      return false;
-    }
-
-    return true;
-  }
-
-  static FlutterStatelessWidgetSnippetProducer newInstance(
-          DartSnippetRequest request) =>
-      FlutterStatelessWidgetSnippetProducer._(request);
-}
-
-/// A mixin that provides some common methods for producers that build snippets
-/// for Flutter widget classes.
-mixin FlutterWidgetSnippetProducerMixin on FlutterSnippetProducer {
-  ClassElement? get classBuildContext;
-  ClassElement? get classKey;
-  String get widgetClassName => 'MyWidget';
-
-  void writeBuildMethod(DartEditBuilder builder) {
-    // Checked by isValid() before this will be called.
-    final classBuildContext = this.classBuildContext!;
-    final classWidget = this.classWidget!;
-    final classContainer = this.classContainer!;
-
-    // Add the build method.
-    builder.writeln('  @override');
-    builder.write('  ');
-    builder.writeFunctionDeclaration(
-      'build',
-      returnType: _getType(classWidget),
-      parameterWriter: () {
-        builder.writeParameter(
-          'context',
-          type: _getType(classBuildContext),
-        );
-      },
-      bodyWriter: () {
-        builder.writeln('{');
-        builder.write('    return ');
-        builder.selectAll(() {
-          builder.writeType(_getType(classContainer));
-          builder.write('()');
-        });
-        builder.writeln(';');
-        builder.writeln('  }');
-      },
-    );
-  }
-
-  void writeCreateStateMethod(DartEditBuilder builder) {
-    builder.writeln('  @override');
-    builder.write('  State<');
-    builder.addSimpleLinkedEdit('name', widgetClassName);
-    builder.write('> createState() => _');
-    builder.addSimpleLinkedEdit('name', widgetClassName);
-    builder.writeln('State();');
-  }
-
-  void writeWidgetConstructor(DartEditBuilder builder) {
-    // Checked by isValid() before this will be called.
-    final classKey = this.classKey!;
-
-    String keyName;
-    DartType? keyType;
-    void Function()? keyInitializer;
-    if (useSuperParams) {
-      keyName = 'super.key';
-    } else {
-      keyName = 'key';
-      keyType = _getType(classKey, nullableSuffix);
-      keyInitializer = () => builder.write('super(key: key)');
-    }
-
-    builder.write('  ');
-    builder.writeConstructorDeclaration(
-      widgetClassName,
-      classNameGroupName: 'name',
-      isConst: true,
-      parameterWriter: () {
-        builder.write('{');
-        builder.writeParameter(keyName, type: keyType);
-        builder.write('}');
-      },
-      initializerWriter: keyInitializer,
-    );
-  }
-}
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateful_widget.dart b/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateful_widget.dart
new file mode 100644
index 0000000..7babe62
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateful_widget.dart
@@ -0,0 +1,90 @@
+// Copyright (c) 2022, 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/snippets/snippet.dart';
+import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+
+/// Produces a [Snippet] that creates a Flutter StatefulWidget and related State
+/// class.
+class FlutterStatefulWidget extends FlutterSnippetProducer
+    with FlutterWidgetSnippetProducerMixin {
+  static const prefix = 'stful';
+  static const label = 'Flutter Stateful Widget';
+
+  late ClassElement? classStatefulWidget;
+  late ClassElement? classState;
+  @override
+  late ClassElement? classBuildContext;
+  @override
+  late ClassElement? classKey;
+
+  FlutterStatefulWidget(super.request);
+
+  @override
+  Future<Snippet> compute() async {
+    final builder = ChangeBuilder(session: request.analysisSession);
+
+    // Checked by isValid().
+    final classStatefulWidget = this.classStatefulWidget!;
+    final classState = this.classState!;
+
+    await builder.addDartFileEdit(request.filePath, (builder) {
+      builder.addReplacement(request.replacementRange, (builder) {
+        // Write the StatefulWidget class
+        builder.writeClassDeclaration(
+          widgetClassName,
+          nameGroupName: 'name',
+          superclass: getType(classStatefulWidget),
+          membersWriter: () {
+            writeWidgetConstructor(builder);
+            builder.writeln();
+            builder.writeln();
+
+            writeCreateStateMethod(builder);
+          },
+        );
+        builder.writeln();
+        builder.writeln();
+
+        // Write the State class.
+        builder.write('class _');
+        builder.addSimpleLinkedEdit('name', widgetClassName);
+        builder.write('State extends ');
+        builder.writeReference(classState);
+        builder.write('<');
+        builder.addSimpleLinkedEdit('name', widgetClassName);
+        builder.writeln('> {');
+        {
+          writeBuildMethod(builder);
+        }
+        builder.write('}');
+      });
+    });
+
+    return Snippet(
+      prefix,
+      label,
+      'Insert a Flutter StatefulWidget.',
+      builder.sourceChange,
+    );
+  }
+
+  @override
+  Future<bool> isValid() async {
+    if (!await super.isValid()) {
+      return false;
+    }
+
+    if ((classStatefulWidget = await getClass('StatefulWidget')) == null ||
+        (classState = await getClass('State')) == null ||
+        (classBuildContext = await getClass('BuildContext')) == null ||
+        (classKey = await getClass('Key')) == null) {
+      return false;
+    }
+
+    return true;
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateful_widget_with_animation.dart b/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateful_widget_with_animation.dart
new file mode 100644
index 0000000..48f9208
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateful_widget_with_animation.dart
@@ -0,0 +1,142 @@
+// Copyright (c) 2022, 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/snippets/snippet.dart';
+import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+
+/// Produces a [Snippet] that creates a Flutter StatefulWidget with a
+/// AnimationController and related State class.
+class FlutterStatefulWidgetWithAnimationController
+    extends FlutterSnippetProducer with FlutterWidgetSnippetProducerMixin {
+  static const prefix = 'stanim';
+  static const label = 'Flutter Widget with AnimationController';
+
+  late ClassElement? classStatefulWidget;
+  late ClassElement? classState;
+  @override
+  late ClassElement? classBuildContext;
+  @override
+  late ClassElement? classKey;
+  late ClassElement? classAnimationController;
+  late ClassElement? classSingleTickerProviderStateMixin;
+
+  FlutterStatefulWidgetWithAnimationController(super.request);
+
+  @override
+  Future<Snippet> compute() async {
+    final builder = ChangeBuilder(session: request.analysisSession);
+
+    // Checked by isValid().
+    final classStatefulWidget = this.classStatefulWidget!;
+    final classState = this.classState!;
+    final classAnimationController = this.classAnimationController!;
+    final classSingleTickerProviderStateMixin =
+        this.classSingleTickerProviderStateMixin!;
+
+    await builder.addDartFileEdit(request.filePath, (builder) {
+      builder.addReplacement(request.replacementRange, (builder) {
+        // Write the StatefulWidget class
+        builder.writeClassDeclaration(
+          widgetClassName,
+          nameGroupName: 'name',
+          superclass: getType(classStatefulWidget),
+          membersWriter: () {
+            writeWidgetConstructor(builder);
+            builder.writeln();
+            builder.writeln();
+
+            writeCreateStateMethod(builder);
+          },
+        );
+        builder.writeln();
+        builder.writeln();
+
+        // Write the State class.
+        builder.write('class _');
+        builder.addSimpleLinkedEdit('name', widgetClassName);
+        builder.write('State extends ');
+        builder.writeReference(classState);
+        builder.write('<');
+        builder.addSimpleLinkedEdit('name', widgetClassName);
+        builder.writeln('>');
+        builder.write('    with ');
+        builder.writeReference(classSingleTickerProviderStateMixin);
+        builder.writeln(' {');
+        builder.write('  late ');
+        builder.writeReference(classAnimationController);
+        builder.writeln(' _controller;');
+        builder.writeln();
+        {
+          // Add the initState method.
+          builder.writeln('  @override');
+          builder.write('  ');
+          builder.writeFunctionDeclaration(
+            'initState',
+            returnType: VoidTypeImpl.instance,
+            bodyWriter: () {
+              builder.writeln('{');
+              builder.writeln('    super.initState();');
+              builder.write('    _controller = ');
+              builder.writeReference(classAnimationController);
+              builder.writeln('(vsync: this);');
+              builder.writeln('  }');
+            },
+          );
+        }
+        builder.writeln();
+        {
+          // Add the dispose method.
+          builder.writeln('  @override');
+          builder.write('  ');
+          builder.writeFunctionDeclaration(
+            'dispose',
+            returnType: VoidTypeImpl.instance,
+            bodyWriter: () {
+              builder.writeln('{');
+              builder.writeln('    _controller.dispose();');
+              builder.writeln('    super.dispose();');
+              builder.writeln('  }');
+            },
+          );
+        }
+        builder.writeln();
+        {
+          writeBuildMethod(builder);
+        }
+        builder.write('}');
+      });
+    });
+
+    return Snippet(
+      prefix,
+      label,
+      'Insert a Flutter StatefulWidget with an AnimationController.',
+      builder.sourceChange,
+    );
+  }
+
+  @override
+  Future<bool> isValid() async {
+    if (!await super.isValid()) {
+      return false;
+    }
+
+    if ((classStatefulWidget = await getClass('StatefulWidget')) == null ||
+        (classState = await getClass('State')) == null ||
+        (classBuildContext = await getClass('BuildContext')) == null ||
+        (classKey = await getClass('Key')) == null ||
+        (classAnimationController = await getClass('AnimationController')) ==
+            null ||
+        (classSingleTickerProviderStateMixin =
+                await getClass('SingleTickerProviderStateMixin')) ==
+            null) {
+      return false;
+    }
+
+    return true;
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateless_widget.dart b/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateless_widget.dart
new file mode 100644
index 0000000..e7711d3
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/dart/flutter_stateless_widget.dart
@@ -0,0 +1,70 @@
+// Copyright (c) 2022, 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/snippets/snippet.dart';
+import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+
+/// Produces a [Snippet] that creates a Flutter StatelessWidget.
+class FlutterStatelessWidget extends FlutterSnippetProducer
+    with FlutterWidgetSnippetProducerMixin {
+  static const prefix = 'stless';
+  static const label = 'Flutter Stateless Widget';
+
+  late ClassElement? classStatelessWidget;
+  @override
+  late ClassElement? classBuildContext;
+  @override
+  late ClassElement? classKey;
+
+  FlutterStatelessWidget(super.request);
+
+  @override
+  Future<Snippet> compute() async {
+    final builder = ChangeBuilder(session: request.analysisSession);
+
+    // Checked by isValid().
+    final classStatelessWidget = this.classStatelessWidget!;
+
+    await builder.addDartFileEdit(request.filePath, (builder) {
+      builder.addReplacement(request.replacementRange, (builder) {
+        builder.writeClassDeclaration(
+          widgetClassName,
+          nameGroupName: 'name',
+          superclass: getType(classStatelessWidget),
+          membersWriter: () {
+            writeWidgetConstructor(builder);
+            builder.writeln();
+            builder.writeln();
+
+            writeBuildMethod(builder);
+          },
+        );
+      });
+    });
+
+    return Snippet(
+      prefix,
+      label,
+      'Insert a Flutter StatelessWidget.',
+      builder.sourceChange,
+    );
+  }
+
+  @override
+  Future<bool> isValid() async {
+    if (!await super.isValid()) {
+      return false;
+    }
+
+    if ((classStatelessWidget = await getClass('StatelessWidget')) == null ||
+        (classBuildContext = await getClass('BuildContext')) == null ||
+        (classKey = await getClass('Key')) == null) {
+      return false;
+    }
+
+    return true;
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/for_in_statement.dart b/pkg/analysis_server/lib/src/services/snippets/dart/for_in_statement.dart
new file mode 100644
index 0000000..c9c481b
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/dart/for_in_statement.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2022, 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/linter/lint_names.dart';
+import 'package:analysis_server/src/services/snippets/snippet.dart';
+import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+
+/// Produces a [Snippet] that creates a `for in` loop.
+class ForInStatement extends DartSnippetProducer {
+  static const prefix = 'forin';
+  static const label = 'for in';
+
+  ForInStatement(super.request);
+
+  @override
+  Future<Snippet> compute() async {
+    final builder = ChangeBuilder(session: request.analysisSession);
+    final indent = utils.getLinePrefix(request.offset);
+    final varOrFinal =
+        isLintEnabled(LintNames.prefer_final_locals) ? 'final' : 'var';
+
+    await builder.addDartFileEdit(request.filePath, (builder) {
+      builder.addReplacement(request.replacementRange, (builder) {
+        void writeIndented(String string) => builder.write('$indent$string');
+        builder.write('for ($varOrFinal ');
+        builder.addSimpleLinkedEdit('elementName', 'element');
+        builder.write(' in ');
+        builder.addSimpleLinkedEdit('collectionName', 'collection');
+        builder.writeln(') {');
+        writeIndented('  ');
+        builder.selectHere();
+        builder.writeln();
+        writeIndented('}');
+      });
+    });
+
+    return Snippet(
+      prefix,
+      label,
+      'Insert a for-in loop.',
+      builder.sourceChange,
+    );
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/for_statement.dart b/pkg/analysis_server/lib/src/services/snippets/dart/for_statement.dart
new file mode 100644
index 0000000..557bb11
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/dart/for_statement.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2022, 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/snippets/snippet.dart';
+import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+
+/// Produces a [Snippet] that creates a `for` loop.
+class ForStatement extends DartSnippetProducer {
+  static const prefix = 'for';
+  static const label = 'for';
+
+  ForStatement(super.request);
+
+  @override
+  Future<Snippet> compute() async {
+    final builder = ChangeBuilder(session: request.analysisSession);
+    final indent = utils.getLinePrefix(request.offset);
+
+    await builder.addDartFileEdit(request.filePath, (builder) {
+      builder.addReplacement(request.replacementRange, (builder) {
+        void writeIndented(String string) => builder.write('$indent$string');
+        builder.write('for (var i = 0; i < ');
+        builder.addSimpleLinkedEdit('count', 'count');
+        builder.writeln('; i++) {');
+        writeIndented('  ');
+        builder.selectHere();
+        builder.writeln();
+        writeIndented('}');
+      });
+    });
+
+    return Snippet(
+      prefix,
+      label,
+      'Insert a for loop.',
+      builder.sourceChange,
+    );
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/function_declaration.dart b/pkg/analysis_server/lib/src/services/snippets/dart/function_declaration.dart
new file mode 100644
index 0000000..5471752
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/dart/function_declaration.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2022, 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/snippets/snippet.dart';
+import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+
+/// Produces a [Snippet] that creates a function definition.
+class FunctionDeclaration extends DartSnippetProducer {
+  static const prefix = 'fun';
+  static const label = 'fun';
+
+  FunctionDeclaration(super.request);
+
+  @override
+  Future<Snippet> compute() async {
+    final builder = ChangeBuilder(session: request.analysisSession);
+    final indent = utils.getLinePrefix(request.offset);
+
+    await builder.addDartFileEdit(request.filePath, (builder) {
+      builder.addReplacement(request.replacementRange, (builder) {
+        void writeIndented(String string) => builder.write('$indent$string');
+
+        builder.addSimpleLinkedEdit('returnType', 'void');
+        builder.write(' ');
+        builder.addSimpleLinkedEdit('name', 'name');
+        builder.write('(');
+        builder.addSimpleLinkedEdit('params', 'params');
+        builder.writeln(') {');
+        writeIndented('  ');
+        builder.selectHere();
+        builder.writeln();
+        writeIndented('}');
+      });
+    });
+
+    return Snippet(
+      prefix,
+      label,
+      'Insert a function definition.',
+      builder.sourceChange,
+    );
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/if_else_statement.dart b/pkg/analysis_server/lib/src/services/snippets/dart/if_else_statement.dart
new file mode 100644
index 0000000..78b1b88
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/dart/if_else_statement.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2022, 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/snippets/snippet.dart';
+import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+
+/// Produces a [Snippet] that creates an if/else statement.
+class IfElseStatement extends DartSnippetProducer {
+  static const prefix = 'ife';
+  static const label = 'ife';
+
+  IfElseStatement(super.request);
+
+  @override
+  Future<Snippet> compute() async {
+    final builder = ChangeBuilder(session: request.analysisSession);
+    final indent = utils.getLinePrefix(request.offset);
+
+    await builder.addDartFileEdit(request.filePath, (builder) {
+      builder.addReplacement(request.replacementRange, (builder) {
+        void writeIndented(String string) => builder.write('$indent$string');
+        void writeIndentedln(String string) =>
+            builder.writeln('$indent$string');
+        builder.write('if (');
+        builder.addSimpleLinkedEdit('condition', 'condition');
+        builder.writeln(') {');
+        writeIndented('  ');
+        builder.selectHere();
+        builder.writeln();
+        writeIndentedln('} else {');
+        writeIndentedln('  ');
+        writeIndented('}');
+      });
+    });
+
+    return Snippet(
+      prefix,
+      label,
+      'Insert an if/else statement.',
+      builder.sourceChange,
+    );
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/if_statement.dart b/pkg/analysis_server/lib/src/services/snippets/dart/if_statement.dart
new file mode 100644
index 0000000..3f667b1
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/dart/if_statement.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2022, 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/snippets/snippet.dart';
+import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+
+/// Produces a [Snippet] that creates an if statement.
+class IfStatement extends DartSnippetProducer {
+  static const prefix = 'if';
+  static const label = 'if';
+
+  IfStatement(super.request);
+
+  @override
+  Future<Snippet> compute() async {
+    final builder = ChangeBuilder(session: request.analysisSession);
+    final indent = utils.getLinePrefix(request.offset);
+
+    await builder.addDartFileEdit(request.filePath, (builder) {
+      builder.addReplacement(request.replacementRange, (builder) {
+        void writeIndented(String string) => builder.write('$indent$string');
+        builder.write('if (');
+        builder.addSimpleLinkedEdit('condition', 'condition');
+        builder.writeln(') {');
+        writeIndented('  ');
+        builder.selectHere();
+        builder.writeln();
+        writeIndented('}');
+      });
+    });
+
+    return Snippet(
+      prefix,
+      label,
+      'Insert an if statement.',
+      builder.sourceChange,
+    );
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/main_function.dart b/pkg/analysis_server/lib/src/services/snippets/dart/main_function.dart
new file mode 100644
index 0000000..69976c5
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/dart/main_function.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2022, 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/snippets/snippet.dart';
+import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+
+/// Produces a [Snippet] that creates a top-level `main` function.
+///
+/// A `List<String> args` parameter will be included when generating inside a
+/// file in `bin` or `tool` folders.
+class MainFunction extends DartSnippetProducer {
+  static const prefix = 'main';
+  static const label = 'main()';
+
+  MainFunction(super.request);
+
+  /// Whether to insert a `List<String> args` parameter in the generated
+  /// function.
+  ///
+  /// The parameter is suppressed for any known test directories.
+  bool get _insertArgsParameter => !isInTestDirectory;
+
+  @override
+  Future<Snippet> compute() async {
+    final builder = ChangeBuilder(session: request.analysisSession);
+
+    final typeProvider = request.unit.typeProvider;
+    final listString = typeProvider.listType(typeProvider.stringType);
+
+    await builder.addDartFileEdit(request.filePath, (builder) {
+      builder.addReplacement(request.replacementRange, (builder) {
+        builder.writeFunctionDeclaration(
+          'main',
+          returnType: VoidTypeImpl.instance,
+          parameterWriter: _insertArgsParameter
+              ? () => builder.writeParameter('args', type: listString)
+              : null,
+          bodyWriter: () {
+            builder.writeln('{');
+            builder.write('  ');
+            builder.selectHere();
+            builder.writeln();
+            builder.write('}');
+          },
+        );
+      });
+    });
+
+    return Snippet(
+      prefix,
+      label,
+      'Insert a main function, used as an entry point.',
+      builder.sourceChange,
+    );
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/snippet_manager.dart b/pkg/analysis_server/lib/src/services/snippets/dart/snippet_manager.dart
deleted file mode 100644
index 006870c..0000000
--- a/pkg/analysis_server/lib/src/services/snippets/dart/snippet_manager.dart
+++ /dev/null
@@ -1,213 +0,0 @@
-// Copyright (c) 2022, 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/protocol_server.dart';
-import 'package:analysis_server/src/provisional/completion/completion_core.dart';
-import 'package:analysis_server/src/services/snippets/dart/dart_snippet_producers.dart';
-import 'package:analysis_server/src/services/snippets/dart/flutter_snippet_producers.dart';
-import 'package:analyzer/dart/analysis/results.dart';
-import 'package:analyzer/dart/analysis/session.dart';
-import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/token.dart';
-import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/source/source_range.dart';
-import 'package:analyzer/src/util/file_paths.dart' as file_paths;
-import 'package:analyzer_plugin/src/utilities/completion/completion_target.dart';
-
-typedef SnippetProducerGenerator = SnippetProducer Function(DartSnippetRequest);
-
-/// [DartSnippetManager] determines if a snippet request is Dart specific
-/// and forwards those requests to all Snippet Producers that return `true` from
-/// their `isValid()` method.
-class DartSnippetManager {
-  final producerGenerators =
-      const <SnippetContext, List<SnippetProducerGenerator>>{
-    SnippetContext.atTopLevel: [
-      DartMainFunctionSnippetProducer.newInstance,
-      FlutterStatefulWidgetSnippetProducer.newInstance,
-      FlutterStatefulWidgetWithAnimationControllerSnippetProducer.newInstance,
-      FlutterStatelessWidgetSnippetProducer.newInstance,
-      DartClassSnippetProducer.newInstance,
-      DartFunctionSnippetProducer.newInstance,
-    ],
-    SnippetContext.inBlock: [
-      DartFunctionSnippetProducer.newInstance,
-      DartDoWhileLoopSnippetProducer.newInstance,
-      DartForInLoopSnippetProducer.newInstance,
-      DartForLoopSnippetProducer.newInstance,
-      DartIfElseSnippetProducer.newInstance,
-      DartIfSnippetProducer.newInstance,
-      DartSwitchSnippetProducer.newInstance,
-      DartTryCatchSnippetProducer.newInstance,
-      DartWhileLoopSnippetProducer.newInstance,
-      DartTestBlockSnippetProducer.newInstance,
-      DartTestGroupBlockSnippetProducer.newInstance,
-    ],
-    SnippetContext.inClass: [
-      DartFunctionSnippetProducer.newInstance,
-    ]
-  };
-
-  Future<List<Snippet>> computeSnippets(
-    DartSnippetRequest request,
-  ) async {
-    var pathContext = request.resourceProvider.pathContext;
-    if (!file_paths.isDart(pathContext, request.filePath)) {
-      return const [];
-    }
-
-    try {
-      final snippets = <Snippet>[];
-      final generators = producerGenerators[request.context];
-      if (generators == null) {
-        return snippets;
-      }
-      for (final generator in generators) {
-        final producer = generator(request);
-        if (await producer.isValid()) {
-          snippets.add(await producer.compute());
-        }
-      }
-      return snippets;
-    } on InconsistentAnalysisException {
-      // The state of the code being analyzed has changed, so results are likely
-      // to be inconsistent. Just abort the operation.
-      throw AbortCompletion();
-    }
-  }
-}
-
-/// The information about a request for a list of snippets within a Dart file.
-class DartSnippetRequest {
-  /// The resolved unit for the file that snippets are being requested for.
-  final ResolvedUnitResult unit;
-
-  /// The path of the file snippets are being requested for.
-  final String filePath;
-
-  /// The offset within the source at which snippets are being
-  /// requested for.
-  final int offset;
-
-  /// The context in which the snippet request is being made.
-  late final SnippetContext context;
-
-  /// The source range that represents the region of text that should be
-  /// replaced if the snippet is selected.
-  late final SourceRange replacementRange;
-
-  DartSnippetRequest({
-    required this.unit,
-    required this.offset,
-  }) : filePath = unit.path {
-    final target = CompletionTarget.forOffset(unit.unit, offset);
-    context = _getContext(target);
-    replacementRange = target.computeReplacementRange(offset);
-  }
-
-  /// The analysis session that produced the elements of the request.
-  AnalysisSession get analysisSession => unit.session;
-
-  /// The resource provider associated with this request.
-  ResourceProvider get resourceProvider => analysisSession.resourceProvider;
-
-  static SnippetContext _getContext(CompletionTarget target) {
-    final entity = target.entity;
-    if (entity is Token) {
-      final tokenType = (entity.beforeSynthetic ?? entity).type;
-
-      if (tokenType == TokenType.MULTI_LINE_COMMENT ||
-          tokenType == TokenType.SINGLE_LINE_COMMENT) {
-        return SnippetContext.inComment;
-      }
-
-      if (tokenType == TokenType.STRING ||
-          tokenType == TokenType.STRING_INTERPOLATION_EXPRESSION ||
-          tokenType == TokenType.STRING_INTERPOLATION_IDENTIFIER) {
-        return SnippetContext.inString;
-      }
-    }
-
-    AstNode? node = target.containingNode;
-    while (node != null) {
-      if (node is Comment) {
-        return SnippetContext.inComment;
-      }
-
-      if (node is StringLiteral) {
-        return SnippetContext.inString;
-      }
-
-      if (node is Block) {
-        return SnippetContext.inBlock;
-      }
-
-      if (node is Statement || node is Expression || node is Annotation) {
-        return SnippetContext.inExpressionOrStatement;
-      }
-
-      if (node is BlockFunctionBody) {
-        return SnippetContext.inBlock;
-      }
-
-      if (node is ClassOrMixinDeclaration || node is ExtensionDeclaration) {
-        return SnippetContext.inClass;
-      }
-
-      node = node.parent;
-    }
-
-    return SnippetContext.atTopLevel;
-  }
-}
-
-class Snippet {
-  /// The text the user will type to use this snippet.
-  final String prefix;
-
-  /// The label/title of this snippet.
-  final String label;
-
-  /// A description of/documentation for the snippet.
-  final String? documentation;
-
-  /// The source changes to be made to insert this snippet.
-  final SourceChange change;
-
-  Snippet(
-    this.prefix,
-    this.label,
-    this.documentation,
-    this.change,
-  );
-}
-
-/// The context in which a snippet request was made.
-///
-/// This is used to filter the available snippets (for example preventing
-/// snippets that create classes showing up when inside an existing class or
-/// function body).
-enum SnippetContext {
-  atTopLevel,
-  inClass,
-  inBlock,
-  inExpressionOrStatement,
-  inComment,
-  inString,
-}
-
-abstract class SnippetProducer {
-  final DartSnippetRequest request;
-
-  SnippetProducer(this.request);
-
-  Future<Snippet> compute();
-
-  Future<bool> isValid() async {
-    // File edit builders will not produce edits for files outside of the
-    // analysis roots so we should not try to produce any snippets.
-    final analysisContext = request.analysisSession.analysisContext;
-    return analysisContext.contextRoot.isAnalyzed(request.filePath);
-  }
-}
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/switch_statement.dart b/pkg/analysis_server/lib/src/services/snippets/dart/switch_statement.dart
new file mode 100644
index 0000000..5896568
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/dart/switch_statement.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2022, 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/snippets/snippet.dart';
+import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+
+/// Produces a [Snippet] that creates an if statement.
+class SwitchStatement extends DartSnippetProducer {
+  static const prefix = 'switch';
+  static const label = 'switch case';
+
+  SwitchStatement(super.request);
+
+  @override
+  Future<Snippet> compute() async {
+    final builder = ChangeBuilder(session: request.analysisSession);
+    final indent = utils.getLinePrefix(request.offset);
+
+    await builder.addDartFileEdit(request.filePath, (builder) {
+      builder.addReplacement(request.replacementRange, (builder) {
+        void writeIndented(String string) => builder.write('$indent$string');
+        void writeIndentedln(String string) =>
+            builder.writeln('$indent$string');
+        builder.write('switch (');
+        builder.addSimpleLinkedEdit('expression', 'expression');
+        builder.writeln(') {');
+        writeIndented('  case ');
+        builder.addSimpleLinkedEdit('value', 'value');
+        builder.writeln(':');
+        writeIndented('    ');
+        builder.selectHere();
+        builder.writeln();
+        writeIndentedln('    break;');
+        writeIndentedln('  default:');
+        writeIndented('}');
+      });
+    });
+
+    return Snippet(
+      prefix,
+      label,
+      'Insert a switch statement.',
+      builder.sourceChange,
+    );
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/test_definition.dart b/pkg/analysis_server/lib/src/services/snippets/dart/test_definition.dart
new file mode 100644
index 0000000..29a348d
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/dart/test_definition.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2022, 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/snippets/snippet.dart';
+import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+
+/// Produces a [Snippet] that creates a `test()` block.
+class TestDefinition extends DartSnippetProducer {
+  static const prefix = 'test';
+  static const label = 'test';
+
+  TestDefinition(super.request);
+
+  @override
+  Future<Snippet> compute() async {
+    final builder = ChangeBuilder(session: request.analysisSession);
+    final indent = utils.getLinePrefix(request.offset);
+
+    await builder.addDartFileEdit(request.filePath, (builder) {
+      builder.addReplacement(request.replacementRange, (builder) {
+        void writeIndented(String string) => builder.write('$indent$string');
+        builder.write("test('");
+        builder.addSimpleLinkedEdit('testName', 'test name');
+        builder.writeln("', () {");
+        writeIndented('  ');
+        builder.selectHere();
+        builder.writeln();
+        writeIndented('});');
+      });
+    });
+
+    return Snippet(
+      prefix,
+      label,
+      'Insert a test block.',
+      builder.sourceChange,
+    );
+  }
+
+  @override
+  Future<bool> isValid() async {
+    if (!await super.isValid()) {
+      return false;
+    }
+
+    return isInTestDirectory;
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/test_group_definition.dart b/pkg/analysis_server/lib/src/services/snippets/dart/test_group_definition.dart
new file mode 100644
index 0000000..5bb4616
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/dart/test_group_definition.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2022, 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/snippets/snippet.dart';
+import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+
+/// Produces a [Snippet] that creates a `test()` block.
+class TestGroupDefinition extends DartSnippetProducer {
+  static const prefix = 'group';
+  static const label = 'group';
+
+  TestGroupDefinition(super.request);
+
+  @override
+  Future<Snippet> compute() async {
+    final builder = ChangeBuilder(session: request.analysisSession);
+    final indent = utils.getLinePrefix(request.offset);
+
+    await builder.addDartFileEdit(request.filePath, (builder) {
+      builder.addReplacement(request.replacementRange, (builder) {
+        void writeIndented(String string) => builder.write('$indent$string');
+        builder.write("group('");
+        builder.addSimpleLinkedEdit('groupName', 'group name');
+        builder.writeln("', () {");
+        writeIndented('  ');
+        builder.selectHere();
+        builder.writeln();
+        writeIndented('});');
+      });
+    });
+
+    return Snippet(
+      prefix,
+      label,
+      'Insert a test group block.',
+      builder.sourceChange,
+    );
+  }
+
+  @override
+  Future<bool> isValid() async {
+    if (!await super.isValid()) {
+      return false;
+    }
+
+    return isInTestDirectory;
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/try_catch_statement.dart b/pkg/analysis_server/lib/src/services/snippets/dart/try_catch_statement.dart
new file mode 100644
index 0000000..5320ab3
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/dart/try_catch_statement.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2022, 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/snippets/snippet.dart';
+import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+
+/// Produces a [Snippet] that creates a try/catch statement.
+class TryCatchStatement extends DartSnippetProducer {
+  static const prefix = 'try';
+  static const label = 'try';
+
+  TryCatchStatement(super.request);
+
+  @override
+  Future<Snippet> compute() async {
+    final builder = ChangeBuilder(session: request.analysisSession);
+    final indent = utils.getLinePrefix(request.offset);
+
+    await builder.addDartFileEdit(request.filePath, (builder) {
+      builder.addReplacement(request.replacementRange, (builder) {
+        void writeIndented(String string) => builder.write('$indent$string');
+        void writeIndentedln(String string) =>
+            builder.writeln('$indent$string');
+        builder.writeln('try {');
+        writeIndented('  ');
+        builder.selectHere();
+        builder.writeln();
+        writeIndented('} catch (');
+        builder.addLinkedEdit('exceptionName', (builder) {
+          builder.write('e');
+        });
+        builder.writeln(') {');
+        writeIndentedln('  ');
+        writeIndented('}');
+      });
+    });
+
+    return Snippet(
+      prefix,
+      label,
+      'Insert a try/catch statement.',
+      builder.sourceChange,
+    );
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart/while_statement.dart b/pkg/analysis_server/lib/src/services/snippets/dart/while_statement.dart
new file mode 100644
index 0000000..48776ad
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/dart/while_statement.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2022, 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/snippets/snippet.dart';
+import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+
+/// Produces a [Snippet] that creates a `while` loop.
+class WhileStatement extends DartSnippetProducer {
+  static const prefix = 'while';
+  static const label = 'while';
+
+  WhileStatement(super.request);
+
+  @override
+  Future<Snippet> compute() async {
+    final builder = ChangeBuilder(session: request.analysisSession);
+    final indent = utils.getLinePrefix(request.offset);
+
+    await builder.addDartFileEdit(request.filePath, (builder) {
+      builder.addReplacement(request.replacementRange, (builder) {
+        void writeIndented(String string) => builder.write('$indent$string');
+        builder.write('while (');
+        builder.addSimpleLinkedEdit('condition', 'condition');
+        builder.writeln(') {');
+        writeIndented('  ');
+        builder.selectHere();
+        builder.writeln();
+        writeIndented('}');
+      });
+    });
+
+    return Snippet(
+      prefix,
+      label,
+      'Insert a while loop.',
+      builder.sourceChange,
+    );
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/snippets/dart_snippet_request.dart b/pkg/analysis_server/lib/src/services/snippets/dart_snippet_request.dart
new file mode 100644
index 0000000..93ab0a8
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/dart_snippet_request.dart
@@ -0,0 +1,96 @@
+// Copyright (c) 2022, 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/snippets/snippet_context.dart';
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/analysis/session.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/source/source_range.dart';
+import 'package:analyzer_plugin/src/utilities/completion/completion_target.dart';
+
+/// The information about a request for a list of snippets within a Dart file.
+class DartSnippetRequest {
+  /// The resolved unit for the file that snippets are being requested for.
+  final ResolvedUnitResult unit;
+
+  /// The path of the file snippets are being requested for.
+  final String filePath;
+
+  /// The offset within the source at which snippets are being
+  /// requested for.
+  final int offset;
+
+  /// The context in which the snippet request is being made.
+  late final SnippetContext context;
+
+  /// The source range that represents the region of text that should be
+  /// replaced if the snippet is selected.
+  late final SourceRange replacementRange;
+
+  DartSnippetRequest({
+    required this.unit,
+    required this.offset,
+  }) : filePath = unit.path {
+    final target = CompletionTarget.forOffset(unit.unit, offset);
+    context = _getContext(target);
+    replacementRange = target.computeReplacementRange(offset);
+  }
+
+  /// The analysis session that produced the elements of the request.
+  AnalysisSession get analysisSession => unit.session;
+
+  /// The resource provider associated with this request.
+  ResourceProvider get resourceProvider => analysisSession.resourceProvider;
+
+  static SnippetContext _getContext(CompletionTarget target) {
+    final entity = target.entity;
+    if (entity is Token) {
+      final tokenType = (entity.beforeSynthetic ?? entity).type;
+
+      if (tokenType == TokenType.MULTI_LINE_COMMENT ||
+          tokenType == TokenType.SINGLE_LINE_COMMENT) {
+        return SnippetContext.inComment;
+      }
+
+      if (tokenType == TokenType.STRING ||
+          tokenType == TokenType.STRING_INTERPOLATION_EXPRESSION ||
+          tokenType == TokenType.STRING_INTERPOLATION_IDENTIFIER) {
+        return SnippetContext.inString;
+      }
+    }
+
+    AstNode? node = target.containingNode;
+    while (node != null) {
+      if (node is Comment) {
+        return SnippetContext.inComment;
+      }
+
+      if (node is StringLiteral) {
+        return SnippetContext.inString;
+      }
+
+      if (node is Block) {
+        return SnippetContext.inBlock;
+      }
+
+      if (node is Statement || node is Expression || node is Annotation) {
+        return SnippetContext.inExpressionOrStatement;
+      }
+
+      if (node is BlockFunctionBody) {
+        return SnippetContext.inBlock;
+      }
+
+      if (node is ClassOrMixinDeclaration || node is ExtensionDeclaration) {
+        return SnippetContext.inClass;
+      }
+
+      node = node.parent;
+    }
+
+    return SnippetContext.atTopLevel;
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/snippets/snippet.dart b/pkg/analysis_server/lib/src/services/snippets/snippet.dart
new file mode 100644
index 0000000..a19bc96
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/snippet.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2022, 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/protocol_server.dart';
+
+class Snippet {
+  /// The text the user will type to use this snippet.
+  final String prefix;
+
+  /// The label/title of this snippet.
+  final String label;
+
+  /// A description of/documentation for the snippet.
+  final String? documentation;
+
+  /// The source changes to be made to insert this snippet.
+  final SourceChange change;
+
+  Snippet(
+    this.prefix,
+    this.label,
+    this.documentation,
+    this.change,
+  );
+}
diff --git a/pkg/analysis_server/lib/src/services/snippets/snippet_context.dart b/pkg/analysis_server/lib/src/services/snippets/snippet_context.dart
new file mode 100644
index 0000000..9b5d3af
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/snippet_context.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2022, 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.
+
+/// The context in which a snippet request was made.
+///
+/// This is used to filter the available snippets (for example preventing
+/// snippets that create classes showing up when inside an existing class or
+/// function body).
+enum SnippetContext {
+  atTopLevel,
+  inClass,
+  inBlock,
+  inExpressionOrStatement,
+  inComment,
+  inString,
+}
diff --git a/pkg/analysis_server/lib/src/services/snippets/snippet_manager.dart b/pkg/analysis_server/lib/src/services/snippets/snippet_manager.dart
new file mode 100644
index 0000000..26b94bf
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/snippet_manager.dart
@@ -0,0 +1,90 @@
+// Copyright (c) 2022, 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/provisional/completion/completion_core.dart';
+import 'package:analysis_server/src/services/snippets/dart/class_declaration.dart';
+import 'package:analysis_server/src/services/snippets/dart/do_statement.dart';
+import 'package:analysis_server/src/services/snippets/dart/flutter_stateful_widget.dart';
+import 'package:analysis_server/src/services/snippets/dart/flutter_stateful_widget_with_animation.dart';
+import 'package:analysis_server/src/services/snippets/dart/flutter_stateless_widget.dart';
+import 'package:analysis_server/src/services/snippets/dart/for_in_statement.dart';
+import 'package:analysis_server/src/services/snippets/dart/for_statement.dart';
+import 'package:analysis_server/src/services/snippets/dart/function_declaration.dart';
+import 'package:analysis_server/src/services/snippets/dart/if_else_statement.dart';
+import 'package:analysis_server/src/services/snippets/dart/if_statement.dart';
+import 'package:analysis_server/src/services/snippets/dart/main_function.dart';
+import 'package:analysis_server/src/services/snippets/dart/switch_statement.dart';
+import 'package:analysis_server/src/services/snippets/dart/test_definition.dart';
+import 'package:analysis_server/src/services/snippets/dart/test_group_definition.dart';
+import 'package:analysis_server/src/services/snippets/dart/try_catch_statement.dart';
+import 'package:analysis_server/src/services/snippets/dart/while_statement.dart';
+import 'package:analysis_server/src/services/snippets/dart_snippet_request.dart';
+import 'package:analysis_server/src/services/snippets/snippet.dart';
+import 'package:analysis_server/src/services/snippets/snippet_context.dart';
+import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
+import 'package:analyzer/dart/analysis/session.dart';
+import 'package:analyzer/src/util/file_paths.dart' as file_paths;
+
+typedef SnippetProducerGenerator = SnippetProducer Function(DartSnippetRequest);
+
+/// [DartSnippetManager] determines if a snippet request is Dart specific
+/// and forwards those requests to all Snippet Producers that return `true` from
+/// their `isValid()` method.
+class DartSnippetManager {
+  final producerGenerators =
+      const <SnippetContext, List<SnippetProducerGenerator>>{
+    SnippetContext.atTopLevel: [
+      ClassDeclaration.new,
+      FlutterStatefulWidget.new,
+      FlutterStatefulWidgetWithAnimationController.new,
+      FlutterStatelessWidget.new,
+      FunctionDeclaration.new,
+      MainFunction.new,
+    ],
+    SnippetContext.inBlock: [
+      DoStatement.new,
+      ForInStatement.new,
+      ForStatement.new,
+      FunctionDeclaration.new,
+      IfElseStatement.new,
+      IfStatement.new,
+      SwitchStatement.new,
+      TestDefinition.new,
+      TestGroupDefinition.new,
+      TryCatchStatement.new,
+      WhileStatement.new,
+    ],
+    SnippetContext.inClass: [
+      FunctionDeclaration.new,
+    ]
+  };
+
+  Future<List<Snippet>> computeSnippets(
+    DartSnippetRequest request,
+  ) async {
+    var pathContext = request.resourceProvider.pathContext;
+    if (!file_paths.isDart(pathContext, request.filePath)) {
+      return const [];
+    }
+
+    try {
+      final snippets = <Snippet>[];
+      final generators = producerGenerators[request.context];
+      if (generators == null) {
+        return snippets;
+      }
+      for (final generator in generators) {
+        final producer = generator(request);
+        if (await producer.isValid()) {
+          snippets.add(await producer.compute());
+        }
+      }
+      return snippets;
+    } on InconsistentAnalysisException {
+      // The state of the code being analyzed has changed, so results are likely
+      // to be inconsistent. Just abort the operation.
+      throw AbortCompletion();
+    }
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/snippets/snippet_producer.dart b/pkg/analysis_server/lib/src/services/snippets/snippet_producer.dart
new file mode 100644
index 0000000..52c1307
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/snippets/snippet_producer.dart
@@ -0,0 +1,173 @@
+// Copyright (c) 2022, 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/util.dart';
+import 'package:analysis_server/src/services/snippets/dart_snippet_request.dart';
+import 'package:analysis_server/src/services/snippets/snippet.dart';
+import 'package:analysis_server/src/utilities/flutter.dart';
+import 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/nullability_suffix.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/analysis/session_helper.dart';
+import 'package:analyzer/src/lint/linter.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
+import 'package:meta/meta.dart';
+
+abstract class DartSnippetProducer extends SnippetProducer {
+  final AnalysisSessionHelper sessionHelper;
+  final CorrectionUtils utils;
+  final LibraryElement libraryElement;
+  final bool useSuperParams;
+
+  DartSnippetProducer(super.request)
+      : sessionHelper = AnalysisSessionHelper(request.analysisSession),
+        utils = CorrectionUtils(request.unit),
+        libraryElement = request.unit.libraryElement,
+        useSuperParams = request.unit.libraryElement.featureSet
+            .isEnabled(Feature.super_parameters);
+
+  bool get isInTestDirectory {
+    final path = request.unit.path;
+    return LinterContextImpl.testDirectories
+        .any((testDir) => path.contains(testDir));
+  }
+
+  /// The nullable suffix to use in this library.
+  NullabilitySuffix get nullableSuffix => libraryElement.isNonNullableByDefault
+      ? NullabilitySuffix.question
+      : NullabilitySuffix.none;
+
+  bool isLintEnabled(String name) {
+    var analysisOptions = sessionHelper.session.analysisContext.analysisOptions;
+    return analysisOptions.isLintEnabled(name);
+  }
+}
+
+abstract class FlutterSnippetProducer extends DartSnippetProducer {
+  final flutter = Flutter.instance;
+
+  late ClassElement? classWidget;
+  late ClassElement? classContainer;
+
+  FlutterSnippetProducer(super.request);
+
+  Future<ClassElement?> getClass(String name) =>
+      sessionHelper.getClass(flutter.widgetsUri, name);
+
+  DartType getType(
+    ClassElement classElement, [
+    NullabilitySuffix nullabilitySuffix = NullabilitySuffix.none,
+  ]) =>
+      classElement.instantiate(
+        typeArguments: const [],
+        nullabilitySuffix: nullabilitySuffix,
+      );
+
+  @override
+  @mustCallSuper
+  Future<bool> isValid() async {
+    if ((classWidget = await getClass('Widget')) == null) {
+      return false;
+    }
+
+    if ((classContainer = await getClass('Container')) == null) {
+      return false;
+    }
+
+    return super.isValid();
+  }
+}
+
+/// A mixin that provides some common methods for producers that build snippets
+/// for Flutter widget classes.
+mixin FlutterWidgetSnippetProducerMixin on FlutterSnippetProducer {
+  ClassElement? get classBuildContext;
+  ClassElement? get classKey;
+  String get widgetClassName => 'MyWidget';
+
+  void writeBuildMethod(DartEditBuilder builder) {
+    // Checked by isValid() before this will be called.
+    final classBuildContext = this.classBuildContext!;
+    final classWidget = this.classWidget!;
+    final classContainer = this.classContainer!;
+
+    // Add the build method.
+    builder.writeln('  @override');
+    builder.write('  ');
+    builder.writeFunctionDeclaration(
+      'build',
+      returnType: getType(classWidget),
+      parameterWriter: () {
+        builder.writeParameter(
+          'context',
+          type: getType(classBuildContext),
+        );
+      },
+      bodyWriter: () {
+        builder.writeln('{');
+        builder.write('    return ');
+        builder.selectAll(() {
+          builder.writeType(getType(classContainer));
+          builder.write('()');
+        });
+        builder.writeln(';');
+        builder.writeln('  }');
+      },
+    );
+  }
+
+  void writeCreateStateMethod(DartEditBuilder builder) {
+    builder.writeln('  @override');
+    builder.write('  State<');
+    builder.addSimpleLinkedEdit('name', widgetClassName);
+    builder.write('> createState() => _');
+    builder.addSimpleLinkedEdit('name', widgetClassName);
+    builder.writeln('State();');
+  }
+
+  void writeWidgetConstructor(DartEditBuilder builder) {
+    // Checked by isValid() before this will be called.
+    final classKey = this.classKey!;
+
+    String keyName;
+    DartType? keyType;
+    void Function()? keyInitializer;
+    if (useSuperParams) {
+      keyName = 'super.key';
+    } else {
+      keyName = 'key';
+      keyType = getType(classKey, nullableSuffix);
+      keyInitializer = () => builder.write('super(key: key)');
+    }
+
+    builder.write('  ');
+    builder.writeConstructorDeclaration(
+      widgetClassName,
+      classNameGroupName: 'name',
+      isConst: true,
+      parameterWriter: () {
+        builder.write('{');
+        builder.writeParameter(keyName, type: keyType);
+        builder.write('}');
+      },
+      initializerWriter: keyInitializer,
+    );
+  }
+}
+
+abstract class SnippetProducer {
+  final DartSnippetRequest request;
+
+  SnippetProducer(this.request);
+
+  Future<Snippet> compute();
+
+  Future<bool> isValid() async {
+    // File edit builders will not produce edits for files outside of the
+    // analysis roots so we should not try to produce any snippets.
+    final analysisContext = request.analysisSession.analysisContext;
+    return analysisContext.contextRoot.isAnalyzed(request.filePath);
+  }
+}
diff --git a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
index eadd2aa..e334a60 100644
--- a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
@@ -677,9 +677,11 @@
 class ExtractWidgetRefactorCodeActionsTest extends AbstractCodeActionsTest {
   final extractWidgetTitle = 'Extract Widget';
 
-  /// Nullability suffix expected in this test class.
-  String get expectedNullableSuffix => '?';
-
+  String get expectedNewWidgetConstructorDeclaration => '''
+const NewWidget({
+    super.key,
+  });
+''';
   @override
   void setUp() {
     super.setUp();
@@ -728,10 +730,7 @@
 }
 
 class NewWidget extends StatelessWidget {
-  const NewWidget({
-    Key$expectedNullableSuffix key,
-  }) : super(key: key);
-
+  $expectedNewWidgetConstructorDeclaration
   @override
   Widget build(BuildContext context) {
     return new Column(
@@ -776,7 +775,11 @@
 class ExtractWidgetRefactorCodeActionsWithoutNullSafetyTest
     extends ExtractWidgetRefactorCodeActionsTest {
   @override
-  String get expectedNullableSuffix => '';
+  String get expectedNewWidgetConstructorDeclaration => '''
+const NewWidget({
+    Key key,
+  }) : super(key: key);
+''';
 
   @override
   String get testPackageLanguageVersion => '2.9';
diff --git a/pkg/analysis_server/test/lsp/completion_dart_test.dart b/pkg/analysis_server/test/lsp/completion_dart_test.dart
index 30298a0..9684d3f 100644
--- a/pkg/analysis_server/test/lsp/completion_dart_test.dart
+++ b/pkg/analysis_server/test/lsp/completion_dart_test.dart
@@ -5,8 +5,22 @@
 import 'package:analysis_server/lsp_protocol/protocol.dart';
 import 'package:analysis_server/src/lsp/constants.dart';
 import 'package:analysis_server/src/services/linter/lint_names.dart';
-import 'package:analysis_server/src/services/snippets/dart/dart_snippet_producers.dart';
-import 'package:analysis_server/src/services/snippets/dart/flutter_snippet_producers.dart';
+import 'package:analysis_server/src/services/snippets/dart/class_declaration.dart';
+import 'package:analysis_server/src/services/snippets/dart/do_statement.dart';
+import 'package:analysis_server/src/services/snippets/dart/flutter_stateful_widget.dart';
+import 'package:analysis_server/src/services/snippets/dart/flutter_stateful_widget_with_animation.dart';
+import 'package:analysis_server/src/services/snippets/dart/flutter_stateless_widget.dart';
+import 'package:analysis_server/src/services/snippets/dart/for_in_statement.dart';
+import 'package:analysis_server/src/services/snippets/dart/for_statement.dart';
+import 'package:analysis_server/src/services/snippets/dart/function_declaration.dart';
+import 'package:analysis_server/src/services/snippets/dart/if_else_statement.dart';
+import 'package:analysis_server/src/services/snippets/dart/if_statement.dart';
+import 'package:analysis_server/src/services/snippets/dart/main_function.dart';
+import 'package:analysis_server/src/services/snippets/dart/switch_statement.dart';
+import 'package:analysis_server/src/services/snippets/dart/test_definition.dart';
+import 'package:analysis_server/src/services/snippets/dart/test_group_definition.dart';
+import 'package:analysis_server/src/services/snippets/dart/try_catch_statement.dart';
+import 'package:analysis_server/src/services/snippets/dart/while_statement.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart' as plugin;
 import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
 import 'package:collection/collection.dart';
@@ -2679,8 +2693,8 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix: DartClassSnippetProducer.prefix,
-      label: DartClassSnippetProducer.label,
+      prefix: ClassDeclaration.prefix,
+      label: ClassDeclaration.label,
     );
 
     expect(updated, r'''
@@ -2720,8 +2734,8 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix: DartDoWhileLoopSnippetProducer.prefix,
-      label: DartDoWhileLoopSnippetProducer.label,
+      prefix: DoStatement.prefix,
+      label: DoStatement.label,
     );
 
     expect(updated, r'''
@@ -2746,7 +2760,7 @@
     await initializeWithSnippetSupport();
     await expectNoSnippet(
       content,
-      FlutterStatelessWidgetSnippetProducer.prefix,
+      FlutterStatelessWidget.prefix,
     );
   }
 
@@ -2760,8 +2774,8 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix: DartForLoopSnippetProducer.prefix,
-      label: DartForLoopSnippetProducer.label,
+      prefix: ForStatement.prefix,
+      label: ForStatement.label,
     );
 
     expect(updated, r'''
@@ -2783,8 +2797,8 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix: DartForInLoopSnippetProducer.prefix,
-      label: DartForInLoopSnippetProducer.label,
+      prefix: ForInStatement.prefix,
+      label: ForInStatement.label,
     );
 
     expect(updated, r'''
@@ -2806,8 +2820,8 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix: DartFunctionSnippetProducer.prefix,
-      label: DartFunctionSnippetProducer.label,
+      prefix: FunctionDeclaration.prefix,
+      label: FunctionDeclaration.label,
     );
 
     expect(updated, r'''
@@ -2829,8 +2843,8 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix: DartFunctionSnippetProducer.prefix,
-      label: DartFunctionSnippetProducer.label,
+      prefix: FunctionDeclaration.prefix,
+      label: FunctionDeclaration.label,
     );
 
     expect(updated, r'''
@@ -2850,8 +2864,8 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix: DartFunctionSnippetProducer.prefix,
-      label: DartFunctionSnippetProducer.label,
+      prefix: FunctionDeclaration.prefix,
+      label: FunctionDeclaration.label,
     );
 
     expect(updated, r'''
@@ -2871,8 +2885,8 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix: DartIfSnippetProducer.prefix,
-      label: DartIfSnippetProducer.label,
+      prefix: IfStatement.prefix,
+      label: IfStatement.label,
     );
 
     expect(updated, r'''
@@ -2894,10 +2908,9 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix: DartIfElseSnippetProducer.prefix,
-      label: DartIfElseSnippetProducer.label,
+      prefix: IfElseStatement.prefix,
+      label: IfElseStatement.label,
     );
-
     expect(updated, r'''
 void f() {
   if (${1:condition}) {
@@ -2921,8 +2934,8 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix: DartMainFunctionSnippetProducer.prefix,
-      label: DartMainFunctionSnippetProducer.label,
+      prefix: MainFunction.prefix,
+      label: MainFunction.label,
     );
 
     expect(updated, r'''
@@ -2957,8 +2970,8 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix: DartSwitchSnippetProducer.prefix,
-      label: DartSwitchSnippetProducer.label,
+      prefix: SwitchStatement.prefix,
+      label: SwitchStatement.label,
     );
 
     expect(updated, r'''
@@ -2985,8 +2998,8 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix: DartTestBlockSnippetProducer.prefix,
-      label: DartTestBlockSnippetProducer.label,
+      prefix: TestDefinition.prefix,
+      label: TestDefinition.label,
     );
 
     expect(updated, r'''
@@ -3010,8 +3023,8 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix: DartTestGroupBlockSnippetProducer.prefix,
-      label: DartTestGroupBlockSnippetProducer.label,
+      prefix: TestGroupDefinition.prefix,
+      label: TestGroupDefinition.label,
     );
 
     expect(updated, r'''
@@ -3033,8 +3046,8 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix: DartTryCatchSnippetProducer.prefix,
-      label: DartTryCatchSnippetProducer.label,
+      prefix: TryCatchStatement.prefix,
+      label: TryCatchStatement.label,
     );
 
     expect(updated, r'''
@@ -3058,8 +3071,8 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix: DartWhileLoopSnippetProducer.prefix,
-      label: DartWhileLoopSnippetProducer.label,
+      prefix: WhileStatement.prefix,
+      label: WhileStatement.label,
     );
 
     expect(updated, r'''
@@ -3112,8 +3125,8 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix: FlutterStatefulWidgetSnippetProducer.prefix,
-      label: FlutterStatefulWidgetSnippetProducer.label,
+      prefix: FlutterStatefulWidget.prefix,
+      label: FlutterStatefulWidget.label,
     );
 
     expect(updated, '''
@@ -3153,9 +3166,8 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix:
-          FlutterStatefulWidgetWithAnimationControllerSnippetProducer.prefix,
-      label: FlutterStatefulWidgetWithAnimationControllerSnippetProducer.label,
+      prefix: FlutterStatefulWidgetWithAnimationController.prefix,
+      label: FlutterStatefulWidgetWithAnimationController.label,
     );
 
     expect(updated, '''
@@ -3210,8 +3222,8 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix: FlutterStatelessWidgetSnippetProducer.prefix,
-      label: FlutterStatelessWidgetSnippetProducer.label,
+      prefix: FlutterStatelessWidget.prefix,
+      label: FlutterStatelessWidget.label,
     );
 
     expect(updated, '''
@@ -3244,8 +3256,8 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix: FlutterStatelessWidgetSnippetProducer.prefix,
-      label: FlutterStatelessWidgetSnippetProducer.label,
+      prefix: FlutterStatelessWidget.prefix,
+      label: FlutterStatelessWidget.label,
     );
 
     expect(updated, '''
@@ -3274,8 +3286,8 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix: FlutterStatelessWidgetSnippetProducer.prefix,
-      label: FlutterStatelessWidgetSnippetProducer.label,
+      prefix: FlutterStatelessWidget.prefix,
+      label: FlutterStatelessWidget.label,
     );
 
     expect(updated, '''
@@ -3300,8 +3312,8 @@
     await initializeWithSnippetSupport();
     final updated = await expectAndApplySnippet(
       content,
-      prefix: FlutterStatelessWidgetSnippetProducer.prefix,
-      label: FlutterStatelessWidgetSnippetProducer.label,
+      prefix: FlutterStatelessWidget.prefix,
+      label: FlutterStatelessWidget.label,
     );
 
     expect(updated, '''
@@ -3330,7 +3342,7 @@
     await initializeWithSnippetSupport();
     await expectNoSnippet(
       content,
-      FlutterStatelessWidgetSnippetProducer.prefix,
+      FlutterStatelessWidget.prefix,
     );
   }
 
diff --git a/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart b/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart
index ab67627..eabe685 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart
@@ -126,8 +126,8 @@
 
 class Test extends StatelessWidget {
   const Test({
-    Key? key,
-  }) : super(key: key);
+    super.key,
+  });
 
   @override
   Widget build(BuildContext context) {
@@ -177,8 +177,8 @@
 
 class Test extends StatelessWidget {
   const Test({
-    Key? key,
-  }) : super(key: key);
+    super.key,
+  });
 
   @override
   Widget build(BuildContext context) {
@@ -213,8 +213,8 @@
 
 class Test extends StatelessWidget {
   const Test({
-    Key? key,
-  }) : super(key: key);
+    super.key,
+  });
 
   @override
   Widget build(BuildContext context) {
@@ -246,8 +246,8 @@
 
 class Test extends StatelessWidget {
   const Test({
-    Key? key,
-  }) : super(key: key);
+    super.key,
+  });
 
   @override
   Widget build(BuildContext context) {
@@ -300,8 +300,8 @@
 
 class Test extends StatelessWidget {
   const Test({
-    Key? key,
-  }) : super(key: key);
+    super.key,
+  });
 
   @override
   Widget build(BuildContext context) {
@@ -403,9 +403,9 @@
 
 class Test extends StatelessWidget {
   const Test({
-    Key? key,
+    super.key,
     required this.c,
-  }) : super(key: key);
+  });
 
   final C c;
 
@@ -455,8 +455,8 @@
 
 class Test extends StatelessWidget {
   const Test({
-    Key? key,
-  }) : super(key: key);
+    super.key,
+  });
 
   @override
   Widget build(BuildContext context) {
@@ -519,11 +519,11 @@
 
 class Test extends StatelessWidget {
   const Test({
-    Key? key,
+    super.key,
     required this.foo,
     required this.p1,
     required this.p2,
-  }) : super(key: key);
+  });
 
   final String foo;
   final String p1;
@@ -594,11 +594,11 @@
 
 class Test extends StatelessWidget {
   const Test({
-    Key? key,
+    super.key,
     required this.foo,
     required this.p1,
     required this.p2,
-  }) : super(key: key);
+  });
 
   final String foo;
   final String p1;
@@ -649,9 +649,9 @@
 
 class Test extends StatelessWidget {
   const Test({
-    Key? key,
+    super.key,
     required this.field,
-  }) : super(key: key);
+  });
 
   final String field;
 
@@ -700,9 +700,9 @@
 
 class Test extends StatelessWidget {
   const Test({
-    Key? key,
+    super.key,
     required this.c,
-  }) : super(key: key);
+  });
 
   final C c;
 
@@ -743,8 +743,8 @@
 
 class Test extends StatelessWidget {
   const Test({
-    Key? key,
-  }) : super(key: key);
+    super.key,
+  });
 
   @override
   Widget build(BuildContext context) {
@@ -848,9 +848,9 @@
 
 class Test extends StatelessWidget {
   const Test({
-    Key? key,
+    super.key,
     required this.c,
-  }) : super(key: key);
+  });
 
   final C c;
 
@@ -912,9 +912,9 @@
 
 class Test extends StatelessWidget {
   const Test({
-    Key? key,
+    super.key,
     required this.local,
-  }) : super(key: key);
+  });
 
   final String local;
 
@@ -982,9 +982,9 @@
 
 class Test extends StatelessWidget {
   const Test({
-    Key? key,
+    super.key,
     required String field,
-  }) : _field = field, super(key: key);
+  }) : _field = field;
 
   final String _field;
 
@@ -1031,10 +1031,10 @@
 
 class Test extends StatelessWidget {
   const Test({
-    Key? key,
+    super.key,
     required this.field,
     required String field2,
-  }) : _field = field2, super(key: key);
+  }) : _field = field2;
 
   final int field;
   final String _field;
@@ -1087,10 +1087,10 @@
 
 class Test extends StatelessWidget {
   const Test({
-    Key? key,
+    super.key,
     required this.field,
     required this.local,
-  }) : super(key: key);
+  });
 
   final String field;
   final String local;
@@ -1156,10 +1156,10 @@
 
 class Test extends StatelessWidget {
   const Test({
-    Key? key,
+    super.key,
     required this.index,
     required this.a,
-  }) : super(key: key);
+  });
 
   final int index;
   final String a;
@@ -1209,6 +1209,68 @@
         RefactoringProblemSeverity.FATAL);
   }
 
+  Future<void> test_useSuperParameters_disabled() async {
+    await indexTestUnit('''
+// No super params.    
+// @dart = 2.15
+import 'package:flutter/material.dart';
+
+class MyWidget extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    return new Row(
+      children: <Widget>[
+        new Column(
+          children: <Widget>[
+            new Text('AAA'),
+            new Text('BBB'),
+          ],
+        ),
+        new Text('CCC'),
+        new Text('DDD'),
+      ],
+    );
+  }
+}
+''');
+    _createRefactoringForStringOffset('new Column');
+
+    await _assertSuccessfulRefactoring('''
+// No super params.    
+// @dart = 2.15
+import 'package:flutter/material.dart';
+
+class MyWidget extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    return new Row(
+      children: <Widget>[
+        Test(),
+        new Text('CCC'),
+        new Text('DDD'),
+      ],
+    );
+  }
+}
+
+class Test extends StatelessWidget {
+  const Test({
+    Key? key,
+  }) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return new Column(
+      children: <Widget>[
+        new Text('AAA'),
+        new Text('BBB'),
+      ],
+    );
+  }
+}
+''');
+  }
+
   Future<void> _assertRefactoringChange(String expectedCode) async {
     var refactoringChange = await refactoring.createChange();
     this.refactoringChange = refactoringChange;
diff --git a/pkg/analysis_server/test/services/snippets/dart/class_declaration_test.dart b/pkg/analysis_server/test/services/snippets/dart/class_declaration_test.dart
new file mode 100644
index 0000000..93d7eed
--- /dev/null
+++ b/pkg/analysis_server/test/services/snippets/dart/class_declaration_test.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2022, 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/protocol_server.dart';
+import 'package:analysis_server/src/services/snippets/dart/class_declaration.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ClassDeclarationTest);
+  });
+}
+
+@reflectiveTest
+class ClassDeclarationTest extends DartSnippetProducerTest {
+  @override
+  final generator = ClassDeclaration.new;
+
+  @override
+  String get label => ClassDeclaration.label;
+
+  @override
+  String get prefix => ClassDeclaration.prefix;
+
+  Future<void> test_class() async {
+    var code = r'''
+class A {}
+  
+^
+
+class B {}''';
+    final snippet = await expectValidSnippet(code);
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    expect(snippet.change.edits, hasLength(1));
+    code = withoutMarkers(code);
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+class A {}
+  
+class ClassName {
+  
+}
+
+class B {}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 34);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      {
+        'positions': [
+          {'file': testFile, 'offset': 20},
+        ],
+        'length': 9,
+        'suggestions': []
+      }
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/services/snippets/dart/dart_snippet_producers_test.dart b/pkg/analysis_server/test/services/snippets/dart/dart_snippet_producers_test.dart
deleted file mode 100644
index 8ce0a7d..0000000
--- a/pkg/analysis_server/test/services/snippets/dart/dart_snippet_producers_test.dart
+++ /dev/null
@@ -1,974 +0,0 @@
-// Copyright (c) 2022, 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/protocol_server.dart';
-import 'package:analysis_server/src/services/snippets/dart/dart_snippet_producers.dart';
-import 'package:analysis_server/src/services/snippets/dart/snippet_manager.dart';
-import 'package:test/test.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-import '../../../abstract_single_unit.dart';
-import 'test_support.dart';
-
-void main() {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(DartDoWhileLoopSnippetProducerTest);
-    defineReflectiveTests(DartForInLoopSnippetProducerTest);
-    defineReflectiveTests(DartForLoopSnippetProducerTest);
-    defineReflectiveTests(DartIfElseSnippetProducerTest);
-    defineReflectiveTests(DartIfSnippetProducerTest);
-    defineReflectiveTests(DartMainFunctionSnippetProducerTest);
-    defineReflectiveTests(DartSwitchSnippetProducerTest);
-    defineReflectiveTests(DartTryCatchSnippetProducerTest);
-    defineReflectiveTests(DartWhileLoopSnippetProducerTest);
-    defineReflectiveTests(DartClassSnippetProducerTest);
-    defineReflectiveTests(DartFunctionSnippetProducerTest);
-    defineReflectiveTests(DartTestBlockSnippetProducerTest);
-    defineReflectiveTests(DartTestGroupBlockSnippetProducerTest);
-  });
-}
-
-@reflectiveTest
-class DartClassSnippetProducerTest extends DartSnippetProducerTest {
-  @override
-  final generator = DartClassSnippetProducer.newInstance;
-
-  @override
-  String get label => DartClassSnippetProducer.label;
-
-  @override
-  String get prefix => DartClassSnippetProducer.prefix;
-
-  Future<void> test_class() async {
-    var code = r'''
-class A {}
-  
-^
-
-class B {}''';
-    final snippet = await expectValidSnippet(code);
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    expect(snippet.change.edits, hasLength(1));
-    code = withoutMarkers(code);
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-class A {}
-  
-class ClassName {
-  
-}
-
-class B {}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 34);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      {
-        'positions': [
-          {'file': testFile, 'offset': 20},
-        ],
-        'length': 9,
-        'suggestions': []
-      }
-    ]);
-  }
-}
-
-@reflectiveTest
-class DartDoWhileLoopSnippetProducerTest extends DartSnippetProducerTest {
-  @override
-  final generator = DartDoWhileLoopSnippetProducer.newInstance;
-
-  @override
-  String get label => DartDoWhileLoopSnippetProducer.label;
-
-  @override
-  String get prefix => DartDoWhileLoopSnippetProducer.prefix;
-
-  Future<void> test_do() async {
-    var code = r'''
-void f() {
-  do^
-}''';
-    final snippet = await expectValidSnippet(code);
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    expect(snippet.change.edits, hasLength(1));
-    code = withoutMarkers(code);
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-void f() {
-  do {
-    
-  } while (condition);
-}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 22);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      {
-        'positions': [
-          {'file': testFile, 'offset': 34},
-        ],
-        'length': 9,
-        'suggestions': []
-      }
-    ]);
-  }
-}
-
-@reflectiveTest
-class DartForInLoopSnippetProducerTest extends DartSnippetProducerTest {
-  @override
-  final generator = DartForInLoopSnippetProducer.newInstance;
-
-  @override
-  String get label => DartForInLoopSnippetProducer.label;
-
-  @override
-  String get prefix => DartForInLoopSnippetProducer.prefix;
-
-  Future<void> test_for() async {
-    var code = r'''
-void f() {
-  forin^
-}''';
-    final snippet = await expectValidSnippet(code);
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    expect(snippet.change.edits, hasLength(1));
-    code = withoutMarkers(code);
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-void f() {
-  for (var element in collection) {
-    
-  }
-}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 51);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      {
-        'positions': [
-          {'file': testFile, 'offset': 22},
-        ],
-        'length': 7,
-        'suggestions': []
-      },
-      {
-        'positions': [
-          {'file': testFile, 'offset': 33},
-        ],
-        'length': 10,
-        'suggestions': []
-      }
-    ]);
-  }
-}
-
-@reflectiveTest
-class DartForLoopSnippetProducerTest extends DartSnippetProducerTest {
-  @override
-  final generator = DartForLoopSnippetProducer.newInstance;
-
-  @override
-  String get label => DartForLoopSnippetProducer.label;
-
-  @override
-  String get prefix => DartForLoopSnippetProducer.prefix;
-
-  Future<void> test_for() async {
-    var code = r'''
-void f() {
-  for^
-}''';
-    final snippet = await expectValidSnippet(code);
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    expect(snippet.change.edits, hasLength(1));
-    code = withoutMarkers(code);
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-void f() {
-  for (var i = 0; i < count; i++) {
-    
-  }
-}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 51);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      {
-        'positions': [
-          {'file': testFile, 'offset': 33},
-        ],
-        'length': 5,
-        'suggestions': []
-      }
-    ]);
-  }
-}
-
-@reflectiveTest
-class DartFunctionSnippetProducerTest extends DartSnippetProducerTest {
-  @override
-  final generator = DartFunctionSnippetProducer.newInstance;
-
-  @override
-  String get label => DartFunctionSnippetProducer.label;
-
-  @override
-  String get prefix => DartFunctionSnippetProducer.prefix;
-
-  Future<void> test_classMethod() async {
-    var code = r'''
-class A {
-  ^
-}''';
-    final snippet = await expectValidSnippet(code);
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    expect(snippet.change.edits, hasLength(1));
-    code = withoutMarkers(code);
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-class A {
-  void name(params) {
-    
-  }
-}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 36);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      {
-        'positions': [
-          {'file': testFile, 'offset': 12},
-        ],
-        'length': 4,
-        'suggestions': []
-      },
-      {
-        'positions': [
-          {'file': testFile, 'offset': 17},
-        ],
-        'length': 4,
-        'suggestions': []
-      },
-      {
-        'positions': [
-          {'file': testFile, 'offset': 22},
-        ],
-        'length': 6,
-        'suggestions': []
-      },
-    ]);
-  }
-
-  Future<void> test_nested() async {
-    var code = r'''
-void a() {
-  ^
-}''';
-    final snippet = await expectValidSnippet(code);
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    expect(snippet.change.edits, hasLength(1));
-    code = withoutMarkers(code);
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-void a() {
-  void name(params) {
-    
-  }
-}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 37);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      {
-        'positions': [
-          {'file': testFile, 'offset': 13},
-        ],
-        'length': 4,
-        'suggestions': []
-      },
-      {
-        'positions': [
-          {'file': testFile, 'offset': 18},
-        ],
-        'length': 4,
-        'suggestions': []
-      },
-      {
-        'positions': [
-          {'file': testFile, 'offset': 23},
-        ],
-        'length': 6,
-        'suggestions': []
-      },
-    ]);
-  }
-
-  Future<void> test_topLevel() async {
-    var code = r'''
-class A {}
-  
-^
-
-class B {}''';
-    final snippet = await expectValidSnippet(code);
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    expect(snippet.change.edits, hasLength(1));
-    code = withoutMarkers(code);
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-class A {}
-  
-void name(params) {
-  
-}
-
-class B {}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 36);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      {
-        'positions': [
-          {'file': testFile, 'offset': 14},
-        ],
-        'length': 4,
-        'suggestions': []
-      },
-      {
-        'positions': [
-          {'file': testFile, 'offset': 19},
-        ],
-        'length': 4,
-        'suggestions': []
-      },
-      {
-        'positions': [
-          {'file': testFile, 'offset': 24},
-        ],
-        'length': 6,
-        'suggestions': []
-      },
-    ]);
-  }
-}
-
-@reflectiveTest
-class DartIfElseSnippetProducerTest extends DartSnippetProducerTest {
-  @override
-  final generator = DartIfElseSnippetProducer.newInstance;
-
-  @override
-  String get label => DartIfElseSnippetProducer.label;
-
-  @override
-  String get prefix => DartIfElseSnippetProducer.prefix;
-
-  Future<void> test_ifElse() async {
-    var code = r'''
-void f() {
-  if^
-}''';
-    final snippet = await expectValidSnippet(code);
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    expect(snippet.change.edits, hasLength(1));
-    code = withoutMarkers(code);
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-void f() {
-  if (condition) {
-    
-  } else {
-    
-  }
-}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 34);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      {
-        'positions': [
-          {'file': testFile, 'offset': 17},
-        ],
-        'length': 9,
-        'suggestions': []
-      }
-    ]);
-  }
-
-  Future<void> test_ifElse_indentedInsideBlock() async {
-    var code = r'''
-void f() {
-  if (true) {
-    if^
-  }
-}''';
-    final snippet = await expectValidSnippet(code);
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    expect(snippet.change.edits, hasLength(1));
-    code = withoutMarkers(code);
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-void f() {
-  if (true) {
-    if (condition) {
-      
-    } else {
-      
-    }
-  }
-}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 52);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      {
-        'positions': [
-          {'file': testFile, 'offset': 33},
-        ],
-        'length': 9,
-        'suggestions': []
-      }
-    ]);
-  }
-}
-
-@reflectiveTest
-class DartIfSnippetProducerTest extends DartSnippetProducerTest {
-  @override
-  final generator = DartIfSnippetProducer.newInstance;
-
-  @override
-  String get label => DartIfSnippetProducer.label;
-
-  @override
-  String get prefix => DartIfSnippetProducer.prefix;
-
-  Future<void> test_if() async {
-    var code = r'''
-void f() {
-  if^
-}''';
-    final snippet = await expectValidSnippet(code);
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    expect(snippet.change.edits, hasLength(1));
-    code = withoutMarkers(code);
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-void f() {
-  if (condition) {
-    
-  }
-}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 34);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      {
-        'positions': [
-          {'file': testFile, 'offset': 17},
-        ],
-        'length': 9,
-        'suggestions': []
-      }
-    ]);
-  }
-
-  Future<void> test_if_indentedInsideBlock() async {
-    var code = r'''
-void f() {
-  if (true) {
-    if^
-  }
-}''';
-    final snippet = await expectValidSnippet(code);
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    expect(snippet.change.edits, hasLength(1));
-    code = withoutMarkers(code);
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-void f() {
-  if (true) {
-    if (condition) {
-      
-    }
-  }
-}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 52);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      {
-        'positions': [
-          {'file': testFile, 'offset': 33},
-        ],
-        'length': 9,
-        'suggestions': []
-      }
-    ]);
-  }
-}
-
-@reflectiveTest
-class DartMainFunctionSnippetProducerTest extends DartSnippetProducerTest {
-  @override
-  final generator = DartMainFunctionSnippetProducer.newInstance;
-
-  @override
-  String get label => DartMainFunctionSnippetProducer.label;
-
-  @override
-  String get prefix => DartMainFunctionSnippetProducer.prefix;
-
-  Future<void> test_noParams_testFolder() => testInFile(
-        convertPath('$testPackageLibPath/test/foo_test.dart'),
-        expectArgsParameter: false,
-      );
-
-  Future<void> test_params_binFolder() => testInFile(
-        convertPath('$testPackageLibPath/bin/main.dart'),
-        expectArgsParameter: true,
-      );
-
-  Future<void> test_params_projectRoot() => testInFile(
-        convertPath('$testPackageRootPath/foo.dart'),
-        expectArgsParameter: true,
-      );
-
-  Future<void> test_params_toolFolder() => testInFile(
-        convertPath('$testPackageLibPath/tool/tool.dart'),
-        expectArgsParameter: true,
-      );
-
-  Future<void> test_typedPrefix() => testInFile(
-        testFile,
-        code: '$prefix^',
-        expectArgsParameter: true,
-      );
-
-  Future<void> testInFile(
-    String file, {
-    String code = '^',
-    required bool expectArgsParameter,
-  }) async {
-    testFile = file;
-    final snippet = await expectValidSnippet(code);
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    expect(snippet.change.edits, hasLength(1));
-    code = withoutMarkers(code);
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    final expectedParams = expectArgsParameter ? 'List<String> args' : '';
-    expect(code, '''
-void main($expectedParams) {
-  
-}''');
-    expect(snippet.change.selection!.file, file);
-    expect(snippet.change.selection!.offset, 16 + expectedParams.length);
-    expect(snippet.change.linkedEditGroups, isEmpty);
-  }
-}
-
-abstract class DartSnippetProducerTest extends AbstractSingleUnitTest {
-  SnippetProducerGenerator get generator;
-  String get label;
-  String get prefix;
-
-  /// Override the package root because it usually contains /test/ and some
-  /// snippets behave differently for test files.
-  @override
-  String get testPackageRootPath => '$workspaceRootPath/my_package';
-
-  @override
-  bool get verifyNoTestUnitErrors => false;
-
-  Future<void> expectNotValidSnippet(
-    String code,
-  ) async {
-    await resolveTestCode(withoutMarkers(code));
-    final request = DartSnippetRequest(
-      unit: testAnalysisResult,
-      offset: offsetFromMarker(code),
-    );
-
-    final producer = generator(request);
-    expect(await producer.isValid(), isFalse);
-  }
-
-  Future<Snippet> expectValidSnippet(String code) async {
-    await resolveTestCode(withoutMarkers(code));
-    final request = DartSnippetRequest(
-      unit: testAnalysisResult,
-      offset: offsetFromMarker(code),
-    );
-
-    final producer = generator(request);
-    expect(await producer.isValid(), isTrue);
-    return producer.compute();
-  }
-}
-
-@reflectiveTest
-class DartSwitchSnippetProducerTest extends DartSnippetProducerTest {
-  @override
-  final generator = DartSwitchSnippetProducer.newInstance;
-
-  @override
-  String get label => DartSwitchSnippetProducer.label;
-
-  @override
-  String get prefix => DartSwitchSnippetProducer.prefix;
-
-  Future<void> test_switch() async {
-    var code = r'''
-void f() {
-  sw^
-}''';
-    final snippet = await expectValidSnippet(code);
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    expect(snippet.change.edits, hasLength(1));
-    code = withoutMarkers(code);
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-void f() {
-  switch (expression) {
-    case value:
-      
-      break;
-    default:
-  }
-}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 57);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      // expression
-      {
-        'positions': [
-          {'file': testFile, 'offset': 21},
-        ],
-        'length': 10,
-        'suggestions': []
-      },
-      // value
-      {
-        'positions': [
-          {'file': testFile, 'offset': 44},
-        ],
-        'length': 5,
-        'suggestions': []
-      },
-    ]);
-  }
-
-  Future<void> test_switch_indentedInsideBlock() async {
-    var code = r'''
-void f() {
-  if (true) {
-    sw^
-  }
-}''';
-    final snippet = await expectValidSnippet(code);
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    expect(snippet.change.edits, hasLength(1));
-    code = withoutMarkers(code);
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-void f() {
-  if (true) {
-    switch (expression) {
-      case value:
-        
-        break;
-      default:
-    }
-  }
-}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 77);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      // expression
-      {
-        'positions': [
-          {'file': testFile, 'offset': 37},
-        ],
-        'length': 10,
-        'suggestions': []
-      },
-      // value
-      {
-        'positions': [
-          {'file': testFile, 'offset': 62},
-        ],
-        'length': 5,
-        'suggestions': []
-      },
-    ]);
-  }
-}
-
-@reflectiveTest
-class DartTestBlockSnippetProducerTest extends DartSnippetProducerTest {
-  @override
-  final generator = DartTestBlockSnippetProducer.newInstance;
-
-  @override
-  String get label => DartTestBlockSnippetProducer.label;
-
-  @override
-  String get prefix => DartTestBlockSnippetProducer.prefix;
-
-  Future<void> test_inTestFile() async {
-    testFile = convertPath('$testPackageLibPath/test/foo_test.dart');
-    var code = r'''
-void f() {
-  test^
-}''';
-    final snippet = await expectValidSnippet(code);
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    expect(snippet.change.edits, hasLength(1));
-    code = withoutMarkers(code);
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-void f() {
-  test('test name', () {
-    
-  });
-}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 40);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      {
-        'positions': [
-          {'file': testFile, 'offset': 19},
-        ],
-        'length': 9,
-        'suggestions': []
-      }
-    ]);
-  }
-
-  Future<void> test_notTestFile() async {
-    var code = r'''
-void f() {
-  test^
-}''';
-    await expectNotValidSnippet(code);
-  }
-}
-
-@reflectiveTest
-class DartTestGroupBlockSnippetProducerTest extends DartSnippetProducerTest {
-  @override
-  final generator = DartTestGroupBlockSnippetProducer.newInstance;
-
-  @override
-  String get label => DartTestGroupBlockSnippetProducer.label;
-
-  @override
-  String get prefix => DartTestGroupBlockSnippetProducer.prefix;
-
-  Future<void> test_inTestFile() async {
-    testFile = convertPath('$testPackageLibPath/test/foo_test.dart');
-    var code = r'''
-void f() {
-  group^
-}''';
-    final snippet = await expectValidSnippet(code);
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    expect(snippet.change.edits, hasLength(1));
-    code = withoutMarkers(code);
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-void f() {
-  group('group name', () {
-    
-  });
-}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 42);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      {
-        'positions': [
-          {'file': testFile, 'offset': 20},
-        ],
-        'length': 10,
-        'suggestions': []
-      }
-    ]);
-  }
-
-  Future<void> test_notTestFile() async {
-    var code = r'''
-void f() {
-  group^
-}''';
-    await expectNotValidSnippet(code);
-  }
-}
-
-@reflectiveTest
-class DartTryCatchSnippetProducerTest extends DartSnippetProducerTest {
-  @override
-  final generator = DartTryCatchSnippetProducer.newInstance;
-
-  @override
-  String get label => DartTryCatchSnippetProducer.label;
-
-  @override
-  String get prefix => DartTryCatchSnippetProducer.prefix;
-
-  Future<void> test_tryCatch() async {
-    var code = r'''
-void f() {
-  tr^
-}''';
-    final snippet = await expectValidSnippet(code);
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    expect(snippet.change.edits, hasLength(1));
-    code = withoutMarkers(code);
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-void f() {
-  try {
-    
-  } catch (e) {
-    
-  }
-}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 23);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      {
-        'positions': [
-          {'file': testFile, 'offset': 35},
-        ],
-        'length': 1,
-        'suggestions': []
-      }
-    ]);
-  }
-
-  Future<void> test_tryCatch_indentedInsideBlock() async {
-    var code = r'''
-void f() {
-  if (true) {
-    tr^
-  }
-}''';
-    final snippet = await expectValidSnippet(code);
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    expect(snippet.change.edits, hasLength(1));
-    code = withoutMarkers(code);
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-void f() {
-  if (true) {
-    try {
-      
-    } catch (e) {
-      
-    }
-  }
-}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 41);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      {
-        'positions': [
-          {'file': testFile, 'offset': 55},
-        ],
-        'length': 1,
-        'suggestions': []
-      }
-    ]);
-  }
-}
-
-@reflectiveTest
-class DartWhileLoopSnippetProducerTest extends DartSnippetProducerTest {
-  @override
-  final generator = DartWhileLoopSnippetProducer.newInstance;
-
-  @override
-  String get label => DartWhileLoopSnippetProducer.label;
-
-  @override
-  String get prefix => DartWhileLoopSnippetProducer.prefix;
-
-  Future<void> test_while() async {
-    var code = r'''
-void f() {
-  while^
-}''';
-    final snippet = await expectValidSnippet(code);
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    expect(snippet.change.edits, hasLength(1));
-    code = withoutMarkers(code);
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-void f() {
-  while (condition) {
-    
-  }
-}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 37);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      {
-        'positions': [
-          {'file': testFile, 'offset': 20},
-        ],
-        'length': 9,
-        'suggestions': []
-      }
-    ]);
-  }
-}
diff --git a/pkg/analysis_server/test/services/snippets/dart/do_statement_test.dart b/pkg/analysis_server/test/services/snippets/dart/do_statement_test.dart
new file mode 100644
index 0000000..a2b388c
--- /dev/null
+++ b/pkg/analysis_server/test/services/snippets/dart/do_statement_test.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2022, 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/protocol_server.dart';
+import 'package:analysis_server/src/services/snippets/dart/do_statement.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(DoStatementTest);
+  });
+}
+
+@reflectiveTest
+class DoStatementTest extends DartSnippetProducerTest {
+  @override
+  final generator = DoStatement.new;
+
+  @override
+  String get label => DoStatement.label;
+
+  @override
+  String get prefix => DoStatement.prefix;
+
+  Future<void> test_do() async {
+    var code = r'''
+void f() {
+  do^
+}''';
+    final snippet = await expectValidSnippet(code);
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    expect(snippet.change.edits, hasLength(1));
+    code = withoutMarkers(code);
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+void f() {
+  do {
+    
+  } while (condition);
+}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 22);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      {
+        'positions': [
+          {'file': testFile, 'offset': 34},
+        ],
+        'length': 9,
+        'suggestions': []
+      }
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/services/snippets/dart/flutter_snippet_producers_test.dart b/pkg/analysis_server/test/services/snippets/dart/flutter_snippet_producers_test.dart
deleted file mode 100644
index fcce56b..0000000
--- a/pkg/analysis_server/test/services/snippets/dart/flutter_snippet_producers_test.dart
+++ /dev/null
@@ -1,381 +0,0 @@
-// Copyright (c) 2022, 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/protocol_server.dart';
-import 'package:analysis_server/src/services/snippets/dart/flutter_snippet_producers.dart';
-import 'package:test/test.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-import 'dart_snippet_producers_test.dart';
-
-void main() {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(FlutterStatefulWidgetSnippetProducerTest);
-    defineReflectiveTests(
-        FlutterStatefulWidgetWithAnimationControllerSnippetProducerTest);
-    defineReflectiveTests(FlutterStatelessWidgetSnippetProducerTest);
-  });
-}
-
-abstract class FlutterSnippetProducerTest extends DartSnippetProducerTest {
-  /// Checks snippets can produce edits where the imports and snippet will be
-  /// inserted at the same location.
-  ///
-  /// For example, when a document is completely empty besides the snippet
-  /// prefix, the imports will be inserted at offset 0 and the snippet will
-  /// replace from 0 to the end of the typed prefix.
-  Future<void> test_valid_importsAndEditsOverlap() async {
-    writeTestPackageConfig(flutter: true);
-
-    final snippet = await expectValidSnippet('$prefix^');
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-
-    // Main edits replace $prefix.length characters starting at $prefix
-    final mainEdit = snippet.change.edits[0].edits[0];
-    expect(mainEdit.offset, testCode.indexOf(prefix));
-    expect(mainEdit.length, prefix.length);
-
-    // Imports inserted at start of doc (0)
-    final importEdit = snippet.change.edits[0].edits[1];
-    expect(importEdit.offset, 0);
-    expect(importEdit.length, 0);
-  }
-
-  Future<void> test_valid_suffixReplacement() async {
-    writeTestPackageConfig(flutter: true);
-
-    final snippet = await expectValidSnippet('''
-class A {}
-
-$prefix^
-''');
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-
-    // Main edits replace $prefix.length characters starting at $prefix
-    final mainEdit = snippet.change.edits[0].edits[0];
-    expect(mainEdit.offset, testCode.indexOf(prefix));
-    expect(mainEdit.length, prefix.length);
-
-    // Imports inserted at start of doc (0)
-    final importEdit = snippet.change.edits[0].edits[1];
-    expect(importEdit.offset, 0);
-    expect(importEdit.length, 0);
-  }
-}
-
-@reflectiveTest
-class FlutterStatefulWidgetSnippetProducerTest
-    extends FlutterSnippetProducerTest {
-  @override
-  final generator = FlutterStatefulWidgetSnippetProducer.newInstance;
-
-  @override
-  String get label => FlutterStatefulWidgetSnippetProducer.label;
-
-  @override
-  String get prefix => FlutterStatefulWidgetSnippetProducer.prefix;
-
-  Future<void> test_noSuperParams() async {
-    writeTestPackageConfig(flutter: true, languageVersion: '2.16');
-
-    final snippet = await expectValidSnippet('^');
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    var code = '';
-    expect(snippet.change.edits, hasLength(1));
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-import 'package:flutter/src/foundation/key.dart';
-import 'package:flutter/src/widgets/container.dart';
-import 'package:flutter/src/widgets/framework.dart';
-
-class MyWidget extends StatefulWidget {
-  const MyWidget({Key? key}) : super(key: key);
-
-  @override
-  State<MyWidget> createState() => _MyWidgetState();
-}
-
-class _MyWidgetState extends State<MyWidget> {
-  @override
-  Widget build(BuildContext context) {
-    return Container();
-  }
-}''');
-  }
-
-  Future<void> test_notValid_notFlutterProject() async {
-    writeTestPackageConfig();
-
-    await expectNotValidSnippet('^');
-  }
-
-  Future<void> test_valid() async {
-    writeTestPackageConfig(flutter: true);
-
-    final snippet = await expectValidSnippet('^');
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    var code = '';
-    expect(snippet.change.edits, hasLength(1));
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-import 'package:flutter/src/widgets/container.dart';
-import 'package:flutter/src/widgets/framework.dart';
-
-class MyWidget extends StatefulWidget {
-  const MyWidget({super.key});
-
-  @override
-  State<MyWidget> createState() => _MyWidgetState();
-}
-
-class _MyWidgetState extends State<MyWidget> {
-  @override
-  Widget build(BuildContext context) {
-    return Container();
-  }
-}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 356);
-    expect(snippet.change.selectionLength, 11);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      {
-        'positions': [
-          {'file': testFile, 'offset': 113},
-          {'file': testFile, 'offset': 155},
-          {'file': testFile, 'offset': 199},
-          {'file': testFile, 'offset': 227},
-          {'file': testFile, 'offset': 254},
-          {'file': testFile, 'offset': 282},
-        ],
-        'length': 8,
-        'suggestions': []
-      }
-    ]);
-  }
-}
-
-@reflectiveTest
-class FlutterStatefulWidgetWithAnimationControllerSnippetProducerTest
-    extends FlutterSnippetProducerTest {
-  @override
-  final generator =
-      FlutterStatefulWidgetWithAnimationControllerSnippetProducer.newInstance;
-
-  @override
-  String get label =>
-      FlutterStatefulWidgetWithAnimationControllerSnippetProducer.label;
-
-  @override
-  String get prefix =>
-      FlutterStatefulWidgetWithAnimationControllerSnippetProducer.prefix;
-
-  Future<void> test_noSuperParams() async {
-    writeTestPackageConfig(flutter: true, languageVersion: '2.16');
-
-    final snippet = await expectValidSnippet('^');
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    var code = '';
-    expect(snippet.change.edits, hasLength(1));
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-import 'package:flutter/src/animation/animation_controller.dart';
-import 'package:flutter/src/foundation/key.dart';
-import 'package:flutter/src/widgets/container.dart';
-import 'package:flutter/src/widgets/framework.dart';
-import 'package:flutter/src/widgets/ticker_provider.dart';
-
-class MyWidget extends StatefulWidget {
-  const MyWidget({Key? key}) : super(key: key);
-
-  @override
-  State<MyWidget> createState() => _MyWidgetState();
-}
-
-class _MyWidgetState extends State<MyWidget>
-    with SingleTickerProviderStateMixin {
-  late AnimationController _controller;
-
-  @override
-  void initState() {
-    super.initState();
-    _controller = AnimationController(vsync: this);
-  }
-
-  @override
-  void dispose() {
-    _controller.dispose();
-    super.dispose();
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    return Container();
-  }
-}''');
-  }
-
-  Future<void> test_notValid_notFlutterProject() async {
-    writeTestPackageConfig();
-
-    await expectNotValidSnippet('^');
-  }
-
-  Future<void> test_valid() async {
-    writeTestPackageConfig(flutter: true);
-
-    final snippet = await expectValidSnippet('^');
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    var code = '';
-    expect(snippet.change.edits, hasLength(1));
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-import 'package:flutter/src/animation/animation_controller.dart';
-import 'package:flutter/src/widgets/container.dart';
-import 'package:flutter/src/widgets/framework.dart';
-import 'package:flutter/src/widgets/ticker_provider.dart';
-
-class MyWidget extends StatefulWidget {
-  const MyWidget({super.key});
-
-  @override
-  State<MyWidget> createState() => _MyWidgetState();
-}
-
-class _MyWidgetState extends State<MyWidget>
-    with SingleTickerProviderStateMixin {
-  late AnimationController _controller;
-
-  @override
-  void initState() {
-    super.initState();
-    _controller = AnimationController(vsync: this);
-  }
-
-  @override
-  void dispose() {
-    _controller.dispose();
-    super.dispose();
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    return Container();
-  }
-}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 759);
-    expect(snippet.change.selectionLength, 11);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      {
-        'positions': [
-          {'file': testFile, 'offset': 238},
-          {'file': testFile, 'offset': 280},
-          {'file': testFile, 'offset': 324},
-          {'file': testFile, 'offset': 352},
-          {'file': testFile, 'offset': 379},
-          {'file': testFile, 'offset': 407},
-        ],
-        'length': 8,
-        'suggestions': []
-      }
-    ]);
-  }
-}
-
-@reflectiveTest
-class FlutterStatelessWidgetSnippetProducerTest
-    extends FlutterSnippetProducerTest {
-  @override
-  final generator = FlutterStatelessWidgetSnippetProducer.newInstance;
-
-  @override
-  String get label => FlutterStatelessWidgetSnippetProducer.label;
-
-  @override
-  String get prefix => FlutterStatelessWidgetSnippetProducer.prefix;
-
-  Future<void> test_noSuperParams() async {
-    writeTestPackageConfig(flutter: true, languageVersion: '2.16');
-
-    final snippet = await expectValidSnippet('^');
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    var code = '';
-    expect(snippet.change.edits, hasLength(1));
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-import 'package:flutter/src/foundation/key.dart';
-import 'package:flutter/src/widgets/container.dart';
-import 'package:flutter/src/widgets/framework.dart';
-
-class MyWidget extends StatelessWidget {
-  const MyWidget({Key? key}) : super(key: key);
-
-  @override
-  Widget build(BuildContext context) {
-    return Container();
-  }
-}''');
-  }
-
-  Future<void> test_notValid_notFlutterProject() async {
-    writeTestPackageConfig();
-
-    await expectNotValidSnippet('^');
-  }
-
-  Future<void> test_valid() async {
-    writeTestPackageConfig(flutter: true);
-
-    final snippet = await expectValidSnippet('^');
-    expect(snippet.prefix, prefix);
-    expect(snippet.label, label);
-    var code = '';
-    expect(snippet.change.edits, hasLength(1));
-    for (var edit in snippet.change.edits) {
-      code = SourceEdit.applySequence(code, edit.edits);
-    }
-    expect(code, '''
-import 'package:flutter/src/widgets/container.dart';
-import 'package:flutter/src/widgets/framework.dart';
-
-class MyWidget extends StatelessWidget {
-  const MyWidget({super.key});
-
-  @override
-  Widget build(BuildContext context) {
-    return Container();
-  }
-}''');
-    expect(snippet.change.selection!.file, testFile);
-    expect(snippet.change.selection!.offset, 242);
-    expect(snippet.change.selectionLength, 11);
-    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
-      {
-        'positions': [
-          {'file': testFile, 'offset': 113},
-          {'file': testFile, 'offset': 156},
-        ],
-        'length': 8,
-        'suggestions': []
-      }
-    ]);
-  }
-}
diff --git a/pkg/analysis_server/test/services/snippets/dart/flutter_stateful_widget_test.dart b/pkg/analysis_server/test/services/snippets/dart/flutter_stateful_widget_test.dart
new file mode 100644
index 0000000..2b97ffe
--- /dev/null
+++ b/pkg/analysis_server/test/services/snippets/dart/flutter_stateful_widget_test.dart
@@ -0,0 +1,112 @@
+// Copyright (c) 2022, 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/protocol_server.dart';
+import 'package:analysis_server/src/services/snippets/dart/flutter_stateful_widget.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(FlutterStatefulWidgetTest);
+  });
+}
+
+@reflectiveTest
+class FlutterStatefulWidgetTest extends FlutterSnippetProducerTest {
+  @override
+  final generator = FlutterStatefulWidget.new;
+
+  @override
+  String get label => FlutterStatefulWidget.label;
+
+  @override
+  String get prefix => FlutterStatefulWidget.prefix;
+
+  Future<void> test_noSuperParams() async {
+    writeTestPackageConfig(flutter: true, languageVersion: '2.16');
+
+    final snippet = await expectValidSnippet('^');
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    var code = '';
+    expect(snippet.change.edits, hasLength(1));
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+import 'package:flutter/src/foundation/key.dart';
+import 'package:flutter/src/widgets/container.dart';
+import 'package:flutter/src/widgets/framework.dart';
+
+class MyWidget extends StatefulWidget {
+  const MyWidget({Key? key}) : super(key: key);
+
+  @override
+  State<MyWidget> createState() => _MyWidgetState();
+}
+
+class _MyWidgetState extends State<MyWidget> {
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}''');
+  }
+
+  Future<void> test_notValid_notFlutterProject() async {
+    writeTestPackageConfig();
+
+    await expectNotValidSnippet('^');
+  }
+
+  Future<void> test_valid() async {
+    writeTestPackageConfig(flutter: true);
+
+    final snippet = await expectValidSnippet('^');
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    var code = '';
+    expect(snippet.change.edits, hasLength(1));
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+import 'package:flutter/src/widgets/container.dart';
+import 'package:flutter/src/widgets/framework.dart';
+
+class MyWidget extends StatefulWidget {
+  const MyWidget({super.key});
+
+  @override
+  State<MyWidget> createState() => _MyWidgetState();
+}
+
+class _MyWidgetState extends State<MyWidget> {
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 356);
+    expect(snippet.change.selectionLength, 11);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      {
+        'positions': [
+          {'file': testFile, 'offset': 113},
+          {'file': testFile, 'offset': 155},
+          {'file': testFile, 'offset': 199},
+          {'file': testFile, 'offset': 227},
+          {'file': testFile, 'offset': 254},
+          {'file': testFile, 'offset': 282},
+        ],
+        'length': 8,
+        'suggestions': []
+      }
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/services/snippets/dart/flutter_stateful_widget_with_animation_controller_test.dart b/pkg/analysis_server/test/services/snippets/dart/flutter_stateful_widget_with_animation_controller_test.dart
new file mode 100644
index 0000000..5975c84
--- /dev/null
+++ b/pkg/analysis_server/test/services/snippets/dart/flutter_stateful_widget_with_animation_controller_test.dart
@@ -0,0 +1,147 @@
+// Copyright (c) 2022, 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/protocol_server.dart';
+import 'package:analysis_server/src/services/snippets/dart/flutter_stateful_widget_with_animation.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(FlutterStatefulWidgetWithAnimationControllerTest);
+  });
+}
+
+@reflectiveTest
+class FlutterStatefulWidgetWithAnimationControllerTest
+    extends FlutterSnippetProducerTest {
+  @override
+  final generator = FlutterStatefulWidgetWithAnimationController.new;
+
+  @override
+  String get label => FlutterStatefulWidgetWithAnimationController.label;
+
+  @override
+  String get prefix => FlutterStatefulWidgetWithAnimationController.prefix;
+
+  Future<void> test_noSuperParams() async {
+    writeTestPackageConfig(flutter: true, languageVersion: '2.16');
+
+    final snippet = await expectValidSnippet('^');
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    var code = '';
+    expect(snippet.change.edits, hasLength(1));
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+import 'package:flutter/src/animation/animation_controller.dart';
+import 'package:flutter/src/foundation/key.dart';
+import 'package:flutter/src/widgets/container.dart';
+import 'package:flutter/src/widgets/framework.dart';
+import 'package:flutter/src/widgets/ticker_provider.dart';
+
+class MyWidget extends StatefulWidget {
+  const MyWidget({Key? key}) : super(key: key);
+
+  @override
+  State<MyWidget> createState() => _MyWidgetState();
+}
+
+class _MyWidgetState extends State<MyWidget>
+    with SingleTickerProviderStateMixin {
+  late AnimationController _controller;
+
+  @override
+  void initState() {
+    super.initState();
+    _controller = AnimationController(vsync: this);
+  }
+
+  @override
+  void dispose() {
+    _controller.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}''');
+  }
+
+  Future<void> test_notValid_notFlutterProject() async {
+    writeTestPackageConfig();
+
+    await expectNotValidSnippet('^');
+  }
+
+  Future<void> test_valid() async {
+    writeTestPackageConfig(flutter: true);
+
+    final snippet = await expectValidSnippet('^');
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    var code = '';
+    expect(snippet.change.edits, hasLength(1));
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+import 'package:flutter/src/animation/animation_controller.dart';
+import 'package:flutter/src/widgets/container.dart';
+import 'package:flutter/src/widgets/framework.dart';
+import 'package:flutter/src/widgets/ticker_provider.dart';
+
+class MyWidget extends StatefulWidget {
+  const MyWidget({super.key});
+
+  @override
+  State<MyWidget> createState() => _MyWidgetState();
+}
+
+class _MyWidgetState extends State<MyWidget>
+    with SingleTickerProviderStateMixin {
+  late AnimationController _controller;
+
+  @override
+  void initState() {
+    super.initState();
+    _controller = AnimationController(vsync: this);
+  }
+
+  @override
+  void dispose() {
+    _controller.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 759);
+    expect(snippet.change.selectionLength, 11);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      {
+        'positions': [
+          {'file': testFile, 'offset': 238},
+          {'file': testFile, 'offset': 280},
+          {'file': testFile, 'offset': 324},
+          {'file': testFile, 'offset': 352},
+          {'file': testFile, 'offset': 379},
+          {'file': testFile, 'offset': 407},
+        ],
+        'length': 8,
+        'suggestions': []
+      }
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/services/snippets/dart/flutter_stateless_widget_test.dart b/pkg/analysis_server/test/services/snippets/dart/flutter_stateless_widget_test.dart
new file mode 100644
index 0000000..d01c58d
--- /dev/null
+++ b/pkg/analysis_server/test/services/snippets/dart/flutter_stateless_widget_test.dart
@@ -0,0 +1,98 @@
+// Copyright (c) 2022, 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/protocol_server.dart';
+import 'package:analysis_server/src/services/snippets/dart/flutter_stateless_widget.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(FlutterStatelessWidgetTest);
+  });
+}
+
+@reflectiveTest
+class FlutterStatelessWidgetTest extends FlutterSnippetProducerTest {
+  @override
+  final generator = FlutterStatelessWidget.new;
+
+  @override
+  String get label => FlutterStatelessWidget.label;
+
+  @override
+  String get prefix => FlutterStatelessWidget.prefix;
+
+  Future<void> test_noSuperParams() async {
+    writeTestPackageConfig(flutter: true, languageVersion: '2.16');
+
+    final snippet = await expectValidSnippet('^');
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    var code = '';
+    expect(snippet.change.edits, hasLength(1));
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+import 'package:flutter/src/foundation/key.dart';
+import 'package:flutter/src/widgets/container.dart';
+import 'package:flutter/src/widgets/framework.dart';
+
+class MyWidget extends StatelessWidget {
+  const MyWidget({Key? key}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}''');
+  }
+
+  Future<void> test_notValid_notFlutterProject() async {
+    writeTestPackageConfig();
+
+    await expectNotValidSnippet('^');
+  }
+
+  Future<void> test_valid() async {
+    writeTestPackageConfig(flutter: true);
+
+    final snippet = await expectValidSnippet('^');
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    var code = '';
+    expect(snippet.change.edits, hasLength(1));
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+import 'package:flutter/src/widgets/container.dart';
+import 'package:flutter/src/widgets/framework.dart';
+
+class MyWidget extends StatelessWidget {
+  const MyWidget({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 242);
+    expect(snippet.change.selectionLength, 11);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      {
+        'positions': [
+          {'file': testFile, 'offset': 113},
+          {'file': testFile, 'offset': 156},
+        ],
+        'length': 8,
+        'suggestions': []
+      }
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/services/snippets/dart/for_in_statement_test.dart b/pkg/analysis_server/test/services/snippets/dart/for_in_statement_test.dart
new file mode 100644
index 0000000..9f1d457
--- /dev/null
+++ b/pkg/analysis_server/test/services/snippets/dart/for_in_statement_test.dart
@@ -0,0 +1,67 @@
+// Copyright (c) 2022, 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/protocol_server.dart';
+import 'package:analysis_server/src/services/snippets/dart/for_in_statement.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ForInStatementTest);
+  });
+}
+
+@reflectiveTest
+class ForInStatementTest extends DartSnippetProducerTest {
+  @override
+  final generator = ForInStatement.new;
+
+  @override
+  String get label => ForInStatement.label;
+
+  @override
+  String get prefix => ForInStatement.prefix;
+
+  Future<void> test_for() async {
+    var code = r'''
+void f() {
+  forin^
+}''';
+    final snippet = await expectValidSnippet(code);
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    expect(snippet.change.edits, hasLength(1));
+    code = withoutMarkers(code);
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+void f() {
+  for (var element in collection) {
+    
+  }
+}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 51);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      {
+        'positions': [
+          {'file': testFile, 'offset': 22},
+        ],
+        'length': 7,
+        'suggestions': []
+      },
+      {
+        'positions': [
+          {'file': testFile, 'offset': 33},
+        ],
+        'length': 10,
+        'suggestions': []
+      }
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/services/snippets/dart/for_statement_test.dart b/pkg/analysis_server/test/services/snippets/dart/for_statement_test.dart
new file mode 100644
index 0000000..6b11ccc
--- /dev/null
+++ b/pkg/analysis_server/test/services/snippets/dart/for_statement_test.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2022, 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/protocol_server.dart';
+import 'package:analysis_server/src/services/snippets/dart/for_statement.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ForStatementTest);
+  });
+}
+
+@reflectiveTest
+class ForStatementTest extends DartSnippetProducerTest {
+  @override
+  final generator = ForStatement.new;
+
+  @override
+  String get label => ForStatement.label;
+
+  @override
+  String get prefix => ForStatement.prefix;
+
+  Future<void> test_for() async {
+    var code = r'''
+void f() {
+  for^
+}''';
+    final snippet = await expectValidSnippet(code);
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    expect(snippet.change.edits, hasLength(1));
+    code = withoutMarkers(code);
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+void f() {
+  for (var i = 0; i < count; i++) {
+    
+  }
+}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 51);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      {
+        'positions': [
+          {'file': testFile, 'offset': 33},
+        ],
+        'length': 5,
+        'suggestions': []
+      }
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/services/snippets/dart/function_declaration_test.dart b/pkg/analysis_server/test/services/snippets/dart/function_declaration_test.dart
new file mode 100644
index 0000000..7d5aefe
--- /dev/null
+++ b/pkg/analysis_server/test/services/snippets/dart/function_declaration_test.dart
@@ -0,0 +1,170 @@
+// Copyright (c) 2022, 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/protocol_server.dart';
+import 'package:analysis_server/src/services/snippets/dart/function_declaration.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(FunctionDeclarationTest);
+  });
+}
+
+@reflectiveTest
+class FunctionDeclarationTest extends DartSnippetProducerTest {
+  @override
+  final generator = FunctionDeclaration.new;
+
+  @override
+  String get label => FunctionDeclaration.label;
+
+  @override
+  String get prefix => FunctionDeclaration.prefix;
+
+  Future<void> test_classMethod() async {
+    var code = r'''
+class A {
+  ^
+}''';
+    final snippet = await expectValidSnippet(code);
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    expect(snippet.change.edits, hasLength(1));
+    code = withoutMarkers(code);
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+class A {
+  void name(params) {
+    
+  }
+}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 36);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      {
+        'positions': [
+          {'file': testFile, 'offset': 12},
+        ],
+        'length': 4,
+        'suggestions': []
+      },
+      {
+        'positions': [
+          {'file': testFile, 'offset': 17},
+        ],
+        'length': 4,
+        'suggestions': []
+      },
+      {
+        'positions': [
+          {'file': testFile, 'offset': 22},
+        ],
+        'length': 6,
+        'suggestions': []
+      },
+    ]);
+  }
+
+  Future<void> test_nested() async {
+    var code = r'''
+void a() {
+  ^
+}''';
+    final snippet = await expectValidSnippet(code);
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    expect(snippet.change.edits, hasLength(1));
+    code = withoutMarkers(code);
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+void a() {
+  void name(params) {
+    
+  }
+}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 37);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      {
+        'positions': [
+          {'file': testFile, 'offset': 13},
+        ],
+        'length': 4,
+        'suggestions': []
+      },
+      {
+        'positions': [
+          {'file': testFile, 'offset': 18},
+        ],
+        'length': 4,
+        'suggestions': []
+      },
+      {
+        'positions': [
+          {'file': testFile, 'offset': 23},
+        ],
+        'length': 6,
+        'suggestions': []
+      },
+    ]);
+  }
+
+  Future<void> test_topLevel() async {
+    var code = r'''
+class A {}
+  
+^
+
+class B {}''';
+    final snippet = await expectValidSnippet(code);
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    expect(snippet.change.edits, hasLength(1));
+    code = withoutMarkers(code);
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+class A {}
+  
+void name(params) {
+  
+}
+
+class B {}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 36);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      {
+        'positions': [
+          {'file': testFile, 'offset': 14},
+        ],
+        'length': 4,
+        'suggestions': []
+      },
+      {
+        'positions': [
+          {'file': testFile, 'offset': 19},
+        ],
+        'length': 4,
+        'suggestions': []
+      },
+      {
+        'positions': [
+          {'file': testFile, 'offset': 24},
+        ],
+        'length': 6,
+        'suggestions': []
+      },
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/services/snippets/dart/if_else_statement_test.dart b/pkg/analysis_server/test/services/snippets/dart/if_else_statement_test.dart
new file mode 100644
index 0000000..e92e873
--- /dev/null
+++ b/pkg/analysis_server/test/services/snippets/dart/if_else_statement_test.dart
@@ -0,0 +1,100 @@
+// Copyright (c) 2022, 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/protocol_server.dart';
+import 'package:analysis_server/src/services/snippets/dart/if_else_statement.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(IfElseStatementTest);
+  });
+}
+
+@reflectiveTest
+class IfElseStatementTest extends DartSnippetProducerTest {
+  @override
+  final generator = IfElseStatement.new;
+
+  @override
+  String get label => IfElseStatement.label;
+
+  @override
+  String get prefix => IfElseStatement.prefix;
+
+  Future<void> test_ifElse() async {
+    var code = r'''
+void f() {
+  if^
+}''';
+    final snippet = await expectValidSnippet(code);
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    expect(snippet.change.edits, hasLength(1));
+    code = withoutMarkers(code);
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+void f() {
+  if (condition) {
+    
+  } else {
+    
+  }
+}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 34);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      {
+        'positions': [
+          {'file': testFile, 'offset': 17},
+        ],
+        'length': 9,
+        'suggestions': []
+      }
+    ]);
+  }
+
+  Future<void> test_ifElse_indentedInsideBlock() async {
+    var code = r'''
+void f() {
+  if (true) {
+    if^
+  }
+}''';
+    final snippet = await expectValidSnippet(code);
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    expect(snippet.change.edits, hasLength(1));
+    code = withoutMarkers(code);
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+void f() {
+  if (true) {
+    if (condition) {
+      
+    } else {
+      
+    }
+  }
+}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 52);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      {
+        'positions': [
+          {'file': testFile, 'offset': 33},
+        ],
+        'length': 9,
+        'suggestions': []
+      }
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/services/snippets/dart/if_statement_test.dart b/pkg/analysis_server/test/services/snippets/dart/if_statement_test.dart
new file mode 100644
index 0000000..bc83aa2
--- /dev/null
+++ b/pkg/analysis_server/test/services/snippets/dart/if_statement_test.dart
@@ -0,0 +1,96 @@
+// Copyright (c) 2022, 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/protocol_server.dart';
+import 'package:analysis_server/src/services/snippets/dart/if_statement.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(IfStatementTest);
+  });
+}
+
+@reflectiveTest
+class IfStatementTest extends DartSnippetProducerTest {
+  @override
+  final generator = IfStatement.new;
+
+  @override
+  String get label => IfStatement.label;
+
+  @override
+  String get prefix => IfStatement.prefix;
+
+  Future<void> test_if() async {
+    var code = r'''
+void f() {
+  if^
+}''';
+    final snippet = await expectValidSnippet(code);
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    expect(snippet.change.edits, hasLength(1));
+    code = withoutMarkers(code);
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+void f() {
+  if (condition) {
+    
+  }
+}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 34);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      {
+        'positions': [
+          {'file': testFile, 'offset': 17},
+        ],
+        'length': 9,
+        'suggestions': []
+      }
+    ]);
+  }
+
+  Future<void> test_if_indentedInsideBlock() async {
+    var code = r'''
+void f() {
+  if (true) {
+    if^
+  }
+}''';
+    final snippet = await expectValidSnippet(code);
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    expect(snippet.change.edits, hasLength(1));
+    code = withoutMarkers(code);
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+void f() {
+  if (true) {
+    if (condition) {
+      
+    }
+  }
+}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 52);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      {
+        'positions': [
+          {'file': testFile, 'offset': 33},
+        ],
+        'length': 9,
+        'suggestions': []
+      }
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/services/snippets/dart/main_function_test.dart b/pkg/analysis_server/test/services/snippets/dart/main_function_test.dart
new file mode 100644
index 0000000..82e1e12
--- /dev/null
+++ b/pkg/analysis_server/test/services/snippets/dart/main_function_test.dart
@@ -0,0 +1,78 @@
+// Copyright (c) 2022, 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/protocol_server.dart';
+import 'package:analysis_server/src/services/snippets/dart/main_function.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(MainFunctionTest);
+  });
+}
+
+@reflectiveTest
+class MainFunctionTest extends DartSnippetProducerTest {
+  @override
+  final generator = MainFunction.new;
+
+  @override
+  String get label => MainFunction.label;
+
+  @override
+  String get prefix => MainFunction.prefix;
+
+  Future<void> test_noParams_testFolder() => testInFile(
+        convertPath('$testPackageLibPath/test/foo_test.dart'),
+        expectArgsParameter: false,
+      );
+
+  Future<void> test_params_binFolder() => testInFile(
+        convertPath('$testPackageLibPath/bin/main.dart'),
+        expectArgsParameter: true,
+      );
+
+  Future<void> test_params_projectRoot() => testInFile(
+        convertPath('$testPackageRootPath/foo.dart'),
+        expectArgsParameter: true,
+      );
+
+  Future<void> test_params_toolFolder() => testInFile(
+        convertPath('$testPackageLibPath/tool/tool.dart'),
+        expectArgsParameter: true,
+      );
+
+  Future<void> test_typedPrefix() => testInFile(
+        testFile,
+        code: '$prefix^',
+        expectArgsParameter: true,
+      );
+
+  Future<void> testInFile(
+    String file, {
+    String code = '^',
+    required bool expectArgsParameter,
+  }) async {
+    testFile = file;
+    final snippet = await expectValidSnippet(code);
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    expect(snippet.change.edits, hasLength(1));
+    code = withoutMarkers(code);
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    final expectedParams = expectArgsParameter ? 'List<String> args' : '';
+    expect(code, '''
+void main($expectedParams) {
+  
+}''');
+    expect(snippet.change.selection!.file, file);
+    expect(snippet.change.selection!.offset, 16 + expectedParams.length);
+    expect(snippet.change.linkedEditGroups, isEmpty);
+  }
+}
diff --git a/pkg/analysis_server/test/services/snippets/dart/switch_statement_test.dart b/pkg/analysis_server/test/services/snippets/dart/switch_statement_test.dart
new file mode 100644
index 0000000..c2585a0
--- /dev/null
+++ b/pkg/analysis_server/test/services/snippets/dart/switch_statement_test.dart
@@ -0,0 +1,120 @@
+// Copyright (c) 2022, 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/protocol_server.dart';
+import 'package:analysis_server/src/services/snippets/dart/switch_statement.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(SwitchStatementTest);
+  });
+}
+
+@reflectiveTest
+class SwitchStatementTest extends DartSnippetProducerTest {
+  @override
+  final generator = SwitchStatement.new;
+
+  @override
+  String get label => SwitchStatement.label;
+
+  @override
+  String get prefix => SwitchStatement.prefix;
+
+  Future<void> test_switch() async {
+    var code = r'''
+void f() {
+  sw^
+}''';
+    final snippet = await expectValidSnippet(code);
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    expect(snippet.change.edits, hasLength(1));
+    code = withoutMarkers(code);
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+void f() {
+  switch (expression) {
+    case value:
+      
+      break;
+    default:
+  }
+}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 57);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      // expression
+      {
+        'positions': [
+          {'file': testFile, 'offset': 21},
+        ],
+        'length': 10,
+        'suggestions': []
+      },
+      // value
+      {
+        'positions': [
+          {'file': testFile, 'offset': 44},
+        ],
+        'length': 5,
+        'suggestions': []
+      },
+    ]);
+  }
+
+  Future<void> test_switch_indentedInsideBlock() async {
+    var code = r'''
+void f() {
+  if (true) {
+    sw^
+  }
+}''';
+    final snippet = await expectValidSnippet(code);
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    expect(snippet.change.edits, hasLength(1));
+    code = withoutMarkers(code);
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+void f() {
+  if (true) {
+    switch (expression) {
+      case value:
+        
+        break;
+      default:
+    }
+  }
+}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 77);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      // expression
+      {
+        'positions': [
+          {'file': testFile, 'offset': 37},
+        ],
+        'length': 10,
+        'suggestions': []
+      },
+      // value
+      {
+        'positions': [
+          {'file': testFile, 'offset': 62},
+        ],
+        'length': 5,
+        'suggestions': []
+      },
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/services/snippets/dart/test_all.dart b/pkg/analysis_server/test/services/snippets/dart/test_all.dart
index 5686247..cc290a6 100644
--- a/pkg/analysis_server/test/services/snippets/dart/test_all.dart
+++ b/pkg/analysis_server/test/services/snippets/dart/test_all.dart
@@ -4,16 +4,41 @@
 
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import 'dart_snippet_producers_test.dart' as dart_snippet_producers;
-import 'flutter_snippet_producers_test.dart' as flutter_snippet_producers;
-import 'snippet_manager_test.dart' as snippet_manager;
-import 'snippet_request_test.dart' as snippet_request;
+import 'class_declaration_test.dart' as class_declaration;
+import 'do_statement_test.dart' as do_statement;
+import 'flutter_stateful_widget_test.dart' as flutter_stateful_widget;
+import 'flutter_stateful_widget_with_animation_controller_test.dart'
+    as flutter_stateful_widget_with_animation_controller;
+import 'flutter_stateless_widget_test.dart' as flutter_stateless_widget;
+import 'for_in_statement_test.dart' as for_in_statement;
+import 'for_statement_test.dart' as for_statement;
+import 'function_declaration_test.dart' as function_declaration;
+import 'if_else_statement_test.dart' as if_else_statement;
+import 'if_statement_test.dart' as if_statement;
+import 'main_function_test.dart' as main_function;
+import 'switch_statement_test.dart' as switch_statement;
+import 'test_definition_test.dart' as test_definition;
+import 'test_group_definition_test.dart' as test_group_definition;
+import 'try_catch_statement_test.dart' as try_catch_statement;
+import 'while_statement_test.dart' as while_statement;
 
 void main() {
   defineReflectiveSuite(() {
-    dart_snippet_producers.main();
-    flutter_snippet_producers.main();
-    snippet_manager.main();
-    snippet_request.main();
+    class_declaration.main();
+    do_statement.main();
+    flutter_stateful_widget.main();
+    flutter_stateful_widget_with_animation_controller.main();
+    flutter_stateless_widget.main();
+    for_in_statement.main();
+    for_statement.main();
+    function_declaration.main();
+    if_else_statement.main();
+    if_statement.main();
+    main_function.main();
+    switch_statement.main();
+    test_definition.main();
+    test_group_definition.main();
+    try_catch_statement.main();
+    while_statement.main();
   }, name: 'dart');
 }
diff --git a/pkg/analysis_server/test/services/snippets/dart/test_definition_test.dart b/pkg/analysis_server/test/services/snippets/dart/test_definition_test.dart
new file mode 100644
index 0000000..1bb9a2d
--- /dev/null
+++ b/pkg/analysis_server/test/services/snippets/dart/test_definition_test.dart
@@ -0,0 +1,69 @@
+// Copyright (c) 2022, 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/protocol_server.dart';
+import 'package:analysis_server/src/services/snippets/dart/test_definition.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(TestDefinitionTest);
+  });
+}
+
+@reflectiveTest
+class TestDefinitionTest extends DartSnippetProducerTest {
+  @override
+  final generator = TestDefinition.new;
+
+  @override
+  String get label => TestDefinition.label;
+
+  @override
+  String get prefix => TestDefinition.prefix;
+
+  Future<void> test_inTestFile() async {
+    testFile = convertPath('$testPackageLibPath/test/foo_test.dart');
+    var code = r'''
+void f() {
+  test^
+}''';
+    final snippet = await expectValidSnippet(code);
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    expect(snippet.change.edits, hasLength(1));
+    code = withoutMarkers(code);
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+void f() {
+  test('test name', () {
+    
+  });
+}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 40);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      {
+        'positions': [
+          {'file': testFile, 'offset': 19},
+        ],
+        'length': 9,
+        'suggestions': []
+      }
+    ]);
+  }
+
+  Future<void> test_notTestFile() async {
+    var code = r'''
+void f() {
+  test^
+}''';
+    await expectNotValidSnippet(code);
+  }
+}
diff --git a/pkg/analysis_server/test/services/snippets/dart/test_group_definition_test.dart b/pkg/analysis_server/test/services/snippets/dart/test_group_definition_test.dart
new file mode 100644
index 0000000..1033e0d
--- /dev/null
+++ b/pkg/analysis_server/test/services/snippets/dart/test_group_definition_test.dart
@@ -0,0 +1,69 @@
+// Copyright (c) 2022, 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/protocol_server.dart';
+import 'package:analysis_server/src/services/snippets/dart/test_group_definition.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(TestGroupDefinitionTest);
+  });
+}
+
+@reflectiveTest
+class TestGroupDefinitionTest extends DartSnippetProducerTest {
+  @override
+  final generator = TestGroupDefinition.new;
+
+  @override
+  String get label => TestGroupDefinition.label;
+
+  @override
+  String get prefix => TestGroupDefinition.prefix;
+
+  Future<void> test_inTestFile() async {
+    testFile = convertPath('$testPackageLibPath/test/foo_test.dart');
+    var code = r'''
+void f() {
+  group^
+}''';
+    final snippet = await expectValidSnippet(code);
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    expect(snippet.change.edits, hasLength(1));
+    code = withoutMarkers(code);
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+void f() {
+  group('group name', () {
+    
+  });
+}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 42);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      {
+        'positions': [
+          {'file': testFile, 'offset': 20},
+        ],
+        'length': 10,
+        'suggestions': []
+      }
+    ]);
+  }
+
+  Future<void> test_notTestFile() async {
+    var code = r'''
+void f() {
+  group^
+}''';
+    await expectNotValidSnippet(code);
+  }
+}
diff --git a/pkg/analysis_server/test/services/snippets/dart/test_support.dart b/pkg/analysis_server/test/services/snippets/dart/test_support.dart
index 9f2d740..2d0a595 100644
--- a/pkg/analysis_server/test/services/snippets/dart/test_support.dart
+++ b/pkg/analysis_server/test/services/snippets/dart/test_support.dart
@@ -2,29 +2,99 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:analyzer/source/source_range.dart';
+import 'package:analysis_server/src/services/snippets/dart_snippet_request.dart';
+import 'package:analysis_server/src/services/snippets/snippet.dart';
+import 'package:analysis_server/src/services/snippets/snippet_manager.dart';
 import 'package:test/test.dart';
 
-int offsetFromMarker(String code) {
-  final offset = withoutRangeMarkers(code).indexOf('^');
-  expect(offset, isNot(-1));
-  return offset;
+import '../../../abstract_single_unit.dart';
+import '../test_support.dart';
+
+export '../test_support.dart';
+
+abstract class DartSnippetProducerTest extends AbstractSingleUnitTest {
+  SnippetProducerGenerator get generator;
+  String get label;
+  String get prefix;
+
+  /// Override the package root because it usually contains /test/ and some
+  /// snippets behave differently for test files.
+  @override
+  String get testPackageRootPath => '$workspaceRootPath/my_package';
+
+  @override
+  bool get verifyNoTestUnitErrors => false;
+
+  Future<void> expectNotValidSnippet(
+    String code,
+  ) async {
+    await resolveTestCode(withoutMarkers(code));
+    final request = DartSnippetRequest(
+      unit: testAnalysisResult,
+      offset: offsetFromMarker(code),
+    );
+
+    final producer = generator(request);
+    expect(await producer.isValid(), isFalse);
+  }
+
+  Future<Snippet> expectValidSnippet(String code) async {
+    await resolveTestCode(withoutMarkers(code));
+    final request = DartSnippetRequest(
+      unit: testAnalysisResult,
+      offset: offsetFromMarker(code),
+    );
+
+    final producer = generator(request);
+    expect(await producer.isValid(), isTrue);
+    return producer.compute();
+  }
 }
 
-SourceRange rangeFromMarkers(String code) {
-  code = _withoutPositionMarker(code);
-  final start = code.indexOf('[[');
-  final end = code.indexOf(']]');
-  expect(start, isNot(-1));
-  expect(end, isNot(-1));
-  final endAdjusted = end - 2; // Account for the [[ before this marker
-  return SourceRange(start, endAdjusted - start);
+abstract class FlutterSnippetProducerTest extends DartSnippetProducerTest {
+  /// Checks snippets can produce edits where the imports and snippet will be
+  /// inserted at the same location.
+  ///
+  /// For example, when a document is completely empty besides the snippet
+  /// prefix, the imports will be inserted at offset 0 and the snippet will
+  /// replace from 0 to the end of the typed prefix.
+  Future<void> test_valid_importsAndEditsOverlap() async {
+    writeTestPackageConfig(flutter: true);
+
+    final snippet = await expectValidSnippet('$prefix^');
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+
+    // Main edits replace $prefix.length characters starting at $prefix
+    final mainEdit = snippet.change.edits[0].edits[0];
+    expect(mainEdit.offset, testCode.indexOf(prefix));
+    expect(mainEdit.length, prefix.length);
+
+    // Imports inserted at start of doc (0)
+    final importEdit = snippet.change.edits[0].edits[1];
+    expect(importEdit.offset, 0);
+    expect(importEdit.length, 0);
+  }
+
+  Future<void> test_valid_suffixReplacement() async {
+    writeTestPackageConfig(flutter: true);
+
+    final snippet = await expectValidSnippet('''
+class A {}
+
+$prefix^
+''');
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+
+    // Main edits replace $prefix.length characters starting at $prefix
+    final mainEdit = snippet.change.edits[0].edits[0];
+    expect(mainEdit.offset, testCode.indexOf(prefix));
+    expect(mainEdit.length, prefix.length);
+
+    // Imports inserted at start of doc (0)
+    final importEdit = snippet.change.edits[0].edits[1];
+    expect(importEdit.offset, 0);
+    expect(importEdit.length, 0);
+  }
 }
-
-String withoutMarkers(String code) =>
-    withoutRangeMarkers(_withoutPositionMarker(code));
-
-String withoutRangeMarkers(String code) =>
-    code.replaceAll('[[', '').replaceAll(']]', '');
-
-String _withoutPositionMarker(String code) => code.replaceAll('^', '');
diff --git a/pkg/analysis_server/test/services/snippets/dart/try_catch_statement_test.dart b/pkg/analysis_server/test/services/snippets/dart/try_catch_statement_test.dart
new file mode 100644
index 0000000..3ecc95a
--- /dev/null
+++ b/pkg/analysis_server/test/services/snippets/dart/try_catch_statement_test.dart
@@ -0,0 +1,100 @@
+// Copyright (c) 2022, 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/protocol_server.dart';
+import 'package:analysis_server/src/services/snippets/dart/try_catch_statement.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(TryCatchStatementTest);
+  });
+}
+
+@reflectiveTest
+class TryCatchStatementTest extends DartSnippetProducerTest {
+  @override
+  final generator = TryCatchStatement.new;
+
+  @override
+  String get label => TryCatchStatement.label;
+
+  @override
+  String get prefix => TryCatchStatement.prefix;
+
+  Future<void> test_tryCatch() async {
+    var code = r'''
+void f() {
+  tr^
+}''';
+    final snippet = await expectValidSnippet(code);
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    expect(snippet.change.edits, hasLength(1));
+    code = withoutMarkers(code);
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+void f() {
+  try {
+    
+  } catch (e) {
+    
+  }
+}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 23);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      {
+        'positions': [
+          {'file': testFile, 'offset': 35},
+        ],
+        'length': 1,
+        'suggestions': []
+      }
+    ]);
+  }
+
+  Future<void> test_tryCatch_indentedInsideBlock() async {
+    var code = r'''
+void f() {
+  if (true) {
+    tr^
+  }
+}''';
+    final snippet = await expectValidSnippet(code);
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    expect(snippet.change.edits, hasLength(1));
+    code = withoutMarkers(code);
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+void f() {
+  if (true) {
+    try {
+      
+    } catch (e) {
+      
+    }
+  }
+}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 41);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      {
+        'positions': [
+          {'file': testFile, 'offset': 55},
+        ],
+        'length': 1,
+        'suggestions': []
+      }
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/services/snippets/dart/while_statement_test.dart b/pkg/analysis_server/test/services/snippets/dart/while_statement_test.dart
new file mode 100644
index 0000000..06e00c3
--- /dev/null
+++ b/pkg/analysis_server/test/services/snippets/dart/while_statement_test.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2022, 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/protocol_server.dart';
+import 'package:analysis_server/src/services/snippets/dart/while_statement.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(WhileStatementTest);
+  });
+}
+
+@reflectiveTest
+class WhileStatementTest extends DartSnippetProducerTest {
+  @override
+  final generator = WhileStatement.new;
+
+  @override
+  String get label => WhileStatement.label;
+
+  @override
+  String get prefix => WhileStatement.prefix;
+
+  Future<void> test_while() async {
+    var code = r'''
+void f() {
+  while^
+}''';
+    final snippet = await expectValidSnippet(code);
+    expect(snippet.prefix, prefix);
+    expect(snippet.label, label);
+    expect(snippet.change.edits, hasLength(1));
+    code = withoutMarkers(code);
+    for (var edit in snippet.change.edits) {
+      code = SourceEdit.applySequence(code, edit.edits);
+    }
+    expect(code, '''
+void f() {
+  while (condition) {
+    
+  }
+}''');
+    expect(snippet.change.selection!.file, testFile);
+    expect(snippet.change.selection!.offset, 37);
+    expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
+      {
+        'positions': [
+          {'file': testFile, 'offset': 20},
+        ],
+        'length': 9,
+        'suggestions': []
+      }
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/services/snippets/dart/snippet_manager_test.dart b/pkg/analysis_server/test/services/snippets/snippet_manager_test.dart
similarity index 88%
rename from pkg/analysis_server/test/services/snippets/dart/snippet_manager_test.dart
rename to pkg/analysis_server/test/services/snippets/snippet_manager_test.dart
index eeff24a..ae98fe8 100644
--- a/pkg/analysis_server/test/services/snippets/dart/snippet_manager_test.dart
+++ b/pkg/analysis_server/test/services/snippets/snippet_manager_test.dart
@@ -2,12 +2,16 @@
 // 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/snippets/dart/snippet_manager.dart';
+import 'package:analysis_server/src/services/snippets/dart_snippet_request.dart';
+import 'package:analysis_server/src/services/snippets/snippet.dart';
+import 'package:analysis_server/src/services/snippets/snippet_context.dart';
+import 'package:analysis_server/src/services/snippets/snippet_manager.dart';
+import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../../../abstract_single_unit.dart';
+import '../../abstract_single_unit.dart';
 
 void main() {
   defineReflectiveSuite(() {
diff --git a/pkg/analysis_server/test/services/snippets/dart/snippet_request_test.dart b/pkg/analysis_server/test/services/snippets/snippet_request_test.dart
similarity index 97%
rename from pkg/analysis_server/test/services/snippets/dart/snippet_request_test.dart
rename to pkg/analysis_server/test/services/snippets/snippet_request_test.dart
index fd6a240..87c5911 100644
--- a/pkg/analysis_server/test/services/snippets/dart/snippet_request_test.dart
+++ b/pkg/analysis_server/test/services/snippets/snippet_request_test.dart
@@ -2,12 +2,13 @@
 // 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/snippets/dart/snippet_manager.dart';
+import 'package:analysis_server/src/services/snippets/dart_snippet_request.dart';
+import 'package:analysis_server/src/services/snippets/snippet_context.dart';
 import 'package:analyzer/src/test_utilities/platform.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../../../abstract_single_unit.dart';
+import '../../abstract_single_unit.dart';
 import 'test_support.dart';
 
 void main() {
diff --git a/pkg/analysis_server/test/services/snippets/test_all.dart b/pkg/analysis_server/test/services/snippets/test_all.dart
index 899f5ae..b66e99a 100644
--- a/pkg/analysis_server/test/services/snippets/test_all.dart
+++ b/pkg/analysis_server/test/services/snippets/test_all.dart
@@ -4,10 +4,14 @@
 
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import 'dart/test_all.dart' as dart_all;
+import 'dart/test_all.dart' as dart;
+import 'snippet_manager_test.dart' as snippet_manager;
+import 'snippet_request_test.dart' as snippet_request;
 
 void main() {
   defineReflectiveSuite(() {
-    dart_all.main();
+    dart.main();
+    snippet_manager.main();
+    snippet_request.main();
   }, name: 'snippets');
 }
diff --git a/pkg/analysis_server/test/services/snippets/test_support.dart b/pkg/analysis_server/test/services/snippets/test_support.dart
new file mode 100644
index 0000000..9f2d740
--- /dev/null
+++ b/pkg/analysis_server/test/services/snippets/test_support.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/source/source_range.dart';
+import 'package:test/test.dart';
+
+int offsetFromMarker(String code) {
+  final offset = withoutRangeMarkers(code).indexOf('^');
+  expect(offset, isNot(-1));
+  return offset;
+}
+
+SourceRange rangeFromMarkers(String code) {
+  code = _withoutPositionMarker(code);
+  final start = code.indexOf('[[');
+  final end = code.indexOf(']]');
+  expect(start, isNot(-1));
+  expect(end, isNot(-1));
+  final endAdjusted = end - 2; // Account for the [[ before this marker
+  return SourceRange(start, endAdjusted - start);
+}
+
+String withoutMarkers(String code) =>
+    withoutRangeMarkers(_withoutPositionMarker(code));
+
+String withoutRangeMarkers(String code) =>
+    code.replaceAll('[[', '').replaceAll(']]', '');
+
+String _withoutPositionMarker(String code) => code.replaceAll('^', '');
diff --git a/pkg/analysis_server/test/src/computer/call_hierarchy_computer_test.dart b/pkg/analysis_server/test/src/computer/call_hierarchy_computer_test.dart
index 486abe6..c247892 100644
--- a/pkg/analysis_server/test/src/computer/call_hierarchy_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/call_hierarchy_computer_test.dart
@@ -1459,6 +1459,21 @@
     );
   }
 
+  Future<void> test_prefixedTypes() async {
+    // Prefixed type names that are not tear-offs should never be included.
+    final contents = '''
+// ignore_for_file: unused_local_variable
+import 'dart:io' as io;
+
+void ^f(io.File f) {
+  io.Directory? d;
+}
+    ''';
+
+    final calls = await findOutgoingCalls(contents);
+    expect(calls, isEmpty);
+  }
+
   Future<void> test_setter() async {
     final contents = '''
 import 'other.dart';
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index 2555f6d..c4e8160 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -75,326 +75,146 @@
   DirectiveUri get uri;
 }
 
+/// The result of applying augmentations to a [ClassElement].
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class AugmentedClassElement implements AugmentedClassOrEnumElement {
+  /// Returns mixins applied by this class or in its augmentations.
+  ///
+  /// This is a union of mixins applied by the class declaration and all its
+  /// augmentations.
+  List<InterfaceType> get mixins;
+}
+
+/// The result of applying augmentations to a [ClassElement] or [EnumElement].
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class AugmentedClassOrEnumElement
+    implements AugmentedInterfaceDefiningElement {
+  /// Returns constructors declared in this element.
+  ///
+  /// [ConstructorAugmentationElement]s replace corresponding elements,
+  /// other [ConstructorElement]s are appended.
+  List<ConstructorElement> get constructors;
+
+  /// Returns the unnamed constructor from [constructors].
+  ConstructorElement? get unnamedConstructor;
+
+  /// Returns the constructor from [constructors] that has the given [name].
+  ConstructorElement? getNamedConstructor(String name);
+}
+
+/// The result of applying augmentations to a [EnumElement].
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class AugmentedEnumElement implements AugmentedClassOrEnumElement {
+  /// Returns mixins applied by this class or in its augmentations.
+  ///
+  /// This is a union of mixins applied by the class declaration and all its
+  /// augmentations.
+  List<InterfaceType> get mixins;
+}
+
+/// The result of applying augmentations to a [InterfaceDefiningElement].
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class AugmentedInterfaceDefiningElement {
+  /// Returns accessors (getters and setters) declared in this element.
+  ///
+  /// [PropertyAccessorAugmentationElement]s replace corresponding elements,
+  /// other [PropertyAccessorElement]s are appended.
+  List<PropertyAccessorElement> get accessors;
+
+  /// Returns fields declared in this element.
+  ///
+  /// [FieldAugmentationElement]s replace corresponding elements, other
+  /// [FieldElement]s are appended.
+  List<FieldElement> get fields;
+
+  /// Returns interfaces implemented by this element.
+  ///
+  /// This is a union of interfaces declared by the class declaration and
+  /// all its augmentations.
+  List<InterfaceType> get interfaces;
+
+  /// Returns metadata associated with this element.
+  ///
+  /// This is a union of annotations associated with the class declaration and
+  /// all its augmentations.
+  List<ElementAnnotation> get metadata;
+
+  /// Returns methods declared in this element.
+  ///
+  /// [MethodAugmentationElement]s replace corresponding elements, other
+  /// [MethodElement]s are appended.
+  List<MethodElement> get methods;
+
+  /// Returns the field from [fields] that has the given [name].
+  FieldElement? getField(String name);
+
+  /// Returns the getter from [accessors] that has the given [name].
+  PropertyAccessorElement? getGetter(String name);
+
+  /// Returns the method from [methods] that has the given [name].
+  MethodElement? getMethod(String name);
+
+  /// Returns the setter from [accessors] that has the given [name].
+  PropertyAccessorElement? getSetter(String name);
+}
+
+/// The result of applying augmentations to a [MixinElement].
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class AugmentedMixinElement extends AugmentedInterfaceDefiningElement {
+  /// Returns superclass constraints of this element.
+  ///
+  /// This is a union of constraints declared by the class declaration and
+  /// all its augmentations.
+  List<InterfaceType> get superclassConstraints;
+}
+
+/// A class augmentation, defined by a class augmentation declaration.
+///
+/// Clients may not extend, implement or mix-in this class.
+@experimental
+abstract class ClassAugmentationElement implements ClassOrAugmentationElement {
+  /// Returns the element that is augmented by this augmentation; or `null` if
+  /// there is no corresponding element to be augmented. The chain of
+  /// augmentations should normally end with a [ClassElement], but might end
+  /// with `null` immediately or after a few intermediate
+  /// [ClassAugmentationElement]s in case of invalid code when an augmentation
+  /// is declared without the corresponding class declaration.
+  ClassOrAugmentationElement? get augmentationTarget;
+}
+
 /// An element that represents a class or a mixin. The class can be defined by
 /// either a class declaration (with a class body), a mixin application (without
 /// a class body), a mixin declaration, or an enum declaration.
 ///
 /// Clients may not extend, implement or mix-in this class.
 abstract class ClassElement
-    implements TypeDefiningElement, TypeParameterizedElement {
-  /// Return a list containing all of the accessors (getters and setters)
-  /// declared in this class.
-  List<PropertyAccessorElement> get accessors;
-
-  /// Return a list containing all the supertypes defined for this class and its
-  /// supertypes. This includes superclasses, mixins, interfaces and superclass
-  /// constraints.
-  List<InterfaceType> get allSupertypes;
-
-  /// Return a list containing all of the constructors declared in this class.
-  /// The list will be empty if there are no constructors defined for this
-  /// class, as is the case when this element represents an enum or a mixin.
-  List<ConstructorElement> get constructors;
-
-  @override
-  String get displayName;
-
-  @Deprecated('Use enclosingElement2 instead')
-  @override
-  CompilationUnitElement get enclosingElement;
-
-  @override
-  CompilationUnitElement get enclosingElement2;
-
-  /// Return a list containing all of the fields declared in this class.
-  List<FieldElement> get fields;
-
-  /// Return `true` if this class or its superclass declares a non-final
-  /// instance field.
-  bool get hasNonFinalField;
-
-  /// Return `true` if this class declares a static member.
-  bool get hasStaticMember;
-
-  /// Return a list containing all of the interfaces that are implemented by
-  /// this class.
-  ///
-  /// <b>Note:</b> Because the element model represents the state of the code,
-  /// it is possible for it to be semantically invalid. In particular, it is not
-  /// safe to assume that the inheritance structure of a class does not contain
-  /// a cycle. Clients that traverse the inheritance structure must explicitly
-  /// guard against infinite loops.
-  List<InterfaceType> get interfaces;
-
-  /// Return `true` if this class is abstract. A class is abstract if it has an
-  /// explicit `abstract` modifier or if it is implicitly abstract, such as a
-  /// class defined by a mixin declaration. Note, that this definition of
-  /// <i>abstract</i> is different from <i>has unimplemented members</i>.
-  bool get isAbstract;
-
-  /// Return `true` if this class represents the class 'Enum' defined in the
-  /// dart:core library.
-  bool get isDartCoreEnum;
-
-  /// Return `true` if this class represents the class 'Object' defined in the
-  /// dart:core library.
-  bool get isDartCoreObject;
-
-  /// Return `true` if this class is defined by an enum declaration.
-  bool get isEnum;
-
-  /// Return `true` if this class is defined by a mixin declaration.
-  bool get isMixin;
-
-  /// Return `true` if this class is a mixin application.  A class is a mixin
-  /// application if it was declared using the syntax "class A = B with C;".
-  bool get isMixinApplication;
-
-  /// Return `true` if this class can validly be used as a mixin when defining
-  /// another class. For classes defined by a mixin declaration, the result is
-  /// always `true`. For classes defined by a class declaration or a mixin
-  /// application, the behavior of this method is defined by the Dart Language
-  /// Specification in section 9:
-  /// <blockquote>
-  /// It is a compile-time error if a declared or derived mixin refers to super.
-  /// It is a compile-time error if a declared or derived mixin explicitly
-  /// declares a constructor. It is a compile-time error if a mixin is derived
-  /// from a class whose superclass is not Object.
-  /// </blockquote>
-  bool get isValidMixin;
-
-  /// Return a list containing all of the methods declared in this class.
-  List<MethodElement> get methods;
-
-  /// Return a list containing all of the mixins that are applied to the class
-  /// being extended in order to derive the superclass of this class.
-  ///
-  /// <b>Note:</b> Because the element model represents the state of the code,
-  /// it is possible for it to be semantically invalid. In particular, it is not
-  /// safe to assume that the inheritance structure of a class does not contain
-  /// a cycle. Clients that traverse the inheritance structure must explicitly
-  /// guard against infinite loops.
-  List<InterfaceType> get mixins;
-
-  @override
-  String get name;
-
-  /// Return a list containing all of the superclass constraints defined for
-  /// this class. The list will be empty if this class does not represent a
-  /// mixin declaration. If this class _does_ represent a mixin declaration but
-  /// the declaration does not have an `on` clause, then the list will contain
-  /// the type for the class `Object`.
-  ///
-  /// <b>Note:</b> Because the element model represents the state of the code,
-  /// it is possible for it to be semantically invalid. In particular, it is not
-  /// safe to assume that the inheritance structure of a class does not contain
-  /// a cycle. Clients that traverse the inheritance structure must explicitly
-  /// guard against infinite loops.
-  List<InterfaceType> get superclassConstraints;
+    implements
+        ClassOrAugmentationElement,
+        InterfaceDefiningElement,
+        _TmpSharedClassElement {
+  /// Returns the result of applying augmentations to this class.
+  AugmentedClassElement get augmented;
 
   /// Return the superclass of this class, or `null` if either the class
-  /// represents the class 'Object' or if the class represents a mixin
-  /// declaration. All other classes will have a non-`null` superclass. If the
-  /// superclass was not explicitly declared then the implicit superclass
-  /// 'Object' will be returned.
+  /// represents the class 'Object'. If the superclass was not explicitly
+  /// declared then the implicit superclass 'Object' will be returned.
   ///
   /// <b>Note:</b> Because the element model represents the state of the code,
   /// it is possible for it to be semantically invalid. In particular, it is not
   /// safe to assume that the inheritance structure of a class does not contain
   /// a cycle. Clients that traverse the inheritance structure must explicitly
   /// guard against infinite loops.
+  @override
   InterfaceType? get supertype;
-
-  /// Return the type of `this` expression for this class.
-  ///
-  /// For a class like `class MyClass<T, U> {}` the returned type is equivalent
-  /// to the type `MyClass<T, U>`. So, the type arguments are the types of the
-  /// type parameters, and either `none` or `star` nullability suffix is used
-  /// for the type arguments, and the returned type depending on the
-  /// nullability status of the declaring library.
-  InterfaceType get thisType;
-
-  /// Return the unnamed constructor declared in this class, or `null` if either
-  /// this class does not declare an unnamed constructor but does declare named
-  /// constructors or if this class represents a mixin declaration. The returned
-  /// constructor will be synthetic if this class does not declare any
-  /// constructors, in which case it will represent the default constructor for
-  /// the class.
-  ConstructorElement? get unnamedConstructor;
-
-  /// Return the field (synthetic or explicit) defined in this class that has
-  /// the given [name], or `null` if this class does not define a field with the
-  /// given name.
-  FieldElement? getField(String name);
-
-  /// Return the element representing the getter with the given [name] that is
-  /// declared in this class, or `null` if this class does not declare a getter
-  /// with the given name.
-  PropertyAccessorElement? getGetter(String name);
-
-  /// Return the element representing the method with the given [name] that is
-  /// declared in this class, or `null` if this class does not declare a method
-  /// with the given name.
-  MethodElement? getMethod(String name);
-
-  /// Return the named constructor declared in this class with the given [name],
-  /// or `null` if this class does not declare a named constructor with the
-  /// given name.
-  ConstructorElement? getNamedConstructor(String name);
-
-  /// Return the element representing the setter with the given [name] that is
-  /// declared in this class, or `null` if this class does not declare a setter
-  /// with the given name.
-  PropertyAccessorElement? getSetter(String name);
-
-  /// Create the [InterfaceType] for this class with the given [typeArguments]
-  /// and [nullabilitySuffix].
-  InterfaceType instantiate({
-    required List<DartType> typeArguments,
-    required NullabilitySuffix nullabilitySuffix,
-  });
-
-  /// Return the element representing the method that results from looking up
-  /// the given [methodName] in this class with respect to the given [library],
-  /// ignoring abstract methods, or `null` if the look up fails. The behavior of
-  /// this method is defined by the Dart Language Specification in section
-  /// 16.15.1:
-  /// <blockquote>
-  /// The result of looking up method <i>m</i> in class <i>C</i> with respect to
-  /// library <i>L</i> is: If <i>C</i> declares an instance method named
-  /// <i>m</i> that is accessible to <i>L</i>, then that method is the result of
-  /// the lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the
-  /// result of the lookup is the result of looking up method <i>m</i> in
-  /// <i>S</i> with respect to <i>L</i>. Otherwise, we say that the lookup has
-  /// failed.
-  /// </blockquote>
-  MethodElement? lookUpConcreteMethod(
-      String methodName, LibraryElement library);
-
-  /// Return the element representing the getter that results from looking up
-  /// the given [getterName] in this class with respect to the given [library],
-  /// or `null` if the look up fails. The behavior of this method is defined by
-  /// the Dart Language Specification in section 16.15.2:
-  /// <blockquote>
-  /// The result of looking up getter (respectively setter) <i>m</i> in class
-  /// <i>C</i> with respect to library <i>L</i> is: If <i>C</i> declares an
-  /// instance getter (respectively setter) named <i>m</i> that is accessible to
-  /// <i>L</i>, then that getter (respectively setter) is the result of the
-  /// lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the result
-  /// of the lookup is the result of looking up getter (respectively setter)
-  /// <i>m</i> in <i>S</i> with respect to <i>L</i>. Otherwise, we say that the
-  /// lookup has failed.
-  /// </blockquote>
-  PropertyAccessorElement? lookUpGetter(
-      String getterName, LibraryElement library);
-
-  /// Return the element representing the getter that results from looking up
-  /// the given [getterName] in the superclass of this class with respect to the
-  /// given [library], ignoring abstract getters, or `null` if the look up
-  /// fails.  The behavior of this method is defined by the Dart Language
-  /// Specification in section 16.15.2:
-  /// <blockquote>
-  /// The result of looking up getter (respectively setter) <i>m</i> in class
-  /// <i>C</i> with respect to library <i>L</i> is: If <i>C</i> declares an
-  /// instance getter (respectively setter) named <i>m</i> that is accessible to
-  /// <i>L</i>, then that getter (respectively setter) is the result of the
-  /// lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the result
-  /// of the lookup is the result of looking up getter (respectively setter)
-  /// <i>m</i> in <i>S</i> with respect to <i>L</i>. Otherwise, we say that the
-  /// lookup has failed.
-  /// </blockquote>
-  PropertyAccessorElement? lookUpInheritedConcreteGetter(
-      String getterName, LibraryElement library);
-
-  /// Return the element representing the method that results from looking up
-  /// the given [methodName] in the superclass of this class with respect to the
-  /// given [library], ignoring abstract methods, or `null` if the look up
-  /// fails.  The behavior of this method is defined by the Dart Language
-  /// Specification in section 16.15.1:
-  /// <blockquote>
-  /// The result of looking up method <i>m</i> in class <i>C</i> with respect to
-  /// library <i>L</i> is:  If <i>C</i> declares an instance method named
-  /// <i>m</i> that is accessible to <i>L</i>, then that method is the result of
-  /// the lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the
-  /// result of the lookup is the result of looking up method <i>m</i> in
-  /// <i>S</i> with respect to <i>L</i>. Otherwise, we say that the lookup has
-  /// failed.
-  /// </blockquote>
-  MethodElement? lookUpInheritedConcreteMethod(
-      String methodName, LibraryElement library);
-
-  /// Return the element representing the setter that results from looking up
-  /// the given [setterName] in the superclass of this class with respect to the
-  /// given [library], ignoring abstract setters, or `null` if the look up
-  /// fails.  The behavior of this method is defined by the Dart Language
-  /// Specification in section 16.15.2:
-  /// <blockquote>
-  /// The result of looking up getter (respectively setter) <i>m</i> in class
-  /// <i>C</i> with respect to library <i>L</i> is:  If <i>C</i> declares an
-  /// instance getter (respectively setter) named <i>m</i> that is accessible to
-  /// <i>L</i>, then that getter (respectively setter) is the result of the
-  /// lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the result
-  /// of the lookup is the result of looking up getter (respectively setter)
-  /// <i>m</i> in <i>S</i> with respect to <i>L</i>. Otherwise, we say that the
-  /// lookup has failed.
-  /// </blockquote>
-  PropertyAccessorElement? lookUpInheritedConcreteSetter(
-      String setterName, LibraryElement library);
-
-  /// Return the element representing the method that results from looking up
-  /// the given [methodName] in the superclass of this class with respect to the
-  /// given [library], or `null` if the look up fails. The behavior of this
-  /// method is defined by the Dart Language Specification in section 16.15.1:
-  /// <blockquote>
-  /// The result of looking up method <i>m</i> in class <i>C</i> with respect to
-  /// library <i>L</i> is:  If <i>C</i> declares an instance method named
-  /// <i>m</i> that is accessible to <i>L</i>, then that method is the result of
-  /// the lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the
-  /// result of the lookup is the result of looking up method <i>m</i> in
-  /// <i>S</i> with respect to <i>L</i>. Otherwise, we say that the lookup has
-  /// failed.
-  /// </blockquote>
-  MethodElement? lookUpInheritedMethod(
-      String methodName, LibraryElement library);
-
-  /// Return the element representing the method that results from looking up
-  /// the given [methodName] in this class with respect to the given [library],
-  /// or `null` if the look up fails. The behavior of this method is defined by
-  /// the Dart Language Specification in section 16.15.1:
-  /// <blockquote>
-  /// The result of looking up method <i>m</i> in class <i>C</i> with respect to
-  /// library <i>L</i> is:  If <i>C</i> declares an instance method named
-  /// <i>m</i> that is accessible to <i>L</i>, then that method is the result of
-  /// the lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the
-  /// result of the lookup is the result of looking up method <i>m</i> in
-  /// <i>S</i> with respect to <i>L</i>. Otherwise, we say that the lookup has
-  /// failed.
-  /// </blockquote>
-  MethodElement? lookUpMethod(String methodName, LibraryElement library);
-
-  /// Return the element representing the setter that results from looking up
-  /// the given [setterName] in this class with respect to the given [library],
-  /// or `null` if the look up fails. The behavior of this method is defined by
-  /// the Dart Language Specification in section 16.15.2:
-  /// <blockquote>
-  /// The result of looking up getter (respectively setter) <i>m</i> in class
-  /// <i>C</i> with respect to library <i>L</i> is: If <i>C</i> declares an
-  /// instance getter (respectively setter) named <i>m</i> that is accessible to
-  /// <i>L</i>, then that getter (respectively setter) is the result of the
-  /// lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the result
-  /// of the lookup is the result of looking up getter (respectively setter)
-  /// <i>m</i> in <i>S</i> with respect to <i>L</i>. Otherwise, we say that the
-  /// lookup has failed.
-  /// </blockquote>
-  PropertyAccessorElement? lookUpSetter(
-      String setterName, LibraryElement library);
 }
 
 /// An element that is contained within a [ClassElement].
 ///
-/// When the 'extension-methods' experiment is enabled, these elements can also
-/// be contained within an extension element.
-///
 /// Clients may not extend, implement or mix-in this class.
 abstract class ClassMemberElement implements Element {
   // TODO(brianwilkerson) Either remove this class or rename it to something
@@ -413,6 +233,18 @@
   bool get isStatic;
 }
 
+/// Shared interface between [ClassElement] and [ClassAugmentationElement].
+///
+/// Clients may not extend, implement or mix-in this class.
+@experimental
+abstract class ClassOrAugmentationElement
+    implements InterfaceDefiningOrAugmentationElement {
+  /// The immediate augmentation of this element, or `null` if there are no
+  /// augmentations. [ClassAugmentationElement.augmentationTarget] is the back
+  /// pointer that will point at this element.
+  ClassAugmentationElement? get augmentation;
+}
+
 /// An element representing a compilation unit.
 ///
 /// Clients may not extend, implement or mix-in this class.
@@ -474,12 +306,30 @@
   ClassElement? getType(String name);
 }
 
+/// An element representing a constructor augmentation.
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class ConstructorAugmentationElement implements ConstructorElement {
+  /// Returns the element that is augmented by this augmentation. The chain of
+  /// augmentations should normally end with a [ConstructorElement] that is not
+  /// [ConstructorAugmentationElement], but might end with `null` immediately
+  /// or after a few intermediate [ConstructorAugmentationElement]s in case of
+  /// invalid code when an augmentation is declared without the corresponding
+  /// constructor declaration.
+  ConstructorElement? get augmentationTarget;
+}
+
 /// An element representing a constructor or a factory method defined within a
 /// class.
 ///
 /// Clients may not extend, implement or mix-in this class.
 abstract class ConstructorElement
     implements ClassMemberElement, ExecutableElement, ConstantEvaluationTarget {
+  /// The immediate augmentation of this element, or `null` if there are no
+  /// augmentations. [ConstructorAugmentationElement.augmentationTarget] is
+  /// the back pointer that will point at this element.
+  ConstructorAugmentationElement? get augmentation;
+
   @override
   ConstructorElement get declaration;
 
@@ -1193,6 +1043,48 @@
   R? visitTypeParameterElement(TypeParameterElement element);
 }
 
+/// An enum augmentation, defined by a enum augmentation declaration.
+///
+/// Clients may not extend, implement or mix-in this class.
+@experimental
+abstract class EnumAugmentationElement implements EnumOrAugmentationElement {
+  /// Returns the element that is augmented by this augmentation; or `null` if
+  /// there is no corresponding element to be augmented. The chain of
+  /// augmentations should normally end with a [EnumElement], but might end
+  /// with `null` immediately or after a few intermediate
+  /// [EnumAugmentationElement]s in case of invalid code when an augmentation
+  /// is declared without the corresponding enum declaration.
+  EnumOrAugmentationElement? get augmentationTarget;
+}
+
+/// An element that represents an enum.
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class EnumElement
+    implements
+        EnumOrAugmentationElement,
+        InterfaceDefiningElement,
+        _TmpSharedClassElement {
+  /// Returns the result of applying augmentations to this element.
+  AugmentedEnumElement get augmented;
+
+  /// Returns `Enum` from `dart:core`.
+  @override
+  InterfaceType? get supertype;
+}
+
+/// Shared interface between [EnumElement] and [EnumAugmentationElement].
+///
+/// Clients may not extend, implement or mix-in this class.
+@experimental
+abstract class EnumOrAugmentationElement
+    implements InterfaceDefiningOrAugmentationElement {
+  /// The immediate augmentation of this element, or `null` if there are no
+  /// augmentations. [EnumAugmentationElement.augmentationTarget] is the back
+  /// pointer that will point at this element.
+  EnumAugmentationElement? get augmentation;
+}
+
 /// An element representing an executable object, including functions, methods,
 /// constructors, getters, and setters.
 ///
@@ -1309,14 +1201,29 @@
   PropertyAccessorElement? getSetter(String name);
 }
 
-/// A field defined within a class.
+/// A field augmentation defined within a class.
 ///
-/// When the 'extension-methods' experiment is enabled, these elements can also
-/// be contained within an extension element.
+/// Clients may not extend, implement or mix-in this class.
+abstract class FieldAugmentationElement implements FieldElement {
+  /// Returns the element that is augmented by this augmentation. The chain of
+  /// augmentations should normally end with a [FieldElement] that is not
+  /// [FieldAugmentationElement], but might end with `null` immediately or
+  /// after a few intermediate [FieldAugmentationElement]s in case of invalid
+  /// code when an augmentation is declared without the corresponding field
+  /// declaration.
+  FieldElement? get augmentationTarget;
+}
+
+/// A field defined within a class.
 ///
 /// Clients may not extend, implement or mix-in this class.
 abstract class FieldElement
     implements ClassMemberElement, PropertyInducingElement {
+  /// The immediate augmentation of this element, or `null` if there are no
+  /// augmentations. [FieldAugmentationElement.augmentationTarget] is the
+  /// back pointer that will point at this element.
+  FieldAugmentationElement? get augmentation;
+
   @override
   FieldElement get declaration;
 
@@ -1444,6 +1351,87 @@
   PrefixElement get element;
 }
 
+/// An element that defines an [InterfaceType].
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class InterfaceDefiningElement
+    implements InterfaceDefiningOrAugmentationElement, TypeDefiningElement {
+  /// Return a list containing all the supertypes defined for this element and
+  /// its supertypes. This includes superclasses, mixins, interfaces, and
+  /// superclass constraints.
+  List<InterfaceType> get allSupertypes;
+
+  /// Return the type of `this` expression for this element.
+  ///
+  /// For a class like `class MyClass<T, U> {}` the returned type is equivalent
+  /// to the type `MyClass<T, U>`. So, the type arguments are the types of the
+  /// type parameters, and either `none` or `star` is used for the nullability
+  /// suffix is used, depending on the nullability status of the declaring
+  /// library.
+  InterfaceType get thisType;
+
+  /// Create the [InterfaceType] for this element with the given [typeArguments]
+  /// and [nullabilitySuffix].
+  InterfaceType instantiate({
+    required List<DartType> typeArguments,
+    required NullabilitySuffix nullabilitySuffix,
+  });
+}
+
+/// Shared interface between [InterfaceDefiningElement] and augmentations.
+///
+/// Augmentations of [InterfaceDefiningElement] don't have their own type,
+/// so they cannot by instantiated into an [InterfaceType].
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class InterfaceDefiningOrAugmentationElement
+    implements TypeParameterizedElement {
+  /// Return a list containing all of the accessors (getters and setters)
+  /// declared in this class.
+  List<PropertyAccessorElement> get accessors;
+
+  /// Return a list containing all of the constructors declared in this class.
+  /// The list will be empty if there are no constructors defined for this
+  /// class, as is the case when this element represents an enum or a mixin.
+  List<ConstructorElement> get constructors;
+
+  @Deprecated('Use enclosingElement2 instead')
+  @override
+  CompilationUnitElement get enclosingElement;
+
+  @override
+  CompilationUnitElement get enclosingElement2;
+
+  /// Return a list containing all of the fields declared in this class.
+  List<FieldElement> get fields;
+
+  /// Return a list containing all of the interfaces that are implemented by
+  /// this class.
+  ///
+  /// <b>Note:</b> Because the element model represents the state of the code,
+  /// it is possible for it to be semantically invalid. In particular, it is not
+  /// safe to assume that the inheritance structure of a class does not contain
+  /// a cycle. Clients that traverse the inheritance structure must explicitly
+  /// guard against infinite loops.
+  List<InterfaceType> get interfaces;
+
+  /// Return a list containing all of the methods declared in this class.
+  List<MethodElement> get methods;
+
+  /// Return a list containing all of the mixins that are applied to the class
+  /// being extended in order to derive the superclass of this class.
+  ///
+  /// <b>Note:</b> Because the element model represents the state of the code,
+  /// it is possible for it to be semantically invalid. In particular, it is not
+  /// safe to assume that the inheritance structure of a class does not contain
+  /// a cycle. Clients that traverse the inheritance structure must explicitly
+  /// guard against infinite loops.
+  List<InterfaceType> get mixins;
+
+  @override
+  String get name;
+}
+
 /// A label associated with a statement.
 ///
 /// Clients may not extend, implement or mix-in this class.
@@ -1700,17 +1688,82 @@
   String get name;
 }
 
-/// An element that represents a method defined within a class.
+/// An element that represents a method augmentation defined within a class.
 ///
-/// When the 'extension-methods' experiment is enabled, these elements can also
-/// be contained within an extension element.
+/// Clients may not extend, implement or mix-in this class.
+abstract class MethodAugmentationElement implements MethodElement {
+  /// Returns the element that is augmented by this augmentation. The chain of
+  /// augmentations should normally end with a [MethodElement] that is not
+  /// [MethodAugmentationElement], but might end with `null` immediately or
+  /// after a few intermediate [MethodAugmentationElement]s in case of invalid
+  /// code when an augmentation is declared without the corresponding method
+  /// declaration.
+  MethodElement? get augmentationTarget;
+}
+
+/// An element that represents a method defined within a class.
 ///
 /// Clients may not extend, implement or mix-in this class.
 abstract class MethodElement implements ClassMemberElement, ExecutableElement {
+  /// The immediate augmentation of this element, or `null` if there are no
+  /// augmentations. [MethodAugmentationElement.augmentationTarget] is the
+  /// back pointer that will point at this element.
+  MethodAugmentationElement? get augmentation;
+
   @override
   MethodElement get declaration;
 }
 
+/// A class augmentation, defined by a mixin augmentation declaration.
+///
+/// Clients may not extend, implement or mix-in this class.
+@experimental
+abstract class MixinAugmentationElement implements MixinOrAugmentationElement {
+  /// Returns the element that is augmented by this augmentation; or `null` if
+  /// there is no corresponding element to be augmented. The chain of
+  /// augmentations should normally end with a [MixinElement], but might end
+  /// with `null` immediately or after a few intermediate
+  /// [MixinAugmentationElement]s in case of invalid code when an augmentation
+  /// is declared without the corresponding class declaration.
+  MixinOrAugmentationElement? get augmentationTarget;
+}
+
+/// An element that represents a mixin.
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class MixinElement
+    implements
+        MixinOrAugmentationElement,
+        InterfaceDefiningElement,
+        _TmpSharedClassElement {
+  /// Returns the result of applying augmentations to this element.
+  AugmentedMixinElement get augmented;
+
+  /// Returns the superclass constraints defined for this mixin. If the
+  /// declaration does not have an `on` clause, then the list will contain
+  /// the type for the class `Object`.
+  ///
+  /// <b>Note:</b> Because the element model represents the state of the code,
+  /// it is possible for it to be semantically invalid. In particular, it is not
+  /// safe to assume that the inheritance structure of a class does not contain
+  /// a cycle. Clients that traverse the inheritance structure must explicitly
+  /// guard against infinite loops.
+  @override
+  List<InterfaceType> get superclassConstraints;
+}
+
+/// Shared interface between [MixinElement] and [MixinAugmentationElement].
+///
+/// Clients may not extend, implement or mix-in this class.
+@experimental
+abstract class MixinOrAugmentationElement
+    implements InterfaceDefiningOrAugmentationElement {
+  /// The immediate augmentation of this element, or `null` if there are no
+  /// augmentations. [MixinAugmentationElement.augmentationTarget] is the back
+  /// pointer that will point at this element.
+  MixinAugmentationElement? get augmentation;
+}
+
 /// A pseudo-element that represents multiple elements defined within a single
 /// scope that have the same name. This situation is not allowed by the
 /// language, so objects implementing this interface always represent an error.
@@ -1893,6 +1946,21 @@
   String get name;
 }
 
+/// Augmentation of a [PropertyAccessorElement].
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class PropertyAccessorAugmentationElement
+    implements PropertyAccessorElement {
+  /// Returns the element that is augmented by this augmentation. The chain of
+  /// augmentations should normally end with a [PropertyAccessorElement] that
+  /// is not [PropertyAccessorAugmentationElement], but might end with `null`
+  /// immediately or after a few intermediate
+  /// [PropertyAccessorAugmentationElement]s in case of invalid code when an
+  /// augmentation is declared without the corresponding property accessor
+  /// declaration.
+  PropertyAccessorElement? get augmentationTarget;
+}
+
 /// A getter or a setter. Note that explicitly defined property accessors
 /// implicitly define a synthetic field. Symmetrically, synthetic accessors are
 /// implicitly created for explicitly defined fields. The following rules apply:
@@ -1907,6 +1975,11 @@
 ///
 /// Clients may not extend, implement or mix-in this class.
 abstract class PropertyAccessorElement implements ExecutableElement {
+  /// The immediate augmentation of this element, or `null` if there are no
+  /// augmentations. [PropertyAccessorAugmentationElement.augmentationTarget]
+  /// is the back pointer that will point at this element.
+  PropertyAccessorAugmentationElement? get augmentation;
+
   /// Return the accessor representing the getter that corresponds to (has the
   /// same name as) this setter, or `null` if this accessor is not a setter or
   /// if there is no corresponding getter.
@@ -2206,3 +2279,255 @@
   @override
   Source get source;
 }
+
+/// Properties that existed in [ClassElement], so we should keep them for
+/// backward compatibility for now. But we want them to be either moved, or
+/// removed.
+abstract class _TmpSharedClassElement {
+  /// Return `true` if this class or its superclass declares a non-final
+  /// instance field.
+  bool get hasNonFinalField;
+
+  /// Return `true` if this class declares a static member.
+  bool get hasStaticMember;
+
+  /// Return `true` if this class is abstract. A class is abstract if it has an
+  /// explicit `abstract` modifier or if it is implicitly abstract, such as a
+  /// class defined by a mixin declaration. Note, that this definition of
+  /// <i>abstract</i> is different from <i>has unimplemented members</i>.
+  /// TODO(scheglov) Deprecate and replace it.
+  bool get isAbstract;
+
+  /// Return `true` if this class represents the class 'Enum' defined in the
+  /// dart:core library.
+  bool get isDartCoreEnum;
+
+  /// Return `true` if this class represents the class 'Object' defined in the
+  /// dart:core library.
+  bool get isDartCoreObject;
+
+  /// Return `true` if this class is defined by an enum declaration.
+  bool get isEnum;
+
+  /// Return `true` if this class is defined by a mixin declaration.
+  bool get isMixin;
+
+  /// Return `true` if this class is a mixin application.  A class is a mixin
+  /// application if it was declared using the syntax "class A = B with C;".
+  bool get isMixinApplication;
+
+  /// Return `true` if this class can validly be used as a mixin when defining
+  /// another class. For classes defined by a mixin declaration, the result is
+  /// always `true`. For classes defined by a class declaration or a mixin
+  /// application, the behavior of this method is defined by the Dart Language
+  /// Specification in section 9:
+  /// <blockquote>
+  /// It is a compile-time error if a declared or derived mixin refers to super.
+  /// It is a compile-time error if a declared or derived mixin explicitly
+  /// declares a constructor. It is a compile-time error if a mixin is derived
+  /// from a class whose superclass is not Object.
+  /// </blockquote>
+  /// TODO(scheglov) Deprecate and remove it.
+  bool get isValidMixin;
+
+  /// Return a list containing all of the superclass constraints defined for
+  /// this class. The list will be empty if this class does not represent a
+  /// mixin declaration. If this class _does_ represent a mixin declaration but
+  /// the declaration does not have an `on` clause, then the list will contain
+  /// the type for the class `Object`.
+  ///
+  /// <b>Note:</b> Because the element model represents the state of the code,
+  /// it is possible for it to be semantically invalid. In particular, it is not
+  /// safe to assume that the inheritance structure of a class does not contain
+  /// a cycle. Clients that traverse the inheritance structure must explicitly
+  /// guard against infinite loops.
+  /// TODO(scheglov) Deprecate and remove it.
+  List<InterfaceType> get superclassConstraints;
+
+  /// Return the superclass of this class, or `null` if either the class
+  /// represents the class 'Object' or if the class represents a mixin
+  /// declaration. All other classes will have a non-`null` superclass. If the
+  /// superclass was not explicitly declared then the implicit superclass
+  /// 'Object' will be returned.
+  ///
+  /// <b>Note:</b> Because the element model represents the state of the code,
+  /// it is possible for it to be semantically invalid. In particular, it is not
+  /// safe to assume that the inheritance structure of a class does not contain
+  /// a cycle. Clients that traverse the inheritance structure must explicitly
+  /// guard against infinite loops.
+  InterfaceType? get supertype;
+
+  /// Returns the unnamed constructor declared directly in this class. If the
+  /// class does not declare any constructors, a synthetic default constructor
+  /// will be returned.
+  /// TODO(scheglov) Deprecate and remove it.
+  ConstructorElement? get unnamedConstructor;
+
+  /// Returns the field (synthetic or explicit) defined directly in this
+  /// class or augmentation that has the given [name].
+  /// TODO(scheglov) Deprecate and remove it.
+  FieldElement? getField(String name);
+
+  /// Returns the getter (synthetic or explicit) defined directly in this
+  /// class or augmentation that has the given [name].
+  /// TODO(scheglov) Deprecate and remove it.
+  PropertyAccessorElement? getGetter(String name);
+
+  /// Returns the method defined directly in this class or augmentation that
+  /// has the given [name].
+  /// TODO(scheglov) Deprecate and remove it.
+  MethodElement? getMethod(String name);
+
+  /// Returns the constructor defined directly in this class or augmentation
+  /// that has the given [name].
+  /// TODO(scheglov) Deprecate and remove it.
+  ConstructorElement? getNamedConstructor(String name);
+
+  /// Returns the setter (synthetic or explicit) defined directly in this
+  /// class or augmentation that has the given [name].
+  /// TODO(scheglov) Deprecate and remove it.
+  PropertyAccessorElement? getSetter(String name);
+
+  /// Return the element representing the method that results from looking up
+  /// the given [methodName] in this class with respect to the given [library],
+  /// ignoring abstract methods, or `null` if the look up fails. The behavior of
+  /// this method is defined by the Dart Language Specification in section
+  /// 16.15.1:
+  /// <blockquote>
+  /// The result of looking up method <i>m</i> in class <i>C</i> with respect to
+  /// library <i>L</i> is: If <i>C</i> declares an instance method named
+  /// <i>m</i> that is accessible to <i>L</i>, then that method is the result of
+  /// the lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the
+  /// result of the lookup is the result of looking up method <i>m</i> in
+  /// <i>S</i> with respect to <i>L</i>. Otherwise, we say that the lookup has
+  /// failed.
+  /// </blockquote>
+  /// TODO(scheglov) Deprecate and remove it.
+  MethodElement? lookUpConcreteMethod(
+      String methodName, LibraryElement library);
+
+  /// Return the element representing the getter that results from looking up
+  /// the given [getterName] in this class with respect to the given [library],
+  /// or `null` if the look up fails. The behavior of this method is defined by
+  /// the Dart Language Specification in section 16.15.2:
+  /// <blockquote>
+  /// The result of looking up getter (respectively setter) <i>m</i> in class
+  /// <i>C</i> with respect to library <i>L</i> is: If <i>C</i> declares an
+  /// instance getter (respectively setter) named <i>m</i> that is accessible to
+  /// <i>L</i>, then that getter (respectively setter) is the result of the
+  /// lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the result
+  /// of the lookup is the result of looking up getter (respectively setter)
+  /// <i>m</i> in <i>S</i> with respect to <i>L</i>. Otherwise, we say that the
+  /// lookup has failed.
+  /// </blockquote>
+  /// TODO(scheglov) Deprecate and remove it.
+  PropertyAccessorElement? lookUpGetter(
+      String getterName, LibraryElement library);
+
+  /// Return the element representing the getter that results from looking up
+  /// the given [getterName] in the superclass of this class with respect to the
+  /// given [library], ignoring abstract getters, or `null` if the look up
+  /// fails.  The behavior of this method is defined by the Dart Language
+  /// Specification in section 16.15.2:
+  /// <blockquote>
+  /// The result of looking up getter (respectively setter) <i>m</i> in class
+  /// <i>C</i> with respect to library <i>L</i> is: If <i>C</i> declares an
+  /// instance getter (respectively setter) named <i>m</i> that is accessible to
+  /// <i>L</i>, then that getter (respectively setter) is the result of the
+  /// lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the result
+  /// of the lookup is the result of looking up getter (respectively setter)
+  /// <i>m</i> in <i>S</i> with respect to <i>L</i>. Otherwise, we say that the
+  /// lookup has failed.
+  /// </blockquote>
+  /// TODO(scheglov) Deprecate and remove it.
+  PropertyAccessorElement? lookUpInheritedConcreteGetter(
+      String getterName, LibraryElement library);
+
+  /// Return the element representing the method that results from looking up
+  /// the given [methodName] in the superclass of this class with respect to the
+  /// given [library], ignoring abstract methods, or `null` if the look up
+  /// fails.  The behavior of this method is defined by the Dart Language
+  /// Specification in section 16.15.1:
+  /// <blockquote>
+  /// The result of looking up method <i>m</i> in class <i>C</i> with respect to
+  /// library <i>L</i> is:  If <i>C</i> declares an instance method named
+  /// <i>m</i> that is accessible to <i>L</i>, then that method is the result of
+  /// the lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the
+  /// result of the lookup is the result of looking up method <i>m</i> in
+  /// <i>S</i> with respect to <i>L</i>. Otherwise, we say that the lookup has
+  /// failed.
+  /// </blockquote>
+  /// TODO(scheglov) Deprecate and remove it.
+  MethodElement? lookUpInheritedConcreteMethod(
+      String methodName, LibraryElement library);
+
+  /// Return the element representing the setter that results from looking up
+  /// the given [setterName] in the superclass of this class with respect to the
+  /// given [library], ignoring abstract setters, or `null` if the look up
+  /// fails.  The behavior of this method is defined by the Dart Language
+  /// Specification in section 16.15.2:
+  /// <blockquote>
+  /// The result of looking up getter (respectively setter) <i>m</i> in class
+  /// <i>C</i> with respect to library <i>L</i> is:  If <i>C</i> declares an
+  /// instance getter (respectively setter) named <i>m</i> that is accessible to
+  /// <i>L</i>, then that getter (respectively setter) is the result of the
+  /// lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the result
+  /// of the lookup is the result of looking up getter (respectively setter)
+  /// <i>m</i> in <i>S</i> with respect to <i>L</i>. Otherwise, we say that the
+  /// lookup has failed.
+  /// </blockquote>
+  /// TODO(scheglov) Deprecate and remove it.
+  PropertyAccessorElement? lookUpInheritedConcreteSetter(
+      String setterName, LibraryElement library);
+
+  /// Return the element representing the method that results from looking up
+  /// the given [methodName] in the superclass of this class with respect to the
+  /// given [library], or `null` if the look up fails. The behavior of this
+  /// method is defined by the Dart Language Specification in section 16.15.1:
+  /// <blockquote>
+  /// The result of looking up method <i>m</i> in class <i>C</i> with respect to
+  /// library <i>L</i> is:  If <i>C</i> declares an instance method named
+  /// <i>m</i> that is accessible to <i>L</i>, then that method is the result of
+  /// the lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the
+  /// result of the lookup is the result of looking up method <i>m</i> in
+  /// <i>S</i> with respect to <i>L</i>. Otherwise, we say that the lookup has
+  /// failed.
+  /// </blockquote>
+  /// TODO(scheglov) Deprecate and remove it.
+  MethodElement? lookUpInheritedMethod(
+      String methodName, LibraryElement library);
+
+  /// Return the element representing the method that results from looking up
+  /// the given [methodName] in this class with respect to the given [library],
+  /// or `null` if the look up fails. The behavior of this method is defined by
+  /// the Dart Language Specification in section 16.15.1:
+  /// <blockquote>
+  /// The result of looking up method <i>m</i> in class <i>C</i> with respect to
+  /// library <i>L</i> is:  If <i>C</i> declares an instance method named
+  /// <i>m</i> that is accessible to <i>L</i>, then that method is the result of
+  /// the lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the
+  /// result of the lookup is the result of looking up method <i>m</i> in
+  /// <i>S</i> with respect to <i>L</i>. Otherwise, we say that the lookup has
+  /// failed.
+  /// </blockquote>
+  /// TODO(scheglov) Deprecate and remove it.
+  MethodElement? lookUpMethod(String methodName, LibraryElement library);
+
+  /// Return the element representing the setter that results from looking up
+  /// the given [setterName] in this class with respect to the given [library],
+  /// or `null` if the look up fails. The behavior of this method is defined by
+  /// the Dart Language Specification in section 16.15.2:
+  /// <blockquote>
+  /// The result of looking up getter (respectively setter) <i>m</i> in class
+  /// <i>C</i> with respect to library <i>L</i> is: If <i>C</i> declares an
+  /// instance getter (respectively setter) named <i>m</i> that is accessible to
+  /// <i>L</i>, then that getter (respectively setter) is the result of the
+  /// lookup. Otherwise, if <i>C</i> has a superclass <i>S</i>, then the result
+  /// of the lookup is the result of looking up getter (respectively setter)
+  /// <i>m</i> in <i>S</i> with respect to <i>L</i>. Otherwise, we say that the
+  /// lookup has failed.
+  /// </blockquote>
+  /// TODO(scheglov) Deprecate and remove it.
+  PropertyAccessorElement? lookUpSetter(
+      String setterName, LibraryElement library);
+}
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index c36fadc..3818634 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -117,13 +117,6 @@
 
     var node = NodeLocator(offset).searchWithin(parsedUnit);
 
-    if (_hasEmptyCompletionContext(node)) {
-      return AnalysisForCompletionResult(
-        parsedUnit: parsedUnit,
-        resolvedNodes: [],
-      );
-    }
-
     var errorListener = RecordingErrorListener();
 
     return performance.run('resolve', (performance) {
@@ -1011,81 +1004,6 @@
       ...dependenciesFinder.dependencies,
     ];
   }
-
-  static bool _hasEmptyCompletionContext(AstNode? node) {
-    if (node is DoubleLiteral || node is IntegerLiteral) {
-      return true;
-    }
-
-    if (node is SimpleIdentifier) {
-      var parent = node.parent;
-
-      if (parent is ConstructorDeclaration && parent.name == node) {
-        return true;
-      }
-
-      if (parent is ConstructorFieldInitializer && parent.fieldName == node) {
-        return true;
-      }
-
-      if (parent is FormalParameter && parent.identifier == node) {
-        // We use elements to access fields.
-        if (parent is FieldFormalParameter) {
-          return false;
-        }
-        // We use elements to access the enclosing constructor.
-        if (parent is SuperFormalParameter) {
-          return false;
-        }
-        // We have a contributor that looks at the type, but it is syntactic.
-        return true;
-      }
-
-      if (parent is FunctionDeclaration && parent.name == node) {
-        return true;
-      }
-
-      if (parent is MethodDeclaration && parent.name == node) {
-        return true;
-      }
-
-      // The name of a NamedType does not provide any context.
-      // So, we don't need to resolve anything.
-      if (parent is NamedType) {
-        var parent3 = parent.parent?.parent;
-        // `class A {foo^ int bar = 0;}` looks as `class A {foo int; bar = 0;}`.
-        if (parent3 is FieldDeclaration) {
-          return false;
-        }
-        // `{foo^ print(0);}` looks as `foo print; (0);`.
-        if (parent3 is VariableDeclarationStatement &&
-            parent3.semicolon.isSynthetic) {
-          return false;
-        }
-        return true;
-      }
-
-      if (parent is TypeParameter && parent.name == node) {
-        return true;
-      }
-
-      // We have a contributor that looks at the type, but it is syntactic.
-      if (parent is VariableDeclaration && parent.name == node) {
-        final parent2 = parent.parent;
-        final parent3 = parent2?.parent;
-        // `class A { foo^ }` looks like `class A { <noType> foo; }`.
-        if (parent2 is VariableDeclarationList &&
-            parent2.type == null &&
-            parent3 is FieldDeclaration &&
-            parent3.semicolon.isSynthetic) {
-          return false;
-        }
-        return true;
-      }
-    }
-
-    return false;
-  }
 }
 
 /// Analysis result for single file.
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index af9564a..437d67b 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -610,6 +610,18 @@
   }
 
   @override
+  ClassAugmentationElement? get augmentation {
+    // TODO(scheglov) implement
+    throw UnimplementedError();
+  }
+
+  @override
+  AugmentedClassElement get augmented {
+    // TODO(scheglov) implement
+    throw UnimplementedError();
+  }
+
+  @override
   List<ConstructorElement> get constructors {
     if (!identical(_constructors, _Sentinel.constructorElement)) {
       return _constructors;
@@ -1363,6 +1375,12 @@
   /// and [offset].
   ConstructorElementImpl(super.name, super.offset);
 
+  @override
+  ConstructorAugmentationElement? get augmentation {
+    // TODO(scheglov) implement
+    throw UnimplementedError();
+  }
+
   /// Return the constant initializers for this element, which will be empty if
   /// there are no initializers, or `null` if there was an error in the source.
   List<ConstructorInitializer> get constantInitializers {
@@ -2868,7 +2886,7 @@
 }
 
 /// An [AbstractClassElementImpl] which is an enum.
-class EnumElementImpl extends AbstractClassElementImpl {
+class EnumElementImpl extends AbstractClassElementImpl implements EnumElement {
   ElementLinkedData? linkedData;
   List<ConstructorElement> _constructors = _Sentinel.constructorElement;
 
@@ -2881,6 +2899,18 @@
     return _accessors;
   }
 
+  @override
+  Never get augmentation {
+    // TODO(scheglov) implement
+    throw UnimplementedError();
+  }
+
+  @override
+  Never get augmented {
+    // TODO(scheglov) implement
+    throw UnimplementedError();
+  }
+
   List<FieldElement> get constants {
     return fields.where((field) => field.isEnumConstant).toList();
   }
@@ -3453,6 +3483,12 @@
   FieldElementImpl(super.name, super.offset);
 
   @override
+  FieldAugmentationElement? get augmentation {
+    // TODO(scheglov) implement
+    throw UnimplementedError();
+  }
+
+  @override
   FieldElement get declaration => this;
 
   @override
@@ -4751,6 +4787,12 @@
   MethodElementImpl(super.name, super.offset);
 
   @override
+  MethodAugmentationElement? get augmentation {
+    // TODO(scheglov) implement
+    throw UnimplementedError();
+  }
+
+  @override
   MethodElement get declaration => prototype ?? this;
 
   @override
@@ -4805,7 +4847,7 @@
 }
 
 /// A [ClassElementImpl] representing a mixin declaration.
-class MixinElementImpl extends ClassElementImpl {
+class MixinElementImpl extends ClassElementImpl implements MixinElement {
   // TODO(brianwilkerson) Consider creating an abstract superclass of
   // ClassElementImpl that contains the portions of the API that this class
   // needs, and make this class extend the new class.
@@ -4822,6 +4864,18 @@
   MixinElementImpl(super.name, super.offset);
 
   @override
+  Never get augmentation {
+    // TODO(scheglov) implement
+    throw UnimplementedError();
+  }
+
+  @override
+  Never get augmented {
+    // TODO(scheglov) implement
+    throw UnimplementedError();
+  }
+
+  @override
   bool get isAbstract => true;
 
   @override
@@ -5640,6 +5694,12 @@
   }
 
   @override
+  PropertyAccessorAugmentationElement? get augmentation {
+    // TODO(scheglov) implement
+    throw UnimplementedError();
+  }
+
+  @override
   PropertyAccessorElement? get correspondingGetter {
     if (isGetter) {
       return null;
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index 28785d5..242170d 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -32,6 +32,12 @@
             const <TypeParameterElement>[]);
 
   @override
+  ConstructorAugmentationElement? get augmentation {
+    // TODO(scheglov) implement
+    throw UnimplementedError();
+  }
+
+  @override
   ConstructorElement get declaration => super.declaration as ConstructorElement;
 
   @override
@@ -331,6 +337,12 @@
   );
 
   @override
+  FieldAugmentationElement? get augmentation {
+    // TODO(scheglov) implement
+    throw UnimplementedError();
+  }
+
+  @override
   FieldElement get declaration => super.declaration as FieldElement;
 
   @override
@@ -779,6 +791,12 @@
   );
 
   @override
+  MethodAugmentationElement? get augmentation {
+    // TODO(scheglov) implement
+    throw UnimplementedError();
+  }
+
+  @override
   MethodElement get declaration => super.declaration as MethodElement;
 
   @Deprecated('Use enclosingElement2 instead')
@@ -985,6 +1003,12 @@
   );
 
   @override
+  PropertyAccessorAugmentationElement? get augmentation {
+    // TODO(scheglov) implement
+    throw UnimplementedError();
+  }
+
+  @override
   PropertyAccessorElement? get correspondingGetter {
     var baseGetter = declaration.correspondingGetter;
     if (baseGetter == null) {
diff --git a/pkg/analyzer/lib/src/error/best_practices_verifier.dart b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
index cd17032..ec868b6 100644
--- a/pkg/analyzer/lib/src/error/best_practices_verifier.dart
+++ b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
@@ -190,13 +190,19 @@
       }
     } else if (element.isMustBeOverridden) {
       if ((parent is MethodDeclaration && parent.isStatic) ||
-          (parent is FieldDeclaration && parent.isStatic)) {
+          (parent is FieldDeclaration && parent.isStatic) ||
+          parent.parent is ExtensionDeclaration ||
+          parent.parent is EnumDeclaration) {
         _errorReporter.reportErrorForNode(
           HintCode.INVALID_ANNOTATION_TARGET,
           node,
           [node.name.name, 'instance members of classes and mixins'],
         );
-      } else if (parent.parent is ExtensionDeclaration ||
+      }
+    } else if (element.isMustCallSuper) {
+      if ((parent is MethodDeclaration && parent.isStatic) ||
+          (parent is FieldDeclaration && parent.isStatic) ||
+          parent.parent is ExtensionDeclaration ||
           parent.parent is EnumDeclaration) {
         _errorReporter.reportErrorForNode(
           HintCode.INVALID_ANNOTATION_TARGET,
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_packages.dart b/pkg/analyzer/lib/src/test_utilities/mock_packages.dart
index 05d9022..d6c64be 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_packages.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_packages.dart
@@ -179,6 +179,12 @@
   const _MustBeOverridden();
 }
 
+@Target({
+  TargetKind.field,
+  TargetKind.getter,
+  TargetKind.method,
+  TargetKind.setter,
+})
 class _MustCallSuper {
   const _MustCallSuper();
 }
diff --git a/pkg/analyzer/test/src/dart/analysis/resolve_for_completion_test.dart b/pkg/analyzer/test/src/dart/analysis/resolve_for_completion_test.dart
index a9deb63..5bf59c1 100644
--- a/pkg/analyzer/test/src/dart/analysis/resolve_for_completion_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/resolve_for_completion_test.dart
@@ -22,32 +22,6 @@
     return driverFor(testFile);
   }
 
-  test_class__fieldDeclaration_type_namedType_name() async {
-    var result = await _resolveTestCode(r'''
-class A {
-  var f1 = 0;
-  dou^ f2 = null;
-  var f3 = 1;
-}
-''');
-
-    result.assertResolvedNodes([
-      'dou f2 = null;',
-    ]);
-  }
-
-  test_class__fieldDeclaration_type_namedType_typeArgument_name() async {
-    var result = await _resolveTestCode(r'''
-class A {
-  var f1 = 0;
-  List<doub^>? f2 = null;
-  var f3 = 1;
-}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
   test_class_body_identifier_beforeFieldDeclaration() async {
     var result = await _resolveTestCode(r'''
 class A {
@@ -61,14 +35,6 @@
     ]);
   }
 
-  test_class_extends_name() async {
-    var result = await _resolveTestCode(r'''
-class A extends foo^ {}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
   test_class_fieldDeclaration_initializer() async {
     var result = await _resolveTestCode(r'''
 class A {
@@ -83,12 +49,18 @@
     ]);
   }
 
-  test_class_implements_name() async {
+  test_class_fieldDeclaration_type_namedType_name() async {
     var result = await _resolveTestCode(r'''
-class A implements foo^ {}
+class A {
+  var f1 = 0;
+  dou^ f2 = null;
+  var f3 = 1;
+}
 ''');
 
-    result.assertResolvedNodes([]);
+    result.assertResolvedNodes([
+      'dou f2 = null;',
+    ]);
   }
 
   test_class_methodDeclaration_body() async {
@@ -113,36 +85,6 @@
     ]);
   }
 
-  test_class_methodDeclaration_name() async {
-    var result = await _resolveTestCode(r'''
-class A {
-  void foo^() {
-    print(0);
-  }
-}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
-  test_class_methodDeclaration_returnType_name() async {
-    var result = await _resolveTestCode(r'''
-class A {
-  doub^ foo() {}
-}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
-  test_class_with_name() async {
-    var result = await _resolveTestCode(r'''
-class A with foo^ {}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
   test_classDeclaration_body_identifier() async {
     var result = await _resolveTestCode(r'''
 class A {}
@@ -194,26 +136,6 @@
     ]);
   }
 
-  test_constructorDeclaration_fieldInitializer_name() async {
-    var result = await _resolveTestCode(r'''
-class A {}
-
-class B {
-  var f;
-
-  void foo1() {}
-
-  B(int a) : bar^ = 0 {
-    print(0);
-  }
-
-  void foo2() {}
-}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
   test_constructorDeclaration_fieldInitializer_value() async {
     var result = await _resolveTestCode(r'''
 class A {
@@ -231,18 +153,6 @@
     ]);
   }
 
-  test_constructorDeclaration_name() async {
-    var result = await _resolveTestCode(r'''
-class A {
-  A.foo^() {
-    print(0);
-  }
-}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
   test_constructorDeclaration_superFormalParameter_name() async {
     var result = await _resolveTestCode(r'''
 class A {
@@ -260,14 +170,6 @@
     ]);
   }
 
-  test_doubleLiteral() async {
-    var result = await _resolveTestCode(r'''
-var v = 1.2^;
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
   test_extension_methodDeclaration_body() async {
     var result = await _resolveTestCode(r'''
 extension E on int {
@@ -288,38 +190,6 @@
     ]);
   }
 
-  test_extension_methodDeclaration_name() async {
-    var result = await _resolveTestCode(r'''
-extension E on int {
-  void foo^() {
-    print(0);
-  }
-}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
-  test_extension_methodDeclaration_returnType_name() async {
-    var result = await _resolveTestCode(r'''
-extension E on int {
-  doub^ foo() {}
-}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
-  test_extension_on_name() async {
-    var result = await _resolveTestCode(r'''
-extension E on int^ {
-  void foo() {}
-}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
   test_functionDeclaration_body() async {
     var result = await _resolveTestCode(r'''
 void foo1() {}
@@ -356,24 +226,6 @@
     ]);
   }
 
-  test_functionDeclaration_name() async {
-    var result = await _resolveTestCode(r'''
-void foo^() {
-  print(0);
-}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
-  test_functionDeclaration_returnType_name() async {
-    var result = await _resolveTestCode(r'''
-doub^ f() {}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
   test_importDirective_show_name() async {
     var result = await _resolveTestCode(r'''
 import 'dart:async';
@@ -398,42 +250,6 @@
     ]);
   }
 
-  test_integerLiteral() async {
-    var result = await _resolveTestCode(r'''
-var v = 0^;
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
-  test_localVariableDeclaration_name() async {
-    var result = await _resolveTestCode(r'''
-void f() {
-  var foo^
-}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
-  test_localVariableDeclaration_type_name() async {
-    var result = await _resolveTestCode(r'''
-void f() {
-  doub^ a;
-}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
-  test_mixin_implements_name() async {
-    var result = await _resolveTestCode(r'''
-mixin M implements foo^ {}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
   test_mixin_methodDeclaration_body() async {
     var result = await _resolveTestCode(r'''
 class A {}
@@ -456,36 +272,6 @@
     ]);
   }
 
-  test_mixin_methodDeclaration_name() async {
-    var result = await _resolveTestCode(r'''
-mixin M {
-  void foo^() {
-    print(0);
-  }
-}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
-  test_mixin_methodDeclaration_returnType_name() async {
-    var result = await _resolveTestCode(r'''
-mixin M {
-  doub^ foo() {}
-}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
-  test_mixin_on_name() async {
-    var result = await _resolveTestCode(r'''
-mixin M on foo^ {}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
   test_processPendingChanges() async {
     addTestFile('class A {}');
 
@@ -503,22 +289,6 @@
     ]);
   }
 
-  test_simpleFormalParameter_name() async {
-    var result = await _resolveTestCode(r'''
-void f(doub^) {}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
-  test_simpleFormalParameter_type_name() async {
-    var result = await _resolveTestCode(r'''
-void f(doub^ a) {}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
   test_topLevelVariable_initializer() async {
     var result = await _resolveTestCode(r'''
 var v1 = 0;
@@ -531,36 +301,6 @@
     ]);
   }
 
-  test_topLevelVariable_name() async {
-    var result = await _resolveTestCode(r'''
-var v1 = 0;
-var v2^
-var v3 = 0;
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
-  test_topLevelVariable_type_namedType_name() async {
-    var result = await _resolveTestCode(r'''
-var v1 = 0;
-doub^ v2 = null;
-var v3 = 1;
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
-  test_topLevelVariable_type_namedType_typeArgument_name() async {
-    var result = await _resolveTestCode(r'''
-var v1 = 0;
-List<doub^>? v2 = null;
-var v3 = 1;
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
   test_typedef_name_nothing() async {
     var result = await _resolveTestCode(r'''
 typedef F^
@@ -569,16 +309,6 @@
     _assertWholeUnitResolved(result);
   }
 
-  test_typeParameter_name() async {
-    var result = await _resolveTestCode(r'''
-void f<T^>() {
-  print(0);
-}
-''');
-
-    result.assertResolvedNodes([]);
-  }
-
   int _newFileWithOffset(String path, String content) {
     var offset = content.indexOf('^');
     expect(offset, isNot(equals(-1)), reason: 'missing ^');
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_annotation_target_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_annotation_target_test.dart
index dd7c738..9923146 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_annotation_target_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_annotation_target_test.dart
@@ -10,6 +10,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(InvalidAnnotationTarget_MustBeOverriddenTest);
+    defineReflectiveTests(InvalidAnnotationTarget_MustCallSuperTest);
     defineReflectiveTests(InvalidAnnotationTargetTest);
   });
 }
@@ -179,6 +180,170 @@
 }
 
 @reflectiveTest
+class InvalidAnnotationTarget_MustCallSuperTest
+    extends PubPackageResolutionTest {
+  @override
+  void setUp() {
+    super.setUp();
+    writeTestPackageConfigWithMeta();
+  }
+
+  test_class_instance_field() async {
+    await assertNoErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+class A {
+  @mustCallSuper
+  int f = 0;
+}
+''');
+  }
+
+  test_class_instance_getter() async {
+    await assertNoErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+class A {
+  @mustCallSuper
+  int get f => 0;
+}
+''');
+  }
+
+  test_class_instance_method() async {
+    await assertNoErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+class A {
+  @mustCallSuper
+  void m() {}
+}
+''');
+  }
+
+  test_class_instance_setter() async {
+    await assertNoErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+class A {
+  @mustCallSuper
+  void set s(int value) {}
+}
+''');
+  }
+
+  test_class_static_field() async {
+    await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+class A {
+  @mustCallSuper
+  static int f = 0;
+}
+''', [
+      error(HintCode.INVALID_ANNOTATION_TARGET, 45, 14),
+    ]);
+  }
+
+  test_class_static_getter() async {
+    await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+class A {
+  @mustCallSuper
+  static int get f => 0;
+}
+''', [
+      error(HintCode.INVALID_ANNOTATION_TARGET, 45, 14),
+    ]);
+  }
+
+  test_class_static_method() async {
+    await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+class A {
+  @mustCallSuper
+  static void m() {}
+}
+''', [
+      error(HintCode.INVALID_ANNOTATION_TARGET, 45, 14),
+    ]);
+  }
+
+  test_class_static_setter() async {
+    await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+class A {
+  @mustCallSuper
+  static void set f(int value) {}
+}
+''', [
+      error(HintCode.INVALID_ANNOTATION_TARGET, 45, 14),
+    ]);
+  }
+
+  test_constructor() async {
+    await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+class C {
+  @mustCallSuper
+  C();
+}
+''', [
+      error(HintCode.INVALID_ANNOTATION_TARGET, 47, 13),
+    ]);
+  }
+
+  test_enum_member() async {
+    await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+enum E {
+  one, two;
+  @mustCallSuper
+  void m() {}
+}
+''', [
+      error(HintCode.INVALID_ANNOTATION_TARGET, 57, 14),
+    ]);
+  }
+
+  test_extension_member() async {
+    await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+extension E on String {
+  @mustCallSuper
+  void m() {}
+}
+''', [
+      error(HintCode.INVALID_ANNOTATION_TARGET, 60, 14),
+    ]);
+  }
+
+  test_mixin_instance_method() async {
+    await assertNoErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+mixin M {
+  @mustCallSuper
+  void m() {}
+}
+''');
+  }
+
+  test_topLevel() async {
+    await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+@mustCallSuper
+void m() {}
+''', [
+      error(HintCode.INVALID_ANNOTATION_TARGET, 35, 13),
+    ]);
+  }
+}
+
+@reflectiveTest
 class InvalidAnnotationTargetTest extends PubPackageResolutionTest {
   // todo(pq): add tests for topLevelVariables:
   // https://dart-review.googlesource.com/c/sdk/+/200301
diff --git a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
index edba42a..43e340b 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
@@ -2,6 +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.
 
+import 'package:analyzer/dart/analysis/code_style_options.dart';
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -1351,6 +1352,9 @@
       int timeStamp, this.libraryChangeBuilder)
       : super(changeBuilder, resolvedUnit.path, timeStamp);
 
+  CodeStyleOptions get codeStyleOptions =>
+      resolvedUnit.session.analysisContext.analysisOptions.codeStyleOptions;
+
   @override
   bool get hasEdits => super.hasEdits || librariesToImport.isNotEmpty;
 
@@ -1794,7 +1798,7 @@
       var whatPath = pathContext.fromUri(uri);
       return getRelativePath(whatPath);
     }
-    var preferRelative = _isLintEnabled('prefer_relative_imports');
+    var preferRelative = codeStyleOptions.useRelativeUris;
     if (forceRelative || (preferRelative && !forceAbsolute)) {
       if (canBeRelativeImport(uri, resolvedUnit.uri)) {
         var whatPath = resolvedUnit.session.uriConverter.uriToPath(uri);
@@ -1833,12 +1837,6 @@
     return element.library == resolvedUnit.libraryElement;
   }
 
-  bool _isLintEnabled(String lintName) {
-    final analysisOptions =
-        resolvedUnit.session.analysisContext.analysisOptions;
-    return analysisOptions.isLintEnabled(lintName);
-  }
-
   /// Create an edit to replace the return type of the innermost function
   /// containing the given [node] with the type `Future`. The [typeProvider] is
   /// used to check the current return type, because if it is already `Future`
diff --git a/pkg/compiler/lib/src/inferrer/abstract_value_strategy.dart b/pkg/compiler/lib/src/inferrer/abstract_value_strategy.dart
index 87d5b7d1..d98ec15 100644
--- a/pkg/compiler/lib/src/inferrer/abstract_value_strategy.dart
+++ b/pkg/compiler/lib/src/inferrer/abstract_value_strategy.dart
@@ -2,10 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.10
-
 import '../universe/world_builder.dart' show SelectorConstraintsStrategy;
-import '../world.dart';
+import '../world_interfaces.dart';
 import 'abstract_value_domain.dart';
 
 /// Strategy for the abstraction of runtime values used by the global type
diff --git a/pkg/compiler/lib/src/ir/impact.dart b/pkg/compiler/lib/src/ir/impact.dart
index e1e7473..abe548f 100644
--- a/pkg/compiler/lib/src/ir/impact.dart
+++ b/pkg/compiler/lib/src/ir/impact.dart
@@ -162,12 +162,12 @@
   void registerInstanceSet(
       ir.DartType receiverType, ClassRelation relation, ir.Member target);
 
-  void registerSuperInvocation(ir.Member target, int positionalArguments,
+  void registerSuperInvocation(ir.Member? target, int positionalArguments,
       List<String> namedArguments, List<ir.DartType> typeArguments);
 
-  void registerSuperGet(ir.Member target);
+  void registerSuperGet(ir.Member? target);
 
-  void registerSuperSet(ir.Member target);
+  void registerSuperSet(ir.Member? target);
 
   void registerSuperInitializer(
       ir.Constructor source,
diff --git a/pkg/compiler/lib/src/ir/impact_data.dart b/pkg/compiler/lib/src/ir/impact_data.dart
index 2a65114..5704733 100644
--- a/pkg/compiler/lib/src/ir/impact_data.dart
+++ b/pkg/compiler/lib/src/ir/impact_data.dart
@@ -606,19 +606,19 @@
   }
 
   @override
-  void registerSuperSet(ir.Member target) {
-    (_data._superSets ??= []).add(target);
+  void registerSuperSet(ir.Member? target) {
+    (_data._superSets ??= []).add(target!);
   }
 
   @override
-  void registerSuperGet(ir.Member target) {
-    (_data._superGets ??= []).add(target);
+  void registerSuperGet(ir.Member? target) {
+    (_data._superGets ??= []).add(target!);
   }
 
   @override
-  void registerSuperInvocation(ir.Member target, int positionalArguments,
+  void registerSuperInvocation(ir.Member? target, int positionalArguments,
       List<String> namedArguments, List<ir.DartType> typeArguments) {
-    (_data._superInvocations ??= []).add(_SuperInvocation(target,
+    (_data._superInvocations ??= []).add(_SuperInvocation(target!,
         _CallStructure(positionalArguments, namedArguments, typeArguments)));
   }
 
diff --git a/pkg/compiler/lib/src/js_model/closure.dart b/pkg/compiler/lib/src/js_model/closure.dart
index 5cd2856..4a05706 100644
--- a/pkg/compiler/lib/src/js_model/closure.dart
+++ b/pkg/compiler/lib/src/js_model/closure.dart
@@ -987,42 +987,6 @@
   }
 }
 
-class ClosureClassDefinition implements ClassDefinition {
-  /// Tag used for identifying serialized [ClosureClassDefinition] objects in a
-  /// debugging data stream.
-  static const String tag = 'closure-class-definition';
-
-  @override
-  final SourceSpan location;
-
-  ClosureClassDefinition(this.location);
-
-  factory ClosureClassDefinition.readFromDataSource(DataSourceReader source) {
-    source.begin(tag);
-    SourceSpan location = source.readSourceSpan();
-    source.end(tag);
-    return ClosureClassDefinition(location);
-  }
-
-  @override
-  void writeToDataSink(DataSinkWriter sink) {
-    sink.writeEnum(ClassKind.closure);
-    sink.begin(tag);
-    sink.writeSourceSpan(location);
-    sink.end(tag);
-  }
-
-  @override
-  ClassKind get kind => ClassKind.closure;
-
-  @override
-  ir.Node get node =>
-      throw UnsupportedError('ClosureClassDefinition.node for $location');
-
-  @override
-  String toString() => 'ClosureClassDefinition(kind:$kind,location:$location)';
-}
-
 abstract class ClosureMemberData implements JMemberData {
   @override
   final MemberDefinition definition;
@@ -1037,7 +1001,7 @@
   }
 
   @override
-  InterfaceType getMemberThisType(JsToElementMap elementMap) {
+  InterfaceType getMemberThisType(covariant JsToElementMap elementMap) {
     return memberThisType;
   }
 }
@@ -1181,44 +1145,6 @@
       ClassTypeVariableAccess.none;
 }
 
-class RecordContainerDefinition implements ClassDefinition {
-  /// Tag used for identifying serialized [RecordContainerDefinition] objects in
-  /// a debugging data stream.
-  static const String tag = 'record-definition';
-
-  @override
-  final SourceSpan location;
-
-  RecordContainerDefinition(this.location);
-
-  factory RecordContainerDefinition.readFromDataSource(
-      DataSourceReader source) {
-    source.begin(tag);
-    SourceSpan location = source.readSourceSpan();
-    source.end(tag);
-    return RecordContainerDefinition(location);
-  }
-
-  @override
-  void writeToDataSink(DataSinkWriter sink) {
-    sink.writeEnum(ClassKind.record);
-    sink.begin(tag);
-    sink.writeSourceSpan(location);
-    sink.end(tag);
-  }
-
-  @override
-  ClassKind get kind => ClassKind.record;
-
-  @override
-  ir.Node get node =>
-      throw UnsupportedError('RecordContainerDefinition.node for $location');
-
-  @override
-  String toString() =>
-      'RecordContainerDefinition(kind:$kind,location:$location)';
-}
-
 abstract class ClosureRtiNeed {
   bool classNeedsTypeArguments(ClassEntity cls);
 
diff --git a/pkg/compiler/lib/src/js_model/element_map.dart b/pkg/compiler/lib/src/js_model/element_map.dart
index 7350f29..75b6a58 100644
--- a/pkg/compiler/lib/src/js_model/element_map.dart
+++ b/pkg/compiler/lib/src/js_model/element_map.dart
@@ -19,7 +19,6 @@
 import '../js_model/class_type_variable_access.dart';
 import '../js_model/elements.dart' show JGeneratorBody;
 import '../native/behavior.dart';
-import '../serialization/serialization.dart';
 import '../universe/call_structure.dart';
 import '../universe/selector.dart';
 import '../world.dart';
@@ -36,6 +35,7 @@
   JCommonElements get commonElements;
 
   /// Access to the [DartTypes] object.
+  @override
   DartTypes get types;
 
   /// Returns the [DartType] corresponding to [type].
@@ -64,6 +64,7 @@
   Selector getSelector(ir.Expression node);
 
   /// Returns the [MemberEntity] corresponding to the member [node].
+  @override
   MemberEntity getMember(ir.Member node);
 
   /// Returns the [FunctionEntity] corresponding to the procedure [node].
@@ -102,6 +103,7 @@
   // TODO(johnniwinther,sigmund): Remove the need for [memberContext]. This is
   //  only needed because effectively constant expressions are not replaced by
   //  constant expressions during resolution.
+  @override
   ConstantValue getConstantValue(
       ir.Member memberContext, ir.Expression expression,
       {bool requireConstant = true, bool implicitNull = false});
@@ -111,6 +113,7 @@
   ///
   /// These should only appear within the defaultValues object attached to
   /// closures and tearoffs when emitting Function.apply.
+  @override
   ConstantValue getRequiredSentinelConstantValue();
 
   /// Return the [ImportEntity] corresponding to [node].
@@ -120,6 +123,7 @@
   ClassDefinition getClassDefinition(covariant ClassEntity cls);
 
   /// [ElementEnvironment] for library, class and member lookup.
+  @override
   JElementEnvironment get elementEnvironment;
 
   /// Returns the list of [DartType]s corresponding to [types].
@@ -242,81 +246,6 @@
   return null;
 }
 
-enum ClassKind {
-  regular,
-  closure,
-  // TODO(efortuna, johnniwinther): Record is not a class, but is
-  // masquerading as one currently for consistency with the old element model.
-  record,
-}
-
-/// Definition information for a [ClassEntity].
-abstract class ClassDefinition {
-  /// The kind of the defined class. This determines the semantics of [node].
-  ClassKind get kind;
-
-  /// The defining [ir.Node] for this class, if supported by its [kind].
-  ir.Node get node;
-
-  /// The canonical location of [cls]. This is used for sorting the classes
-  /// in the emitted code.
-  SourceSpan get location;
-
-  /// Deserializes a [ClassDefinition] object from [source].
-  factory ClassDefinition.readFromDataSource(DataSourceReader source) {
-    ClassKind kind = source.readEnum(ClassKind.values);
-    switch (kind) {
-      case ClassKind.regular:
-        return RegularClassDefinition.readFromDataSource(source);
-      case ClassKind.closure:
-        return ClosureClassDefinition.readFromDataSource(source);
-      case ClassKind.record:
-        return RecordContainerDefinition.readFromDataSource(source);
-    }
-    throw UnsupportedError("Unexpected ClassKind $kind");
-  }
-
-  /// Serializes this [ClassDefinition] to [sink].
-  void writeToDataSink(DataSinkWriter sink);
-}
-
-/// A class directly defined by its [ir.Class] node.
-class RegularClassDefinition implements ClassDefinition {
-  /// Tag used for identifying serialized [RegularClassDefinition] objects in a
-  /// debugging data stream.
-  static const String tag = 'regular-class-definition';
-
-  @override
-  final ir.Class node;
-
-  RegularClassDefinition(this.node);
-
-  factory RegularClassDefinition.readFromDataSource(DataSourceReader source) {
-    source.begin(tag);
-    ir.Class node = source.readClassNode();
-    source.end(tag);
-    return RegularClassDefinition(node);
-  }
-
-  @override
-  void writeToDataSink(DataSinkWriter sink) {
-    sink.writeEnum(kind);
-    sink.begin(tag);
-    sink.writeClassNode(node);
-    sink.end(tag);
-  }
-
-  @override
-  SourceSpan get location => computeSourceSpanFromTreeNode(node);
-
-  @override
-  ClassKind get kind => ClassKind.regular;
-
-  @override
-  String toString() => 'RegularClassDefinition(kind:$kind,'
-      'node:$node,location:$location)';
-}
-
 /// Returns the initializer for [field].
 ///
 /// If [field] is an instance field with a null literal initializer `null` is
diff --git a/pkg/compiler/lib/src/js_model/element_map_impl.dart b/pkg/compiler/lib/src/js_model/element_map_impl.dart
index 7836deb..f005c4d 100644
--- a/pkg/compiler/lib/src/js_model/element_map_impl.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_impl.dart
@@ -55,10 +55,12 @@
 import 'closure_migrated.dart' as closureMigrated;
 import 'elements.dart';
 import 'element_map.dart';
+import 'element_map_interfaces.dart' as interfaces show JsKernelToElementMap;
 import 'env.dart';
 import 'locals.dart';
 
-class JsKernelToElementMap implements JsToElementMap, IrToElementMap {
+class JsKernelToElementMap
+    implements interfaces.JsKernelToElementMap, JsToElementMap, IrToElementMap {
   /// Tag used for identifying serialized [JsKernelToElementMap] objects in a
   /// debugging data stream.
   static const String tag = 'js-kernel-to-element-map';
diff --git a/pkg/compiler/lib/src/js_model/element_map_interfaces.dart b/pkg/compiler/lib/src/js_model/element_map_interfaces.dart
index 8016e27..7b548e09 100644
--- a/pkg/compiler/lib/src/js_model/element_map_interfaces.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_interfaces.dart
@@ -5,12 +5,24 @@
 import 'package:compiler/src/js_model/element_map_migrated.dart';
 import 'package:kernel/ast.dart' as ir;
 
+import '../common/elements.dart';
+import '../constants/values.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart';
+import '../ir/element_map.dart';
 
 // TODO(48820): Remove this interface when nnbd migration is done.
 abstract class JsToElementMap {
+  JElementEnvironment get elementEnvironment;
+  DartTypes get types;
+  ConstantValue getConstantValue(
+      ir.Member memberContext, ir.Expression expression,
+      {bool requireConstant = true, bool implicitNull = false});
   DartType getDartType(ir.DartType type);
 
+  MemberEntity getMember(ir.Member node);
   MemberDefinition getMemberDefinition(MemberEntity member);
+  ConstantValue getRequiredSentinelConstantValue();
 }
+
+abstract class JsKernelToElementMap implements JsToElementMap, IrToElementMap {}
diff --git a/pkg/compiler/lib/src/js_model/element_map_migrated.dart b/pkg/compiler/lib/src/js_model/element_map_migrated.dart
index fb5417f..1794774 100644
--- a/pkg/compiler/lib/src/js_model/element_map_migrated.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_migrated.dart
@@ -340,3 +340,151 @@
   }
   failedAt(function, "Unexpected function definition $definition.");
 }
+
+enum ClassKind {
+  regular,
+  closure,
+  // TODO(efortuna, johnniwinther): Record is not a class, but is
+  // masquerading as one currently for consistency with the old element model.
+  record,
+}
+
+/// Definition information for a [ClassEntity].
+abstract class ClassDefinition {
+  /// The kind of the defined class. This determines the semantics of [node].
+  ClassKind get kind;
+
+  /// The defining [ir.Node] for this class, if supported by its [kind].
+  ir.Node get node;
+
+  /// The canonical location of [cls]. This is used for sorting the classes
+  /// in the emitted code.
+  SourceSpan get location;
+
+  /// Deserializes a [ClassDefinition] object from [source].
+  factory ClassDefinition.readFromDataSource(DataSourceReader source) {
+    ClassKind kind = source.readEnum(ClassKind.values);
+    switch (kind) {
+      case ClassKind.regular:
+        return RegularClassDefinition.readFromDataSource(source);
+      case ClassKind.closure:
+        return ClosureClassDefinition.readFromDataSource(source);
+      case ClassKind.record:
+        return RecordContainerDefinition.readFromDataSource(source);
+    }
+  }
+
+  /// Serializes this [ClassDefinition] to [sink].
+  void writeToDataSink(DataSinkWriter sink);
+}
+
+/// A class directly defined by its [ir.Class] node.
+class RegularClassDefinition implements ClassDefinition {
+  /// Tag used for identifying serialized [RegularClassDefinition] objects in a
+  /// debugging data stream.
+  static const String tag = 'regular-class-definition';
+
+  @override
+  final ir.Class node;
+
+  RegularClassDefinition(this.node);
+
+  factory RegularClassDefinition.readFromDataSource(DataSourceReader source) {
+    source.begin(tag);
+    ir.Class node = source.readClassNode();
+    source.end(tag);
+    return RegularClassDefinition(node);
+  }
+
+  @override
+  void writeToDataSink(DataSinkWriter sink) {
+    sink.writeEnum(kind);
+    sink.begin(tag);
+    sink.writeClassNode(node);
+    sink.end(tag);
+  }
+
+  @override
+  SourceSpan get location => computeSourceSpanFromTreeNode(node);
+
+  @override
+  ClassKind get kind => ClassKind.regular;
+
+  @override
+  String toString() => 'RegularClassDefinition(kind:$kind,'
+      'node:$node,location:$location)';
+}
+
+class ClosureClassDefinition implements ClassDefinition {
+  /// Tag used for identifying serialized [ClosureClassDefinition] objects in a
+  /// debugging data stream.
+  static const String tag = 'closure-class-definition';
+
+  @override
+  final SourceSpan location;
+
+  ClosureClassDefinition(this.location);
+
+  factory ClosureClassDefinition.readFromDataSource(DataSourceReader source) {
+    source.begin(tag);
+    SourceSpan location = source.readSourceSpan();
+    source.end(tag);
+    return ClosureClassDefinition(location);
+  }
+
+  @override
+  void writeToDataSink(DataSinkWriter sink) {
+    sink.writeEnum(ClassKind.closure);
+    sink.begin(tag);
+    sink.writeSourceSpan(location);
+    sink.end(tag);
+  }
+
+  @override
+  ClassKind get kind => ClassKind.closure;
+
+  @override
+  ir.Node get node =>
+      throw UnsupportedError('ClosureClassDefinition.node for $location');
+
+  @override
+  String toString() => 'ClosureClassDefinition(kind:$kind,location:$location)';
+}
+
+class RecordContainerDefinition implements ClassDefinition {
+  /// Tag used for identifying serialized [RecordContainerDefinition] objects in
+  /// a debugging data stream.
+  static const String tag = 'record-definition';
+
+  @override
+  final SourceSpan location;
+
+  RecordContainerDefinition(this.location);
+
+  factory RecordContainerDefinition.readFromDataSource(
+      DataSourceReader source) {
+    source.begin(tag);
+    SourceSpan location = source.readSourceSpan();
+    source.end(tag);
+    return RecordContainerDefinition(location);
+  }
+
+  @override
+  void writeToDataSink(DataSinkWriter sink) {
+    sink.writeEnum(ClassKind.record);
+    sink.begin(tag);
+    sink.writeSourceSpan(location);
+    sink.end(tag);
+  }
+
+  @override
+  ClassKind get kind => ClassKind.record;
+
+  @override
+  ir.Node get node =>
+      throw UnsupportedError('RecordContainerDefinition.node for $location');
+
+  @override
+  String toString() =>
+      'RecordContainerDefinition(kind:$kind,location:$location)';
+}
diff --git a/pkg/compiler/lib/src/js_model/env.dart b/pkg/compiler/lib/src/js_model/env.dart
index 0bf7e80..f597c52 100644
--- a/pkg/compiler/lib/src/js_model/env.dart
+++ b/pkg/compiler/lib/src/js_model/env.dart
@@ -19,9 +19,18 @@
 import '../ordered_typeset.dart';
 import '../serialization/deferrable.dart';
 import '../serialization/serialization.dart';
-import 'closure.dart';
-import 'element_map.dart';
-import 'element_map_impl.dart';
+import 'closure.dart'
+    show
+        ClosureClassData,
+        RecordClassData,
+        ClosureFunctionData,
+        ClosureFieldData;
+import 'element_map_interfaces.dart' show JsToElementMap, JsKernelToElementMap;
+import 'element_map_migrated.dart'
+    show
+        ClassDefinition,
+        MemberDefinition,
+        forEachOrderedParameterByFunctionNode;
 import 'elements.dart';
 
 /// Environment for fast lookup of component libraries.
diff --git a/pkg/compiler/lib/src/kernel/element_map.dart b/pkg/compiler/lib/src/kernel/element_map.dart
index dc09e06..eb27551 100644
--- a/pkg/compiler/lib/src/kernel/element_map.dart
+++ b/pkg/compiler/lib/src/kernel/element_map.dart
@@ -8,10 +8,4 @@
 export 'element_map_impl.dart';
 
 /// Kinds of foreign functions.
-enum ForeignKind {
-  JS,
-  JS_BUILTIN,
-  JS_EMBEDDED_GLOBAL,
-  JS_INTERCEPTOR_CONSTANT,
-  NONE,
-}
+export 'element_map_interfaces.dart' show ForeignKind;
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index 45f3683..c0e7df0 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -61,6 +61,7 @@
         KernelElementEnvironment,
         KernelToElementMapForClassHierarchy,
         KernelToElementMapForImpactData,
+        KernelToElementMapForKernelImpact,
         KernelToElementMapForNativeData,
         KernelToElementMapForDeferredLoading;
 import 'env.dart';
@@ -75,6 +76,7 @@
         interfaces.KernelToElementMapForImpactData,
         interfaces.KernelToElementMapForNativeData,
         interfaces.KernelToElementMapForDeferredLoading,
+        interfaces.KernelToElementMapForKernelImpact,
         IrToElementMap {
   @override
   final CompilerOptions options;
@@ -502,6 +504,7 @@
   /// Kernel will say that C()'s super initializer resolves to Object(), but
   /// this function will return an entity representing the unnamed mixin
   /// application "Object+M"'s constructor.
+  @override
   ConstructorEntity getSuperConstructor(
       ir.Constructor sourceNode, ir.Member targetNode) {
     ConstructorEntity source = getConstructor(sourceNode);
@@ -548,6 +551,7 @@
   }
 
   /// Returns the [InterfaceType] corresponding to [type].
+  @override
   InterfaceType getInterfaceType(ir.InterfaceType type) =>
       _typeConverter.visitType(type).withoutNullability;
 
@@ -867,6 +871,7 @@
   ir.CoreTypes get coreTypes => _coreTypes ??= ir.CoreTypes(env.mainComponent);
 
   /// Returns the type environment for the underlying kernel model.
+  @override
   ir.TypeEnvironment get typeEnvironment =>
       _typeEnvironment ??= ir.TypeEnvironment(coreTypes, classHierarchy);
 
@@ -894,6 +899,7 @@
   }
 
   /// Returns the [Name] corresponding to [name].
+  @override
   Name getName(ir.Name name) {
     return Name(name.text, name.isPrivate ? getLibrary(name.library) : null);
   }
@@ -934,6 +940,7 @@
 
   /// Returns the [Selector] corresponding to the invocation of [name] with
   /// [arguments].
+  @override
   Selector getInvocationSelector(ir.Name irName, int positionalArguments,
       List<String> namedArguments, int typeArguments) {
     Name name = getName(irName);
@@ -1042,6 +1049,7 @@
 
   /// Computes the [NativeBehavior] for a call to the [JS] function.
   /// TODO(johnniwinther): Cache this for later use.
+  @override
   NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) {
     if (node.arguments.positional.length < 2 ||
         node.arguments.named.isNotEmpty) {
@@ -1075,6 +1083,7 @@
   /// TODO(johnniwinther): Cache this for later use.
   /// Computes the [NativeBehavior] for a call to the [JS_BUILTIN]
   /// function.
+  @override
   NativeBehavior getNativeBehaviorForJsBuiltinCall(ir.StaticInvocation node) {
     if (node.arguments.positional.length < 1) {
       reporter.internalError(
@@ -1103,6 +1112,7 @@
   /// Computes the [NativeBehavior] for a call to the
   /// [JS_EMBEDDED_GLOBAL] function.
   /// TODO(johnniwinther): Cache this for later use.
+  @override
   NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
       ir.StaticInvocation node) {
     if (node.arguments.positional.length < 1) {
@@ -1207,6 +1217,7 @@
 
   /// Returns the `noSuchMethod` [FunctionEntity] call from a
   /// `super.noSuchMethod` invocation within [cls].
+  @override
   FunctionEntity getSuperNoSuchMethod(ClassEntity cls) {
     while (cls != null) {
       cls = elementEnvironment.getSuperClass(cls);
@@ -1471,6 +1482,7 @@
   }
 
   /// NativeBasicData is need for computation of the default super class.
+  @override
   NativeBasicData get nativeBasicData {
     var data = _nativeBasicData;
     if (data == null) {
@@ -1557,6 +1569,7 @@
   }
 
   /// Returns the [Local] corresponding to the local function [node].
+  @override
   Local getLocalFunction(ir.LocalFunction node) {
     KLocalFunction localFunction = localFunctionMap[node];
     if (localFunction == null) {
@@ -1622,6 +1635,7 @@
   }
 
   /// Compute the kind of foreign helper function called by [node], if any.
+  @override
   ForeignKind getForeignKind(ir.StaticInvocation node) {
     if (commonElements.isForeignHelper(getMember(node.target))) {
       switch (node.target.name.text) {
@@ -1640,6 +1654,7 @@
 
   /// Computes the [InterfaceType] referenced by a call to the
   /// [JS_INTERCEPTOR_CONSTANT] function, if any.
+  @override
   InterfaceType getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node) {
     if (node.arguments.positional.length != 1 ||
         node.arguments.named.isNotEmpty) {
diff --git a/pkg/compiler/lib/src/kernel/element_map_interfaces.dart b/pkg/compiler/lib/src/kernel/element_map_interfaces.dart
index ac78b1f..12453f5 100644
--- a/pkg/compiler/lib/src/kernel/element_map_interfaces.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_interfaces.dart
@@ -9,26 +9,53 @@
 import 'package:kernel/ast.dart' as ir
     show
         Class,
+        Constructor,
         DartType,
+        Expression,
         Field,
+        InterfaceType,
+        LibraryDependency,
+        LocalFunction,
         Member,
+        Name,
         Procedure,
         ProcedureStubKind,
-        LibraryDependency,
-        Expression;
-import 'package:kernel/type_environment.dart' as ir show StaticTypeContext;
+        StaticInvocation;
+import 'package:kernel/type_environment.dart' as ir
+    show TypeEnvironment, StaticTypeContext;
 import '../common.dart' show DiagnosticReporter;
 import '../common/elements.dart' show CommonElements, ElementEnvironment;
 import '../elements/entities.dart'
-    show ClassEntity, ConstructorEntity, MemberEntity, ImportEntity;
+    show
+        ClassEntity,
+        ConstructorEntity,
+        FieldEntity,
+        FunctionEntity,
+        Local,
+        MemberEntity,
+        ImportEntity;
 import '../constants/values.dart';
 import '../elements/indexed.dart' show IndexedClass;
+import '../elements/names.dart' show Name;
 import '../elements/types.dart' show DartType, DartTypes, InterfaceType;
 import '../ir/constants.dart' show Dart2jsConstantEvaluator;
 import '../native/behavior.dart';
+import '../js_backend/native_data.dart' show NativeBasicData;
 import '../options.dart';
+import '../universe/selector.dart';
 
-abstract class KernelElementEnvironment implements ElementEnvironment {}
+enum ForeignKind {
+  JS,
+  JS_BUILTIN,
+  JS_EMBEDDED_GLOBAL,
+  JS_INTERCEPTOR_CONSTANT,
+  NONE,
+}
+
+abstract class KernelElementEnvironment implements ElementEnvironment {
+  Iterable<ConstantValue> getMemberMetadata(MemberEntity member,
+      {bool includeParameterMetadata = false});
+}
 
 abstract class KernelToElementMapForNativeData {
   KernelElementEnvironment get elementEnvironment;
@@ -75,6 +102,48 @@
   ir.StaticTypeContext getStaticTypeContext(MemberEntity member);
 }
 
+abstract class KernelToElementMapForKernelImpact {
+  CommonElements get commonElements;
+  KernelElementEnvironment get elementEnvironment;
+  NativeBasicData get nativeBasicData;
+  ir.TypeEnvironment get typeEnvironment;
+  InterfaceType createInterfaceType(
+      ir.Class cls, List<ir.DartType> typeArguments);
+  ClassEntity getClass(ir.Class node);
+  ConstantValue? getConstantValue(
+      ir.StaticTypeContext staticTypeContext, ir.Expression node,
+      {bool requireConstant = true,
+      bool implicitNull = false,
+      bool checkCasts = true});
+  ConstructorEntity getConstructor(ir.Member node);
+  ConstructorEntity getSuperConstructor(
+      ir.Constructor sourceNode, ir.Member targetNode);
+  DartType getDartType(ir.DartType type);
+  FieldEntity getField(ir.Field node);
+  ForeignKind getForeignKind(ir.StaticInvocation node);
+  FunctionEntity getMethod(ir.Procedure node);
+  FunctionEntity getSuperNoSuchMethod(ClassEntity cls);
+  InterfaceType getInterfaceType(ir.InterfaceType type);
+  ImportEntity? getImport(ir.LibraryDependency? node);
+  InterfaceType? getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node);
+  Local getLocalFunction(ir.LocalFunction node);
+  MemberEntity getMember(ir.Member node);
+  Name getName(ir.Name name);
+  NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field,
+      Iterable<String> createsAnnotations, Iterable<String> returnsAnnotations,
+      {required bool isJsInterop});
+  NativeBehavior getNativeBehaviorForFieldStore(ir.Field field);
+  NativeBehavior getNativeBehaviorForJsBuiltinCall(ir.StaticInvocation node);
+  NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node);
+  NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
+      ir.StaticInvocation node);
+  NativeBehavior getNativeBehaviorForMethod(ir.Member member,
+      Iterable<String> createsAnnotations, Iterable<String> returnsAnnotations,
+      {required bool isJsInterop});
+  Selector getInvocationSelector(ir.Name irName, int positionalArguments,
+      List<String> namedArguments, int typeArguments);
+}
+
 // Members which dart2js ignores.
 bool memberIsIgnorable(ir.Member node, {ir.Class? cls}) {
   if (node is! ir.Procedure) return false;
diff --git a/pkg/compiler/lib/src/kernel/kernel_impact.dart b/pkg/compiler/lib/src/kernel/kernel_impact.dart
index 7f95d06..c4c4f4c 100644
--- a/pkg/compiler/lib/src/kernel/kernel_impact.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_impact.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.10
-
 import 'package:kernel/ast.dart' as ir;
 import 'package:kernel/type_environment.dart' as ir;
 
@@ -35,7 +33,9 @@
 import '../universe/use.dart';
 import '../universe/world_builder.dart';
 import '../universe/world_impact.dart';
-import 'element_map.dart';
+import 'element_map_interfaces.dart';
+
+typedef KernelToElementMap = KernelToElementMapForKernelImpact;
 
 /// [ImpactRegistry] that converts kernel based impact data to world impact
 /// object based on the K model.
@@ -82,7 +82,7 @@
   String typeToString(DartType type) =>
       type.toStructuredText(dartTypes, _options);
 
-  Object _computeReceiverConstraint(
+  Object? _computeReceiverConstraint(
       ir.DartType receiverType, ClassRelation relation) {
     if (receiverType is ir.InterfaceType) {
       return StrongModeConstraint(commonElements, _nativeBasicData,
@@ -142,7 +142,7 @@
     }
   }
 
-  List<DartType> _getTypeArguments(List<ir.DartType> types) {
+  List<DartType>? _getTypeArguments(List<ir.DartType> types) {
     if (types.isEmpty) return null;
     return types.map(elementMap.getDartType).toList();
   }
@@ -156,12 +156,12 @@
   void registerFieldNode(ir.Field field) {
     if (field.isInstanceMember &&
         _nativeBasicData
-            .isNativeClass(elementMap.getClass(field.enclosingClass))) {
+            .isNativeClass(elementMap.getClass(field.enclosingClass!))) {
       MemberEntity member = elementMap.getMember(field);
       // TODO(johnniwinther): NativeDataBuilder already has the native behavior
       // at this point. Use that instead.
       bool isJsInterop = _nativeBasicData.isJsInteropMember(member);
-      List<ConstantValue> metadata =
+      Iterable<ConstantValue> metadata =
           elementMap.elementEnvironment.getMemberMetadata(member);
       Iterable<String> createsAnnotations =
           getCreatesAnnotations(dartTypes, reporter, commonElements, metadata);
@@ -181,7 +181,7 @@
       // TODO(johnniwinther): NativeDataBuilder already has the native behavior
       // at this point. Use that instead.
       bool isJsInterop = _nativeBasicData.isJsInteropMember(member);
-      List<ConstantValue> metadata =
+      Iterable<ConstantValue> metadata =
           elementMap.elementEnvironment.getMemberMetadata(member);
       Iterable<String> createsAnnotations =
           getCreatesAnnotations(dartTypes, reporter, commonElements, metadata);
@@ -227,7 +227,7 @@
       // TODO(johnniwinther): NativeDataBuilder already has the native behavior
       // at this point. Use that instead.
       bool isJsInterop = _nativeBasicData.isJsInteropMember(member);
-      List<ConstantValue> metadata =
+      Iterable<ConstantValue> metadata =
           elementMap.elementEnvironment.getMemberMetadata(member);
       Iterable<String> createsAnnotations =
           getCreatesAnnotations(dartTypes, reporter, commonElements, metadata);
@@ -271,7 +271,7 @@
 
   @override
   void registerListLiteral(ir.DartType elementType,
-      {bool isConst, bool isEmpty}) {
+      {required bool isConst, required bool isEmpty}) {
     // TODO(johnniwinther): Use the [isConstant] and [isEmpty] property when
     // factory constructors are registered directly.
     impactBuilder.registerTypeUse(TypeUse.instantiation(
@@ -280,7 +280,7 @@
 
   @override
   void registerSetLiteral(ir.DartType elementType,
-      {bool isConst, bool isEmpty}) {
+      {required bool isConst, required bool isEmpty}) {
     // TODO(johnniwinther): Use the [isEmpty] property when factory
     // constructors are registered directly.
     if (isConst) {
@@ -293,7 +293,7 @@
 
   @override
   void registerMapLiteral(ir.DartType keyType, ir.DartType valueType,
-      {bool isConst, bool isEmpty}) {
+      {required bool isConst, required bool isEmpty}) {
     // TODO(johnniwinther): Use the [isEmpty] property when factory
     // constructors are registered directly.
     if (isConst) {
@@ -312,19 +312,19 @@
       int positionalArguments,
       List<String> namedArguments,
       List<ir.DartType> typeArguments,
-      ir.LibraryDependency import,
-      {bool isConst}) {
+      ir.LibraryDependency? import,
+      {required bool isConst}) {
     ConstructorEntity constructor = elementMap.getConstructor(target);
     CallStructure callStructure = CallStructure(
         positionalArguments + namedArguments.length,
         namedArguments,
         typeArguments.length);
-    ImportEntity deferredImport = elementMap.getImport(import);
+    ImportEntity? deferredImport = elementMap.getImport(import);
     impactBuilder.registerStaticUse(isConst
         ? StaticUse.constConstructorInvoke(constructor, callStructure,
-            elementMap.getDartType(type).withoutNullability, deferredImport)
+            elementMap.getInterfaceType(type), deferredImport)
         : StaticUse.typedConstructorInvoke(constructor, callStructure,
-            elementMap.getDartType(type).withoutNullability, deferredImport));
+            elementMap.getInterfaceType(type), deferredImport));
     if (type.typeArguments.any((ir.DartType type) => type is! ir.DynamicType)) {
       registerBackendImpact(_impacts.typeVariableBoundCheck);
     }
@@ -340,8 +340,8 @@
 
   @override
   void registerConstInstantiation(ir.Class cls, List<ir.DartType> typeArguments,
-      ir.LibraryDependency import) {
-    ImportEntity deferredImport = elementMap.getImport(import);
+      ir.LibraryDependency? import) {
+    ImportEntity? deferredImport = elementMap.getImport(import);
     InterfaceType type = elementMap.createInterfaceType(cls, typeArguments);
     impactBuilder
         .registerTypeUse(TypeUse.constInstantiation(type, deferredImport));
@@ -377,18 +377,18 @@
       int positionalArguments,
       List<String> namedArguments,
       List<ir.DartType> typeArguments,
-      ir.LibraryDependency import) {
+      ir.LibraryDependency? import) {
     FunctionEntity target = elementMap.getMethod(procedure);
     CallStructure callStructure = CallStructure(
         positionalArguments + namedArguments.length,
         namedArguments,
         typeArguments.length);
-    List<DartType> dartTypeArguments = _getTypeArguments(typeArguments);
+    List<DartType>? dartTypeArguments = _getTypeArguments(typeArguments);
     if (commonElements.isExtractTypeArguments(target)) {
-      _handleExtractTypeArguments(target, dartTypeArguments, callStructure);
+      _handleExtractTypeArguments(target, dartTypeArguments!, callStructure);
       return;
     } else {
-      ImportEntity deferredImport = elementMap.getImport(import);
+      ImportEntity? deferredImport = elementMap.getImport(import);
       impactBuilder.registerStaticUse(StaticUse.staticInvoke(
           target, callStructure, dartTypeArguments, deferredImport));
     }
@@ -409,7 +409,7 @@
             elementMap.getNativeBehaviorForJsEmbeddedGlobalCall(node));
         break;
       case ForeignKind.JS_INTERCEPTOR_CONSTANT:
-        InterfaceType type =
+        InterfaceType? type =
             elementMap.getInterfaceTypeForJsInterceptorCall(node);
         if (type != null) {
           impactBuilder.registerTypeUse(TypeUse.instantiation(type));
@@ -449,29 +449,29 @@
 
   @override
   void registerStaticTearOff(
-      ir.Procedure procedure, ir.LibraryDependency import) {
+      ir.Procedure procedure, ir.LibraryDependency? import) {
     impactBuilder.registerStaticUse(StaticUse.staticTearOff(
         elementMap.getMethod(procedure), elementMap.getImport(import)));
   }
 
   @override
-  void registerStaticGet(ir.Member member, ir.LibraryDependency import) {
+  void registerStaticGet(ir.Member member, ir.LibraryDependency? import) {
     impactBuilder.registerStaticUse(StaticUse.staticGet(
         elementMap.getMember(member), elementMap.getImport(import)));
   }
 
   @override
-  void registerStaticSet(ir.Member member, ir.LibraryDependency import) {
+  void registerStaticSet(ir.Member member, ir.LibraryDependency? import) {
     impactBuilder.registerStaticUse(StaticUse.staticSet(
         elementMap.getMember(member), elementMap.getImport(import)));
   }
 
   @override
-  void registerSuperInvocation(ir.Member target, int positionalArguments,
+  void registerSuperInvocation(ir.Member? target, int positionalArguments,
       List<String> namedArguments, List<ir.DartType> typeArguments) {
     if (target != null) {
-      FunctionEntity method = elementMap.getMember(target);
-      List<DartType> dartTypeArguments = _getTypeArguments(typeArguments);
+      FunctionEntity method = elementMap.getMember(target) as FunctionEntity;
+      List<DartType>? dartTypeArguments = _getTypeArguments(typeArguments);
       impactBuilder.registerStaticUse(StaticUse.superInvoke(
           method,
           CallStructure(positionalArguments + namedArguments.length,
@@ -481,18 +481,19 @@
       // TODO(johnniwinther): Remove this when the CFE checks for missing
       //  concrete super targets.
       impactBuilder.registerStaticUse(StaticUse.superInvoke(
-          elementMap.getSuperNoSuchMethod(currentMember.enclosingClass),
+          elementMap.getSuperNoSuchMethod(currentMember.enclosingClass!),
           CallStructure.ONE_ARG));
       registerBackendImpact(_impacts.superNoSuchMethod);
     }
   }
 
   @override
-  void registerSuperGet(ir.Member target) {
+  void registerSuperGet(ir.Member? target) {
     if (target != null) {
       MemberEntity member = elementMap.getMember(target);
       if (member.isFunction) {
-        impactBuilder.registerStaticUse(StaticUse.superTearOff(member));
+        impactBuilder.registerStaticUse(
+            StaticUse.superTearOff(member as FunctionEntity));
       } else {
         impactBuilder.registerStaticUse(StaticUse.superGet(member));
       }
@@ -500,26 +501,28 @@
       // TODO(johnniwinther): Remove this when the CFE checks for missing
       //  concrete super targets.
       impactBuilder.registerStaticUse(StaticUse.superInvoke(
-          elementMap.getSuperNoSuchMethod(currentMember.enclosingClass),
+          elementMap.getSuperNoSuchMethod(currentMember.enclosingClass!),
           CallStructure.ONE_ARG));
       registerBackendImpact(_impacts.superNoSuchMethod);
     }
   }
 
   @override
-  void registerSuperSet(ir.Member target) {
+  void registerSuperSet(ir.Member? target) {
     if (target != null) {
       MemberEntity member = elementMap.getMember(target);
       if (member.isField) {
-        impactBuilder.registerStaticUse(StaticUse.superFieldSet(member));
+        impactBuilder
+            .registerStaticUse(StaticUse.superFieldSet(member as FieldEntity));
       } else {
-        impactBuilder.registerStaticUse(StaticUse.superSetterSet(member));
+        impactBuilder.registerStaticUse(
+            StaticUse.superSetterSet(member as FunctionEntity));
       }
     } else {
       // TODO(johnniwinther): Remove this when the CFE checks for missing
       //  concrete super targets.
       impactBuilder.registerStaticUse(StaticUse.superInvoke(
-          elementMap.getSuperNoSuchMethod(currentMember.enclosingClass),
+          elementMap.getSuperNoSuchMethod(currentMember.enclosingClass!),
           CallStructure.ONE_ARG));
       registerBackendImpact(_impacts.superNoSuchMethod);
     }
@@ -535,7 +538,7 @@
         positionalArguments + namedArguments.length,
         namedArguments,
         typeArguments.length);
-    List<DartType> dartTypeArguments = _getTypeArguments(typeArguments);
+    List<DartType>? dartTypeArguments = _getTypeArguments(typeArguments);
     // Invocation of a local function. No need for dynamic use, but
     // we need to track the type arguments.
     impactBuilder.registerStaticUse(StaticUse.closureCall(
@@ -559,7 +562,7 @@
       List<ir.DartType> typeArguments) {
     Selector selector = elementMap.getInvocationSelector(
         name, positionalArguments, namedArguments, typeArguments.length);
-    List<DartType> dartTypeArguments = _getTypeArguments(typeArguments);
+    List<DartType>? dartTypeArguments = _getTypeArguments(typeArguments);
     impactBuilder.registerDynamicUse(DynamicUse(selector,
         _computeReceiverConstraint(receiverType, relation), dartTypeArguments));
   }
@@ -574,7 +577,7 @@
         positionalArguments + namedArguments.length,
         namedArguments,
         typeArguments.length);
-    List<DartType> dartTypeArguments = _getTypeArguments(typeArguments);
+    List<DartType>? dartTypeArguments = _getTypeArguments(typeArguments);
     impactBuilder.registerDynamicUse(DynamicUse(
         callStructure.callSelector,
         _computeReceiverConstraint(receiverType, ClassRelation.subtype),
@@ -589,7 +592,7 @@
       int positionalArguments,
       List<String> namedArguments,
       List<ir.DartType> typeArguments) {
-    List<DartType> dartTypeArguments = _getTypeArguments(typeArguments);
+    List<DartType>? dartTypeArguments = _getTypeArguments(typeArguments);
     impactBuilder.registerDynamicUse(DynamicUse(
         elementMap.getInvocationSelector(target.name, positionalArguments,
             namedArguments, typeArguments.length),
@@ -635,9 +638,9 @@
 
   @override
   void registerRuntimeTypeUse(RuntimeTypeUseKind kind, ir.DartType receiverType,
-      ir.DartType argumentType) {
+      ir.DartType? argumentType) {
     DartType receiverDartType = elementMap.getDartType(receiverType);
-    DartType argumentDartType =
+    DartType? argumentDartType =
         argumentType == null ? null : elementMap.getDartType(argumentType);
 
     // Enable runtime type support if we discover a getter called
@@ -649,7 +652,7 @@
   }
 
   @override
-  void registerAssert({bool withMessage}) {
+  void registerAssert({required bool withMessage}) {
     registerBackendImpact(withMessage
         ? _impacts.assertWithMessage
         : _impacts.assertWithoutMessage);
@@ -660,7 +663,8 @@
       ir.FunctionType expressionType, List<ir.DartType> typeArguments) {
     // TODO(johnniwinther): Track which arities are used in instantiation.
     final instantiation = GenericInstantiation(
-        elementMap.getDartType(expressionType).withoutNullability,
+        elementMap.getDartType(expressionType).withoutNullability
+            as FunctionType,
         typeArguments.map(elementMap.getDartType).toList());
     registerBackendImpact(
         _impacts.getGenericInstantiation(instantiation.typeArguments.length));
@@ -674,7 +678,7 @@
   }
 
   @override
-  void registerLocalFunction(ir.TreeNode node) {
+  void registerLocalFunction(covariant ir.LocalFunction node) {
     Local function = elementMap.getLocalFunction(node);
     impactBuilder.registerStaticUse(StaticUse.closure(function));
     registerBackendImpact(_impacts.closure);
@@ -727,7 +731,7 @@
   @override
   void registerSyncForIn(ir.DartType iterableType, ir.DartType iteratorType,
       ClassRelation iteratorClassRelation) {
-    Object receiverConstraint =
+    Object? receiverConstraint =
         _computeReceiverConstraint(iteratorType, iteratorClassRelation);
     registerBackendImpact(_impacts.syncForIn);
     impactBuilder.registerDynamicUse(
@@ -741,7 +745,7 @@
   @override
   void registerAsyncForIn(ir.DartType iterableType, ir.DartType iteratorType,
       ClassRelation iteratorClassRelation) {
-    Object receiverConstraint =
+    Object? receiverConstraint =
         _computeReceiverConstraint(iteratorType, iteratorClassRelation);
     registerBackendImpact(_impacts.asyncForIn);
     impactBuilder.registerDynamicUse(
@@ -770,8 +774,8 @@
   }
 
   @override
-  void registerTypeLiteral(ir.DartType irType, ir.LibraryDependency import) {
-    ImportEntity deferredImport = elementMap.getImport(import);
+  void registerTypeLiteral(ir.DartType irType, ir.LibraryDependency? import) {
+    ImportEntity? deferredImport = elementMap.getImport(import);
     DartType type = elementMap.getDartType(irType);
     impactBuilder.registerTypeUse(TypeUse.typeLiteral(type, deferredImport));
     _customElementsResolutionAnalysis.registerTypeLiteral(type);
@@ -825,10 +829,10 @@
         // Treat symbol constants as if Symbol doesn't override `==`.
         return false;
       }
-      ClassEntity cls = type.element;
+      ClassEntity? cls = type.element;
       while (cls != null) {
         MemberEntity member =
-            elementMap.elementEnvironment.lookupClassMember(cls, '==');
+            elementMap.elementEnvironment.lookupClassMember(cls, '==')!;
         if (member.isAbstract) {
           cls = elementMap.elementEnvironment.getSuperClass(cls);
         } else {
@@ -842,7 +846,7 @@
     for (ir.SwitchCase switchCase in node.cases) {
       for (ir.Expression expression in switchCase.expressions) {
         ConstantValue value =
-            elementMap.getConstantValue(staticTypeContext, expression);
+            elementMap.getConstantValue(staticTypeContext, expression)!;
         DartType type = value.getType(elementMap.commonElements);
         if (type == commonElements.doubleType) {
           reporter.reportErrorMessage(
@@ -854,7 +858,7 @@
               MessageKind.SWITCH_CASE_FORBIDDEN, {'type': "Function"});
         } else if (value is ObjectConstantValue &&
             type != commonElements.typeLiteralType &&
-            overridesEquals(type)) {
+            overridesEquals(type as InterfaceType)) {
           reporter.reportErrorMessage(
               computeSourceSpanFromTreeNode(expression),
               MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS,
diff --git a/pkg/compiler/lib/src/universe/use.dart b/pkg/compiler/lib/src/universe/use.dart
index b4ebace..fb60943 100644
--- a/pkg/compiler/lib/src/universe/use.dart
+++ b/pkg/compiler/lib/src/universe/use.dart
@@ -561,7 +561,7 @@
       ConstructorEntity element,
       CallStructure callStructure,
       InterfaceType type,
-      ImportEntity deferredImport) {
+      ImportEntity? deferredImport) {
     assert(
         (type as dynamic) != null, // TODO(48820): remove when sound
         failedAt(element, "No type provided for constructor invocation."));
@@ -583,7 +583,7 @@
       ConstructorEntity element,
       CallStructure callStructure,
       InterfaceType type,
-      ImportEntity deferredImport) {
+      ImportEntity? deferredImport) {
     assert(
         (type as dynamic) != null, // TODO(48820): remove when sound
         failedAt(element, "No type provided for constructor invocation."));
@@ -645,7 +645,7 @@
   /// An invocation of a local function [element] with the provided
   /// [callStructure] and [typeArguments].
   factory StaticUse.closureCall(Local element, CallStructure callStructure,
-      List<DartType> typeArguments) {
+      List<DartType>? typeArguments) {
     StaticUse staticUse = StaticUse.internal(
         element, StaticUseKind.CLOSURE_CALL,
         callStructure: callStructure, typeArguments: typeArguments);
@@ -836,7 +836,7 @@
   }
 
   /// [type] used as a type literal, like `foo() => T;`.
-  factory TypeUse.typeLiteral(DartType type, ImportEntity deferredImport) {
+  factory TypeUse.typeLiteral(DartType type, ImportEntity? deferredImport) {
     return TypeUse.internal(type, TypeUseKind.TYPE_LITERAL, deferredImport);
   }
 
@@ -847,7 +847,7 @@
 
   /// [type] used in a constant instantiation, like `const T();`.
   factory TypeUse.constInstantiation(
-      InterfaceType type, ImportEntity deferredImport) {
+      InterfaceType type, ImportEntity? deferredImport) {
     return TypeUse.internal(
         type, TypeUseKind.CONST_INSTANTIATION, deferredImport);
   }
diff --git a/pkg/dds/lib/src/dap/isolate_manager.dart b/pkg/dds/lib/src/dap/isolate_manager.dart
index 16eaf74..eca3678 100644
--- a/pkg/dds/lib/src/dap/isolate_manager.dart
+++ b/pkg/dds/lib/src/dap/isolate_manager.dart
@@ -542,7 +542,7 @@
     final isolateId = isolate.id!;
     final uriStrings = uris.map((uri) => uri.toString()).toList();
     final res = await _adapter.vmService
-        ?.lookupResolvedPackageUris(isolateId, uriStrings);
+        ?.lookupResolvedPackageUris(isolateId, uriStrings, local: true);
 
     return res?.uris
         ?.cast<String?>()
@@ -648,6 +648,10 @@
             Uri.parse(uri).toFilePath(),
           );
 
+          if (vmUri == null) {
+            return;
+          }
+
           final vmBp = await service.addBreakpointWithScriptUri(
               isolateId, vmUri.toString(), bp.line,
               column: bp.column);
@@ -826,7 +830,15 @@
   /// (which they may have navigated to via the Analysis Server) we generate a
   /// valid URI that the VM would create a breakpoint for.
   Future<Uri?> resolvePathToUri(String filePath) async {
-    // We don't currently need to call lookupPackageUris because the VM can
+    var google3Path = _convertPathToGoogle3Uri(filePath);
+    if (google3Path != null) {
+      var result = await _manager._adapter.vmService
+          ?.lookupPackageUris(isolate.id!, [google3Path.toString()]);
+      var uriStr = result?.uris?.first;
+      return uriStr != null ? Uri.parse(uriStr) : null;
+    }
+
+    // We don't need to call lookupPackageUris in non-google3 because the VM can
     // handle incoming file:/// URIs for packages, and also the org-dartlang-sdk
     // URIs directly for SDK sources (we do not need to convert to 'dart:'),
     // however this method is Future-returning in case this changes in future
@@ -965,6 +977,21 @@
     return null;
   }
 
+  Uri? _convertPathToGoogle3Uri(String input) {
+    const search = '/google3/';
+    if (input.startsWith('/google') && input.contains(search)) {
+      var idx = input.indexOf(search);
+      var remainingPath = input.substring(idx + search.length);
+      return Uri(
+        scheme: 'google3',
+        host: '',
+        path: remainingPath,
+      );
+    }
+
+    return null;
+  }
+
   /// Converts a file path inside the current SDK root into a URI in the form
   /// org-dartlang-sdk:///sdk/lib/collection/hash_set.dart.
   Uri? _convertPathToOrgDartlangSdk(String input) {
diff --git a/pkg/dds/lib/src/package_uri_converter.dart b/pkg/dds/lib/src/package_uri_converter.dart
index 0f9b64a..a8ef863 100644
--- a/pkg/dds/lib/src/package_uri_converter.dart
+++ b/pkg/dds/lib/src/package_uri_converter.dart
@@ -28,10 +28,13 @@
     if (converter != null && useLocalResolver) {
       final vmUris = result['uris'];
 
-      final localUris = uris.map((x) => converter(x as String)).toList();
+      final localPaths = uris.map((x) => converter(x as String)).toList();
 
       final resultUris = <String?>[
-        for (var i = 0; i < vmUris.length; i++) localUris[i] ?? vmUris[i],
+        for (var i = 0; i < vmUris.length; i++)
+          localPaths[i] != null
+              ? Uri.file(localPaths[i]!).toString()
+              : vmUris[i],
       ];
 
       return <String, dynamic>{
diff --git a/pkg/dds/test/uri_converter_test.dart b/pkg/dds/test/uri_converter_test.dart
index 2d82ea6..2364961 100644
--- a/pkg/dds/test/uri_converter_test.dart
+++ b/pkg/dds/test/uri_converter_test.dart
@@ -34,7 +34,7 @@
       dds = await DartDevelopmentService.startDartDevelopmentService(
         remoteVmServiceUri,
         uriConverter: (uri) => uri == 'package:test/has_local.dart'
-            ? 'file:///has_local.dart'
+            ? '/home/has_local.dart'
             : null,
       );
       serviceUri = dds!.wsUri!;
@@ -68,7 +68,7 @@
           .lookupResolvedPackageUris(isolate.id!, unresolvedUris, local: true);
 
       expect(result.uris?[0], 'org-dartlang-sdk:///sdk/lib/io/io.dart');
-      expect(result.uris?[1], 'file:///has_local.dart');
+      expect(result.uris?[1], 'file:///home/has_local.dart');
       expect(result.uris?[2], null);
     },
     timeout: Timeout.none,
diff --git a/pkg/meta/lib/meta.dart b/pkg/meta/lib/meta.dart
index 7a1ce9f..fb15a7d 100644
--- a/pkg/meta/lib/meta.dart
+++ b/pkg/meta/lib/meta.dart
@@ -458,6 +458,12 @@
   const _MustBeOverridden();
 }
 
+@Target({
+  TargetKind.field,
+  TargetKind.getter,
+  TargetKind.method,
+  TargetKind.setter,
+})
 class _MustCallSuper {
   const _MustCallSuper();
 }
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index bc4ebde..e7f9172 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -5722,6 +5722,7 @@
     __ TryAllocate(cls, compiler->intrinsic_slow_path_label(),
                    compiler::Assembler::kFarJump, result, temp);
   } else {
+    RELEASE_ASSERT(instruction->CanTriggerGC());
     auto slow_path = new BoxAllocationSlowPath(instruction, cls, result);
     compiler->AddSlowPathCode(slow_path);
 
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 2aa863f..af9f8b1 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -445,7 +445,7 @@
   M(DebugStepCheck, _)                                                         \
   M(RecordCoverage, kNoGC)                                                     \
   M(LoadIndexed, kNoGC)                                                        \
-  M(LoadCodeUnits, kNoGC)                                                      \
+  M(LoadCodeUnits, _)                                                          \
   M(StoreIndexed, kNoGC)                                                       \
   M(StoreField, _)                                                             \
   M(LoadStaticField, _)                                                        \
@@ -5989,6 +5989,10 @@
 
   virtual bool HasUnknownSideEffects() const { return false; }
 
+  virtual bool CanTriggerGC() const {
+    return !can_pack_into_smi() && (representation() == kTagged);
+  }
+
  private:
   const intptr_t class_id_;
   const TokenPosition token_pos_;
@@ -6869,6 +6873,10 @@
 
   virtual bool AllowsCSE() const { return slot_.is_immutable(); }
 
+  virtual bool CanTriggerGC() const {
+    return calls_initializer() || IsPotentialUnboxedDartFieldLoad();
+  }
+
   virtual bool AttributesEqual(const Instruction& other) const;
 
   PRINT_OPERANDS_TO_SUPPORT
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index a12f853..44f2547 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -1133,30 +1133,17 @@
                              FLAG_branch_coverage);
     }
 
-// Generated code must match the host architecture and ABI.
-#if defined(TARGET_ARCH_ARM)
-#if defined(DART_TARGET_OS_MACOS) || defined(DART_TARGET_OS_MACOS_IOS)
-    buffer.AddString(" arm-ios");
-#else
-    buffer.AddString(" arm-eabi");
-#endif
-    buffer.AddString(TargetCPUFeatures::hardfp_supported() ? " hardfp"
-                                                           : " softfp");
-#elif defined(TARGET_ARCH_ARM64)
-#if defined(DART_TARGET_OS_FUCHSIA)
-    // See signal handler cheat in Assembler::EnterFrame.
-    buffer.AddString(" arm64-fuchsia");
-#else
-    buffer.AddString(" arm64-sysv");
-#endif
-#elif defined(TARGET_ARCH_IA32)
+    // Generated code must match the host architecture and ABI. We check the
+    // strong condition of matching on operating system so that
+    // Platform.isAndroid etc can be compile-time constants.
+#if defined(TARGET_ARCH_IA32)
     buffer.AddString(" ia32");
 #elif defined(TARGET_ARCH_X64)
-#if defined(DART_TARGET_OS_WINDOWS)
-    buffer.AddString(" x64-win");
-#else
-    buffer.AddString(" x64-sysv");
-#endif
+    buffer.AddString(" x64");
+#elif defined(TARGET_ARCH_ARM)
+    buffer.AddString(" arm");
+#elif defined(TARGET_ARCH_ARM64)
+    buffer.AddString(" arm64");
 #elif defined(TARGET_ARCH_RISCV32)
     buffer.AddString(" riscv32");
 #elif defined(TARGET_ARCH_RISCV64)
@@ -1164,6 +1151,25 @@
 #else
 #error What architecture?
 #endif
+
+#if defined(DART_TARGET_OS_ANDROID)
+    buffer.AddString(" android");
+#elif defined(DART_TARGET_OS_FUCHSIA)
+    buffer.AddString(" fuchsia");
+#elif defined(DART_TARGET_OS_MACOS)
+#if defined(DART_TARGET_OS_MACOS_IOS)
+    buffer.AddString(" ios");
+#else
+    buffer.AddString(" macos");
+#endif
+#elif defined(DART_TARGET_OS_LINUX)
+    buffer.AddString(" linux");
+#elif defined(DART_TARGET_OS_WINDOWS)
+    buffer.AddString(" windows");
+#else
+#error What operating system?
+#endif
+
 #if defined(DART_COMPRESSED_POINTERS)
     buffer.AddString(" compressed-pointers");
 #else
diff --git a/tools/VERSION b/tools/VERSION
index 4190dd2..1aac611 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 19
 PATCH 0
-PRERELEASE 44
+PRERELEASE 45
 PRERELEASE_PATCH 0
\ No newline at end of file