Version 2.13.0-27.0.dev

Merge commit '6944a2c1ec9c2c6018e21c27ed868ff1ad6cfb1a' into 'dev'
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index d3df682..62fa573 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -1525,7 +1525,11 @@
     var builder = callbacks.createContextBuilder(info.folder);
     var options = builder.getAnalysisOptions(contextRoot,
         contextRoot: driver.contextRoot);
-    var packages = builder.createPackageMap(contextRoot);
+    var packages = ContextBuilder.createPackageMap(
+      resourceProvider: builder.resourceProvider,
+      options: builder.builderOptions,
+      rootPath: contextRoot,
+    );
     var factory = builder.createSourceFactory(contextRoot);
     driver.configure(
       analysisOptions: options,
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
index f2bec91..87d5edb 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
@@ -70,6 +70,31 @@
 
     final unit = await path.mapResult(requireResolvedUnit);
 
+    bool shouldIncludeKind(CodeActionKind kind) {
+      /// Checks whether the kind matches the [wanted] kind.
+      ///
+      /// If `wanted` is `refactor.foo` then:
+      ///  - refactor.foo - included
+      ///  - refactor.foobar - not included
+      ///  - refactor.foo.bar - included
+      bool isMatch(CodeActionKind wanted) =>
+          kind == wanted || kind.toString().startsWith('${wanted.toString()}.');
+
+      // If the client wants only a specific set, use only that filter.
+      if (params.context?.only != null) {
+        return params.context.only.any(isMatch);
+      }
+
+      // Otherwise, filter out anything not supported by the client (if they
+      // advertised that they provided the kinds).
+      if (clientSupportsLiteralCodeActions &&
+          !clientSupportedCodeActionKinds.any(isMatch)) {
+        return false;
+      }
+
+      return true;
+    }
+
     return unit.mapResult((unit) {
       final startOffset = toOffset(unit.lineInfo, params.range.start);
       final endOffset = toOffset(unit.lineInfo, params.range.end);
@@ -78,7 +103,7 @@
           final offset = startOffset;
           final length = endOffset - startOffset;
           return _getCodeActions(
-              clientSupportedCodeActionKinds,
+              shouldIncludeKind,
               clientSupportsLiteralCodeActions,
               clientSupportsWorkspaceApplyEdit,
               clientSupportedDiagnosticTags,
@@ -218,19 +243,13 @@
   }
 
   Future<List<Either2<Command, CodeAction>>> _getAssistActions(
-    HashSet<CodeActionKind> clientSupportedCodeActionKinds,
+    bool Function(CodeActionKind) shouldIncludeKind,
     bool clientSupportsLiteralCodeActions,
     Range range,
     int offset,
     int length,
     ResolvedUnitResult unit,
   ) async {
-    // We only support these for clients that advertise codeActionLiteralSupport.
-    if (!clientSupportsLiteralCodeActions ||
-        !clientSupportedCodeActionKinds.contains(CodeActionKind.Refactor)) {
-      return const [];
-    }
-
     try {
       var context = DartAssistContextImpl(
         server.instrumentationService,
@@ -247,6 +266,7 @@
           _dedupeActions(assists.map(_createAssistAction), range.start);
 
       return assistActions
+          .where((action) => shouldIncludeKind(action.kind))
           .map((action) => Either2<Command, CodeAction>.t2(action))
           .toList();
     } on InconsistentAnalysisException {
@@ -258,7 +278,7 @@
   }
 
   Future<ErrorOr<List<Either2<Command, CodeAction>>>> _getCodeActions(
-    HashSet<CodeActionKind> kinds,
+    bool Function(CodeActionKind) shouldIncludeKind,
     bool supportsLiterals,
     bool supportsWorkspaceApplyEdit,
     HashSet<DiagnosticTag> supportedDiagnosticTags,
@@ -269,12 +289,14 @@
     ResolvedUnitResult unit,
   ) async {
     final results = await Future.wait([
-      _getSourceActions(
-          kinds, supportsLiterals, supportsWorkspaceApplyEdit, path),
-      _getAssistActions(kinds, supportsLiterals, range, offset, length, unit),
-      _getRefactorActions(kinds, supportsLiterals, path, offset, length, unit),
-      _getFixActions(
-          kinds, supportsLiterals, supportedDiagnosticTags, range, unit),
+      _getSourceActions(shouldIncludeKind, supportsLiterals,
+          supportsWorkspaceApplyEdit, path),
+      _getAssistActions(
+          shouldIncludeKind, supportsLiterals, range, offset, length, unit),
+      _getRefactorActions(
+          shouldIncludeKind, supportsLiterals, path, offset, length, unit),
+      _getFixActions(shouldIncludeKind, supportsLiterals,
+          supportedDiagnosticTags, range, unit),
     ]);
     final flatResults = results.expand((x) => x).toList();
 
@@ -282,18 +304,12 @@
   }
 
   Future<List<Either2<Command, CodeAction>>> _getFixActions(
-    HashSet<CodeActionKind> clientSupportedCodeActionKinds,
+    bool Function(CodeActionKind) shouldIncludeKind,
     bool clientSupportsLiteralCodeActions,
     HashSet<DiagnosticTag> supportedDiagnosticTags,
     Range range,
     ResolvedUnitResult unit,
   ) async {
-    // We only support these for clients that advertise codeActionLiteralSupport.
-    if (!clientSupportsLiteralCodeActions ||
-        !clientSupportedCodeActionKinds.contains(CodeActionKind.QuickFix)) {
-      return const [];
-    }
-
     final lineInfo = unit.lineInfo;
     final codeActions = <CodeAction>[];
     final fixAllCodeActions = <CodeAction>[];
@@ -374,6 +390,7 @@
       final dedupedActions = _dedupeActions(codeActions, range.start);
 
       return dedupedActions
+          .where((action) => shouldIncludeKind(action.kind))
           .map((action) => Either2<Command, CodeAction>.t2(action))
           .toList();
     } on InconsistentAnalysisException {
@@ -385,7 +402,7 @@
   }
 
   Future<List<Either2<Command, CodeAction>>> _getRefactorActions(
-    HashSet<CodeActionKind> clientSupportedCodeActionKinds,
+    bool Function(CodeActionKind) shouldIncludeKind,
     bool clientSupportsLiteralCodeActions,
     String path,
     int offset,
@@ -397,13 +414,6 @@
       return const [];
     }
 
-    // If the client told us what kinds they support but it does not include
-    // Refactor then don't return any.
-    if (clientSupportsLiteralCodeActions &&
-        !clientSupportedCodeActionKinds.contains(CodeActionKind.Refactor)) {
-      return const [];
-    }
-
     /// Helper to create refactors that execute commands provided with
     /// the current file, location and document version.
     Either2<Command, CodeAction> createRefactor(
@@ -432,24 +442,29 @@
     try {
       final refactorActions = <Either2<Command, CodeAction>>[];
 
-      // Extract Method
-      if (ExtractMethodRefactoring(server.searchEngine, unit, offset, length)
-          .isAvailable()) {
-        refactorActions.add(createRefactor(CodeActionKind.RefactorExtract,
-            'Extract Method', RefactoringKind.EXTRACT_METHOD));
-      }
+      // Extracts
+      if (shouldIncludeKind(CodeActionKind.RefactorExtract)) {
+        // Extract Method
+        if (ExtractMethodRefactoring(server.searchEngine, unit, offset, length)
+            .isAvailable()) {
+          refactorActions.add(createRefactor(CodeActionKind.RefactorExtract,
+              'Extract Method', RefactoringKind.EXTRACT_METHOD));
+        }
 
-      // Extract Local Variable
-      if (ExtractLocalRefactoring(unit, offset, length).isAvailable()) {
-        refactorActions.add(createRefactor(CodeActionKind.RefactorExtract,
-            'Extract Local Variable', RefactoringKind.EXTRACT_LOCAL_VARIABLE));
-      }
+        // Extract Local Variable
+        if (ExtractLocalRefactoring(unit, offset, length).isAvailable()) {
+          refactorActions.add(createRefactor(
+              CodeActionKind.RefactorExtract,
+              'Extract Local Variable',
+              RefactoringKind.EXTRACT_LOCAL_VARIABLE));
+        }
 
-      // Extract Widget
-      if (ExtractWidgetRefactoring(server.searchEngine, unit, offset, length)
-          .isAvailable()) {
-        refactorActions.add(createRefactor(CodeActionKind.RefactorExtract,
-            'Extract Widget', RefactoringKind.EXTRACT_WIDGET));
+        // Extract Widget
+        if (ExtractWidgetRefactoring(server.searchEngine, unit, offset, length)
+            .isAvailable()) {
+          refactorActions.add(createRefactor(CodeActionKind.RefactorExtract,
+              'Extract Widget', RefactoringKind.EXTRACT_WIDGET));
+        }
       }
 
       return refactorActions;
@@ -464,7 +479,7 @@
   /// Gets "Source" CodeActions, which are actions that apply to whole files of
   /// source such as Sort Members and Organise Imports.
   Future<List<Either2<Command, CodeAction>>> _getSourceActions(
-    HashSet<CodeActionKind> clientSupportedCodeActionKinds,
+    bool Function(CodeActionKind) shouldIncludeKind,
     bool clientSupportsLiteralCodeActions,
     bool clientSupportsWorkspaceApplyEdit,
     String path,
@@ -474,13 +489,6 @@
       return const [];
     }
 
-    // If the client told us what kinds they support but it does not include
-    // Source then don't return any.
-    if (clientSupportsLiteralCodeActions &&
-        !clientSupportedCodeActionKinds.contains(CodeActionKind.Source)) {
-      return const [];
-    }
-
     // If the client does not support workspace/applyEdit, we won't be able to
     // run any of these.
     if (!clientSupportsWorkspaceApplyEdit) {
@@ -488,22 +496,24 @@
     }
 
     return [
-      _commandOrCodeAction(
-        clientSupportsLiteralCodeActions,
-        DartCodeActionKind.SortMembers,
-        Command(
-            title: 'Sort Members',
-            command: Commands.sortMembers,
-            arguments: [path]),
-      ),
-      _commandOrCodeAction(
-        clientSupportsLiteralCodeActions,
-        CodeActionKind.SourceOrganizeImports,
-        Command(
-            title: 'Organize Imports',
-            command: Commands.organizeImports,
-            arguments: [path]),
-      ),
+      if (shouldIncludeKind(DartCodeActionKind.SortMembers))
+        _commandOrCodeAction(
+          clientSupportsLiteralCodeActions,
+          DartCodeActionKind.SortMembers,
+          Command(
+              title: 'Sort Members',
+              command: Commands.sortMembers,
+              arguments: [path]),
+        ),
+      if (shouldIncludeKind(CodeActionKind.SourceOrganizeImports))
+        _commandOrCodeAction(
+          clientSupportsLiteralCodeActions,
+          CodeActionKind.SourceOrganizeImports,
+          Command(
+              title: 'Organize Imports',
+              command: Commands.organizeImports,
+              arguments: [path]),
+        ),
     ];
   }
 }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart
index 242c72f..4a74f56 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart
@@ -36,11 +36,19 @@
     if (!server.initializationOptions.onlyAnalyzeProjectsWithOpenFiles) {
       if (params.workspaceFolders != null) {
         params.workspaceFolders.forEach((wf) {
-          openWorkspacePaths.add(Uri.parse(wf.uri).toFilePath());
+          final uri = Uri.parse(wf.uri);
+          // Only file URIs are supported, but there's no way to signal this to
+          // the LSP client (and certainly not before initialization).
+          if (uri.isScheme('file')) {
+            openWorkspacePaths.add(uri.toFilePath());
+          }
         });
       }
       if (params.rootUri != null) {
-        openWorkspacePaths.add(Uri.parse(params.rootUri).toFilePath());
+        final uri = Uri.parse(params.rootUri);
+        if (uri.isScheme('file')) {
+          openWorkspacePaths.add(uri.toFilePath());
+        }
       } else if (params.rootPath != null) {
         openWorkspacePaths.add(params.rootPath);
       }
diff --git a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
index a0dbd4c..f020e2a 100644
--- a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
@@ -8,69 +8,12 @@
 import 'package:analysis_server/protocol/protocol_generated.dart';
 import 'package:analysis_server/src/services/correction/change_workspace.dart';
 import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
-import 'package:analysis_server/src/services/correction/dart/add_await.dart';
-import 'package:analysis_server/src/services/correction/dart/add_const.dart';
-import 'package:analysis_server/src/services/correction/dart/add_diagnostic_property_reference.dart';
-import 'package:analysis_server/src/services/correction/dart/add_override.dart';
-import 'package:analysis_server/src/services/correction/dart/add_required.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_add_all_to_spread.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_conditional_expression_to_if_element.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_documentation_into_line.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_into_is_not.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_map_from_iterable_to_for_literal.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_quotes.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_contains.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_generic_function_syntax.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_if_null.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_int_literal.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_list_literal.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_map_literal.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_null_aware.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_package_import.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_relative_import.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_set_literal.dart';
-import 'package:analysis_server/src/services/correction/dart/convert_to_where_type.dart';
-import 'package:analysis_server/src/services/correction/dart/create_method.dart';
 import 'package:analysis_server/src/services/correction/dart/data_driven.dart';
-import 'package:analysis_server/src/services/correction/dart/inline_invocation.dart';
-import 'package:analysis_server/src/services/correction/dart/inline_typedef.dart';
-import 'package:analysis_server/src/services/correction/dart/make_final.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_argument.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_await.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_const.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_duplicate_case.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_empty_catch.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_empty_constructor_body.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_empty_else.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_empty_statement.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_if_null_operator.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_initializer.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_interpolation_braces.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_method_declaration.dart';
 import 'package:analysis_server/src/services/correction/dart/remove_non_null_assertion.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_operator.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_this_expression.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_type_annotation.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_unnecessary_new.dart';
-import 'package:analysis_server/src/services/correction/dart/remove_unnecessary_string_interpolation.dart';
-import 'package:analysis_server/src/services/correction/dart/rename_to_camel_case.dart';
-import 'package:analysis_server/src/services/correction/dart/replace_cascade_with_dot.dart';
-import 'package:analysis_server/src/services/correction/dart/replace_colon_with_equals.dart';
-import 'package:analysis_server/src/services/correction/dart/replace_final_with_const.dart';
-import 'package:analysis_server/src/services/correction/dart/replace_null_with_closure.dart';
-import 'package:analysis_server/src/services/correction/dart/replace_with_conditional_assignment.dart';
-import 'package:analysis_server/src/services/correction/dart/replace_with_is_empty.dart';
-import 'package:analysis_server/src/services/correction/dart/replace_with_tear_off.dart';
-import 'package:analysis_server/src/services/correction/dart/replace_with_var.dart';
-import 'package:analysis_server/src/services/correction/dart/sort_child_property_last.dart';
-import 'package:analysis_server/src/services/correction/dart/use_curly_braces.dart';
-import 'package:analysis_server/src/services/correction/dart/use_is_not_empty.dart';
-import 'package:analysis_server/src/services/correction/dart/use_rethrow.dart';
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/transform_override_set.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/transform_override_set_parser.dart';
 import 'package:analysis_server/src/services/correction/fix_internal.dart';
-import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analyzer/dart/analysis/analysis_context.dart';
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/error/error.dart';
@@ -97,202 +40,6 @@
 /// The correction producers that are associated with the diagnostics should not
 /// produce changes that alter the semantics of the code.
 class BulkFixProcessor {
-  /// A map from the name of a lint rule to a list of generators used to create
-  /// the correction producer used to build a fix for that diagnostic. The
-  /// generators used for non-lint diagnostics are in the [nonLintProducerMap].
-  ///
-  /// Most entries will have only one generator. In cases where there is more
-  /// than one, they will be applied in series and the expectation is that only
-  /// one will produce a change for a given fix. If more than one change is
-  /// produced the result will almost certainly be invalid code.
-  static const Map<String, List<ProducerGenerator>> lintProducerMap = {
-    LintNames.always_require_non_null_named_parameters: [
-      AddRequired.newInstance,
-    ],
-    LintNames.annotate_overrides: [
-      AddOverride.newInstance,
-    ],
-    LintNames.avoid_annotating_with_dynamic: [
-      RemoveTypeAnnotation.newInstance,
-    ],
-    LintNames.avoid_empty_else: [
-      RemoveEmptyElse.newInstance,
-    ],
-    LintNames.avoid_init_to_null: [
-      RemoveInitializer.newInstance,
-    ],
-    LintNames.avoid_private_typedef_functions: [
-      InlineTypedef.newInstance,
-    ],
-    LintNames.avoid_redundant_argument_values: [
-      RemoveArgument.newInstance,
-    ],
-    LintNames.avoid_relative_lib_imports: [
-      ConvertToPackageImport.newInstance,
-    ],
-    LintNames.avoid_return_types_on_setters: [
-      RemoveTypeAnnotation.newInstance,
-    ],
-    LintNames.avoid_single_cascade_in_expression_statements: [
-      ReplaceCascadeWithDot.newInstance,
-    ],
-    LintNames.avoid_types_on_closure_parameters: [
-      RemoveTypeAnnotation.newInstance,
-    ],
-    LintNames.await_only_futures: [
-      RemoveAwait.newInstance,
-    ],
-    LintNames.curly_braces_in_flow_control_structures: [
-      UseCurlyBraces.newInstance,
-    ],
-    LintNames.diagnostic_describe_all_properties: [
-      AddDiagnosticPropertyReference.newInstance,
-    ],
-    LintNames.empty_catches: [
-      RemoveEmptyCatch.newInstance,
-    ],
-    LintNames.empty_constructor_bodies: [
-      RemoveEmptyConstructorBody.newInstance,
-    ],
-    LintNames.empty_statements: [
-      RemoveEmptyStatement.newInstance,
-    ],
-    LintNames.hash_and_equals: [
-      CreateMethod.equalsOrHashCode,
-    ],
-    LintNames.no_duplicate_case_values: [
-      RemoveDuplicateCase.newInstance,
-    ],
-    LintNames.non_constant_identifier_names: [
-      RenameToCamelCase.newInstance,
-    ],
-    LintNames.null_closures: [
-      ReplaceNullWithClosure.newInstance,
-    ],
-    LintNames.omit_local_variable_types: [
-      ReplaceWithVar.newInstance,
-    ],
-    LintNames.prefer_adjacent_string_concatenation: [
-      RemoveOperator.newInstance,
-    ],
-    LintNames.prefer_collection_literals: [
-      ConvertToListLiteral.newInstance,
-      ConvertToMapLiteral.newInstance,
-      ConvertToSetLiteral.newInstance,
-    ],
-    LintNames.prefer_conditional_assignment: [
-      ReplaceWithConditionalAssignment.newInstance,
-    ],
-    // TODO (pq): can produce results incompatible w/ `unnecessary_const`
-    // LintNames.prefer_const_constructors: [
-    //   AddConst.newInstance,
-    //   ReplaceNewWithConst.newInstance,
-    // ],
-    LintNames.prefer_const_constructors_in_immutables: [
-      AddConst.newInstance,
-    ],
-    LintNames.prefer_const_declarations: [
-      ReplaceFinalWithConst.newInstance,
-    ],
-    LintNames.prefer_contains: [
-      ConvertToContains.newInstance,
-    ],
-    LintNames.prefer_equal_for_default_values: [
-      ReplaceColonWithEquals.newInstance,
-    ],
-    LintNames.prefer_final_fields: [
-      MakeFinal.newInstance,
-    ],
-    LintNames.prefer_final_locals: [
-      MakeFinal.newInstance,
-    ],
-    LintNames.prefer_for_elements_to_map_fromIterable: [
-      ConvertMapFromIterableToForLiteral.newInstance,
-    ],
-    LintNames.prefer_generic_function_type_aliases: [
-      ConvertToGenericFunctionSyntax.newInstance,
-    ],
-    LintNames.prefer_if_elements_to_conditional_expressions: [
-      ConvertConditionalExpressionToIfElement.newInstance,
-    ],
-    LintNames.prefer_if_null_operators: [
-      ConvertToIfNull.newInstance,
-    ],
-    LintNames.prefer_inlined_adds: [
-      ConvertAddAllToSpread.newInstance,
-      InlineInvocation.newInstance,
-    ],
-    LintNames.prefer_int_literals: [
-      ConvertToIntLiteral.newInstance,
-    ],
-    LintNames.prefer_is_empty: [
-      ReplaceWithIsEmpty.newInstance,
-    ],
-    LintNames.prefer_is_not_empty: [
-      UseIsNotEmpty.newInstance,
-    ],
-    LintNames.prefer_is_not_operator: [
-      ConvertIntoIsNot.newInstance,
-    ],
-    LintNames.prefer_iterable_whereType: [
-      ConvertToWhereType.newInstance,
-    ],
-    LintNames.prefer_null_aware_operators: [
-      ConvertToNullAware.newInstance,
-    ],
-    LintNames.prefer_relative_imports: [
-      ConvertToRelativeImport.newInstance,
-    ],
-    LintNames.prefer_single_quotes: [
-      ConvertToSingleQuotes.newInstance,
-    ],
-    LintNames.prefer_spread_collections: [
-      ConvertAddAllToSpread.newInstance,
-    ],
-    LintNames.slash_for_doc_comments: [
-      ConvertDocumentationIntoLine.newInstance,
-    ],
-    LintNames.sort_child_properties_last: [
-      SortChildPropertyLast.newInstance,
-    ],
-    LintNames.type_init_formals: [
-      RemoveTypeAnnotation.newInstance,
-    ],
-    LintNames.unawaited_futures: [
-      AddAwait.newInstance,
-    ],
-    LintNames.unnecessary_brace_in_string_interps: [
-      RemoveInterpolationBraces.newInstance,
-    ],
-    LintNames.unnecessary_const: [
-      RemoveUnnecessaryConst.newInstance,
-    ],
-    LintNames.unnecessary_lambdas: [
-      ReplaceWithTearOff.newInstance,
-    ],
-    LintNames.unnecessary_new: [
-      RemoveUnnecessaryNew.newInstance,
-    ],
-    LintNames.unnecessary_null_in_if_null_operators: [
-      RemoveIfNullOperator.newInstance,
-    ],
-    LintNames.unnecessary_overrides: [
-      RemoveMethodDeclaration.newInstance,
-    ],
-    LintNames.unnecessary_string_interpolations: [
-      RemoveUnnecessaryStringInterpolation.newInstance,
-    ],
-    LintNames.unnecessary_this: [
-      RemoveThisExpression.newInstance,
-    ],
-    LintNames.use_function_type_syntax_for_parameters: [
-      ConvertToGenericFunctionSyntax.newInstance,
-    ],
-    LintNames.use_rethrow_when_possible: [
-      UseRethrow.newInstance,
-    ],
-  };
-
   /// A map from an error code to a list of generators used to create multiple
   /// correction producers used to build fixes for those diagnostics. The
   /// generators used for lint rules are in the [lintMultiProducerMap].
@@ -489,9 +236,14 @@
   ) sync* {
     final errorCode = diagnostic.errorCode;
     if (errorCode is LintCode) {
-      final generators = lintProducerMap[errorCode.name];
-      if (generators != null) {
-        yield* generators.map((g) => g().fixKind).where((k) => k != null);
+      var fixes = FixProcessor.lintProducerMap2[errorCode.name];
+      for (var fix in fixes) {
+        if (fix.canBeBulkApplied) {
+          final generators = fix.generators;
+          if (generators != null) {
+            yield* generators.map((g) => g().fixKind).where((k) => k != null);
+          }
+        }
       }
       return;
     }
@@ -613,10 +365,15 @@
     try {
       var codeName = errorCode.name;
       if (errorCode is LintCode) {
-        var generators = lintProducerMap[codeName];
-        if (generators != null) {
-          for (var generator in generators) {
-            await generate(generator(), codeName);
+        var fixes = FixProcessor.lintProducerMap2[errorCode.name];
+        for (var fix in fixes) {
+          if (fix.canBeBulkApplied) {
+            final generators = fix.generators;
+            if (generators != null) {
+              for (var generator in generators) {
+                await generate(generator(), codeName);
+              }
+            }
           }
         }
       } else {
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 3cacd94..0c2b4ba 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -38,6 +38,7 @@
 import 'package:analysis_server/src/services/correction/dart/convert_documentation_into_line.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_flutter_child.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_flutter_children.dart';
+import 'package:analysis_server/src/services/correction/dart/convert_into_is_not.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_map_from_iterable_to_for_literal.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_quotes.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_to_contains.dart';
@@ -166,6 +167,7 @@
 import 'package:analyzer_plugin/utilities/change_builder/change_workspace.dart';
 import 'package:analyzer_plugin/utilities/change_builder/conflicting_edit_exception.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart' hide FixContributor;
+import 'package:meta/meta.dart';
 
 /// A function that can be executed to create a multi-correction producer.
 typedef MultiProducerGenerator = MultiCorrectionProducer Function();
@@ -302,7 +304,7 @@
 
     var fixes = <Fix>[];
     for (var generator in generators) {
-      var fixInfo = FixInfo(workspace);
+      var fixState = FixState(workspace);
       for (var error in errors) {
         var fixContext = DartFixContextImpl(
           instrumentationService,
@@ -311,12 +313,12 @@
           error,
           (name) => [],
         );
-        await _fixError(fixContext, fixInfo, generator(), error);
+        await _fixError(fixContext, fixState, generator(), error);
       }
-      var sourceChange = fixInfo.builder.sourceChange;
+      var sourceChange = fixState.builder.sourceChange;
       if (sourceChange.edits.isNotEmpty) {
-        var fixKind = fixInfo.fixKind;
-        if (fixKind.canBeAppliedTogether() && fixInfo.fixCount > 1) {
+        var fixKind = fixState.fixKind;
+        if (fixKind.canBeAppliedTogether() && fixState.fixCount > 1) {
           sourceChange.message = fixKind.appliedTogetherMessage;
           fixes.add(Fix(fixKind, sourceChange));
         }
@@ -325,7 +327,7 @@
     return fixes;
   }
 
-  Future<void> _fixError(DartFixContext fixContext, FixInfo fixInfo,
+  Future<void> _fixError(DartFixContext fixContext, FixState fixState,
       CorrectionProducer producer, AnalysisError diagnostic) async {
     var context = CorrectionProducerContext(
       applyingBulkFixes: true,
@@ -345,13 +347,13 @@
     producer.configure(context);
 
     try {
-      var localBuilder = fixInfo.builder.copy();
+      var localBuilder = fixState.builder.copy();
       await producer.compute(localBuilder);
-      fixInfo.builder = localBuilder;
+      fixState.builder = localBuilder;
       // todo (pq): consider discarding the change if the producer's fixKind
       // doesn't match a previously cached one.
-      fixInfo.fixKind = producer.fixKind;
-      fixInfo.fixCount++;
+      fixState.fixKind = producer.fixKind;
+      fixState.fixCount++;
     } on ConflictingEditException {
       // If a conflicting edit was added in [compute], then the [localBuilder]
       // is discarded and we revert to the previous state of the builder.
@@ -379,17 +381,690 @@
   }
 }
 
-/// Info used while producing fix all in file fixes.
 class FixInfo {
-  ChangeBuilder builder;
-  FixKind fixKind;
-  int fixCount = 0;
-  FixInfo(ChangeWorkspace workspace)
-      : builder = ChangeBuilder(workspace: workspace);
+  final bool canBeAppliedToFile;
+  final bool canBeBulkApplied;
+  final List<ProducerGenerator> generators;
+  const FixInfo({
+    @required this.canBeAppliedToFile,
+    @required this.canBeBulkApplied,
+    @required this.generators,
+  });
 }
 
 /// The computer for Dart fixes.
 class FixProcessor extends BaseProcessor {
+  /// todo (pq): to replace lintProducerMap.
+  static const Map<String, List<FixInfo>> lintProducerMap2 = {
+    LintNames.always_declare_return_types: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        // not currently supported; TODO(pq): consider adding
+        canBeBulkApplied: false,
+        generators: [
+          AddReturnType.newInstance,
+        ],
+      )
+    ],
+    LintNames.always_require_non_null_named_parameters: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          AddRequired.newInstance,
+        ],
+      )
+    ],
+    LintNames.always_specify_types: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        // not currently supported; TODO(pq): consider adding
+        canBeBulkApplied: false,
+        generators: [
+          AddTypeAnnotation.newInstance,
+        ],
+      )
+    ],
+    LintNames.annotate_overrides: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          AddOverride.newInstance,
+        ],
+      )
+    ],
+    LintNames.avoid_annotating_with_dynamic: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          RemoveTypeAnnotation.newInstance,
+        ],
+      )
+    ],
+    LintNames.avoid_empty_else: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          RemoveEmptyElse.newInstance,
+        ],
+      )
+    ],
+    LintNames.avoid_init_to_null: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          RemoveInitializer.newInstance,
+        ],
+      )
+    ],
+    LintNames.avoid_private_typedef_functions: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          InlineTypedef.newInstance,
+        ],
+      )
+    ],
+    LintNames.avoid_redundant_argument_values: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          RemoveArgument.newInstance,
+        ],
+      )
+    ],
+    LintNames.avoid_relative_lib_imports: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ConvertToPackageImport.newInstance,
+        ],
+      )
+    ],
+    LintNames.avoid_return_types_on_setters: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          RemoveTypeAnnotation.newInstance,
+        ],
+      )
+    ],
+    LintNames.avoid_returning_null_for_future: [
+      FixInfo(
+        canBeAppliedToFile: false,
+        // not currently supported; TODO(pq): consider adding
+        canBeBulkApplied: false,
+        generators: [
+          AddAsync.newInstance,
+          WrapInFuture.newInstance,
+        ],
+      )
+    ],
+    LintNames.avoid_single_cascade_in_expression_statements: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          // TODO(brianwilkerson) This fix should be applied to some non-lint
+          //  diagnostics and should also be available as an assist.
+          ReplaceCascadeWithDot.newInstance,
+        ],
+      )
+    ],
+    LintNames.avoid_types_as_parameter_names: [
+      FixInfo(
+        canBeAppliedToFile: false,
+        canBeBulkApplied: false,
+        generators: [
+          ConvertToOnType.newInstance,
+        ],
+      )
+    ],
+    LintNames.avoid_types_on_closure_parameters: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ReplaceWithIdentifier.newInstance,
+          RemoveTypeAnnotation.newInstance,
+        ],
+      )
+    ],
+    LintNames.avoid_unused_constructor_parameters: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: false,
+        generators: [
+          RemoveUnusedParameter.newInstance,
+        ],
+      )
+    ],
+    LintNames.await_only_futures: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          RemoveAwait.newInstance,
+        ],
+      )
+    ],
+    LintNames.curly_braces_in_flow_control_structures: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          UseCurlyBraces.newInstance,
+        ],
+      )
+    ],
+    LintNames.diagnostic_describe_all_properties: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          AddDiagnosticPropertyReference.newInstance,
+        ],
+      )
+    ],
+    LintNames.directives_ordering: [
+      FixInfo(
+        canBeAppliedToFile: false, // Fix will sort all directives.
+        canBeBulkApplied: false,
+        generators: [
+          OrganizeImports.newInstance,
+        ],
+      )
+    ],
+    LintNames.empty_catches: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          RemoveEmptyCatch.newInstance,
+        ],
+      )
+    ],
+    LintNames.empty_constructor_bodies: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          RemoveEmptyConstructorBody.newInstance,
+        ],
+      )
+    ],
+    LintNames.empty_statements: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          RemoveEmptyStatement.newInstance,
+          ReplaceWithBrackets.newInstance,
+        ],
+      )
+    ],
+    LintNames.hash_and_equals: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          CreateMethod.equalsOrHashCode,
+        ],
+      )
+    ],
+    LintNames.no_duplicate_case_values: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          RemoveDuplicateCase.newInstance,
+        ],
+      )
+    ],
+    LintNames.non_constant_identifier_names: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          RenameToCamelCase.newInstance,
+        ],
+      )
+    ],
+    LintNames.null_closures: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ReplaceNullWithClosure.newInstance,
+        ],
+      )
+    ],
+    LintNames.omit_local_variable_types: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ReplaceWithVar.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_adjacent_string_concatenation: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          RemoveOperator.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_collection_literals: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ConvertToListLiteral.newInstance,
+          ConvertToMapLiteral.newInstance,
+          ConvertToSetLiteral.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_conditional_assignment: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ReplaceWithConditionalAssignment.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_const_constructors: [
+      FixInfo(
+        canBeAppliedToFile: false,
+        // Can produce results incompatible w/ `unnecessary_const`
+        canBeBulkApplied: false,
+        generators: [
+          AddConst.newInstance,
+          ReplaceNewWithConst.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_const_constructors_in_immutables: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          AddConst.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_const_declarations: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ReplaceFinalWithConst.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_contains: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ConvertToContains.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_equal_for_default_values: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ReplaceColonWithEquals.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_expression_function_bodies: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        // not currently supported; TODO(pq): consider adding
+        canBeBulkApplied: false,
+        generators: [
+          ConvertToExpressionFunctionBody.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_final_fields: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          MakeFinal.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_final_in_for_each: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          MakeFinal.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_final_locals: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          MakeFinal.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_for_elements_to_map_fromIterable: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ConvertMapFromIterableToForLiteral.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_generic_function_type_aliases: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ConvertToGenericFunctionSyntax.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_if_elements_to_conditional_expressions: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ConvertConditionalExpressionToIfElement.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_is_empty: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ReplaceWithIsEmpty.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_is_not_empty: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          UseIsNotEmpty.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_if_null_operators: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ConvertToIfNull.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_inlined_adds: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ConvertAddAllToSpread.newInstance,
+          InlineInvocation.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_int_literals: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ConvertToIntLiteral.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_interpolation_to_compose_strings: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        // not currently supported; TODO(pq): consider adding
+        canBeBulkApplied: false,
+        generators: [
+          ReplaceWithInterpolation.newInstance,
+        ],
+      )
+    ],
+    // todo (pq): note this is not in lintProducerMap
+    LintNames.prefer_is_not_operator: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ConvertIntoIsNot.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_iterable_whereType: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ConvertToWhereType.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_null_aware_operators: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ConvertToNullAware.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_relative_imports: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ConvertToRelativeImport.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_single_quotes: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ConvertToSingleQuotes.newInstance,
+        ],
+      )
+    ],
+    LintNames.prefer_spread_collections: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ConvertAddAllToSpread.newInstance,
+        ],
+      )
+    ],
+    LintNames.slash_for_doc_comments: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ConvertDocumentationIntoLine.newInstance,
+        ],
+      )
+    ],
+    LintNames.sort_child_properties_last: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          SortChildPropertyLast.newInstance,
+        ],
+      )
+    ],
+    LintNames.type_annotate_public_apis: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        // not currently supported; TODO(pq): consider adding
+        canBeBulkApplied: false,
+        generators: [
+          AddTypeAnnotation.newInstance,
+        ],
+      )
+    ],
+    LintNames.type_init_formals: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          RemoveTypeAnnotation.newInstance,
+        ],
+      )
+    ],
+    LintNames.unawaited_futures: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          AddAwait.newInstance,
+        ],
+      )
+    ],
+    LintNames.unnecessary_brace_in_string_interps: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          RemoveInterpolationBraces.newInstance,
+        ],
+      )
+    ],
+    LintNames.unnecessary_const: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          RemoveUnnecessaryConst.newInstance,
+        ],
+      )
+    ],
+    LintNames.unnecessary_lambdas: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ReplaceWithTearOff.newInstance,
+        ],
+      )
+    ],
+    LintNames.unnecessary_new: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          RemoveUnnecessaryNew.newInstance,
+        ],
+      )
+    ],
+    LintNames.unnecessary_null_in_if_null_operators: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          RemoveIfNullOperator.newInstance,
+        ],
+      )
+    ],
+    LintNames.unnecessary_overrides: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          RemoveMethodDeclaration.newInstance,
+        ],
+      )
+    ],
+    LintNames.unnecessary_parenthesis: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        // not currently supported; TODO(pq): consider adding
+        canBeBulkApplied: false,
+        generators: [
+          RemoveUnnecessaryParentheses.newInstance,
+        ],
+      )
+    ],
+    LintNames.unnecessary_string_interpolations: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          RemoveUnnecessaryStringInterpolation.newInstance,
+        ],
+      )
+    ],
+    LintNames.unnecessary_this: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          RemoveThisExpression.newInstance,
+        ],
+      )
+    ],
+    LintNames.use_full_hex_values_for_flutter_colors: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        // not currently supported; TODO(pq): consider adding
+        canBeBulkApplied: false,
+        generators: [
+          ReplaceWithEightDigitHex.newInstance,
+        ],
+      )
+    ],
+    LintNames.use_function_type_syntax_for_parameters: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          ConvertToGenericFunctionSyntax.newInstance,
+        ],
+      )
+    ],
+    LintNames.use_rethrow_when_possible: [
+      FixInfo(
+        canBeAppliedToFile: true,
+        canBeBulkApplied: true,
+        generators: [
+          UseRethrow.newInstance,
+        ],
+      )
+    ],
+  };
+
   /// A map from the names of lint rules to a list of generators used to create
   /// the correction producers used to build fixes for those diagnostics. The
   /// generators used for non-lint diagnostics are in the [nonLintProducerMap].
@@ -1339,3 +2014,12 @@
     }
   }
 }
+
+/// State associated with producing fix-all-in-file fixes.
+class FixState {
+  ChangeBuilder builder;
+  FixKind fixKind;
+  int fixCount = 0;
+  FixState(ChangeWorkspace workspace)
+      : builder = ChangeBuilder(workspace: workspace);
+}
diff --git a/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart b/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
index bf327be..0996e9d 100644
--- a/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
@@ -96,6 +96,29 @@
     expect(contents[mainFilePath], equals(expectedContent));
   }
 
+  Future<void> test_filtersCorrectly() async {
+    const content = '''
+    import 'dart:async';
+    [[import]] 'dart:convert';
+
+    Future foo;
+    ''';
+    newFile(mainFilePath, content: withoutMarkers(content));
+    await initialize();
+
+    final ofKind = (CodeActionKind kind) => getCodeActions(
+          mainFileUri.toString(),
+          range: rangeFromMarkers(content),
+          kinds: [kind],
+        );
+
+    // The code above will return a quickfix.remove.unusedImport
+    expect(await ofKind(CodeActionKind.QuickFix), isNotEmpty);
+    expect(await ofKind(CodeActionKind('quickfix.remove')), isNotEmpty);
+    expect(await ofKind(CodeActionKind('quickfix.other')), isEmpty);
+    expect(await ofKind(CodeActionKind.Refactor), isEmpty);
+  }
+
   Future<void> test_noDuplicates_sameFix() async {
     const content = '''
     var a = [Test, Test, Te[[]]st];
diff --git a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
index bd236eb..e6d10cc 100644
--- a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
@@ -159,6 +159,31 @@
         req1, throwsA(isResponseError(ErrorCodes.ContentModified)));
   }
 
+  Future<void> test_filtersCorrectly() async {
+    const content = '''
+main() {
+  print('Test!');
+  [[print('Test!');]]
+}
+    ''';
+    newFile(mainFilePath, content: withoutMarkers(content));
+    await initialize();
+
+    final ofKind = (CodeActionKind kind) => getCodeActions(
+          mainFileUri.toString(),
+          range: rangeFromMarkers(content),
+          kinds: [kind],
+        );
+
+    // The code above will return a RefactorExtract that should be included
+    // by both Refactor and RefactorExtract, but not RefactorExtractFoo or
+    // RefactorRewrite
+    expect(await ofKind(CodeActionKind.Refactor), isNotEmpty);
+    expect(await ofKind(CodeActionKind.RefactorExtract), isNotEmpty);
+    expect(await ofKind(CodeActionKind('refactor.extract.foo')), isEmpty);
+    expect(await ofKind(CodeActionKind.RefactorRewrite), isEmpty);
+  }
+
   Future<void> test_generatesNames() async {
     const content = '''
 Object main() {
diff --git a/pkg/analysis_server/test/lsp/code_actions_source_test.dart b/pkg/analysis_server/test/lsp/code_actions_source_test.dart
index 12838ed..9a75e7e 100644
--- a/pkg/analysis_server/test/lsp/code_actions_source_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_source_test.dart
@@ -128,6 +128,24 @@
     expect(commandResponse, isNull);
   }
 
+  Future<void> test_filtersCorrectly() async {
+    newFile(mainFilePath, content: '');
+    await initialize(
+        workspaceCapabilities:
+            withApplyEditSupport(emptyWorkspaceClientCapabilities));
+
+    final ofKind = (CodeActionKind kind) => getCodeActions(
+          mainFileUri.toString(),
+          kinds: [kind],
+        );
+
+    expect(await ofKind(CodeActionKind.Source), hasLength(2));
+    expect(await ofKind(CodeActionKind.SourceOrganizeImports), hasLength(1));
+    expect(await ofKind(DartCodeActionKind.SortMembers), hasLength(1));
+    expect(await ofKind(CodeActionKind('source.foo')), isEmpty);
+    expect(await ofKind(CodeActionKind.Refactor), isEmpty);
+  }
+
   Future<void> test_noEdits() async {
     const content = '''
 import 'dart:async';
diff --git a/pkg/analysis_server/test/lsp/initialization_test.dart b/pkg/analysis_server/test/lsp/initialization_test.dart
index ce2263f..f864ea6 100644
--- a/pkg/analysis_server/test/lsp/initialization_test.dart
+++ b/pkg/analysis_server/test/lsp/initialization_test.dart
@@ -459,6 +459,36 @@
     expect(server.contextManager.includedPaths, equals([projectFolderPath]));
   }
 
+  Future<void> test_nonFileScheme_rootUri() async {
+    final rootUri = Uri.parse('vsls://');
+    final fileUri = rootUri.replace(path: '/file1.dart');
+
+    await initialize(rootUri: rootUri);
+    expect(server.contextManager.includedPaths, equals([]));
+
+    // Also open a non-file file to ensure it doesn't cause the root to be added.
+    await openFile(fileUri, '');
+    expect(server.contextManager.includedPaths, equals([]));
+  }
+
+  Future<void> test_nonFileScheme_workspaceFolders() async {
+    final pubspecPath = join(projectFolderPath, 'pubspec.yaml');
+    newFile(pubspecPath);
+
+    final rootUri = Uri.parse('vsls://');
+    final fileUri = rootUri.replace(path: '/file1.dart');
+
+    await initialize(workspaceFolders: [
+      rootUri,
+      Uri.file(projectFolderPath),
+    ]);
+    expect(server.contextManager.includedPaths, equals([projectFolderPath]));
+
+    // Also open a non-file file to ensure it doesn't cause the root to be added.
+    await openFile(fileUri, '');
+    expect(server.contextManager.includedPaths, equals([projectFolderPath]));
+  }
+
   Future<void> test_onlyAnalyzeProjectsWithOpenFiles_multipleFiles() async {
     final file1 = join(projectFolderPath, 'file1.dart');
     final file1Uri = Uri.file(file1);
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index fead448..dc653fe 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -1470,7 +1470,7 @@
   WorkspaceFolder toWorkspaceFolder(Uri uri) {
     return WorkspaceFolder(
       uri: uri.toString(),
-      name: path.basename(uri.toFilePath()),
+      name: path.basename(uri.path),
     );
   }
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/data_driven_test.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/data_driven_test.dart
index 2a480a0..a92e878 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/bulk/data_driven_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/data_driven_test.dart
@@ -5,6 +5,7 @@
 import 'package:analysis_server/src/services/correction/bulk_fix_processor.dart';
 import 'package:analysis_server/src/services/correction/dart/data_driven.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_manager.dart';
+import 'package:analysis_server/src/services/correction/fix_internal.dart';
 import 'package:analyzer/src/test_utilities/package_config_file_builder.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -505,8 +506,11 @@
     // action accidentally executing data-driven fixes.
 
     final dataDrivenCodes = <String>{};
+    final bulkFixCodes = FixProcessor.lintProducerMap2.entries
+        .where((e) => e.value.where((fix) => fix.canBeBulkApplied).isNotEmpty)
+        .map((e) => e.key);
     final nonDataDrivenCodes = <String>{
-      ...BulkFixProcessor.lintProducerMap.keys,
+      ...bulkFixCodes,
       ...BulkFixProcessor.nonLintProducerMap.keys.map((c) => c.uniqueName),
     };
 
diff --git a/pkg/analysis_server/tool/bulk_fix/supported_lints.dart b/pkg/analysis_server/tool/bulk_fix/supported_lints.dart
index 7d6fbb3..135c10c 100644
--- a/pkg/analysis_server/tool/bulk_fix/supported_lints.dart
+++ b/pkg/analysis_server/tool/bulk_fix/supported_lints.dart
@@ -2,13 +2,16 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:analysis_server/src/services/correction/bulk_fix_processor.dart';
+import 'package:analysis_server/src/services/correction/fix_internal.dart';
 
 /// Print lints that are bulk-fixable in a format that can be included in
 /// analysis options.
 void main() {
+  final bulkFixCodes = FixProcessor.lintProducerMap2.entries
+      .where((e) => e.value.where((fix) => fix.canBeBulkApplied).isNotEmpty)
+      .map((e) => e.key);
   print('    # bulk-fixable lints');
-  for (var lintName in BulkFixProcessor.lintProducerMap.keys) {
+  for (var lintName in bulkFixCodes) {
     print('    - $lintName');
   }
 }
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index 4219495..77ee797 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -1491,12 +1491,11 @@
 ///
 /// Clients may not extend, implement or mix-in this class.
 abstract class ConstructorDeclaration implements ClassMember {
-  /// Return the body of the constructor, or `null` if the constructor does not
-  /// have a body.
-  FunctionBody? get body;
+  /// Return the body of the constructor.
+  FunctionBody get body;
 
   /// Set the body of the constructor to the given [functionBody].
-  set body(FunctionBody? functionBody);
+  set body(FunctionBody functionBody);
 
   /// Return the token for the 'const' keyword, or `null` if the constructor is
   /// not a const constructor.
@@ -2747,12 +2746,11 @@
 ///
 /// Clients may not extend, implement or mix-in this class.
 abstract class FunctionExpression implements Expression {
-  /// Return the body of the function, or `null` if this is an external
-  /// function.
-  FunctionBody? get body;
+  /// Return the body of the function.
+  FunctionBody get body;
 
   /// Set the body of the function to the given [functionBody].
-  set body(FunctionBody? functionBody);
+  set body(FunctionBody functionBody);
 
   /// Return the element associated with the function, or `null` if the AST
   /// structure has not been resolved.
diff --git a/pkg/analyzer/lib/dart/ast/ast_factory.dart b/pkg/analyzer/lib/dart/ast/ast_factory.dart
index 7aabf24..8ba70d1 100644
--- a/pkg/analyzer/lib/dart/ast/ast_factory.dart
+++ b/pkg/analyzer/lib/dart/ast/ast_factory.dart
@@ -201,8 +201,7 @@
   /// initializers and does not redirect to a different constructor. The list of
   /// [initializers] can be `null` if the constructor does not have any
   /// initializers. The [redirectedConstructor] can be `null` if the constructor
-  /// does not redirect to a different constructor. The [body] can be `null` if
-  /// the constructor does not have a body.
+  /// does not redirect to a different constructor.
   ConstructorDeclaration constructorDeclaration(
       Comment? comment,
       List<Annotation>? metadata,
@@ -216,7 +215,7 @@
       Token? separator,
       List<ConstructorInitializer>? initializers,
       ConstructorName? redirectedConstructor,
-      FunctionBody? body);
+      FunctionBody body);
 
   /// Returns a newly created field initializer to initialize the field with
   /// the given name to the value of the given expression. The [thisKeyword] and
@@ -465,7 +464,7 @@
 
   /// Returns a newly created function declaration.
   FunctionExpression functionExpression(TypeParameterList? typeParameters,
-      FormalParameterList? parameters, FunctionBody? body);
+      FormalParameterList? parameters, FunctionBody body);
 
   /// Returns a newly created function expression invocation.
   FunctionExpressionInvocation functionExpressionInvocation(Expression function,
diff --git a/pkg/analyzer/lib/exception/exception.dart b/pkg/analyzer/lib/exception/exception.dart
index d23c830..9ac1bca 100644
--- a/pkg/analyzer/lib/exception/exception.dart
+++ b/pkg/analyzer/lib/exception/exception.dart
@@ -20,10 +20,13 @@
     StringBuffer buffer = StringBuffer();
     buffer.write('$runtimeType: ');
     buffer.writeln(message);
+
+    var cause = this.cause;
     if (cause != null) {
       buffer.write('Caused by ');
-      cause!._writeOn(buffer);
+      cause._writeOn(buffer);
     }
+
     return buffer.toString();
   }
 }
diff --git a/pkg/analyzer/lib/instrumentation/log_adapter.dart b/pkg/analyzer/lib/instrumentation/log_adapter.dart
index c3f3ad6..cd1393c 100644
--- a/pkg/analyzer/lib/instrumentation/log_adapter.dart
+++ b/pkg/analyzer/lib/instrumentation/log_adapter.dart
@@ -25,7 +25,7 @@
   static const String TAG_WATCH_EVENT = 'Watch';
 
   /// A logger used to log instrumentation in string format.
-  final InstrumentationLogger? _instrumentationLogger;
+  final InstrumentationLogger _instrumentationLogger;
 
   /// Initialize a newly created instrumentation service to communicate with the
   /// given [_instrumentationLogger].
@@ -43,11 +43,9 @@
     StackTrace? stackTrace,
     List<InstrumentationServiceAttachment>? attachments,
   ]) {
-    if (_instrumentationLogger != null) {
-      String message = _toString(exception);
-      String trace = _toString(stackTrace);
-      _instrumentationLogger!.log(_join([TAG_EXCEPTION, message, trace]));
-    }
+    String message = _toString(exception);
+    String trace = _toString(stackTrace);
+    _instrumentationLogger.log(_join([TAG_EXCEPTION, message, trace]));
   }
 
   @override
@@ -57,20 +55,18 @@
   @override
   void logLogEntry(String level, DateTime? time, String message,
       Object exception, StackTrace stackTrace) {
-    if (_instrumentationLogger != null) {
-      String timeStamp =
-          time == null ? 'null' : time.millisecondsSinceEpoch.toString();
-      String exceptionText = exception.toString();
-      String stackTraceText = stackTrace.toString();
-      _instrumentationLogger!.log(_join([
-        TAG_LOG_ENTRY,
-        level,
-        timeStamp,
-        message,
-        exceptionText,
-        stackTraceText
-      ]));
-    }
+    String timeStamp =
+        time == null ? 'null' : time.millisecondsSinceEpoch.toString();
+    String exceptionText = exception.toString();
+    String stackTraceText = stackTrace.toString();
+    _instrumentationLogger.log(_join([
+      TAG_LOG_ENTRY,
+      level,
+      timeStamp,
+      message,
+      exceptionText,
+      stackTraceText
+    ]));
   }
 
   @override
@@ -80,63 +76,46 @@
   @override
   void logPluginError(
       PluginData plugin, String code, String message, String stackTrace) {
-    if (_instrumentationLogger != null) {
-      List<String> fields = <String>[
-        TAG_PLUGIN_ERROR,
-        code,
-        message,
-        stackTrace
-      ];
-      plugin.addToFields(fields);
-      _instrumentationLogger!.log(_join(fields));
-    }
+    List<String> fields = <String>[TAG_PLUGIN_ERROR, code, message, stackTrace];
+    plugin.addToFields(fields);
+    _instrumentationLogger.log(_join(fields));
   }
 
   @override
   void logPluginException(
       PluginData plugin, dynamic exception, StackTrace? stackTrace) {
-    if (_instrumentationLogger != null) {
-      List<String> fields = <String>[
-        TAG_PLUGIN_EXCEPTION,
-        _toString(exception),
-        _toString(stackTrace)
-      ];
-      plugin.addToFields(fields);
-      _instrumentationLogger!.log(_join(fields));
-    }
+    List<String> fields = <String>[
+      TAG_PLUGIN_EXCEPTION,
+      _toString(exception),
+      _toString(stackTrace)
+    ];
+    plugin.addToFields(fields);
+    _instrumentationLogger.log(_join(fields));
   }
 
   @override
   void logPluginNotification(String pluginId, String notification) {
-    if (_instrumentationLogger != null) {
-      _instrumentationLogger!.log(
-          _join([TAG_PLUGIN_NOTIFICATION, notification, pluginId, '', '']));
-    }
+    _instrumentationLogger
+        .log(_join([TAG_PLUGIN_NOTIFICATION, notification, pluginId, '', '']));
   }
 
   @override
   void logPluginRequest(String pluginId, String request) {
-    if (_instrumentationLogger != null) {
-      _instrumentationLogger!
-          .log(_join([TAG_PLUGIN_REQUEST, request, pluginId, '', '']));
-    }
+    _instrumentationLogger
+        .log(_join([TAG_PLUGIN_REQUEST, request, pluginId, '', '']));
   }
 
   @override
   void logPluginResponse(String pluginId, String response) {
-    if (_instrumentationLogger != null) {
-      _instrumentationLogger!
-          .log(_join([TAG_PLUGIN_RESPONSE, response, pluginId, '', '']));
-    }
+    _instrumentationLogger
+        .log(_join([TAG_PLUGIN_RESPONSE, response, pluginId, '', '']));
   }
 
   @override
   void logPluginTimeout(PluginData plugin, String request) {
-    if (_instrumentationLogger != null) {
-      List<String> fields = <String>[TAG_PLUGIN_TIMEOUT, request];
-      plugin.addToFields(fields);
-      _instrumentationLogger!.log(_join(fields));
-    }
+    List<String> fields = <String>[TAG_PLUGIN_TIMEOUT, request];
+    plugin.addToFields(fields);
+    _instrumentationLogger.log(_join(fields));
   }
 
   @override
@@ -151,29 +130,25 @@
     String normalize(String? value) =>
         value != null && value.isNotEmpty ? value : 'unknown';
 
-    if (_instrumentationLogger != null) {
-      _instrumentationLogger!.log(_join([
-        TAG_VERSION,
-        uuid,
-        normalize(clientId),
-        normalize(clientVersion),
-        serverVersion,
-        sdkVersion
-      ]));
-    }
+    _instrumentationLogger.log(_join([
+      TAG_VERSION,
+      uuid,
+      normalize(clientId),
+      normalize(clientVersion),
+      serverVersion,
+      sdkVersion
+    ]));
   }
 
   @override
   void logWatchEvent(String folderPath, String filePath, String changeType) {
-    if (_instrumentationLogger != null) {
-      _instrumentationLogger!
-          .log(_join([TAG_WATCH_EVENT, folderPath, filePath, changeType]));
-    }
+    _instrumentationLogger
+        .log(_join([TAG_WATCH_EVENT, folderPath, filePath, changeType]));
   }
 
   @override
   Future<void> shutdown() async {
-    await _instrumentationLogger?.shutdown();
+    await _instrumentationLogger.shutdown();
   }
 
   /// Write an escaped version of the given [field] to the given [buffer].
@@ -208,9 +183,7 @@
 
   /// Log the given message with the given tag.
   void _log(String tag, String message) {
-    if (_instrumentationLogger != null) {
-      _instrumentationLogger!.log(_join([tag, message]));
-    }
+    _instrumentationLogger.log(_join([tag, message]));
   }
 
   /// Convert the given [object] to a string.
diff --git a/pkg/analyzer/lib/src/context/builder.dart b/pkg/analyzer/lib/src/context/builder.dart
index e8a31f4..6d79372 100644
--- a/pkg/analyzer/lib/src/context/builder.dart
+++ b/pkg/analyzer/lib/src/context/builder.dart
@@ -67,7 +67,7 @@
 
   /// The manager used to manage the DartSdk's that have been created so that
   /// they can be shared across contexts.
-  final DartSdkManager? sdkManager;
+  final DartSdkManager sdkManager;
 
   /// The cache containing the contents of overlaid files. If this builder will
   /// be used to build analysis drivers, set the [fileContentOverlay] instead.
@@ -114,13 +114,19 @@
     String path = contextRoot.root;
     var options = getAnalysisOptions(path, contextRoot: contextRoot);
     //_processAnalysisOptions(context, optionMap);
+
     SummaryDataStore? summaryData;
-    if (builderOptions.librarySummaryPaths != null) {
-      summaryData = SummaryDataStore(builderOptions.librarySummaryPaths!);
+    var librarySummaryPaths = builderOptions.librarySummaryPaths;
+    if (librarySummaryPaths != null) {
+      summaryData = SummaryDataStore(librarySummaryPaths);
     }
+
     Workspace workspace = ContextBuilder.createWorkspace(
-        resourceProvider, path, this,
-        lookForBazelBuildFileSubstitutes: lookForBazelBuildFileSubstitutes);
+      resourceProvider: resourceProvider,
+      options: builderOptions,
+      rootPath: path,
+      lookForBazelBuildFileSubstitutes: lookForBazelBuildFileSubstitutes,
+    );
     final sf =
         createSourceFactoryFromWorkspace(workspace, summaryData: summaryData);
 
@@ -133,7 +139,11 @@
       contextRoot,
       sf,
       options,
-      packages: createPackageMap(path),
+      packages: createPackageMap(
+        resourceProvider: resourceProvider,
+        options: builderOptions,
+        rootPath: path,
+      ),
       enableIndex: enableIndex,
       externalSummaries: summaryData,
       retainDataForTesting: retainDataForTesting,
@@ -196,21 +206,13 @@
 //    }
 //  }
 
-  Packages createPackageMap(String rootDirectoryPath) {
-    var configPath = builderOptions.defaultPackageFilePath;
-    if (configPath != null) {
-      var configFile = resourceProvider.getFile(configPath);
-      return parsePackagesFile(resourceProvider, configFile);
-    } else {
-      var resource = resourceProvider.getResource(rootDirectoryPath);
-      return findPackagesFrom(resourceProvider, resource);
-    }
-  }
-
   SourceFactory createSourceFactory(String rootPath,
       {SummaryDataStore? summaryData}) {
-    Workspace workspace =
-        ContextBuilder.createWorkspace(resourceProvider, rootPath, this);
+    Workspace workspace = ContextBuilder.createWorkspace(
+      resourceProvider: resourceProvider,
+      options: builderOptions,
+      rootPath: rootPath,
+    );
     DartSdk sdk = findSdk(workspace);
     if (summaryData != null && sdk is SummaryBasedDartSdk) {
       summaryData.addBundle(null, sdk.bundle);
@@ -248,9 +250,9 @@
 
     DartSdk folderSdk;
     {
-      String sdkPath = sdkManager!.defaultSdkDirectory;
+      String sdkPath = sdkManager.defaultSdkDirectory;
       SdkDescription description = SdkDescription(sdkPath);
-      folderSdk = sdkManager!.getSdk(description, () {
+      folderSdk = sdkManager.getSdk(description, () {
         return FolderBasedDartSdk(
           resourceProvider,
           resourceProvider.getFolder(sdkPath),
@@ -296,8 +298,11 @@
 
     // TODO(danrubel) restructure so that we don't create a workspace
     // both here and in createSourceFactory
-    Workspace workspace =
-        ContextBuilder.createWorkspace(resourceProvider, path, this);
+    Workspace workspace = ContextBuilder.createWorkspace(
+      resourceProvider: resourceProvider,
+      options: builderOptions,
+      rootPath: path,
+    );
     SourceFactory sourceFactory = workspace.createSourceFactory(null, null);
     AnalysisOptionsProvider optionsProvider =
         AnalysisOptionsProvider(sourceFactory);
@@ -342,8 +347,9 @@
 
     if (optionMap != null) {
       applyToAnalysisOptions(options, optionMap);
-      if (builderOptions.argResults != null) {
-        applyAnalysisOptionFlags(options, builderOptions.argResults!,
+      var argResults = builderOptions.argResults;
+      if (argResults != null) {
+        applyAnalysisOptionFlags(options, argResults,
             verbosePrint: verbosePrint);
       }
     } else {
@@ -402,10 +408,33 @@
     return null;
   }
 
-  static Workspace createWorkspace(ResourceProvider resourceProvider,
-      String rootPath, ContextBuilder contextBuilder,
-      {bool lookForBazelBuildFileSubstitutes = true}) {
-    var packages = contextBuilder.createPackageMap(rootPath);
+  /// Return [Packages] to analyze a resource with the [rootPath].
+  static Packages createPackageMap({
+    required ResourceProvider resourceProvider,
+    required ContextBuilderOptions options,
+    required String rootPath,
+  }) {
+    var configPath = options.defaultPackageFilePath;
+    if (configPath != null) {
+      var configFile = resourceProvider.getFile(configPath);
+      return parsePackagesFile(resourceProvider, configFile);
+    } else {
+      var resource = resourceProvider.getResource(rootPath);
+      return findPackagesFrom(resourceProvider, resource);
+    }
+  }
+
+  static Workspace createWorkspace({
+    required ResourceProvider resourceProvider,
+    required ContextBuilderOptions options,
+    required String rootPath,
+    bool lookForBazelBuildFileSubstitutes = true,
+  }) {
+    var packages = ContextBuilder.createPackageMap(
+      resourceProvider: resourceProvider,
+      options: options,
+      rootPath: rootPath,
+    );
     var packageMap = <String, List<Folder>>{};
     for (var package in packages.packages) {
       packageMap[package.name] = [package.libFolder];
diff --git a/pkg/analyzer/lib/src/context/packages.dart b/pkg/analyzer/lib/src/context/packages.dart
index 57cdcd2..fd7c7e5 100644
--- a/pkg/analyzer/lib/src/context/packages.dart
+++ b/pkg/analyzer/lib/src/context/packages.dart
@@ -93,10 +93,11 @@
     );
 
     Version? languageVersion;
-    if (jsonPackage.languageVersion != null) {
+    var jsonLanguageVersion = jsonPackage.languageVersion;
+    if (jsonLanguageVersion != null) {
       languageVersion = Version(
-        jsonPackage.languageVersion!.major,
-        jsonPackage.languageVersion!.minor,
+        jsonLanguageVersion.major,
+        jsonLanguageVersion.minor,
         0,
       );
       // New features were added in `2.2.2` over `2.2.0`.
diff --git a/pkg/analyzer/lib/src/dart/analysis/dependency/library_builder.dart b/pkg/analyzer/lib/src/dart/analysis/dependency/library_builder.dart
index 836177c..6a8e2c1 100644
--- a/pkg/analyzer/lib/src/dart/analysis/dependency/library_builder.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/dependency/library_builder.dart
@@ -142,12 +142,6 @@
   /// are different.
   late List<int> uriSignature;
 
-  /// The name of the enclosing class name, or `null` if outside a class.
-  String? enclosingClassName;
-
-  /// The super class of the enclosing class, or `null` if outside a class.
-  TypeName? enclosingSuperClass;
-
   /// The precomputed signature of the enclosing class name, or `null` if
   /// outside a class.
   ///
@@ -156,9 +150,6 @@
   /// locations are different.
   List<int>? enclosingClassNameSignature;
 
-  /// The node of the enclosing class.
-  Node? enclosingClass;
-
   _LibraryBuilder(this.uri, this.units);
 
   Library build() {
@@ -176,25 +167,29 @@
   }
 
   void _addClassOrMixin(ClassOrMixinDeclaration node) {
-    enclosingClassName = node.name.name;
+    var enclosingClassName = node.name.name;
+
+    TypeName? enclosingSuperClass;
     if (node is ClassDeclaration) {
       enclosingSuperClass = node.extendsClause?.superclass;
     }
 
     enclosingClassNameSignature =
-        (ApiSignature()..addString(enclosingClassName!)).toByteList();
+        (ApiSignature()..addString(enclosingClassName)).toByteList();
 
     var apiTokenSignature = _computeTokenSignature(
       node.beginToken,
       node.leftBracket,
     );
 
+    var typeParameters = node.typeParameters;
+
     Dependencies api;
     if (node is ClassDeclaration) {
       api = referenceCollector.collect(
         apiTokenSignature,
         thisNodeName: enclosingClassName,
-        typeParameters: node.typeParameters,
+        typeParameters: typeParameters,
         extendsClause: node.extendsClause,
         withClause: node.withClause,
         implementsClause: node.implementsClause,
@@ -203,7 +198,7 @@
       api = referenceCollector.collect(
         apiTokenSignature,
         thisNodeName: enclosingClassName,
-        typeParameters: node.typeParameters,
+        typeParameters: typeParameters,
         onClause: node.onClause,
         implementsClause: node.implementsClause,
       );
@@ -211,8 +206,8 @@
       throw UnimplementedError('(${node.runtimeType}) $node');
     }
 
-    enclosingClass = Node(
-      LibraryQualifiedName(uri, enclosingClassName!),
+    var enclosingClass = Node(
+      LibraryQualifiedName(uri, enclosingClassName),
       node is MixinDeclaration ? NodeKind.MIXIN : NodeKind.CLASS,
       api,
       Dependencies.none,
@@ -224,9 +219,9 @@
 
     // TODO(scheglov) do we need type parameters at all?
     List<Node> classTypeParameters;
-    if (node.typeParameters != null) {
+    if (typeParameters != null) {
       classTypeParameters = <Node>[];
-      for (var typeParameter in node.typeParameters!.typeParameters) {
+      for (var typeParameter in typeParameters.typeParameters) {
         var api = referenceCollector.collect(
           _computeNodeTokenSignature(typeParameter),
           enclosingClassName: enclosingClassName,
@@ -238,11 +233,11 @@
           NodeKind.TYPE_PARAMETER,
           api,
           Dependencies.none,
-          enclosingClass: enclosingClass!,
+          enclosingClass: enclosingClass,
         ));
       }
       classTypeParameters.sort(Node.compare);
-      enclosingClass!.setTypeParameters(classTypeParameters);
+      enclosingClass.setTypeParameters(classTypeParameters);
     }
 
     var classMembers = <Node>[];
@@ -250,16 +245,22 @@
     for (var member in node.members) {
       if (member is ConstructorDeclaration) {
         hasConstructor = true;
-        _addConstructor(classMembers, member);
+        _addConstructor(
+          enclosingClass,
+          enclosingSuperClass,
+          classMembers,
+          member,
+        );
       } else if (member is FieldDeclaration) {
         _addVariables(
+          enclosingClass,
           classMembers,
           member.metadata,
           member.fields,
           hasConstConstructor,
         );
       } else if (member is MethodDeclaration) {
-        _addMethod(classMembers, member);
+        _addMethod(enclosingClass, classMembers, member);
       } else {
         throw UnimplementedError('(${member.runtimeType}) $member');
       }
@@ -271,18 +272,15 @@
         NodeKind.CONSTRUCTOR,
         Dependencies.none,
         Dependencies.none,
-        enclosingClass: enclosingClass!,
+        enclosingClass: enclosingClass,
       ));
     }
 
     classMembers.sort(Node.compare);
-    enclosingClass!.setClassMembers(classMembers);
+    enclosingClass.setClassMembers(classMembers);
 
-    declaredNodes.add(enclosingClass!);
-    enclosingClassName = null;
+    declaredNodes.add(enclosingClass);
     enclosingClassNameSignature = null;
-    enclosingSuperClass = null;
-    enclosingClass = null;
   }
 
   void _addClassTypeAlias(ClassTypeAlias node) {
@@ -303,7 +301,12 @@
     ));
   }
 
-  void _addConstructor(List<Node> classMembers, ConstructorDeclaration node) {
+  void _addConstructor(
+    Node enclosingClass,
+    TypeName? enclosingSuperClass,
+    List<Node> classMembers,
+    ConstructorDeclaration node,
+  ) {
     var builder = _newApiSignatureBuilder();
     _appendMetadataTokens(builder, node.metadata);
     _appendFormalParametersTokens(builder, node.parameters);
@@ -311,14 +314,14 @@
 
     var api = referenceCollector.collect(
       apiTokenSignature,
-      enclosingClassName: enclosingClassName,
+      enclosingClassName: enclosingClass.name.name,
       formalParameters: node.parameters,
     );
 
     var implTokenSignature = _computeNodeTokenSignature(node.body);
     var impl = referenceCollector.collect(
       implTokenSignature,
-      enclosingClassName: enclosingClassName,
+      enclosingClassName: enclosingClass.name.name,
       enclosingSuperClass: enclosingSuperClass,
       formalParametersForImpl: node.parameters,
       constructorInitializers: node.initializers,
@@ -331,7 +334,7 @@
       NodeKind.CONSTRUCTOR,
       api,
       impl,
-      enclosingClass: enclosingClass!,
+      enclosingClass: enclosingClass,
     ));
   }
 
@@ -392,9 +395,11 @@
     for (var directive in units.first.directives) {
       if (directive is ExportDirective) {
         var refUri = directive.uri.stringValue;
-        var importUri = uri.resolve(refUri!);
-        var combinators = _getCombinators(directive);
-        exports.add(Export(importUri, combinators));
+        if (refUri != null) {
+          var importUri = uri.resolve(refUri);
+          var combinators = _getCombinators(directive);
+          exports.add(Export(importUri, combinators));
+        }
       }
     }
   }
@@ -499,7 +504,11 @@
     for (var directive in units.first.directives) {
       if (directive is ImportDirective) {
         var refUri = directive.uri.stringValue;
-        var importUri = uri.resolve(refUri!);
+        if (refUri == null) {
+          continue;
+        }
+
+        var importUri = uri.resolve(refUri);
 
         if (importUri.toString() == 'dart:core') {
           hasDartCoreImport = true;
@@ -521,7 +530,11 @@
     }
   }
 
-  void _addMethod(List<Node> classMembers, MethodDeclaration node) {
+  void _addMethod(
+    Node enclosingClass,
+    List<Node> classMembers,
+    MethodDeclaration node,
+  ) {
     var builder = _newApiSignatureBuilder();
     _appendMetadataTokens(builder, node.metadata);
     _appendNodeTokens(builder, node.returnType);
@@ -541,7 +554,7 @@
     // TODO(scheglov) metadata, here and everywhere
     var api = referenceCollector.collect(
       apiTokenSignature,
-      enclosingClassName: enclosingClassName,
+      enclosingClassName: enclosingClass.name.name,
       thisNodeName: node.name.name,
       typeParameters: node.typeParameters,
       formalParameters: node.parameters,
@@ -551,7 +564,7 @@
     var implTokenSignature = _computeNodeTokenSignature(node.body);
     var impl = referenceCollector.collect(
       implTokenSignature,
-      enclosingClassName: enclosingClassName,
+      enclosingClassName: enclosingClass.name.name,
       thisNodeName: node.name.name,
       formalParametersForImpl: node.parameters,
       functionBody: node.body,
@@ -559,7 +572,7 @@
 
     var name = LibraryQualifiedName(uri, node.name.name);
     classMembers.add(
-      Node(name, kind, api, impl, enclosingClass: enclosingClass!),
+      Node(name, kind, api, impl, enclosingClass: enclosingClass),
     );
   }
 
@@ -579,6 +592,7 @@
         _addGenericTypeAlias(declaration);
       } else if (declaration is TopLevelVariableDeclaration) {
         _addVariables(
+          null,
           declaredNodes,
           declaration.metadata,
           declaration.variables,
@@ -590,8 +604,13 @@
     }
   }
 
-  void _addVariables(List<Node> variableNodes, List<Annotation> metadata,
-      VariableDeclarationList variables, bool appendInitializerToApi) {
+  void _addVariables(
+    Node? enclosingClass,
+    List<Node> variableNodes,
+    List<Annotation> metadata,
+    VariableDeclarationList variables,
+    bool appendInitializerToApi,
+  ) {
     if (variables.isConst || variables.type == null) {
       appendInitializerToApi = true;
     }
@@ -610,7 +629,7 @@
       var apiTokenSignature = builder.toByteList();
       var api = referenceCollector.collect(
         apiTokenSignature,
-        enclosingClassName: enclosingClassName,
+        enclosingClassName: enclosingClass?.name.name,
         thisNodeName: variable.name.name,
         type: variables.type,
         expression: appendInitializerToApi ? initializer : null,
@@ -619,7 +638,7 @@
       var implTokenSignature = _computeNodeTokenSignature(initializer);
       var impl = referenceCollector.collect(
         implTokenSignature,
-        enclosingClassName: enclosingClassName,
+        enclosingClassName: enclosingClass?.name.name,
         thisNodeName: variable.name.name,
         expression: initializer,
       );
@@ -668,9 +687,12 @@
   ApiSignature _newApiSignatureBuilder() {
     var builder = ApiSignature();
     builder.addBytes(uriSignature);
+
+    var enclosingClassNameSignature = this.enclosingClassNameSignature;
     if (enclosingClassNameSignature != null) {
-      builder.addBytes(enclosingClassNameSignature!);
+      builder.addBytes(enclosingClassNameSignature);
     }
+
     return builder;
   }
 
@@ -692,13 +714,12 @@
 
       // If a simple not named parameter, we don't need its name.
       // We should be careful to include also annotations.
-      if (parameter is SimpleFormalParameter && parameter.type != null) {
-        _appendTokens(
-          signature,
-          parameter.beginToken,
-          parameter.type!.endToken,
-        );
-        continue;
+      if (parameter is SimpleFormalParameter) {
+        var type = parameter.type;
+        if (type != null) {
+          _appendTokens(signature, parameter.beginToken, type.endToken);
+          continue;
+        }
       }
 
       // We don't know anything better than adding the whole parameter.
diff --git a/pkg/analyzer/lib/src/dart/analysis/dependency/reference_collector.dart b/pkg/analyzer/lib/src/dart/analysis/dependency/reference_collector.dart
index 6f7679b..85fe63e 100644
--- a/pkg/analyzer/lib/src/dart/analysis/dependency/reference_collector.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/dependency/reference_collector.dart
@@ -429,9 +429,12 @@
         DefaultFormalParameter defaultParameter = parameter;
         parameter = defaultParameter.parameter;
       }
-      if (parameter.identifier != null) {
-        _localScopes.add(parameter.identifier!.name);
+
+      var identifier = parameter.identifier;
+      if (identifier != null) {
+        _localScopes.add(identifier.name);
       }
+
       if (parameter is FieldFormalParameter) {
         _visitTypeAnnotation(parameter.type);
         // Strongly speaking, we reference a field of the enclosing class.
@@ -462,8 +465,9 @@
         parameter = defaultParameter.parameter;
       }
 
-      if (parameter.identifier != null) {
-        _localScopes.add(parameter.identifier!.name);
+      var identifier = parameter.identifier;
+      if (identifier != null) {
+        _localScopes.add(identifier.name);
       }
     }
   }
@@ -783,8 +787,9 @@
     if (node is GenericFunctionType) {
       _localScopes.enter();
 
-      if (node.typeParameters != null) {
-        var typeParameters = node.typeParameters!.typeParameters;
+      var typeParameterList = node.typeParameters;
+      if (typeParameterList != null) {
+        var typeParameters = typeParameterList.typeParameters;
         for (var i = 0; i < typeParameters.length; i++) {
           var typeParameter = typeParameters[i];
           _localScopes.add(typeParameter.name.name);
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver_based_analysis_context.dart b/pkg/analyzer/lib/src/dart/analysis/driver_based_analysis_context.dart
index 7178759..05e4a4b 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver_based_analysis_context.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver_based_analysis_context.dart
@@ -57,9 +57,11 @@
   }
 
   Workspace _buildWorkspace() {
-    String path = contextRoot.root.path;
-    ContextBuilder builder = ContextBuilder(
-        resourceProvider, null /* sdkManager */, null /* contentCache */);
-    return ContextBuilder.createWorkspace(resourceProvider, path, builder);
+    var path = contextRoot.root.path;
+    return ContextBuilder.createWorkspace(
+      resourceProvider: resourceProvider,
+      options: ContextBuilderOptions(),
+      rootPath: path,
+    );
   }
 }
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index da21735..df1ca02 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -2403,9 +2403,8 @@
   /// or `null` if this is not a redirecting factory constructor.
   ConstructorNameImpl? _redirectedConstructor;
 
-  /// The body of the constructor, or `null` if the constructor does not have a
-  /// body.
-  FunctionBodyImpl? _body;
+  /// The body of the constructor.
+  FunctionBodyImpl _body;
 
   /// The element associated with this constructor, or `null` if the AST
   /// structure has not been resolved or if this constructor could not be
@@ -2450,11 +2449,11 @@
   }
 
   @override
-  FunctionBody? get body => _body;
+  FunctionBody get body => _body;
 
   @override
-  set body(FunctionBody? functionBody) {
-    _body = _becomeParentOf(functionBody as FunctionBodyImpl?);
+  set body(FunctionBody functionBody) {
+    _body = _becomeParentOf(functionBody as FunctionBodyImpl);
   }
 
   @override
@@ -2473,12 +2472,7 @@
 
   @override
   Token get endToken {
-    if (_body != null) {
-      return _body!.endToken;
-    } else if (_initializers.isNotEmpty) {
-      return _initializers.endToken!;
-    }
-    return _parameters.endToken;
+    return _body.endToken;
   }
 
   @override
@@ -2539,7 +2533,7 @@
     _parameters.accept(visitor);
     _initializers.accept(visitor);
     _redirectedConstructor?.accept(visitor);
-    _body?.accept(visitor);
+    _body.accept(visitor);
   }
 }
 
@@ -4903,8 +4897,8 @@
   /// part of a top-level getter.
   FormalParameterListImpl? _parameters;
 
-  /// The body of the function, or `null` if this is an external function.
-  FunctionBodyImpl? _body;
+  /// The body of the function.
+  FunctionBodyImpl _body;
 
   @override
   ExecutableElement? declaredElement;
@@ -4922,20 +4916,16 @@
       return _typeParameters!.beginToken;
     } else if (_parameters != null) {
       return _parameters!.beginToken;
-    } else if (_body != null) {
-      return _body!.beginToken;
     }
-    // This should never be reached because external functions must be named,
-    // hence either the body or the name should be non-null.
-    throw StateError("Non-external functions must have a body");
+    return _body.beginToken;
   }
 
   @override
-  FunctionBody? get body => _body;
+  FunctionBody get body => _body;
 
   @override
-  set body(FunctionBody? functionBody) {
-    _body = _becomeParentOf(functionBody as FunctionBodyImpl?);
+  set body(FunctionBody functionBody) {
+    _body = _becomeParentOf(functionBody as FunctionBodyImpl);
   }
 
   @override
@@ -4944,14 +4934,7 @@
 
   @override
   Token get endToken {
-    if (_body != null) {
-      return _body!.endToken;
-    } else if (_parameters != null) {
-      return _parameters!.endToken;
-    }
-    // This should never be reached because external functions must be named,
-    // hence either the body or the name should be non-null.
-    throw StateError("Non-external functions must have a body");
+    return _body.endToken;
   }
 
   @override
@@ -4980,7 +4963,7 @@
   void visitChildren(AstVisitor visitor) {
     _typeParameters?.accept(visitor);
     _parameters?.accept(visitor);
-    _body?.accept(visitor);
+    _body.accept(visitor);
   }
 }
 
diff --git a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
index dca4023..9caaf9f 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
@@ -273,7 +273,7 @@
           separator,
           initializers,
           redirectedConstructor as ConstructorNameImpl?,
-          body as FunctionBodyImpl?);
+          body as FunctionBodyImpl);
 
   @override
   ConstructorFieldInitializer constructorFieldInitializer(
@@ -607,9 +607,9 @@
 
   @override
   FunctionExpression functionExpression(TypeParameterList? typeParameters,
-          FormalParameterList? parameters, FunctionBody? body) =>
+          FormalParameterList? parameters, FunctionBody body) =>
       FunctionExpressionImpl(typeParameters as TypeParameterListImpl?,
-          parameters as FormalParameterListImpl?, body as FunctionBodyImpl?);
+          parameters as FormalParameterListImpl?, body as FunctionBodyImpl);
 
   @override
   FunctionExpressionInvocation functionExpressionInvocation(Expression function,
diff --git a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
index 199a37f..4335edf 100644
--- a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
@@ -333,7 +333,7 @@
     safelyVisitNode(node.parameters);
     safelyVisitNodeListWithSeparatorAndPrefix(" : ", node.initializers, ", ");
     safelyVisitNodeWithPrefix(" = ", node.redirectedConstructor);
-    safelyVisitFunctionWithPrefix(" ", node.body!);
+    safelyVisitFunctionWithPrefix(" ", node.body);
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index d837988..abae5f8 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -322,7 +322,7 @@
           cloneNullableToken(node.separator),
           cloneNodeList(node.initializers),
           cloneNullableNode(node.redirectedConstructor),
-          cloneNullableNode(node.body));
+          cloneNode(node.body));
 
   @override
   ConstructorFieldInitializer visitConstructorFieldInitializer(
@@ -573,7 +573,7 @@
   @override
   FunctionExpression visitFunctionExpression(FunctionExpression node) =>
       astFactory.functionExpression(cloneNullableNode(node.typeParameters),
-          cloneNullableNode(node.parameters), cloneNullableNode(node.body));
+          cloneNullableNode(node.parameters), cloneNode(node.body));
 
   @override
   FunctionExpressionInvocation visitFunctionExpressionInvocation(
diff --git a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
index 3f8499f..3462422 100644
--- a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
+++ b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
@@ -95,11 +95,12 @@
 
   @override
   void visitConstructorDeclaration(ConstructorDeclaration node) {
-    if (node.constKeyword != null) {
+    var constKeyword = node.constKeyword;
+    if (constKeyword != null) {
       _validateConstructorInitializers(node);
       if (node.factoryKeyword == null) {
         _validateFieldInitializers(
-            node.parent as ClassOrMixinDeclaration, node);
+            node.parent as ClassOrMixinDeclaration, constKeyword);
       }
     }
     _validateDefaultValues(node.parameters);
@@ -148,7 +149,6 @@
       var verifier = _ConstLiteralVerifier(
         this,
         errorCode: CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT,
-        forList: true,
         listElementType: elementType,
       );
       for (CollectionElement element in node.elements) {
@@ -170,19 +170,16 @@
       if (node.isConst) {
         var nodeType = node.staticType as InterfaceType;
         var elementType = nodeType.typeArguments[0];
-        var duplicateElements = <Expression, Expression>{};
+        var config = _SetVerifierConfig(elementType: elementType);
         var verifier = _ConstLiteralVerifier(
           this,
           errorCode: CompileTimeErrorCode.NON_CONSTANT_SET_ELEMENT,
-          forSet: true,
-          setElementType: elementType,
-          setUniqueValues: <DartObject, Expression>{},
-          setDuplicateExpressions: duplicateElements,
+          setConfig: config,
         );
         for (CollectionElement element in node.elements) {
           verifier.verify(element);
         }
-        for (var duplicateEntry in duplicateElements.entries) {
+        for (var duplicateEntry in config.duplicateElements.entries) {
           _errorReporter.reportError(_diagnosticFactory.equalElementsInConstSet(
               _errorReporter.source, duplicateEntry.key, duplicateEntry.value));
         }
@@ -193,21 +190,20 @@
         var keyType = nodeType.typeArguments[0];
         var valueType = nodeType.typeArguments[1];
         bool reportEqualKeys = true;
-        var duplicateKeyElements = <Expression, Expression>{};
+        var config = _MapVerifierConfig(
+          keyType: keyType,
+          valueType: valueType,
+        );
         var verifier = _ConstLiteralVerifier(
           this,
           errorCode: CompileTimeErrorCode.NON_CONSTANT_MAP_ELEMENT,
-          forMap: true,
-          mapKeyType: keyType,
-          mapValueType: valueType,
-          mapUniqueKeys: <DartObject, Expression>{},
-          mapDuplicateKeyExpressions: duplicateKeyElements,
+          mapConfig: config,
         );
         for (CollectionElement entry in node.elements) {
           verifier.verify(entry);
         }
         if (reportEqualKeys) {
-          for (var duplicateEntry in duplicateKeyElements.entries) {
+          for (var duplicateEntry in config.duplicateKeys.entries) {
             _errorReporter.reportError(_diagnosticFactory.equalKeysInConstMap(
                 _errorReporter.source,
                 duplicateEntry.key,
@@ -484,8 +480,8 @@
   ///
   /// @param classDeclaration the class which should be validated
   /// @param errorSite the site at which errors should be reported.
-  void _validateFieldInitializers(ClassOrMixinDeclaration classDeclaration,
-      ConstructorDeclaration errorSite) {
+  void _validateFieldInitializers(
+      ClassOrMixinDeclaration classDeclaration, Token constKeyword) {
     NodeList<ClassMember> members = classDeclaration.members;
     for (ClassMember member in members) {
       if (member is FieldDeclaration && !member.isStatic) {
@@ -508,7 +504,7 @@
               _errorReporter.reportErrorForToken(
                   CompileTimeErrorCode
                       .CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST,
-                  errorSite.constKeyword!,
+                  constKeyword,
                   [variableDeclaration.name.name]);
             }
           }
@@ -618,62 +614,34 @@
 
 class _ConstLiteralVerifier {
   final ConstantVerifier verifier;
-  final Map<DartObject, Expression>? mapUniqueKeys;
-  final Map<Expression, Expression>? mapDuplicateKeyExpressions;
   final ErrorCode errorCode;
   final DartType? listElementType;
-  final DartType? mapKeyType;
-  final DartType? mapValueType;
-  final DartType? setElementType;
-  final Map<DartObject, Expression>? setUniqueValues;
-  final Map<Expression, Expression>? setDuplicateExpressions;
-  final bool forList;
-  final bool forMap;
-  final bool forSet;
+  final _SetVerifierConfig? setConfig;
+  final _MapVerifierConfig? mapConfig;
 
   _ConstLiteralVerifier(
     this.verifier, {
-    this.mapUniqueKeys,
-    this.mapDuplicateKeyExpressions,
     required this.errorCode,
     this.listElementType,
-    this.mapKeyType,
-    this.mapValueType,
-    this.setElementType,
-    this.setUniqueValues,
-    this.setDuplicateExpressions,
-    this.forList = false,
-    this.forMap = false,
-    this.forSet = false,
+    this.mapConfig,
+    this.setConfig,
   });
 
-  ErrorCode? get _fromDeferredErrorCode {
-    if (forList) {
-      return CompileTimeErrorCode
-          .NON_CONSTANT_LIST_ELEMENT_FROM_DEFERRED_LIBRARY;
-    } else if (forSet) {
-      return CompileTimeErrorCode.SET_ELEMENT_FROM_DEFERRED_LIBRARY;
-    }
-
-    return null;
-  }
-
   bool verify(CollectionElement element) {
     if (element is Expression) {
       var value = verifier._validate(element, errorCode);
       if (value == null) return false;
 
-      if (_fromDeferredErrorCode != null) {
-        verifier._reportErrorIfFromDeferredLibrary(
-            element, _fromDeferredErrorCode!);
+      _validateExpressionFromDeferredLibrary(element);
+
+      var listElementType = this.listElementType;
+      if (listElementType != null) {
+        return _validateListExpression(listElementType, element, value);
       }
 
-      if (forList) {
-        return _validateListExpression(element, value);
-      }
-
-      if (forSet) {
-        return _validateSetExpression(element, value);
+      var setConfig = this.setConfig;
+      if (setConfig != null) {
+        return _validateSetExpression(setConfig, element, value);
       }
 
       return true;
@@ -692,15 +660,17 @@
 
       var thenValid = true;
       var elseValid = true;
+      var thenElement = element.thenElement;
+      var elseElement = element.elseElement;
       if (conditionBool) {
-        thenValid = verify(element.thenElement);
-        if (element.elseElement != null) {
-          elseValid = _reportNotPotentialConstants(element.elseElement!);
+        thenValid = verify(thenElement);
+        if (elseElement != null) {
+          elseValid = _reportNotPotentialConstants(elseElement);
         }
       } else {
-        thenValid = _reportNotPotentialConstants(element.thenElement);
-        if (element.elseElement != null) {
-          elseValid = verify(element.elseElement!);
+        thenValid = _reportNotPotentialConstants(thenElement);
+        if (elseElement != null) {
+          elseValid = verify(elseElement);
         }
       }
 
@@ -714,12 +684,13 @@
       verifier._reportErrorIfFromDeferredLibrary(element.expression,
           CompileTimeErrorCode.SPREAD_EXPRESSION_FROM_DEFERRED_LIBRARY);
 
-      if (forList || forSet) {
+      if (listElementType != null || setConfig != null) {
         return _validateListOrSetSpread(element, value);
       }
 
-      if (forMap) {
-        return _validateMapSpread(element, value);
+      var mapConfig = this.mapConfig;
+      if (mapConfig != null) {
+        return _validateMapSpread(mapConfig, element, value);
       }
 
       return true;
@@ -739,9 +710,9 @@
 
     for (var notConst in notPotentiallyConstants) {
       CompileTimeErrorCode errorCode;
-      if (forList) {
+      if (listElementType != null) {
         errorCode = CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT;
-      } else if (forMap) {
+      } else if (mapConfig != null) {
         errorCode = CompileTimeErrorCode.NON_CONSTANT_MAP_ELEMENT;
         for (AstNode? parent = notConst;
             parent != null;
@@ -755,7 +726,7 @@
             break;
           }
         }
-      } else if (forSet) {
+      } else if (setConfig != null) {
         errorCode = CompileTimeErrorCode.NON_CONSTANT_SET_ELEMENT;
       } else {
         throw UnimplementedError();
@@ -766,8 +737,23 @@
     return false;
   }
 
-  bool _validateListExpression(Expression expression, DartObjectImpl value) {
-    if (!verifier._runtimeTypeMatch(value, listElementType!)) {
+  void _validateExpressionFromDeferredLibrary(Expression expression) {
+    if (listElementType != null) {
+      verifier._reportErrorIfFromDeferredLibrary(
+        expression,
+        CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT_FROM_DEFERRED_LIBRARY,
+      );
+    } else if (setConfig != null) {
+      verifier._reportErrorIfFromDeferredLibrary(
+        expression,
+        CompileTimeErrorCode.SET_ELEMENT_FROM_DEFERRED_LIBRARY,
+      );
+    }
+  }
+
+  bool _validateListExpression(
+      DartType listElementType, Expression expression, DartObjectImpl value) {
+    if (!verifier._runtimeTypeMatch(value, listElementType)) {
       verifier._errorReporter.reportErrorForNode(
         CompileTimeErrorCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE,
         expression,
@@ -787,9 +773,10 @@
   bool _validateListOrSetSpread(SpreadElement element, DartObjectImpl value) {
     var listValue = value.toListValue();
     var setValue = value.toSetValue();
+    var iterableValue = listValue ?? setValue;
 
-    if (listValue == null && setValue == null) {
-      if (value.isNull && _isNullableSpread(element)) {
+    if (iterableValue == null) {
+      if (value.isNull && element.isNullAware) {
         return true;
       }
       verifier._errorReporter.reportErrorForNode(
@@ -811,14 +798,15 @@
       }
     }
 
-    if (forSet) {
-      var iterableValue = (listValue ?? setValue)!;
+    var setConfig = this.setConfig;
+    if (setConfig != null) {
       for (var item in iterableValue) {
         Expression expression = element.expression;
-        if (setUniqueValues!.containsKey(item)) {
-          setDuplicateExpressions![expression] = setUniqueValues![item]!;
+        var existingValue = setConfig.uniqueValues[item];
+        if (existingValue != null) {
+          setConfig.duplicateElements[expression] = existingValue;
         } else {
-          setUniqueValues![item] = expression;
+          setConfig.uniqueValues[item] = expression;
         }
       }
     }
@@ -827,7 +815,8 @@
   }
 
   bool _validateMapLiteralEntry(MapLiteralEntry entry) {
-    if (!forMap) return false;
+    var config = mapConfig;
+    if (config == null) return false;
 
     var keyExpression = entry.key;
     var valueExpression = entry.value;
@@ -844,11 +833,11 @@
     if (keyValue != null) {
       var keyType = keyValue.type;
 
-      if (!verifier._runtimeTypeMatch(keyValue, mapKeyType!)) {
+      if (!verifier._runtimeTypeMatch(keyValue, config.keyType)) {
         verifier._errorReporter.reportErrorForNode(
           CompileTimeErrorCode.MAP_KEY_TYPE_NOT_ASSIGNABLE,
           keyExpression,
-          [keyType, mapKeyType],
+          [keyType, config.keyType],
         );
       }
 
@@ -865,19 +854,20 @@
         CompileTimeErrorCode.NON_CONSTANT_MAP_KEY_FROM_DEFERRED_LIBRARY,
       );
 
-      if (mapUniqueKeys!.containsKey(keyValue)) {
-        mapDuplicateKeyExpressions![keyExpression] = mapUniqueKeys![keyValue]!;
+      var existingKey = config.uniqueKeys[keyValue];
+      if (existingKey != null) {
+        config.duplicateKeys[keyExpression] = existingKey;
       } else {
-        mapUniqueKeys![keyValue] = keyExpression;
+        config.uniqueKeys[keyValue] = keyExpression;
       }
     }
 
     if (valueValue != null) {
-      if (!verifier._runtimeTypeMatch(valueValue, mapValueType!)) {
+      if (!verifier._runtimeTypeMatch(valueValue, config.valueType)) {
         verifier._errorReporter.reportErrorForNode(
           CompileTimeErrorCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE,
           valueExpression,
-          [valueValue.type, mapValueType],
+          [valueValue.type, config.valueType],
         );
       }
 
@@ -890,8 +880,12 @@
     return true;
   }
 
-  bool _validateMapSpread(SpreadElement element, DartObjectImpl value) {
-    if (value.isNull && _isNullableSpread(element)) {
+  bool _validateMapSpread(
+    _MapVerifierConfig config,
+    SpreadElement element,
+    DartObjectImpl value,
+  ) {
+    if (value.isNull && element.isNullAware) {
       return true;
     }
     var map = value.toMapValue();
@@ -901,11 +895,11 @@
       //  value being referenced might not be located there (if it's referenced
       //  through a const variable).
       for (var keyValue in map.keys) {
-        if (mapUniqueKeys!.containsKey(keyValue)) {
-          mapDuplicateKeyExpressions![element.expression] =
-              mapUniqueKeys![keyValue]!;
+        var existingKey = config.uniqueKeys[keyValue];
+        if (existingKey != null) {
+          config.duplicateKeys[element.expression] = existingKey;
         } else {
-          mapUniqueKeys![keyValue] = element.expression;
+          config.uniqueKeys[keyValue] = element.expression;
         }
       }
       return true;
@@ -917,12 +911,16 @@
     return false;
   }
 
-  bool _validateSetExpression(Expression expression, DartObjectImpl value) {
-    if (!verifier._runtimeTypeMatch(value, setElementType!)) {
+  bool _validateSetExpression(
+    _SetVerifierConfig config,
+    Expression expression,
+    DartObjectImpl value,
+  ) {
+    if (!verifier._runtimeTypeMatch(value, config.elementType)) {
       verifier._errorReporter.reportErrorForNode(
         CompileTimeErrorCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE,
         expression,
-        [value.type, setElementType],
+        [value.type, config.elementType],
       );
       return false;
     }
@@ -941,17 +939,35 @@
       CompileTimeErrorCode.SET_ELEMENT_FROM_DEFERRED_LIBRARY,
     );
 
-    if (setUniqueValues!.containsKey(value)) {
-      setDuplicateExpressions![expression] = setUniqueValues![value]!;
+    var existingValue = config.uniqueValues[value];
+    if (existingValue != null) {
+      config.duplicateElements[expression] = existingValue;
     } else {
-      setUniqueValues![value] = expression;
+      config.uniqueValues[value] = expression;
     }
 
     return true;
   }
+}
 
-  static bool _isNullableSpread(SpreadElement element) {
-    return element.spreadOperator.type ==
-        TokenType.PERIOD_PERIOD_PERIOD_QUESTION;
-  }
+class _MapVerifierConfig {
+  final DartType keyType;
+  final DartType valueType;
+  final Map<DartObject, Expression> uniqueKeys = {};
+  final Map<Expression, Expression> duplicateKeys = {};
+
+  _MapVerifierConfig({
+    required this.keyType,
+    required this.valueType,
+  });
+}
+
+class _SetVerifierConfig {
+  final DartType elementType;
+  final Map<DartObject, Expression> uniqueValues = {};
+  final Map<Expression, Expression> duplicateElements = {};
+
+  _SetVerifierConfig({
+    required this.elementType,
+  });
 }
diff --git a/pkg/analyzer/lib/src/dart/element/extensions.dart b/pkg/analyzer/lib/src/dart/element/extensions.dart
index f600bd9..66ba586 100644
--- a/pkg/analyzer/lib/src/dart/element/extensions.dart
+++ b/pkg/analyzer/lib/src/dart/element/extensions.dart
@@ -32,13 +32,20 @@
     if (hasDoNotStore) {
       return true;
     }
+
     var ancestor = enclosingElement;
-    if (ancestor is ClassElement || ancestor is ExtensionElement) {
-      if (ancestor!.hasDoNotStore) {
+    if (ancestor is ClassElement) {
+      if (ancestor.hasDoNotStore) {
+        return true;
+      }
+      ancestor = ancestor.enclosingElement;
+    } else if (ancestor is ExtensionElement) {
+      if (ancestor.hasDoNotStore) {
         return true;
       }
       ancestor = ancestor.enclosingElement;
     }
+
     return ancestor is CompilationUnitElement &&
         ancestor.enclosingElement.hasDoNotStore;
   }
diff --git a/pkg/analyzer/lib/src/dart/micro/analysis_context.dart b/pkg/analyzer/lib/src/dart/micro/analysis_context.dart
index 530ff1f..4a7f9eb 100644
--- a/pkg/analyzer/lib/src/dart/micro/analysis_context.dart
+++ b/pkg/analyzer/lib/src/dart/micro/analysis_context.dart
@@ -140,10 +140,12 @@
   dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
 
   Workspace _buildWorkspace() {
-    String path = contextRoot.root.path;
-    ContextBuilder builder = ContextBuilder(
-        resourceProvider, null /* sdkManager */, null /* contentCache */);
-    return ContextBuilder.createWorkspace(resourceProvider, path, builder);
+    var path = contextRoot.root.path;
+    return ContextBuilder.createWorkspace(
+      resourceProvider: resourceProvider,
+      options: ContextBuilderOptions(),
+      rootPath: path,
+    );
   }
 }
 
diff --git a/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart
index f60d683..3b2ef9e 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart
@@ -36,7 +36,7 @@
 
   void resolve(FunctionExpression node) {
     var isFunctionDeclaration = node.parent is FunctionDeclaration;
-    var body = node.body!;
+    var body = node.body;
 
     if (_resolver.flowAnalysis != null) {
       if (_resolver.flowAnalysis!.flow != null && !isFunctionDeclaration) {
@@ -64,7 +64,7 @@
 
     if (_resolver.flowAnalysis != null) {
       if (_resolver.flowAnalysis!.flow != null && !isFunctionDeclaration) {
-        var bodyContext = BodyInferenceContext.of(node.body!);
+        var bodyContext = BodyInferenceContext.of(node.body);
         _resolver.checkForBodyMayCompleteNormally(
           returnType: bodyContext?.contextType,
           body: body,
diff --git a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
index b5eef7b..033fd97 100644
--- a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
@@ -297,7 +297,7 @@
 
           _resolveRedirectedConstructor(node);
           node.initializers.accept(this);
-          node.body?.accept(this);
+          node.body.accept(this);
         });
       });
     });
@@ -513,7 +513,7 @@
       setElementDocumentationComment(element, node);
       element.metadata = _createElementAnnotations(node.metadata);
 
-      var body = node.functionExpression.body as FunctionBody;
+      var body = node.functionExpression.body;
       if (node.externalKeyword != null || body is NativeFunctionBody) {
         element.isExternal = true;
       }
@@ -555,7 +555,7 @@
 
             _defineParameters(element.parameters);
             _withElementWalker(null, () {
-              expression.body!.accept(this);
+              expression.body.accept(this);
             });
           });
         },
@@ -581,7 +581,7 @@
     element.hasImplicitReturnType = true;
     element.returnType = DynamicTypeImpl.instance;
 
-    FunctionBody body = node.body!;
+    FunctionBody body = node.body;
     element.isAsynchronous = body.isAsynchronous;
     element.isGenerator = body.isGenerator;
 
@@ -596,7 +596,7 @@
         element.parameters = holder.parameters;
 
         _defineParameters(element.parameters);
-        node.body!.accept(this);
+        node.body.accept(this);
       });
     });
 
diff --git a/pkg/analyzer/lib/src/error/best_practices_verifier.dart b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
index 6b1b894..b3136ff 100644
--- a/pkg/analyzer/lib/src/error/best_practices_verifier.dart
+++ b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
@@ -341,14 +341,14 @@
     if (!_isNonNullableByDefault && node.declaredElement!.isFactory) {
       if (node.body is BlockFunctionBody) {
         // Check the block for a return statement, if not, create the hint.
-        if (!ExitDetector.exits(node.body!)) {
+        if (!ExitDetector.exits(node.body)) {
           _errorReporter.reportErrorForNode(
               HintCode.MISSING_RETURN, node, [node.returnType.name]);
         }
       }
     }
     _checkStrictInferenceInParameters(node.parameters,
-        body: node.body!, initializers: node.initializers);
+        body: node.body, initializers: node.initializers);
     super.visitConstructorDeclaration(node);
   }
 
@@ -429,7 +429,7 @@
       _inDoNotStoreMember = true;
     }
     try {
-      _checkForMissingReturn(node.functionExpression.body!, node);
+      _checkForMissingReturn(node.functionExpression.body, node);
 
       // Return types are inferred only on non-recursive local functions.
       if (node.parent is CompilationUnit && !node.isSetter) {
@@ -454,7 +454,7 @@
   @override
   void visitFunctionExpression(FunctionExpression node) {
     if (node.parent is! FunctionDeclaration) {
-      _checkForMissingReturn(node.body!, node);
+      _checkForMissingReturn(node.body, node);
     }
     var functionType = InferenceContext.getContext(node);
     if (functionType is! FunctionType) {
diff --git a/pkg/analyzer/lib/src/error/catch_error_verifier.dart b/pkg/analyzer/lib/src/error/catch_error_verifier.dart
index 08a8a52..42a6dc4 100644
--- a/pkg/analyzer/lib/src/error/catch_error_verifier.dart
+++ b/pkg/analyzer/lib/src/error/catch_error_verifier.dart
@@ -62,7 +62,7 @@
       var returnStatementVerifier =
           _ReturnStatementVerifier(_returnTypeVerifier);
       _returnTypeVerifier.enclosingExecutable = catchErrorOnErrorExecutable;
-      callback.body!.accept(returnStatementVerifier);
+      callback.body.accept(returnStatementVerifier);
     } else {
       var callbackType = callback.staticType;
       if (callbackType is FunctionType) {
diff --git a/pkg/analyzer/lib/src/error/dead_code_verifier.dart b/pkg/analyzer/lib/src/error/dead_code_verifier.dart
index bce84b9..eea542d 100644
--- a/pkg/analyzer/lib/src/error/dead_code_verifier.dart
+++ b/pkg/analyzer/lib/src/error/dead_code_verifier.dart
@@ -31,18 +31,18 @@
   final ErrorReporter _errorReporter;
 
   /// The object used to track the usage of labels within a given label scope.
-  _LabelTracker? labelTracker;
+  _LabelTracker? _labelTracker;
 
   DeadCodeVerifier(this._errorReporter);
 
   @override
   void visitBreakStatement(BreakStatement node) {
-    labelTracker?.recordUsage(node.label?.name);
+    _labelTracker?.recordUsage(node.label?.name);
   }
 
   @override
   void visitContinueStatement(ContinueStatement node) {
-    labelTracker?.recordUsage(node.label?.name);
+    _labelTracker?.recordUsage(node.label?.name);
   }
 
   @override
@@ -78,12 +78,9 @@
 
   @override
   void visitLabeledStatement(LabeledStatement node) {
-    _pushLabels(node.labels);
-    try {
+    _withLabelTracker(node.labels, () {
       super.visitLabeledStatement(node);
-    } finally {
-      _popLabels();
-    }
+    });
   }
 
   @override
@@ -92,12 +89,9 @@
     for (SwitchMember member in node.members) {
       labels.addAll(member.labels);
     }
-    _pushLabels(labels);
-    try {
+    _withLabelTracker(labels, () {
       super.visitSwitchStatement(node);
-    } finally {
-      _popLabels();
-    }
+    });
   }
 
   /// Resolve the names in the given [combinator] in the scope of the given
@@ -125,19 +119,18 @@
     }
   }
 
-  /// Exit the most recently entered label scope after reporting any labels that
-  /// were not referenced within that scope.
-  void _popLabels() {
-    for (Label label in labelTracker!.unusedLabels()) {
-      _errorReporter
-          .reportErrorForNode(HintCode.UNUSED_LABEL, label, [label.label.name]);
+  void _withLabelTracker(List<Label> labels, void Function() f) {
+    var labelTracker = _LabelTracker(_labelTracker, labels);
+    try {
+      _labelTracker = labelTracker;
+      f();
+    } finally {
+      for (Label label in labelTracker.unusedLabels()) {
+        _errorReporter.reportErrorForNode(
+            HintCode.UNUSED_LABEL, label, [label.label.name]);
+      }
+      _labelTracker = labelTracker.outerTracker;
     }
-    labelTracker = labelTracker!.outerTracker;
-  }
-
-  /// Enter a new label scope in which the given [labels] are defined.
-  void _pushLabels(List<Label> labels) {
-    labelTracker = _LabelTracker(labelTracker, labels);
   }
 }
 
@@ -491,13 +484,14 @@
   /// not `null`, and is covered by the [node], then we reached the end of
   /// the current dead code interval.
   void flowEnd(AstNode node) {
-    if (_firstDeadNode != null) {
+    var firstDeadNode = _firstDeadNode;
+    if (firstDeadNode != null) {
       if (!_containsFirstDeadNode(node)) {
         return;
       }
 
-      var parent = _firstDeadNode!.parent;
-      if (parent is Assertion && identical(_firstDeadNode, parent.message)) {
+      var parent = firstDeadNode.parent;
+      if (parent is Assertion && identical(firstDeadNode, parent.message)) {
         // Don't report "dead code" for the message part of an assert statement,
         // because this causes nuisance warnings for redundant `!= null`
         // asserts.
@@ -505,12 +499,12 @@
         // We know that [node] is the first dead node, or contains it.
         // So, technically the code code interval ends at the end of [node].
         // But we trim it to the last statement for presentation purposes.
-        if (node != _firstDeadNode) {
+        if (node != firstDeadNode) {
           if (node is FunctionDeclaration) {
-            node = node.functionExpression.body!;
+            node = node.functionExpression.body;
           }
           if (node is FunctionExpression) {
-            node = node.body!;
+            node = node.body;
           }
           if (node is MethodDeclaration) {
             node = node.body;
@@ -526,7 +520,7 @@
           }
         }
 
-        var offset = _firstDeadNode!.offset;
+        var offset = firstDeadNode.offset;
         var length = node.end - offset;
         _errorReporter.reportErrorForOffset(HintCode.DEAD_CODE, offset, length);
       }
@@ -570,10 +564,11 @@
     // So, they look unreachable, but this does not make sense.
     if (node is Comment) return;
 
-    if (_flowAnalysis == null) return;
-    _flowAnalysis!.checkUnreachableNode(node);
+    var flowAnalysis = _flowAnalysis;
+    if (flowAnalysis == null) return;
+    flowAnalysis.checkUnreachableNode(node);
 
-    var flow = _flowAnalysis!.flow;
+    var flow = flowAnalysis.flow;
     if (flow == null) return;
 
     if (flow.isReachable) return;
@@ -678,8 +673,8 @@
       var index = labelMap[labelName];
       if (index != null) {
         used[index] = true;
-      } else if (outerTracker != null) {
-        outerTracker!.recordUsage(labelName);
+      } else {
+        outerTracker?.recordUsage(labelName);
       }
     }
   }
diff --git a/pkg/analyzer/lib/src/error/must_call_super_verifier.dart b/pkg/analyzer/lib/src/error/must_call_super_verifier.dart
index ad1ca30..7898133 100644
--- a/pkg/analyzer/lib/src/error/must_call_super_verifier.dart
+++ b/pkg/analyzer/lib/src/error/must_call_super_verifier.dart
@@ -91,8 +91,9 @@
         .any(isConcrete)) {
       return true;
     }
-    if (classElement.supertype != null &&
-        isConcrete(classElement.supertype!.element)) {
+
+    var supertype = classElement.supertype;
+    if (supertype != null && isConcrete(supertype.element)) {
       return true;
     }
 
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index f0cf878..a90f3ab 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -523,7 +523,7 @@
     var element = node.declaredElement!;
     _withEnclosingExecutable(element, () {
       _checkForInvalidModifierOnBody(
-          node.body!, CompileTimeErrorCode.INVALID_MODIFIER_ON_CONSTRUCTOR);
+          node.body, CompileTimeErrorCode.INVALID_MODIFIER_ON_CONSTRUCTOR);
       _checkForConstConstructorWithNonFinalField(node, element);
       _checkForConstConstructorWithNonConstSuper(node);
       _constructorFieldsVerifier.verify(node);
@@ -4077,7 +4077,7 @@
       return;
     }
     // block body (with possible return statement) is checked elsewhere
-    FunctionBody body = declaration.body!;
+    FunctionBody body = declaration.body;
     if (body is! ExpressionFunctionBody) {
       return;
     }
diff --git a/pkg/analyzer/lib/src/generated/ffi_verifier.dart b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
index 16e000f..9b71259 100644
--- a/pkg/analyzer/lib/src/generated/ffi_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
@@ -18,7 +18,7 @@
   static const _allocatorClassName = 'Allocator';
   static const _allocateExtensionMethodName = 'call';
   static const _allocatorExtensionName = 'AllocatorAlloc';
-  static const _carrayClassName = 'CArray';
+  static const _cArrayClassName = 'CArray';
   static const _dartFfiLibraryName = 'dart.ffi';
   static const _opaqueClassName = 'Opaque';
 
@@ -61,11 +61,12 @@
     var extendsClause = node.extendsClause;
     if (extendsClause != null) {
       final TypeName superclass = extendsClause.superclass;
-      if (_isDartFfiClass(superclass)) {
-        final className = superclass.name.staticElement!.name;
+      final ffiClass = superclass.ffiClass;
+      if (ffiClass != null) {
+        final className = ffiClass.name;
         if (className == _structClassName) {
           inStruct = true;
-          if (_isEmptyStruct(node.declaredElement!)) {
+          if (node.declaredElement!.isEmptyStruct) {
             _errorReporter.reportErrorForNode(
                 FfiCode.EMPTY_STRUCT_WARNING, node, [node.name]);
           }
@@ -76,7 +77,7 @@
               superclass.name,
               [node.name.name, superclass.name.name]);
         }
-      } else if (_isSubtypeOfStruct(superclass)) {
+      } else if (superclass.isStructSubtype) {
         _errorReporter.reportErrorForNode(
             FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_EXTENDS,
             superclass,
@@ -91,10 +92,10 @@
       if (superName == _allocatorClassName) {
         return;
       }
-      if (_isDartFfiClass(typename)) {
+      if (typename.ffiClass != null) {
         _errorReporter.reportErrorForNode(
             subtypeOfFfiCode, typename, [node.name, typename.name]);
-      } else if (_isSubtypeOfStruct(typename)) {
+      } else if (typename.isStructSubtype) {
         _errorReporter.reportErrorForNode(
             subtypeOfStructCode, typename, [node.name, typename.name]);
       }
@@ -144,11 +145,9 @@
     var element = node.staticElement;
     if (element is MethodElement) {
       var enclosingElement = element.enclosingElement;
-      if (enclosingElement is ExtensionElement) {
-        if (_isAllocatorExtension(enclosingElement) &&
-            element.name == _allocateExtensionMethodName) {
-          _validateAllocate(node);
-        }
+      if (enclosingElement.isAllocatorExtension &&
+          element.name == _allocateExtensionMethodName) {
+        _validateAllocate(node);
       }
     }
     super.visitFunctionExpressionInvocation(node);
@@ -159,12 +158,10 @@
     var element = node.staticElement;
     if (element is MethodElement) {
       var enclosingElement = element.enclosingElement;
-      if (enclosingElement is ExtensionElement) {
-        if (_isNativeStructPointerExtension(enclosingElement) ||
-            _isNativeStructCArrayExtension(enclosingElement)) {
-          if (element.name == '[]') {
-            _validateRefIndexed(node);
-          }
+      if (enclosingElement.isNativeStructPointerExtension ||
+          enclosingElement.isNativeStructCArrayExtension) {
+        if (element.name == '[]') {
+          _validateRefIndexed(node);
         }
       }
     }
@@ -175,22 +172,18 @@
     var element = node.methodName.staticElement;
     if (element is MethodElement) {
       Element enclosingElement = element.enclosingElement;
-      if (enclosingElement is ClassElement) {
-        if (_isPointer(enclosingElement)) {
-          if (element.name == 'fromFunction') {
-            _validateFromFunction(node, element);
-          } else if (element.name == 'elementAt') {
-            _validateElementAt(node);
-          }
+      if (enclosingElement.isPointer) {
+        if (element.name == 'fromFunction') {
+          _validateFromFunction(node, element);
+        } else if (element.name == 'elementAt') {
+          _validateElementAt(node);
         }
-      }
-      if (enclosingElement is ExtensionElement) {
-        if (_isNativeFunctionPointerExtension(enclosingElement)) {
-          if (element.name == 'asFunction') {
-            _validateAsFunction(node, element);
-          }
-        } else if (_isDynamicLibraryExtension(enclosingElement) &&
-            element.name == 'lookupFunction') {
+      } else if (enclosingElement.isNativeFunctionPointerExtension) {
+        if (element.name == 'asFunction') {
+          _validateAsFunction(node, element);
+        }
+      } else if (enclosingElement.isDynamicLibraryExtension) {
+        if (element.name == 'lookupFunction') {
           _validateLookupFunction(node);
         }
       }
@@ -212,11 +205,9 @@
     var element = node.staticElement;
     if (element != null) {
       var enclosingElement = element.enclosingElement;
-      if (enclosingElement is ExtensionElement) {
-        if (_isNativeStructPointerExtension(enclosingElement)) {
-          if (element.name == 'ref') {
-            _validateRefPrefixedIdentifier(node);
-          }
+      if (enclosingElement.isNativeStructPointerExtension) {
+        if (element.name == 'ref') {
+          _validateRefPrefixedIdentifier(node);
         }
       }
     }
@@ -228,140 +219,15 @@
     var element = node.propertyName.staticElement;
     if (element != null) {
       var enclosingElement = element.enclosingElement;
-      if (enclosingElement is ExtensionElement) {
-        if (_isNativeStructPointerExtension(enclosingElement)) {
-          if (element.name == 'ref') {
-            _validateRefPropertyAccess(node);
-          }
+      if (enclosingElement.isNativeStructPointerExtension) {
+        if (element.name == 'ref') {
+          _validateRefPropertyAccess(node);
         }
       }
     }
     super.visitPropertyAccess(node);
   }
 
-  /// Return `true` if the given [element] represents the extension
-  /// `AllocatorAlloc`.
-  bool _isAllocatorExtension(Element element) =>
-      element.name == _allocatorExtensionName &&
-      element.library?.name == _dartFfiLibraryName;
-
-  /// Return `true` if the given [element] represents the class `CArray`.
-  bool _isCArray(Element? element) =>
-      element != null &&
-      element.name == _carrayClassName &&
-      element.library?.name == _dartFfiLibraryName;
-
-  /// Return `true` if the [typeName] is the name of a type from `dart:ffi`.
-  bool _isDartFfiClass(TypeName typeName) =>
-      _isDartFfiElement(typeName.name.staticElement);
-
-  /// Return `true` if the [element] is a class element from `dart:ffi`.
-  bool _isDartFfiElement(Element? element) {
-    if (element is ConstructorElement) {
-      element = element.enclosingElement;
-    }
-    return element is ClassElement &&
-        element.library.name == _dartFfiLibraryName;
-  }
-
-  /// Return `true` if the given [element] represents the extension
-  /// `DynamicLibraryExtension`.
-  bool _isDynamicLibraryExtension(Element element) =>
-      element.name == 'DynamicLibraryExtension' &&
-      element.library?.name == _dartFfiLibraryName;
-
-  bool _isEmptyStruct(ClassElement classElement) {
-    final fields = classElement.fields;
-    var structFieldCount = 0;
-    for (final field in fields) {
-      final declaredType = field.type;
-      if (declaredType.isDartCoreInt) {
-        structFieldCount++;
-      } else if (declaredType.isDartCoreDouble) {
-        structFieldCount++;
-      } else if (_isPointer(declaredType.element)) {
-        structFieldCount++;
-      } else if (_isStructClass(declaredType)) {
-        structFieldCount++;
-      } else if (_isCArray(declaredType.element)) {
-        structFieldCount++;
-      }
-    }
-    return structFieldCount == 0;
-  }
-
-  bool _isHandle(Element? element) =>
-      element != null &&
-      element.name == 'Handle' &&
-      element.library?.name == _dartFfiLibraryName;
-
-  /// Returns `true` iff [nativeType] is a `ffi.NativeFunction<???>` type.
-  bool _isNativeFunctionInterfaceType(DartType nativeType) {
-    if (nativeType is InterfaceType) {
-      final element = nativeType.element;
-      if (element.library.name == _dartFfiLibraryName) {
-        return element.name == 'NativeFunction' &&
-            nativeType.typeArguments.length == 1;
-      }
-    }
-    return false;
-  }
-
-  bool _isNativeFunctionPointerExtension(Element? element) =>
-      element != null &&
-      element.name == 'NativeFunctionPointer' &&
-      element.library?.name == _dartFfiLibraryName;
-
-  bool _isNativeStructCArrayExtension(Element element) =>
-      element.name == 'StructCArray' && element.library?.name == 'dart.ffi';
-
-  bool _isNativeStructPointerExtension(Element element) =>
-      element.name == 'StructPointer' && element.library?.name == 'dart.ffi';
-
-  /// Returns `true` iff [nativeType] is a `ffi.NativeType` type.
-  bool _isNativeTypeInterfaceType(DartType nativeType) {
-    if (nativeType is InterfaceType) {
-      final element = nativeType.element;
-      if (element.library.name == _dartFfiLibraryName) {
-        return element.name == 'NativeType';
-      }
-    }
-    return false;
-  }
-
-  /// Returns `true` iff [nativeType] is a opaque type, i.e. a subtype of `Opaque`.
-  bool _isOpaqueClass(DartType nativeType) {
-    if (nativeType is InterfaceType) {
-      final superType = nativeType.element.supertype;
-      if (superType == null) {
-        return false;
-      }
-      final superClassElement = superType.element;
-      if (superClassElement.library.name == _dartFfiLibraryName) {
-        return superClassElement.name == _opaqueClassName;
-      }
-    }
-    return false;
-  }
-
-  /// Return `true` if the given [element] represents the class `Pointer`.
-  bool _isPointer(Element? element) =>
-      element != null &&
-      element.name == 'Pointer' &&
-      element.library?.name == _dartFfiLibraryName;
-
-  /// Returns `true` iff [nativeType] is a `ffi.Pointer<???>` type.
-  bool _isPointerInterfaceType(DartType nativeType) {
-    if (nativeType is InterfaceType) {
-      final element = nativeType.element;
-      if (element.library.name == _dartFfiLibraryName) {
-        return element.name == 'Pointer' &&
-            nativeType.typeArguments.length == 1;
-      }
-    }
-    return false;
-  }
-
   /// Returns `true` if [nativeType] is a C type that has a size.
   bool _isSized(DartType nativeType) {
     switch (_primitiveNativeType(nativeType)) {
@@ -376,48 +242,15 @@
       case _PrimitiveDartType.none:
         break;
     }
-    if (_isStructClass(nativeType)) {
+    if (nativeType.isStructSubtype) {
       return true;
     }
-    if (_isPointer(nativeType.element)) {
+    if (nativeType.isPointer) {
       return true;
     }
     return false;
   }
 
-  /// Returns `true` iff [nativeType] is a struct type.
-  bool _isStructClass(DartType nativeType) {
-    if (nativeType is InterfaceType) {
-      final superType = nativeType.element.supertype;
-      if (superType == null) {
-        return false;
-      }
-      final superClassElement = superType.element;
-      if (superClassElement.library.name == _dartFfiLibraryName) {
-        return superClassElement.name == _structClassName &&
-            nativeType.typeArguments.isEmpty;
-      }
-    }
-    return false;
-  }
-
-  /// Return `true` if the [typeName] represents a subtype of `Struct`.
-  bool _isSubtypeOfStruct(TypeName typeName) {
-    var superType = typeName.name.staticElement;
-    if (superType is ClassElement) {
-      bool isStruct(InterfaceType? type) {
-        return type != null &&
-            type.element.name == _structClassName &&
-            type.element.library.name == _dartFfiLibraryName;
-      }
-
-      return isStruct(superType.supertype) ||
-          superType.interfaces.any(isStruct) ||
-          superType.mixins.any(isStruct);
-    }
-    return false;
-  }
-
   /// Validates that the given type is a valid dart:ffi native function
   /// signature.
   bool _isValidFfiNativeFunctionType(DartType nativeType) {
@@ -454,19 +287,19 @@
           (primitiveType != _PrimitiveDartType.void_ || allowVoid)) {
         return true;
       }
-      if (_isNativeFunctionInterfaceType(nativeType)) {
+      if (nativeType.isNativeFunction) {
         return _isValidFfiNativeFunctionType(nativeType.typeArguments.single);
       }
-      if (_isPointerInterfaceType(nativeType)) {
+      if (nativeType.isPointer) {
         final nativeArgumentType = nativeType.typeArguments.single;
         return _isValidFfiNativeType(nativeArgumentType,
                 allowVoid: true, allowEmptyStruct: true) ||
-            _isStructClass(nativeArgumentType) ||
-            _isNativeTypeInterfaceType(nativeArgumentType);
+            nativeArgumentType.isStructSubtype ||
+            nativeArgumentType.isNativeType;
       }
-      if (_isStructClass(nativeType)) {
+      if (nativeType.isStructSubtype) {
         if (!allowEmptyStruct) {
-          if (_isEmptyStruct(nativeType.element)) {
+          if (nativeType.element.isEmptyStruct) {
             // TODO(dartbug.com/36780): This results in an error message not
             // mentioning empty structs at all.
             return false;
@@ -474,10 +307,10 @@
         }
         return true;
       }
-      if (_isOpaqueClass(nativeType)) {
+      if (nativeType.isOpaqueSubtype) {
         return true;
       }
-      if (allowCArray && _isCArray(nativeType.element)) {
+      if (allowCArray && nativeType.isCArray) {
         return _isValidFfiNativeType(nativeType.typeArguments.single,
             allowVoid: false, allowEmptyStruct: false);
       }
@@ -490,7 +323,7 @@
   _PrimitiveDartType _primitiveNativeType(DartType nativeType) {
     if (nativeType is InterfaceType) {
       final element = nativeType.element;
-      if (element.library.name == _dartFfiLibraryName) {
+      if (element.isFfiClass) {
         final String name = element.name;
         if (_primitiveIntegerNativeTypes.contains(name)) {
           return _PrimitiveDartType.int;
@@ -547,7 +380,7 @@
     bool requiredFound = false;
     List<Annotation> extraAnnotations = [];
     for (Annotation annotation in annotations) {
-      if (_isDartFfiElement(annotation.element)) {
+      if (annotation.element.ffiClass != null) {
         if (requiredFound) {
           extraAnnotations.add(annotation);
         } else {
@@ -587,11 +420,9 @@
     }
     var target = node.realTarget!;
     var targetType = target.staticType;
-    if (targetType is InterfaceType &&
-        _isPointer(targetType.element) &&
-        targetType.typeArguments.length == 1) {
+    if (targetType is InterfaceType && targetType.isPointer) {
       final DartType T = targetType.typeArguments[0];
-      if (!_isNativeFunctionInterfaceType(T) ||
+      if (!T.isNativeFunction ||
           !_isValidFfiNativeFunctionType(
               (T as InterfaceType).typeArguments.single)) {
         final AstNode errorNode =
@@ -688,9 +519,7 @@
 
   void _validateElementAt(MethodInvocation node) {
     var targetType = node.realTarget?.staticType;
-    if (targetType is InterfaceType &&
-        _isPointer(targetType.element) &&
-        targetType.typeArguments.length == 1) {
+    if (targetType is InterfaceType && targetType.isPointer) {
       final DartType T = targetType.typeArguments[0];
 
       if (!_isValidFfiNativeType(T, allowVoid: true, allowEmptyStruct: true)) {
@@ -721,18 +550,18 @@
         _validateAnnotations(fieldType, annotations, _PrimitiveDartType.int);
       } else if (declaredType.isDartCoreDouble) {
         _validateAnnotations(fieldType, annotations, _PrimitiveDartType.double);
-      } else if (_isPointer(declaredType.element)) {
+      } else if (declaredType.isPointer) {
         _validateNoAnnotations(annotations);
-      } else if (_isCArray(declaredType.element)) {
+      } else if (declaredType.isCArray) {
         final typeArg = (declaredType as InterfaceType).typeArguments.single;
         if (!_isSized(typeArg)) {
           _errorReporter.reportErrorForNode(FfiCode.NON_SIZED_TYPE_ARGUMENT,
-              fieldType, [_carrayClassName, typeArg.toString()]);
+              fieldType, [_cArrayClassName, typeArg.toString()]);
         }
         _validateSizeOfAnnotation(fieldType, annotations);
-      } else if (_isStructClass(declaredType)) {
+      } else if (declaredType.isStructSubtype) {
         final clazz = (declaredType as InterfaceType).element;
-        if (_isEmptyStruct(clazz)) {
+        if (clazz.isEmptyStruct) {
           _errorReporter
               .reportErrorForNode(FfiCode.EMPTY_STRUCT, node, [clazz.name]);
         }
@@ -777,9 +606,9 @@
     // TODO(brianwilkerson) Validate that `f` is a top-level function.
     final DartType R = (T as FunctionType).returnType;
     if ((FT as FunctionType).returnType.isVoid ||
-        _isPointer(R.element) ||
-        _isHandle(R.element) ||
-        _isStructClass(R)) {
+        R.isPointer ||
+        R.isHandle ||
+        R.isStructSubtype) {
       if (argCount != 1) {
         _errorReporter.reportErrorForNode(
             FfiCode.INVALID_EXCEPTION_VALUE, node.argumentList.arguments[1]);
@@ -826,7 +655,7 @@
   /// Validate that none of the [annotations] are from `dart:ffi`.
   void _validateNoAnnotations(NodeList<Annotation> annotations) {
     for (Annotation annotation in annotations) {
-      if (_isDartFfiElement(annotation.element)) {
+      if (annotation.element.ffiClass != null) {
         _errorReporter.reportErrorForNode(
             FfiCode.ANNOTATION_ON_POINTER_FIELD, annotation);
       }
@@ -886,7 +715,7 @@
     final ffiSizeAnnotations = annotations.where((annotation) {
       final element = annotation.element;
       return element is ConstructorElement &&
-          _isDartFfiElement(element) &&
+          element.ffiClass != null &&
           element.enclosingElement.name == 'CArraySize';
     }).toList();
 
@@ -922,3 +751,195 @@
   handle,
   none,
 }
+
+extension on Element? {
+  /// Return `true` if this represents the extension `AllocatorAlloc`.
+  bool get isAllocatorExtension {
+    final element = this;
+    return element is ExtensionElement &&
+        element.name == FfiVerifier._allocatorExtensionName &&
+        element.isFfiExtension;
+  }
+
+  bool get isNativeFunctionPointerExtension {
+    final element = this;
+    return element is ExtensionElement &&
+        element.name == 'NativeFunctionPointer' &&
+        element.isFfiExtension;
+  }
+
+  bool get isNativeStructCArrayExtension {
+    final element = this;
+    return element is ExtensionElement &&
+        element.name == 'StructCArray' &&
+        element.isFfiExtension;
+  }
+
+  bool get isNativeStructPointerExtension {
+    final element = this;
+    return element is ExtensionElement &&
+        element.name == 'StructPointer' &&
+        element.isFfiExtension;
+  }
+
+  /// Return `true` if this represents the extension `DynamicLibraryExtension`.
+  bool get isDynamicLibraryExtension {
+    final element = this;
+    return element is ExtensionElement &&
+        element.name == 'DynamicLibraryExtension' &&
+        element.isFfiExtension;
+  }
+
+  /// Return `true` if this represents the class `Pointer`.
+  bool get isPointer {
+    final element = this;
+    return element is ClassElement &&
+        element.name == 'Pointer' &&
+        element.isFfiClass;
+  }
+
+  /// If this is a class element from `dart:ffi`, return it.
+  ClassElement? get ffiClass {
+    var element = this;
+    if (element is ConstructorElement) {
+      element = element.enclosingElement;
+    }
+    if (element is ClassElement && element.isFfiClass) {
+      return element;
+    }
+    return null;
+  }
+}
+
+extension on ClassElement {
+  bool get isEmptyStruct {
+    for (final field in fields) {
+      final declaredType = field.type;
+      if (declaredType.isDartCoreInt) {
+        return false;
+      } else if (declaredType.isDartCoreDouble) {
+        return false;
+      } else if (declaredType.isPointer) {
+        return false;
+      } else if (declaredType.isStructSubtype) {
+        return false;
+      } else if (declaredType.isCArray) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  bool get isFfiClass {
+    return library.name == FfiVerifier._dartFfiLibraryName;
+  }
+}
+
+extension on ExtensionElement {
+  bool get isFfiExtension {
+    return library.name == FfiVerifier._dartFfiLibraryName;
+  }
+}
+
+extension on DartType {
+  /// Return `true` if this represents the class `CArray`.
+  bool get isCArray {
+    final self = this;
+    if (self is InterfaceType) {
+      final element = self.element;
+      return element.name == FfiVerifier._cArrayClassName && element.isFfiClass;
+    }
+    return false;
+  }
+
+  bool get isPointer {
+    final self = this;
+    return self is InterfaceType && self.element.isPointer;
+  }
+
+  bool get isHandle {
+    final self = this;
+    if (self is InterfaceType) {
+      final element = self.element;
+      return element.name == 'Handle' && element.isFfiClass;
+    }
+    return false;
+  }
+
+  /// Returns `true` iff this is a `ffi.NativeFunction<???>` type.
+  bool get isNativeFunction {
+    final self = this;
+    if (self is InterfaceType) {
+      final element = self.element;
+      return element.name == 'NativeFunction' && element.isFfiClass;
+    }
+    return false;
+  }
+
+  /// Returns `true` iff this is a `ffi.NativeType` type.
+  bool get isNativeType {
+    final self = this;
+    if (self is InterfaceType) {
+      final element = self.element;
+      return element.name == 'NativeType' && element.isFfiClass;
+    }
+    return false;
+  }
+
+  /// Returns `true` iff this is a opaque type, i.e. a subtype of `Opaque`.
+  bool get isOpaqueSubtype {
+    final self = this;
+    if (self is InterfaceType) {
+      final superType = self.element.supertype;
+      if (superType != null) {
+        final superClassElement = superType.element;
+        return superClassElement.name == FfiVerifier._opaqueClassName &&
+            superClassElement.isFfiClass;
+      }
+    }
+    return false;
+  }
+
+  bool get isStruct {
+    final self = this;
+    if (self is InterfaceType) {
+      final element = self.element;
+      return element.name == FfiVerifier._structClassName && element.isFfiClass;
+    }
+    return false;
+  }
+
+  /// Returns `true` if this is a struct type, i.e. a subtype of `Struct`.
+  bool get isStructSubtype {
+    final self = this;
+    if (self is InterfaceType) {
+      final superType = self.element.supertype;
+      if (superType != null) {
+        return superType.isStruct;
+      }
+    }
+    return false;
+  }
+}
+
+extension on TypeName {
+  /// If this is a name of class from `dart:ffi`, return it.
+  ClassElement? get ffiClass {
+    return name.staticElement.ffiClass;
+  }
+
+  /// Return `true` if this represents a subtype of `Struct`.
+  bool get isStructSubtype {
+    var element = name.staticElement;
+    if (element is ClassElement) {
+      bool isStruct(InterfaceType? type) {
+        return type != null && type.isStruct;
+      }
+
+      return isStruct(element.supertype) ||
+          element.interfaces.any(isStruct) ||
+          element.mixins.any(isStruct);
+    }
+    return false;
+  }
+}
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 9e441f9..b648902 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -1162,7 +1162,7 @@
       flowAnalysis!.topLevelDeclaration_enter(node, node.parameters, node.body);
       flowAnalysis!.executableDeclaration_enter(node, node.parameters, false);
     } else {
-      _promoteManager.enterFunctionBody(node.body!);
+      _promoteManager.enterFunctionBody(node.body);
     }
 
     var returnType = _enclosingFunction!.type.returnType;
@@ -1172,14 +1172,14 @@
 
     if (flowAnalysis != null) {
       if (node.factoryKeyword != null) {
-        var bodyContext = BodyInferenceContext.of(node.body!);
+        var bodyContext = BodyInferenceContext.of(node.body);
         checkForBodyMayCompleteNormally(
           returnType: bodyContext?.contextType,
-          body: node.body!,
+          body: node.body,
           errorNode: node,
         );
       }
-      flowAnalysis!.executableDeclaration_exit(node.body!, false);
+      flowAnalysis!.executableDeclaration_exit(node.body, false);
       flowAnalysis!.topLevelDeclaration_exit();
       nullSafetyDeadCodeVerifier.flowEnd(node);
     } else {
@@ -1406,7 +1406,7 @@
         isLocal,
       );
     } else {
-      _promoteManager.enterFunctionBody(node.functionExpression.body!);
+      _promoteManager.enterFunctionBody(node.functionExpression.body);
     }
 
     var functionType = _enclosingFunction!.type;
@@ -1417,15 +1417,15 @@
     if (flowAnalysis != null) {
       // TODO(scheglov) encapsulate
       var bodyContext = BodyInferenceContext.of(
-        node.functionExpression.body!,
+        node.functionExpression.body,
       );
       checkForBodyMayCompleteNormally(
         returnType: bodyContext?.contextType,
-        body: node.functionExpression.body!,
+        body: node.functionExpression.body,
         errorNode: node.name,
       );
       flowAnalysis!.executableDeclaration_exit(
-        node.functionExpression.body!,
+        node.functionExpression.body,
         isLocal,
       );
       if (isLocal) {
@@ -2607,7 +2607,7 @@
   }
 
   void visitConstructorDeclarationInScope(ConstructorDeclaration node) {
-    node.body?.accept(this);
+    node.body.accept(this);
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/lint/project.dart b/pkg/analyzer/lib/src/lint/project.dart
index 110bc63..759dddc 100644
--- a/pkg/analyzer/lib/src/lint/project.dart
+++ b/pkg/analyzer/lib/src/lint/project.dart
@@ -74,8 +74,9 @@
   bool isApi(Element element) => _apiModel.contains(element);
 
   String _calculateName() {
+    var pubspec = this.pubspec;
     if (pubspec != null) {
-      var nameEntry = pubspec!.name;
+      var nameEntry = pubspec.name;
       if (nameEntry != null) {
         return nameEntry.value.text!;
       }
diff --git a/pkg/analyzer/lib/src/summary/base.dart b/pkg/analyzer/lib/src/summary/base.dart
index a3106ed..c29a315 100644
--- a/pkg/analyzer/lib/src/summary/base.dart
+++ b/pkg/analyzer/lib/src/summary/base.dart
@@ -45,34 +45,3 @@
 
   const TopLevel([this.fileIdentifier]);
 }
-
-/// Annotation used in the summary IDL to indicate the field name that is used
-/// to distinguish variants, or logical views on the same physical layout of
-/// fields.
-class Variant {
-  final String fieldName;
-
-  const Variant(this.fieldName);
-}
-
-/// Annotation used in the summary IDL to indicate the id of a field that
-/// represents a logical field.  The set of ids used by a class must cover the
-/// contiguous range from 0 to N-1, where N is the number of fields.  All
-/// logical fields must have the same type, which will become the type of the
-/// actual field.
-///
-/// In order to preserve forwards and backwards compatibility, id numbers must
-/// be stable between releases.  So when new fields are added they should take
-/// the next available id without renumbering other fields.
-class VariantId {
-  /// The ID of the actual field.
-  final int value;
-
-  /// The value of the variant field in [Variant].
-  final Object? variant;
-
-  /// The list of variant values for which this field exists.
-  final List<Object>? variantList;
-
-  const VariantId(this.value, {this.variant, this.variantList});
-}
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
index ae7d510..cf03d4d 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
@@ -495,7 +495,7 @@
       ),
       initializers,
       redirectedConstructor,
-      null,
+      AstTestFactory.emptyFunctionBody(),
     ) as ConstructorDeclarationImpl;
 
     node.linkedContext = LinkedContext(
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
index 6e7a6d3..84007bd 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
@@ -860,8 +860,8 @@
     var body = node.body;
     _writeByte(
       AstBinaryFlags.encode(
-        isAsync: body?.isAsynchronous ?? false,
-        isGenerator: body?.isGenerator ?? false,
+        isAsync: body.isAsynchronous,
+        isGenerator: body.isGenerator,
       ),
     );
 
diff --git a/pkg/analyzer/lib/src/summary2/ast_text_printer.dart b/pkg/analyzer/lib/src/summary2/ast_text_printer.dart
index a5c3518..3c6f084 100644
--- a/pkg/analyzer/lib/src/summary2/ast_text_printer.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_text_printer.dart
@@ -212,9 +212,9 @@
     node.name?.accept(this);
     node.parameters.accept(this);
     _token(node.separator);
-    _nodeList(node.initializers, node.body!.beginToken);
+    _nodeList(node.initializers, node.body.beginToken);
     node.redirectedConstructor?.accept(this);
-    node.body!.accept(this);
+    node.body.accept(this);
   }
 
   @override
@@ -473,7 +473,7 @@
   void visitFunctionExpression(FunctionExpression node) {
     node.typeParameters?.accept(this);
     node.parameters?.accept(this);
-    node.body!.accept(this);
+    node.body.accept(this);
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
index 12d1a56..bde642f 100644
--- a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
+++ b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
@@ -501,7 +501,7 @@
     } else if (node is FunctionDeclaration) {
       return isAsynchronous(node.functionExpression);
     } else if (node is FunctionExpression) {
-      return node.body!.isAsynchronous;
+      return node.body.isAsynchronous;
     } else if (node is MethodDeclaration) {
       return node.body.isAsynchronous;
     } else {
@@ -580,7 +580,7 @@
     } else if (node is FunctionDeclaration) {
       return isGenerator(node.functionExpression);
     } else if (node is FunctionExpression) {
-      return node.body!.isGenerator;
+      return node.body.isGenerator;
     } else if (node is MethodDeclaration) {
       return node.body.isGenerator;
     } else {
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index a587c44..257f912 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -314,16 +314,18 @@
 
   @override
   void visitForPartsWithDeclarations(ForPartsWithDeclarations node) {
-    if (node.condition != null) {
-      checkBoolean(node.condition!);
+    var condition = node.condition;
+    if (condition != null) {
+      checkBoolean(condition);
     }
     node.visitChildren(this);
   }
 
   @override
   void visitForPartsWithExpression(ForPartsWithExpression node) {
-    if (node.condition != null) {
-      checkBoolean(node.condition!);
+    var condition = node.condition;
+    if (condition != null) {
+      checkBoolean(condition);
     }
     node.visitChildren(this);
   }
@@ -370,10 +372,11 @@
   @override
   void visitListLiteral(ListLiteral node) {
     DartType type = DynamicTypeImpl.instance;
-    if (node.typeArguments != null) {
-      NodeList<TypeAnnotation> targs = node.typeArguments!.arguments;
-      if (targs.isNotEmpty) {
-        type = targs[0].type!;
+    var typeArgumentList = node.typeArguments;
+    if (typeArgumentList != null) {
+      var typeArguments = typeArgumentList.arguments;
+      if (typeArguments.isNotEmpty) {
+        type = typeArguments[0].type!;
       }
     } else {
       DartType staticType = node.typeOrThrow;
@@ -437,11 +440,12 @@
 
   @override
   void visitSetOrMapLiteral(SetOrMapLiteral node) {
+    var typeArgumentsList = node.typeArguments;
     if (node.isMap) {
       DartType keyType = DynamicTypeImpl.instance;
       DartType valueType = DynamicTypeImpl.instance;
-      if (node.typeArguments != null) {
-        NodeList<TypeAnnotation> typeArguments = node.typeArguments!.arguments;
+      if (typeArgumentsList != null) {
+        NodeList<TypeAnnotation> typeArguments = typeArgumentsList.arguments;
         if (typeArguments.isNotEmpty) {
           keyType = typeArguments[0].type!;
         }
@@ -460,8 +464,8 @@
       }
     } else if (node.isSet) {
       DartType type = DynamicTypeImpl.instance;
-      if (node.typeArguments != null) {
-        NodeList<TypeAnnotation> typeArguments = node.typeArguments!.arguments;
+      if (typeArgumentsList != null) {
+        NodeList<TypeAnnotation> typeArguments = typeArgumentsList.arguments;
         if (typeArguments.isNotEmpty) {
           type = typeArguments[0].type!;
         }
@@ -502,13 +506,12 @@
   void visitVariableDeclaration(VariableDeclaration node) {
     var variableElement = node.declaredElement;
     var parent = node.parent;
-    if (variableElement != null &&
+    if (variableElement is PropertyInducingElement &&
         parent is VariableDeclarationList &&
-        parent.type == null &&
-        node.initializer != null) {
-      if (variableElement.kind == ElementKind.TOP_LEVEL_VARIABLE ||
-          variableElement.kind == ElementKind.FIELD) {
-        _validateTopLevelInitializer(variableElement.name!, node.initializer!);
+        parent.type == null) {
+      var initializer = node.initializer;
+      if (initializer != null) {
+        _validateTopLevelInitializer(variableElement.name, initializer);
       }
     }
     node.visitChildren(this);
@@ -890,14 +893,12 @@
       }
 
       var e = _getKnownElement(expr);
-      if (e is FunctionElement || e is MethodElement && e.isStatic) {
+      if (e is FunctionElement) {
+        _recordMessage(expr, CompileTimeErrorCode.INVALID_CAST_FUNCTION,
+            [e.name, from, to]);
+      } else if (e is MethodElement && e.isStatic) {
         _recordMessage(
-            expr,
-            e is MethodElement
-                ? CompileTimeErrorCode.INVALID_CAST_METHOD
-                : CompileTimeErrorCode.INVALID_CAST_FUNCTION,
-            [e!.name, from, to]);
-        return;
+            expr, CompileTimeErrorCode.INVALID_CAST_METHOD, [e.name, from, to]);
       }
     }
   }
diff --git a/pkg/analyzer/lib/src/test_utilities/find_element.dart b/pkg/analyzer/lib/src/test_utilities/find_element.dart
index b44613c..53cdcc4 100644
--- a/pkg/analyzer/lib/src/test_utilities/find_element.dart
+++ b/pkg/analyzer/lib/src/test_utilities/find_element.dart
@@ -19,7 +19,7 @@
     ExportElement? result;
 
     for (var export in unitElement.library.exports) {
-      var exportedUri = export.exportedLibrary!.source.uri.toString();
+      var exportedUri = export.exportedLibrary?.source.uri.toString();
       if (exportedUri == targetUri) {
         if (result != null) {
           throw StateError('Not unique: $targetUri');
@@ -51,7 +51,7 @@
     ImportElement? importElement;
 
     for (var import in unitElement.library.imports) {
-      var importedUri = import.importedLibrary!.source.uri.toString();
+      var importedUri = import.importedLibrary?.source.uri.toString();
       if (importedUri == targetUri) {
         if (importElement == null) {
           importElement = import;
diff --git a/pkg/analyzer/test/generated/expression_parser_test.dart b/pkg/analyzer/test/generated/expression_parser_test.dart
index 4dbc53b..14eaa8d 100644
--- a/pkg/analyzer/test/generated/expression_parser_test.dart
+++ b/pkg/analyzer/test/generated/expression_parser_test.dart
@@ -804,8 +804,8 @@
     Expression expression = parseExpression('() async {}');
     var functionExpression = expression as FunctionExpression;
     expect(functionExpression.body, isNotNull);
-    expect(functionExpression.body!.isAsynchronous, isTrue);
-    expect(functionExpression.body!.isGenerator, isFalse);
+    expect(functionExpression.body.isAsynchronous, isTrue);
+    expect(functionExpression.body.isGenerator, isFalse);
     expect(functionExpression.parameters, isNotNull);
   }
 
@@ -813,8 +813,8 @@
     Expression expression = parseExpression('() async* {}');
     var functionExpression = expression as FunctionExpression;
     expect(functionExpression.body, isNotNull);
-    expect(functionExpression.body!.isAsynchronous, isTrue);
-    expect(functionExpression.body!.isGenerator, isTrue);
+    expect(functionExpression.body.isAsynchronous, isTrue);
+    expect(functionExpression.body.isGenerator, isTrue);
     expect(functionExpression.parameters, isNotNull);
   }
 
@@ -822,8 +822,8 @@
     Expression expression = parseExpression('() {}');
     var functionExpression = expression as FunctionExpression;
     expect(functionExpression.body, isNotNull);
-    expect(functionExpression.body!.isAsynchronous, isFalse);
-    expect(functionExpression.body!.isGenerator, isFalse);
+    expect(functionExpression.body.isAsynchronous, isFalse);
+    expect(functionExpression.body.isGenerator, isFalse);
     expect(functionExpression.parameters, isNotNull);
   }
 
@@ -831,8 +831,8 @@
     Expression expression = parseExpression('() sync* {}');
     var functionExpression = expression as FunctionExpression;
     expect(functionExpression.body, isNotNull);
-    expect(functionExpression.body!.isAsynchronous, isFalse);
-    expect(functionExpression.body!.isGenerator, isTrue);
+    expect(functionExpression.body.isAsynchronous, isFalse);
+    expect(functionExpression.body.isGenerator, isTrue);
     expect(functionExpression.parameters, isNotNull);
   }
 
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
index 304b425..ded3bea 100644
--- a/pkg/analyzer/test/generated/strong_mode_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -171,7 +171,7 @@
 
     void check(String name, Asserter<InterfaceType> typeTest) {
       FunctionDeclaration test = AstFinder.getTopLevelFunction(unit, name);
-      var body = test.functionExpression.body as FunctionBody;
+      var body = test.functionExpression.body;
       Expression returnExp;
       if (body is ExpressionFunctionBody) {
         returnExp = body.expression;
@@ -538,7 +538,7 @@
       var stmt = statements[i] as VariableDeclarationStatement;
       VariableDeclaration decl = stmt.variables.variables[0];
       var exp = decl.initializer as FunctionExpression;
-      FunctionBody body = exp.body!;
+      FunctionBody body = exp.body;
       if (body is ExpressionFunctionBody) {
         return body.expression;
       } else {
@@ -791,7 +791,7 @@
       var stmt = statements[i] as VariableDeclarationStatement;
       VariableDeclaration decl = stmt.variables.variables[0];
       var exp = decl.initializer as FunctionExpression;
-      FunctionBody body = exp.body!;
+      FunctionBody body = exp.body;
       if (body is ExpressionFunctionBody) {
         return body.expression;
       } else {
diff --git a/pkg/analyzer/test/src/context/builder_test.dart b/pkg/analyzer/test/src/context/builder_test.dart
index 0483996..baefdb9 100644
--- a/pkg/analyzer/test/src/context/builder_test.dart
+++ b/pkg/analyzer/test/src/context/builder_test.dart
@@ -236,7 +236,7 @@
 ''');
 
     builderOptions.defaultPackageFilePath = packageFilePath;
-    Packages packages = builder.createPackageMap(projectPath);
+    Packages packages = _createPackageMap(projectPath);
     _assertPackages(
       packages,
       {
@@ -257,7 +257,7 @@
 bar:${toUriStr('/pkg/bar')}
 ''');
 
-    Packages packages = builder.createPackageMap(projectPath);
+    Packages packages = _createPackageMap(projectPath);
     _assertPackages(
       packages,
       {
@@ -278,7 +278,7 @@
 bar:${toUriStr('/pkg/bar')}
 ''');
 
-    Packages packages = builder.createPackageMap(projectPath);
+    Packages packages = _createPackageMap(projectPath);
     _assertPackages(
       packages,
       {
@@ -291,13 +291,13 @@
   void test_createPackageMap_none() {
     String rootPath = convertPath('/root');
     newFolder(rootPath);
-    Packages packages = builder.createPackageMap(rootPath);
+    Packages packages = _createPackageMap(rootPath);
     expect(packages.packages, isEmpty);
   }
 
   void test_createPackageMap_rootDoesNotExist() {
     String rootPath = convertPath('/root');
-    Packages packages = builder.createPackageMap(rootPath);
+    Packages packages = _createPackageMap(rootPath);
     expect(packages.packages, isEmpty);
   }
 
@@ -396,39 +396,34 @@
     newFile('/workspace/.packages');
     newFolder('/workspace/.dart_tool/build/generated/project/lib');
     newFile('/workspace/pubspec.yaml', content: 'name: project');
-    Workspace workspace = ContextBuilder.createWorkspace(resourceProvider,
-        convertPath('/workspace/project/lib/lib.dart'), builder);
+    Workspace workspace = _createWorkspace('/workspace/project/lib/lib.dart');
     expect(workspace, TypeMatcher<PackageBuildWorkspace>());
   }
 
   void test_createWorkspace_hasPackagesFile_hasPubspec() {
     newFile('/workspace/.packages');
     newFile('/workspace/pubspec.yaml', content: 'name: project');
-    Workspace workspace = ContextBuilder.createWorkspace(resourceProvider,
-        convertPath('/workspace/project/lib/lib.dart'), builder);
+    Workspace workspace = _createWorkspace('/workspace/project/lib/lib.dart');
     expect(workspace, TypeMatcher<PubWorkspace>());
   }
 
   void test_createWorkspace_hasPackagesFile_noMarkerFiles() {
     newFile('/workspace/.packages');
-    Workspace workspace = ContextBuilder.createWorkspace(resourceProvider,
-        convertPath('/workspace/project/lib/lib.dart'), builder);
+    Workspace workspace = _createWorkspace('/workspace/project/lib/lib.dart');
     expect(workspace, TypeMatcher<BasicWorkspace>());
   }
 
   void test_createWorkspace_noPackagesFile_hasBazelMarkerFiles() {
     newFile('/workspace/WORKSPACE');
     newFolder('/workspace/bazel-genfiles');
-    Workspace workspace = ContextBuilder.createWorkspace(resourceProvider,
-        convertPath('/workspace/project/lib/lib.dart'), builder);
+    Workspace workspace = _createWorkspace('/workspace/project/lib/lib.dart');
     expect(workspace, TypeMatcher<BazelWorkspace>());
   }
 
   void test_createWorkspace_noPackagesFile_hasDartToolAndPubspec() {
     newFolder('/workspace/.dart_tool/build/generated/project/lib');
     newFile('/workspace/pubspec.yaml', content: 'name: project');
-    Workspace workspace = ContextBuilder.createWorkspace(resourceProvider,
-        convertPath('/workspace/project/lib/lib.dart'), builder);
+    Workspace workspace = _createWorkspace('/workspace/project/lib/lib.dart');
     expect(workspace, TypeMatcher<PackageBuildWorkspace>());
   }
 
@@ -440,21 +435,18 @@
   "configVersion": 2,
   "packages": []
 }''');
-    Workspace workspace = ContextBuilder.createWorkspace(resourceProvider,
-        convertPath('/workspace/project/lib/lib.dart'), builder);
+    Workspace workspace = _createWorkspace('/workspace/project/lib/lib.dart');
     expect(workspace, TypeMatcher<GnWorkspace>());
   }
 
   void test_createWorkspace_noPackagesFile_hasPubspec() {
     newFile('/workspace/pubspec.yaml', content: 'name: project');
-    Workspace workspace = ContextBuilder.createWorkspace(resourceProvider,
-        convertPath('/workspace/project/lib/lib.dart'), builder);
+    Workspace workspace = _createWorkspace('/workspace/project/lib/lib.dart');
     expect(workspace, TypeMatcher<PubWorkspace>());
   }
 
   void test_createWorkspace_noPackagesFile_noMarkerFiles() {
-    Workspace workspace = ContextBuilder.createWorkspace(resourceProvider,
-        convertPath('/workspace/project/lib/lib.dart'), builder);
+    Workspace workspace = _createWorkspace('/workspace/project/lib/lib.dart');
     expect(workspace, TypeMatcher<BasicWorkspace>());
   }
 
@@ -741,6 +733,22 @@
     }
   }
 
+  Packages _createPackageMap(String rootPath) {
+    return ContextBuilder.createPackageMap(
+      resourceProvider: resourceProvider,
+      options: builderOptions,
+      rootPath: rootPath,
+    );
+  }
+
+  Workspace _createWorkspace(String posixPath) {
+    return ContextBuilder.createWorkspace(
+      resourceProvider: resourceProvider,
+      options: ContextBuilderOptions(),
+      rootPath: convertPath(posixPath),
+    );
+  }
+
   _defineMockLintRules() {
     _mockLintRule = _MockLintRule('mock_lint_rule');
     Registry.ruleRegistry.register(_mockLintRule);
diff --git a/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart b/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
index cf43a2a..b580419 100644
--- a/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
+++ b/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
@@ -34,11 +34,12 @@
     var contextUnit = LinterContextUnit(result.content!, result.unit!);
 
     final libraryPath = result.libraryElement.source.fullName;
-    final builder = ContextBuilder(
-        resourceProvider, null /* sdkManager */, null /* contentCache */);
     // todo (pq): get workspace from analysis context
-    final workspace =
-        ContextBuilder.createWorkspace(resourceProvider, libraryPath, builder);
+    final workspace = ContextBuilder.createWorkspace(
+      resourceProvider: resourceProvider,
+      options: ContextBuilderOptions(),
+      rootPath: libraryPath,
+    );
     final workspacePackage = workspace.findPackageFor(libraryPath);
 
     context = LinterContextImpl(
diff --git a/pkg/analyzer/tool/summary/generate.dart b/pkg/analyzer/tool/summary/generate.dart
index 2c495ae..a4b1c37 100644
--- a/pkg/analyzer/tool/summary/generate.dart
+++ b/pkg/analyzer/tool/summary/generate.dart
@@ -173,32 +173,9 @@
     return json.encode(s);
   }
 
-  List<String> _computeVariants(idl_model.ClassDeclaration cls) {
-    var allVariants = <String>{};
-    for (var field in cls.fields) {
-      var logicalFields = field.logicalProperties?.values;
-      if (logicalFields != null) {
-        for (var logicalField in logicalFields) {
-          allVariants.addAll(logicalField.variants);
-        }
-      }
-    }
-    return allVariants.toList()..sort();
-  }
-
   bool _isNullable(idl_model.FieldType type) {
     return !type.isList && _idl.classes.containsKey(type.typeName);
   }
-
-  String _variantAssertStatement(
-    idl_model.ClassDeclaration class_,
-    idl_model.LogicalProperty property,
-  ) {
-    var assertCondition = property.variants
-        .map((key) => '${class_.variantField} == idl.$key')
-        .join(' || ');
-    return 'assert($assertCondition);';
-  }
 }
 
 class _BuilderGenerator extends _BaseGenerator {
@@ -263,41 +240,8 @@
       List<idl_model.FieldDeclaration> sortedFields = cls.fields.toList()
         ..sort((idl_model.FieldDeclaration a, idl_model.FieldDeclaration b) =>
             a.id.compareTo(b.id));
-      if (cls.variantField != null) {
-        var firstVariant = true;
-        for (var variant in _computeVariants(cls)) {
-          if (firstVariant) {
-            firstVariant = false;
-          } else {
-            out('else');
-          }
-          out('if (${cls.variantField} == idl.$variant) {');
-          indent(() {
-            for (var field in sortedFields) {
-              var logicalProperties = field.logicalProperties;
-              if (logicalProperties != null) {
-                for (var logicalEntry in logicalProperties.entries) {
-                  var logicalName = logicalEntry.key;
-                  var logicalProperty = logicalEntry.value;
-                  if (logicalProperty.variants.contains(variant)) {
-                    writeField(
-                      logicalName,
-                      field.type,
-                      logicalProperty.isInformative,
-                    );
-                  }
-                }
-              } else {
-                writeField(field.name, field.type, field.isInformative);
-              }
-            }
-          });
-          out('}');
-        }
-      } else {
-        for (idl_model.FieldDeclaration field in sortedFields) {
-          writeField('_${field.name}', field.type, field.isInformative);
-        }
+      for (idl_model.FieldDeclaration field in sortedFields) {
+        writeField('_${field.name}', field.type, field.isInformative);
       }
     });
     out('}');
@@ -305,55 +249,13 @@
 
   void _generateConstructors() {
     out();
-    if (cls.variantField != null) {
-      for (var variant in _computeVariants(cls)) {
-        var constructorName = variant.split('.')[1];
-        out('$builderName.$constructorName({');
-
-        for (var field in cls.fields) {
-          var logicalProperties = field.logicalProperties;
-          if (logicalProperties != null) {
-            for (var logicalEntry in logicalProperties.entries) {
-              var logicalName = logicalEntry.key;
-              var logicalProperty = logicalEntry.value;
-              if (logicalProperty.variants.contains(variant)) {
-                out('${encodedType2(field.type)} $logicalName,');
-              }
-            }
-          }
-        }
-
-        out('}) : ');
-
-        out('_${cls.variantField} = idl.$variant');
-
-        var separator = ',';
-        for (var field in cls.fields) {
-          var logicalProperties = field.logicalProperties;
-          if (logicalProperties != null) {
-            for (var logicalEntry in logicalProperties.entries) {
-              var logicalName = logicalEntry.key;
-              var logicalProperty = logicalEntry.value;
-              if (logicalProperty.variants.contains(variant)) {
-                out('$separator _${field.name} = $logicalName');
-                separator = ', ';
-              }
-            }
-          }
-        }
-
-        out(';');
-        out();
-      }
-    } else {
-      out('$builderName({${constructorParams.join(', ')}})');
-      List<idl_model.FieldDeclaration> fields = cls.fields.toList();
-      for (int i = 0; i < fields.length; i++) {
-        idl_model.FieldDeclaration field = fields[i];
-        String prefix = i == 0 ? '  : ' : '    ';
-        String suffix = i == fields.length - 1 ? ';' : ',';
-        out('${prefix}_${field.name} = ${field.name}$suffix');
-      }
+    out('$builderName({${constructorParams.join(', ')}})');
+    List<idl_model.FieldDeclaration> fields = cls.fields.toList();
+    for (int i = 0; i < fields.length; i++) {
+      idl_model.FieldDeclaration field = fields[i];
+      String prefix = i == 0 ? '  : ' : '    ';
+      String suffix = i == fields.length - 1 ? ';' : ',';
+      out('${prefix}_${field.name} = ${field.name}$suffix');
     }
   }
 
@@ -483,41 +385,8 @@
     }
 
     indent(() {
-      if (cls.variantField != null) {
-        var firstVariant = true;
-        for (var variant in _computeVariants(cls)) {
-          if (firstVariant) {
-            firstVariant = false;
-          } else {
-            out('else');
-          }
-          out('if (${cls.variantField} == idl.$variant) {');
-          indent(() {
-            for (var field in cls.fields) {
-              var logicalProperties = field.logicalProperties;
-              if (logicalProperties != null) {
-                for (var logicalEntry in logicalProperties.entries) {
-                  var logicalName = logicalEntry.key;
-                  var logicalProperty = logicalEntry.value;
-                  if (logicalProperty.variants.contains(variant)) {
-                    writeField(
-                      logicalName,
-                      field.type,
-                      logicalProperty.isInformative,
-                    );
-                  }
-                }
-              } else {
-                writeField(field.name, field.type, field.isInformative);
-              }
-            }
-          });
-          out('}');
-        }
-      } else {
-        for (idl_model.FieldDeclaration field in cls.fields) {
-          writeField('_${field.name}', field.type, field.isInformative);
-        }
+      for (idl_model.FieldDeclaration field in cls.fields) {
+        writeField('_${field.name}', field.type, field.isInformative);
       }
     });
     out('}');
@@ -535,53 +404,22 @@
         out('@override');
         out('Null get $fieldName => ${_BaseGenerator._throwDeprecated};');
       } else {
-        var logicalProperties = field.logicalProperties;
-        if (logicalProperties != null) {
-          for (var logicalEntry in logicalProperties.entries) {
-            var logicalName = logicalEntry.key;
-            var logicalProperty = logicalEntry.value;
-            out('@override');
-            out('$typeStr get $logicalName {');
-            indent(() {
-              out(_variantAssertStatement(cls, logicalProperty));
-              out('return _${field.name}$defSuffix;');
-            });
-            out('}');
-            out();
-          }
-        } else {
-          out('@override');
-          var nn = _isNullable(field.type) ? '?' : '';
-          out('$typeStr$nn get $fieldName => _$fieldName$defSuffix;');
-        }
+        var nn = _isNullable(field.type) ? '?' : '';
+
+        out('@override');
+        out('$typeStr$nn get $fieldName => _$fieldName$defSuffix;');
         out();
 
         constructorParams.add('$typeStr? $fieldName');
 
         outDoc(field.documentation);
 
-        if (logicalProperties != null) {
-          for (var logicalEntry in logicalProperties.entries) {
-            var logicalName = logicalEntry.key;
-            var logicalProperty = logicalEntry.value;
-            out('set $logicalName($typeStr value) {');
-            indent(() {
-              out(_variantAssertStatement(cls, logicalProperty));
-              _generateNonNegativeInt(fieldType);
-              out('_variantField_${field.id} = value;');
-            });
-            out('}');
-            out();
-          }
-        } else {
-          var nn = _isNullable(field.type) ? '?' : '';
-          out('set $fieldName($typeStr$nn value) {');
-          indent(() {
-            _generateNonNegativeInt(fieldType);
-            out('this._$fieldName = value;');
-          });
-          out('}');
-        }
+        out('set $fieldName($typeStr$nn value) {');
+        indent(() {
+          _generateNonNegativeInt(fieldType);
+          out('this._$fieldName = value;');
+        });
+        out('}');
       }
     }
   }
@@ -743,7 +581,6 @@
         bool isDeprecated = false;
         String? fileIdentifier;
         String clsName = decl.name;
-        String? variantField;
         for (Annotation annotation in decl.metadata) {
           var arguments = annotation.arguments;
           if (arguments != null &&
@@ -767,23 +604,6 @@
               annotation.name == 'deprecated' &&
               annotation.constructorName == null) {
             isDeprecated = true;
-          } else if (arguments != null &&
-              annotation.name == 'Variant' &&
-              annotation.constructorName == null) {
-            if (arguments.length == 1) {
-              Expression arg = arguments[0];
-              if (arg is StringLiteral) {
-                variantField = arg.stringValue;
-              } else {
-                throw Exception(
-                  'Class `$clsName`: @Variant argument must be a string literal',
-                );
-              }
-            } else if (arguments.isNotEmpty) {
-              throw Exception(
-                'Class `$clsName`: @Variant requires 1 argument',
-              );
-            }
           }
         }
         idl_model.ClassDeclaration cls = idl_model.ClassDeclaration(
@@ -792,7 +612,6 @@
           isTopLevel: isTopLevel,
           fileIdentifier: fileIdentifier,
           isDeprecated: isDeprecated,
-          variantField: variantField,
         );
         _idl.classes[clsName] = cls;
         String expectedBase = 'base.SummaryClass';
@@ -912,7 +731,6 @@
     }
 
     int? id;
-    List<String>? variants;
     bool isDeprecated = false;
     bool isInformative = false;
 
@@ -944,51 +762,6 @@
         isDeprecated = true;
       } else if (annotation.name == 'informative') {
         isInformative = true;
-      } else if (annotation.name == 'VariantId') {
-        if (id != null) {
-          throw Exception('Cannot specify both @Id and @VariantId ($getter)');
-        }
-        if (variants != null) {
-          throw Exception('Duplicate @VariantId annotation ($getter)');
-        }
-
-        if (arguments == null) {
-          throw Exception('@VariantId must be given arguments ($desc)');
-        }
-        if (arguments.length != 2) {
-          throw Exception(
-            '@VariantId must be given exactly two arguments ($desc)',
-          );
-        }
-
-        var idExpression = arguments[0];
-        if (idExpression is IntegerLiteral) {
-          id = idExpression.value;
-        } else {
-          throw Exception(
-            '@VariantId argument must be an integer literal ($desc)',
-          );
-        }
-
-        var variantExpression = arguments[1];
-        if (variantExpression is NamedExpression) {
-          if (variantExpression.name == 'variant') {
-            variants = [variantExpression.expression.toCode()];
-          } else if (variantExpression.name == 'variantList') {
-            variants = (variantExpression.expression as ListLiteral)
-                .elements
-                .map((e) => e.toCode())
-                .toList();
-          } else {
-            throw Exception(
-              'Only "key" or "keyList" expected in @VariantId ($desc)',
-            );
-          }
-        } else {
-          throw Exception(
-            'The second argument of @VariantId must be named ($desc)',
-          );
-        }
       }
     }
     if (id == null) {
@@ -997,67 +770,14 @@
 
     var fieldType = idl_model.FieldType(type.name, isList);
 
-    String name = getter.name;
-    Map<String, idl_model.LogicalProperty>? logicalProperties;
-    if (variants != null) {
-      var fieldsWithSameId =
-          cls.allFields.where((field) => field.id == id).toList();
-      if (fieldsWithSameId.isNotEmpty) {
-        var existingField = fieldsWithSameId.single;
-        var logicalProperties = existingField.logicalProperties;
-        if (logicalProperties == null) {
-          throw Exception('$desc: id $id is already used as a non-variant '
-              'field: ${existingField.name}');
-        }
-
-        for (var variant in variants) {
-          for (var entry in logicalProperties.entries) {
-            if (entry.value.variants.contains(variant)) {
-              var logicalName = entry.key;
-              throw Exception('$desc: id $id is already used for $logicalName');
-            }
-          }
-        }
-
-        if (existingField.type != fieldType) {
-          throw Exception(
-            '$desc: id $id is already used with type ${existingField.type}',
-          );
-        }
-
-        if (logicalProperties[getter.name] != null) {
-          throw Exception(
-            '$desc: logical property ${getter.name} is already used',
-          );
-        }
-
-        logicalProperties[getter.name] = idl_model.LogicalProperty(
-          isDeprecated: isDeprecated,
-          isInformative: isInformative,
-          variants: variants,
-        );
-        return;
-      } else {
-        name = 'variantField_$id';
-        logicalProperties = <String, idl_model.LogicalProperty>{
-          getter.name: idl_model.LogicalProperty(
-            isDeprecated: isDeprecated,
-            isInformative: isInformative,
-            variants: variants,
-          ),
-        };
-      }
-    }
-
     cls.allFields.add(
       idl_model.FieldDeclaration(
         documentation: _getNodeDoc(getter),
-        name: name,
+        name: getter.name,
         type: fieldType,
         id: id,
         isDeprecated: isDeprecated,
         isInformative: isInformative,
-        logicalProperties: logicalProperties,
       ),
     );
   }
@@ -1281,40 +1001,22 @@
           out('@override');
           out('Null get $fieldName => ${_BaseGenerator._throwDeprecated};');
         } else {
-          var logicalProperties = field.logicalProperties;
-          if (logicalProperties != null) {
-            for (var logicalEntry in logicalProperties.entries) {
-              var logicalName = logicalEntry.key;
-              var logicalProperty = logicalEntry.value;
-              out('@override');
-              out('$returnType get $logicalName {');
-              indent(() {
-                out(_variantAssertStatement(cls, logicalProperty));
-                String readExpr =
-                    '$readCode.vTableGet(_bc, _bcOffset, $index, $def)';
-                out('return _$fieldName ??= $readExpr;');
-              });
-              out('}');
-              out();
-            }
+          out('@override');
+          if (_isNullable(type)) {
+            out('$returnType? get $fieldName {');
           } else {
-            out('@override');
-            if (_isNullable(type)) {
-              out('$returnType? get $fieldName {');
-            } else {
-              out('$returnType get $fieldName {');
-            }
-            indent(() {
-              String readExpr;
-              if (_isNullable(type)) {
-                readExpr = '$readCode.vTableGetOrNull(_bc, _bcOffset, $index)';
-              } else {
-                readExpr = '$readCode.vTableGet(_bc, _bcOffset, $index, $def)';
-              }
-              out('return _$fieldName ??= $readExpr;');
-            });
-            out('}');
+            out('$returnType get $fieldName {');
           }
+          indent(() {
+            String readExpr;
+            if (_isNullable(type)) {
+              readExpr = '$readCode.vTableGetOrNull(_bc, _bcOffset, $index)';
+            } else {
+              readExpr = '$readCode.vTableGet(_bc, _bcOffset, $index, $def)';
+            }
+            out('return _$fieldName ??= $readExpr;');
+          });
+          out('}');
         }
       }
     });
@@ -1389,52 +1091,15 @@
       indent(() {
         out('Map<String, Object> _result = <String, Object>{};');
 
-        if (cls.variantField != null) {
-          indent(() {
-            for (idl_model.FieldDeclaration field in cls.fields) {
-              if (field.logicalProperties == null) {
-                var localName = 'local_${field.name}';
-                out('var $localName = ${field.name};');
-                var condition = jsonCondition(field.type, localName);
-                var storeField = jsonStore(field.type, field.name, localName);
-                writeConditionalStatement(condition, storeField);
-              }
-            }
-            for (var variant in _computeVariants(cls)) {
-              out('if (${cls.variantField} == idl.$variant) {');
-              indent(() {
-                for (idl_model.FieldDeclaration field in cls.fields) {
-                  var logicalProperties = field.logicalProperties;
-                  if (logicalProperties != null) {
-                    for (var logicalEntry in logicalProperties.entries) {
-                      var logicalName = logicalEntry.key;
-                      var logicalProperty = logicalEntry.value;
-                      if (logicalProperty.variants.contains(variant)) {
-                        var localName = 'local_${field.name}';
-                        out('var $localName = ${field.name};');
-                        var condition = jsonCondition(field.type, localName);
-                        var storeField =
-                            jsonStore(field.type, logicalName, localName);
-                        writeConditionalStatement(condition, storeField);
-                      }
-                    }
-                  }
-                }
-              });
-              out('}');
-            }
-          });
-        } else {
-          indent(() {
-            for (idl_model.FieldDeclaration field in cls.fields) {
-              var localName = 'local_${field.name}';
-              out('var $localName = ${field.name};');
-              String condition = jsonCondition(field.type, localName);
-              String storeField = jsonStore(field.type, field.name, localName);
-              writeConditionalStatement(condition, storeField);
-            }
-          });
-        }
+        indent(() {
+          for (idl_model.FieldDeclaration field in cls.fields) {
+            var localName = 'local_${field.name}';
+            out('var $localName = ${field.name};');
+            String condition = jsonCondition(field.type, localName);
+            String storeField = jsonStore(field.type, field.name, localName);
+            writeConditionalStatement(condition, storeField);
+          }
+        });
 
         out('return _result;');
       });
@@ -1443,43 +1108,14 @@
 
       // Write toMap().
       out('@override');
-      if (cls.variantField != null) {
-        out('Map<String, Object> toMap() {');
-        for (var variant in _computeVariants(cls)) {
-          out('if (${cls.variantField} == idl.$variant) {');
-          indent(() {
-            out('return {');
-            for (idl_model.FieldDeclaration field in cls.fields) {
-              var logicalProperties = field.logicalProperties;
-              if (logicalProperties != null) {
-                for (var logicalEntry in logicalProperties.entries) {
-                  var logicalName = logicalEntry.key;
-                  var logicalProperty = logicalEntry.value;
-                  if (logicalProperty.variants.contains(variant)) {
-                    out('${quoted(logicalName)}: $logicalName,');
-                  }
-                }
-              } else {
-                String fieldName = field.name;
-                out('${quoted(fieldName)}: $fieldName,');
-              }
-            }
-            out('};');
-          });
-          out('}');
+      out('Map<String, Object?> toMap() => {');
+      indent(() {
+        for (idl_model.FieldDeclaration field in cls.fields) {
+          String fieldName = field.name;
+          out('${quoted(fieldName)}: $fieldName,');
         }
-        out('throw StateError("Unexpected \$${cls.variantField}");');
-        out('}');
-      } else {
-        out('Map<String, Object?> toMap() => {');
-        indent(() {
-          for (idl_model.FieldDeclaration field in cls.fields) {
-            String fieldName = field.name;
-            out('${quoted(fieldName)}: $fieldName,');
-          }
-        });
-        out('};');
-      }
+      });
+      out('};');
       out();
       // Write toString().
       out('@override');
diff --git a/pkg/analyzer/tool/summary/idl_model.dart b/pkg/analyzer/tool/summary/idl_model.dart
index 0b78425..6da5456 100644
--- a/pkg/analyzer/tool/summary/idl_model.dart
+++ b/pkg/analyzer/tool/summary/idl_model.dart
@@ -21,15 +21,12 @@
   /// Indicates whether the class has the `deprecated` annotation.
   final bool isDeprecated;
 
-  final String? variantField;
-
   ClassDeclaration({
     required String? documentation,
     required this.fileIdentifier,
     required String name,
     required this.isDeprecated,
     required this.isTopLevel,
-    required this.variantField,
   }) : super(documentation, name);
 
   /// Get the non-deprecated fields defined in the class.
@@ -77,9 +74,6 @@
   /// Indicates whether the field is informative.
   final bool isInformative;
 
-  /// Maps logical property names to logical property.
-  final Map<String, LogicalProperty>? logicalProperties;
-
   FieldDeclaration({
     required String? documentation,
     required String name,
@@ -87,7 +81,6 @@
     required this.id,
     required this.isDeprecated,
     required this.isInformative,
-    required this.logicalProperties,
   }) : super(documentation, name);
 }
 
@@ -129,21 +122,3 @@
   /// Enums defined in the IDL.
   final Map<String, EnumDeclaration> enums = <String, EnumDeclaration>{};
 }
-
-/// Information about a logical property mapped to a single data fields.
-class LogicalProperty {
-  /// Indicates whether the property is deprecated.
-  final bool isDeprecated;
-
-  /// Indicates whether the property is informative.
-  final bool isInformative;
-
-  /// Names of variants in which this property is available.
-  final List<String> variants;
-
-  LogicalProperty({
-    required this.isDeprecated,
-    required this.isInformative,
-    required this.variants,
-  });
-}
diff --git a/pkg/dartdev/test/analytics_test.dart b/pkg/dartdev/test/analytics_test.dart
index 8c74972..6158b0d 100644
--- a/pkg/dartdev/test/analytics_test.dart
+++ b/pkg/dartdev/test/analytics_test.dart
@@ -20,6 +20,33 @@
 void main() {
   group('DisabledAnalytics', disabledAnalyticsObject);
 
+  test('Analytics control smoke test', () {
+    final p = project(logAnalytics: true);
+    var result = p.runSync(['--disable-analytics']);
+    expect(result.stdout, contains('''
+  ╔════════════════════════════════════════════════════════════════════════════╗
+  ║ Anonymous analytics reporting disabled. In order to enable it, run:        ║
+  ║                                                                            ║
+  ║   dart --enable-analytics                                                  ║
+  ║                                                                            ║
+  ╚════════════════════════════════════════════════════════════════════════════╝
+'''));
+
+    result = p.runSync(['--enable-analytics']);
+    expect(result.stdout, contains('''
+  ╔════════════════════════════════════════════════════════════════════════════╗
+  ║ The Dart tool uses Google Analytics to anonymously report feature usage    ║
+  ║ statistics and to send basic crash reports. This data is used to help      ║
+  ║ improve the Dart platform and tools over time.                             ║
+  ║                                                                            ║
+  ║ To disable reporting of anonymous analytics, run:                          ║
+  ║                                                                            ║
+  ║   dart --disable-analytics                                                 ║
+  ║                                                                            ║
+  ╚════════════════════════════════════════════════════════════════════════════╝
+'''));
+  });
+
   group('Sending analytics', () {
     test('help', () {
       final p = project(logAnalytics: true);
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart
index a424674..b198669 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart
@@ -20,7 +20,7 @@
 
   Pointer<Coordinate> next;
 
-  factory Coordinate.allocate( 
+  factory Coordinate.allocate(
       Allocator allocator, double x, double y, Pointer<Coordinate> next) {
     return allocator<Coordinate>().ref
       ..x = x
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.transformed.expect b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.transformed.expect
index 94630fc..8c4ed96 100644
--- a/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/ffi_sample.dart.weak.transformed.expect
@@ -12,10 +12,10 @@
 import "package:ffi/ffi.dart";
 
 @#C3
-@#C8
+@#C9
 class Coordinate extends ffi::Struct {
   @#C3
-  static final field core::int* #sizeOf = (#C11).{core::List::[]}(ffi::_abi());
+  static final field core::int* #sizeOf = (#C12).{core::List::[]}(ffi::_abi());
   @#C3
   constructor #fromTypedDataBase(dynamic #pointer) → dynamic
     : super ffi::Struct::_fromPointer(#pointer)
@@ -39,17 +39,17 @@
   abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
   get x() → core::double*
-    return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C13).{core::List::[]}(ffi::_abi()));
+    return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C14).{core::List::[]}(ffi::_abi()));
   set x(core::double* #v) → void
-    return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C13).{core::List::[]}(ffi::_abi()), #v);
+    return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C14).{core::List::[]}(ffi::_abi()), #v);
   get y() → core::double*
-    return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C15).{core::List::[]}(ffi::_abi()));
+    return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C16).{core::List::[]}(ffi::_abi()));
   set y(core::double* #v) → void
-    return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C15).{core::List::[]}(ffi::_abi()), #v);
+    return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C16).{core::List::[]}(ffi::_abi()), #v);
   get next() → ffi::Pointer<self::Coordinate*>*
-    return ffi::_fromAddress<self::Coordinate*>(ffi::_loadIntPtr(this.{ffi::Struct::_addressOf}, (#C17).{core::List::[]}(ffi::_abi())));
+    return ffi::_fromAddress<self::Coordinate*>(ffi::_loadIntPtr(this.{ffi::Struct::_addressOf}, (#C18).{core::List::[]}(ffi::_abi())));
   set next(ffi::Pointer<self::Coordinate*>* #v) → void
-    return ffi::_storeIntPtr(this.{ffi::Struct::_addressOf}, (#C17).{core::List::[]}(ffi::_abi()), #v.{ffi::Pointer::address});
+    return ffi::_storeIntPtr(this.{ffi::Struct::_addressOf}, (#C18).{core::List::[]}(ffi::_abi()), #v.{ffi::Pointer::address});
 }
 static method main() → dynamic {}
 
@@ -61,16 +61,17 @@
   #C5 = TypeLiteralConstant(ffi::Double)
   #C6 = TypeLiteralConstant(ffi::Pointer<ffi::NativeType>)
   #C7 = <core::Type>[#C5, #C5, #C6]
-  #C8 = core::pragma {name:#C4, options:#C7}
-  #C9 = 24
-  #C10 = 20
-  #C11 = <core::int*>[#C9, #C10, #C9]
-  #C12 = 0
-  #C13 = <core::int*>[#C12, #C12, #C12]
-  #C14 = 8
-  #C15 = <core::int*>[#C14, #C14, #C14]
-  #C16 = 16
-  #C17 = <core::int*>[#C16, #C16, #C16]
+  #C8 = ffi::_FfiStructLayout {fieldTypes:#C7}
+  #C9 = core::pragma {name:#C4, options:#C8}
+  #C10 = 24
+  #C11 = 20
+  #C12 = <core::int*>[#C10, #C11, #C10]
+  #C13 = 0
+  #C14 = <core::int*>[#C13, #C13, #C13]
+  #C15 = 8
+  #C16 = <core::int*>[#C15, #C15, #C15]
+  #C17 = 16
+  #C18 = <core::int*>[#C17, #C17, #C17]
 }
 
 
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_01.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_01.yaml.world.1.expect
index f93c1a3..08f11e7 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_01.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_01.yaml.world.1.expect
@@ -4,10 +4,10 @@
   import "dart:ffi";
 
   @#C3
-  @#C8
+  @#C9
   class Coordinate extends dart.ffi::Struct {
     @#C3
-    static final field dart.core::int* #sizeOf = (#C11).{dart.core::List::[]}(dart.ffi::_abi());
+    static final field dart.core::int* #sizeOf = (#C12).{dart.core::List::[]}(dart.ffi::_abi());
     @#C3
     constructor #fromTypedDataBase(dynamic #pointer) → dynamic
       : super dart.ffi::Struct::_fromPointer(#pointer)
@@ -27,17 +27,17 @@
     abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
     abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
     get x() → dart.core::double*
-      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()));
+      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()));
     set x(dart.core::double* #v) → void
-      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()), #v);
     get y() → dart.core::double*
-      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()));
+      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()));
     set y(dart.core::double* #v) → void
-      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()), #v);
     get next() → dart.ffi::Pointer<lib::Coordinate*>*
-      return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi())));
+      return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi())));
     set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
-      return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
+      return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
   }
 }
 library from "org-dartlang-test:///main.dart" as main {
@@ -59,14 +59,15 @@
   #C5 = TypeLiteralConstant(dart.ffi::Double)
   #C6 = TypeLiteralConstant(dart.ffi::Pointer<dart.ffi::NativeType>)
   #C7 = <dart.core::Type>[#C5, #C5, #C6]
-  #C8 = dart.core::pragma {name:#C4, options:#C7}
-  #C9 = 24
-  #C10 = 20
-  #C11 = <dart.core::int*>[#C9, #C10, #C9]
-  #C12 = 0
-  #C13 = <dart.core::int*>[#C12, #C12, #C12]
-  #C14 = 8
-  #C15 = <dart.core::int*>[#C14, #C14, #C14]
-  #C16 = 16
-  #C17 = <dart.core::int*>[#C16, #C16, #C16]
+  #C8 = dart.ffi::_FfiStructLayout {fieldTypes:#C7}
+  #C9 = dart.core::pragma {name:#C4, options:#C8}
+  #C10 = 24
+  #C11 = 20
+  #C12 = <dart.core::int*>[#C10, #C11, #C10]
+  #C13 = 0
+  #C14 = <dart.core::int*>[#C13, #C13, #C13]
+  #C15 = 8
+  #C16 = <dart.core::int*>[#C15, #C15, #C15]
+  #C17 = 16
+  #C18 = <dart.core::int*>[#C17, #C17, #C17]
 }
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_01.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_01.yaml.world.2.expect
index 466b63f..77ff6cd 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_01.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_01.yaml.world.2.expect
@@ -4,10 +4,10 @@
   import "dart:ffi";
 
   @#C3
-  @#C8
+  @#C9
   class Coordinate extends dart.ffi::Struct {
     @#C3
-    static final field dart.core::int* #sizeOf = (#C11).{dart.core::List::[]}(dart.ffi::_abi());
+    static final field dart.core::int* #sizeOf = (#C12).{dart.core::List::[]}(dart.ffi::_abi());
     @#C3
     constructor #fromTypedDataBase(dynamic #pointer) → dynamic
       : super dart.ffi::Struct::_fromPointer(#pointer)
@@ -27,17 +27,17 @@
     abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
     abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
     get x() → dart.core::double*
-      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()));
+      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()));
     set x(dart.core::double* #v) → void
-      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()), #v);
     get y() → dart.core::double*
-      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()));
+      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()));
     set y(dart.core::double* #v) → void
-      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()), #v);
     get next() → dart.ffi::Pointer<lib::Coordinate*>*
-      return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi())));
+      return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi())));
     set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
-      return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
+      return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
   }
 }
 library from "org-dartlang-test:///main.dart" as main {
@@ -63,14 +63,15 @@
   #C5 = TypeLiteralConstant(dart.ffi::Double)
   #C6 = TypeLiteralConstant(dart.ffi::Pointer<dart.ffi::NativeType>)
   #C7 = <dart.core::Type>[#C5, #C5, #C6]
-  #C8 = dart.core::pragma {name:#C4, options:#C7}
-  #C9 = 24
-  #C10 = 20
-  #C11 = <dart.core::int*>[#C9, #C10, #C9]
-  #C12 = 0
-  #C13 = <dart.core::int*>[#C12, #C12, #C12]
-  #C14 = 8
-  #C15 = <dart.core::int*>[#C14, #C14, #C14]
-  #C16 = 16
-  #C17 = <dart.core::int*>[#C16, #C16, #C16]
+  #C8 = dart.ffi::_FfiStructLayout {fieldTypes:#C7}
+  #C9 = dart.core::pragma {name:#C4, options:#C8}
+  #C10 = 24
+  #C11 = 20
+  #C12 = <dart.core::int*>[#C10, #C11, #C10]
+  #C13 = 0
+  #C14 = <dart.core::int*>[#C13, #C13, #C13]
+  #C15 = 8
+  #C16 = <dart.core::int*>[#C15, #C15, #C15]
+  #C17 = 16
+  #C18 = <dart.core::int*>[#C17, #C17, #C17]
 }
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_02.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_02.yaml.world.1.expect
index 5d79437..a42b6b2 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_02.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/ffi_02.yaml.world.1.expect
@@ -4,10 +4,10 @@
   import "dart:ffi";
 
   @#C3
-  @#C8
+  @#C9
   class Coordinate extends dart.ffi::Struct {
     @#C3
-    static final field dart.core::int* #sizeOf = (#C11).{dart.core::List::[]}(dart.ffi::_abi());
+    static final field dart.core::int* #sizeOf = (#C12).{dart.core::List::[]}(dart.ffi::_abi());
     @#C3
     constructor #fromTypedDataBase(dynamic #pointer) → dynamic
       : super dart.ffi::Struct::_fromPointer(#pointer)
@@ -27,17 +27,17 @@
     abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
     abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
     get x() → dart.core::double*
-      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()));
+      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()));
     set x(dart.core::double* #v) → void
-      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()), #v);
     get y() → dart.core::double*
-      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()));
+      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()));
     set y(dart.core::double* #v) → void
-      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()), #v);
     get next() → dart.ffi::Pointer<lib::Coordinate*>*
-      return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi())));
+      return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi())));
     set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
-      return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
+      return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
   }
 }
 library from "org-dartlang-test:///main.dart" as main {
@@ -60,14 +60,15 @@
   #C5 = TypeLiteralConstant(dart.ffi::Double)
   #C6 = TypeLiteralConstant(dart.ffi::Pointer<dart.ffi::NativeType>)
   #C7 = <dart.core::Type>[#C5, #C5, #C6]
-  #C8 = dart.core::pragma {name:#C4, options:#C7}
-  #C9 = 24
-  #C10 = 20
-  #C11 = <dart.core::int*>[#C9, #C10, #C9]
-  #C12 = 0
-  #C13 = <dart.core::int*>[#C12, #C12, #C12]
-  #C14 = 8
-  #C15 = <dart.core::int*>[#C14, #C14, #C14]
-  #C16 = 16
-  #C17 = <dart.core::int*>[#C16, #C16, #C16]
+  #C8 = dart.ffi::_FfiStructLayout {fieldTypes:#C7}
+  #C9 = dart.core::pragma {name:#C4, options:#C8}
+  #C10 = 24
+  #C11 = 20
+  #C12 = <dart.core::int*>[#C10, #C11, #C10]
+  #C13 = 0
+  #C14 = <dart.core::int*>[#C13, #C13, #C13]
+  #C15 = 8
+  #C16 = <dart.core::int*>[#C15, #C15, #C15]
+  #C17 = 16
+  #C18 = <dart.core::int*>[#C17, #C17, #C17]
 }
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.1.expect
index f93c1a3..08f11e7 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.1.expect
@@ -4,10 +4,10 @@
   import "dart:ffi";
 
   @#C3
-  @#C8
+  @#C9
   class Coordinate extends dart.ffi::Struct {
     @#C3
-    static final field dart.core::int* #sizeOf = (#C11).{dart.core::List::[]}(dart.ffi::_abi());
+    static final field dart.core::int* #sizeOf = (#C12).{dart.core::List::[]}(dart.ffi::_abi());
     @#C3
     constructor #fromTypedDataBase(dynamic #pointer) → dynamic
       : super dart.ffi::Struct::_fromPointer(#pointer)
@@ -27,17 +27,17 @@
     abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
     abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
     get x() → dart.core::double*
-      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()));
+      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()));
     set x(dart.core::double* #v) → void
-      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()), #v);
     get y() → dart.core::double*
-      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()));
+      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()));
     set y(dart.core::double* #v) → void
-      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()), #v);
     get next() → dart.ffi::Pointer<lib::Coordinate*>*
-      return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi())));
+      return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi())));
     set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
-      return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
+      return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
   }
 }
 library from "org-dartlang-test:///main.dart" as main {
@@ -59,14 +59,15 @@
   #C5 = TypeLiteralConstant(dart.ffi::Double)
   #C6 = TypeLiteralConstant(dart.ffi::Pointer<dart.ffi::NativeType>)
   #C7 = <dart.core::Type>[#C5, #C5, #C6]
-  #C8 = dart.core::pragma {name:#C4, options:#C7}
-  #C9 = 24
-  #C10 = 20
-  #C11 = <dart.core::int*>[#C9, #C10, #C9]
-  #C12 = 0
-  #C13 = <dart.core::int*>[#C12, #C12, #C12]
-  #C14 = 8
-  #C15 = <dart.core::int*>[#C14, #C14, #C14]
-  #C16 = 16
-  #C17 = <dart.core::int*>[#C16, #C16, #C16]
+  #C8 = dart.ffi::_FfiStructLayout {fieldTypes:#C7}
+  #C9 = dart.core::pragma {name:#C4, options:#C8}
+  #C10 = 24
+  #C11 = 20
+  #C12 = <dart.core::int*>[#C10, #C11, #C10]
+  #C13 = 0
+  #C14 = <dart.core::int*>[#C13, #C13, #C13]
+  #C15 = 8
+  #C16 = <dart.core::int*>[#C15, #C15, #C15]
+  #C17 = 16
+  #C18 = <dart.core::int*>[#C17, #C17, #C17]
 }
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.2.expect
index 01f4106..4d29471 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.2.expect
@@ -4,10 +4,10 @@
   import "dart:ffi";
 
   @#C3
-  @#C8
+  @#C9
   class Coordinate extends dart.ffi::Struct {
     @#C3
-    static final field dart.core::int* #sizeOf = (#C11).{dart.core::List::[]}(dart.ffi::_abi());
+    static final field dart.core::int* #sizeOf = (#C12).{dart.core::List::[]}(dart.ffi::_abi());
     @#C3
     constructor #fromTypedDataBase(dynamic #pointer) → dynamic
       : super dart.ffi::Struct::_fromPointer(#pointer)
@@ -27,17 +27,17 @@
     abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
     abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
     get x() → dart.core::double*
-      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()));
+      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()));
     set x(dart.core::double* #v) → void
-      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()), #v);
     get y() → dart.core::double*
-      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()));
+      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()));
     set y(dart.core::double* #v) → void
-      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()), #v);
     get next() → dart.ffi::Pointer<lib::Coordinate*>*
-      return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi())));
+      return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi())));
     set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
-      return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
+      return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
   }
 }
 library from "org-dartlang-test:///main.dart" as main {
@@ -60,14 +60,15 @@
   #C5 = TypeLiteralConstant(dart.ffi::Double)
   #C6 = TypeLiteralConstant(dart.ffi::Pointer<dart.ffi::NativeType>)
   #C7 = <dart.core::Type>[#C5, #C5, #C6]
-  #C8 = dart.core::pragma {name:#C4, options:#C7}
-  #C9 = 24
-  #C10 = 20
-  #C11 = <dart.core::int*>[#C9, #C10, #C9]
-  #C12 = 0
-  #C13 = <dart.core::int*>[#C12, #C12, #C12]
-  #C14 = 8
-  #C15 = <dart.core::int*>[#C14, #C14, #C14]
-  #C16 = 16
-  #C17 = <dart.core::int*>[#C16, #C16, #C16]
+  #C8 = dart.ffi::_FfiStructLayout {fieldTypes:#C7}
+  #C9 = dart.core::pragma {name:#C4, options:#C8}
+  #C10 = 24
+  #C11 = 20
+  #C12 = <dart.core::int*>[#C10, #C11, #C10]
+  #C13 = 0
+  #C14 = <dart.core::int*>[#C13, #C13, #C13]
+  #C15 = 8
+  #C16 = <dart.core::int*>[#C15, #C15, #C15]
+  #C17 = 16
+  #C18 = <dart.core::int*>[#C17, #C17, #C17]
 }
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.3.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.3.expect
index 2c057af..6f18d43 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.3.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_35.yaml.world.3.expect
@@ -4,10 +4,10 @@
   import "dart:ffi";
 
   @#C3
-  @#C8
+  @#C9
   class Coordinate extends dart.ffi::Struct {
     @#C3
-    static final field dart.core::int* #sizeOf = (#C11).{dart.core::List::[]}(dart.ffi::_abi());
+    static final field dart.core::int* #sizeOf = (#C12).{dart.core::List::[]}(dart.ffi::_abi());
     @#C3
     constructor #fromTypedDataBase(dynamic #pointer) → dynamic
       : super dart.ffi::Struct::_fromPointer(#pointer)
@@ -28,17 +28,17 @@
     abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
     abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
     get x() → dart.core::double*
-      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()));
+      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()));
     set x(dart.core::double* #v) → void
-      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()), #v);
     get y() → dart.core::double*
-      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()));
+      return dart.ffi::_loadDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()));
     set y(dart.core::double* #v) → void
-      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+      return dart.ffi::_storeDouble(this.{dart.ffi::Struct::_addressOf}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()), #v);
     get next() → dart.ffi::Pointer<lib::Coordinate*>*
-      return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi())));
+      return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi())));
     set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
-      return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C17).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
+      return dart.ffi::_storeIntPtr(this.{dart.ffi::Struct::_addressOf}, (#C18).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
   }
 }
 library from "org-dartlang-test:///main.dart" as main {
@@ -61,14 +61,15 @@
   #C5 = TypeLiteralConstant(dart.ffi::Double)
   #C6 = TypeLiteralConstant(dart.ffi::Pointer<dart.ffi::NativeType>)
   #C7 = <dart.core::Type>[#C5, #C5, #C6]
-  #C8 = dart.core::pragma {name:#C4, options:#C7}
-  #C9 = 24
-  #C10 = 20
-  #C11 = <dart.core::int*>[#C9, #C10, #C9]
-  #C12 = 0
-  #C13 = <dart.core::int*>[#C12, #C12, #C12]
-  #C14 = 8
-  #C15 = <dart.core::int*>[#C14, #C14, #C14]
-  #C16 = 16
-  #C17 = <dart.core::int*>[#C16, #C16, #C16]
+  #C8 = dart.ffi::_FfiStructLayout {fieldTypes:#C7}
+  #C9 = dart.core::pragma {name:#C4, options:#C8}
+  #C10 = 24
+  #C11 = 20
+  #C12 = <dart.core::int*>[#C10, #C11, #C10]
+  #C13 = 0
+  #C14 = <dart.core::int*>[#C13, #C13, #C13]
+  #C15 = 8
+  #C16 = <dart.core::int*>[#C15, #C15, #C15]
+  #C17 = 16
+  #C18 = <dart.core::int*>[#C17, #C17, #C17]
 }
diff --git a/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect
index 79439bc..e8d0533 100644
--- a/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_sample.dart.strong.transformed.expect
@@ -12,30 +12,30 @@
 import "package:ffi/ffi.dart";
 
 @#C3
-@#C8
+@#C9
 class Coordinate extends ffi::Struct {
   @#C3
-  static final field core::int* #sizeOf = (#C11).{core::List::[]}(ffi::_abi())/*isLegacy*/;
+  static final field core::int* #sizeOf = (#C12).{core::List::[]}(ffi::_abi())/*isLegacy*/;
   @#C3
   constructor #fromTypedDataBase(dynamic #pointer) → dynamic
     : super ffi::Struct::_fromPointer(#pointer)
     ;
-  @#C12
+  @#C13
   get x() → core::double
-    return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C14).{core::List::[]}(ffi::_abi()));
-  @#C12
+    return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C15).{core::List::[]}(ffi::_abi()));
+  @#C13
   set x(core::double #externalFieldValue) → void
-    return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C14).{core::List::[]}(ffi::_abi()), #externalFieldValue);
-  @#C12
+    return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C15).{core::List::[]}(ffi::_abi()), #externalFieldValue);
+  @#C13
   get y() → core::double
-    return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C16).{core::List::[]}(ffi::_abi()));
-  @#C12
+    return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C17).{core::List::[]}(ffi::_abi()));
+  @#C13
   set y(core::double #externalFieldValue) → void
-    return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C16).{core::List::[]}(ffi::_abi()), #externalFieldValue);
+    return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C17).{core::List::[]}(ffi::_abi()), #externalFieldValue);
   get next() → ffi::Pointer<self::Coordinate>
-    return ffi::_fromAddress<self::Coordinate>(ffi::_loadIntPtr(this.{ffi::Struct::_addressOf}, (#C18).{core::List::[]}(ffi::_abi())));
+    return ffi::_fromAddress<self::Coordinate>(ffi::_loadIntPtr(this.{ffi::Struct::_addressOf}, (#C19).{core::List::[]}(ffi::_abi())));
   set next(ffi::Pointer<self::Coordinate> #externalFieldValue) → void
-    return ffi::_storeIntPtr(this.{ffi::Struct::_addressOf}, (#C18).{core::List::[]}(ffi::_abi()), #externalFieldValue.{ffi::Pointer::address});
+    return ffi::_storeIntPtr(this.{ffi::Struct::_addressOf}, (#C19).{core::List::[]}(ffi::_abi()), #externalFieldValue.{ffi::Pointer::address});
   static factory allocate(ffi::Allocator allocator, core::double x, core::double y, ffi::Pointer<self::Coordinate> next) → self::Coordinate {
     return let final self::Coordinate #t1 = new self::Coordinate::#fromTypedDataBase(allocator.{ffi::Allocator::allocate}<self::Coordinate>(self::Coordinate::#sizeOf)!) in block {
       #t1.{self::Coordinate::x} = x;
@@ -54,17 +54,18 @@
   #C5 = TypeLiteralConstant(ffi::Double)
   #C6 = TypeLiteralConstant(ffi::Pointer<ffi::NativeType>)
   #C7 = <core::Type>[#C5, #C5, #C6]
-  #C8 = core::pragma {name:#C4, options:#C7}
-  #C9 = 24
-  #C10 = 20
-  #C11 = <core::int*>[#C9, #C10, #C9]
-  #C12 = ffi::Double {}
-  #C13 = 0
-  #C14 = <core::int*>[#C13, #C13, #C13]
-  #C15 = 8
-  #C16 = <core::int*>[#C15, #C15, #C15]
-  #C17 = 16
-  #C18 = <core::int*>[#C17, #C17, #C17]
+  #C8 = ffi::_FfiStructLayout {fieldTypes:#C7}
+  #C9 = core::pragma {name:#C4, options:#C8}
+  #C10 = 24
+  #C11 = 20
+  #C12 = <core::int*>[#C10, #C11, #C10]
+  #C13 = ffi::Double {}
+  #C14 = 0
+  #C15 = <core::int*>[#C14, #C14, #C14]
+  #C16 = 8
+  #C17 = <core::int*>[#C16, #C16, #C16]
+  #C18 = 16
+  #C19 = <core::int*>[#C18, #C18, #C18]
 }
 
 
diff --git a/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect
index 79439bc..e8d0533 100644
--- a/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_sample.dart.weak.transformed.expect
@@ -12,30 +12,30 @@
 import "package:ffi/ffi.dart";
 
 @#C3
-@#C8
+@#C9
 class Coordinate extends ffi::Struct {
   @#C3
-  static final field core::int* #sizeOf = (#C11).{core::List::[]}(ffi::_abi())/*isLegacy*/;
+  static final field core::int* #sizeOf = (#C12).{core::List::[]}(ffi::_abi())/*isLegacy*/;
   @#C3
   constructor #fromTypedDataBase(dynamic #pointer) → dynamic
     : super ffi::Struct::_fromPointer(#pointer)
     ;
-  @#C12
+  @#C13
   get x() → core::double
-    return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C14).{core::List::[]}(ffi::_abi()));
-  @#C12
+    return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C15).{core::List::[]}(ffi::_abi()));
+  @#C13
   set x(core::double #externalFieldValue) → void
-    return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C14).{core::List::[]}(ffi::_abi()), #externalFieldValue);
-  @#C12
+    return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C15).{core::List::[]}(ffi::_abi()), #externalFieldValue);
+  @#C13
   get y() → core::double
-    return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C16).{core::List::[]}(ffi::_abi()));
-  @#C12
+    return ffi::_loadDouble(this.{ffi::Struct::_addressOf}, (#C17).{core::List::[]}(ffi::_abi()));
+  @#C13
   set y(core::double #externalFieldValue) → void
-    return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C16).{core::List::[]}(ffi::_abi()), #externalFieldValue);
+    return ffi::_storeDouble(this.{ffi::Struct::_addressOf}, (#C17).{core::List::[]}(ffi::_abi()), #externalFieldValue);
   get next() → ffi::Pointer<self::Coordinate>
-    return ffi::_fromAddress<self::Coordinate>(ffi::_loadIntPtr(this.{ffi::Struct::_addressOf}, (#C18).{core::List::[]}(ffi::_abi())));
+    return ffi::_fromAddress<self::Coordinate>(ffi::_loadIntPtr(this.{ffi::Struct::_addressOf}, (#C19).{core::List::[]}(ffi::_abi())));
   set next(ffi::Pointer<self::Coordinate> #externalFieldValue) → void
-    return ffi::_storeIntPtr(this.{ffi::Struct::_addressOf}, (#C18).{core::List::[]}(ffi::_abi()), #externalFieldValue.{ffi::Pointer::address});
+    return ffi::_storeIntPtr(this.{ffi::Struct::_addressOf}, (#C19).{core::List::[]}(ffi::_abi()), #externalFieldValue.{ffi::Pointer::address});
   static factory allocate(ffi::Allocator allocator, core::double x, core::double y, ffi::Pointer<self::Coordinate> next) → self::Coordinate {
     return let final self::Coordinate #t1 = new self::Coordinate::#fromTypedDataBase(allocator.{ffi::Allocator::allocate}<self::Coordinate>(self::Coordinate::#sizeOf)!) in block {
       #t1.{self::Coordinate::x} = x;
@@ -54,17 +54,18 @@
   #C5 = TypeLiteralConstant(ffi::Double)
   #C6 = TypeLiteralConstant(ffi::Pointer<ffi::NativeType>)
   #C7 = <core::Type>[#C5, #C5, #C6]
-  #C8 = core::pragma {name:#C4, options:#C7}
-  #C9 = 24
-  #C10 = 20
-  #C11 = <core::int*>[#C9, #C10, #C9]
-  #C12 = ffi::Double {}
-  #C13 = 0
-  #C14 = <core::int*>[#C13, #C13, #C13]
-  #C15 = 8
-  #C16 = <core::int*>[#C15, #C15, #C15]
-  #C17 = 16
-  #C18 = <core::int*>[#C17, #C17, #C17]
+  #C8 = ffi::_FfiStructLayout {fieldTypes:#C7}
+  #C9 = core::pragma {name:#C4, options:#C8}
+  #C10 = 24
+  #C11 = 20
+  #C12 = <core::int*>[#C10, #C11, #C10]
+  #C13 = ffi::Double {}
+  #C14 = 0
+  #C15 = <core::int*>[#C14, #C14, #C14]
+  #C16 = 8
+  #C17 = <core::int*>[#C16, #C16, #C16]
+  #C18 = 16
+  #C19 = <core::int*>[#C18, #C18, #C18]
 }
 
 
diff --git a/pkg/vm/lib/transformations/ffi.dart b/pkg/vm/lib/transformations/ffi.dart
index 5ead392..209e4df 100644
--- a/pkg/vm/lib/transformations/ffi.dart
+++ b/pkg/vm/lib/transformations/ffi.dart
@@ -214,6 +214,8 @@
   final Class opaqueClass;
   final Class pointerClass;
   final Class structClass;
+  final Class ffiStructLayoutClass;
+  final Field ffiStructLayoutTypesField;
   final Procedure allocateMethod;
   final Procedure allocatorAllocateMethod;
   final Procedure castMethod;
@@ -245,6 +247,9 @@
   /// Classes corresponding to [NativeType], indexed by [NativeType].
   final List<Class> nativeTypesClasses;
 
+  Library currentLibrary;
+  IndexedLibrary currentLibraryIndex;
+
   FfiTransformer(this.index, this.coreTypes, this.hierarchy,
       this.diagnosticReporter, this.referenceFromIndex)
       : env = new TypeEnvironment(coreTypes, hierarchy),
@@ -274,6 +279,9 @@
         opaqueClass = index.getClass('dart:ffi', 'Opaque'),
         pointerClass = index.getClass('dart:ffi', 'Pointer'),
         structClass = index.getClass('dart:ffi', 'Struct'),
+        ffiStructLayoutClass = index.getClass('dart:ffi', '_FfiStructLayout'),
+        ffiStructLayoutTypesField =
+            index.getMember('dart:ffi', '_FfiStructLayout', 'fieldTypes'),
         allocateMethod = index.getMember('dart:ffi', 'AllocatorAlloc', 'call'),
         allocatorAllocateMethod =
             index.getMember('dart:ffi', 'Allocator', 'allocate'),
@@ -331,6 +339,16 @@
             'DynamicLibraryExtension',
             LibraryIndex.tearoffPrefix + 'lookupFunction');
 
+  @override
+  TreeNode visitLibrary(Library node) {
+    assert(currentLibrary == null);
+    currentLibrary = node;
+    currentLibraryIndex = referenceFromIndex?.lookupLibrary(node);
+    final result = super.visitLibrary(node);
+    currentLibrary = null;
+    return result;
+  }
+
   /// Computes the Dart type corresponding to a ffi.[NativeType], returns null
   /// if it is not a valid NativeType.
   ///
@@ -436,6 +454,111 @@
         Arguments([StaticInvocation(abiMethod, Arguments([]))]),
         listElementAt);
   }
+
+  /// Generates an expression that returns a new `Pointer<dartType>` offset
+  /// by [offset] from [pointer].
+  ///
+  /// Sample output:
+  ///
+  /// ```
+  /// _fromAddress<dartType>(pointer.address + #offset)
+  /// ```
+  Expression _pointerOffset(Expression pointer, Expression offset,
+          DartType dartType, int fileOffset) =>
+      StaticInvocation(
+          fromAddressInternal,
+          Arguments([
+            MethodInvocation(
+                PropertyGet(pointer, addressGetter.name, addressGetter)
+                  ..fileOffset = fileOffset,
+                numAddition.name,
+                Arguments([offset]),
+                numAddition)
+          ], types: [
+            dartType
+          ]))
+        ..fileOffset = fileOffset;
+
+  /// Generates an expression that returns a new `TypedData` offset
+  /// by [offset] from [typedData].
+  ///
+  /// Sample output:
+  ///
+  /// ```
+  /// TypedData #typedData = typedData;
+  /// #typedData.buffer.asInt8List(#typedData.offsetInBytes + offset, length)
+  /// ```
+  Expression _typedDataOffset(Expression typedData, Expression offset,
+      Expression length, int fileOffset) {
+    final typedDataVar = VariableDeclaration("#typedData",
+        initializer: typedData,
+        type: InterfaceType(typedDataClass, Nullability.nonNullable))
+      ..fileOffset = fileOffset;
+    return Let(
+        typedDataVar,
+        MethodInvocation(
+            PropertyGet(VariableGet(typedDataVar), typedDataBufferGetter.name,
+                typedDataBufferGetter)
+              ..fileOffset = fileOffset,
+            byteBufferAsUint8List.name,
+            Arguments([
+              MethodInvocation(
+                  PropertyGet(
+                      VariableGet(typedDataVar),
+                      typedDataOffsetInBytesGetter.name,
+                      typedDataOffsetInBytesGetter)
+                    ..fileOffset = fileOffset,
+                  numAddition.name,
+                  Arguments([offset]),
+                  numAddition),
+              length
+            ]),
+            byteBufferAsUint8List));
+  }
+
+  /// Generates an expression that returns a new `TypedDataBase` offset
+  /// by [offset] from [typedDataBase].
+  ///
+  /// If [typedDataBase] is a `Pointer`, returns a `Pointer<dartType>`.
+  /// If [typedDataBase] is a `TypedData` returns a `TypedData`.
+  ///
+  /// Sample output:
+  ///
+  /// ```
+  /// Object #typedDataBase = typedDataBase;
+  /// int #offset = offset;
+  /// #typedDataBase is Pointer ?
+  ///   _pointerOffset<dartType>(#typedDataBase, #offset) :
+  ///   _typedDataOffset((#typedDataBase as TypedData), #offset, length)
+  /// ```
+  Expression typedDataBaseOffset(Expression typedDataBase, Expression offset,
+      Expression length, DartType dartType, int fileOffset) {
+    final typedDataBaseVar = VariableDeclaration("#typedDataBase",
+        initializer: typedDataBase, type: coreTypes.objectNonNullableRawType)
+      ..fileOffset = fileOffset;
+    final offsetVar = VariableDeclaration("#offset",
+        initializer: offset, type: coreTypes.intNonNullableRawType)
+      ..fileOffset = fileOffset;
+    return BlockExpression(
+        Block([typedDataBaseVar, offsetVar]),
+        ConditionalExpression(
+            IsExpression(VariableGet(typedDataBaseVar),
+                InterfaceType(pointerClass, Nullability.nonNullable)),
+            _pointerOffset(VariableGet(typedDataBaseVar),
+                VariableGet(offsetVar), dartType, fileOffset),
+            _typedDataOffset(
+                StaticInvocation(
+                    unsafeCastMethod,
+                    Arguments([
+                      VariableGet(typedDataBaseVar)
+                    ], types: [
+                      InterfaceType(typedDataClass, Nullability.nonNullable)
+                    ])),
+                VariableGet(offsetVar),
+                length,
+                fileOffset),
+            coreTypes.objectNonNullableRawType));
+  }
 }
 
 /// Contains all information collected by _FfiDefinitionTransformer that is
diff --git a/pkg/vm/lib/transformations/ffi_definitions.dart b/pkg/vm/lib/transformations/ffi_definitions.dart
index b06c63f..5c114c2 100644
--- a/pkg/vm/lib/transformations/ffi_definitions.dart
+++ b/pkg/vm/lib/transformations/ffi_definitions.dart
@@ -104,7 +104,7 @@
   Map<Class, IndexedClass> indexedStructClasses = {};
   Map<Class, Set<Class>> structClassDependencies = {};
   Map<Class, bool> fieldsValid = {};
-  Map<Class, Map<Abi, StructLayout>> structLayouts = {};
+  Map<Class, StructNativeTypeCfe> structCache = {};
 
   Map<Field, Procedure> replacedGetters = {};
   Map<Field, Procedure> replacedSetters = {};
@@ -150,12 +150,11 @@
               e.name.length,
               e.fileUri);
         });
+      } else {
+        // Only visit the ones without cycles.
+        visitClassInTopologicalOrder(component.single);
       }
     });
-
-    final structClassesSorted = connectedComponents.expand((i) => i).toList();
-
-    structClassesSorted.forEach(visitClassInTopologicalOrder);
   }
 
   @override
@@ -216,6 +215,9 @@
   }
 
   bool _isPointerType(DartType type) {
+    if (type is InvalidType) {
+      return false;
+    }
     return env.isSubtypeOf(
         type,
         InterfaceType(pointerClass, Nullability.legacy, [
@@ -226,6 +228,9 @@
   }
 
   bool _isStructSubtype(DartType type) {
+    if (type is InvalidType) {
+      return false;
+    }
     return env.isSubtypeOf(type, InterfaceType(structClass, Nullability.legacy),
         SubtypeCheckMode.ignoringNullabilities);
   }
@@ -272,6 +277,8 @@
               f.fileOffset,
               f.name.text.length,
               f.fileUri);
+          // This class is invalid, but continue reporting other errors on it.
+          success = false;
         }
       }
       final nativeTypeAnnos = _getNativeTypeAnnotations(f).toList();
@@ -283,6 +290,8 @@
               f.fileOffset,
               f.name.text.length,
               f.fileUri);
+          // This class is invalid, but continue reporting other errors on it.
+          success = false;
         }
         if (_isStructSubtype(type)) {
           final clazz = (type as InterfaceType).classNode;
@@ -294,6 +303,8 @@
             f.fileOffset,
             f.name.text.length,
             f.fileUri);
+        // This class is invalid, but continue reporting other errors on it.
+        success = false;
       } else {
         final DartType nativeType = InterfaceType(
             nativeTypesClasses[_getFieldType(nativeTypeAnnos.first).index],
@@ -311,6 +322,7 @@
               f.fileOffset,
               1,
               f.location.file);
+          // This class is invalid, but continue reporting other errors on it.
           success = false;
         }
       }
@@ -364,8 +376,7 @@
   ///
   /// Returns the total size of the struct (for all ABIs).
   Map<Abi, int> _replaceFields(Class node, IndexedClass indexedClass) {
-    final classes = <Class>[];
-    final types = <NativeType>[];
+    final types = <NativeTypeCfe>[];
     final fields = <int, Field>{};
     final getters = <int, Procedure>{};
     final setters = <int, Procedure>{};
@@ -374,14 +385,12 @@
     for (final Member m in _structFieldMembers(node)) {
       final dartType = _structFieldMemberType(m);
 
-      NativeType nativeType;
-      Class clazz;
+      NativeTypeCfe type;
       if (_isPointerType(dartType)) {
-        nativeType = NativeType.kPointer;
-        clazz = pointerClass;
+        type = PointerNativeTypeCfe();
       } else if (_isStructSubtype(dartType)) {
-        nativeType = NativeType.kStruct;
-        clazz = (dartType as InterfaceType).classNode;
+        final clazz = (dartType as InterfaceType).classNode;
+        type = structCache[clazz];
         if (emptyStructs.contains(clazz)) {
           diagnosticReporter.report(
               templateFfiEmptyStruct.withArguments(clazz.name),
@@ -392,15 +401,14 @@
       } else {
         final nativeTypeAnnos = _getNativeTypeAnnotations(m).toList();
         if (nativeTypeAnnos.length == 1) {
-          clazz = nativeTypeAnnos.first;
-          nativeType = _getFieldType(clazz);
+          final clazz = nativeTypeAnnos.first;
+          final nativeType = _getFieldType(clazz);
+          type = PrimitiveNativeTypeCfe(nativeType, clazz);
         }
       }
 
-      if ((m is Field || (m is Procedure && m.isGetter)) &&
-          nativeType != null) {
-        types.add(nativeType);
-        classes.add(clazz);
+      if ((m is Field || (m is Procedure && m.isGetter)) && type != null) {
+        types.add(type);
         if (m is Field) {
           fields[i] = m;
         }
@@ -417,8 +425,8 @@
       }
     }
 
-    _annoteStructWithFields(node, classes);
-    if (classes.isEmpty) {
+    _annoteStructWithFields(node, types);
+    if (types.isEmpty) {
       diagnosticReporter.report(
           templateFfiEmptyStructWarning.withArguments(node.name),
           node.fileOffset,
@@ -427,11 +435,9 @@
       emptyStructs.add(node);
     }
 
-    final structLayout = <Abi, StructLayout>{};
-    for (final Abi abi in Abi.values) {
-      structLayout[abi] = _calculateStructLayout(types, classes, abi);
-    }
-    structLayouts[node] = structLayout;
+    final structType = StructNativeTypeCfe(node, types);
+    structCache[node] = structType;
+    final structLayout = structType.layout;
 
     for (final i in fields.keys) {
       final fieldOffsets = structLayout
@@ -449,11 +455,8 @@
       final fieldOffsets = structLayout
           .map((Abi abi, StructLayout v) => MapEntry(abi, v.offsets[i]));
       Procedure getter = getters[i];
-      getter.function.body = _generateGetterStatement(
-          getter.function.returnType,
-          types[i],
-          getter.fileOffset,
-          fieldOffsets);
+      getter.function.body = types[i].generateGetterStatement(
+          getter.function.returnType, getter.fileOffset, fieldOffsets, this);
       getter.isExternal = false;
     }
 
@@ -461,207 +464,38 @@
       final fieldOffsets = structLayout
           .map((Abi abi, StructLayout v) => MapEntry(abi, v.offsets[i]));
       Procedure setter = setters[i];
-      setter.function.body = _generateSetterStatement(
+      setter.function.body = types[i].generateSetterStatement(
           setter.function.positionalParameters.single.type,
-          types[i],
           setter.fileOffset,
           fieldOffsets,
-          setter.function.positionalParameters.single);
+          setter.function.positionalParameters.single,
+          this);
       setter.isExternal = false;
     }
 
     return structLayout.map((k, v) => MapEntry(k, v.size));
   }
 
-  void _annoteStructWithFields(Class node, List<Class> fieldTypes) {
-    final types = fieldTypes.map((Class c) {
-      List<DartType> typeArg = const [];
-      if (c == pointerClass) {
-        typeArg = [
-          InterfaceType(pointerClass.superclass, Nullability.nonNullable)
-        ];
-      }
-      return TypeLiteralConstant(
-          InterfaceType(c, Nullability.nonNullable, typeArg));
-    }).toList();
+  void _annoteStructWithFields(Class node, List<NativeTypeCfe> types) {
+    List<Constant> constants =
+        types.map((t) => t.generateConstant(this)).toList();
 
     node.addAnnotation(ConstantExpression(
         InstanceConstant(pragmaClass.reference, [], {
           pragmaName.getterReference: StringConstant("vm:ffi:struct-fields"),
-          // TODO(dartbug.com/38158): Wrap list in class to be able to encode
-          // more information when needed.
-          pragmaOptions.getterReference: ListConstant(
-              InterfaceType(typeClass, Nullability.nonNullable), types)
+          pragmaOptions.getterReference:
+              InstanceConstant(ffiStructLayoutClass.reference, [], {
+            ffiStructLayoutTypesField.getterReference: ListConstant(
+                InterfaceType(typeClass, Nullability.nonNullable), constants)
+          })
         }),
         InterfaceType(pragmaClass, Nullability.nonNullable, [])));
   }
 
-  Statement _generateGetterStatement(DartType dartType, NativeType type,
-      int fileOffset, Map<Abi, int> offsets) {
-    final bool isPointer = type == NativeType.kPointer;
-    final bool isStruct = type == NativeType.kStruct;
-
-    // Sample output:
-    // int get x => _loadInt8(pointer, offset);
-    //
-    // Treat Pointer fields different to get correct behavior without casts:
-    // Pointer<Int8> get x =>
-    //   _fromAddress<Int8>(_loadIntPtr(pointer, offset));
-    //
-    // Nested structs:
-    // MyStruct get x =>
-    //   MyStruct.#fromTypedDataBase(
-    //     _addressOf is Pointer ?
-    //       _fromAddress<MyStruct>((_addressOf as Pointer).address + offset) :
-    //       (_addressOf as TypedData).buffer.asInt8List(
-    //         (_addressOf as TypedData).offsetInBytes + offset,
-    //         size
-    //       )
-    //   );
-    if (isStruct) {
-      final clazz = (dartType as InterfaceType).classNode;
-      final constructor = clazz.constructors
-          .firstWhere((c) => c.name == Name("#fromTypedDataBase"));
-      final lengths =
-          structLayouts[clazz].map((key, value) => MapEntry(key, value.size));
-      Expression thisDotAddressOf() =>
-          PropertyGet(ThisExpression(), addressOfField.name, addressOfField)
-            ..fileOffset = fileOffset;
-      return ReturnStatement(ConstructorInvocation(
-          constructor,
-          Arguments([
-            ConditionalExpression(
-                IsExpression(thisDotAddressOf(),
-                    InterfaceType(pointerClass, Nullability.legacy)),
-                StaticInvocation(
-                    fromAddressInternal,
-                    Arguments([
-                      MethodInvocation(
-                          PropertyGet(thisDotAddressOf(), addressGetter.name,
-                              addressGetter)
-                            ..fileOffset = fileOffset,
-                          numAddition.name,
-                          Arguments([runtimeBranchOnLayout(offsets)]),
-                          numAddition)
-                    ], types: [
-                      dartType
-                    ]))
-                  ..fileOffset = fileOffset,
-                MethodInvocation(
-                    PropertyGet(
-                        StaticInvocation(
-                            unsafeCastMethod,
-                            Arguments([
-                              thisDotAddressOf()
-                            ], types: [
-                              InterfaceType(typedDataClass, Nullability.legacy)
-                            ]))
-                          ..fileOffset = fileOffset,
-                        typedDataBufferGetter.name,
-                        typedDataBufferGetter)
-                      ..fileOffset = fileOffset,
-                    byteBufferAsUint8List.name,
-                    Arguments([
-                      MethodInvocation(
-                          PropertyGet(
-                              StaticInvocation(
-                                  unsafeCastMethod,
-                                  Arguments([
-                                    thisDotAddressOf()
-                                  ], types: [
-                                    InterfaceType(
-                                        typedDataClass, Nullability.legacy)
-                                  ]))
-                                ..fileOffset = fileOffset,
-                              typedDataOffsetInBytesGetter.name,
-                              typedDataOffsetInBytesGetter)
-                            ..fileOffset = fileOffset,
-                          numAddition.name,
-                          Arguments([runtimeBranchOnLayout(offsets)]),
-                          numAddition),
-                      runtimeBranchOnLayout(lengths)
-                    ]),
-                    byteBufferAsUint8List),
-                InterfaceType(objectClass, Nullability.nonNullable))
-          ]))
-        ..fileOffset = fileOffset);
-    }
-    final loadMethod =
-        isPointer ? loadMethods[NativeType.kIntptr] : loadMethods[type];
-    Expression getterReturnValue = StaticInvocation(
-        loadMethod,
-        Arguments([
-          PropertyGet(ThisExpression(), addressOfField.name, addressOfField)
-            ..fileOffset = fileOffset,
-          runtimeBranchOnLayout(offsets)
-        ]))
-      ..fileOffset = fileOffset;
-    if (isPointer) {
-      final typeArg = (dartType as InterfaceType).typeArguments.single;
-      getterReturnValue = StaticInvocation(
-          fromAddressInternal, Arguments([getterReturnValue], types: [typeArg]))
-        ..fileOffset = fileOffset;
-    }
-    return ReturnStatement(getterReturnValue);
-  }
-
-  Statement _generateSetterStatement(DartType dartType, NativeType type,
-      int fileOffset, Map<Abi, int> offsets, VariableDeclaration argument) {
-    final bool isPointer = type == NativeType.kPointer;
-    final bool isStruct = type == NativeType.kStruct;
-
-    // Sample output:
-    // set x(int v) => _storeInt8(pointer, offset, v);
-    //
-    // Treat Pointer fields different to get correct behavior without casts:
-    // set x(Pointer<Int8> v) =>
-    //   _storeIntPtr(pointer, offset, (v as Pointer<Int8>).address);
-    //
-    // Nested structs:
-    // set x(MyStruct v) =>
-    //   _memCopy(this._address, offset, v._address, 0, size);
-    if (isStruct) {
-      final clazz = (dartType as InterfaceType).classNode;
-      final lengths =
-          structLayouts[clazz].map((key, value) => MapEntry(key, value.size));
-      return ReturnStatement(StaticInvocation(
-          memCopy,
-          Arguments([
-            PropertyGet(ThisExpression(), addressOfField.name, addressOfField)
-              ..fileOffset = fileOffset,
-            runtimeBranchOnLayout(offsets),
-            PropertyGet(
-                VariableGet(argument), addressOfField.name, addressOfField)
-              ..fileOffset = fileOffset,
-            ConstantExpression(IntConstant(0)),
-            runtimeBranchOnLayout(lengths),
-          ]))
-        ..fileOffset = fileOffset);
-    }
-    final storeMethod =
-        isPointer ? storeMethods[NativeType.kIntptr] : storeMethods[type];
-    Expression argumentExpression = VariableGet(argument)
-      ..fileOffset = fileOffset;
-    if (isPointer) {
-      argumentExpression =
-          PropertyGet(argumentExpression, addressGetter.name, addressGetter)
-            ..fileOffset = fileOffset;
-    }
-    return ReturnStatement(StaticInvocation(
-        storeMethod,
-        Arguments([
-          PropertyGet(ThisExpression(), addressOfField.name, addressOfField)
-            ..fileOffset = fileOffset,
-          runtimeBranchOnLayout(offsets),
-          argumentExpression
-        ]))
-      ..fileOffset = fileOffset);
-  }
-
-  List<Procedure> _generateMethodsForField(Field field, NativeType type,
+  List<Procedure> _generateMethodsForField(Field field, NativeTypeCfe type,
       Map<Abi, int> offsets, IndexedClass indexedClass) {
-    final getterStatement =
-        _generateGetterStatement(field.type, type, field.fileOffset, offsets);
+    final getterStatement = type.generateGetterStatement(
+        field.type, field.fileOffset, offsets, this);
     final Procedure getter = Procedure(field.name, ProcedureKind.Getter,
         FunctionNode(getterStatement, returnType: field.type),
         fileUri: field.fileUri,
@@ -674,8 +508,8 @@
       final VariableDeclaration argument =
           VariableDeclaration('#v', type: field.type)
             ..fileOffset = field.fileOffset;
-      final setterStatement = _generateSetterStatement(
-          field.type, type, field.fileOffset, offsets, argument);
+      final setterStatement = type.generateSetterStatement(
+          field.type, field.fileOffset, offsets, argument, this);
       setter = Procedure(
           field.name,
           ProcedureKind.Setter,
@@ -711,64 +545,6 @@
     struct.addField(sizeOf);
   }
 
-  int _sizeInBytes(NativeType type, Class clazz, Abi abi) {
-    if (type == NativeType.kStruct) {
-      final structLayout = structLayouts[clazz];
-      if (structLayout == null) {
-        // We have a cycle, so we don't know the size.
-        return 0;
-      }
-      return structLayout[abi].size;
-    }
-    final int size = nativeTypeSizes[type.index];
-    if (size == WORD_SIZE) {
-      return wordSize[abi];
-    }
-    return size;
-  }
-
-  int _alignmentOf(NativeType type, Class clazz, Abi abi) {
-    if (type == NativeType.kStruct) {
-      final structLayout = structLayouts[clazz];
-      if (structLayout == null) {
-        // We have a cycle, so we don't know the size.
-        return 0;
-      }
-      return structLayout[abi].alignment;
-    }
-    final int alignment = nonSizeAlignment[abi][type];
-    if (alignment != null) return alignment;
-    return _sizeInBytes(type, clazz, abi);
-  }
-
-  int _alignOffset(int offset, int alignment) {
-    final int remainder = offset % alignment;
-    if (remainder != 0) {
-      offset -= remainder;
-      offset += alignment;
-    }
-    return offset;
-  }
-
-  // Keep consistent with runtime/vm/compiler/ffi/native_type.cc
-  // NativeCompoundType::FromNativeTypes.
-  StructLayout _calculateStructLayout(
-      List<NativeType> types, List<Class> classes, Abi abi) {
-    int offset = 0;
-    final offsets = <int>[];
-    int structAlignment = 1;
-    for (int i = 0; i < types.length; i++) {
-      final int size = _sizeInBytes(types[i], classes[i], abi);
-      final int alignment = _alignmentOf(types[i], classes[i], abi);
-      offset = _alignOffset(offset, alignment);
-      offsets.add(offset);
-      offset += size;
-      structAlignment = math.max(structAlignment, alignment);
-    }
-    final int size = _alignOffset(offset, structAlignment);
-    return StructLayout(size, structAlignment, offsets);
-  }
-
   void _makeEntryPoint(Annotatable node) {
     node.addAnnotation(ConstantExpression(
         InstanceConstant(pragmaClass.reference, [], {
@@ -811,3 +587,275 @@
 
   StructLayout(this.size, this.alignment, this.offsets);
 }
+
+/// AST node wrapper for native types.
+///
+/// This algebraic data structure does not stand on its own but refers
+/// intimately to AST nodes such as [Class].
+abstract class NativeTypeCfe {
+  /// The size in bytes per [Abi].
+  Map<Abi, int> get size;
+
+  /// The alignment inside structs in bytes per [Abi].
+  ///
+  /// This is not the alignment on stack, this is only calculated in the VM.
+  Map<Abi, int> get alignment;
+
+  /// Generates a Constant representing the type which is consumed by the VM.
+  ///
+  /// Takes [transformer] to be able to lookup classes and methods.
+  ///
+  /// See runtime/vm/compiler/ffi/native_type.cc:NativeType::FromAbstractType.
+  Constant generateConstant(FfiTransformer transformer);
+
+  /// Generates the return statement for a struct field getter with this type.
+  ///
+  /// Takes [transformer] to be able to lookup classes and methods.
+  ReturnStatement generateGetterStatement(DartType dartType, int fileOffset,
+      Map<Abi, int> offsets, FfiTransformer transformer);
+
+  /// Generates the return statement for a struct field setter with this type.
+  ///
+  /// Takes [transformer] to be able to lookup classes and methods.
+  ReturnStatement generateSetterStatement(
+      DartType dartType,
+      int fileOffset,
+      Map<Abi, int> offsets,
+      VariableDeclaration argument,
+      FfiTransformer transformer);
+}
+
+class PrimitiveNativeTypeCfe implements NativeTypeCfe {
+  final NativeType nativeType;
+
+  final Class clazz;
+
+  PrimitiveNativeTypeCfe(this.nativeType, this.clazz);
+
+  @override
+  Map<Abi, int> get size {
+    final int size = nativeTypeSizes[nativeType.index];
+    if (size == WORD_SIZE) {
+      return wordSize;
+    }
+    return Map.fromEntries(Abi.values.map((abi) => MapEntry(abi, size)));
+  }
+
+  @override
+  Map<Abi, int> get alignment => Map.fromEntries(Abi.values.map(
+      (abi) => MapEntry(abi, nonSizeAlignment[abi][nativeType] ?? size[abi])));
+
+  @override
+  Constant generateConstant(FfiTransformer transformer) =>
+      TypeLiteralConstant(InterfaceType(clazz, Nullability.nonNullable));
+
+  /// Sample output for `int get x =>`:
+  ///
+  /// ```
+  /// _loadInt8(_addressOf, offset);
+  /// ```
+  @override
+  ReturnStatement generateGetterStatement(DartType dartType, int fileOffset,
+          Map<Abi, int> offsets, FfiTransformer transformer) =>
+      ReturnStatement(StaticInvocation(
+          transformer.loadMethods[nativeType],
+          Arguments([
+            PropertyGet(ThisExpression(), transformer.addressOfField.name,
+                transformer.addressOfField)
+              ..fileOffset = fileOffset,
+            transformer.runtimeBranchOnLayout(offsets)
+          ]))
+        ..fileOffset = fileOffset);
+
+  /// Sample output for `set x(int #v) =>`:
+  ///
+  /// ```
+  /// _storeInt8(_addressOf, offset, #v);
+  /// ```
+  @override
+  ReturnStatement generateSetterStatement(
+          DartType dartType,
+          int fileOffset,
+          Map<Abi, int> offsets,
+          VariableDeclaration argument,
+          FfiTransformer transformer) =>
+      ReturnStatement(StaticInvocation(
+          transformer.storeMethods[nativeType],
+          Arguments([
+            PropertyGet(ThisExpression(), transformer.addressOfField.name,
+                transformer.addressOfField)
+              ..fileOffset = fileOffset,
+            transformer.runtimeBranchOnLayout(offsets),
+            VariableGet(argument)
+          ]))
+        ..fileOffset = fileOffset);
+}
+
+class PointerNativeTypeCfe implements NativeTypeCfe {
+  @override
+  Map<Abi, int> get size => wordSize;
+
+  @override
+  Map<Abi, int> get alignment => wordSize;
+
+  @override
+  Constant generateConstant(FfiTransformer transformer) => TypeLiteralConstant(
+          InterfaceType(transformer.pointerClass, Nullability.nonNullable, [
+        InterfaceType(
+            transformer.pointerClass.superclass, Nullability.nonNullable)
+      ]));
+
+  /// Sample output for `Pointer<Int8> get x =>`:
+  ///
+  /// ```
+  /// _fromAddress<Int8>(_loadIntPtr(_addressOf, offset));
+  /// ```
+  @override
+  ReturnStatement generateGetterStatement(DartType dartType, int fileOffset,
+          Map<Abi, int> offsets, FfiTransformer transformer) =>
+      ReturnStatement(StaticInvocation(
+          transformer.fromAddressInternal,
+          Arguments([
+            StaticInvocation(
+                transformer.loadMethods[NativeType.kIntptr],
+                Arguments([
+                  PropertyGet(ThisExpression(), transformer.addressOfField.name,
+                      transformer.addressOfField)
+                    ..fileOffset = fileOffset,
+                  transformer.runtimeBranchOnLayout(offsets)
+                ]))
+              ..fileOffset = fileOffset
+          ], types: [
+            (dartType as InterfaceType).typeArguments.single
+          ]))
+        ..fileOffset = fileOffset);
+
+  /// Sample output for `set x(Pointer<Int8> #v) =>`:
+  ///
+  /// ```
+  /// _storeIntPtr(_addressOf, offset, (#v as Pointer<Int8>).address);
+  /// ```
+  @override
+  ReturnStatement generateSetterStatement(
+          DartType dartType,
+          int fileOffset,
+          Map<Abi, int> offsets,
+          VariableDeclaration argument,
+          FfiTransformer transformer) =>
+      ReturnStatement(StaticInvocation(
+          transformer.storeMethods[NativeType.kIntptr],
+          Arguments([
+            PropertyGet(ThisExpression(), transformer.addressOfField.name,
+                transformer.addressOfField)
+              ..fileOffset = fileOffset,
+            transformer.runtimeBranchOnLayout(offsets),
+            PropertyGet(VariableGet(argument), transformer.addressGetter.name,
+                transformer.addressGetter)
+              ..fileOffset = fileOffset
+          ]))
+        ..fileOffset = fileOffset);
+}
+
+class StructNativeTypeCfe implements NativeTypeCfe {
+  final Class clazz;
+
+  final List<NativeTypeCfe> members;
+
+  final Map<Abi, StructLayout> layout;
+
+  factory StructNativeTypeCfe(Class clazz, List<NativeTypeCfe> members) {
+    final layout = Map.fromEntries(
+        Abi.values.map((abi) => MapEntry(abi, _calculateLayout(members, abi))));
+    return StructNativeTypeCfe._(clazz, members, layout);
+  }
+
+  // Keep consistent with runtime/vm/compiler/ffi/native_type.cc
+  // NativeCompoundType::FromNativeTypes.
+  static StructLayout _calculateLayout(List<NativeTypeCfe> types, Abi abi) {
+    int offset = 0;
+    final offsets = <int>[];
+    int structAlignment = 1;
+    for (int i = 0; i < types.length; i++) {
+      final int size = types[i].size[abi];
+      final int alignment = types[i].alignment[abi];
+      offset = _alignOffset(offset, alignment);
+      offsets.add(offset);
+      offset += size;
+      structAlignment = math.max(structAlignment, alignment);
+    }
+    final int size = _alignOffset(offset, structAlignment);
+    return StructLayout(size, structAlignment, offsets);
+  }
+
+  StructNativeTypeCfe._(this.clazz, this.members, this.layout);
+
+  @override
+  Map<Abi, int> get size =>
+      layout.map((abi, layout) => MapEntry(abi, layout.size));
+
+  @override
+  Map<Abi, int> get alignment =>
+      layout.map((abi, layout) => MapEntry(abi, layout.alignment));
+
+  @override
+  Constant generateConstant(FfiTransformer transformer) =>
+      TypeLiteralConstant(InterfaceType(clazz, Nullability.nonNullable));
+
+  /// Sample output for `MyStruct get x =>`:
+  ///
+  /// ```
+  /// MyStruct.#fromTypedDataBase(
+  ///   typedDataBaseOffset(_addressOf, offset, size, dartType)
+  /// );
+  /// ```
+  @override
+  ReturnStatement generateGetterStatement(DartType dartType, int fileOffset,
+      Map<Abi, int> offsets, FfiTransformer transformer) {
+    final constructor = clazz.constructors
+        .firstWhere((c) => c.name == Name("#fromTypedDataBase"));
+
+    return ReturnStatement(ConstructorInvocation(
+        constructor,
+        Arguments([
+          transformer.typedDataBaseOffset(
+              PropertyGet(ThisExpression(), transformer.addressOfField.name,
+                  transformer.addressOfField)
+                ..fileOffset = fileOffset,
+              transformer.runtimeBranchOnLayout(offsets),
+              transformer.runtimeBranchOnLayout(size),
+              dartType,
+              fileOffset)
+        ]))
+      ..fileOffset = fileOffset);
+  }
+
+  /// Sample output for `set x(MyStruct #v) =>`:
+  ///
+  /// ```
+  /// _memCopy(_addressOf, offset, #v._addressOf, 0, size);
+  /// ```
+  @override
+  ReturnStatement generateSetterStatement(
+          DartType dartType,
+          int fileOffset,
+          Map<Abi, int> offsets,
+          VariableDeclaration argument,
+          FfiTransformer transformer) =>
+      ReturnStatement(StaticInvocation(
+          transformer.memCopy,
+          Arguments([
+            PropertyGet(ThisExpression(), transformer.addressOfField.name,
+                transformer.addressOfField)
+              ..fileOffset = fileOffset,
+            transformer.runtimeBranchOnLayout(offsets),
+            PropertyGet(VariableGet(argument), transformer.addressOfField.name,
+                transformer.addressOfField)
+              ..fileOffset = fileOffset,
+            ConstantExpression(IntConstant(0)),
+            transformer.runtimeBranchOnLayout(size),
+          ]))
+        ..fileOffset = fileOffset);
+}
+
+int _alignOffset(int offset, int alignment) =>
+    ((offset + alignment - 1) ~/ alignment) * alignment;
diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart
index 1f0aba6..c03f4b4 100644
--- a/pkg/vm/lib/transformations/ffi_use_sites.dart
+++ b/pkg/vm/lib/transformations/ffi_use_sites.dart
@@ -76,9 +76,7 @@
   final Set<Class> emptyStructs;
   StaticTypeContext _staticTypeContext;
 
-  Library currentLibrary;
   bool get isFfiLibrary => currentLibrary == ffiLibrary;
-  IndexedLibrary currentLibraryIndex;
 
   // Used to create private top-level fields with unique names for each
   // callback.
@@ -98,8 +96,6 @@
 
   @override
   TreeNode visitLibrary(Library node) {
-    currentLibrary = node;
-    currentLibraryIndex = referenceFromIndex?.lookupLibrary(node);
     callbackCount = 0;
     return super.visitLibrary(node);
   }
diff --git a/runtime/bin/main_options.cc b/runtime/bin/main_options.cc
index 1bc116d..e60f6c8 100644
--- a/runtime/bin/main_options.cc
+++ b/runtime/bin/main_options.cc
@@ -523,7 +523,8 @@
     // The analytics flags are a special case as we don't have a target script
     // or DartDev command but we still want to launch DartDev.
     DartDevIsolate::set_should_run_dart_dev(true);
-
+    dart_options->AddArgument(enable_dartdev_analytics ? "--enable-analytics"
+                                                       : "--disable-analytics");
     return true;
   }
 
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index a90d4de..11b7f60 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -225,13 +225,13 @@
 DEFINE_NATIVE_ENTRY(LibraryPrefix_isLoaded, 0, 1) {
   const LibraryPrefix& prefix =
       LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
-  return Bool::Get(prefix.is_loaded()).ptr();
+  return Bool::Get(isolate->IsPrefixLoaded(prefix)).ptr();
 }
 
 DEFINE_NATIVE_ENTRY(LibraryPrefix_setLoaded, 0, 1) {
   const LibraryPrefix& prefix =
       LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
-  prefix.set_is_loaded(true);
+  isolate->SetPrefixIsLoaded(prefix);
   return Instance::null();
 }
 
diff --git a/runtime/tests/vm/dart/deferred_isolate_test.dart b/runtime/tests/vm/dart/deferred_isolate_test.dart
new file mode 100644
index 0000000..d056b31
--- /dev/null
+++ b/runtime/tests/vm/dart/deferred_isolate_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify deferred library status is per-isolate, not per-isolate-group.
+
+// VMOptions=--enable_isolate_groups --experimental_enable_isolate_groups_jit
+
+import 'dart:async';
+import 'dart:isolate';
+import 'package:expect/expect.dart';
+
+import "splay_test.dart" deferred as splay;
+
+worker(SendPort sendPort) {
+  Expect.throws(() => splay.main(),
+      (e) => e.toString() == "Deferred library splay was not loaded.");
+  sendPort.send(true);
+}
+
+main() async {
+  await splay.loadLibrary();
+  splay.main();
+  final receivePort = ReceivePort();
+  Isolate.spawn(worker, receivePort.sendPort);
+  Expect.isTrue(await receivePort.first);
+  receivePort.close();
+}
diff --git a/runtime/tests/vm/dart_2/deferred_isolate_test.dart b/runtime/tests/vm/dart_2/deferred_isolate_test.dart
new file mode 100644
index 0000000..d056b31
--- /dev/null
+++ b/runtime/tests/vm/dart_2/deferred_isolate_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify deferred library status is per-isolate, not per-isolate-group.
+
+// VMOptions=--enable_isolate_groups --experimental_enable_isolate_groups_jit
+
+import 'dart:async';
+import 'dart:isolate';
+import 'package:expect/expect.dart';
+
+import "splay_test.dart" deferred as splay;
+
+worker(SendPort sendPort) {
+  Expect.throws(() => splay.main(),
+      (e) => e.toString() == "Deferred library splay was not loaded.");
+  sendPort.send(true);
+}
+
+main() async {
+  await splay.loadLibrary();
+  splay.main();
+  final receivePort = ReceivePort();
+  Isolate.spawn(worker, receivePort.sendPort);
+  Expect.isTrue(await receivePort.first);
+  receivePort.close();
+}
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 44a7888..964aafd 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -279,6 +279,10 @@
 dart_2/null_safety_autodetection_in_kernel_compiler_test: SkipByDesign # Test needs to run from source
 dart_2/snapshot_depfile_test: SkipByDesign # Test needs to run from source
 
+[ $compiler == dartkp && ($arch == simarm || $arch == simarm64) ]
+dart/causal_stacks/async_throws_stack_lazy_non_symbolic_test: Pass, Slow
+dart_2/causal_stacks/async_throws_stack_lazy_non_symbolic_test: Pass, Slow
+
 [ $compiler == dartkp && ($runtime == dart_precompiled || $runtime == vm) ]
 dart/redirection_type_shuffling_test: SkipByDesign # Includes dart:mirrors.
 dart/spawn_shutdown_test: SkipSlow
diff --git a/runtime/vm/bitmap.cc b/runtime/vm/bitmap.cc
index 334c46b..52c32db 100644
--- a/runtime/vm/bitmap.cc
+++ b/runtime/vm/bitmap.cc
@@ -42,11 +42,13 @@
 void BitmapBuilder::Set(intptr_t bit_offset, bool value) {
   if (!InRange(bit_offset)) {
     length_ = bit_offset + 1;
-    // Bits not covered by the backing store are implicitly false.
-    if (!value) return;
-    // Grow the backing store if necessary.
-    intptr_t byte_offset = bit_offset >> kBitsPerByteLog2;
-    if (byte_offset >= data_size_in_bytes_) {
+  }
+
+  // Bits not covered by the backing store are implicitly false.
+  // Grow the backing store if necessary.
+  if (value) {
+    if (!InBackingStore(bit_offset)) {
+      intptr_t byte_offset = bit_offset >> kBitsPerByteLog2;
       uint8_t* old_data = data_;
       intptr_t old_size = data_size_in_bytes_;
       data_size_in_bytes_ =
@@ -57,8 +59,13 @@
       memmove(data_, old_data, old_size);
       memset(&data_[old_size], 0, (data_size_in_bytes_ - old_size));
     }
+    ASSERT(InBackingStore(bit_offset));
   }
-  SetBit(bit_offset, value);
+
+  // Set bit if in backing store.
+  if (InBackingStore(bit_offset)) {
+    SetBit(bit_offset, value);
+  }
 }
 
 void BitmapBuilder::SetRange(intptr_t min, intptr_t max, bool value) {
diff --git a/runtime/vm/bitmap.h b/runtime/vm/bitmap.h
index ed08009..1fce760 100644
--- a/runtime/vm/bitmap.h
+++ b/runtime/vm/bitmap.h
@@ -60,6 +60,11 @@
     return (offset < length_);
   }
 
+  bool InBackingStore(intptr_t bit_offset) {
+    intptr_t byte_offset = bit_offset >> kBitsPerByteLog2;
+    return byte_offset < data_size_in_bytes_;
+  }
+
   // Get/Set a bit that is known to be covered by the backing store.
   bool GetBit(intptr_t bit_offset) const;
   void SetBit(intptr_t bit_offset, bool value);
diff --git a/runtime/vm/bitmap_test.cc b/runtime/vm/bitmap_test.cc
index c3cd203..2fdab17 100644
--- a/runtime/vm/bitmap_test.cc
+++ b/runtime/vm/bitmap_test.cc
@@ -131,4 +131,14 @@
   EXPECT(builder1->Get(900));
 }
 
+ISOLATE_UNIT_TEST_CASE(BitmapBuilder_Regress44946) {
+  BitmapBuilder* builder1 = new BitmapBuilder();
+  EXPECT_EQ(0, builder1->Length());
+
+  builder1->Set(10000, false);
+  EXPECT_EQ(10001, builder1->Length());
+  builder1->Set(9999, true);
+  EXPECT(builder1->Get(9999));
+}
+
 }  // namespace dart
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index b623a08..45bced2 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -3360,7 +3360,6 @@
       ReadFromTo(prefix);
       prefix->untag()->num_imports_ = d->Read<uint16_t>();
       prefix->untag()->is_deferred_load_ = d->Read<bool>();
-      prefix->untag()->is_loaded_ = !prefix->untag()->is_deferred_load_;
     }
   }
 };
diff --git a/runtime/vm/compiler/assembler/disassembler_arm.cc b/runtime/vm/compiler/assembler/disassembler_arm.cc
index 2195070..946c402 100644
--- a/runtime/vm/compiler/assembler/disassembler_arm.cc
+++ b/runtime/vm/compiler/assembler/disassembler_arm.cc
@@ -104,24 +104,11 @@
   Print(cond_names[instr->ConditionField()]);
 }
 
-// These register names are defined in a way to match the native disassembler
-// formatting, except for register alias pp (r5).
-// See for example the command "objdump -d <binary file>".
-static const char* reg_names[kNumberOfCpuRegisters] = {
-#if defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS)
-    "r0", "r1", "r2",  "r3",  "r4", "pp", "r6", "fp",
-    "r8", "r9", "thr", "r11", "ip", "sp", "lr", "pc",
-#else
-    "r0", "r1", "r2",  "r3", "r4", "pp", "r6", "r7",
-    "r8", "r9", "thr", "fp", "ip", "sp", "lr", "pc",
-#endif
-};
-
 // Print the register name according to the active name converter.
 void ARMDecoder::PrintRegister(int reg) {
   ASSERT(0 <= reg);
   ASSERT(reg < kNumberOfCpuRegisters);
-  Print(reg_names[reg]);
+  Print(cpu_reg_names[reg]);
 }
 
 void ARMDecoder::PrintSRegister(int reg) {
diff --git a/runtime/vm/compiler/assembler/disassembler_arm64.cc b/runtime/vm/compiler/assembler/disassembler_arm64.cc
index e0992ae..fad4210 100644
--- a/runtime/vm/compiler/assembler/disassembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/disassembler_arm64.cc
@@ -80,15 +80,6 @@
   buffer_[buffer_pos_] = '\0';
 }
 
-// These register names are defined in a way to match the native disassembler
-// formatting, except for register aliases ctx (r9), pp (r10) and sp (r19).
-// See for example the command "objdump -d <binary file>".
-static const char* reg_names[kNumberOfCpuRegisters] = {
-    "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",  "r8", "r9",  "r10",
-    "r11", "r12", "r13", "r14", "r15", "ip0", "ip1", "r18", "sp", "r20", "r21",
-    "nr",  "r23", "r24", "r25", "thr", "pp",  "ctx", "fp",  "lr", "r31",
-};
-
 // Print the register name according to the active name converter.
 void ARM64Decoder::PrintRegister(int reg, R31Type r31t) {
   ASSERT(0 <= reg);
@@ -97,7 +88,7 @@
     const char* rstr = (r31t == R31IsZR) ? "zr" : "csp";
     Print(rstr);
   } else {
-    Print(reg_names[reg]);
+    Print(cpu_reg_names[reg]);
   }
 }
 
diff --git a/runtime/vm/compiler/backend/inliner.cc b/runtime/vm/compiler/backend/inliner.cc
index ce2f680..acb987e 100644
--- a/runtime/vm/compiler/backend/inliner.cc
+++ b/runtime/vm/compiler/backend/inliner.cc
@@ -2266,13 +2266,15 @@
 bool FlowGraphInliner::FunctionHasPreferInlinePragma(const Function& function) {
   Object& options = Object::Handle();
   return Library::FindPragma(dart::Thread::Current(), /*only_core=*/false,
-                             function, Symbols::vm_prefer_inline(), &options);
+                             function, Symbols::vm_prefer_inline(),
+                             /*multiple=*/false, &options);
 }
 
 bool FlowGraphInliner::FunctionHasNeverInlinePragma(const Function& function) {
   Object& options = Object::Handle();
   return Library::FindPragma(dart::Thread::Current(), /*only_core=*/false,
-                             function, Symbols::vm_never_inline(), &options);
+                             function, Symbols::vm_never_inline(),
+                             /*multiple=*/false, &options);
 }
 
 bool FlowGraphInliner::AlwaysInline(const Function& function) {
@@ -2891,7 +2893,6 @@
   (*entry)->InheritDeoptTarget(Z, call);
   Instruction* cursor = *entry;
 
-
   // Generates a template for the load, either a dynamic conditional
   // that dispatches on external and internal storage, or a single
   // case that deals with either external or internal storage.
diff --git a/runtime/vm/compiler/backend/redundancy_elimination.cc b/runtime/vm/compiler/backend/redundancy_elimination.cc
index 03d3c39..d63933e 100644
--- a/runtime/vm/compiler/backend/redundancy_elimination.cc
+++ b/runtime/vm/compiler/backend/redundancy_elimination.cc
@@ -4230,7 +4230,8 @@
   Object& options = Object::Handle();
   return Library::FindPragma(dart::Thread::Current(),
                              /*only_core=*/false, function,
-                             Symbols::vm_unsafe_no_interrupts(), &options);
+                             Symbols::vm_unsafe_no_interrupts(),
+                             /*multiple=*/false, &options);
 }
 
 void CheckStackOverflowElimination::EliminateStackOverflow(FlowGraph* graph) {
diff --git a/runtime/vm/compiler/backend/type_propagator_test.cc b/runtime/vm/compiler/backend/type_propagator_test.cc
index a278009..1090bc9 100644
--- a/runtime/vm/compiler/backend/type_propagator_test.cc
+++ b/runtime/vm/compiler/backend/type_propagator_test.cc
@@ -467,7 +467,7 @@
   auto expected_can_be_smi = [&](const Field& f) {
     auto& options = Object::Handle();
     return lib.FindPragma(thread, /*only_core=*/false, f, pragma_can_be_smi,
-                          &options);
+                          /*multiple=*/false, &options);
   };
 
   const auto& cls = Class::Handle(GetClass(lib, "C"));
diff --git a/runtime/vm/compiler/ffi/native_type.cc b/runtime/vm/compiler/ffi/native_type.cc
index 7e1ade5..0e0d125 100644
--- a/runtime/vm/compiler/ffi/native_type.cc
+++ b/runtime/vm/compiler/ffi/native_type.cc
@@ -366,21 +366,57 @@
   // User-defined structs.
   const auto& cls = Class::Handle(zone, type.type_class());
 
-  auto& options = Object::Handle(zone);
+  auto& pragmas = Object::Handle(zone);
   Library::FindPragma(dart::Thread::Current(), /*only_core=*/false, cls,
-                      Symbols::vm_ffi_struct_fields(), &options);
-  ASSERT(!options.IsNull());
-  ASSERT(options.IsArray());
+                      Symbols::vm_ffi_struct_fields(), /*multiple=*/true,
+                      &pragmas);
+  ASSERT(!pragmas.IsNull());
+  ASSERT(pragmas.IsGrowableObjectArray());
+  const auto& pragmas_array = GrowableObjectArray::Cast(pragmas);
+  auto& pragma = Instance::Handle(zone);
+  auto& clazz = Class::Handle(zone);
+  auto& library = Library::Handle(zone);
+  for (intptr_t i = 0; i < pragmas_array.Length(); i++) {
+    pragma ^= pragmas_array.At(i);
+    clazz ^= pragma.clazz();
+    library ^= clazz.library();
+    if (String::Handle(zone, clazz.UserVisibleName())
+            .Equals(Symbols::FfiStructLayout()) &&
+        String::Handle(zone, library.url()).Equals(Symbols::DartFfi())) {
+      break;
+    }
+  }
 
-  const auto& field_types = Array::Cast(options);
+  const auto& struct_layout = pragma;
+  const auto& struct_layout_class = clazz;
+  ASSERT(String::Handle(zone, struct_layout_class.UserVisibleName())
+             .Equals(Symbols::FfiStructLayout()));
+  ASSERT(String::Handle(zone, library.url()).Equals(Symbols::DartFfi()));
+  const auto& struct_layout_fields = Array::Handle(zone, clazz.fields());
+  ASSERT(struct_layout_fields.Length() == 1);
+  const auto& field =
+      Field::Handle(zone, Field::RawCast(struct_layout_fields.At(0)));
+  ASSERT(String::Handle(zone, field.name()).Equals(Symbols::FfiFieldTypes()));
+  const auto& field_types =
+      Array::Handle(zone, Array::RawCast(struct_layout.GetField(field)));
+
+  auto& field_instance = Instance::Handle(zone);
   auto& field_type = AbstractType::Handle(zone);
   auto& field_native_types = *new (zone) ZoneGrowableArray<const NativeType*>(
       zone, field_types.Length());
   for (intptr_t i = 0; i < field_types.Length(); i++) {
-    field_type ^= field_types.At(i);
-    const NativeType& field_native_type =
-        NativeType::FromAbstractType(zone, field_type);
-    field_native_types.Add(&field_native_type);
+    field_instance ^= field_types.At(i);
+    if (field_instance.IsAbstractType()) {
+      // Subtype of NativeType: Struct, native integer or native float.
+      field_type ^= field_types.At(i);
+      const auto& field_native_type =
+          NativeType::FromAbstractType(zone, field_type);
+      field_native_types.Add(&field_native_type);
+    } else {
+      // Inline array.
+      // TODO(http://dartbug.com/35763): Implement this.
+      UNIMPLEMENTED();
+    }
   }
 
   return NativeCompoundType::FromNativeTypes(zone, field_native_types);
diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
index c931003..f8fd87c 100644
--- a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
@@ -1121,7 +1121,8 @@
 
   Object& options = Object::Handle(Z);
   if (!Library::FindPragma(thread_, /*only_core=*/false, function,
-                           Symbols::vm_trace_entrypoints(), &options) ||
+                           Symbols::vm_trace_entrypoints(), /*multiple=*/false,
+                           &options) ||
       options.IsNull() || !options.IsClosure()) {
     return Drop();
   }
diff --git a/runtime/vm/compiler/method_recognizer.cc b/runtime/vm/compiler/method_recognizer.cc
index 3abd57b..6a6bd41 100644
--- a/runtime/vm/compiler/method_recognizer.cc
+++ b/runtime/vm/compiler/method_recognizer.cc
@@ -29,7 +29,8 @@
   auto Z = T->zone();
   auto& option = Object::Handle(Z);
   if (Library::FindPragma(T, /*only_core=*/true, function_or_field,
-                          Symbols::vm_exact_result_type(), &option)) {
+                          Symbols::vm_exact_result_type(),
+                          /*multiple=*/false, &option)) {
     if (option.IsType()) {
       return Type::Cast(option).type_class_id();
     } else if (option.IsString()) {
@@ -82,7 +83,8 @@
   auto Z = T->zone();
   auto& option = Object::Handle(Z);
   if (Library::FindPragma(T, /*only_core=*/true, function_or_field,
-                          Symbols::vm_non_nullable_result_type(), &option)) {
+                          Symbols::vm_non_nullable_result_type(),
+                          /*multiple=*/false, &option)) {
     return true;
   }
 
@@ -203,9 +205,9 @@
           ? &Function::Handle(function.ForwardingTarget())
           : &function;
   Object& options = Object::Handle();
-  bool is_recognized =
-      Library::FindPragma(Thread::Current(), /*only_core=*/true, *functionp,
-                          Symbols::vm_recognized(), &options);
+  bool is_recognized = Library::FindPragma(
+      Thread::Current(), /*only_core=*/true, *functionp,
+      Symbols::vm_recognized(), /*multiple=*/false, &options);
   if (!is_recognized) return false;
   if (kind == nullptr) return true;
 
diff --git a/runtime/vm/constants_arm.cc b/runtime/vm/constants_arm.cc
index 1f33275..21ae852 100644
--- a/runtime/vm/constants_arm.cc
+++ b/runtime/vm/constants_arm.cc
@@ -13,8 +13,13 @@
 using dart::bit_cast;
 
 const char* cpu_reg_names[kNumberOfCpuRegisters] = {
-    "r0", "r1",  "r2", "r3", "r4", "r5", "r6", "r7",
-    "r8", "ctx", "pp", "fp", "ip", "sp", "lr", "pc",
+#if defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS)
+    "r0", "r1", "r2",  "r3",  "r4", "pp", "r6", "fp",
+    "r8", "r9", "thr", "r11", "ip", "sp", "lr", "pc",
+#else
+    "r0", "r1", "r2",  "r3", "r4", "pp", "r6", "r7",
+    "r8", "r9", "thr", "fp", "ip", "sp", "lr", "pc",
+#endif
 };
 
 const char* fpu_reg_names[kNumberOfFpuRegisters] = {
diff --git a/runtime/vm/constants_arm64.cc b/runtime/vm/constants_arm64.cc
index e0999b9..7945838 100644
--- a/runtime/vm/constants_arm64.cc
+++ b/runtime/vm/constants_arm64.cc
@@ -13,7 +13,7 @@
 const char* cpu_reg_names[kNumberOfCpuRegisters] = {
     "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",  "r8",  "r9",  "r10",
     "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21",
-    "nr",  "r23", "r24", "ip0", "ip1", "pp",  "ctx", "fp",  "lr",  "r31",
+    "nr",  "r23", "r24", "ip0", "ip1", "pp",  "r28", "fp",  "lr",  "r31",
 };
 
 const char* fpu_reg_names[kNumberOfFpuRegisters] = {
diff --git a/runtime/vm/constants_ia32.h b/runtime/vm/constants_ia32.h
index d5242f1..da4d058 100644
--- a/runtime/vm/constants_ia32.h
+++ b/runtime/vm/constants_ia32.h
@@ -21,9 +21,9 @@
   ECX = 1,
   EDX = 2,
   EBX = 3,
-  ESP = 4,
-  EBP = 5,
-  ESI = 6,
+  ESP = 4,  // SP
+  EBP = 5,  // FP
+  ESI = 6,  // THR
   EDI = 7,
   kNumberOfCpuRegisters = 8,
   kNoRegister = -1,  // Signals an illegal register.
diff --git a/runtime/vm/constants_x64.h b/runtime/vm/constants_x64.h
index 8ebeb8e..d8ffa7c 100644
--- a/runtime/vm/constants_x64.h
+++ b/runtime/vm/constants_x64.h
@@ -21,8 +21,8 @@
   RCX = 1,
   RDX = 2,
   RBX = 3,
-  RSP = 4,
-  RBP = 5,
+  RSP = 4,  // SP
+  RBP = 5,  // FP
   RSI = 6,
   RDI = 7,
   R8 = 8,
@@ -31,8 +31,8 @@
   R11 = 11,
   R12 = 12,
   R13 = 13,
-  R14 = 14,
-  R15 = 15,
+  R14 = 14,  // THR
+  R15 = 15,  // PP
   kNumberOfCpuRegisters = 16,
   kNoRegister = -1,  // Signals an illegal register.
 };
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 76e5444..c1259f2 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -978,6 +978,8 @@
   const UserTag& default_tag = UserTag::Handle(UserTag::DefaultTag());
   I->set_current_tag(default_tag);
 
+  I->init_loaded_prefixes_set_storage();
+
   return Error::null();
 }
 
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 84cb544..5fff56a 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -1661,6 +1661,24 @@
 
 #define REUSABLE_HANDLE_INITIALIZERS(object) object##_handle_(nullptr),
 
+class LibraryPrefixMapTraits {
+ public:
+  static bool ReportStats() { return false; }
+  static const char* Name() { return "LibraryPrefixMapTraits"; }
+
+  static bool IsMatch(const Object& a, const Object& b) {
+    if (!a.IsLibraryPrefix() || !b.IsLibraryPrefix()) {
+      return false;
+    }
+    return a.ptr() == b.ptr();
+  }
+
+  static uword Hash(const Object& obj) {
+    auto& prefix = LibraryPrefix::Cast(obj);
+    return String::Hash(prefix.name());
+  }
+};
+
 // TODO(srdjan): Some Isolate monitors can be shared. Replace their usage with
 // that shared monitor.
 Isolate::Isolate(IsolateGroup* isolate_group,
@@ -1699,7 +1717,8 @@
       sticky_error_(Error::null()),
       spawn_count_monitor_(),
       handler_info_cache_(),
-      catch_entry_moves_cache_() {
+      catch_entry_moves_cache_(),
+      loaded_prefixes_set_storage_(nullptr) {
   cached_object_store_ = object_store_shared_ptr_.get();
   cached_class_table_table_ = group()->class_table_->table();
   FlagsCopyFrom(api_flags);
@@ -2621,6 +2640,9 @@
     deopt_context()->VisitObjectPointers(visitor);
   }
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
+
+  visitor->VisitPointer(
+      reinterpret_cast<ObjectPtr*>(&loaded_prefixes_set_storage_));
 }
 
 void IsolateGroup::ReleaseStoreBuffers() {
@@ -2639,6 +2661,27 @@
   }
 }
 
+void Isolate::init_loaded_prefixes_set_storage() {
+  ASSERT(loaded_prefixes_set_storage_ == nullptr);
+  loaded_prefixes_set_storage_ =
+      HashTables::New<UnorderedHashSet<LibraryPrefixMapTraits> >(4);
+}
+
+bool Isolate::IsPrefixLoaded(const LibraryPrefix& prefix) const {
+  UnorderedHashSet<LibraryPrefixMapTraits> loaded_prefixes_set(
+      loaded_prefixes_set_storage_);
+  bool result = loaded_prefixes_set.GetOrNull(prefix) != Object::null();
+  loaded_prefixes_set.Release();
+  return result;
+}
+
+void Isolate::SetPrefixIsLoaded(const LibraryPrefix& prefix) {
+  UnorderedHashSet<LibraryPrefixMapTraits> loaded_prefixes_set(
+      loaded_prefixes_set_storage_);
+  loaded_prefixes_set.InsertOrGet(prefix);
+  loaded_prefixes_set_storage_ = loaded_prefixes_set.Release().ptr();
+}
+
 void IsolateGroup::EnableIncrementalBarrier(
     MarkingStack* marking_stack,
     MarkingStack* deferred_marking_stack) {
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index ceca443..fefa565 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -1460,6 +1460,10 @@
     regexp_backtracking_stack_cache_ = std::move(stack);
   }
 
+  void init_loaded_prefixes_set_storage();
+  bool IsPrefixLoaded(const LibraryPrefix& prefix) const;
+  void SetPrefixIsLoaded(const LibraryPrefix& prefix);
+
  private:
   friend class Dart;                  // Init, InitOnce, Shutdown.
   friend class IsolateKillerVisitor;  // Kill().
@@ -1694,6 +1698,8 @@
   static Monitor* isolate_creation_monitor_;
   static bool creation_enabled_;
 
+  ArrayPtr loaded_prefixes_set_storage_;
+
 #define REUSABLE_FRIEND_DECLARATION(name)                                      \
   friend class Reusable##name##HandleScope;
   REUSABLE_HANDLE_LIST(REUSABLE_FRIEND_DECLARATION)
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index dcb54c3..4b38596 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -3621,6 +3621,7 @@
                          bool only_core,
                          const Object& obj,
                          const String& pragma_name,
+                         bool multiple,
                          Object* options) {
   auto IG = T->isolate_group();
   auto Z = T->zone();
@@ -3666,6 +3667,13 @@
       Field::Handle(Z, pragma_class.LookupField(Symbols::options()));
 
   auto& pragma = Object::Handle(Z);
+  bool found = false;
+  auto& options_value = Object::Handle(Z);
+  auto& results = GrowableObjectArray::Handle(Z);
+  if (multiple) {
+    ASSERT(options != nullptr);
+    results ^= GrowableObjectArray::New(1);
+  }
   for (intptr_t i = 0; i < metadata.Length(); ++i) {
     pragma = metadata.At(i);
     if (pragma.clazz() != pragma_class.ptr() ||
@@ -3673,13 +3681,22 @@
             pragma_name.ptr()) {
       continue;
     }
+    options_value = Instance::Cast(pragma).GetField(pragma_options_field);
+    found = true;
+    if (multiple) {
+      results.Add(options_value);
+      continue;
+    }
     if (options != nullptr) {
-      *options = Instance::Cast(pragma).GetField(pragma_options_field);
+      *options = options_value.ptr();
     }
     return true;
   }
 
-  return false;
+  if (found && options != nullptr) {
+    *options = results.ptr();
+  }
+  return found;
 }
 
 bool Function::IsDynamicInvocationForwarderName(const String& name) {
@@ -13450,7 +13467,6 @@
   result.set_num_imports(0);
   result.set_importer(importer);
   result.StoreNonPointer(&result.untag()->is_deferred_load_, deferred_load);
-  result.StoreNonPointer(&result.untag()->is_loaded_, !deferred_load);
   result.set_imports(Array::Handle(Array::New(kInitialSize)));
   result.AddImport(import);
   return result.ptr();
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 0739a20..5cf9f6c 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -4658,12 +4658,16 @@
   // If [only_core] is true, then the annotations on the object will only
   // be inspected if it is part of a core library.
   //
+  // If [multiple] is true, then sets [options] to an GrowableObjectArray
+  // containing all results and [options] may not be nullptr.
+  //
   // WARNING: If the isolate received an [UnwindError] this function will not
   // return and rather unwinds until the enclosing setjmp() handler.
   static bool FindPragma(Thread* T,
                          bool only_core,
                          const Object& object,
                          const String& pragma_name,
+                         bool multiple = false,
                          Object* options = nullptr);
 
   ClassPtr toplevel_class() const { return untag()->toplevel_class(); }
@@ -6144,11 +6148,9 @@
     explicit Comments(const Array& comments);
 
     // Layout of entries describing comments.
-    enum {
-      kPCOffsetEntry = 0,  // PC offset to a comment as a Smi.
-      kCommentEntry,       // Comment text as a String.
-      kNumberOfEntries
-    };
+    enum {kPCOffsetEntry = 0,  // PC offset to a comment as a Smi.
+          kCommentEntry,       // Comment text as a String.
+          kNumberOfEntries};
 
     const Array& comments_;
     String& string_;
@@ -7262,10 +7264,6 @@
   void AddImport(const Namespace& import) const;
 
   bool is_deferred_load() const { return untag()->is_deferred_load_; }
-  bool is_loaded() const { return untag()->is_loaded_; }
-  void set_is_loaded(bool value) const {
-    return StoreNonPointer(&untag()->is_loaded_, value);
-  }
 
   static intptr_t InstanceSize() {
     return RoundedAllocationSize(sizeof(UntaggedLibraryPrefix));
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
index e9c33b4..d4472ac 100644
--- a/runtime/vm/object_reload.cc
+++ b/runtime/vm/object_reload.cc
@@ -852,12 +852,9 @@
       original_name = original_prefix.name();
       if (!name.Equals(original_name)) continue;
 
-      if (original_prefix.is_loaded()) {
-        prefix.set_is_loaded(true);
-      }
-
-      // The old prefix may be captured in the message queue for a pending load
-      // completion. This pending load should carry to the new prefix.
+      // The replacement of the old prefix with the new prefix
+      // in Isolate::loaded_prefixes_set_ implicitly carried
+      // the loaded state over to the new prefix.
       context->AddBecomeMapping(original_prefix, prefix);
     }
   }
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 8c041a2..ca51cc9 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -2239,7 +2239,6 @@
   }
   uint16_t num_imports_;  // Number of library entries in libraries_.
   bool is_deferred_load_;
-  bool is_loaded_;
 };
 
 class UntaggedTypeArguments : public UntaggedInstance {
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 39dfa25..631c7a8 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -124,6 +124,7 @@
   V(FfiCallback, "_FfiCallback")                                               \
   V(FfiDouble, "Double")                                                       \
   V(FfiDynamicLibrary, "DynamicLibrary")                                       \
+  V(FfiFieldTypes, "fieldTypes")                                               \
   V(FfiFloat, "Float")                                                         \
   V(FfiInt16, "Int16")                                                         \
   V(FfiInt32, "Int32")                                                         \
@@ -133,6 +134,7 @@
   V(FfiNativeFunction, "NativeFunction")                                       \
   V(FfiNativeType, "NativeType")                                               \
   V(FfiPointer, "Pointer")                                                     \
+  V(FfiStructLayout, "_FfiStructLayout")                                       \
   V(FfiTrampolineData, "FfiTrampolineData")                                    \
   V(FfiUint16, "Uint16")                                                       \
   V(FfiUint32, "Uint32")                                                       \
diff --git a/sdk/lib/_internal/vm/lib/ffi_struct_patch.dart b/sdk/lib/_internal/vm/lib/ffi_struct_patch.dart
index 8fad967..489dd6e 100644
--- a/sdk/lib/_internal/vm/lib/ffi_struct_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_struct_patch.dart
@@ -10,3 +10,11 @@
 
 @pragma("vm:entry-point")
 abstract class Struct extends NativeType {}
+
+@pragma("vm:entry-point")
+class _FfiStructLayout {
+  @pragma("vm:entry-point")
+  final List<Type> fieldTypes;
+
+  const _FfiStructLayout(this.fieldTypes);
+}
diff --git a/tools/VERSION b/tools/VERSION
index a31069b..de4905b 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 13
 PATCH 0
-PRERELEASE 26
+PRERELEASE 27
 PRERELEASE_PATCH 0
\ No newline at end of file