Version 2.18.0-18.0.dev

Merge commit 'c50940b56b1ec2232e135954dc84bc223ce45348' into 'dev'
diff --git a/DEPS b/DEPS
index 3c0b60d..db8fe96 100644
--- a/DEPS
+++ b/DEPS
@@ -152,7 +152,7 @@
   "shelf_web_socket_rev": "24fb8a04befa75a94ac63a27047b231d1a22aab4",
   "source_map_stack_trace_rev": "8eabd96b1811e30a11d3c54c9b4afae4fb72e98f",
   "source_maps-0.9.4_rev": "38524",
-  "source_maps_rev": "6499ee3adac8d469e2953e2e8ba4bdb4c2fbef90",
+  "source_maps_rev": "c07a01b8d5547ce3a47ee7a7a2b938a2bc09afe3",
   "source_span_rev": "8ae724c3e67f5afaacead44e93ff145bfb8775c7",
   "sse_rev": "9084339389eb441d0c0518cddac211a097e78657",
   "stack_trace_rev": "5220580872625ddee41e9ca9a5f3364789b2f0f6",
diff --git a/build/config/linux/BUILD.gn b/build/config/linux/BUILD.gn
index 06aabec..cf3f77a5 100644
--- a/build/config/linux/BUILD.gn
+++ b/build/config/linux/BUILD.gn
@@ -35,10 +35,6 @@
       ]
     }
   }
-
-  if (is_qemu) {
-    cflags += [ "-DDART_RUN_IN_QEMU_ARMv7" ]
-  }
 }
 
 config("executable_config") {
diff --git a/pkg/_js_interop_checks/lib/src/transformations/js_util_wasm_optimizer.dart b/pkg/_js_interop_checks/lib/src/transformations/js_util_wasm_optimizer.dart
index eb6de83..220d07b 100644
--- a/pkg/_js_interop_checks/lib/src/transformations/js_util_wasm_optimizer.dart
+++ b/pkg/_js_interop_checks/lib/src/transformations/js_util_wasm_optimizer.dart
@@ -8,7 +8,11 @@
 import 'package:kernel/type_environment.dart';
 
 import '../js_interop.dart'
-    show getJSName, hasStaticInteropAnnotation, hasJSInteropAnnotation;
+    show
+        getJSName,
+        hasAnonymousAnnotation,
+        hasStaticInteropAnnotation,
+        hasJSInteropAnnotation;
 
 /// Replaces:
 ///   1) Factory constructors in classes with `@staticInterop` annotations with
@@ -29,6 +33,15 @@
 ///      trampolines based off the interop type, to avoid megamorphic behavior.
 ///      This would have code size implications though, so we would need to
 ///      proceed carefully.
+/// TODO(joshualitt): A few of the functions in this file use js_utils in a
+/// naive way, and could be optimized further. In particular, there are a few
+/// complex operations in [JsUtilWasmOptimizer] where it is obvious a value is
+/// flowing from / to JS, and we have a few options for optimization:
+///    1) Integrate with `js_ast` and emit custom JavaScript for each of these
+///       operations.
+///    2) Use the `raw` variants of the js_util calls.
+///    3) Move more of the logic for these calls into JS where it will likely be
+///       faster.
 class JsUtilWasmOptimizer extends Transformer {
   final Procedure _callMethodTarget;
   final Procedure _callConstructorTarget;
@@ -37,6 +50,7 @@
   final Procedure _setPropertyTarget;
   final Procedure _jsifyTarget;
   final Procedure _dartifyTarget;
+  final Procedure _newObjectTarget;
   final Class _jsValueClass;
 
   final CoreTypes _coreTypes;
@@ -59,6 +73,8 @@
             _coreTypes.index.getTopLevelProcedure('dart:js_util_wasm', 'jsify'),
         _dartifyTarget = _coreTypes.index
             .getTopLevelProcedure('dart:js_util_wasm', 'dartify'),
+        _newObjectTarget = _coreTypes.index
+            .getTopLevelProcedure('dart:js_util_wasm', 'newObject'),
         _jsValueClass =
             _coreTypes.index.getClass('dart:js_util_wasm', 'JSValue'),
         _staticTypeContext = StatefulStaticTypeContext.stacked(
@@ -85,15 +101,19 @@
   @override
   Procedure visitProcedure(Procedure node) {
     _staticTypeContext.enterMember(node);
-    ReturnStatement? transformedBody;
+    Statement? transformedBody;
     if (node.isExternal) {
       if (node.isFactory) {
         Class cls = node.enclosingClass!;
         if (hasStaticInteropAnnotation(cls)) {
-          String jsName = getJSName(cls);
-          String constructorName = jsName == '' ? cls.name : jsName;
-          transformedBody =
-              _getExternalCallConstructorBody(node, constructorName);
+          if (hasAnonymousAnnotation(cls)) {
+            transformedBody = _getExternalAnonymousConstructorBody(node);
+          } else {
+            String jsName = getJSName(cls);
+            String constructorName = jsName == '' ? cls.name : jsName;
+            transformedBody =
+                _getExternalCallConstructorBody(node, constructorName);
+          }
         }
       } else if (node.isExtensionMember) {
         var index = _extensionMemberIndex ??=
@@ -161,6 +181,9 @@
   DartType get _nullableJSValueType =>
       _jsValueClass.getThisType(_coreTypes, Nullability.nullable);
 
+  DartType get _nonNullableJSValueType =>
+      _jsValueClass.getThisType(_coreTypes, Nullability.nonNullable);
+
   Expression _jsifyVariable(VariableDeclaration variable) =>
       StaticInvocation(_jsifyTarget, Arguments([VariableGet(variable)]));
 
@@ -173,13 +196,30 @@
   Expression getObjectOffGlobalThis(Procedure node, List<String> selectors) {
     Expression currentTarget = _globalThis;
     for (String selector in selectors) {
-      currentTarget = _dartify(StaticInvocation(_getPropertyTarget,
-          Arguments([currentTarget, StringLiteral(selector)])))
-        ..fileOffset = node.fileOffset;
+      currentTarget = _getProperty(node, currentTarget, selector);
     }
     return currentTarget;
   }
 
+  /// Returns a new function body for the given [node] external factory method
+  /// for a class annotated with `@anonymous`.
+  ///
+  /// This lowers a factory function with named arguments to the creation of a
+  /// new object literal, and a series of `setProperty` calls.
+  Block _getExternalAnonymousConstructorBody(Procedure node) {
+    List<Statement> body = [];
+    final object = VariableDeclaration('|anonymousObject',
+        initializer: StaticInvocation(_newObjectTarget, Arguments([])),
+        type: _nonNullableJSValueType);
+    body.add(object);
+    for (VariableDeclaration variable in node.function.namedParameters) {
+      body.add(ExpressionStatement(
+          _setProperty(node, VariableGet(object), variable.name!, variable)));
+    }
+    body.add(ReturnStatement(VariableGet(object)));
+    return Block(body);
+  }
+
   /// Returns a new function body for the given [node] external method.
   ///
   /// The new function body will call `js_util_wasm.callConstructorVarArgs`
@@ -194,7 +234,7 @@
           StringLiteral(constructorName),
           ListLiteral(
               function.positionalParameters.map(_jsifyVariable).toList(),
-              typeArgument: _nullableJSValueType)
+              typeArgument: _nonNullableJSValueType)
         ]))
       ..fileOffset = node.fileOffset;
     return ReturnStatement(callConstructorInvocation);
@@ -203,17 +243,20 @@
   Expression _dartify(Expression expression) =>
       StaticInvocation(_dartifyTarget, Arguments([expression]));
 
-  /// Returns a new function body for the given [node] external getter.
+  /// Returns a new [Expression] for the given [node] external getter.
   ///
-  /// The new function body is equivalent to:
+  /// The new [Expression] is equivalent to:
   /// `js_util_wasm.getProperty([object], [getterName])`.
+  Expression _getProperty(
+          Procedure node, Expression object, String getterName) =>
+      StaticInvocation(
+          _getPropertyTarget, Arguments([object, StringLiteral(getterName)]))
+        ..fileOffset = node.fileOffset;
+
+  /// Returns a new function body for the given [node] external getter.
   ReturnStatement _getExternalGetterBody(
-      Procedure node, Expression object, String getterName) {
-    final getPropertyInvocation = _dartify(StaticInvocation(
-        _getPropertyTarget, Arguments([object, StringLiteral(getterName)])))
-      ..fileOffset = node.fileOffset;
-    return ReturnStatement(getPropertyInvocation);
-  }
+          Procedure node, Expression object, String getterName) =>
+      ReturnStatement(_dartify(_getProperty(node, object, getterName)));
 
   ReturnStatement _getExternalExtensionGetterBody(Procedure node) =>
       _getExternalGetterBody(
@@ -225,17 +268,20 @@
           Procedure node, Expression target) =>
       _getExternalGetterBody(node, target, node.name.text);
 
-  /// Returns a new function body for the given [node] external setter.
+  /// Returns a new [Expression] for the given [node] external setter.
   ///
-  /// The new function body is equivalent to:
+  /// The new [Expression] is equivalent to:
   /// `js_util_wasm.setProperty([object], [setterName], [value])`.
+  Expression _setProperty(Procedure node, Expression object, String setterName,
+          VariableDeclaration value) =>
+      StaticInvocation(_setPropertyTarget,
+          Arguments([object, StringLiteral(setterName), _jsifyVariable(value)]))
+        ..fileOffset = node.fileOffset;
+
+  /// Returns a new function body for the given [node] external setter.
   ReturnStatement _getExternalSetterBody(Procedure node, Expression object,
-      String setterName, VariableDeclaration value) {
-    final setPropertyInvocation = _dartify(StaticInvocation(_setPropertyTarget,
-        Arguments([object, StringLiteral(setterName), _jsifyVariable(value)])))
-      ..fileOffset = node.fileOffset;
-    return ReturnStatement(setPropertyInvocation);
-  }
+          String setterName, VariableDeclaration value) =>
+      ReturnStatement(_dartify(_setProperty(node, object, setterName, value)));
 
   ReturnStatement _getExternalExtensionSetterBody(Procedure node) {
     final parameters = node.function.positionalParameters;
diff --git a/pkg/analysis_server/pubspec.yaml b/pkg/analysis_server/pubspec.yaml
index 20795bf..9eda1d5 100644
--- a/pkg/analysis_server/pubspec.yaml
+++ b/pkg/analysis_server/pubspec.yaml
@@ -3,7 +3,7 @@
 publish_to: none
 
 environment:
-  sdk: '>=2.15.0 <3.0.0'
+  sdk: '>=2.17.0 <3.0.0'
 
 dependencies:
   _fe_analyzer_shared:
diff --git a/pkg/analysis_server/test/completion_test_support.dart b/pkg/analysis_server/test/completion_test_support.dart
index 7de6d30..cba131c 100644
--- a/pkg/analysis_server/test/completion_test_support.dart
+++ b/pkg/analysis_server/test/completion_test_support.dart
@@ -81,17 +81,19 @@
 
   Future runTest(LocationSpec spec, [Map<String, String>? extraFiles]) async {
     await super.setUp();
-    return Future(() {
-      var content = spec.source;
-      newFile2(testFile, content);
-      testCode = content;
+
+    try {
+      extraFiles?.forEach((String fileName, String content) {
+        newFile2(fileName, content);
+      });
+
+      newFile2(testFile.path, spec.source);
       completionOffset = spec.testLocation;
-      if (extraFiles != null) {
-        extraFiles.forEach((String fileName, String content) {
-          newFile2(fileName, content);
-        });
-      }
-    }).then((_) => getSuggestions()).then((_) {
+      await getSuggestions(
+        path: testFile.path,
+        completionOffset: completionOffset,
+      );
+
       filterResults(spec.source);
       for (var result in spec.positiveResults) {
         assertHasCompletion(result);
@@ -99,9 +101,9 @@
       for (var result in spec.negativeResults) {
         assertHasNoCompletion(result);
       }
-    }).whenComplete(() {
+    } finally {
       super.tearDown();
-    });
+    }
   }
 }
 
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 7503258..78c3b52 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -1989,28 +1989,25 @@
     extends AbstractCompletionDomainTest {
   Future<void> test_ArgumentList_constructor_named_fieldFormalParam() async {
     // https://github.com/dart-lang/sdk/issues/31023
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f() { new A(field: ^);}
 class A {
   A({this.field: -1}) {}
 }
 ''');
-    await getSuggestions();
   }
 
   Future<void> test_ArgumentList_constructor_named_param_label() async {
-    addTestFile('void f() { new A(^);}'
+    await getTestCodeSuggestions('void f() { new A(^);}'
         'class A { A({one, two}) {} }');
-    await getSuggestions();
     assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'one: ');
     assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'two: ');
     expect(suggestions, hasLength(2));
   }
 
   Future<void> test_ArgumentList_factory_named_param_label() async {
-    addTestFile('void f() { new A(^);}'
+    await getTestCodeSuggestions('void f() { new A(^);}'
         'class A { factory A({one, two}) => throw 0; }');
-    await getSuggestions();
     assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'one: ');
     assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'two: ');
     expect(suggestions, hasLength(2));
@@ -2018,9 +2015,8 @@
 
   Future<void>
       test_ArgumentList_function_named_fromPositionalNumeric_withoutSpace() async {
-    addTestFile('void f(int a, {int b = 0}) {}'
+    await getTestCodeSuggestions('void f(int a, {int b = 0}) {}'
         'void g() { f(2, ^3); }');
-    await getSuggestions();
     assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'b: ');
     expect(suggestions, hasLength(1));
     // Ensure we don't try to replace the following arg.
@@ -2030,9 +2026,8 @@
 
   Future<void>
       test_ArgumentList_function_named_fromPositionalNumeric_withSpace() async {
-    addTestFile('void f(int a, {int b = 0}) {}'
+    await getTestCodeSuggestions('void f(int a, {int b = 0}) {}'
         'void g() { f(2, ^ 3); }');
-    await getSuggestions();
     assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'b: ');
     expect(suggestions, hasLength(1));
     // Ensure we don't try to replace the following arg.
@@ -2042,10 +2037,9 @@
 
   Future<void>
       test_ArgumentList_function_named_fromPositionalVariable_withoutSpace() async {
-    addTestFile('void f(int a, {int b = 0}) {}'
+    await getTestCodeSuggestions('void f(int a, {int b = 0}) {}'
         'var foo = 1;'
         'void g() { f(2, ^foo); }');
-    await getSuggestions();
     expect(suggestions, hasLength(1));
 
     // The named arg "b: " should not replace anything.
@@ -2055,10 +2049,9 @@
 
   Future<void>
       test_ArgumentList_function_named_fromPositionalVariable_withSpace() async {
-    addTestFile('void f(int a, {int b = 0}) {}'
+    await getTestCodeSuggestions('void f(int a, {int b = 0}) {}'
         'var foo = 1;'
         'void g() { f(2, ^ foo); }');
-    await getSuggestions();
     assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'b: ');
     expect(suggestions, hasLength(1));
     // Ensure we don't try to replace the following arg.
@@ -2067,7 +2060,7 @@
   }
 
   Future<void> test_ArgumentList_function_named_partiallyTyped() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
     class C {
       void m(String firstString, {String secondString}) {}
 
@@ -2076,7 +2069,6 @@
       }
     }
     ''');
-    await getSuggestions();
     assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'secondString: ');
     expect(suggestions, hasLength(1));
     // Ensure we replace the correct section.
@@ -2085,48 +2077,42 @@
   }
 
   Future<void> test_ArgumentList_imported_function_named_param() async {
-    addTestFile('void f() { int.parse("16", ^);}');
-    await getSuggestions();
+    await getTestCodeSuggestions('void f() { int.parse("16", ^);}');
     assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'radix: ');
     assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'onError: ');
     expect(suggestions, hasLength(2));
   }
 
   Future<void> test_ArgumentList_imported_function_named_param1() async {
-    addTestFile('void f() { foo(o^);} foo({one, two}) {}');
-    await getSuggestions();
+    await getTestCodeSuggestions('void f() { foo(o^);} foo({one, two}) {}');
     assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'one: ');
     assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'two: ');
     expect(suggestions, hasLength(2));
   }
 
   Future<void> test_ArgumentList_imported_function_named_param2() async {
-    addTestFile('void f() {A a = new A(); a.foo(one: 7, ^);}'
+    await getTestCodeSuggestions('void f() {A a = new A(); a.foo(one: 7, ^);}'
         'class A { foo({one, two}) {} }');
-    await getSuggestions();
     assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'two: ');
     expect(suggestions, hasLength(1));
   }
 
   Future<void> test_ArgumentList_imported_function_named_param_label1() async {
-    addTestFile('void f() { int.parse("16", r^: 16);}');
-    await getSuggestions();
+    await getTestCodeSuggestions('void f() { int.parse("16", r^: 16);}');
     assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'radix');
     assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'onError');
     expect(suggestions, hasLength(2));
   }
 
   Future<void> test_ArgumentList_imported_function_named_param_label3() async {
-    addTestFile('void f() { int.parse("16", ^: 16);}');
-    await getSuggestions();
+    await getTestCodeSuggestions('void f() { int.parse("16", ^: 16);}');
     assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'radix');
     assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'onError');
     expect(suggestions, hasLength(2));
   }
 
   Future<void> test_catch() async {
-    addTestFile('void f() {try {} ^}');
-    await getSuggestions();
+    await getTestCodeSuggestions('void f() {try {} ^}');
     assertHasResult(CompletionSuggestionKind.KEYWORD, 'on');
     assertHasResult(CompletionSuggestionKind.KEYWORD, 'catch');
     assertHasResult(CompletionSuggestionKind.KEYWORD, 'finally');
@@ -2134,8 +2120,7 @@
   }
 
   Future<void> test_catch2() async {
-    addTestFile('void f() {try {} on Foo {} ^}');
-    await getSuggestions();
+    await getTestCodeSuggestions('void f() {try {} on Foo {} ^}');
     assertHasResult(CompletionSuggestionKind.KEYWORD, 'on');
     assertHasResult(CompletionSuggestionKind.KEYWORD, 'catch');
     assertHasResult(CompletionSuggestionKind.KEYWORD, 'finally');
@@ -2148,8 +2133,7 @@
   }
 
   Future<void> test_catch3() async {
-    addTestFile('void f() {try {} catch (e) {} finally {} ^}');
-    await getSuggestions();
+    await getTestCodeSuggestions('void f() {try {} catch (e) {} finally {} ^}');
     assertNoResult('on');
     assertNoResult('catch');
     assertNoResult('finally');
@@ -2162,8 +2146,7 @@
   }
 
   Future<void> test_catch4() async {
-    addTestFile('void f() {try {} finally {} ^}');
-    await getSuggestions();
+    await getTestCodeSuggestions('void f() {try {} finally {} ^}');
     assertNoResult('on');
     assertNoResult('catch');
     assertNoResult('finally');
@@ -2176,57 +2159,51 @@
   }
 
   Future<void> test_catch5() async {
-    addTestFile('void f() {try {} ^ finally {}}');
-    await getSuggestions();
+    await getTestCodeSuggestions('void f() {try {} ^ finally {}}');
     assertHasResult(CompletionSuggestionKind.KEYWORD, 'on');
     assertHasResult(CompletionSuggestionKind.KEYWORD, 'catch');
     expect(suggestions, hasLength(2));
   }
 
   Future<void> test_constructor() async {
-    addTestFile('class A {bool foo; A() : ^;}');
-    await getSuggestions();
+    await getTestCodeSuggestions('class A {bool foo; A() : ^;}');
     assertHasResult(CompletionSuggestionKind.KEYWORD, 'super');
     assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'foo');
   }
 
   Future<void> test_constructor2() async {
-    addTestFile('class A {bool foo; A() : s^;}');
-    await getSuggestions();
+    await getTestCodeSuggestions('class A {bool foo; A() : s^;}');
     assertHasResult(CompletionSuggestionKind.KEYWORD, 'super');
     assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'foo');
   }
 
   Future<void> test_constructor3() async {
-    addTestFile('class A {bool foo; A() : a=7,^;}');
-    await getSuggestions();
+    await getTestCodeSuggestions('class A {bool foo; A() : a=7,^;}');
     assertHasResult(CompletionSuggestionKind.KEYWORD, 'super');
     assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'foo');
   }
 
   Future<void> test_constructor4() async {
-    addTestFile('class A {bool foo; A() : a=7,s^;}');
-    await getSuggestions();
+    await getTestCodeSuggestions('class A {bool foo; A() : a=7,s^;}');
     assertHasResult(CompletionSuggestionKind.KEYWORD, 'super');
     assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'foo');
   }
 
   Future<void> test_constructor5() async {
-    addTestFile('class A {bool foo; A() : a=7,s^}');
-    await getSuggestions();
+    await getTestCodeSuggestions('class A {bool foo; A() : a=7,s^}');
     assertHasResult(CompletionSuggestionKind.KEYWORD, 'super');
     assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'foo');
   }
 
   Future<void> test_constructor6() async {
-    addTestFile('class A {bool foo; A() : a=7,^ void bar() {}}');
-    await getSuggestions();
+    await getTestCodeSuggestions(
+        'class A {bool foo; A() : a=7,^ void bar() {}}');
     assertHasResult(CompletionSuggestionKind.KEYWORD, 'super');
     assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'foo');
   }
 
   Future<void> test_extension() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class MyClass {
   void foo() {
     ba^
@@ -2237,71 +2214,67 @@
   void bar() {}
 }
 ''');
-    await getSuggestions();
     assertHasResult(CompletionSuggestionKind.INVOCATION, 'bar');
   }
 
-  Future<void> test_html() {
+  Future<void> test_html() async {
     //
     // We no longer support the analysis of non-dart files.
     //
-    testFile = convertPath('/project/web/test.html');
-    addTestFile('''
-      <html>^</html>
-    ''');
-    return getSuggestions().then((_) {
-      expect(replacementOffset, equals(completionOffset));
-      expect(replacementLength, equals(0));
-      expect(suggestions, hasLength(0));
-    });
+    await getCodeSuggestions(
+      path: convertPath('$testPackageLibPath/test.html'),
+      content: '<html>^</html>',
+    );
+    expect(replacementOffset, equals(completionOffset));
+    expect(replacementLength, equals(0));
+    expect(suggestions, hasLength(0));
   }
 
-  Future<void> test_import_uri_with_trailing() {
+  Future<void> test_import_uri_with_trailing() async {
     final filePath = '/project/bin/testA.dart';
     final incompleteImportText = toUriStr('/project/bin/t');
     newFile2(filePath, 'library libA;');
-    addTestFile('''
+    await getTestCodeSuggestions('''
     import "$incompleteImportText^.dart";
     void f() {}''');
-    return getSuggestions().then((_) {
-      expect(replacementOffset,
-          equals(completionOffset - incompleteImportText.length));
-      expect(replacementLength, equals(5 + incompleteImportText.length));
-      assertHasResult(CompletionSuggestionKind.IMPORT, toUriStr(filePath));
-      assertNoResult('test');
-    });
+    expect(replacementOffset,
+        equals(completionOffset - incompleteImportText.length));
+    expect(replacementLength, equals(5 + incompleteImportText.length));
+    assertHasResult(CompletionSuggestionKind.IMPORT, toUriStr(filePath));
+    assertNoResult('test');
   }
 
-  Future<void> test_imports() {
-    addTestFile('''
+  Future<void> test_imports() async {
+    await getTestCodeSuggestions('''
       import 'dart:html';
       void f() {^}
     ''');
-    return getSuggestions().then((_) {
-      expect(replacementOffset, equals(completionOffset));
-      expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'Object',
-          elementKind: ElementKind.CLASS);
-      assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'HtmlElement',
-          elementKind: ElementKind.CLASS);
-      assertNoResult('test');
-    });
+    expect(replacementOffset, equals(completionOffset));
+    expect(replacementLength, equals(0));
+    assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'Object',
+        elementKind: ElementKind.CLASS);
+    assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'HtmlElement',
+        elementKind: ElementKind.CLASS);
+    assertNoResult('test');
   }
 
   Future<void> test_imports_aborted_new_request() async {
     addTestFile('''
         class foo { }
-        c^''');
+        c''');
+    completionOffset = 31;
 
     // Make a request for suggestions
-    var request1 = CompletionGetSuggestionsParams(testFile, completionOffset)
-        .toRequest('7');
-    var responseFuture1 = waitResponse(request1);
+    var request1 =
+        CompletionGetSuggestionsParams(testFile.path, completionOffset)
+            .toRequest('7');
+    var responseFuture1 = serverChannel.sendRequest(request1);
 
     // Make another request before the first request completes
-    var request2 = CompletionGetSuggestionsParams(testFile, completionOffset)
-        .toRequest('8');
-    var responseFuture2 = waitResponse(request2);
+    var request2 =
+        CompletionGetSuggestionsParams(testFile.path, completionOffset)
+            .toRequest('8');
+    var responseFuture2 = serverChannel.sendRequest(request2);
 
     // Await first response
     var response1 = await responseFuture1;
@@ -2314,7 +2287,7 @@
     assertValidId(result2.id);
 
     // Wait for all processing to be complete
-    await analysisHandler.server.onAnalysisComplete;
+    await server.onAnalysisComplete;
     await pumpEventQueue();
 
     // Assert that first request has been aborted
@@ -2336,14 +2309,17 @@
         c^''');
 
     // Make a request for suggestions
-    var request = CompletionGetSuggestionsParams(testFile, completionOffset)
-        .toRequest('0');
-    var responseFuture = waitResponse(request);
+    var request =
+        CompletionGetSuggestionsParams(testFile.path, completionOffset)
+            .toRequest('0');
+    var responseFuture = handleSuccessfulRequest(request);
 
     // Simulate user deleting text after request but before suggestions returned
-    server.updateContent('uc1', {testFile: AddContentOverlay(testCode)});
+    server.updateContent(
+        'uc1', {testFile.path: AddContentOverlay(testFileContent)});
     server.updateContent('uc2', {
-      testFile: ChangeContentOverlay([SourceEdit(completionOffset - 1, 1, '')])
+      testFile.path:
+          ChangeContentOverlay([SourceEdit(completionOffset - 1, 1, '')])
     });
 
     // Await a response
@@ -2352,7 +2328,7 @@
     assertValidId(completionId);
 
     // Wait for all processing to be complete
-    await analysisHandler.server.onAnalysisComplete;
+    await server.onAnalysisComplete;
     await pumpEventQueue();
 
     // Assert that request has been aborted
@@ -2366,13 +2342,19 @@
       import "dart:async";
       import "package:foo/foo.dart";
       class foo { }''');
+    completionOffset = 20;
     await waitForTasksFinished();
-    server.updateContent('uc1', {testFile: AddContentOverlay(testCode)});
+    server.updateContent(
+        'uc1', {testFile.path: AddContentOverlay(testFileContent)});
     server.updateContent('uc2', {
-      testFile: ChangeContentOverlay([SourceEdit(completionOffset, 0, 'xp')])
+      testFile.path:
+          ChangeContentOverlay([SourceEdit(completionOffset, 0, 'xp')])
     });
     completionOffset += 2;
-    await getSuggestions();
+    await getSuggestions(
+      path: testFile.path,
+      completionOffset: completionOffset,
+    );
     expect(replacementOffset, completionOffset - 3);
     expect(replacementLength, 3);
     assertHasResult(CompletionSuggestionKind.KEYWORD, 'export \'\';',
@@ -2384,22 +2366,24 @@
   }
 
   Future<void> test_imports_partial() async {
-    addTestFile('''^
+    addTestFile('''
       import "package:foo/foo.dart";
       import "package:bar/bar.dart";
       class Baz { }''');
+    completionOffset = 0;
 
     // Wait for analysis then edit the content
     await waitForTasksFinished();
-    var revisedContent =
-        '${testCode.substring(0, completionOffset)}i${testCode.substring(completionOffset)}';
+    var revisedContent = testFileContent.substring(0, 0) +
+        'i' +
+        testFileContent.substring(completionOffset);
     ++completionOffset;
     server.handleRequest(AnalysisUpdateContentParams(
-        {testFile: AddContentOverlay(revisedContent)}).toRequest('add1'));
+        {testFile.path: AddContentOverlay(revisedContent)}).toRequest('add1'));
 
     // Request code completion immediately after edit
-    var response = await waitResponse(
-        CompletionGetSuggestionsParams(testFile, completionOffset)
+    var response = await handleSuccessfulRequest(
+        CompletionGetSuggestionsParams(testFile.path, completionOffset)
             .toRequest('0'));
     completionId = response.id;
     assertValidId(completionId);
@@ -2422,123 +2406,110 @@
     assertNoResult('extends');
   }
 
-  Future<void> test_imports_prefixed() {
-    addTestFile('''
+  Future<void> test_imports_prefixed() async {
+    await getTestCodeSuggestions('''
       import 'dart:html' as foo;
       void f() {^}
     ''');
-    return getSuggestions().then((_) {
-      expect(replacementOffset, equals(completionOffset));
-      expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'Object',
-          elementKind: ElementKind.CLASS);
-      assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'foo');
-      assertNoResult('HtmlElement');
-      assertNoResult('test');
-    });
+    expect(replacementOffset, equals(completionOffset));
+    expect(replacementLength, equals(0));
+    assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'Object',
+        elementKind: ElementKind.CLASS);
+    assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'foo');
+    assertNoResult('HtmlElement');
+    assertNoResult('test');
   }
 
-  Future<void> test_imports_prefixed2() {
-    addTestFile('''
+  Future<void> test_imports_prefixed2() async {
+    await getTestCodeSuggestions('''
       import 'dart:html' as foo;
       void f() {foo.^}
     ''');
-    return getSuggestions().then((_) {
-      expect(replacementOffset, equals(completionOffset));
-      expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'HtmlElement');
-      assertNoResult('test');
-    });
+    expect(replacementOffset, equals(completionOffset));
+    expect(replacementLength, equals(0));
+    assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'HtmlElement');
+    assertNoResult('test');
   }
 
   Future<void> test_inComment_block_beforeDartDoc() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 /* text ^ */
 
 /// some doc comments
 class SomeClass {}
   ''');
-    await getSuggestions();
     expect(suggestions, isEmpty);
   }
 
   Future<void> test_inComment_block_beforeNode() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
   void f(aaa, bbb) {
     /* text ^ */
     print(42);
   }
   ''');
-    await getSuggestions();
     expect(suggestions, isEmpty);
   }
 
   Future<void> test_inComment_endOfFile_withNewline() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
     // text ^
   ''');
-    await getSuggestions();
     expect(suggestions, isEmpty);
   }
 
   Future<void> test_inComment_endOfFile_withoutNewline() async {
-    addTestFile('// text ^');
-    await getSuggestions();
+    await getTestCodeSuggestions('// text ^');
     expect(suggestions, isEmpty);
   }
 
   Future<void> test_inComment_endOfLine_beforeDartDoc() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 // text ^
 
 /// some doc comments
 class SomeClass {}
   ''');
-    await getSuggestions();
     expect(suggestions, isEmpty);
   }
 
   Future<void> test_inComment_endOfLine_beforeNode() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
   void f(aaa, bbb) {
     // text ^
     print(42);
   }
   ''');
-    await getSuggestions();
     expect(suggestions, isEmpty);
   }
 
   Future<void> test_inComment_endOfLine_beforeToken() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
   void f(aaa, bbb) {
     // text ^
   }
   ''');
-    await getSuggestions();
     expect(suggestions, isEmpty);
   }
 
   Future<void> test_inDartDoc1() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
   /// ^
   void f(aaa, bbb) {}
   ''');
-    await getSuggestions();
     expect(suggestions, isEmpty);
   }
 
   Future<void> test_inDartDoc2() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
   /// Some text^
   void f(aaa, bbb) {}
   ''');
-    await getSuggestions();
     expect(suggestions, isEmpty);
   }
 
   Future<void> test_inDartDoc3() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class MyClass {
   /// ^
   void foo() {}
@@ -2550,7 +2521,6 @@
   void baz() {}
 }
   ''');
-    await getSuggestions();
     expect(suggestions, isEmpty);
   }
 
@@ -2558,30 +2528,28 @@
     newFile2('/testA.dart', '''
   part of libA;
   foo(bar) => 0;''');
-    addTestFile('''
+    await getTestCodeSuggestions('''
   library libA;
   part "${toUriStr('/testA.dart')}";
   import "dart:math";
   /// The [^]
   void f(aaa, bbb) {}
   ''');
-    await getSuggestions();
     assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'f');
     assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'foo');
     assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'min');
   }
 
   Future<void> test_inDartDoc_reference2() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
   /// The [m^]
   void f(aaa, bbb) {}
   ''');
-    await getSuggestions();
     assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'f');
   }
 
   Future<void> test_inDartDoc_reference3() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class MyClass {
   /// [^]
   void foo() {}
@@ -2593,13 +2561,12 @@
   void baz() {}
 }
   ''');
-    await getSuggestions();
     assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'bar');
     assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'baz');
   }
 
-  Future<void> test_inherited() {
-    addTestFile('''
+  Future<void> test_inherited() async {
+    await getTestCodeSuggestions('''
 class A {
   m() {}
 }
@@ -2607,19 +2574,18 @@
   x() {^}
 }
 ''');
-    return getSuggestions().then((_) {
-      expect(replacementOffset, equals(completionOffset));
-      expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'm');
-    });
+    expect(replacementOffset, equals(completionOffset));
+    expect(replacementLength, equals(0));
+    assertHasResult(CompletionSuggestionKind.INVOCATION, 'm');
   }
 
   Future<void> test_invalidFilePathFormat_notAbsolute() async {
     var request = CompletionGetSuggestionsParams('test.dart', 0).toRequest('0');
-    var response = await waitResponse(request);
-    expect(
+    var response = await handleRequest(request);
+    assertResponseFailure(
       response,
-      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+      requestId: '0',
+      errorCode: RequestErrorCode.INVALID_FILE_PATH_FORMAT,
     );
   }
 
@@ -2627,52 +2593,47 @@
     var request =
         CompletionGetSuggestionsParams(convertPath('/foo/../bar/test.dart'), 0)
             .toRequest('0');
-    var response = await waitResponse(request);
-    expect(
+    var response = await handleRequest(request);
+    assertResponseFailure(
       response,
-      isResponseFailure('0', RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+      requestId: '0',
+      errorCode: RequestErrorCode.INVALID_FILE_PATH_FORMAT,
     );
   }
 
-  Future<void> test_invocation() {
-    addTestFile('class A {b() {}} void f() {A a; a.^}');
-    return getSuggestions().then((_) {
-      expect(replacementOffset, equals(completionOffset));
-      expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'b');
-    });
+  Future<void> test_invocation() async {
+    await getTestCodeSuggestions('class A {b() {}} void f() {A a; a.^}');
+    expect(replacementOffset, equals(completionOffset));
+    expect(replacementLength, equals(0));
+    assertHasResult(CompletionSuggestionKind.INVOCATION, 'b');
   }
 
-  Future<void> test_invocation_withTrailingStmt() {
-    addTestFile('class A {b() {}} void f() {A a; a.^ int x = 7;}');
-    return getSuggestions().then((_) {
-      expect(replacementOffset, equals(completionOffset));
-      expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'b');
-    });
+  Future<void> test_invocation_withTrailingStmt() async {
+    await getTestCodeSuggestions(
+        'class A {b() {}} void f() {A a; a.^ int x = 7;}');
+    expect(replacementOffset, equals(completionOffset));
+    expect(replacementLength, equals(0));
+    assertHasResult(CompletionSuggestionKind.INVOCATION, 'b');
   }
 
   Future<void> test_is_asPrefixedIdentifierStart() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class A { var isVisible;}
 void f(A p) { var v1 = p.is^; }''');
-    await getSuggestions();
     assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'isVisible');
   }
 
-  Future<void> test_keyword() {
-    addTestFile('library A; cl^');
-    return getSuggestions().then((_) {
-      expect(replacementOffset, equals(completionOffset - 2));
-      expect(replacementLength, equals(2));
-      assertHasResult(CompletionSuggestionKind.KEYWORD, 'export \'\';',
-          selectionOffset: 8);
-      assertHasResult(CompletionSuggestionKind.KEYWORD, 'class');
-    });
+  Future<void> test_keyword() async {
+    await getTestCodeSuggestions('library A; cl^');
+    expect(replacementOffset, equals(completionOffset - 2));
+    expect(replacementLength, equals(2));
+    assertHasResult(CompletionSuggestionKind.KEYWORD, 'export \'\';',
+        selectionOffset: 8);
+    assertHasResult(CompletionSuggestionKind.KEYWORD, 'class');
   }
 
   Future<void> test_local_implicitCreation() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class A {
   A();
   A.named();
@@ -2681,7 +2642,6 @@
   ^
 }
 ''');
-    await getSuggestions();
 
     expect(replacementOffset, equals(completionOffset));
     expect(replacementLength, equals(0));
@@ -2697,34 +2657,30 @@
         elementKind: ElementKind.CONSTRUCTOR);
   }
 
-  Future<void> test_local_named_constructor() {
-    addTestFile('class A {A.c(); x() {new A.^}}');
-    return getSuggestions().then((_) {
-      expect(replacementOffset, equals(completionOffset));
-      expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'c');
-      assertNoResult('A');
-    });
+  Future<void> test_local_named_constructor() async {
+    await getTestCodeSuggestions('class A {A.c(); x() {new A.^}}');
+    expect(replacementOffset, equals(completionOffset));
+    expect(replacementLength, equals(0));
+    assertHasResult(CompletionSuggestionKind.INVOCATION, 'c');
+    assertNoResult('A');
   }
 
-  Future<void> test_local_override() {
+  Future<void> test_local_override() async {
     newFile2('/project/bin/a.dart', 'class A {m() {}}');
-    addTestFile('''
+    await getTestCodeSuggestions('''
 import 'a.dart';
 class B extends A {
   m() {}
   x() {^}
 }
 ''');
-    return getSuggestions().then((_) {
-      expect(replacementOffset, equals(completionOffset));
-      expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'm');
-    });
+    expect(replacementOffset, equals(completionOffset));
+    expect(replacementLength, equals(0));
+    assertHasResult(CompletionSuggestionKind.INVOCATION, 'm');
   }
 
   Future<void> test_local_shadowClass() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class A {
   A();
   A.named();
@@ -2734,7 +2690,6 @@
   ^
 }
 ''');
-    await getSuggestions();
 
     expect(replacementOffset, equals(completionOffset));
     expect(replacementLength, equals(0));
@@ -2748,149 +2703,145 @@
     assertNoResult('A.named', elementKind: ElementKind.CONSTRUCTOR);
   }
 
-  Future<void> test_locals() {
-    addTestFile('class A {var a; x() {var b;^}} class DateTime { }');
-    return getSuggestions().then((_) {
-      expect(replacementOffset, equals(completionOffset));
-      expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'A',
-          elementKind: ElementKind.CLASS);
-      assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'a');
-      assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'b');
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'x');
-      assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'DateTime',
-          elementKind: ElementKind.CLASS);
-    });
+  Future<void> test_locals() async {
+    await getTestCodeSuggestions(
+        'class A {var a; x() {var b;^}} class DateTime { }');
+    expect(replacementOffset, equals(completionOffset));
+    expect(replacementLength, equals(0));
+    assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'A',
+        elementKind: ElementKind.CLASS);
+    assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'a');
+    assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'b');
+    assertHasResult(CompletionSuggestionKind.INVOCATION, 'x');
+    assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'DateTime',
+        elementKind: ElementKind.CLASS);
   }
 
   Future<void> test_offset_past_eof() async {
-    addTestFile('void f() { }', offset: 300);
-    var request = CompletionGetSuggestionsParams(testFile, completionOffset)
-        .toRequest('0');
-    var response = await waitResponse(request);
-    expect(response.id, '0');
-    expect(response.error!.code, RequestErrorCode.INVALID_PARAMETER);
+    addTestFile('void f() { }');
+    var request =
+        CompletionGetSuggestionsParams(testFile.path, 300).toRequest('0');
+    var response = await handleRequest(request);
+    assertResponseFailure(
+      response,
+      requestId: '0',
+      errorCode: RequestErrorCode.INVALID_PARAMETER,
+    );
   }
 
-  Future<void> test_overrides() {
+  Future<void> test_overrides() async {
     newFile2('/project/bin/a.dart', 'class A {m() {}}');
-    addTestFile('''
+    await getTestCodeSuggestions('''
 import 'a.dart';
 class B extends A {m() {^}}
 ''');
-    return getSuggestions().then((_) {
-      expect(replacementOffset, equals(completionOffset));
-      expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'm');
-    });
+    expect(replacementOffset, equals(completionOffset));
+    expect(replacementLength, equals(0));
+    assertHasResult(CompletionSuggestionKind.INVOCATION, 'm');
   }
 
-  Future<void> test_partFile() {
-    newFile2('/project/bin/a.dart', '''
+  Future<void> test_partFile() async {
+    newFile2('$testPackageLibPath/a.dart', '''
       library libA;
       import 'dart:html';
       part 'test.dart';
       class A { }
     ''');
-    addTestFile('''
+    await getTestCodeSuggestions('''
       part of libA;
       void f() {^}''');
-    return getSuggestions().then((_) {
-      expect(replacementOffset, equals(completionOffset));
-      expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'Object',
-          elementKind: ElementKind.CLASS);
-      assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'HtmlElement',
-          elementKind: ElementKind.CLASS);
-      assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'A',
-          elementKind: ElementKind.CLASS);
-      assertNoResult('test');
-    });
+    expect(replacementOffset, equals(completionOffset));
+    expect(replacementLength, equals(0));
+    assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'Object',
+        elementKind: ElementKind.CLASS);
+    assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'HtmlElement',
+        elementKind: ElementKind.CLASS);
+    assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'A',
+        elementKind: ElementKind.CLASS);
+    assertNoResult('test');
   }
 
-  Future<void> test_partFile2() {
-    newFile2('/project/bin/a.dart', '''
+  Future<void> test_partFile2() async {
+    newFile2('$testPackageLibPath/a.dart', '''
       part of libA;
       class A { }''');
-    addTestFile('''
+    await getTestCodeSuggestions('''
       library libA;
       part "a.dart";
       import 'dart:html';
       void f() {^}
     ''');
-    return getSuggestions().then((_) {
-      expect(replacementOffset, equals(completionOffset));
-      expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'Object',
-          elementKind: ElementKind.CLASS);
-      assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'HtmlElement',
-          elementKind: ElementKind.CLASS);
-      assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'A',
-          elementKind: ElementKind.CLASS);
-      assertNoResult('test');
-    });
+    expect(replacementOffset, equals(completionOffset));
+    expect(replacementLength, equals(0));
+    assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'Object',
+        elementKind: ElementKind.CLASS);
+    assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'HtmlElement',
+        elementKind: ElementKind.CLASS);
+    assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'A',
+        elementKind: ElementKind.CLASS);
+    assertNoResult('test');
   }
 
   Future<void> test_sentToPlugins() async {
     addTestFile('''
       void f() {
-        ^
+        
       }
     ''');
     PluginInfo info = DiscoveredPluginInfo('a', 'b', 'c',
         TestNotificationManager(), InstrumentationService.NULL_SERVICE);
     var result = plugin.CompletionGetSuggestionsResult(
-        testFile.indexOf('^'), 0, <CompletionSuggestion>[
+        testFileContent.indexOf('^'), 0, <CompletionSuggestion>[
       CompletionSuggestion(CompletionSuggestionKind.IDENTIFIER,
           DART_RELEVANCE_DEFAULT, 'plugin completion', 3, 0, false, false)
     ]);
     pluginManager.broadcastResults = <PluginInfo, Future<plugin.Response>>{
       info: Future.value(result.toResponse('-', 1))
     };
-    await getSuggestions();
-    assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'plugin completion',
-        selectionOffset: 3);
-  }
-
-  Future<void> test_simple() {
-    addTestFile('''
+    await getTestCodeSuggestions('''
       void f() {
         ^
       }
     ''');
-    return getSuggestions().then((_) {
-      expect(replacementOffset, equals(completionOffset));
-      expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'Object',
-          elementKind: ElementKind.CLASS);
-      assertNoResult('HtmlElement');
-      assertNoResult('test');
-    });
+    assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'plugin completion',
+        selectionOffset: 3);
+  }
+
+  Future<void> test_simple() async {
+    await getTestCodeSuggestions('''
+      void f() {
+        ^
+      }
+    ''');
+    expect(replacementOffset, equals(completionOffset));
+    expect(replacementLength, equals(0));
+    assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'Object',
+        elementKind: ElementKind.CLASS);
+    assertNoResult('HtmlElement');
+    assertNoResult('test');
   }
 
   Future<void> test_static() async {
-    addTestFile('class A {static b() {} c() {}} void f() {A.^}');
-    await getSuggestions();
+    await getTestCodeSuggestions(
+        'class A {static b() {} c() {}} void f() {A.^}');
     expect(replacementOffset, equals(completionOffset));
     expect(replacementLength, equals(0));
     assertHasResult(CompletionSuggestionKind.INVOCATION, 'b');
     assertNoResult('c');
   }
 
-  Future<void> test_topLevel() {
-    addTestFile('''
+  Future<void> test_topLevel() async {
+    await getTestCodeSuggestions('''
       typedef foo();
       var test = '';
       void f() {tes^t}
     ''');
-    return getSuggestions().then((_) {
-      expect(replacementOffset, equals(completionOffset - 3));
-      expect(replacementLength, equals(4));
-      // Suggestions based upon imported elements are partially filtered
-      //assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object');
-      assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'test');
-      assertNoResult('HtmlElement');
-    });
+    expect(replacementOffset, equals(completionOffset - 3));
+    expect(replacementLength, equals(4));
+    // Suggestions based upon imported elements are partially filtered
+    //assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object');
+    assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'test');
+    assertNoResult('HtmlElement');
   }
 }
 
diff --git a/pkg/analysis_server/test/domain_completion_util.dart b/pkg/analysis_server/test/domain_completion_util.dart
index 1d02ab8..19086f3 100644
--- a/pkg/analysis_server/test/domain_completion_util.dart
+++ b/pkg/analysis_server/test/domain_completion_util.dart
@@ -7,16 +7,15 @@
 import 'package:analysis_server/protocol/protocol.dart';
 import 'package:analysis_server/protocol/protocol_constants.dart';
 import 'package:analysis_server/protocol/protocol_generated.dart';
-import 'package:analysis_server/src/domain_completion.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
 import 'package:test/test.dart';
 
-import 'analysis_abstract.dart';
+import 'analysis_server_base.dart';
 import 'constants.dart';
 
-class AbstractCompletionDomainTest extends AbstractAnalysisTest {
+class AbstractCompletionDomainTest extends PubPackageAnalysisServerTest {
   late String completionId;
-  late int completionOffset;
+  late int completionOffset; // TODO(scheglov) remove it
   int? replacementOffset;
   late int replacementLength;
   Map<String, Completer<void>> receivedSuggestionsCompleters = {};
@@ -24,21 +23,6 @@
   bool suggestionsDone = false;
   Map<String, List<CompletionSuggestion>> allSuggestions = {};
 
-  @override
-  String addTestFile(String content, {int? offset}) {
-    completionOffset = content.indexOf('^');
-    if (offset != null) {
-      expect(completionOffset, -1, reason: 'cannot supply offset and ^');
-      completionOffset = offset;
-      return super.addTestFile(content);
-    }
-    expect(completionOffset, isNot(equals(-1)), reason: 'missing ^');
-    var nextOffset = content.indexOf('^', completionOffset + 1);
-    expect(nextOffset, equals(-1), reason: 'too many ^');
-    return super.addTestFile(content.substring(0, completionOffset) +
-        content.substring(completionOffset + 1));
-  }
-
   void assertHasResult(CompletionSuggestionKind kind, String completion,
       {bool isDeprecated = false,
       bool isPotential = false,
@@ -92,12 +76,35 @@
     expect(id.isNotEmpty, isTrue);
   }
 
-  Future getSuggestions() async {
-    await waitForTasksFinished();
+  Future<void> getCodeSuggestions({
+    required String path,
+    required String content,
+  }) async {
+    completionOffset = content.indexOf('^');
+    expect(completionOffset, isNot(equals(-1)), reason: 'missing ^');
 
-    var request = CompletionGetSuggestionsParams(testFile, completionOffset)
-        .toRequest('0');
-    var response = await waitResponse(request);
+    var nextOffset = content.indexOf('^', completionOffset + 1);
+    expect(nextOffset, equals(-1), reason: 'too many ^');
+
+    newFile2(
+      path,
+      content.substring(0, completionOffset) +
+          content.substring(completionOffset + 1),
+    );
+
+    return await getSuggestions(
+      path: path,
+      completionOffset: completionOffset,
+    );
+  }
+
+  Future<void> getSuggestions({
+    required String path,
+    required int completionOffset,
+  }) async {
+    var request =
+        CompletionGetSuggestionsParams(path, completionOffset).toRequest('0');
+    var response = await handleSuccessfulRequest(request);
     var result = CompletionGetSuggestionsResult.fromResponse(response);
     completionId = result.id;
     assertValidId(completionId);
@@ -105,6 +112,13 @@
     expect(suggestionsDone, isTrue);
   }
 
+  Future<void> getTestCodeSuggestions(String content) {
+    return getCodeSuggestions(
+      path: testFile.path,
+      content: content,
+    );
+  }
+
   @override
   Future<void> processNotification(Notification notification) async {
     if (notification.event == COMPLETION_RESULTS) {
@@ -127,8 +141,7 @@
   @override
   Future<void> setUp() async {
     super.setUp();
-    await createProject();
-    handler = CompletionDomainHandler(server);
+    await setRoots(included: [workspaceRootPath], excluded: []);
   }
 
   Completer<void> _getResultsCompleter(String id) {
diff --git a/pkg/analysis_server/test/src/services/completion/dart/completion_test.dart b/pkg/analysis_server/test/src/services/completion/dart/completion_test.dart
index b6ad6a1..f5d703b 100644
--- a/pkg/analysis_server/test/src/services/completion/dart/completion_test.dart
+++ b/pkg/analysis_server/test/src/services/completion/dart/completion_test.dart
@@ -31,7 +31,7 @@
 @reflectiveTest
 class ArgumentListCompletionTest extends CompletionTestCase {
   Future<void> test_functionWithVoidReturnType_optionalNamed() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f(C c) {
   c.m(handler: ^);
 }
@@ -42,12 +42,11 @@
   void m({void Function()? handler}) {}
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('g');
   }
 
   Future<void> test_functionWithVoidReturnType_requiredPositional() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f(C c) {
   c.m(^);
 }
@@ -58,12 +57,11 @@
   void m(void Function() handler) {}
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('g');
   }
 
   Future<void> test_privateStaticField() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 extension on int {
   static int _x = 0;
 
@@ -72,7 +70,6 @@
   }
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('_x');
   }
 }
@@ -80,12 +77,11 @@
 @reflectiveTest
 class AsExpressionCompletionTest extends CompletionTestCase {
   Future<void> test_type_dynamic() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f(Object o) {
   var x = o as ^;
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('dynamic');
   }
 }
@@ -94,14 +90,13 @@
 class AssertStatementCompletionTest extends CompletionTestCase {
   @failingTest
   Future<void> test_message() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f() {
   assert(true, ^);
 }
 
 const c = <int>[];
 ''');
-    await getSuggestions();
     assertHasCompletion('c');
   }
 }
@@ -109,7 +104,7 @@
 @reflectiveTest
 class ConstructorCompletionTest extends CompletionTestCase {
   Future<void> test_constructor_abstract() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f() {
   g(^);
 }
@@ -118,7 +113,6 @@
   C.c();
 }
 ''');
-    await getSuggestions();
     assertHasNoCompletion('C.c');
   }
 }
@@ -126,26 +120,24 @@
 @reflectiveTest
 class DeclaredIdentifierCompletionTest extends CompletionTestCase {
   Future<void> test_afterFinal_withIdentifier() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class C {
   void m(List<C> cs) {
     for (final ^ x in cs) {}
   }
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('C');
   }
 
   Future<void> test_afterFinal_withoutIdentifier() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class C {
   void m(List<C> cs) {
     for (final ^) {}
   }
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('C');
   }
 }
@@ -153,7 +145,7 @@
 @reflectiveTest
 class ExpressionFunctionBodyCompletionTest extends CompletionTestCase {
   Future<void> test_voidReturn_localFunction() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class C {
   void m() {
     void f() => ^;
@@ -162,29 +154,26 @@
 
 void g() {}
 ''');
-    await getSuggestions();
     assertHasCompletion('g');
   }
 
   Future<void> test_voidReturn_method() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class C {
   void m() => ^;
 }
 
 void g() {}
 ''');
-    await getSuggestions();
     assertHasCompletion('g');
   }
 
   Future<void> test_voidReturn_topLevelFunction() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f() => ^;
 
 void g() {}
 ''');
-    await getSuggestions();
     assertHasCompletion('g');
   }
 }
@@ -192,7 +181,7 @@
 @reflectiveTest
 class ExtensionCompletionTest extends CompletionTestCase {
   Future<void> test_explicitTarget_getter_sameUnit() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f(String s) {
   s.^;
 }
@@ -200,56 +189,52 @@
   int get g => length;
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('g');
   }
 
   Future<void> test_explicitTarget_method_imported() async {
-    newFile2(convertPath('/project/bin/lib.dart'), '''
+    newFile2(convertPath('$testPackageLibPath/lib.dart'), '''
 extension E on String {
   void m() {}
 }
 ''');
-    addTestFile('''
+    await getTestCodeSuggestions('''
 import 'lib.dart';
 void f(String s) {
   s.^;
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('m');
   }
 
   Future<void> test_explicitTarget_method_inLibrary() async {
-    newFile2(convertPath('/project/bin/lib.dart'), '''
+    newFile2(convertPath('$testPackageLibPath/lib.dart'), '''
 part 'test.dart';
 extension E on String {
   void m() {}
 }
 ''');
-    addTestFile('''
+    await getTestCodeSuggestions('''
 part of 'lib.dart';
 void f(String s) {
   s.^;
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('m');
   }
 
   Future<void> test_explicitTarget_method_inPart() async {
-    newFile2(convertPath('/project/bin/part.dart'), '''
+    newFile2(convertPath('$testPackageLibPath/part.dart'), '''
 extension E on String {
   void m() {}
 }
 ''');
-    addTestFile('''
+    await getTestCodeSuggestions('''
 part 'part.dart';
 void f(String s) {
   s.^;
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('m');
   }
 
@@ -262,17 +247,16 @@
   void m() {}
 }
 ''');
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f(String s) {
   s.^;
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('m');
   }
 
   Future<void> test_explicitTarget_method_sameUnit() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f(String s) {
   s.^;
 }
@@ -280,12 +264,11 @@
   void m() {}
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('m');
   }
 
   Future<void> test_explicitTarget_setter_sameUnit() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f(String s) {
   s.^;
 }
@@ -293,12 +276,11 @@
   set e(int v) {}
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('e');
   }
 
   Future<void> test_implicitTarget_inClass_method_sameUnit() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class C {
   void c() {
     ^
@@ -308,19 +290,17 @@
   void m() {}
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('m');
   }
 
   Future<void> test_implicitTarget_inExtension_method_sameUnit() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 extension E on String {
   void m() {
     ^
   }
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('m');
   }
 }
@@ -328,10 +308,9 @@
 @reflectiveTest
 class FormalParameterCompletionTest extends CompletionTestCase {
   Future<void> test_named_last() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f({int? a, ^}) {}
 ''');
-    await getSuggestions();
     assertHasCompletion('covariant');
     assertHasCompletion('dynamic');
     assertHasCompletion('required');
@@ -339,10 +318,9 @@
   }
 
   Future<void> test_named_last_afterCovariant() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f({covariant ^}) {}
 ''');
-    await getSuggestions();
     assertHasNoCompletion('covariant');
     assertHasCompletion('dynamic');
     assertHasNoCompletion('required');
@@ -350,10 +328,9 @@
   }
 
   Future<void> test_named_last_afterRequired() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f({required ^}) {}
 ''');
-    await getSuggestions();
     assertHasCompletion('covariant');
     assertHasCompletion('dynamic');
     assertHasNoCompletion('required');
@@ -361,10 +338,9 @@
   }
 
   Future<void> test_named_only() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f({^}) {}
 ''');
-    await getSuggestions();
     assertHasCompletion('covariant');
     assertHasCompletion('dynamic');
     assertHasCompletion('required');
@@ -372,10 +348,9 @@
   }
 
   Future<void> test_optionalPositional_last() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f([int a, ^]) {}
 ''');
-    await getSuggestions();
     assertHasCompletion('covariant');
     assertHasCompletion('dynamic');
     assertHasNoCompletion('required');
@@ -383,10 +358,9 @@
   }
 
   Future<void> test_optionalPositional_only() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f([^]) {}
 ''');
-    await getSuggestions();
     assertHasCompletion('covariant');
     assertHasCompletion('dynamic');
     assertHasNoCompletion('required');
@@ -394,10 +368,9 @@
   }
 
   Future<void> test_requiredPositional_only() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f(^) {}
 ''');
-    await getSuggestions();
     assertHasCompletion('covariant');
     assertHasCompletion('dynamic');
     assertHasNoCompletion('required');
@@ -408,50 +381,44 @@
 @reflectiveTest
 class GenericFunctionTypeCompletionTest extends CompletionTestCase {
   Future<void> test_returnType_beforeType() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f({^vo Function() p}) {}
 ''');
-    await getSuggestions();
     assertHasCompletion('void');
   }
 
   Future<void> test_returnType_beforeType_afterRequired() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f({required ^vo Function() p}) {}
 ''');
-    await getSuggestions();
     assertHasCompletion('void');
   }
 
   Future<void> test_returnType_inType() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f({v^o Function() p}) {}
 ''');
-    await getSuggestions();
     assertHasCompletion('void');
   }
 
   Future<void> test_returnType_inType_afterRequired() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f({required v^o Function() p}) {}
 ''');
-    await getSuggestions();
     assertHasCompletion('void');
   }
 
   Future<void> test_returnType_partialFunctionType() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f({^ Function() p}) {}
 ''');
-    await getSuggestions();
     assertHasCompletion('void');
   }
 
   Future<void> test_returnType_partialFunctionType_afterRequired() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f({required ^ Function() p}) {}
 ''');
-    await getSuggestions();
     assertHasCompletion('void');
   }
 }
@@ -459,10 +426,9 @@
 @reflectiveTest
 class GenericTypeAliasCompletionTest extends CompletionTestCase {
   Future<void> test_returnType_void() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 typedef F = ^
 ''');
-    await getSuggestions();
     assertHasCompletion('void');
   }
 }
@@ -470,7 +436,7 @@
 @reflectiveTest
 class PropertyAccessCompletionTest extends CompletionTestCase {
   Future<void> test_nullSafe_extension() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f(C c) {
   c.a?.^;
 }
@@ -481,12 +447,11 @@
   int get b => 0;
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('b');
   }
 
   Future<void> test_setter_deprecated() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f(C c) {
   c.^;
 }
@@ -495,13 +460,12 @@
   set x(int x) {}
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('x',
         elementKind: ElementKind.SETTER, isDeprecated: true);
   }
 
   Future<void> test_setter_deprecated_withNonDeprecatedGetter() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f(C c) {
   c.^;
 }
@@ -511,7 +475,6 @@
   set x(int x) {}
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('x',
         elementKind: ElementKind.GETTER, isDeprecated: false);
   }
@@ -521,7 +484,7 @@
 class RedirectedConstructorCompletionTest extends CompletionTestCase {
   @failingTest
   Future<void> test_keywords() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class A {
   factory A() = ^
 }
@@ -529,14 +492,13 @@
   B();
 }
 ''');
-    await getSuggestions();
     assertHasNoCompletion('assert');
     assertHasNoCompletion('super');
     assertHasNoCompletion('this');
   }
 
   Future<void> test_namedConstructor_private() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class A {
   factory A() = ^
 }
@@ -544,12 +506,11 @@
   B._();
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('B._');
   }
 
   Future<void> test_namedConstructor_public() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class A {
   factory A() = ^
 }
@@ -557,12 +518,11 @@
   B.b();
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('B.b');
   }
 
   Future<void> test_sameConstructor() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class A {
   factory A() = ^
 }
@@ -570,12 +530,11 @@
   B();
 }
 ''');
-    await getSuggestions();
     assertHasNoCompletion('A');
   }
 
   Future<void> test_unnamedConstructor() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class A {
   factory A() = ^
 }
@@ -583,7 +542,6 @@
   B();
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('B');
   }
 
@@ -594,14 +552,13 @@
   B();
 }
 ''');
-    addTestFile('''
+    await getTestCodeSuggestions('''
 import 'b.dart';
 
 class A {
   factory A() = ^
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('B');
   }
 }
@@ -611,56 +568,51 @@
     extends CompletionTestCase {
   @failingTest
   Future<void> test_instanceMember() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class C {
   C.c() {}
   C() : this.^
 }
 ''');
-    await getSuggestions();
     assertHasNoCompletion('toString');
   }
 
   Future<void> test_namedConstructor_private() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class C {
   C._() {}
   C() : this.^
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('_');
   }
 
   Future<void> test_namedConstructor_public() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class C {
   C.c() {}
   C() : this.^
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('c');
   }
 
   Future<void> test_sameConstructor() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class C {
   C.c() : this.^
 }
 ''');
-    await getSuggestions();
     assertHasNoCompletion('c');
   }
 
   Future<void> test_unnamedConstructor() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class C {
   C() {}
   C.c() : this.^
 }
 ''');
-    await getSuggestions();
     assertHasNoCompletion('');
   }
 }
@@ -668,7 +620,7 @@
 @reflectiveTest
 class ReturnStatementTest extends CompletionTestCase {
   Future<void> test_voidFromVoid_localFunction() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class C {
   void m() {
     void f() {
@@ -678,12 +630,11 @@
   void g() {}
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('g');
   }
 
   Future<void> test_voidFromVoid_method() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class C {
   void f() {
     return ^
@@ -691,18 +642,16 @@
   void g() {}
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('g');
   }
 
   Future<void> test_voidFromVoid_topLevelFunction() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 void f() {
   return ^
 }
 void g() {}
 ''');
-    await getSuggestions();
     assertHasCompletion('g');
   }
 }
@@ -715,19 +664,18 @@
   A._() {}
 }
 ''');
-    addTestFile('''
+    await getTestCodeSuggestions('''
 import 'a.dart';
 
 class B extends A {
   B() : super.^
 }
 ''');
-    await getSuggestions();
     assertHasNoCompletion('_');
   }
 
   Future<void> test_namedConstructor_private() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class A {
   A._() {}
 }
@@ -735,12 +683,11 @@
   B() : super.^
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('_');
   }
 
   Future<void> test_namedConstructor_public() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class A {
   A.a() {}
 }
@@ -748,12 +695,11 @@
   B() : super.^
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('a');
   }
 
   Future<void> test_unnamedConstructor() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class A {
   A() {}
 }
@@ -761,7 +707,6 @@
   B() : super.^
 }
 ''');
-    await getSuggestions();
     assertHasNoCompletion('');
   }
 }
@@ -769,12 +714,11 @@
 @reflectiveTest
 class VariableDeclarationListCompletionTest extends CompletionTestCase {
   Future<void> test_type_voidAfterFinal() async {
-    addTestFile('''
+    await getTestCodeSuggestions('''
 class C {
   final ^
 }
 ''');
-    await getSuggestions();
     assertHasCompletion('void');
   }
 }
diff --git a/pkg/compiler/lib/src/common/elements.dart b/pkg/compiler/lib/src/common/elements.dart
index d4e4c7b..f7d3f71 100644
--- a/pkg/compiler/lib/src/common/elements.dart
+++ b/pkg/compiler/lib/src/common/elements.dart
@@ -1520,7 +1520,7 @@
 
   /// Returns the 'raw type' of [cls]. That is, the instantiation of [cls]
   /// where all types arguments are `dynamic`.
-  InterfaceType getRawType(ClassEntity cls);
+  InterfaceType /*!*/ getRawType(ClassEntity /*!*/ cls);
 
   /// Returns the 'JS-interop type' of [cls]; that is, the instantiation of
   /// [cls] where all type arguments are 'any'.
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index d1999fa..55d0d01 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -70,7 +70,7 @@
 
   KernelFrontendStrategy frontendStrategy;
   JsBackendStrategy backendStrategy;
-  DiagnosticReporter _reporter;
+  /*late*/ DiagnosticReporter _reporter;
   Map<Entity, WorldImpact> _impactCache;
   GenericTask userHandlerTask;
   GenericTask userProviderTask;
diff --git a/pkg/compiler/lib/src/constants/values.dart b/pkg/compiler/lib/src/constants/values.dart
index a109bc5..afc17fe 100644
--- a/pkg/compiler/lib/src/constants/values.dart
+++ b/pkg/compiler/lib/src/constants/values.dart
@@ -104,9 +104,9 @@
   bool get isNegativeInfinity => false;
 
   // TODO(johnniwinther): Replace with a 'type' getter.
-  DartType getType(CommonElements types);
+  DartType /*!*/ getType(CommonElements types);
 
-  List<ConstantValue> getDependencies();
+  List<ConstantValue /*!*/ > /*!*/ getDependencies();
 
   accept(ConstantValueVisitor visitor, arg);
 
@@ -135,9 +135,9 @@
 }
 
 class FunctionConstantValue extends ConstantValue {
-  final FunctionEntity element;
+  final FunctionEntity /*!*/ element;
   // TODO(johnniwinther): Should the type be derived from [element].
-  final FunctionType type;
+  final FunctionType /*!*/ type;
 
   FunctionConstantValue(this.element, this.type);
 
@@ -244,7 +244,7 @@
 }
 
 class IntConstantValue extends NumConstantValue {
-  final BigInt intValue;
+  final BigInt /*!*/ intValue;
 
   // Caching IntConstantValues representing -2 through 10 so that we don't have
   // to create new ones every time those values are used.
@@ -253,7 +253,7 @@
   @override
   double get doubleValue => intValue.toDouble();
 
-  factory IntConstantValue(BigInt value) {
+  factory IntConstantValue(BigInt /*!*/ value) {
     var existing = _cachedValues[value];
     if (existing != null) return existing;
     var intConstantVal = IntConstantValue._internal(value);
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 92e8499..e66e57d 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -1004,20 +1004,24 @@
         ..run();
 
       var allInfo = buildDumpInfoDataNew(closedWorld, kernelInfoCollector);
+      // TODO(markzipan): Filter DumpInfo here instead of passing a filter
+      // filter flag through the serializers.
       if (useBinaryFormat) {
-        dumpInfoBinary(allInfo);
+        dumpInfoBinary(allInfo, filterTreeshaken: true);
       } else {
-        dumpInfoJson(allInfo);
+        dumpInfoJson(allInfo, filterTreeshaken: true);
       }
     });
   }
 
-  void dumpInfoJson(AllInfo data) {
+  void dumpInfoJson(AllInfo data, {bool filterTreeshaken = false}) {
     StringBuffer jsonBuffer = StringBuffer();
     JsonEncoder encoder = const JsonEncoder.withIndent('  ');
     ChunkedConversionSink<Object> sink = encoder.startChunkedConversion(
         StringConversionSink.fromStringSink(jsonBuffer));
-    sink.add(AllInfoJsonCodec(isBackwardCompatible: true).encode(data));
+    sink.add(AllInfoJsonCodec(
+            isBackwardCompatible: true, filterTreeshaken: filterTreeshaken)
+        .encode(data));
     compiler.outputProvider.createOutputSink(
         compiler.options.outputUri.pathSegments.last,
         'info.json',
@@ -1031,8 +1035,10 @@
     });
   }
 
-  void dumpInfoBinary(AllInfo data) {
+  void dumpInfoBinary(AllInfo data, {bool filterTreeshaken = false}) {
     var name = compiler.options.outputUri.pathSegments.last + ".info.data";
+    // TODO(markzipan): Plumb [filterTreeshaken] through
+    // [BinaryOutputSinkAdapter].
     Sink<List<int>> sink = BinaryOutputSinkAdapter(compiler.outputProvider
         .createBinarySink(compiler.options.outputUri.resolve(name)));
     dump_info.encode(data, sink);
@@ -1137,6 +1143,7 @@
         // Don't register dart2js builtin functions that are not recorded.
         Info useInfo = infoCollector._entityToInfo[selection.selectedEntity];
         if (useInfo == null) continue;
+        if (useInfo.treeShakenStatus != TreeShakenStatus.Live) continue;
         info.uses.add(
             DependencyInfo(useInfo, selection.receiverConstraint?.toString()));
       }
@@ -1152,6 +1159,7 @@
       for (Selection selection in uses) {
         Info useInfo = infoCollector._entityToInfo[selection.selectedEntity];
         if (useInfo == null) continue;
+        if (useInfo.treeShakenStatus != TreeShakenStatus.Live) continue;
         info.uses.add(
             DependencyInfo(useInfo, selection.receiverConstraint?.toString()));
       }
@@ -1164,6 +1172,7 @@
       for (Entity inlined in inlineMap[entity]) {
         Info inlinedInfo = infoCollector._entityToInfo[inlined];
         if (inlinedInfo == null) continue;
+        if (inlinedInfo.treeShakenStatus != TreeShakenStatus.Live) continue;
         outerInfo.uses.add(DependencyInfo(inlinedInfo, 'inlined'));
       }
     }
diff --git a/pkg/compiler/lib/src/elements/entities.dart b/pkg/compiler/lib/src/elements/entities.dart
index d363a30..0451c39 100644
--- a/pkg/compiler/lib/src/elements/entities.dart
+++ b/pkg/compiler/lib/src/elements/entities.dart
@@ -34,7 +34,7 @@
 /// and/or Dart-in-JS classes.
 abstract class LibraryEntity extends Entity {
   /// Return the canonical uri that identifies this library.
-  Uri get canonicalUri;
+  Uri /*!*/ get canonicalUri;
 
   /// Returns whether or not this library has opted into null safety.
   bool get isNonNullableByDefault;
@@ -125,14 +125,14 @@
   bool get isSetter;
 
   /// Whether this member is assignable, i.e. a non-final, non-const field.
-  bool get isAssignable;
+  bool /*!*/ get isAssignable;
 
   /// Whether this member is constant, i.e. a constant field or constructor.
-  bool get isConst;
+  bool /*!*/ get isConst;
 
   /// Whether this member is abstract, i.e. an abstract method, getter or
   /// setter.
-  bool get isAbstract;
+  bool /*!*/ get isAbstract;
 
   /// The enclosing class if this is a constructor, instance member or
   /// static member of a class.
@@ -156,7 +156,7 @@
 abstract class FunctionEntity extends MemberEntity {
   /// Whether this function is external, i.e. the body is not defined in terms
   /// of Dart code.
-  bool get isExternal;
+  bool /*!*/ get isExternal;
 
   /// The structure of the function parameters.
   ParameterStructure get parameterStructure;
diff --git a/pkg/compiler/lib/src/hash/sha1.dart b/pkg/compiler/lib/src/hash/sha1.dart
index 4c4e65b..e8698a0 100644
--- a/pkg/compiler/lib/src/hash/sha1.dart
+++ b/pkg/compiler/lib/src/hash/sha1.dart
@@ -47,7 +47,7 @@
   Digest _value;
 
   /// The value added to the sink, if any.
-  Digest get value {
+  Digest /*!*/ get value {
     assert(_value != null);
     return _value;
   }
diff --git a/pkg/compiler/lib/src/ir/element_map.dart b/pkg/compiler/lib/src/ir/element_map.dart
index e021596..6d8c86a 100644
--- a/pkg/compiler/lib/src/ir/element_map.dart
+++ b/pkg/compiler/lib/src/ir/element_map.dart
@@ -54,7 +54,7 @@
   /// [node].
   TypeVariableEntity getTypeVariable(ir.TypeParameter node);
 
-  CommonElements get commonElements;
+  CommonElements /*!*/ get commonElements;
   DiagnosticReporter get reporter;
   ir.CoreTypes get coreTypes;
   InterfaceType getThisType(IndexedClass cls);
diff --git a/pkg/compiler/lib/src/ir/visitors.dart b/pkg/compiler/lib/src/ir/visitors.dart
index a85e726..aea9e7d 100644
--- a/pkg/compiler/lib/src/ir/visitors.dart
+++ b/pkg/compiler/lib/src/ir/visitors.dart
@@ -43,7 +43,7 @@
 }
 
 /// Visitor that converts kernel dart types into [DartType].
-class DartTypeConverter extends ir.DartTypeVisitor<DartType> {
+class DartTypeConverter extends ir.DartTypeVisitor<DartType /*!*/ > {
   final IrToElementMap elementMap;
   final Map<ir.TypeParameter, DartType> currentFunctionTypeParameters =
       <ir.TypeParameter, DartType>{};
diff --git a/pkg/compiler/lib/src/js/js_debug.dart b/pkg/compiler/lib/src/js/js_debug.dart
index df828b6..c50a232 100644
--- a/pkg/compiler/lib/src/js/js_debug.dart
+++ b/pkg/compiler/lib/src/js/js_debug.dart
@@ -11,8 +11,6 @@
 import 'package:js_ast/js_ast.dart';
 import 'package:kernel/text/indentation.dart' show Indentation, Tagging;
 
-import '../io/code_output.dart' show BufferedCodeOutput;
-
 /// Unparse the JavaScript [node].
 String nodeToString(Node node, {bool pretty = false}) {
   JavaScriptPrintingOptions options = JavaScriptPrintingOptions(
@@ -64,8 +62,7 @@
 }
 
 /// Simple printing context that doesn't throw on errors.
-class LenientPrintingContext extends SimpleJavaScriptPrintingContext
-    implements BufferedCodeOutput {
+class LenientPrintingContext extends SimpleJavaScriptPrintingContext {
   @override
   void error(String message) {
     buffer.write('>>$message<<');
diff --git a/pkg/compiler/lib/src/js_backend/constant_emitter.dart b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
index 5b3a396..fcc9618 100644
--- a/pkg/compiler/lib/src/js_backend/constant_emitter.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
@@ -10,7 +10,6 @@
 import '../constants/values.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart';
-import '../io/code_output.dart';
 import '../js/js.dart' as jsAst;
 import '../js/js.dart' show js;
 import '../js_backend/field_analysis.dart';
diff --git a/pkg/compiler/lib/src/js_model/js_world.dart b/pkg/compiler/lib/src/js_model/js_world.dart
index 6b64172..a90587d 100644
--- a/pkg/compiler/lib/src/js_model/js_world.dart
+++ b/pkg/compiler/lib/src/js_model/js_world.dart
@@ -83,7 +83,7 @@
   final JsKernelToElementMap elementMap;
   @override
   final RuntimeTypesNeed rtiNeed;
-  AbstractValueDomain _abstractValueDomain;
+  AbstractValueDomain /*!*/ _abstractValueDomain;
   @override
   final JFieldAnalysis fieldAnalysis;
   @override
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index 4b9a722..42536ed 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -66,7 +66,7 @@
   final NativeBasicDataBuilder nativeBasicDataBuilder =
       NativeBasicDataBuilder();
   NativeBasicData _nativeBasicData;
-  KCommonElements _commonElements;
+  KCommonElements /*!*/ _commonElements;
   KernelElementEnvironment _elementEnvironment;
   DartTypeConverter _typeConverter;
   KernelDartTypes _types;
@@ -1686,7 +1686,9 @@
 
   IndexedFunction createGetter(LibraryEntity library,
       ClassEntity enclosingClass, Name name, AsyncMarker asyncMarker,
-      {bool isStatic, bool isExternal, bool isAbstract}) {
+      {/*required*/ bool isStatic,
+      /*required*/ bool isExternal,
+      /*required*/ bool isAbstract}) {
     return KGetter(library, enclosingClass, name, asyncMarker,
         isStatic: isStatic, isExternal: isExternal, isAbstract: isAbstract);
   }
@@ -1697,9 +1699,9 @@
       Name name,
       ParameterStructure parameterStructure,
       AsyncMarker asyncMarker,
-      {bool isStatic,
-      bool isExternal,
-      bool isAbstract}) {
+      {/*required*/ bool isStatic,
+      /*required*/ bool isExternal,
+      /*required*/ bool isAbstract}) {
     return KMethod(
         library, enclosingClass, name, parameterStructure, asyncMarker,
         isStatic: isStatic, isExternal: isExternal, isAbstract: isAbstract);
@@ -1707,14 +1709,18 @@
 
   IndexedFunction createSetter(
       LibraryEntity library, ClassEntity enclosingClass, Name name,
-      {bool isStatic, bool isExternal, bool isAbstract}) {
+      {/*required*/ bool isStatic,
+      /*required*/ bool isExternal,
+      /*required*/ bool isAbstract}) {
     return KSetter(library, enclosingClass, name,
         isStatic: isStatic, isExternal: isExternal, isAbstract: isAbstract);
   }
 
   IndexedField createField(
       LibraryEntity library, ClassEntity enclosingClass, Name name,
-      {bool isStatic, bool isAssignable, bool isConst}) {
+      {/*required*/ bool isStatic,
+      /*required*/ bool isAssignable,
+      /*required*/ bool isConst}) {
     return KField(library, enclosingClass, name,
         isStatic: isStatic, isAssignable: isAssignable, isConst: isConst);
   }
diff --git a/pkg/compiler/lib/src/kernel/kelements.dart b/pkg/compiler/lib/src/kernel/kelements.dart
index 8d37d9f..bb67948 100644
--- a/pkg/compiler/lib/src/kernel/kelements.dart
+++ b/pkg/compiler/lib/src/kernel/kelements.dart
@@ -187,7 +187,9 @@
 
   KMethod(KLibrary library, KClass enclosingClass, Name name,
       ParameterStructure parameterStructure, AsyncMarker asyncMarker,
-      {bool isStatic, bool isExternal, this.isAbstract})
+      {/*required*/ bool isStatic,
+      /*required*/ bool isExternal,
+      /*required*/ this.isAbstract})
       : super(library, enclosingClass, name, parameterStructure, asyncMarker,
             isStatic: isStatic, isExternal: isExternal);
 
@@ -204,7 +206,9 @@
 
   KGetter(KLibrary library, KClass enclosingClass, Name name,
       AsyncMarker asyncMarker,
-      {bool isStatic, bool isExternal, this.isAbstract})
+      {/*required*/ bool isStatic,
+      /*required*/ bool isExternal,
+      /*required*/ this.isAbstract})
       : super(library, enclosingClass, name, ParameterStructure.getter,
             asyncMarker,
             isStatic: isStatic, isExternal: isExternal);
@@ -221,7 +225,9 @@
   final bool isAbstract;
 
   KSetter(KLibrary library, KClass enclosingClass, Name name,
-      {bool isStatic, bool isExternal, this.isAbstract})
+      {/*required*/ bool isStatic,
+      /*required*/ bool isExternal,
+      /*required*/ this.isAbstract})
       : super(library, enclosingClass, name, ParameterStructure.setter,
             AsyncMarker.SYNC,
             isStatic: isStatic, isExternal: isExternal);
@@ -243,7 +249,9 @@
   final bool isConst;
 
   KField(KLibrary library, KClass enclosingClass, Name name,
-      {bool isStatic, this.isAssignable, this.isConst})
+      {/*required*/ bool isStatic,
+      /*required*/ this.isAssignable,
+      /*required*/ this.isConst})
       : super(library, enclosingClass, name, isStatic: isStatic);
 
   @override
diff --git a/pkg/compiler/lib/src/kernel/kernel_strategy.dart b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
index 0a7cda9..94f87ab 100644
--- a/pkg/compiler/lib/src/kernel/kernel_strategy.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
@@ -53,7 +53,7 @@
 class KernelFrontendStrategy {
   final CompilerOptions _options;
   final CompilerTask _compilerTask;
-  KernelToElementMap _elementMap;
+  /*late*/ KernelToElementMap _elementMap;
   RuntimeTypesNeedBuilder _runtimeTypesNeedBuilder;
 
   KernelAnnotationProcessor _annotationProcessor;
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index f5e81f0..dbdf302 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -392,7 +392,7 @@
 
   /// If the [instruction] is not `null` it will be used to attach the position
   /// to the [expression].
-  push(js.Expression expression) {
+  push(js.Expression /*!*/ expression) {
     expressionStack.add(expression);
   }
 
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 1eb9226..16ac75c 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -185,7 +185,7 @@
     }
   }
 
-  visitBasicBlock(HBasicBlock block);
+  visitBasicBlock(HBasicBlock /*!*/ block);
 }
 
 class _Frame {
@@ -1032,9 +1032,9 @@
   SourceInformation sourceInformation;
 
   final int id = idCounter++;
-  static int idCounter;
+  static int idCounter = 0;
 
-  final List<HInstruction> inputs;
+  final List<HInstruction /*!*/ > inputs;
   final List<HInstruction> usedBy = [];
 
   HBasicBlock block;
diff --git a/pkg/dart2js_info/lib/info.dart b/pkg/dart2js_info/lib/info.dart
index 1ebb2a7..d5d64bf 100644
--- a/pkg/dart2js_info/lib/info.dart
+++ b/pkg/dart2js_info/lib/info.dart
@@ -26,9 +26,15 @@
   /// Info of the enclosing element.
   Info parent;
 
+  /// At which stage of the compiler this component was treeshaken.
+  TreeShakenStatus treeShakenStatus;
+
   T accept<T>(InfoVisitor<T> visitor);
 }
 
+/// Indicates at what stage of compilation the [Info] element was treeshaken.
+enum TreeShakenStatus { Dead, Live }
+
 /// Common information used for most kind of elements.
 // TODO(sigmund): add more:
 //  - inputSize: bytes used in the Dart source program
@@ -42,6 +48,8 @@
   int size;
   @override
   Info parent;
+  @override
+  TreeShakenStatus treeShakenStatus = TreeShakenStatus.Dead;
 
   @override
   String name;
diff --git a/pkg/dart2js_info/lib/json_info_codec.dart b/pkg/dart2js_info/lib/json_info_codec.dart
index 1b741a7..40d0332 100644
--- a/pkg/dart2js_info/lib/json_info_codec.dart
+++ b/pkg/dart2js_info/lib/json_info_codec.dart
@@ -11,10 +11,6 @@
 import 'info.dart';
 import 'src/util.dart';
 
-List<String> _toSortedSerializedIds(
-        Iterable<Info> infos, Id Function(Info) getId) =>
-    infos.map((i) => getId(i).serializedId).toList()..sort(compareNatural);
-
 // TODO(sigmund): add unit tests.
 class JsonToAllInfoConverter extends Converter<Map<String, dynamic>, AllInfo> {
   // Using `MashMap` here because it's faster than the default `LinkedHashMap`.
@@ -349,10 +345,14 @@
     implements InfoVisitor<Map> {
   /// Whether to generate json compatible with format 5.1
   final bool isBackwardCompatible;
+
+  /// Whether to filter all treeshaken elements.
+  final bool filterTreeshaken;
   final Map<Info, Id> ids = HashMap<Info, Id>();
   final Set<int> usedIds = <int>{};
 
-  AllInfoToJsonConverter({this.isBackwardCompatible = false});
+  AllInfoToJsonConverter(
+      {this.isBackwardCompatible = false, this.filterTreeshaken = false});
 
   Id idFor(Info info) {
     var serializedId = ids[info];
@@ -391,6 +391,12 @@
     // Using SplayTree to maintain a consistent order of keys
     var map = SplayTreeMap<String, Map>(compareNatural);
     for (var info in infos) {
+      if (info is BasicInfo) {
+        if (filterTreeshaken &&
+            info.treeShakenStatus != TreeShakenStatus.Live) {
+          continue;
+        }
+      }
       map[idFor(info).id] = info.accept(this);
     }
     return map;
@@ -500,15 +506,13 @@
   Map visitLibrary(LibraryInfo info) {
     return _visitBasicInfo(info)
       ..addAll(<String, Object>{
-        'children': _toSortedSerializedIds(
-            [
-              info.topLevelFunctions,
-              info.topLevelVariables,
-              info.classes,
-              info.classTypes,
-              info.typedefs
-            ].expand((i) => i),
-            idFor),
+        'children': _toSortedSerializedIds([
+          ...info.topLevelFunctions,
+          ...info.topLevelVariables,
+          ...info.classes,
+          ...info.classTypes,
+          ...info.typedefs
+        ], idFor),
         'canonicalUri': '${info.uri}',
       });
   }
@@ -519,8 +523,8 @@
       ..addAll(<String, Object>{
         // TODO(sigmund): change format, include only when abstract is true.
         'modifiers': {'abstract': info.isAbstract},
-        'children': _toSortedSerializedIds(
-            [info.fields, info.functions].expand((i) => i), idFor)
+        'children':
+            _toSortedSerializedIds([...info.fields, ...info.functions], idFor)
       });
   }
 
@@ -613,6 +617,15 @@
             })
         .toList();
   }
+
+  List<String> _toSortedSerializedIds(
+          Iterable<Info> infos, Id Function(Info) getId) =>
+      infos
+          .where((i) =>
+              !filterTreeshaken || i.treeShakenStatus == TreeShakenStatus.Live)
+          .map((i) => getId(i).serializedId)
+          .toList()
+        ..sort(compareNatural);
 }
 
 class AllInfoJsonCodec extends Codec<AllInfo, Map> {
@@ -621,9 +634,11 @@
   @override
   final Converter<Map, AllInfo> decoder = JsonToAllInfoConverter();
 
-  AllInfoJsonCodec({bool isBackwardCompatible = false})
-      : encoder =
-            AllInfoToJsonConverter(isBackwardCompatible: isBackwardCompatible);
+  AllInfoJsonCodec(
+      {bool isBackwardCompatible = false, bool filterTreeshaken = false})
+      : encoder = AllInfoToJsonConverter(
+            isBackwardCompatible: isBackwardCompatible,
+            filterTreeshaken: filterTreeshaken);
 }
 
 class Id {
diff --git a/pkg/js_ast/lib/src/nodes.dart b/pkg/js_ast/lib/src/nodes.dart
index fab2e1b..661efd6 100644
--- a/pkg/js_ast/lib/src/nodes.dart
+++ b/pkg/js_ast/lib/src/nodes.dart
@@ -580,7 +580,7 @@
   /// Returns a node equivalent to [this], but with new source position and end
   /// source position.
   Node withSourceInformation(
-      JavaScriptNodeSourceInformation sourceInformation) {
+      JavaScriptNodeSourceInformation? sourceInformation) {
     if (sourceInformation == _sourceInformation) {
       return this;
     }
diff --git a/runtime/vm/cpu_arm.cc b/runtime/vm/cpu_arm.cc
index eef1084..ce9a8ff 100644
--- a/runtime/vm/cpu_arm.cc
+++ b/runtime/vm/cpu_arm.cc
@@ -20,6 +20,10 @@
 #elif defined(DART_HOST_OS_WINDOWS)
 #include <processthreadsapi.h>
 #endif
+#if !defined(DART_HOST_OS_WINDOWS)
+#include <string.h>      /* NOLINT */
+#include <sys/utsname.h> /* NOLINT */
+#endif
 #endif
 
 // ARM version differences.
@@ -145,20 +149,27 @@
   CpuInfo::Init();
   hardware_ = CpuInfo::GetCpuModel();
 
+  // QEMU may report host cpuinfo instead of emulated cpuinfo, use uname as a
+  // fallback for checking if CPU is AArch64 or ARMv7.
+  struct utsname uname_;
+  int ret_ = uname(&uname_);
+
   // Check for ARMv7, or aarch64.
   // It can be in either the Processor or Model information fields.
   if (CpuInfo::FieldContains(kCpuInfoProcessor, "aarch64") ||
       CpuInfo::FieldContains(kCpuInfoModel, "aarch64") ||
       CpuInfo::FieldContains(kCpuInfoArchitecture, "8") ||
-      CpuInfo::FieldContains(kCpuInfoArchitecture, "AArch64")) {
+      CpuInfo::FieldContains(kCpuInfoArchitecture, "AArch64") ||
+      (ret_ == 0 && (strstr(uname_.machine, "aarch64") != NULL ||
+                     strstr(uname_.machine, "arm64") != NULL ||
+                     strstr(uname_.machine, "armv8") != NULL))) {
     // pretend that this arm64 cpu is really an ARMv7
     is_arm64 = true;
   } else if (!CpuInfo::FieldContains(kCpuInfoProcessor, "ARMv7") &&
              !CpuInfo::FieldContains(kCpuInfoModel, "ARMv7") &&
-             !CpuInfo::FieldContains(kCpuInfoArchitecture, "7")) {
-#if !defined(DART_RUN_IN_QEMU_ARMv7)
+             !CpuInfo::FieldContains(kCpuInfoArchitecture, "7") &&
+             !(ret_ == 0 && strstr(uname_.machine, "armv7") != NULL)) {
     FATAL("Unrecognized ARM CPU architecture.");
-#endif
   }
 
   // Has integer division.
@@ -203,7 +214,7 @@
 
 // Use the cross-compiler's predefined macros to determine whether we should
 // use the hard or soft float ABI.
-#if defined(__ARM_PCS_VFP) || defined(DART_RUN_IN_QEMU_ARMv7)
+#if defined(__ARM_PCS_VFP)
   hardfp_supported_ = true;
 #else
   hardfp_supported_ = false;
diff --git a/sdk/lib/js/js_wasm.dart b/sdk/lib/js/js_wasm.dart
index 847e6e0..28fa458 100644
--- a/sdk/lib/js/js_wasm.dart
+++ b/sdk/lib/js/js_wasm.dart
@@ -9,8 +9,14 @@
   const JS([this.name]);
 }
 
+class _Anonymous {
+  const _Anonymous();
+}
+
 class _StaticInterop {
   const _StaticInterop();
 }
 
+const _Anonymous anonymous = _Anonymous();
+
 const _StaticInterop staticInterop = _StaticInterop();
diff --git a/tests/web/wasm/static_interop_test.dart b/tests/web/wasm/static_interop_test.dart
index c1be1eb..97bb80f 100644
--- a/tests/web/wasm/static_interop_test.dart
+++ b/tests/web/wasm/static_interop_test.dart
@@ -138,9 +138,31 @@
   Expect.equals(fooBar('hello'), 'hello world!');
 }
 
+@JS()
+@anonymous
+@staticInterop
+class AnonymousJSClass {
+  external factory AnonymousJSClass.factory(
+      {String? foo, String bar = 'baz', String? bleep});
+}
+
+extension AnonymousJSClassExtension on AnonymousJSClass {
+  external String? get foo;
+  external String get bar;
+  external String? get bleep;
+}
+
+void anonymousTest() {
+  final anonymousJSClass = AnonymousJSClass.factory(foo: 'boo');
+  Expect.equals('boo', anonymousJSClass.foo);
+  Expect.equals('baz', anonymousJSClass.bar);
+  Expect.equals(null, anonymousJSClass.bleep);
+}
+
 void main() {
   createClassTest();
   setInteropPropertyTest();
   setDartObjectPropertyTest();
   topLevelMethodsTest();
+  anonymousTest();
 }
diff --git a/tools/VERSION b/tools/VERSION
index 822343f..fd91a2d 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 18
 PATCH 0
-PRERELEASE 17
+PRERELEASE 18
 PRERELEASE_PATCH 0
\ No newline at end of file