Version 2.18.0-264.0.dev

Merge commit '7b7a4665783f8857024cd6e80850ed8931973d9c' into 'dev'
diff --git a/DEPS b/DEPS
index 74fde4b..e9818b9 100644
--- a/DEPS
+++ b/DEPS
@@ -81,7 +81,7 @@
   "args_rev": "73e8d3b55cbedc9765f8e266f3422d8914f8e62a",
   "async_rev": "f3ed5f690e2ec9dbe1bfc5184705575b4f6480e5",
   "bazel_worker_rev": "9710de6c9c70b1b583183db9d9721ba64e5a16fe",
-  "benchmark_harness_rev": "f4ed0fcac4c284580263f0c548664dd548c9cca3",
+  "benchmark_harness_rev": "4183c76739ed7a27c260ca9ebaab6e0f210d1a37",
   "boolean_selector_rev": "1d3565e2651d16566bb556955b96ea75018cbd0c",
   "boringssl_gen_rev": "ced85ef0a00bbca77ce5a91261a5f2ae61b1e62f",
   "boringssl_rev": "87f316d7748268eb56f2dc147bd593254ae93198",
@@ -108,7 +108,7 @@
   # For more details, see https://github.com/dart-lang/sdk/issues/30164.
   "dart_style_rev": "d7b73536a8079331c888b7da539b80e6825270ea", # manually rev'd
 
-  "dartdoc_rev": "61dea6b8307392ee6dfe8fd952716b07f5243b1d",
+  "dartdoc_rev": "bf7cf5112bf2742a8fe05a5ec61377dc07f27cf7",
   "devtools_rev": "95d292626da26505b02417735f77e8922783b477",
   "ffi_rev": "18b2b549d55009ff594600b04705ff6161681e07",
   "file_rev": "0132eeedea2933513bf230513a766a8baeab0c4f",
@@ -135,7 +135,7 @@
   "path_rev": "7a0ed40280345b1c11df4c700c71e590738f4257",
   "ply_rev": "604b32590ffad5cbb82e4afef1d305512d06ae93",
   "pool_rev": "fa84ddd0e39f45bf3f09dcc5d6b9fbdda7820fef",
-  "protobuf_rev": "585878516d90b973ba47e2ffa295814ccaa19d3d",
+  "protobuf_rev": "7b20134b5609a4d25a57c7396e91b93ba60888d5",
   "pub_rev": "9bf4289d6fd5d6872a8929d6312bbd7098f3ea9c", # manually rev'd
   "pub_semver_rev": "5c0b4bfd5ca57fe16f1319c581dc8c882e9b8cb2",
   "root_certificates_rev": "692f6d6488af68e0121317a9c2c9eb393eb0ee50",
diff --git a/pkg/analysis_server/lib/lsp_protocol/protocol_custom_generated.dart b/pkg/analysis_server/lib/lsp_protocol/protocol_custom_generated.dart
index 1c684d6..ac255c9 100644
--- a/pkg/analysis_server/lib/lsp_protocol/protocol_custom_generated.dart
+++ b/pkg/analysis_server/lib/lsp_protocol/protocol_custom_generated.dart
@@ -143,6 +143,10 @@
   );
 
   static CompletionItemResolutionInfo fromJson(Map<String, Object?> json) {
+    if (DartNotImportedCompletionResolutionInfo.canParse(
+        json, nullLspJsonReporter)) {
+      return DartNotImportedCompletionResolutionInfo.fromJson(json);
+    }
     if (DartSuggestionSetCompletionItemResolutionInfo.canParse(
         json, nullLspJsonReporter)) {
       return DartSuggestionSetCompletionItemResolutionInfo.fromJson(json);
@@ -229,6 +233,78 @@
   String toString() => jsonEncoder.convert(toJson());
 }
 
+class DartNotImportedCompletionResolutionInfo
+    implements CompletionItemResolutionInfo, ToJsonable {
+  static const jsonHandler = LspJsonHandler(
+    DartNotImportedCompletionResolutionInfo.canParse,
+    DartNotImportedCompletionResolutionInfo.fromJson,
+  );
+
+  DartNotImportedCompletionResolutionInfo({
+    required this.file,
+    required this.libraryUri,
+  });
+  static DartNotImportedCompletionResolutionInfo fromJson(
+      Map<String, Object?> json) {
+    final fileJson = json['file'];
+    final file = fileJson as String;
+    final libraryUriJson = json['libraryUri'];
+    final libraryUri = libraryUriJson as String;
+    return DartNotImportedCompletionResolutionInfo(
+      file: file,
+      libraryUri: libraryUri,
+    );
+  }
+
+  /// The file where the completion is being inserted.
+  ///
+  /// This is used to compute where to add the import.
+  final String file;
+
+  /// The URI to be imported if this completion is selected.
+  final String libraryUri;
+
+  @override
+  Map<String, Object?> toJson() {
+    var result = <String, Object?>{};
+    result['file'] = file;
+    result['libraryUri'] = libraryUri;
+    return result;
+  }
+
+  static bool canParse(Object? obj, LspJsonReporter reporter) {
+    if (obj is Map<String, Object?>) {
+      if (!_canParseString(obj, reporter, 'file',
+          allowsUndefined: false, allowsNull: false)) {
+        return false;
+      }
+      return _canParseString(obj, reporter, 'libraryUri',
+          allowsUndefined: false, allowsNull: false);
+    } else {
+      reporter.reportError(
+          'must be of type DartNotImportedCompletionResolutionInfo');
+      return false;
+    }
+  }
+
+  @override
+  bool operator ==(Object other) {
+    return other is DartNotImportedCompletionResolutionInfo &&
+        other.runtimeType == DartNotImportedCompletionResolutionInfo &&
+        file == other.file &&
+        libraryUri == other.libraryUri;
+  }
+
+  @override
+  int get hashCode => Object.hash(
+        file,
+        libraryUri,
+      );
+
+  @override
+  String toString() => jsonEncoder.convert(toJson());
+}
+
 class DartSuggestionSetCompletionItemResolutionInfo
     implements CompletionItemResolutionInfo, ToJsonable {
   static const jsonHandler = LspJsonHandler(
@@ -237,89 +313,39 @@
   );
 
   DartSuggestionSetCompletionItemResolutionInfo({
-    required this.displayUri,
     required this.file,
-    required this.iLength,
     required this.libId,
-    required this.offset,
-    required this.rLength,
-    required this.rOffset,
   });
   static DartSuggestionSetCompletionItemResolutionInfo fromJson(
       Map<String, Object?> json) {
-    final displayUriJson = json['displayUri'];
-    final displayUri = displayUriJson as String;
     final fileJson = json['file'];
     final file = fileJson as String;
-    final iLengthJson = json['iLength'];
-    final iLength = iLengthJson as int;
     final libIdJson = json['libId'];
     final libId = libIdJson as int;
-    final offsetJson = json['offset'];
-    final offset = offsetJson as int;
-    final rLengthJson = json['rLength'];
-    final rLength = rLengthJson as int;
-    final rOffsetJson = json['rOffset'];
-    final rOffset = rOffsetJson as int;
     return DartSuggestionSetCompletionItemResolutionInfo(
-      displayUri: displayUri,
       file: file,
-      iLength: iLength,
       libId: libId,
-      offset: offset,
-      rLength: rLength,
-      rOffset: rOffset,
     );
   }
 
-  final String displayUri;
   final String file;
-  final int iLength;
   final int libId;
-  final int offset;
-  final int rLength;
-  final int rOffset;
 
   @override
   Map<String, Object?> toJson() {
     var result = <String, Object?>{};
-    result['displayUri'] = displayUri;
     result['file'] = file;
-    result['iLength'] = iLength;
     result['libId'] = libId;
-    result['offset'] = offset;
-    result['rLength'] = rLength;
-    result['rOffset'] = rOffset;
     return result;
   }
 
   static bool canParse(Object? obj, LspJsonReporter reporter) {
     if (obj is Map<String, Object?>) {
-      if (!_canParseString(obj, reporter, 'displayUri',
-          allowsUndefined: false, allowsNull: false)) {
-        return false;
-      }
       if (!_canParseString(obj, reporter, 'file',
           allowsUndefined: false, allowsNull: false)) {
         return false;
       }
-      if (!_canParseInt(obj, reporter, 'iLength',
-          allowsUndefined: false, allowsNull: false)) {
-        return false;
-      }
-      if (!_canParseInt(obj, reporter, 'libId',
-          allowsUndefined: false, allowsNull: false)) {
-        return false;
-      }
-      if (!_canParseInt(obj, reporter, 'offset',
-          allowsUndefined: false, allowsNull: false)) {
-        return false;
-      }
-      if (!_canParseInt(obj, reporter, 'rLength',
-          allowsUndefined: false, allowsNull: false)) {
-        return false;
-      }
-      return _canParseInt(obj, reporter, 'rOffset',
+      return _canParseInt(obj, reporter, 'libId',
           allowsUndefined: false, allowsNull: false);
     } else {
       reporter.reportError(
@@ -332,24 +358,14 @@
   bool operator ==(Object other) {
     return other is DartSuggestionSetCompletionItemResolutionInfo &&
         other.runtimeType == DartSuggestionSetCompletionItemResolutionInfo &&
-        displayUri == other.displayUri &&
         file == other.file &&
-        iLength == other.iLength &&
-        libId == other.libId &&
-        offset == other.offset &&
-        rLength == other.rLength &&
-        rOffset == other.rOffset;
+        libId == other.libId;
   }
 
   @override
   int get hashCode => Object.hash(
-        displayUri,
         file,
-        iLength,
         libId,
-        offset,
-        rLength,
-        rOffset,
       );
 
   @override
diff --git a/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart b/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart
index 3f7c863..c97b898 100644
--- a/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart
+++ b/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart
@@ -91,6 +91,9 @@
   if (kind == engine.ElementKind.PARAMETER) {
     return ElementKind.PARAMETER;
   }
+  if (kind == engine.ElementKind.PART) {
+    return ElementKind.COMPILATION_UNIT;
+  }
   if (kind == engine.ElementKind.PREFIX) {
     return ElementKind.PREFIX;
   }
diff --git a/pkg/analysis_server/lib/src/computer/computer_folding.dart b/pkg/analysis_server/lib/src/computer/computer_folding.dart
index 816e3cd..f5feba2 100644
--- a/pkg/analysis_server/lib/src/computer/computer_folding.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_folding.dart
@@ -13,7 +13,7 @@
   final LineInfo _lineInfo;
   final CompilationUnit _unit;
 
-  Directive? _firstDirective, _lastDirective;
+  _Directive? _firstDirective, _lastDirective;
   final List<FoldingRegion> _foldingRegions = [];
 
   DartUnitFoldingComputer(this._lineInfo, this._unit);
@@ -59,10 +59,13 @@
     if (firstDirective != null &&
         lastDirective != null &&
         firstDirective != lastDirective) {
-      _foldingRegions.add(FoldingRegion(
+      _foldingRegions.add(
+        FoldingRegion(
           FoldingKind.DIRECTIVES,
           firstDirective.keyword.end,
-          lastDirective.end - firstDirective.keyword.end));
+          lastDirective.directive.end - firstDirective.keyword.end,
+        ),
+      );
     }
 
     _addCommentRegions();
@@ -146,7 +149,7 @@
       isFirstToken = false;
       // Only exit the loop when hitting EOF *after* processing the token as
       // the EOF token may have preceding comments.
-      if (token.type == TokenType.EOF) {
+      if (token.isEof) {
         break;
       }
       token = token.next;
@@ -176,7 +179,7 @@
     return secondLoc.lineNumber - firstLoc.lineNumber > 1;
   }
 
-  void _recordDirective(Directive node) {
+  void _recordDirective(_Directive node) {
     _firstDirective ??= node;
     _lastDirective = node;
   }
@@ -242,7 +245,7 @@
 
   @override
   void visitExportDirective(ExportDirective node) {
-    _computer._recordDirective(node);
+    _computer._recordDirective(_Directive(node, node.exportKeyword));
     super.visitExportDirective(node);
   }
 
@@ -295,7 +298,7 @@
 
   @override
   void visitImportDirective(ImportDirective node) {
-    _computer._recordDirective(node);
+    _computer._recordDirective(_Directive(node, node.importKeyword));
     super.visitImportDirective(node);
   }
 
@@ -308,7 +311,7 @@
 
   @override
   void visitLibraryDirective(LibraryDirective node) {
-    _computer._recordDirective(node);
+    _computer._recordDirective(_Directive(node, node.libraryKeyword));
     super.visitLibraryDirective(node);
   }
 
@@ -343,13 +346,13 @@
 
   @override
   void visitPartDirective(PartDirective node) {
-    _computer._recordDirective(node);
+    _computer._recordDirective(_Directive(node, node.partKeyword));
     super.visitPartDirective(node);
   }
 
   @override
   void visitPartOfDirective(PartOfDirective node) {
-    _computer._recordDirective(node);
+    _computer._recordDirective(_Directive(node, node.partKeyword));
     super.visitPartOfDirective(node);
   }
 
@@ -370,6 +373,13 @@
   }
 }
 
+class _Directive {
+  final Directive directive;
+  final Token keyword;
+
+  _Directive(this.directive, this.keyword);
+}
+
 extension _CommentTokenExtensions on Token {
   static final _newlinePattern = RegExp(r'[\r\n]');
 
diff --git a/pkg/analysis_server/lib/src/computer/computer_highlights.dart b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
index 503a8ec..4e25d41 100644
--- a/pkg/analysis_server/lib/src/computer/computer_highlights.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
@@ -84,7 +84,7 @@
         }
         commentToken = commentToken.next;
       }
-      if (token.type == TokenType.EOF) {
+      if (token.isEof) {
         // Only exit the loop *after* processing the EOF token as it may
         // have preceding comments.
         break;
@@ -759,7 +759,7 @@
   @override
   void visitExportDirective(ExportDirective node) {
     computer._addRegion_node(node, HighlightRegionType.DIRECTIVE);
-    computer._addRegion_token(node.keyword, HighlightRegionType.BUILT_IN);
+    computer._addRegion_token(node.exportKeyword, HighlightRegionType.BUILT_IN);
     _addRegions_configurations(node.configurations);
     super.visitExportDirective(node);
   }
@@ -916,7 +916,7 @@
   @override
   void visitImportDirective(ImportDirective node) {
     computer._addRegion_node(node, HighlightRegionType.DIRECTIVE);
-    computer._addRegion_token(node.keyword, HighlightRegionType.BUILT_IN);
+    computer._addRegion_token(node.importKeyword, HighlightRegionType.BUILT_IN);
     computer._addRegion_token(
         node.deferredKeyword, HighlightRegionType.BUILT_IN);
     computer._addRegion_token(node.asKeyword, HighlightRegionType.BUILT_IN);
@@ -978,7 +978,8 @@
   @override
   void visitLibraryDirective(LibraryDirective node) {
     computer._addRegion_node(node, HighlightRegionType.DIRECTIVE);
-    computer._addRegion_token(node.keyword, HighlightRegionType.BUILT_IN);
+    computer._addRegion_token(
+        node.libraryKeyword, HighlightRegionType.BUILT_IN);
     super.visitLibraryDirective(node);
   }
 
@@ -1053,7 +1054,7 @@
   @override
   void visitPartDirective(PartDirective node) {
     computer._addRegion_node(node, HighlightRegionType.DIRECTIVE);
-    computer._addRegion_token(node.keyword, HighlightRegionType.BUILT_IN);
+    computer._addRegion_token(node.partKeyword, HighlightRegionType.BUILT_IN);
     super.visitPartDirective(node);
   }
 
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
index 1e44d82..cad822d 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
@@ -37,8 +37,25 @@
   /// Whether to include symbols from libraries that have not been imported.
   final bool suggestFromUnimportedLibraries;
 
+  /// Whether to use [NotImportedContributor] instead of SuggestionSets to
+  /// build completions for not-yet-imported libraries.
+  final bool previewNotImportedCompletions;
+
+  /// The budget to use for [NotImportedContributor] computation.
+  ///
+  /// This is usually the default value, but can be overridden via
+  /// initializationOptions (used for tests, but may also be useful for
+  /// debugging).
+  late final CompletionBudget completionBudget;
+
   CompletionHandler(super.server, LspInitializationOptions options)
-      : suggestFromUnimportedLibraries = options.suggestFromUnimportedLibraries;
+      : suggestFromUnimportedLibraries = options.suggestFromUnimportedLibraries,
+        previewNotImportedCompletions = options.previewNotImportedCompletions {
+    final budgetMs = options.notImportedCompletionBudgetMilliseconds;
+    completionBudget = CompletionBudget(budgetMs != null
+        ? Duration(milliseconds: budgetMs)
+        : CompletionBudget.defaultDuration);
+  }
 
   @override
   Method get handlesMessage => Method.textDocument_completion;
@@ -299,8 +316,12 @@
     String? triggerCharacter,
     CancellationToken token,
   ) async {
-    final useSuggestionSets =
-        suggestFromUnimportedLibraries && capabilities.applyEdit;
+    final useSuggestionSets = suggestFromUnimportedLibraries &&
+        capabilities.applyEdit &&
+        !previewNotImportedCompletions;
+    final useNotImportedCompletions = suggestFromUnimportedLibraries &&
+        capabilities.applyEdit &&
+        previewNotImportedCompletions;
 
     final completionRequest = DartCompletionRequest.forResolvedUnit(
       resolvedUnit: unit,
@@ -321,20 +342,24 @@
     Set<ElementKind>? includedElementKinds;
     Set<String>? includedElementNames;
     List<IncludedSuggestionRelevanceTag>? includedSuggestionRelevanceTags;
+    NotImportedSuggestions? notImportedSuggestions;
     if (useSuggestionSets) {
       includedElementKinds = <ElementKind>{};
       includedElementNames = <String>{};
       includedSuggestionRelevanceTags = <IncludedSuggestionRelevanceTag>[];
+    } else if (useNotImportedCompletions) {
+      notImportedSuggestions = NotImportedSuggestions();
     }
 
     try {
       final serverSuggestions2 =
           await performance.runAsync('computeSuggestions', (performance) async {
         var contributor = DartCompletionManager(
-          budget: CompletionBudget(CompletionBudget.defaultDuration),
+          budget: completionBudget,
           includedElementKinds: includedElementKinds,
           includedElementNames: includedElementNames,
           includedSuggestionRelevanceTags: includedSuggestionRelevanceTags,
+          notImportedSuggestions: notImportedSuggestions,
         );
 
         // `await` required for `performance.runAsync` to count time.
@@ -383,11 +408,25 @@
         }
 
         // Convert to LSP ranges using the LineInfo.
-        Range? replacementRange = toRange(
+        var replacementRange = toRange(
             unit.lineInfo, itemReplacementOffset, itemReplacementLength);
-        Range? insertionRange =
+        var insertionRange =
             toRange(unit.lineInfo, itemReplacementOffset, itemInsertLength);
 
+        // For not-imported items, we need to include the file+uri to be able
+        // to compute the import-inserting edits in the `completionItem/resolve`
+        // call later.
+        CompletionItemResolutionInfo? resolutionInfo;
+        final libraryUri = item.libraryUri;
+        if (useNotImportedCompletions &&
+            libraryUri != null &&
+            (item.isNotImported ?? false)) {
+          resolutionInfo = DartNotImportedCompletionResolutionInfo(
+            file: unit.path,
+            libraryUri: libraryUri,
+          );
+        }
+
         return toCompletionItem(
           capabilities,
           unit.lineInfo,
@@ -402,6 +441,10 @@
           includeCommitCharacters:
               server.clientConfiguration.global.previewCommitCharacters,
           completeFunctionCalls: completeFunctionCalls,
+          resolutionData: resolutionInfo,
+          // Exclude docs if we will be providing them via
+          // `completionItem/resolve`.
+          includeDocs: resolutionInfo == null,
         );
       }
 
@@ -504,7 +547,6 @@
                 .map((item) => declarationToCompletionItem(
                       capabilities,
                       unit.path,
-                      offset,
                       includedSet,
                       library,
                       tagBoosts,
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
index 07ab252..93b22ad 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/lsp_protocol/protocol.dart' hide Element;
+import 'package:analysis_server/src/computer/computer_hover.dart';
 import 'package:analysis_server/src/lsp/client_capabilities.dart';
 import 'package:analysis_server/src/lsp/constants.dart';
 import 'package:analysis_server/src/lsp/handlers/handlers.dart';
@@ -10,8 +11,6 @@
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/analysis/session.dart';
 import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/source/line_info.dart';
-import 'package:analyzer/src/util/comment.dart' as analyzer;
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
 
 class CompletionResolveHandler
@@ -41,6 +40,8 @@
 
     if (resolutionInfo is DartSuggestionSetCompletionItemResolutionInfo) {
       return resolveDartSuggestionSetCompletion(params, resolutionInfo, token);
+    } else if (resolutionInfo is DartNotImportedCompletionResolutionInfo) {
+      return resolveDartNotImportedCompletion(params, resolutionInfo, token);
     } else if (resolutionInfo is PubPackageCompletionItemResolutionInfo) {
       return resolvePubPackageCompletion(params, resolutionInfo, token);
     } else {
@@ -51,12 +52,9 @@
   Future<ErrorOr<CompletionItem>> resolveDartCompletion(
     CompletionItem item,
     LspClientCapabilities clientCapabilities,
-    LineInfo lineInfo,
     CancellationToken token, {
     required String file,
     required Uri libraryUri,
-    required Range insertionRange,
-    required Range replacementRange,
   }) async {
     const timeout = Duration(milliseconds: 1000);
     var timer = Stopwatch()..start();
@@ -72,6 +70,11 @@
           return cancelled();
         }
 
+        final result = await session.getResolvedUnit(file);
+        if (result is! ResolvedUnitResult) {
+          return cancelled();
+        }
+
         final element = await _getElement(session, libraryUri, item);
         if (element == null) {
           return error(
@@ -85,15 +88,9 @@
           return cancelled();
         }
 
-        var newInsertText = item.textEdit
-                ?.map((edit) => edit.newText, (edit) => edit.newText) ??
-            item.label;
         final builder = ChangeBuilder(session: session);
         await builder.addDartFileEdit(file, (builder) {
-          final result = builder.importLibraryElement(libraryUri);
-          if (result.prefix != null) {
-            newInsertText = '${result.prefix}.$newInsertText';
-          }
+          builder.importLibraryElement(libraryUri);
         });
 
         if (token.isCancellationRequested) {
@@ -121,12 +118,14 @@
         }
 
         final formats = clientCapabilities.completionDocumentationFormats;
-        final dartDoc =
-            analyzer.getDartDocPlainText(element.documentationComment);
-        final documentation =
-            dartDoc != null ? asMarkupContentOrString(formats, dartDoc) : null;
-        final supportsInsertReplace =
-            clientCapabilities.insertReplaceCompletionRanges;
+        final dartDocInfo = server.getDartdocDirectiveInfoForSession(session);
+        final dartDocData =
+            DartUnitHoverComputer.computeDocumentation(dartDocInfo, element);
+        final dartDoc = dartDocData?.full;
+        // `dartDoc` can be both null or empty.
+        final documentation = dartDoc != null && dartDoc.isNotEmpty
+            ? asMarkupContentOrString(formats, dartDoc)
+            : null;
 
         // If the only URI we have is a file:// URI, display it as relative to
         // the file we're importing into, rather than the full URI.
@@ -144,7 +143,7 @@
           label: item.label,
           kind: item.kind,
           tags: item.tags,
-          detail: thisFilesChanges.isNotEmpty
+          detail: changes.edits.isNotEmpty
               ? "Auto import from '$autoImportDisplayUri'\n\n${item.detail ?? ''}"
                   .trim()
               : item.detail,
@@ -155,23 +154,10 @@
           filterText: item.filterText,
           insertTextFormat: item.insertTextFormat,
           insertTextMode: item.insertTextMode,
-          textEdit: supportsInsertReplace && insertionRange != replacementRange
-              ? Either2<InsertReplaceEdit, TextEdit>.t1(
-                  InsertReplaceEdit(
-                    insert: insertionRange,
-                    replace: replacementRange,
-                    newText: newInsertText,
-                  ),
-                )
-              : Either2<InsertReplaceEdit, TextEdit>.t2(
-                  TextEdit(
-                    range: replacementRange,
-                    newText: newInsertText,
-                  ),
-                ),
+          textEdit: item.textEdit,
           additionalTextEdits: thisFilesChanges
               .expand((change) =>
-                  change.edits.map((edit) => toTextEdit(lineInfo, edit)))
+                  change.edits.map((edit) => toTextEdit(result.lineInfo, edit)))
               .toList(),
           commitCharacters: item.commitCharacters,
           command: command ?? item.command,
@@ -191,6 +177,27 @@
     );
   }
 
+  Future<ErrorOr<CompletionItem>> resolveDartNotImportedCompletion(
+    CompletionItem item,
+    DartNotImportedCompletionResolutionInfo data,
+    CancellationToken token,
+  ) async {
+    final clientCapabilities = server.clientCapabilities;
+    if (clientCapabilities == null) {
+      // This should not happen unless a client misbehaves.
+      return error(ErrorCodes.ServerNotInitialized,
+          'Requests not before server is initilized');
+    }
+
+    return resolveDartCompletion(
+      item,
+      clientCapabilities,
+      token,
+      file: data.file,
+      libraryUri: Uri.parse(data.libraryUri),
+    );
+  }
+
   Future<ErrorOr<CompletionItem>> resolveDartSuggestionSetCompletion(
     CompletionItem item,
     DartSuggestionSetCompletionItemResolutionInfo data,
@@ -202,16 +209,6 @@
       return serverNotInitializedError;
     }
 
-    final file = data.file;
-    final lineInfo = server.getLineInfo(file);
-    if (lineInfo == null) {
-      return error(
-        ErrorCodes.InternalError,
-        'Line info not available for $file',
-        null,
-      );
-    }
-
     var library = server.declarationsTracker?.getLibrary(data.libId);
     if (library == null) {
       return error(
@@ -221,18 +218,12 @@
       );
     }
 
-    final insertionRange = toRange(lineInfo, data.rOffset, data.iLength);
-    final replacementRange = toRange(lineInfo, data.rOffset, data.rLength);
-
     return resolveDartCompletion(
       item,
       clientCapabilities,
-      lineInfo,
       token,
-      file: file,
+      file: data.file,
       libraryUri: library.uri,
-      insertionRange: insertionRange,
-      replacementRange: replacementRange,
     );
   }
 
diff --git a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
index 49cc0b8..6a1cc96 100644
--- a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
@@ -887,21 +887,30 @@
 
 class LspInitializationOptions {
   final bool onlyAnalyzeProjectsWithOpenFiles;
+  final bool previewNotImportedCompletions;
   final bool suggestFromUnimportedLibraries;
   final bool closingLabels;
   final bool outline;
   final bool flutterOutline;
+  final int? notImportedCompletionBudgetMilliseconds;
 
   LspInitializationOptions(dynamic options)
       : onlyAnalyzeProjectsWithOpenFiles = options != null &&
             options['onlyAnalyzeProjectsWithOpenFiles'] == true,
+        // Undocumented preview flag to allow easy testing of not imported
+        // completion contributor.
+        previewNotImportedCompletions =
+            options != null && options['previewNotImportedCompletions'] == true,
         // suggestFromUnimportedLibraries defaults to true, so must be
         // explicitly passed as false to disable.
         suggestFromUnimportedLibraries = options == null ||
             options['suggestFromUnimportedLibraries'] != false,
         closingLabels = options != null && options['closingLabels'] == true,
         outline = options != null && options['outline'] == true,
-        flutterOutline = options != null && options['flutterOutline'] == true;
+        flutterOutline = options != null && options['flutterOutline'] == true,
+        notImportedCompletionBudgetMilliseconds = options != null
+            ? options['notImportedCompletionBudgetMilliseconds'] as int?
+            : null;
 }
 
 class LspServerContextManagerCallbacks extends ContextManagerCallbacks {
diff --git a/pkg/analysis_server/lib/src/lsp/mapping.dart b/pkg/analysis_server/lib/src/lsp/mapping.dart
index 77a4353..a3c3c99 100644
--- a/pkg/analysis_server/lib/src/lsp/mapping.dart
+++ b/pkg/analysis_server/lib/src/lsp/mapping.dart
@@ -269,7 +269,6 @@
 lsp.CompletionItem declarationToCompletionItem(
   LspClientCapabilities capabilities,
   String file,
-  int offset,
   server.IncludedSuggestionSet includedSuggestionSet,
   Library library,
   Map<String, int> tagBoosts,
@@ -382,13 +381,9 @@
           ),
     // data, used for completionItem/resolve.
     data: lsp.DartSuggestionSetCompletionItemResolutionInfo(
-        file: file,
-        offset: offset,
-        libId: includedSuggestionSet.id,
-        displayUri: includedSuggestionSet.displayUri ?? library.uri.toString(),
-        rOffset: replacementOffset,
-        iLength: insertLength,
-        rLength: replacementLength),
+      file: file,
+      libId: includedSuggestionSet.id,
+    ),
   );
 }
 
@@ -1123,6 +1118,7 @@
   server.CompletionSuggestion suggestion, {
   required Range replacementRange,
   required Range insertionRange,
+  bool includeDocs = true,
   required bool includeCommitCharacters,
   required bool completeFunctionCalls,
   CompletionItemResolutionInfo? resolutionData,
@@ -1221,7 +1217,7 @@
         includeCommitCharacters ? dartCompletionCommitCharacters : null,
     data: resolutionData,
     detail: detail,
-    documentation: cleanedDoc != null
+    documentation: cleanedDoc != null && includeDocs
         ? asMarkupContentOrString(formats, cleanedDoc)
         : null,
     deprecated: supportsCompletionDeprecatedFlag && suggestion.isDeprecated
diff --git a/pkg/analysis_server/lib/src/lsp/source_edits.dart b/pkg/analysis_server/lib/src/lsp/source_edits.dart
index ac2a8b8..cea729e 100644
--- a/pkg/analysis_server/lib/src/lsp/source_edits.dart
+++ b/pkg/analysis_server/lib/src/lsp/source_edits.dart
@@ -309,7 +309,7 @@
 
 /// Iterates over a token stream returning all tokens including comments.
 Iterable<Token> _iterateAllTokens(Token token) sync* {
-  while (token.type != TokenType.EOF) {
+  while (!token.isEof) {
     Token? commentToken = token.precedingComments;
     while (commentToken != null) {
       yield commentToken;
diff --git a/pkg/analysis_server/lib/src/services/correction/assist.dart b/pkg/analysis_server/lib/src/services/correction/assist.dart
index 2dbdf85..43a169f 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist.dart
@@ -228,6 +228,11 @@
     30,
     'Convert to StatefulWidget',
   );
+  static const FLUTTER_CONVERT_TO_STATELESS_WIDGET = AssistKind(
+    'dart.assist.flutter.convert.toStatelessWidget',
+    30,
+    'Convert to StatelessWidget',
+  );
 
   // Flutter wrap specific assists
   static const FLUTTER_WRAP_GENERIC = AssistKind(
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index 00f542e..41f866b 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -44,6 +44,7 @@
 import 'package:analysis_server/src/services/correction/dart/exchange_operands.dart';
 import 'package:analysis_server/src/services/correction/dart/flutter_convert_to_children.dart';
 import 'package:analysis_server/src/services/correction/dart/flutter_convert_to_stateful_widget.dart';
+import 'package:analysis_server/src/services/correction/dart/flutter_convert_to_stateless_widget.dart';
 import 'package:analysis_server/src/services/correction/dart/flutter_move_down.dart';
 import 'package:analysis_server/src/services/correction/dart/flutter_move_up.dart';
 import 'package:analysis_server/src/services/correction/dart/flutter_remove_widget.dart';
@@ -125,6 +126,7 @@
     ExchangeOperands.new,
     FlutterConvertToChildren.new,
     FlutterConvertToStatefulWidget.new,
+    FlutterConvertToStatelessWidget.new,
     FlutterMoveDown.new,
     FlutterMoveUp.new,
     FlutterRemoveWidget.new,
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/flutter_convert_to_stateful_widget.dart b/pkg/analysis_server/lib/src/services/correction/dart/flutter_convert_to_stateful_widget.dart
index 4e73f85..c646e6f 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/flutter_convert_to_stateful_widget.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/flutter_convert_to_stateful_widget.dart
@@ -34,28 +34,18 @@
       return;
     }
 
-    // Find the build() method.
-    MethodDeclaration? buildMethod;
-    for (var member in widgetClass.members) {
-      if (member is MethodDeclaration && member.name.name == 'build') {
-        var parameters = member.parameters;
-        if (parameters != null && parameters.parameters.length == 1) {
-          buildMethod = member;
-          break;
-        }
-      }
-    }
-    if (buildMethod == null) {
-      return;
-    }
-
-    // Must be a StatelessWidget subclasses.
+    // Must be a StatelessWidget subclass.
     var widgetClassElement = widgetClass.declaredElement!;
     var superType = widgetClassElement.supertype;
     if (superType == null || !flutter.isExactlyStatelessWidgetType(superType)) {
       return;
     }
 
+    var buildMethod = _findBuildMethod(widgetClass);
+    if (buildMethod == null) {
+      return;
+    }
+
     var widgetName = widgetClassElement.displayName;
     var stateName = widgetClassElement.isPrivate
         ? '${widgetName}State'
@@ -254,6 +244,18 @@
       });
     });
   }
+
+  MethodDeclaration? _findBuildMethod(ClassDeclaration widgetClass) {
+    for (var member in widgetClass.members) {
+      if (member is MethodDeclaration && member.name.name == 'build') {
+        var parameters = member.parameters;
+        if (parameters != null && parameters.parameters.length == 1) {
+          return member;
+        }
+      }
+    }
+    return null;
+  }
 }
 
 class _FieldFinder extends RecursiveAstVisitor<void> {
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/flutter_convert_to_stateless_widget.dart b/pkg/analysis_server/lib/src/services/correction/dart/flutter_convert_to_stateless_widget.dart
new file mode 100644
index 0000000..c061f38
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/dart/flutter_convert_to_stateless_widget.dart
@@ -0,0 +1,406 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:_fe_analyzer_shared/src/scanner/token.dart';
+import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
+import 'package:analysis_server/src/utilities/flutter.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/source/source_range.dart';
+import 'package:analyzer/src/dart/ast/extensions.dart';
+import 'package:analyzer_plugin/protocol/protocol_common.dart' hide Element;
+import 'package:analyzer_plugin/utilities/assist/assist.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+import 'package:analyzer_plugin/utilities/range_factory.dart';
+
+class FlutterConvertToStatelessWidget extends CorrectionProducer {
+  @override
+  AssistKind get assistKind =>
+      DartAssistKind.FLUTTER_CONVERT_TO_STATELESS_WIDGET;
+
+  @override
+  Future<void> compute(ChangeBuilder builder) async {
+    var widgetClass = node.thisOrAncestorOfType<ClassDeclaration>();
+    var superclass = widgetClass?.extendsClause?.superclass;
+    if (widgetClass == null || superclass == null) return;
+
+    // Don't spam, activate only from the `class` keyword to the class body.
+    if (selectionOffset < widgetClass.classKeyword.offset ||
+        selectionOffset > widgetClass.leftBracket.end) {
+      return;
+    }
+
+    // Must be a StatefulWidget subclass.
+    var widgetClassElement = widgetClass.declaredElement!;
+    var superType = widgetClassElement.supertype;
+    if (superType == null || !flutter.isExactlyStatefulWidgetType(superType)) {
+      return;
+    }
+
+    var createStateMethod = _findCreateStateMethod(widgetClass);
+    if (createStateMethod == null) return;
+
+    var stateClass = _findStateClass(widgetClassElement);
+    var stateClassElement = stateClass?.declaredElement;
+    if (stateClass == null ||
+        stateClassElement == null ||
+        !Identifier.isPrivateName(stateClass.name.name) ||
+        !_isSameTypeParameters(widgetClass, stateClass)) {
+      return;
+    }
+
+    var verifier = _StatelessVerifier();
+    var fieldFinder = _FieldFinder();
+
+    for (var member in stateClass.members) {
+      if (member is ConstructorDeclaration) {
+        member.accept(fieldFinder);
+      } else if (member is MethodDeclaration) {
+        member.accept(verifier);
+        if (!verifier.canBeStateless) {
+          return;
+        }
+      }
+    }
+
+    var usageVerifier =
+        _StateUsageVisitor(widgetClassElement, stateClassElement);
+    unit.visitChildren(usageVerifier);
+    if (usageVerifier.used) return;
+
+    var fieldsAssignedInConstructors = fieldFinder.fieldsAssignedInConstructors;
+
+    // Prepare nodes to move.
+    var nodesToMove = <ClassMember>[];
+    var elementsToMove = <Element>{};
+    for (var member in stateClass.members) {
+      if (member is FieldDeclaration) {
+        if (member.isStatic) {
+          return;
+        }
+        for (var fieldNode in member.fields.variables) {
+          var fieldElement = fieldNode.declaredElement as FieldElement;
+          if (!fieldsAssignedInConstructors.contains(fieldElement)) {
+            nodesToMove.add(member);
+            elementsToMove.add(fieldElement);
+
+            var getter = fieldElement.getter;
+            if (getter != null) {
+              elementsToMove.add(getter);
+            }
+
+            var setter = fieldElement.setter;
+            if (setter != null) {
+              elementsToMove.add(setter);
+            }
+          }
+        }
+      } else if (member is MethodDeclaration) {
+        if (member.isStatic) {
+          return;
+        }
+        if (!_isDefaultOverride(member)) {
+          nodesToMove.add(member);
+          elementsToMove.add(member.declaredElement!);
+        }
+      }
+    }
+
+    /// Return the code for the [movedNode], so that qualification of the
+    /// references to the widget (`widget.` or static `MyWidgetClass.`)
+    /// is removed
+    String rewriteWidgetMemberReferences(AstNode movedNode) {
+      var linesRange = utils.getLinesRange(range.node(movedNode));
+      var text = utils.getRangeText(linesRange);
+
+      // Remove `widget.` before references to the widget instance members.
+      var visitor = _ReplacementEditBuilder(
+          widgetClassElement, elementsToMove, linesRange);
+      movedNode.accept(visitor);
+      return SourceEdit.applySequence(text, visitor.edits.reversed);
+    }
+
+    var statelessWidgetClass = await sessionHelper.getClass(
+      flutter.widgetsUri,
+      'StatelessWidget',
+    );
+    if (statelessWidgetClass == null) {
+      return;
+    }
+
+    await builder.addDartFileEdit(file, (builder) {
+      builder.addReplacement(range.node(superclass), (builder) {
+        builder.writeReference(statelessWidgetClass);
+      });
+
+      builder.addDeletion(range.deletionRange(stateClass));
+
+      var createStateNextToEnd = createStateMethod.endToken.next!;
+      createStateNextToEnd =
+          createStateNextToEnd.precedingComments ?? createStateNextToEnd;
+      var createStateRange = range.startOffsetEndOffset(
+          utils.getLineContentStart(createStateMethod.offset),
+          utils.getLineContentStart(createStateNextToEnd.offset));
+
+      var newLine = createStateNextToEnd.type != TokenType.CLOSE_CURLY_BRACKET;
+
+      builder.addReplacement(createStateRange, (builder) {
+        for (var i = 0; i < nodesToMove.length; i++) {
+          var member = nodesToMove[i];
+          var comments = member.beginToken.precedingComments;
+          if (comments != null) {
+            var offset = utils.getLineContentStart(comments.offset);
+            var length = comments.end - offset;
+            builder.writeln(utils.getText(offset, length));
+          }
+
+          var text = rewriteWidgetMemberReferences(member);
+          builder.write(text);
+          if (newLine || i < nodesToMove.length - 1) {
+            builder.writeln();
+          }
+        }
+      });
+    });
+  }
+
+  MethodDeclaration? _findCreateStateMethod(ClassDeclaration widgetClass) {
+    for (var member in widgetClass.members) {
+      if (member is MethodDeclaration && member.name.name == 'createState') {
+        var parameters = member.parameters;
+        if (parameters?.parameters.isEmpty ?? false) {
+          return member;
+        }
+        break;
+      }
+    }
+    return null;
+  }
+
+  ClassDeclaration? _findStateClass(ClassElement widgetClassElement) {
+    for (var declaration in unit.declarations) {
+      if (declaration is ClassDeclaration) {
+        var type = declaration.extendsClause?.superclass.type;
+
+        if (_isState(widgetClassElement, type)) {
+          return declaration;
+        }
+      }
+    }
+    return null;
+  }
+
+  bool _isSameTypeParameters(
+      ClassDeclaration widgetClass, ClassDeclaration stateClass) {
+    List<TypeParameter>? parameters(ClassDeclaration declaration) =>
+        declaration.typeParameters?.typeParameters;
+
+    var widgetParams = parameters(widgetClass);
+    var stateParams = parameters(stateClass);
+
+    if (widgetParams == null && stateParams == null) {
+      return true;
+    }
+    if (widgetParams == null || stateParams == null) {
+      return false;
+    }
+    if (widgetParams.length < stateParams.length) {
+      return false;
+    }
+    outer:
+    for (var stateParam in stateParams) {
+      for (var widgetParam in widgetParams) {
+        if (stateParam.name.name == widgetParam.name.name &&
+            stateParam.bound?.type == widgetParam.bound?.type) {
+          continue outer;
+        }
+      }
+      return false;
+    }
+    return true;
+  }
+
+  static bool _isDefaultOverride(MethodDeclaration? methodDeclaration) {
+    var body = methodDeclaration?.body;
+    if (body != null) {
+      Expression expression;
+      if (body is BlockFunctionBody) {
+        var statements = body.block.statements;
+        if (statements.isEmpty) return true;
+        if (statements.length > 1) return false;
+        var first = statements.first;
+        if (first is! ExpressionStatement) return false;
+        expression = first.expression;
+      } else if (body is ExpressionFunctionBody) {
+        expression = body.expression;
+      } else {
+        return false;
+      }
+      if (expression is MethodInvocation &&
+          expression.target is SuperExpression &&
+          methodDeclaration!.name.name == expression.methodName.name) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  static bool _isState(ClassElement widgetClassElement, DartType? type) {
+    if (type is! ParameterizedType) return false;
+
+    var typeArguments = type.typeArguments;
+    if (typeArguments.length != 1 ||
+        typeArguments[0].element != widgetClassElement) {
+      return false;
+    }
+
+    var classElement = type.element;
+    return classElement is ClassElement &&
+        Flutter.instance.isExactState(classElement);
+  }
+}
+
+class _FieldFinder extends RecursiveAstVisitor<void> {
+  Set<FieldElement> fieldsAssignedInConstructors = {};
+
+  @override
+  void visitSimpleIdentifier(SimpleIdentifier node) {
+    if (node.parent is FieldFormalParameter) {
+      var element = node.staticElement;
+      if (element is FieldFormalParameterElement) {
+        var field = element.field;
+        if (field != null) {
+          fieldsAssignedInConstructors.add(field);
+        }
+      }
+    }
+    if (node.parent is ConstructorFieldInitializer) {
+      var element = node.staticElement;
+      if (element is FieldElement) {
+        fieldsAssignedInConstructors.add(element);
+      }
+    }
+    if (node.inSetterContext()) {
+      var element = node.writeOrReadElement;
+      if (element is PropertyAccessorElement) {
+        var field = element.variable;
+        if (field is FieldElement) {
+          fieldsAssignedInConstructors.add(field);
+        }
+      }
+    }
+  }
+}
+
+class _ReplacementEditBuilder extends RecursiveAstVisitor<void> {
+  final ClassElement widgetClassElement;
+
+  final Set<Element> elementsToMove;
+
+  final SourceRange linesRange;
+
+  List<SourceEdit> edits = [];
+
+  _ReplacementEditBuilder(
+      this.widgetClassElement, this.elementsToMove, this.linesRange);
+
+  @override
+  void visitSimpleIdentifier(SimpleIdentifier node) {
+    if (node.inDeclarationContext()) {
+      return;
+    }
+    var element = node.staticElement;
+    if (element is ExecutableElement &&
+        element.enclosingElement == widgetClassElement &&
+        !elementsToMove.contains(element)) {
+      var parent = node.parent;
+      if (parent is PrefixedIdentifier) {
+        var grandParent = parent.parent;
+        SourceEdit? rightBracketEdit;
+        if (!node.name.contains('\$') &&
+            grandParent is InterpolationExpression &&
+            grandParent.leftBracket.type ==
+                TokenType.STRING_INTERPOLATION_EXPRESSION) {
+          edits.add(SourceEdit(
+              grandParent.leftBracket.end - 1 - linesRange.offset, 1, ''));
+          var offset = grandParent.rightBracket?.offset;
+          if (offset != null) {
+            rightBracketEdit = SourceEdit(offset - linesRange.offset, 1, '');
+          }
+        }
+        var offset = parent.prefix.offset;
+        var length = parent.period.end - offset;
+        edits.add(SourceEdit(offset - linesRange.offset, length, ''));
+        if (rightBracketEdit != null) {
+          edits.add(rightBracketEdit);
+        }
+      } else if (parent is MethodInvocation) {
+        var target = parent.target;
+        var operator = parent.operator;
+        if (target != null && operator != null) {
+          var offset = target.beginToken.offset;
+          var length = operator.end - offset;
+          edits.add(SourceEdit(offset - linesRange.offset, length, ''));
+        }
+      }
+    }
+  }
+}
+
+class _StatelessVerifier extends RecursiveAstVisitor<void> {
+  var canBeStateless = true;
+
+  @override
+  void visitMethodInvocation(MethodInvocation node) {
+    var methodElement = node.methodName.staticElement?.declaration;
+    if (methodElement is ClassMemberElement) {
+      var classElement = methodElement.enclosingElement;
+      if (classElement is ClassElement &&
+          Flutter.instance.isExactState(classElement) &&
+          !FlutterConvertToStatelessWidget._isDefaultOverride(
+              node.thisOrAncestorOfType<MethodDeclaration>())) {
+        canBeStateless = false;
+        return;
+      }
+    }
+    super.visitMethodInvocation(node);
+  }
+}
+
+class _StateUsageVisitor extends RecursiveAstVisitor<void> {
+  bool used = false;
+  ClassElement widgetClassElement;
+  ClassElement stateClassElement;
+
+  _StateUsageVisitor(this.widgetClassElement, this.stateClassElement);
+
+  @override
+  void visitInstanceCreationExpression(InstanceCreationExpression node) {
+    super.visitInstanceCreationExpression(node);
+    if (node.staticType?.element != stateClassElement) {
+      return;
+    }
+    var methodDeclaration = node.thisOrAncestorOfType<MethodDeclaration>();
+    var classDeclaration =
+        methodDeclaration?.thisOrAncestorOfType<ClassDeclaration>();
+
+    if (methodDeclaration?.name.name != 'createState' ||
+        classDeclaration?.declaredElement != widgetClassElement) {
+      used = true;
+    }
+  }
+
+  @override
+  void visitMethodInvocation(MethodInvocation node) {
+    var type = node.staticType;
+    if (node.methodName.name == 'createState' &&
+        (FlutterConvertToStatelessWidget._isState(widgetClassElement, type) ||
+            type?.element == stateClassElement)) {
+      used = true;
+    }
+  }
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/statement_analyzer.dart b/pkg/analysis_server/lib/src/services/correction/statement_analyzer.dart
index 9a156c4..59d04bd 100644
--- a/pkg/analysis_server/lib/src/services/correction/statement_analyzer.dart
+++ b/pkg/analysis_server/lib/src/services/correction/statement_analyzer.dart
@@ -28,7 +28,7 @@
         featureSet: featureSet,
       );
     var token = scanner.tokenize();
-    while (token.type != TokenType.EOF) {
+    while (!token.isEof) {
       tokens.add(token);
       token = token.next!;
     }
diff --git a/pkg/analysis_server/lib/src/services/correction/util.dart b/pkg/analysis_server/lib/src/services/correction/util.dart
index 3f0281a7..3c1c745 100644
--- a/pkg/analysis_server/lib/src/services/correction/util.dart
+++ b/pkg/analysis_server/lib/src/services/correction/util.dart
@@ -176,7 +176,7 @@
 List<SourceRange> getCommentRanges(CompilationUnit unit) {
   var ranges = <SourceRange>[];
   var token = unit.beginToken;
-  while (token.type != TokenType.EOF) {
+  while (!token.isEof) {
     var commentToken = token.precedingComments;
     while (commentToken != null) {
       ranges.add(range.token(commentToken));
@@ -1450,7 +1450,7 @@
           featureSet: featureSet,
         );
       var token = scanner.tokenize();
-      while (token.type != TokenType.EOF) {
+      while (!token.isEof) {
         tokens.add(token);
         token = token.next!;
       }
diff --git a/pkg/analysis_server/lib/src/utilities/extensions/range_factory.dart b/pkg/analysis_server/lib/src/utilities/extensions/range_factory.dart
index eedc3c7..f073fdb 100644
--- a/pkg/analysis_server/lib/src/utilities/extensions/range_factory.dart
+++ b/pkg/analysis_server/lib/src/utilities/extensions/range_factory.dart
@@ -119,7 +119,7 @@
   /// the [token] if there is no such comment.
   Token _leadingComment(LineInfo lineInfo, Token token) {
     var previous = token.previous;
-    if (previous == null || previous.type == TokenType.EOF) {
+    if (previous == null || previous.isEof) {
       return token.precedingComments ?? token;
     }
     var previousLine = lineInfo.getLocation(previous.offset).lineNumber;
diff --git a/pkg/analysis_server/test/analysis/notification_navigation_test.dart b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
index 2d1b4e5..1502fd5 100644
--- a/pkg/analysis_server/test/analysis/notification_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
@@ -1318,6 +1318,15 @@
     assertHasFileTarget(unitFile, 0, 0);
   }
 
+  Future<void> test_string_part_hasSource_notPart() async {
+    addTestFile('''
+library lib;
+part "test_unit.dart";
+''');
+    await prepareNavigation();
+    assertHasRegionString('"test_unit.dart"');
+  }
+
   Future<void> test_string_part_invalidUri() async {
     addTestFile('''
 part ":[invalid]";
@@ -1326,15 +1335,6 @@
     assertNoRegionString('":[invalid]"');
   }
 
-  Future<void> test_string_part_unresolvedUri() async {
-    addTestFile('''
-library lib;
-part "test_unit.dart";
-''');
-    await prepareNavigation();
-    assertNoRegionString('"test_unit.dart"');
-  }
-
   Future<void> test_superConstructorInvocation() async {
     addTestFile('''
 class A {
diff --git a/pkg/analysis_server/test/client/completion_driver_test.dart b/pkg/analysis_server/test/client/completion_driver_test.dart
index 39d20e9..539374a 100644
--- a/pkg/analysis_server/test/client/completion_driver_test.dart
+++ b/pkg/analysis_server/test/client/completion_driver_test.dart
@@ -163,7 +163,11 @@
         if (file != null && s.element?.location?.file != convertPath(file)) {
           return false;
         }
-        if (libraryUri != null && s.libraryUri != libraryUri) {
+        // Library URIs are not available in protocol v1 so skip the check to
+        // allow the the same test to verify for v2.
+        if (!isProtocolVersion1 &&
+            libraryUri != null &&
+            s.libraryUri != libraryUri) {
           return false;
         }
         return true;
@@ -621,6 +625,7 @@
     assertSuggestion(
       completion: 'A',
       element: ElementKind.CLASS,
+      libraryUri: 'package:test/b.dart',
     );
   }
 
@@ -641,10 +646,12 @@
 ''');
 
     // Should be only one suggestion, which comes from local declaration.
-    assertSuggestion(
+    var suggestion = suggestionWith(
       completion: 'A',
       element: ElementKind.CLASS,
     );
+    expect(suggestion, isNotNull);
+    expect(suggestion.libraryUri, isNull);
   }
 
   Future<void> test_project_lib_setters_class() async {
diff --git a/pkg/analysis_server/test/lsp/completion_dart_test.dart b/pkg/analysis_server/test/lsp/completion_dart_test.dart
index 9010d16..6eb8824 100644
--- a/pkg/analysis_server/test/lsp/completion_dart_test.dart
+++ b/pkg/analysis_server/test/lsp/completion_dart_test.dart
@@ -21,6 +21,7 @@
 void main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(CompletionTest);
+    defineReflectiveTests(CompletionWithPreviewNotImportedCompletionsTest);
     defineReflectiveTests(DartSnippetCompletionTest);
     defineReflectiveTests(FlutterSnippetCompletionTest);
     defineReflectiveTests(FlutterSnippetCompletionWithoutNullSafetyTest);
@@ -30,6 +31,15 @@
 @reflectiveTest
 class CompletionTest extends AbstractLspAnalysisServerTest
     with CompletionTestMixin {
+  CompletionTest({bool previewNotImportedCompletions = false}) {
+    defaultInitializationOptions = {
+      'previewNotImportedCompletions': previewNotImportedCompletions,
+      // Default to a high budget for tests because everything is cold and
+      // may take longer to return.
+      'notImportedCompletionBudgetMilliseconds': 50000
+    };
+  }
+
   Future<void> checkCompleteFunctionCallInsertText(
       String content, String completion,
       {required String? editText, InsertTextFormat? insertTextFormat}) async {
@@ -1852,16 +1862,28 @@
   }
 
   Future<void> test_unimportedSymbols_enumValues() async {
+    // Enum values only show up in contexts with their types, so we need two
+    // extra files - one with the Enum definition, and one with a function that
+    // accepts the Enum type that is imported into the test files.
     newFile(
-      join(projectFolderPath, 'source_file.dart'),
+      join(projectFolderPath, 'lib', 'enum.dart'),
       '''
-      enum MyExportedEnum { One, Two }
+        enum MyExportedEnum { One, Two }
+      ''',
+    );
+    newFile(
+      join(projectFolderPath, 'lib', 'function_x.dart'),
+      '''
+        import 'package:test/enum.dart';
+        void x(MyExportedEnum e) {}
       ''',
     );
 
     final content = '''
+import 'package:test/function_x.dart';
+
 void f() {
-  var a = MyExported^
+  x(MyExported^
 }
     ''';
 
@@ -1892,7 +1914,9 @@
 
     // Ensure the detail field was update to show this will auto-import.
     expect(
-        resolved.detail, startsWith("Auto import from '../source_file.dart'"));
+      resolved.detail,
+      startsWith("Auto import from 'package:test/enum.dart'"),
+    );
 
     // Ensure the edit was added on.
     expect(resolved.textEdit, isNotNull);
@@ -1907,17 +1931,18 @@
 
     // Ensure both edits were made - the completion, and the inserted import.
     expect(newContent, equals('''
-import '../source_file.dart';
+import 'package:test/enum.dart';
+import 'package:test/function_x.dart';
 
 void f() {
-  var a = MyExportedEnum.One
+  x(MyExportedEnum.One
 }
     '''));
   }
 
   Future<void> test_unimportedSymbols_enumValuesAlreadyImported() async {
     newFile(
-      join(projectFolderPath, 'lib', 'source_file.dart'),
+      join(projectFolderPath, 'lib', 'enum.dart'),
       '''
       enum MyExportedEnum { One, Two }
       ''',
@@ -1925,13 +1950,15 @@
     newFile(
       join(projectFolderPath, 'lib', 'reexport1.dart'),
       '''
-      export 'source_file.dart';
+      import 'enum.dart';
+      export 'enum.dart';
+      void x(MyExportedEnum e) {}
       ''',
     );
     newFile(
       join(projectFolderPath, 'lib', 'reexport2.dart'),
       '''
-      export 'source_file.dart';
+      export 'enum.dart';
       ''',
     );
 
@@ -1939,7 +1966,7 @@
 import 'reexport1.dart';
 
 void f() {
-  var a = MyExported^
+  x(MyExported^
 }
     ''';
 
@@ -2265,6 +2292,57 @@
 part 'main.dart';'''));
   }
 
+  Future<void>
+      test_unimportedSymbols_isIncompleteNotSetIfBudgetNotExhausted() async {
+    final content = '''
+void f() {
+  InOtherF^
+}
+    ''';
+
+    final initialAnalysis = waitForAnalysisComplete();
+    await initialize(
+        initializationOptions: {
+          ...?defaultInitializationOptions,
+          // Set budget high to ensure it completes.
+          'notImportedCompletionBudgetMilliseconds': 100000,
+        },
+        workspaceCapabilities:
+            withApplyEditSupport(emptyWorkspaceClientCapabilities));
+    await openFile(mainFileUri, withoutMarkers(content));
+    await initialAnalysis;
+    final res =
+        await getCompletionList(mainFileUri, positionFromMarker(content));
+
+    // Ensure we flagged that we returned everything.
+    expect(res.isIncomplete, isFalse);
+  }
+
+  Future<void> test_unimportedSymbols_isIncompleteSetIfBudgetExhausted() async {
+    final content = '''
+void f() {
+  InOtherF^
+}
+    ''';
+
+    final initialAnalysis = waitForAnalysisComplete();
+    await initialize(
+        initializationOptions: {
+          ...?defaultInitializationOptions,
+          // Set budget low to ensure we don't complete.
+          'notImportedCompletionBudgetMilliseconds': 0,
+        },
+        workspaceCapabilities:
+            withApplyEditSupport(emptyWorkspaceClientCapabilities));
+    await openFile(mainFileUri, withoutMarkers(content));
+    await initialAnalysis;
+    final res =
+        await getCompletionList(mainFileUri, positionFromMarker(content));
+
+    // Ensure we flagged that we did not return everything.
+    expect(res.isIncomplete, isFalse);
+  }
+
   /// This test reproduces a bug where the pathKey hash used in
   /// available_declarations.dart would not change with the contents of the file
   /// (as it always used 0 as the modification stamp) which would prevent
@@ -2449,6 +2527,7 @@
     // Support applyEdit, but explicitly disable the suggestions.
     await initialize(
       initializationOptions: {
+        ...?defaultInitializationOptions,
         'suggestFromUnimportedLibraries': false,
       },
       workspaceCapabilities:
@@ -2577,6 +2656,12 @@
 }
 
 @reflectiveTest
+class CompletionWithPreviewNotImportedCompletionsTest extends CompletionTest {
+  CompletionWithPreviewNotImportedCompletionsTest()
+      : super(previewNotImportedCompletions: true);
+}
+
+@reflectiveTest
 class DartSnippetCompletionTest extends SnippetCompletionTest {
   Future<void> test_snippets_class() async {
     final content = '''
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index f5a74ab..9d9c88e 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -668,6 +668,10 @@
   /// Whether to include 'clientRequestTime' fields in outgoing messages.
   bool includeClientRequestTime = false;
 
+  /// Default initialization options to be used if [initialize] is not provided
+  /// options explicitly.
+  Map<String, Object?>? defaultInitializationOptions;
+
   /// A stream of [NotificationMessage]s from the server that may be errors.
   Stream<NotificationMessage> get errorNotificationsFromServer {
     return notificationsFromServer.where(_isErrorNotification);
@@ -1489,7 +1493,8 @@
         InitializeParams(
           rootPath: rootPath,
           rootUri: rootUri?.toString(),
-          initializationOptions: initializationOptions,
+          initializationOptions:
+              initializationOptions ?? defaultInitializationOptions,
           capabilities: clientCapabilities,
           workspaceFolders: workspaceFolders?.map(toWorkspaceFolder).toList(),
         ));
diff --git a/pkg/analysis_server/test/mock_packages/flutter/lib/src/widgets/framework.dart b/pkg/analysis_server/test/mock_packages/flutter/lib/src/widgets/framework.dart
index 587cdf7..ab927f5 100644
--- a/pkg/analysis_server/test/mock_packages/flutter/lib/src/widgets/framework.dart
+++ b/pkg/analysis_server/test/mock_packages/flutter/lib/src/widgets/framework.dart
@@ -32,6 +32,8 @@
 
   void dispose() {}
 
+  void initState() {}
+
   void setState(VoidCallback fn) {}
 }
 
diff --git a/pkg/analysis_server/test/protocol_server_test.dart b/pkg/analysis_server/test/protocol_server_test.dart
index 603ea68..0e72cb6 100644
--- a/pkg/analysis_server/test/protocol_server_test.dart
+++ b/pkg/analysis_server/test/protocol_server_test.dart
@@ -249,6 +249,7 @@
       engine.ElementKind.LIBRARY_AUGMENTATION: ElementKind.UNKNOWN,
       engine.ElementKind.NAME: ElementKind.UNKNOWN,
       engine.ElementKind.NEVER: ElementKind.UNKNOWN,
+      engine.ElementKind.PART: ElementKind.COMPILATION_UNIT,
       engine.ElementKind.UNIVERSE: ElementKind.UNKNOWN
     });
   }
diff --git a/pkg/analysis_server/test/src/cider/completion_test.dart b/pkg/analysis_server/test/src/cider/completion_test.dart
index c43ddad..b6d230e 100644
--- a/pkg/analysis_server/test/src/cider/completion_test.dart
+++ b/pkg/analysis_server/test/src/cider/completion_test.dart
@@ -475,6 +475,7 @@
 
   Future<void> test_limitedResolution_hasPart() async {
     newFile('/workspace/dart/test/lib/a.dart', r'''
+part of 'test.dart';
 class A {}
 ''');
 
diff --git a/pkg/analysis_server/test/src/services/completion/dart/completion_test.dart b/pkg/analysis_server/test/src/services/completion/dart/completion_test.dart
index d222e07..02729db 100644
--- a/pkg/analysis_server/test/src/services/completion/dart/completion_test.dart
+++ b/pkg/analysis_server/test/src/services/completion/dart/completion_test.dart
@@ -225,6 +225,7 @@
 
   Future<void> test_explicitTarget_method_inPart() async {
     newFile(convertPath('$testPackageLibPath/part.dart'), '''
+part of 'test.dart';
 extension E on String {
   void m() {}
 }
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_stateful_widget_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_stateful_widget_test.dart
index 5e11735..4f73543 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_stateful_widget_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_stateful_widget_test.dart
@@ -505,32 +505,4 @@
 }
 ''');
   }
-
-  Future<void> test_tail() async {
-    await resolveTestCode(r'''
-import 'package:flutter/material.dart';
-
-class /*caret*/MyWidget extends StatelessWidget {
-  @override
-  Widget build(BuildContext context) {
-    return Container();
-  }
-}
-''');
-    await assertHasAssist(r'''
-import 'package:flutter/material.dart';
-
-class MyWidget extends StatefulWidget {
-  @override
-  State<MyWidget> createState() => _MyWidgetState();
-}
-
-class _MyWidgetState extends State<MyWidget> {
-  @override
-  Widget build(BuildContext context) {
-    return Container();
-  }
-}
-''');
-  }
 }
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_stateless_widget_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_stateless_widget_test.dart
new file mode 100644
index 0000000..f50beb7
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_stateless_widget_test.dart
@@ -0,0 +1,850 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analyzer_plugin/utilities/assist/assist.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'assist_processor.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(FlutterConvertToStatelessWidgetTest);
+  });
+}
+
+@reflectiveTest
+class FlutterConvertToStatelessWidgetTest extends AssistProcessorTest {
+  @override
+  AssistKind get kind => DartAssistKind.FLUTTER_CONVERT_TO_STATELESS_WIDGET;
+
+  @override
+  void setUp() {
+    super.setUp();
+    writeTestPackageConfig(
+      flutter: true,
+    );
+  }
+
+  Future<void> test_comment() async {
+    await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class /*caret*/MyWidget extends StatefulWidget {
+  const MyWidget();
+
+  @override
+  State<MyWidget> createState() => _MyWidgetState();
+
+  /// some m
+  void m() {}
+}
+
+/// comment for state
+class _MyWidgetState extends State<MyWidget> {
+  // something for a
+  final bool a = false;
+
+  // another for b
+  final bool b = true;
+
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+
+  /// some m
+  void m() {}
+}
+''');
+    await assertHasAssist('''
+import 'package:flutter/material.dart';
+
+class MyWidget extends StatelessWidget {
+  const MyWidget();
+
+  // something for a
+  final bool a = false;
+
+  // another for b
+  final bool b = true;
+
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+
+  /// some m
+  void m() {}
+}
+''');
+  }
+
+  Future<void> test_default_override() async {
+    await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class /*caret*/MyWidget extends StatefulWidget {
+  const MyWidget({super.key});
+
+  @override
+  State<MyWidget> createState() => _MyWidgetState();
+}
+
+class _MyWidgetState extends State<MyWidget> {
+
+  @override
+  void initState() {
+    // some comment
+    super.initState();
+  }
+
+  @override
+  void dispose() => super.dispose();
+
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}
+''');
+    await assertHasAssist(r'''
+import 'package:flutter/material.dart';
+
+class MyWidget extends StatelessWidget {
+  const MyWidget({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}
+''');
+  }
+
+  Future<void> test_empty() async {
+    await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class /*caret*/MyWidget extends StatefulWidget {
+  const MyWidget({super.key});
+
+  @override
+  State<MyWidget> createState() => _MyWidgetState();
+}
+
+class _MyWidgetState extends State<MyWidget> {
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}
+''');
+    await assertHasAssist(r'''
+import 'package:flutter/material.dart';
+
+class MyWidget extends StatelessWidget {
+  const MyWidget({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}
+''');
+  }
+
+  Future<void> test_fields() async {
+    await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class /*caret*/MyWidget extends StatefulWidget {
+  static String staticField1 = '';
+  final String instanceField1;
+  final String instanceField2;
+  String instanceField3 = '';
+  static String staticField2 = '';
+  static String staticField3 = '';
+
+  MyWidget(this.instanceField1) : instanceField2 = '' {
+    instanceField3 = '';
+  }
+
+  @override
+  State<MyWidget> createState() => _MyWidgetState();
+}
+
+class _MyWidgetState extends State<MyWidget> {
+  String instanceField4 = '';
+
+  String instanceField5 = '';
+
+  @override
+  Widget build(BuildContext context) {
+    instanceField4 = widget.instanceField1;
+    return Row(
+      children: [
+        Text(widget.instanceField1),
+        Text(widget.instanceField2),
+        Text(widget.instanceField3),
+        Text(instanceField4),
+        Text(instanceField5),
+        Text(MyWidget.staticField1),
+        Text(MyWidget.staticField2),
+        Text(MyWidget.staticField3),
+      ],
+    );
+  }
+}
+''');
+    await assertHasAssist(r'''
+import 'package:flutter/material.dart';
+
+class MyWidget extends StatelessWidget {
+  static String staticField1 = '';
+  final String instanceField1;
+  final String instanceField2;
+  String instanceField3 = '';
+  static String staticField2 = '';
+  static String staticField3 = '';
+
+  MyWidget(this.instanceField1) : instanceField2 = '' {
+    instanceField3 = '';
+  }
+
+  String instanceField4 = '';
+
+  String instanceField5 = '';
+
+  @override
+  Widget build(BuildContext context) {
+    instanceField4 = instanceField1;
+    return Row(
+      children: [
+        Text(instanceField1),
+        Text(instanceField2),
+        Text(instanceField3),
+        Text(instanceField4),
+        Text(instanceField5),
+        Text(staticField1),
+        Text(staticField2),
+        Text(staticField3),
+      ],
+    );
+  }
+}
+''');
+  }
+
+  Future<void> test_getters() async {
+    await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class /*caret*/MyWidget extends StatefulWidget {
+  @override
+  State<MyWidget> createState() => _MyWidgetState();
+
+  static String get staticGetter1 => '';
+
+  static String get staticGetter2 => '';
+}
+
+class _MyWidgetState extends State<MyWidget> {
+  @override
+  Widget build(BuildContext context) {
+    return Row(
+      children: [
+        Text(MyWidget.staticGetter1),
+        Text(MyWidget.staticGetter2),
+        Text(instanceGetter1),
+        Text(instanceGetter2),
+      ],
+    );
+  }
+
+  String get instanceGetter1 => '';
+
+  String get instanceGetter2 => '';
+}
+''');
+    await assertHasAssist(r'''
+import 'package:flutter/material.dart';
+
+class MyWidget extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    return Row(
+      children: [
+        Text(staticGetter1),
+        Text(staticGetter2),
+        Text(instanceGetter1),
+        Text(instanceGetter2),
+      ],
+    );
+  }
+
+  String get instanceGetter1 => '';
+
+  String get instanceGetter2 => '';
+
+  static String get staticGetter1 => '';
+
+  static String get staticGetter2 => '';
+}
+''');
+  }
+
+  Future<void> test_methods() async {
+    await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class /*caret*/MyWidget extends StatefulWidget {
+  static String staticField = '';
+  final String instanceField1;
+
+  MyWidget(this.instanceField1);
+
+  @override
+  State<MyWidget> createState() => _MyWidgetState();
+
+  static void staticMethod1() {
+    print('static 1');
+  }
+
+  static void staticMethod2() {
+    print('static 2');
+  }
+}
+
+class _MyWidgetState extends State<MyWidget> {
+  String instanceField2 = '';
+
+  @override
+  Widget build(BuildContext context) {
+    return Row(
+      children: [
+        Text(widget.instanceField1),
+        Text(instanceField2),
+        Text(MyWidget.staticField),
+      ],
+    );
+  }
+
+  void instanceMethod1() {
+    instanceMethod1();
+    instanceMethod2();
+    MyWidget.staticMethod1();
+  }
+
+  void instanceMethod2() {
+    print('instance 2');
+  }
+}
+''');
+    await assertHasAssist(r'''
+import 'package:flutter/material.dart';
+
+class MyWidget extends StatelessWidget {
+  static String staticField = '';
+  final String instanceField1;
+
+  MyWidget(this.instanceField1);
+
+  String instanceField2 = '';
+
+  @override
+  Widget build(BuildContext context) {
+    return Row(
+      children: [
+        Text(instanceField1),
+        Text(instanceField2),
+        Text(staticField),
+      ],
+    );
+  }
+
+  void instanceMethod1() {
+    instanceMethod1();
+    instanceMethod2();
+    staticMethod1();
+  }
+
+  void instanceMethod2() {
+    print('instance 2');
+  }
+
+  static void staticMethod1() {
+    print('static 1');
+  }
+
+  static void staticMethod2() {
+    print('static 2');
+  }
+}
+''');
+  }
+
+  Future<void> test_notClass() async {
+    await resolveTestCode('''
+import 'package:flutter/material.dart';
+/*caret*/void f() {}
+''');
+    await assertNoAssist();
+  }
+
+  Future<void> test_notStatefulWidget() async {
+    await resolveTestCode('''
+import 'package:flutter/material.dart';
+class /*caret*/MyWidget extends AppBar {
+  MyWidget({super.key});
+}
+''');
+    await assertNoAssist();
+  }
+
+  Future<void> test_notWidget() async {
+    await resolveTestCode('''
+import 'package:flutter/material.dart';
+class /*caret*/MyWidget {}
+''');
+    await assertNoAssist();
+  }
+
+  Future<void> test_override() async {
+    await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class /*caret*/MyWidget extends StatefulWidget {
+  const MyWidget({super.key});
+
+  @override
+  State<MyWidget> createState() => _MyWidgetState();
+}
+
+class _MyWidgetState extends State<MyWidget> {
+
+  @override
+  void initState() {
+    print('');
+    super.initState();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}
+''');
+    await assertNoAssist();
+  }
+
+  Future<void> test_public() async {
+    await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class /*caret*/MyWidget extends StatefulWidget {
+  const MyWidget({super.key});
+
+  @override
+  State<MyWidget> createState() => MyWidgetState();
+}
+
+class MyWidgetState extends State<MyWidget> {
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}
+''');
+    await assertNoAssist();
+  }
+
+  Future<void> test_simple() async {
+    await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class /*caret*/MyWidget extends StatefulWidget {
+  final String aaa;
+  final String $bbb;
+
+  const MyWidget(this.aaa, this.$bbb);
+
+  @override
+  State<MyWidget> createState() => _MyWidgetState();
+}
+
+class _MyWidgetState extends State<MyWidget> {
+  @override
+  Widget build(BuildContext context) {
+    return Row(
+      children: [
+        Text(widget.aaa),
+        Text(widget.$bbb),
+        Text('${widget.aaa}'),
+        Text('${widget.$bbb}'),
+      ],
+    );
+  }
+}
+''');
+    await assertHasAssist(r'''
+import 'package:flutter/material.dart';
+
+class MyWidget extends StatelessWidget {
+  final String aaa;
+  final String $bbb;
+
+  const MyWidget(this.aaa, this.$bbb);
+
+  @override
+  Widget build(BuildContext context) {
+    return Row(
+      children: [
+        Text(aaa),
+        Text($bbb),
+        Text('$aaa'),
+        Text('${$bbb}'),
+      ],
+    );
+  }
+}
+''');
+  }
+
+  Future<void> test_state_first() async {
+    await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class _MyWidgetState extends State<MyWidget> {
+  @override
+  Widget build(BuildContext context) {
+    return Row(
+      children: [
+        Text(widget.aaa),
+        Text(widget.$bbb),
+        Text('${widget.aaa}'),
+        Text('${widget.$bbb}'),
+      ],
+    );
+  }
+}
+
+class /*caret*/MyWidget extends StatefulWidget {
+  final String aaa;
+  final String $bbb;
+
+  const MyWidget(this.aaa, this.$bbb);
+
+  @override
+  State<MyWidget> createState() => _MyWidgetState();
+}
+''');
+    await assertHasAssist(r'''
+import 'package:flutter/material.dart';
+
+class MyWidget extends StatelessWidget {
+  final String aaa;
+  final String $bbb;
+
+  const MyWidget(this.aaa, this.$bbb);
+
+  @override
+  Widget build(BuildContext context) {
+    return Row(
+      children: [
+        Text(aaa),
+        Text($bbb),
+        Text('$aaa'),
+        Text('${$bbb}'),
+      ],
+    );
+  }
+}
+''');
+  }
+
+  Future<void> test_state_methodInvocation() async {
+    await resolveTestCode('''
+import 'package:flutter/material.dart';
+
+class /*caret*/MyWidget extends StatefulWidget {
+  const MyWidget({super.key});
+
+  @override
+  State<MyWidget> createState() => _MyWidgetState();
+}
+
+class _MyWidgetState extends State<MyWidget> {
+  @override
+  Widget build(BuildContext context) {
+    setState(() {});
+    return Container();
+  }
+}
+''');
+    await assertNoAssist();
+  }
+
+  Future<void> test_state_override() async {
+    await resolveTestCode('''
+import 'package:flutter/material.dart';
+
+class /*caret*/MyWidget extends StatefulWidget {
+  const MyWidget({super.key});
+
+  @override
+  State<MyWidget> createState() => _MyWidgetState();
+}
+
+class _MyWidgetState extends State<MyWidget> {
+  @override
+  Widget build(BuildContext context) {
+    setState(() {});
+    return Container();
+  }
+}
+''');
+    await assertNoAssist();
+  }
+
+  Future<void> test_state_used_anotherWidget() async {
+    await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class /*caret*/FirstWidget extends StatefulWidget {
+  const FirstWidget({super.key});
+
+  @override
+  createState() => _MyWidgetState();
+}
+
+class SecondWidget extends StatefulWidget {
+  const SecondWidget({super.key});
+
+  @override
+  createState() => _MyWidgetState();
+}
+
+class _MyWidgetState extends State<FirstWidget> {
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}
+''');
+    await assertNoAssist();
+  }
+
+  Future<void> test_state_used_createState() async {
+    await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class /*caret*/MyWidget extends StatefulWidget {
+  const MyWidget({super.key});
+
+  @override
+  State<MyWidget> createState() => _MyWidgetState();
+
+  State<MyWidget> another() => createState();
+}
+
+class _MyWidgetState extends State<MyWidget> {
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}
+''');
+    await assertNoAssist();
+  }
+
+  Future<void> test_state_used_createState_return_stateClass() async {
+    await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class /*caret*/MyWidget extends StatefulWidget {
+  const MyWidget({super.key});
+
+  @override
+  _MyWidgetState createState() => _MyWidgetState();
+
+  _MyWidgetState another() => createState();
+}
+
+class _MyWidgetState extends State<MyWidget> {
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}
+''');
+    await assertNoAssist();
+  }
+
+  Future<void> test_state_used_instanceCreationExpression() async {
+    await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class /*caret*/MyWidget extends StatefulWidget {
+  const MyWidget({super.key});
+
+  @override
+  State<MyWidget> createState() => _MyWidgetState();
+
+  State<MyWidget> another() => _MyWidgetState();
+}
+
+class _MyWidgetState extends State<MyWidget> {
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}
+''');
+    await assertNoAssist();
+  }
+
+  Future<void> test_static_field() async {
+    await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class /*caret*/MyWidget extends StatefulWidget {
+  const MyWidget({super.key});
+
+  @override
+  State<MyWidget> createState() => _MyWidgetState();
+}
+
+class _MyWidgetState extends State<MyWidget> {
+  static var field = 1;
+
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}
+''');
+    await assertNoAssist();
+  }
+
+  Future<void> test_static_method() async {
+    await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class /*caret*/MyWidget extends StatefulWidget {
+  const MyWidget({super.key});
+
+  @override
+  State<MyWidget> createState() => _MyWidgetState();
+}
+
+class _MyWidgetState extends State<MyWidget> {
+
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+
+  static void staticMethod1() {
+    print('static 1');
+  }
+}
+''');
+    await assertNoAssist();
+  }
+
+  Future<void> test_typeParam_bound() async {
+    await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class /*caret*/MyWidget<T extends String> extends StatefulWidget {
+  @override
+  State<MyWidget<T>> createState() => _MyWidgetState<T>();
+}
+
+class _MyWidgetState<T extends String> extends State<MyWidget<T>> {
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}
+''');
+    await assertHasAssist(r'''
+import 'package:flutter/material.dart';
+
+class MyWidget<T extends String> extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}
+''');
+  }
+
+  Future<void> test_typeParam_different_bound() async {
+    await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class /*caret*/MyWidget<T extends String> extends StatefulWidget {
+  @override
+  State createState() => _MyWidgetState();
+}
+
+class _MyWidgetState<T extends List> extends State<MyWidget> {
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}
+''');
+    await assertNoAssist();
+  }
+
+  Future<void> test_typeParam_different_name() async {
+    await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class /*caret*/MyWidget<T> extends StatefulWidget {
+  @override
+  State<MyWidget<T>> createState() => _MyWidgetState<T>();
+}
+
+class _MyWidgetState<S> extends State<MyWidget<S>> {
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}
+''');
+    await assertNoAssist();
+  }
+
+  Future<void> test_typeParam_empty() async {
+    await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class /*caret*/MyWidget<T> extends StatefulWidget {
+  @override
+  State<MyWidget<T>> createState() => _MyWidgetState<T>();
+}
+
+class _MyWidgetState<T> extends State<MyWidget<T>> {
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}
+''');
+    await assertHasAssist(r'''
+import 'package:flutter/material.dart';
+
+class MyWidget<T> extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/assist/test_all.dart b/pkg/analysis_server/test/src/services/correction/assist/test_all.dart
index d32b3c0..4067547 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/test_all.dart
@@ -48,6 +48,8 @@
 import 'flutter_convert_to_children_test.dart' as flutter_convert_to_children;
 import 'flutter_convert_to_stateful_widget_test.dart'
     as flutter_convert_to_stateful_widget;
+import 'flutter_convert_to_stateless_widget_test.dart'
+    as flutter_convert_to_stateless_widget;
 import 'flutter_move_down_test.dart' as flutter_move_down;
 import 'flutter_move_up_test.dart' as flutter_move_up;
 import 'flutter_remove_widget_test.dart' as flutter_remove_widget;
@@ -130,6 +132,7 @@
     exchange_operands.main();
     flutter_convert_to_children.main();
     flutter_convert_to_stateful_widget.main();
+    flutter_convert_to_stateless_widget.main();
     flutter_move_down.main();
     flutter_move_up.main();
     flutter_remove_widget.main();
diff --git a/pkg/analysis_server/test/stress/replay/replay.dart b/pkg/analysis_server/test/stress/replay/replay.dart
index fbfe0e1..8988b18 100644
--- a/pkg/analysis_server/test/stress/replay/replay.dart
+++ b/pkg/analysis_server/test/stress/replay/replay.dart
@@ -222,7 +222,7 @@
       );
     var token = scanner.tokenize();
     // TODO(brianwilkerson) Randomize. Sometimes add zero (0) as a break point.
-    while (token.type != TokenType.EOF) {
+    while (!token.isEof) {
       // TODO(brianwilkerson) Break inside comments?
 //      Token comment = token.precedingComments;
       var offset = token.offset;
diff --git a/pkg/analysis_server/tool/code_completion/visitors.dart b/pkg/analysis_server/tool/code_completion/visitors.dart
index 0e36d73..2cb870b 100644
--- a/pkg/analysis_server/tool/code_completion/visitors.dart
+++ b/pkg/analysis_server/tool/code_completion/visitors.dart
@@ -374,7 +374,7 @@
 
   @override
   void visitExportDirective(ExportDirective node) {
-    safelyRecordKeywordCompletion(node.keyword);
+    safelyRecordKeywordCompletion(node.exportKeyword);
     super.visitExportDirective(node);
   }
 
@@ -494,7 +494,7 @@
 
   @override
   void visitImportDirective(ImportDirective node) {
-    safelyRecordKeywordCompletion(node.keyword);
+    safelyRecordKeywordCompletion(node.importKeyword);
     safelyRecordKeywordCompletion(node.asKeyword);
     safelyRecordKeywordCompletion(node.deferredKeyword);
     super.visitImportDirective(node);
diff --git a/pkg/analysis_server/tool/lsp_spec/generate_all.dart b/pkg/analysis_server/tool/lsp_spec/generate_all.dart
index afe9147..e01e49a 100644
--- a/pkg/analysis_server/tool/lsp_spec/generate_all.dart
+++ b/pkg/analysis_server/tool/lsp_spec/generate_all.dart
@@ -298,12 +298,24 @@
         // These fields have short-ish names because they're on the payload
         // for all suggestion-set backed completions.
         field('file', type: 'string'),
-        field('offset', type: 'int'),
         field('libId', type: 'int'),
-        field('displayUri', type: 'string'),
-        field('rOffset', type: 'int'), // replacementOffset
-        field('iLength', type: 'int'), // insertLength
-        field('rLength', type: 'int'), // replacementLength
+      ],
+      baseType: 'CompletionItemResolutionInfo',
+    ),
+    interface(
+      'DartNotImportedCompletionResolutionInfo',
+      [
+        field(
+          'file',
+          type: 'string',
+          comment: 'The file where the completion is being inserted.\n\n'
+              'This is used to compute where to add the import.',
+        ),
+        field(
+          'libraryUri',
+          type: 'string',
+          comment: 'The URI to be imported if this completion is selected.',
+        ),
       ],
       baseType: 'CompletionItemResolutionInfo',
     ),
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index c089234..c84f8ed 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 4.3.0-dev
+* Deprecated `Directive.keyword`, use corresponding `xyzToken` in specific directives.
+* Deprecated `LibraryElement.parts`, use `parts2` instead.
+
 ## 4.2.0
 * Update SDK constraints to `>=2.17.0 <3.0.0`.
 * Deprecated `ImportDirective.COMPARATOR`, use appropriate custom logic, if necessary.
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index 5f2d688..070e789 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -1525,6 +1525,7 @@
 
   /// Return the token representing the keyword that introduces this directive
   /// ('import', 'export', 'library' or 'part').
+  @Deprecated('Use specific xyzToken instead')
   Token get keyword;
 }
 
@@ -1704,6 +1705,9 @@
 abstract class ExportDirective implements NamespaceDirective {
   @override
   ExportElement? get element;
+
+  /// The token representing the 'export' keyword.
+  Token get exportKeyword;
 }
 
 /// A node that represents an expression.
@@ -2876,6 +2880,9 @@
   @override
   ImportElement? get element;
 
+  /// The token representing the 'import' keyword.
+  Token get importKeyword;
+
   /// Return the prefix to be used with the imported names, or `null` if the
   /// imported names are not prefixed.
   SimpleIdentifier? get prefix;
@@ -4532,6 +4539,7 @@
 
   /// Return the content of the [uri], or `null` if the AST structure has not
   /// been resolved, or if the [uri] has a string interpolation.
+  /// TODO(scheglov) Deprecate and remove it.
   String? get uriContent;
 
   /// Return the element associated with the [uri] of this directive, or `null`
@@ -4540,9 +4548,11 @@
   ///
   /// Examples of the latter case include a directive that contains an invalid
   /// URL or a URL that does not exist.
+  /// TODO(scheglov) Deprecate and remove it.
   Element? get uriElement;
 
   /// Return the source to which the [uri] was resolved.
+  /// TODO(scheglov) Deprecate and remove it.
   Source? get uriSource;
 }
 
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index 4291006..6f64355 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -932,23 +932,25 @@
   static const ElementKind PARAMETER =
       ElementKind('PARAMETER', 21, "parameter");
 
-  static const ElementKind PREFIX = ElementKind('PREFIX', 22, "import prefix");
+  static const ElementKind PART = ElementKind('PART', 22, "part");
 
-  static const ElementKind SETTER = ElementKind('SETTER', 23, "setter");
+  static const ElementKind PREFIX = ElementKind('PREFIX', 23, "import prefix");
+
+  static const ElementKind SETTER = ElementKind('SETTER', 24, "setter");
 
   static const ElementKind TOP_LEVEL_VARIABLE =
-      ElementKind('TOP_LEVEL_VARIABLE', 24, "top level variable");
+      ElementKind('TOP_LEVEL_VARIABLE', 25, "top level variable");
 
   static const ElementKind FUNCTION_TYPE_ALIAS =
-      ElementKind('FUNCTION_TYPE_ALIAS', 25, "function type alias");
+      ElementKind('FUNCTION_TYPE_ALIAS', 26, "function type alias");
 
   static const ElementKind TYPE_PARAMETER =
-      ElementKind('TYPE_PARAMETER', 26, "type parameter");
+      ElementKind('TYPE_PARAMETER', 27, "type parameter");
 
   static const ElementKind TYPE_ALIAS =
-      ElementKind('TYPE_ALIAS', 27, "type alias");
+      ElementKind('TYPE_ALIAS', 28, "type alias");
 
-  static const ElementKind UNIVERSE = ElementKind('UNIVERSE', 28, "<universe>");
+  static const ElementKind UNIVERSE = ElementKind('UNIVERSE', 29, "<universe>");
 
   static const List<ElementKind> values = [
     CLASS,
@@ -970,6 +972,7 @@
     NAME,
     NEVER,
     PARAMETER,
+    PART,
     PREFIX,
     SETTER,
     TOP_LEVEL_VARIABLE,
@@ -1071,6 +1074,8 @@
 
   R? visitParameterElement(ParameterElement element);
 
+  R? visitPartElement(PartElement element);
+
   R? visitPrefixElement(PrefixElement element);
 
   R? visitPropertyAccessorElement(PropertyAccessorElement element);
@@ -1388,8 +1393,12 @@
   /// Return a list containing all of the compilation units that are included in
   /// this library using a `part` directive. This does not include the defining
   /// compilation unit that contains the `part` directives.
+  @Deprecated('Use parts2 instead')
   List<CompilationUnitElement> get parts;
 
+  /// Returns the list of `part` directives of this library.
+  List<PartElement> get parts2;
+
   /// The public [Namespace] of this library.
   Namespace get publicNamespace;
 
@@ -1656,6 +1665,30 @@
   });
 }
 
+/// A 'part' directive within a library.
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class PartElement implements _ExistingElement {}
+
+/// [PartElementWithSource] that represents a valid part of this library.
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class PartElementWithPart implements PartElementWithSource {
+  /// The part [CompilationUnitElement] referenced by [uriSource].
+  CompilationUnitElement get includedUnit;
+}
+
+/// [PartElement] with a relative URI that resolves to a [Source].
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class PartElementWithSource implements PartElement {
+  /// The string value of the URI.
+  String get relativeUriString;
+
+  /// The source to which [relativeUriString] resolves.
+  Source get uriSource;
+}
+
 /// A prefix used to import one or more libraries into another library.
 ///
 /// Clients may not extend, implement or mix-in this class.
diff --git a/pkg/analyzer/lib/dart/element/visitor.dart b/pkg/analyzer/lib/dart/element/visitor.dart
index ace3ca2..86e4839 100644
--- a/pkg/analyzer/lib/dart/element/visitor.dart
+++ b/pkg/analyzer/lib/dart/element/visitor.dart
@@ -167,6 +167,9 @@
       visitLocalElement(element);
 
   @override
+  R? visitPartElement(PartElement element) => visitElement(element);
+
+  @override
   R? visitPrefixElement(PrefixElement element) => visitElement(element);
 
   @override
@@ -318,6 +321,12 @@
   }
 
   @override
+  R? visitPartElement(PartElement element) {
+    element.visitChildren(this);
+    return null;
+  }
+
+  @override
   R? visitPrefixElement(PrefixElement element) {
     element.visitChildren(this);
     return null;
@@ -422,6 +431,9 @@
   R? visitParameterElement(ParameterElement element) => null;
 
   @override
+  R? visitPartElement(PartElement element) => null;
+
+  @override
   R? visitPrefixElement(PrefixElement element) => null;
 
   @override
@@ -513,6 +525,9 @@
   R? visitParameterElement(ParameterElement element) => _throw(element);
 
   @override
+  R? visitPartElement(PartElement element) => _throw(element);
+
+  @override
   R? visitPrefixElement(PrefixElement element) => _throw(element);
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index cb70639..b692981 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -85,7 +85,7 @@
 /// TODO(scheglov) Clean up the list of implicitly analyzed files.
 class AnalysisDriver implements AnalysisDriverGeneric {
   /// The version of data format, should be incremented on every format change.
-  static const int DATA_VERSION = 227;
+  static const int DATA_VERSION = 228;
 
   /// The number of exception contexts allowed to write. Once this field is
   /// zero, we stop writing any new exception contexts in this process.
diff --git a/pkg/analyzer/lib/src/dart/analysis/index.dart b/pkg/analyzer/lib/src/dart/analysis/index.dart
index 8406aee..8d74735 100644
--- a/pkg/analyzer/lib/src/dart/analysis/index.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/index.dart
@@ -793,9 +793,9 @@
 
   @override
   void visitPartDirective(PartDirective node) {
-    var element = node.element as CompilationUnitElement?;
-    if (element?.source != null) {
-      recordUriReference(element, node.uri);
+    final partElement = node.element;
+    if (partElement is PartElementWithPart) {
+      recordUriReference(partElement.includedUnit, node.uri);
     }
     super.visitPartDirective(node);
   }
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index 33a041e..1e61c76 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -805,8 +805,14 @@
   }) {
     StringLiteral partUri = directive.uri;
 
-    final partState = _library.parts[partIndexes.directive++];
+    final index = partIndexes.directive++;
+
+    final partState = _library.parts[index];
     directive.uriSource = partState.includedSource;
+
+    final partElement = _libraryElement.parts2[index];
+    directive.element = partElement;
+
     if (partState is! PartDirectiveWithUri) {
       libraryErrorReporter.reportErrorForNode(
         CompileTimeErrorCode.URI_WITH_INTERPOLATION,
@@ -815,9 +821,7 @@
       return;
     }
 
-    // TODO(scheglov) This should not be necessary if we build `PartElement`
-    // for every `part` directive.
-    if (partIndexes.element >= _libraryElement.parts.length) {
+    if (partState is! PartDirectiveWithFile) {
       final errorCode = partState.uri.isValid
           ? CompileTimeErrorCode.URI_DOES_NOT_EXIST
           : CompileTimeErrorCode.INVALID_URI;
@@ -828,15 +832,6 @@
       );
       return;
     }
-
-    if (partState is! PartDirectiveWithFile) {
-      libraryErrorReporter.reportErrorForNode(
-        CompileTimeErrorCode.URI_DOES_NOT_EXIST,
-        directive.uri,
-        [partState.uri.relativeUriStr],
-      );
-      return;
-    }
     final includedFile = partState.includedFile;
     final includedKind = includedFile.kind;
 
@@ -887,10 +882,11 @@
       return;
     }
 
+    // TODO(scheglov) Unsafe.
     var partUnit = units[includedFile]!;
-    var partElement = _libraryElement.parts[partIndexes.element++];
-    partUnit.element = partElement;
-    directive.element = partElement;
+    if (partElement is PartElementWithPart) {
+      partUnit.element = partElement.includedUnit;
+    }
 
     final partSource = includedKind.file.source;
     directive.uriSource = partSource;
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_context.dart b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
index 0ef2a0e..b7b769b 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_context.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
@@ -125,7 +125,6 @@
     var librariesLoaded = 0;
     var librariesLinked = 0;
     var librariesLinkedTimer = Stopwatch();
-    var inputsTimer = Stopwatch();
     var bytesGet = 0;
     var bytesPut = 0;
 
@@ -176,54 +175,12 @@
           cycle.libraries.map((e) => e.file.path).toSet(),
         );
 
-        inputsTimer.start();
-        var inputLibraries = <LinkInputLibrary>[];
-        for (var library in cycle.libraries) {
-          var librarySource = library.file.source;
-
-          var inputUnits = <LinkInputUnit>[];
-          var partIndex = -1;
-          for (var file in library.files) {
-            var isSynthetic = !file.exists;
-            var unit = file.parse();
-
-            performance.getDataInt('parseCount').increment();
-            performance.getDataInt('parseLength').add(unit.length);
-
-            String? partUriStr;
-            if (partIndex >= 0) {
-              partUriStr = library.file.unlinked2.parts[partIndex].uri;
-            }
-            partIndex++;
-
-            inputUnits.add(
-              LinkInputUnit(
-                // TODO(scheglov) bad, group part data
-                partDirectiveIndex: partIndex - 1,
-                partUriStr: partUriStr,
-                source: file.source,
-                sourceContent: file.content,
-                isSynthetic: isSynthetic,
-                unit: unit,
-              ),
-            );
-          }
-
-          inputLibraries.add(
-            LinkInputLibrary(
-              source: librarySource,
-              units: inputUnits,
-            ),
-          );
-        }
-        inputsTimer.stop();
-
         LinkResult linkResult;
         try {
-          linkResult = await link2(
+          linkResult = await link(
             elementFactory: elementFactory,
             performance: OperationPerformanceImpl('link'),
-            inputLibraries: inputLibraries,
+            inputLibraries: cycle.libraries,
             macroExecutor: macroExecutor,
           );
           librariesLinked += cycle.libraries.length;
@@ -290,7 +247,6 @@
       logger.writeln(
         '[librariesTotal: $librariesTotal]'
         '[librariesLoaded: $librariesLoaded]'
-        '[inputsTimer: ${inputsTimer.elapsedMilliseconds} ms]'
         '[librariesLinked: $librariesLinked]'
         '[librariesLinkedTimer: ${librariesLinkedTimer.elapsedMilliseconds} ms]'
         '[bytesGet: $bytesGet][bytesPut: $bytesPut]',
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 463df80..d56a2cb 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -910,8 +910,9 @@
   Token get endToken => semicolon;
 
   @override
-  Token get firstTokenAfterCommentAndMetadata => keyword;
+  Token get firstTokenAfterCommentAndMetadata => importKeyword;
 
+  @Deprecated('Use specific xyzToken instead')
   @override
   Token get keyword => importKeyword;
 
@@ -922,7 +923,7 @@
 
   @override
   ChildEntities get _childEntities => super._childEntities
-    ..addToken('keyword', keyword)
+    ..addToken('importKeyword', importKeyword)
     ..addToken('augmentKeyword', augmentKeyword)
     ..addNode('uri', uri)
     ..addToken('semicolon', semicolon);
@@ -3250,7 +3251,8 @@
 /// A node that represents a directive.
 ///
 ///    directive ::=
-///        [ExportDirective]
+///        [AugmentationImportDirective]
+///      | [ExportDirective]
 ///      | [ImportDirective]
 ///      | [LibraryDirective]
 ///      | [PartDirective]
@@ -3763,6 +3765,9 @@
 ///        [Annotation] 'export' [StringLiteral] [Combinator]* ';'
 class ExportDirectiveImpl extends NamespaceDirectiveImpl
     implements ExportDirective {
+  @override
+  Token exportKeyword;
+
   /// Initialize a newly created export directive. Either or both of the
   /// [comment] and [metadata] can be `null` if the directive does not have the
   /// corresponding attribute. The list of [combinators] can be `null` if there
@@ -3770,7 +3775,7 @@
   ExportDirectiveImpl(
       super.comment,
       super.metadata,
-      super.keyword,
+      this.exportKeyword,
       super.libraryUri,
       super.configurations,
       super.combinators,
@@ -3780,13 +3785,20 @@
   ExportElement? get element => super.element as ExportElement?;
 
   @override
+  Token get firstTokenAfterCommentAndMetadata => exportKeyword;
+
+  @Deprecated('Use specific xyzToken instead')
+  @override
+  Token get keyword => exportKeyword;
+
+  @override
   LibraryElement? get uriElement {
     return element?.exportedLibrary;
   }
 
   @override
   ChildEntities get _childEntities => super._childEntities
-    ..addToken('keyword', keyword)
+    ..addToken('exportKeyword', exportKeyword)
     ..addNode('uri', uri)
     ..addNodeList('combinators', combinators)
     ..addToken('semicolon', semicolon);
@@ -6369,6 +6381,9 @@
 //         [Combinator]* ';'
 class ImportDirectiveImpl extends NamespaceDirectiveImpl
     implements ImportDirective {
+  @override
+  Token importKeyword;
+
   /// The token representing the 'deferred' keyword, or `null` if the imported
   /// is not deferred.
   @override
@@ -6392,7 +6407,7 @@
   ImportDirectiveImpl(
       CommentImpl? comment,
       List<Annotation>? metadata,
-      Token keyword,
+      this.importKeyword,
       StringLiteralImpl libraryUri,
       List<Configuration>? configurations,
       this.deferredKeyword,
@@ -6400,8 +6415,8 @@
       this._prefix,
       List<Combinator>? combinators,
       Token semicolon)
-      : super(comment, metadata, keyword, libraryUri, configurations,
-            combinators, semicolon) {
+      : super(comment, metadata, libraryUri, configurations, combinators,
+            semicolon) {
     _becomeParentOf(_prefix);
   }
 
@@ -6409,6 +6424,13 @@
   ImportElement? get element => super.element as ImportElement?;
 
   @override
+  Token get firstTokenAfterCommentAndMetadata => importKeyword;
+
+  @Deprecated('Use specific xyzToken instead')
+  @override
+  Token get keyword => importKeyword;
+
+  @override
   SimpleIdentifierImpl? get prefix => _prefix;
 
   set prefix(SimpleIdentifier? identifier) {
@@ -6422,7 +6444,7 @@
 
   @override
   ChildEntities get _childEntities => super._childEntities
-    ..addToken('keyword', keyword)
+    ..addToken('importKeyword', importKeyword)
     ..addNode('uri', uri)
     ..addToken('deferredKeyword', deferredKeyword)
     ..addToken('asKeyword', asKeyword)
@@ -7265,6 +7287,7 @@
   @override
   Token get firstTokenAfterCommentAndMetadata => libraryKeyword;
 
+  @Deprecated('Use specific xyzToken instead')
   @override
   Token get keyword => libraryKeyword;
 
@@ -7318,6 +7341,7 @@
   @override
   Token get firstTokenAfterCommentAndMetadata => libraryKeyword;
 
+  @Deprecated('Use specific xyzToken instead')
   @override
   Token get keyword => libraryKeyword;
 
@@ -8168,10 +8192,6 @@
 ///      | [ImportDirective]
 abstract class NamespaceDirectiveImpl extends UriBasedDirectiveImpl
     implements NamespaceDirective {
-  /// The token representing the 'import' or 'export' keyword.
-  @override
-  Token keyword;
-
   /// The configurations used to control which library will actually be loaded
   /// at run-time.
   final NodeListImpl<Configuration> _configurations = NodeListImpl._();
@@ -8194,14 +8214,12 @@
   /// corresponding attribute. The list of [combinators] can be `null` if there
   /// are no combinators.
   NamespaceDirectiveImpl(
-      CommentImpl? comment,
-      List<Annotation>? metadata,
-      this.keyword,
-      StringLiteralImpl libraryUri,
+      super.comment,
+      super.metadata,
+      super.libraryUri,
       List<Configuration>? configurations,
       List<Combinator>? combinators,
-      this.semicolon)
-      : super(comment, metadata, libraryUri) {
+      this.semicolon) {
     _configurations._initialize(this, configurations);
     _combinators._initialize(this, combinators);
   }
@@ -8216,9 +8234,6 @@
   Token get endToken => semicolon;
 
   @override
-  Token get firstTokenAfterCommentAndMetadata => keyword;
-
-  @override
   LibraryElement? get uriElement;
 }
 
@@ -8757,11 +8772,18 @@
   @override
   Token get firstTokenAfterCommentAndMetadata => partKeyword;
 
+  @Deprecated('Use specific xyzToken instead')
   @override
   Token get keyword => partKeyword;
 
   @override
-  CompilationUnitElement? get uriElement => element as CompilationUnitElement?;
+  CompilationUnitElement? get uriElement {
+    final partElement = element as PartElement?;
+    if (partElement is PartElementWithPart) {
+      return partElement.includedUnit;
+    }
+    return null;
+  }
 
   @override
   ChildEntities get _childEntities => super._childEntities
@@ -8813,6 +8835,7 @@
   @override
   Token get firstTokenAfterCommentAndMetadata => partKeyword;
 
+  @Deprecated('Use specific xyzToken instead')
   @override
   Token get keyword => partKeyword;
 
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index 46b2fb6..f1eb7bf 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -167,7 +167,7 @@
     return isEqualNodes(
             node.documentationComment, other.documentationComment) &&
         _isEqualNodeLists(node.metadata, other.metadata) &&
-        isEqualTokens(node.keyword, other.keyword) &&
+        isEqualTokens(node.importKeyword, other.importKeyword) &&
         isEqualNodes(node.uri, other.uri) &&
         isEqualTokens(node.semicolon, other.semicolon);
   }
@@ -468,7 +468,7 @@
     return isEqualNodes(
             node.documentationComment, other.documentationComment) &&
         _isEqualNodeLists(node.metadata, other.metadata) &&
-        isEqualTokens(node.keyword, other.keyword) &&
+        isEqualTokens(node.exportKeyword, other.exportKeyword) &&
         isEqualNodes(node.uri, other.uri) &&
         _isEqualNodeLists(node.combinators, other.combinators) &&
         isEqualTokens(node.semicolon, other.semicolon);
@@ -760,7 +760,7 @@
     return isEqualNodes(
             node.documentationComment, other.documentationComment) &&
         _isEqualNodeLists(node.metadata, other.metadata) &&
-        isEqualTokens(node.keyword, other.keyword) &&
+        isEqualTokens(node.importKeyword, other.importKeyword) &&
         isEqualNodes(node.uri, other.uri) &&
         _isEqualNodeLists(node.configurations, other.configurations) &&
         isEqualTokens(node.deferredKeyword, other.deferredKeyword) &&
@@ -1481,7 +1481,7 @@
       // Fasta scanner reports unterminated string literal errors
       // and generates a synthetic string token with non-zero length.
       // Because of this, check for length > 0 rather than !isSynthetic.
-      if (endToken.type == TokenType.EOF || endToken.length > 0) {
+      if (endToken.isEof || endToken.length > 0) {
         break;
       }
       endToken = endToken.previous!;
@@ -1570,7 +1570,7 @@
       // Fasta scanner reports unterminated string literal errors
       // and generates a synthetic string token with non-zero length.
       // Because of this, check for length > 0 rather than !isSynthetic.
-      if (endToken.type == TokenType.EOF || endToken.length > 0) {
+      if (endToken.isEof || endToken.length > 0) {
         break;
       }
       endToken = endToken.previous!;
diff --git a/pkg/analyzer/lib/src/dart/element/display_string_builder.dart b/pkg/analyzer/lib/src/dart/element/display_string_builder.dart
index 2e23aab..17553e0 100644
--- a/pkg/analyzer/lib/src/dart/element/display_string_builder.dart
+++ b/pkg/analyzer/lib/src/dart/element/display_string_builder.dart
@@ -162,6 +162,17 @@
     _writeNullability(type.nullabilitySuffix);
   }
 
+  void writePartElement(PartElementImpl element) {
+    _write('part ');
+    if (element is PartElementWithPartImpl) {
+      _write('unit ${element.includedUnit.source.uri}');
+    } else if (element is PartElementWithSourceImpl) {
+      _write('uriSource ${element.uriSource}');
+    } else {
+      _write('<unknown>');
+    }
+  }
+
   void writePrefixElement(PrefixElementImpl element) {
     _write('as ');
     _write(element.displayName);
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 305a074..41d1897 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -16,7 +16,6 @@
 import 'package:analyzer/dart/element/type_provider.dart';
 import 'package:analyzer/dart/element/type_system.dart';
 import 'package:analyzer/error/error.dart';
-import 'package:analyzer/src/context/source.dart';
 import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/dart/analysis/session.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
@@ -48,6 +47,7 @@
 import 'package:analyzer/src/summary2/macro_application_error.dart';
 import 'package:analyzer/src/summary2/reference.dart';
 import 'package:analyzer/src/task/inference_error.dart';
+import 'package:analyzer/src/util/file_paths.dart' as file_paths;
 import 'package:collection/collection.dart';
 
 /// A concrete implementation of a [ClassElement].
@@ -3730,9 +3730,8 @@
   /// an entry point.
   FunctionElement? _entryPoint;
 
-  /// A list containing all of the compilation units that are included in this
-  /// library using a `part` directive.
-  List<CompilationUnitElement> _parts = const <CompilationUnitElement>[];
+  /// The list of `part` directives of this library.
+  List<PartElement> _parts2 = const <PartElement>[];
 
   /// The element representing the synthetic function `loadLibrary` that is
   /// defined for this library, or `null` if the element has not yet been
@@ -3930,18 +3929,27 @@
   @override
   String get name => super.name!;
 
+  @Deprecated('Use parts2 instead')
   @override
-  List<CompilationUnitElement> get parts => _parts;
+  List<CompilationUnitElement> get parts {
+    return _parts2
+        .whereType<PartElementWithPart>()
+        .map((partElement) => partElement.includedUnit)
+        .toList();
+  }
 
-  /// Set the compilation units that are included in this library using a `part`
-  /// directive to the given list of [parts].
-  set parts(List<CompilationUnitElement> parts) {
-    for (CompilationUnitElement compilationUnit in parts) {
-      assert((compilationUnit as CompilationUnitElementImpl).librarySource ==
-          source);
-      (compilationUnit as CompilationUnitElementImpl).enclosingElement = this;
+  @override
+  List<PartElement> get parts2 => _parts2;
+
+  set parts2(List<PartElement> parts) {
+    for (final part in parts) {
+      part as PartElementImpl;
+      part.enclosingElement = this;
+      if (part is PartElementWithPartImpl) {
+        part.includedUnit.enclosingElement = this;
+      }
     }
-    _parts = parts;
+    _parts2 = parts;
   }
 
   @override
@@ -3984,10 +3992,10 @@
 
   @override
   List<CompilationUnitElement> get units {
-    List<CompilationUnitElement> units = <CompilationUnitElement>[];
-    units.add(_definingCompilationUnit);
-    units.addAll(_parts);
-    return units;
+    return [
+      _definingCompilationUnit,
+      ...parts2.whereType<PartElementWithPart>().map((e) => e.includedUnit),
+    ];
   }
 
   @override
@@ -4004,12 +4012,8 @@
   }
 
   ClassElement? getEnum(String name) {
-    var element = _definingCompilationUnit.getEnum(name);
-    if (element != null) {
-      return element;
-    }
-    for (CompilationUnitElement part in _parts) {
-      element = part.getEnum(name);
+    for (final unitElement in units) {
+      final element = unitElement.getEnum(name);
       if (element != null) {
         return element;
       }
@@ -4024,8 +4028,14 @@
   }
 
   @override
-  ClassElement? getType(String className) {
-    return getTypeFromParts(className, _definingCompilationUnit, _parts);
+  ClassElement? getType(String name) {
+    for (final unitElement in units) {
+      final element = unitElement.getType(name);
+      if (element != null) {
+        return element;
+      }
+    }
+    return null;
   }
 
   /// Indicates whether it is unnecessary to report an undefined identifier
@@ -4060,8 +4070,10 @@
     }
 
     if (prefix == null && name.startsWith(r'_$')) {
-      for (var partElement in parts) {
-        if (partElement.isSynthetic && isGeneratedSource(partElement.source)) {
+      for (var partElement in parts2) {
+        if (partElement is PartElementWithSource &&
+            partElement is! PartElementWithPart &&
+            file_paths.isGenerated(partElement.relativeUriString)) {
           return true;
         }
       }
@@ -4101,7 +4113,7 @@
   @override
   void visitChildren(ElementVisitor visitor) {
     super.visitChildren(visitor);
-    safelyVisitChildren(_parts, visitor);
+    safelyVisitChildren(parts2, visitor);
   }
 
   static List<PrefixElement> buildPrefixesFromImports(
@@ -5089,6 +5101,61 @@
   }
 }
 
+class PartElementImpl extends _ExistingElementImpl implements PartElement {
+  PartElementImpl() : super(null, -1);
+
+  @override
+  CompilationUnitElementImpl get enclosingUnit {
+    var enclosingLibrary = enclosingElement as LibraryElementImpl;
+    return enclosingLibrary._definingCompilationUnit;
+  }
+
+  @override
+  String get identifier => 'part';
+
+  @override
+  ElementKind get kind => ElementKind.PART;
+
+  @override
+  T? accept<T>(ElementVisitor<T> visitor) => visitor.visitPartElement(this);
+
+  @override
+  void appendTo(ElementDisplayStringBuilder builder) {
+    builder.writePartElement(this);
+  }
+}
+
+class PartElementWithPartImpl extends PartElementWithSourceImpl
+    implements PartElementWithPart {
+  @override
+  final CompilationUnitElementImpl includedUnit;
+
+  PartElementWithPartImpl({
+    required super.relativeUriString,
+    required super.uriSource,
+    required this.includedUnit,
+  });
+
+  @override
+  void visitChildren(ElementVisitor visitor) {
+    includedUnit.accept(visitor);
+  }
+}
+
+class PartElementWithSourceImpl extends PartElementImpl
+    implements PartElementWithSource {
+  @override
+  final String relativeUriString;
+
+  @override
+  final Source uriSource;
+
+  PartElementWithSourceImpl({
+    required this.relativeUriString,
+    required this.uriSource,
+  });
+}
+
 /// A concrete implementation of a [PrefixElement].
 class PrefixElementImpl extends _ExistingElementImpl implements PrefixElement {
   /// The scope of this prefix, `null` if it has not been created yet.
diff --git a/pkg/analyzer/lib/src/dart/resolver/scope.dart b/pkg/analyzer/lib/src/dart/resolver/scope.dart
index 9a76055..84552fb 100644
--- a/pkg/analyzer/lib/src/dart/resolver/scope.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/scope.dart
@@ -180,9 +180,8 @@
   /// [library].
   Namespace createPublicNamespaceForLibrary(LibraryElement library) {
     Map<String, Element> definedNames = HashMap<String, Element>();
-    _addPublicNames(definedNames, library.definingCompilationUnit);
-    for (CompilationUnitElement compilationUnit in library.parts) {
-      _addPublicNames(definedNames, compilationUnit);
+    for (final unitElement in library.units) {
+      _addPublicNames(definedNames, unitElement);
     }
 
     // For libraries that import `dart:core` with a prefix, we have to add
diff --git a/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart b/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart
index 14775ba..55cd57b4 100644
--- a/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart
+++ b/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart
@@ -327,11 +327,11 @@
     CompilationUnitElement element = node.declaredElement!;
     if (element != _currentLibrary.definingCompilationUnit) {
       addWithoutChecking(_currentLibrary.definingCompilationUnit);
-      for (CompilationUnitElement part in _currentLibrary.parts) {
-        if (element == part) {
+      for (final unitElement in _currentLibrary.units) {
+        if (element == unitElement) {
           break;
         }
-        addWithoutChecking(part);
+        addWithoutChecking(unitElement);
       }
     }
     for (CompilationUnitMember member in node.declarations) {
diff --git a/pkg/analyzer/lib/src/error/todo_finder.dart b/pkg/analyzer/lib/src/error/todo_finder.dart
index b3d3b24..bed283d 100644
--- a/pkg/analyzer/lib/src/error/todo_finder.dart
+++ b/pkg/analyzer/lib/src/error/todo_finder.dart
@@ -42,7 +42,7 @@
   ///
   /// @param token the head of the list of tokens being searched
   void _gatherTodoComments(Token? token, LineInfo lineInfo) {
-    while (token != null && token.type != TokenType.EOF) {
+    while (token != null && !token.isEof) {
       Token? commentToken = token.precedingComments;
       while (commentToken != null) {
         if (commentToken.type == TokenType.SINGLE_LINE_COMMENT ||
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_tag.dart b/pkg/analyzer/lib/src/summary2/ast_binary_tag.dart
index 38aa374..e81a7dc 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_tag.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_tag.dart
@@ -7,6 +7,12 @@
   static const int genericFunctionElement = 1;
 }
 
+enum PartElementKind {
+  withPart,
+  withSource,
+  withNothing,
+}
+
 class Tag {
   static const int Nothing = 0;
   static const int Something = 1;
diff --git a/pkg/analyzer/lib/src/summary2/ast_text_printer.dart b/pkg/analyzer/lib/src/summary2/ast_text_printer.dart
index 7f45994..22d52eb 100644
--- a/pkg/analyzer/lib/src/summary2/ast_text_printer.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_text_printer.dart
@@ -333,7 +333,7 @@
   @override
   void visitExportDirective(ExportDirective node) {
     _directive(node);
-    _token(node.keyword);
+    _token(node.exportKeyword);
     node.uri.accept(this);
     node.configurations.accept(this);
     _nodeList(node.combinators);
@@ -597,7 +597,7 @@
   @override
   void visitImportDirective(ImportDirective node) {
     _directive(node);
-    _token(node.keyword);
+    _token(node.importKeyword);
     node.uri.accept(this);
     node.configurations.accept(this);
     _token(node.deferredKeyword);
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index 9efb948..b8a91b6 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -125,8 +125,6 @@
 
 class CompilationUnitElementLinkedData
     extends ElementLinkedData<CompilationUnitElementImpl> {
-  ApplyConstantOffsets? applyConstantOffsets;
-
   CompilationUnitElementLinkedData({
     required Reference reference,
     required LibraryReader libraryReader,
@@ -135,12 +133,7 @@
   }) : super(reference, libraryReader, unitElement, offset);
 
   @override
-  void _read(element, reader) {
-    element.metadata = reader._readAnnotationList(
-      unitElement: unitElement,
-    );
-    applyConstantOffsets?.perform();
-  }
+  void _read(element, reader) {}
 }
 
 class ConstructorElementLinkedData
@@ -393,6 +386,13 @@
       export.exportedLibrary = reader.readElement() as LibraryElementImpl?;
     }
 
+    for (final part in element.parts2) {
+      part as PartElementImpl;
+      part.metadata = reader._readAnnotationList(
+        unitElement: unitElement,
+      );
+    }
+
     element.entryPoint = reader.readElement() as FunctionElement?;
 
     applyConstantOffsets?.perform();
@@ -451,29 +451,30 @@
     LibraryElementFlags.read(_reader, libraryElement);
 
     var unitContainerRef = _reference.getChild('@unit');
-    var unitCount = _reader.readUInt30();
-    var units = <CompilationUnitElementImpl>[];
-    for (var i = 0; i < unitCount; i++) {
-      var unitElement = _readUnitElement(
-        sourceFactory: sourceFactory,
+
+    libraryElement.definingCompilationUnit = _readUnitElement(
+      sourceFactory: sourceFactory,
+      unitContainerRef: unitContainerRef,
+      libraryElement: libraryElement,
+      librarySource: librarySource,
+      unitSource: librarySource,
+    );
+
+    libraryElement.parts2 = _reader.readTypedList(() {
+      return _readPartElement(
         unitContainerRef: unitContainerRef,
         libraryElement: libraryElement,
-        librarySource: librarySource,
       );
-      units.add(unitElement);
-    }
+    });
 
     libraryElement.exportedReferences = _reader.readTypedList(
       _readExportedReference,
     );
 
-    libraryElement.definingCompilationUnit = units[0];
-    libraryElement.parts = units.skip(1).toList();
-
     libraryElement.linkedData = LibraryElementLinkedData(
       reference: _reference,
       libraryReader: this,
-      unitElement: units[0],
+      unitElement: libraryElement.definingCompilationUnit,
       offset: resolutionOffset,
     );
 
@@ -977,6 +978,47 @@
     });
   }
 
+  PartElement _readPartElement({
+    required Reference unitContainerRef,
+    required LibraryElementImpl libraryElement,
+  }) {
+    final analysisContext = _elementFactory.analysisContext;
+    final sourceFactory = analysisContext.sourceFactory;
+
+    final kindIndex = _reader.readByte();
+    final kind = PartElementKind.values[kindIndex];
+    switch (kind) {
+      case PartElementKind.withPart:
+        final relativeUriString = _reader.readStringReference();
+        final uriStr = _reader.readStringReference();
+        final uri = Uri.parse(uriStr);
+        final uriSource = sourceFactory.forUri2(uri)!;
+        final unitElement = _readUnitElement(
+          sourceFactory: sourceFactory,
+          unitContainerRef: unitContainerRef,
+          libraryElement: libraryElement,
+          librarySource: libraryElement.source,
+          unitSource: uriSource,
+        );
+        return PartElementWithPartImpl(
+          relativeUriString: relativeUriString,
+          uriSource: uriSource,
+          includedUnit: unitElement,
+        );
+      case PartElementKind.withSource:
+        final relativeUriString = _reader.readStringReference();
+        final uriStr = _reader.readStringReference();
+        final uri = Uri.parse(uriStr);
+        final uriSource = sourceFactory.forUri2(uri)!;
+        return PartElementWithSourceImpl(
+          relativeUriString: relativeUriString,
+          uriSource: uriSource,
+        );
+      case PartElementKind.withNothing:
+        return PartElementImpl();
+    }
+  }
+
   PropertyAccessorElementImpl _readPropertyAccessorElement(
     CompilationUnitElementImpl unitElement,
     ElementImpl classElement,
@@ -1196,11 +1238,9 @@
     required Reference unitContainerRef,
     required LibraryElementImpl libraryElement,
     required Source librarySource,
+    required Source unitSource,
   }) {
     var resolutionOffset = _baseResolutionOffset + _reader.readUInt30();
-    var unitUriStr = _reader.readStringReference();
-    var unitUri = Uri.parse(unitUriStr);
-    var unitSource = sourceFactory.forUri2(unitUri)!;
 
     var unitElement = CompilationUnitElementImpl(
       source: unitSource,
@@ -1208,7 +1248,7 @@
       lineInfo: LineInfo([0]),
     );
 
-    var unitReference = unitContainerRef.getChild(unitUriStr);
+    var unitReference = unitContainerRef.getChild('${unitSource.uri}');
     unitElement.setLinkedData(
       unitReference,
       CompilationUnitElementLinkedData(
diff --git a/pkg/analyzer/lib/src/summary2/bundle_writer.dart b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
index ffd3fd6..1993b8e 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
@@ -104,12 +104,14 @@
     _resolutionSink._writeAnnotationList(libraryElement.metadata);
     _writeList(libraryElement.imports, _writeImportElement);
     _writeList(libraryElement.exports, _writeExportElement);
+    for (final partElement in libraryElement.parts2) {
+      _resolutionSink._writeAnnotationList(partElement.metadata);
+    }
     _resolutionSink.writeElement(libraryElement.entryPoint);
     LibraryElementFlags.write(_sink, libraryElement);
-    _sink.writeUInt30(libraryElement.units.length);
-    for (var unitElement in libraryElement.units) {
-      _writeUnitElement(unitElement);
-    }
+    _writeUnitElement(libraryElement.definingCompilationUnit);
+    _writeList(libraryElement.parts2, _writePartElement);
+
     _writeExportedReferences(libraryElement.exportedReferences);
 
     _libraries.add(
@@ -391,6 +393,21 @@
     });
   }
 
+  void _writePartElement(PartElement element) {
+    if (element is PartElementWithPart) {
+      _sink.writeByte(PartElementKind.withPart.index);
+      _sink._writeStringReference(element.relativeUriString);
+      _sink._writeStringReference('${element.uriSource.uri}');
+      _writeUnitElement(element.includedUnit);
+    } else if (element is PartElementWithSource) {
+      _sink.writeByte(PartElementKind.withSource.index);
+      _sink._writeStringReference(element.relativeUriString);
+      _sink._writeStringReference('${element.uriSource.uri}');
+    } else {
+      _sink.writeByte(PartElementKind.withNothing.index);
+    }
+  }
+
   void _writePropertyAccessorElement(PropertyAccessorElement element) {
     element as PropertyAccessorElementImpl;
     _sink.writeUInt30(_resolutionSink.offset);
@@ -455,10 +472,8 @@
     unitElement as CompilationUnitElementImpl;
     _sink.writeUInt30(_resolutionSink.offset);
 
-    _sink._writeStringReference('${unitElement.source.uri}');
     _sink._writeOptionalStringReference(unitElement.uri);
     _sink.writeBool(unitElement.isSynthetic);
-    _resolutionSink._writeAnnotationList(unitElement.metadata);
     _writeList(unitElement.classes, _writeClassElement);
     _writeList(unitElement.enums, _writeEnumElement);
     _writeList(unitElement.extensions, _writeExtensionElement);
diff --git a/pkg/analyzer/lib/src/summary2/element_builder.dart b/pkg/analyzer/lib/src/summary2/element_builder.dart
index 63e3bb8..e53f62f 100644
--- a/pkg/analyzer/lib/src/summary2/element_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/element_builder.dart
@@ -381,7 +381,7 @@
 
   @override
   void visitExportDirective(covariant ExportDirectiveImpl node) {
-    var element = ExportElementImpl(node.keyword.offset);
+    var element = ExportElementImpl(node.exportKeyword.offset);
     element.combinators = _buildCombinators(node.combinators);
 
     try {
@@ -759,7 +759,7 @@
   void visitImportDirective(covariant ImportDirectiveImpl node) {
     var uriStr = node.uri.stringValue;
 
-    var element = ImportElementImpl(node.keyword.offset);
+    var element = ImportElementImpl(node.importKeyword.offset);
     element.combinators = _buildCombinators(node.combinators);
 
     try {
@@ -920,13 +920,10 @@
 
   @override
   void visitPartDirective(PartDirective node) {
-    var index = _partDirectiveIndex++;
-    // TODO(scheglov) With invalid URIs we will associate metadata incorrectly
-    if (index < _libraryElement.parts.length) {
-      var partElement = _libraryElement.parts[index];
-      partElement as CompilationUnitElementImpl;
-      partElement.metadata = _buildAnnotations(node.metadata);
-    }
+    final index = _partDirectiveIndex++;
+    final partElement = _libraryElement.parts2[index];
+    partElement as PartElementImpl;
+    partElement.metadata = _buildAnnotations(node.metadata);
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/summary2/informative_data.dart b/pkg/analyzer/lib/src/summary2/informative_data.dart
index 2cb8c14..086c90d 100644
--- a/pkg/analyzer/lib/src/summary2/informative_data.dart
+++ b/pkg/analyzer/lib/src/summary2/informative_data.dart
@@ -474,18 +474,11 @@
       },
     );
 
-    forCorrespondingPairs<CompilationUnitElement, _InfoPart>(
-      element.parts,
+    forCorrespondingPairs<PartElement, _InfoPart>(
+      element.parts2,
       info.parts,
       (element, info) {
-        element as CompilationUnitElementImpl;
-        var linkedData = element.linkedData as CompilationUnitElementLinkedData;
-        linkedData.applyConstantOffsets = ApplyConstantOffsets(
-          info.constantOffsets,
-          (applier) {
-            applier.applyToMetadata(element);
-          },
-        );
+        element as PartElementImpl;
       },
     );
 
@@ -496,6 +489,7 @@
         applier.applyToMetadata(element);
         applier.applyToDirectives(element.imports);
         applier.applyToDirectives(element.exports);
+        applier.applyToPartDirectives(element.parts2);
       },
     );
   }
@@ -1031,16 +1025,16 @@
 }
 
 class _InfoPart {
-  final Uint32List constantOffsets;
+  final int nameOffset;
 
   factory _InfoPart(SummaryDataReader reader) {
     return _InfoPart._(
-      constantOffsets: reader.readUInt30List(),
+      nameOffset: reader.readUInt30(),
     );
   }
 
   _InfoPart._({
-    required this.constantOffsets,
+    required this.nameOffset,
   });
 }
 
@@ -1061,20 +1055,18 @@
     _writeDocumentationCommentNode(firstDirective?.documentationComment);
 
     sink.writeList2<ImportDirective>(unit.directives, (directive) {
-      sink.writeUInt30(directive.keyword.offset);
+      sink.writeUInt30(directive.importKeyword.offset);
       sink.writeUInt30(1 + (directive.prefix?.offset ?? -1));
       _writeCombinators(directive.combinators);
     });
 
     sink.writeList2<ExportDirective>(unit.directives, (directive) {
-      sink.writeUInt30(directive.keyword.offset);
+      sink.writeUInt30(directive.exportKeyword.offset);
       _writeCombinators(directive.combinators);
     });
 
-    sink.writeList2<PartDirective>(unit.directives, (node) {
-      _writeOffsets(
-        metadata: node.metadata,
-      );
+    sink.writeList2<PartDirective>(unit.directives, (directive) {
+      sink.writeUInt30(directive.partKeyword.offset);
     });
 
     sink.writeList2<ClassDeclaration>(unit.declarations, (node) {
@@ -1398,6 +1390,7 @@
       metadata: firstDirective?.metadata,
       importDirectives: unit.directives.whereType<ImportDirective>(),
       exportDirectives: unit.directives.whereType<ExportDirective>(),
+      partDirectives: unit.directives.whereType<PartDirective>(),
     );
   }
 
@@ -1427,6 +1420,7 @@
     NodeList<Annotation>? metadata,
     Iterable<ImportDirective>? importDirectives,
     Iterable<ExportDirective>? exportDirectives,
+    Iterable<PartDirective>? partDirectives,
     TypeParameterList? typeParameters,
     FormalParameterList? formalParameters,
     Expression? constantInitializer,
@@ -1472,6 +1466,7 @@
     metadata?.accept(collector);
     addDirectives(importDirectives);
     addDirectives(exportDirectives);
+    addDirectives(partDirectives);
     addTypeParameters(typeParameters);
     addFormalParameters(formalParameters);
     constantInitializer?.accept(collector);
@@ -1591,6 +1586,7 @@
       libraryName: _InfoLibraryName(reader),
       libraryConstantOffsets: reader.readUInt30List(),
       docComment: reader.readStringUtf8(),
+      // TODO(scheglov)
       imports: reader.readTypedList(
         () => _InfoImport(reader),
       ),
@@ -1702,6 +1698,12 @@
     }
   }
 
+  void applyToPartDirectives(List<PartElement> elements) {
+    for (var element in elements) {
+      applyToMetadata(element);
+    }
+  }
+
   void applyToTypeParameters(List<TypeParameterElement> typeParameters) {
     for (var typeParameter in typeParameters) {
       applyToMetadata(typeParameter);
diff --git a/pkg/analyzer/lib/src/summary2/library_builder.dart b/pkg/analyzer/lib/src/summary2/library_builder.dart
index 281b0ec..e0f47f2 100644
--- a/pkg/analyzer/lib/src/summary2/library_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/library_builder.dart
@@ -7,6 +7,7 @@
 import 'package:analyzer/dart/ast/ast.dart' as ast;
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/visitor.dart';
+import 'package:analyzer/src/dart/analysis/file_state.dart';
 import 'package:analyzer/src/dart/ast/ast.dart' as ast;
 import 'package:analyzer/src/dart/ast/mixin_super_invoked_names.dart';
 import 'package:analyzer/src/dart/element/element.dart';
@@ -39,6 +40,7 @@
 
 class LibraryBuilder {
   final Linker linker;
+  final LibraryFileStateKind kind;
   final Uri uri;
   final Reference reference;
   final LibraryElementImpl element;
@@ -74,6 +76,7 @@
 
   LibraryBuilder._({
     required this.linker,
+    required this.kind,
     required this.uri,
     required this.reference,
     required this.element,
@@ -305,8 +308,9 @@
 
     // For now we model augmentation libraries as parts.
     var unitUri = uri.resolve('_macro_types.dart');
+    final unitSource = _sourceFactory.forUri2(unitUri)!;
     var unitElement = CompilationUnitElementImpl(
-      source: _sourceFactory.forUri2(unitUri)!,
+      source: unitSource,
       librarySource: element.source,
       lineInfo: parseResult.lineInfo,
     )
@@ -317,7 +321,13 @@
     var unitReference = reference.getChild('@unit').getChild('$unitUri');
     _bindReference(unitReference, unitElement);
 
-    element.parts.add(unitElement);
+    element.parts2.add(
+      PartElementWithPartImpl(
+        relativeUriString: '_macro_types.dart',
+        uriSource: unitSource,
+        includedUnit: unitElement,
+      ),
+    );
 
     ElementBuilder(
       libraryBuilder: this,
@@ -402,20 +412,20 @@
     }
   }
 
-  static void build(Linker linker, LinkInputLibrary inputLibrary) {
-    var elementFactory = linker.elementFactory;
+  static void build(Linker linker, LibraryFileStateKind inputLibrary) {
+    final elementFactory = linker.elementFactory;
+    final rootReference = linker.rootReference;
 
-    var rootReference = linker.rootReference;
-    var libraryUriStr = inputLibrary.uriStr;
-    var libraryReference = rootReference.getChild(libraryUriStr);
+    final libraryFile = inputLibrary.file;
+    final libraryUriStr = libraryFile.uriStr;
+    final libraryReference = rootReference.getChild(libraryUriStr);
 
-    var definingUnit = inputLibrary.units[0];
-    var definingUnitNode = definingUnit.unit as ast.CompilationUnitImpl;
+    final libraryUnitNode = libraryFile.parse();
 
     var name = '';
     var nameOffset = -1;
     var nameLength = 0;
-    for (var directive in definingUnitNode.directives) {
+    for (final directive in libraryUnitNode.directives) {
       if (directive is ast.LibraryDirective) {
         name = directive.name.components.map((e) => e.name).join('.');
         nameOffset = directive.name.offset;
@@ -424,56 +434,101 @@
       }
     }
 
-    var libraryElement = LibraryElementImpl(
+    final libraryElement = LibraryElementImpl(
       elementFactory.analysisContext,
       elementFactory.analysisSession,
       name,
       nameOffset,
       nameLength,
-      definingUnitNode.featureSet,
+      libraryUnitNode.featureSet,
     );
-    libraryElement.isSynthetic = definingUnit.isSynthetic;
-    libraryElement.languageVersion = definingUnitNode.languageVersion!;
+    libraryElement.isSynthetic = !libraryFile.exists;
+    libraryElement.languageVersion = libraryUnitNode.languageVersion!;
     _bindReference(libraryReference, libraryElement);
     elementFactory.setLibraryTypeSystem(libraryElement);
 
-    var unitContainerRef = libraryReference.getChild('@unit');
-    var unitElements = <CompilationUnitElementImpl>[];
-    var isDefiningUnit = true;
-    var linkingUnits = <LinkingUnit>[];
-    for (var inputUnit in inputLibrary.units) {
-      var unitNode = inputUnit.unit as ast.CompilationUnitImpl;
+    final unitContainerRef = libraryReference.getChild('@unit');
 
-      var unitElement = CompilationUnitElementImpl(
-        source: inputUnit.source,
-        librarySource: inputLibrary.source,
-        lineInfo: unitNode.lineInfo,
+    final linkingUnits = <LinkingUnit>[];
+    {
+      final unitElement = CompilationUnitElementImpl(
+        source: libraryFile.source,
+        librarySource: libraryFile.source,
+        lineInfo: libraryUnitNode.lineInfo,
       );
-      unitElement.isSynthetic = inputUnit.isSynthetic;
-      unitElement.uri = inputUnit.partUriStr;
-      unitElement.setCodeRange(0, unitNode.length);
+      unitElement.isSynthetic = !libraryFile.exists;
+      unitElement.setCodeRange(0, libraryUnitNode.length);
 
-      var unitReference = unitContainerRef.getChild(inputUnit.uriStr);
+      final unitReference = unitContainerRef.getChild(libraryFile.uriStr);
       _bindReference(unitReference, unitElement);
 
-      unitElements.add(unitElement);
       linkingUnits.add(
         LinkingUnit(
-          isDefiningUnit: isDefiningUnit,
+          isDefiningUnit: true,
           reference: unitReference,
-          node: unitNode,
+          node: libraryUnitNode,
           element: unitElement,
         ),
       );
-      isDefiningUnit = false;
+
+      libraryElement.definingCompilationUnit = unitElement;
     }
 
-    libraryElement.definingCompilationUnit = unitElements[0];
-    libraryElement.parts = unitElements.skip(1).toList();
+    final parts = <PartElementImpl>[];
+    for (final partState in inputLibrary.parts) {
+      if (partState is PartDirectiveWithFile) {
+        final includedPart = partState.includedPart;
+        if (includedPart != null) {
+          final partFile = includedPart.file;
+          final partUnitNode = partFile.parse();
+          final unitElement = CompilationUnitElementImpl(
+            source: partFile.source,
+            librarySource: libraryFile.source,
+            lineInfo: partUnitNode.lineInfo,
+          );
+          unitElement.isSynthetic = !partFile.exists;
+          unitElement.uri = partFile.uriStr;
+          unitElement.setCodeRange(0, partUnitNode.length);
+          parts.add(
+            PartElementWithPartImpl(
+              relativeUriString: partState.uri.relativeUriStr,
+              uriSource: partFile.source,
+              includedUnit: unitElement,
+            ),
+          );
 
-    var builder = LibraryBuilder._(
+          final unitReference = unitContainerRef.getChild(partFile.uriStr);
+          _bindReference(unitReference, unitElement);
+
+          linkingUnits.add(
+            LinkingUnit(
+              isDefiningUnit: false,
+              reference: unitReference,
+              node: partUnitNode,
+              element: unitElement,
+            ),
+          );
+        } else {
+          parts.add(
+            PartElementWithSourceImpl(
+              relativeUriString: partState.uri.relativeUriStr,
+              uriSource: partState.includedFile.source,
+            ),
+          );
+        }
+      } else {
+        parts.add(
+          PartElementImpl(),
+        );
+      }
+    }
+
+    libraryElement.parts2 = parts;
+
+    final builder = LibraryBuilder._(
       linker: linker,
-      uri: inputLibrary.uri,
+      kind: inputLibrary,
+      uri: libraryFile.uri,
       reference: libraryReference,
       element: libraryElement,
       units: linkingUnits,
diff --git a/pkg/analyzer/lib/src/summary2/link.dart b/pkg/analyzer/lib/src/summary2/link.dart
index e099e37..8bf045ab 100644
--- a/pkg/analyzer/lib/src/summary2/link.dart
+++ b/pkg/analyzer/lib/src/summary2/link.dart
@@ -10,9 +10,9 @@
 import 'package:analyzer/dart/ast/ast.dart' as ast;
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/dart/analysis/file_state.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
-import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/summary2/bundle_writer.dart';
 import 'package:analyzer/src/summary2/detach_nodes.dart';
 import 'package:analyzer/src/summary2/library_builder.dart';
@@ -27,26 +27,10 @@
 import 'package:analyzer/src/summary2/variance_builder.dart';
 import 'package:analyzer/src/util/performance/operation_performance.dart';
 
-/// Note that AST units and tokens of [inputLibraries] will be damaged.
-@Deprecated('Use link2() instead')
-Future<LinkResult> link(
-  LinkedElementFactory elementFactory,
-  List<LinkInputLibrary> inputLibraries, {
-  macro.MultiMacroExecutor? macroExecutor,
-  OperationPerformanceImpl? performance,
-}) async {
-  return await link2(
-    elementFactory: elementFactory,
-    inputLibraries: inputLibraries,
-    performance: OperationPerformanceImpl('<root>'),
-  );
-}
-
-/// Note that AST units and tokens of [inputLibraries] will be damaged.
-Future<LinkResult> link2({
+Future<LinkResult> link({
   required LinkedElementFactory elementFactory,
   required OperationPerformanceImpl performance,
-  required List<LinkInputLibrary> inputLibraries,
+  required List<LibraryFileStateKind> inputLibraries,
   macro.MultiMacroExecutor? macroExecutor,
 }) async {
   final linker = Linker(elementFactory, macroExecutor);
@@ -101,7 +85,7 @@
 
   Future<void> link({
     required OperationPerformanceImpl performance,
-    required List<LinkInputLibrary> inputLibraries,
+    required List<LibraryFileStateKind> inputLibraries,
   }) async {
     for (var inputLibrary in inputLibraries) {
       LibraryBuilder.build(this, inputLibrary);
@@ -311,42 +295,6 @@
   }
 }
 
-class LinkInputLibrary {
-  final Source source;
-  final List<LinkInputUnit> units;
-
-  LinkInputLibrary({
-    required this.source,
-    required this.units,
-  });
-
-  Uri get uri => source.uri;
-
-  String get uriStr => '$uri';
-}
-
-class LinkInputUnit {
-  final int? partDirectiveIndex;
-  final String? partUriStr;
-  final Source source;
-  final String? sourceContent;
-  final bool isSynthetic;
-  final ast.CompilationUnit unit;
-
-  LinkInputUnit({
-    required this.partDirectiveIndex,
-    this.partUriStr,
-    required this.source,
-    this.sourceContent,
-    required this.isSynthetic,
-    required this.unit,
-  });
-
-  Uri get uri => source.uri;
-
-  String get uriStr => '$uri';
-}
-
 class LinkMacroGeneratedUnit {
   final Uri uri;
   final String content;
diff --git a/pkg/analyzer/lib/src/test_utilities/find_element.dart b/pkg/analyzer/lib/src/test_utilities/find_element.dart
index 0c572a2..29ff647 100644
--- a/pkg/analyzer/lib/src/test_utilities/find_element.dart
+++ b/pkg/analyzer/lib/src/test_utilities/find_element.dart
@@ -216,19 +216,22 @@
   }
 
   CompilationUnitElement part(String targetUri) {
-    CompilationUnitElement? partElement;
+    CompilationUnitElement? result;
 
-    for (var part in libraryElement.parts) {
-      if (part.uri == targetUri) {
-        if (partElement != null) {
-          throw StateError('Not unique: $targetUri');
+    for (final part in libraryElement.parts2) {
+      if (part is PartElementWithPart) {
+        final unitElement = part.includedUnit;
+        if ('${unitElement.source.uri}' == targetUri) {
+          if (result != null) {
+            throw StateError('Not unique: $targetUri');
+          }
+          result = unitElement;
         }
-        partElement = part;
       }
     }
 
-    if (partElement != null) {
-      return partElement;
+    if (result != null) {
+      return result;
     }
     throw StateError('Not found: $targetUri');
   }
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index da576fd..4b27f79 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 4.2.0
+version: 4.3.0-dev
 description: This package provides a library that performs static analysis of Dart code.
 repository: https://github.com/dart-lang/sdk/tree/main/pkg/analyzer
 
diff --git a/pkg/analyzer/test/generated/scanner_test.dart b/pkg/analyzer/test/generated/scanner_test.dart
index 8dff3c5..db9c70a 100644
--- a/pkg/analyzer/test/generated/scanner_test.dart
+++ b/pkg/analyzer/test/generated/scanner_test.dart
@@ -286,7 +286,7 @@
     late Token previousToken;
     int previousEnd = -1;
     Token? currentToken = token;
-    while (currentToken != null && currentToken.type != TokenType.EOF) {
+    while (currentToken != null && !currentToken.isEof) {
       _validateStream(buffer, currentToken.precedingComments);
       TokenType type = currentToken.type;
       if (type == TokenType.OPEN_CURLY_BRACKET ||
diff --git a/pkg/analyzer/test/generated/top_level_parser_test.dart b/pkg/analyzer/test/generated/top_level_parser_test.dart
index 8bb9be2..f20c303 100644
--- a/pkg/analyzer/test/generated/top_level_parser_test.dart
+++ b/pkg/analyzer/test/generated/top_level_parser_test.dart
@@ -1098,7 +1098,7 @@
     assertNoErrors();
     expect(directive, TypeMatcher<ExportDirective>());
     var exportDirective = directive as ExportDirective;
-    expect(exportDirective.keyword, isNotNull);
+    expect(exportDirective.exportKeyword, isNotNull);
     expect(exportDirective.uri, isNotNull);
     expect(exportDirective.combinators, hasLength(0));
     expect(exportDirective.semicolon, isNotNull);
@@ -1117,7 +1117,7 @@
     assertNoErrors();
     expect(directive, TypeMatcher<ImportDirective>());
     var importDirective = directive as ImportDirective;
-    expect(importDirective.keyword, isNotNull);
+    expect(importDirective.importKeyword, isNotNull);
     expect(importDirective.uri, isNotNull);
     expect(importDirective.asKeyword, isNull);
     expect(importDirective.prefix, isNull);
@@ -1384,7 +1384,7 @@
     var directive = parseFullDirective() as ExportDirective;
     expect(directive, isNotNull);
     assertNoErrors();
-    expect(directive.keyword, isNotNull);
+    expect(directive.exportKeyword, isNotNull);
     expect(directive.uri, isNotNull);
     expect(directive.configurations, hasLength(2));
     expectDottedName(directive.configurations[0].name, ['a']);
@@ -1398,7 +1398,7 @@
     var directive = parseFullDirective() as ExportDirective;
     expect(directive, isNotNull);
     assertNoErrors();
-    expect(directive.keyword, isNotNull);
+    expect(directive.exportKeyword, isNotNull);
     expect(directive.uri, isNotNull);
     expect(directive.configurations, hasLength(1));
     expectDottedName(directive.configurations[0].name, ['a', 'b']);
@@ -1411,7 +1411,7 @@
     var directive = parseFullDirective() as ExportDirective;
     expect(directive, isNotNull);
     assertNoErrors();
-    expect(directive.keyword, isNotNull);
+    expect(directive.exportKeyword, isNotNull);
     expect(directive.uri, isNotNull);
     expect(directive.combinators, hasLength(1));
     expect(directive.semicolon, isNotNull);
@@ -1422,7 +1422,7 @@
     var directive = parseFullDirective() as ExportDirective;
     expect(directive, isNotNull);
     assertNoErrors();
-    expect(directive.keyword, isNotNull);
+    expect(directive.exportKeyword, isNotNull);
     expect(directive.uri, isNotNull);
     expect(directive.combinators, hasLength(2));
     expect(directive.semicolon, isNotNull);
@@ -1433,7 +1433,7 @@
     var directive = parseFullDirective() as ExportDirective;
     expect(directive, isNotNull);
     assertNoErrors();
-    expect(directive.keyword, isNotNull);
+    expect(directive.exportKeyword, isNotNull);
     expect(directive.uri, isNotNull);
     expect(directive.combinators, hasLength(0));
     expect(directive.semicolon, isNotNull);
@@ -1444,7 +1444,7 @@
     var directive = parseFullDirective() as ExportDirective;
     expect(directive, isNotNull);
     assertNoErrors();
-    expect(directive.keyword, isNotNull);
+    expect(directive.exportKeyword, isNotNull);
     expect(directive.uri, isNotNull);
     expect(directive.combinators, hasLength(1));
     expect(directive.semicolon, isNotNull);
@@ -1455,7 +1455,7 @@
     var directive = parseFullDirective() as ExportDirective;
     expect(directive, isNotNull);
     assertNoErrors();
-    expect(directive.keyword, isNotNull);
+    expect(directive.exportKeyword, isNotNull);
     expect(directive.uri, isNotNull);
     expect(directive.combinators, hasLength(2));
     expect(directive.semicolon, isNotNull);
@@ -1786,7 +1786,7 @@
     var directive = parseFullDirective() as ImportDirective;
     expect(directive, isNotNull);
     assertNoErrors();
-    expect(directive.keyword, isNotNull);
+    expect(directive.importKeyword, isNotNull);
     expect(directive.uri, isNotNull);
     expect(directive.configurations, hasLength(2));
     expectDottedName(directive.configurations[0].name, ['a']);
@@ -1803,7 +1803,7 @@
     var directive = parseFullDirective() as ImportDirective;
     expect(directive, isNotNull);
     assertNoErrors();
-    expect(directive.keyword, isNotNull);
+    expect(directive.importKeyword, isNotNull);
     expect(directive.uri, isNotNull);
     expect(directive.configurations, hasLength(1));
     expectDottedName(directive.configurations[0].name, ['a', 'b']);
@@ -1819,7 +1819,7 @@
     var directive = parseFullDirective() as ImportDirective;
     expect(directive, isNotNull);
     assertNoErrors();
-    expect(directive.keyword, isNotNull);
+    expect(directive.importKeyword, isNotNull);
     expect(directive.uri, isNotNull);
     expect(directive.deferredKeyword, isNotNull);
     expect(directive.asKeyword, isNotNull);
@@ -1833,7 +1833,7 @@
     var directive = parseFullDirective() as ImportDirective;
     expect(directive, isNotNull);
     assertNoErrors();
-    expect(directive.keyword, isNotNull);
+    expect(directive.importKeyword, isNotNull);
     expect(directive.uri, isNotNull);
     expect(directive.deferredKeyword, isNull);
     expect(directive.asKeyword, isNull);
@@ -1847,7 +1847,7 @@
     var directive = parseFullDirective() as ImportDirective;
     expect(directive, isNotNull);
     assertNoErrors();
-    expect(directive.keyword, isNotNull);
+    expect(directive.importKeyword, isNotNull);
     expect(directive.uri, isNotNull);
     expect(directive.deferredKeyword, isNull);
     expect(directive.asKeyword, isNull);
@@ -1861,7 +1861,7 @@
     var directive = parseFullDirective() as ImportDirective;
     expect(directive, isNotNull);
     assertNoErrors();
-    expect(directive.keyword, isNotNull);
+    expect(directive.importKeyword, isNotNull);
     expect(directive.uri, isNotNull);
     expect(directive.deferredKeyword, isNull);
     expect(directive.asKeyword, isNotNull);
@@ -1875,7 +1875,7 @@
     var directive = parseFullDirective() as ImportDirective;
     expect(directive, isNotNull);
     assertNoErrors();
-    expect(directive.keyword, isNotNull);
+    expect(directive.importKeyword, isNotNull);
     expect(directive.uri, isNotNull);
     expect(directive.deferredKeyword, isNull);
     expect(directive.asKeyword, isNotNull);
@@ -1889,7 +1889,7 @@
     var directive = parseFullDirective() as ImportDirective;
     expect(directive, isNotNull);
     assertNoErrors();
-    expect(directive.keyword, isNotNull);
+    expect(directive.importKeyword, isNotNull);
     expect(directive.uri, isNotNull);
     expect(directive.deferredKeyword, isNull);
     expect(directive.asKeyword, isNotNull);
@@ -1903,7 +1903,7 @@
     var directive = parseFullDirective() as ImportDirective;
     expect(directive, isNotNull);
     assertNoErrors();
-    expect(directive.keyword, isNotNull);
+    expect(directive.importKeyword, isNotNull);
     expect(directive.uri, isNotNull);
     expect(directive.deferredKeyword, isNull);
     expect(directive.asKeyword, isNull);
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index 0d9b911..0149bed 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -692,57 +692,6 @@
     expect(allResults.pathList, [b]);
   }
 
-  test_analyze_resolveDirectives() async {
-    var lib = convertPath('/test/lib.dart');
-    var part1 = convertPath('/test/part1.dart');
-    var part2 = convertPath('/test/part2.dart');
-    newFile(lib, '''
-library lib;
-part 'part1.dart';
-part 'part2.dart';
-''');
-    newFile(part1, '''
-part of lib;
-''');
-    newFile(part2, '''
-part of 'lib.dart';
-''');
-
-    ResolvedUnitResult libResult = await driver.getResultValid(lib);
-    ResolvedUnitResult partResult1 = await driver.getResultValid(part1);
-    ResolvedUnitResult partResult2 = await driver.getResultValid(part2);
-
-    CompilationUnit libUnit = libResult.unit;
-    CompilationUnit partUnit1 = partResult1.unit;
-    CompilationUnit partUnit2 = partResult2.unit;
-
-    CompilationUnitElement unitElement = libUnit.declaredElement!;
-    CompilationUnitElement partElement1 = partUnit1.declaredElement!;
-    CompilationUnitElement partElement2 = partUnit2.declaredElement!;
-
-    LibraryElement libraryElement = unitElement.library;
-    {
-      expect(libraryElement.entryPoint, isNull);
-      expect(libraryElement.source, unitElement.source);
-      expect(libraryElement.definingCompilationUnit, unitElement);
-      expect(libraryElement.parts, hasLength(2));
-    }
-
-    expect((libUnit.directives[0] as LibraryDirective).element, libraryElement);
-    expect((libUnit.directives[1] as PartDirective).element, partElement1);
-    expect((libUnit.directives[2] as PartDirective).element, partElement2);
-
-    {
-      var partOf = partUnit1.directives.single as PartOfDirective;
-      expect(partOf.element, libraryElement);
-    }
-
-    {
-      var partOf = partUnit2.directives.single as PartOfDirective;
-      expect(partOf.element, libraryElement);
-    }
-  }
-
   test_analyze_resolveDirectives_error_missingLibraryDirective() async {
     var lib = convertPath('/test/lib.dart');
     var part = convertPath('/test/part.dart');
diff --git a/pkg/analyzer/test/src/dart/analysis/index_test.dart b/pkg/analyzer/test/src/dart/analysis/index_test.dart
index f16ec1f..b3245ba 100644
--- a/pkg/analyzer/test/src/dart/analysis/index_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/index_test.dart
@@ -740,7 +740,7 @@
 library my_lib;
 part 'my_unit.dart';
 ''');
-    var element = findElement.part('my_unit.dart');
+    var element = findElement.part('package:test/my_unit.dart');
     assertThat(element).isReferencedAt("'my_unit.dart';", true, length: 14);
   }
 
diff --git a/pkg/analyzer/test/src/dart/analysis/search_test.dart b/pkg/analyzer/test/src/dart/analysis/search_test.dart
index 490c069..9714635 100644
--- a/pkg/analyzer/test/src/dart/analysis/search_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/search_test.dart
@@ -1292,8 +1292,10 @@
 part 'unitB.dart';
 ''');
     LibraryElement element = result.libraryElement;
-    CompilationUnitElement unitElementA = element.parts[0];
-    CompilationUnitElement unitElementB = element.parts[1];
+    CompilationUnitElement unitElementA =
+        (element.parts2[0] as PartElementWithPart).includedUnit;
+    CompilationUnitElement unitElementB =
+        (element.parts2[1] as PartElementWithPart).includedUnit;
     var expected = [
       ExpectedResult(unitElementA, SearchResultKind.REFERENCE,
           codeA.indexOf('lib; // A'), 'lib'.length),
@@ -1328,8 +1330,10 @@
 part 'unitB.dart';
 ''');
     LibraryElement element = result.libraryElement;
-    CompilationUnitElement unitElementA = element.parts[0];
-    CompilationUnitElement unitElementB = element.parts[1];
+    CompilationUnitElement unitElementA =
+        (element.parts2[0] as PartElementWithPart).includedUnit;
+    CompilationUnitElement unitElementB =
+        (element.parts2[1] as PartElementWithPart).includedUnit;
     var expected = [
       ExpectedResult(unitElementA, SearchResultKind.REFERENCE,
           codeA.indexOf('lib; // A'), 'lib'.length),
@@ -1843,7 +1847,7 @@
 ''');
     var element = findElement.prefix('ppp');
     var main = findElement.function('main');
-    var c = findElement.partFind('my_part.dart').topVar('c');
+    var c = findElement.partFind('package:test/my_part.dart').topVar('c');
     var expected = [
       _expectId(main, SearchResultKind.REFERENCE, 'ppp.Future'),
       _expectId(main, SearchResultKind.REFERENCE, 'ppp.Stream'),
@@ -1882,7 +1886,7 @@
 ''');
     var element = findElement.prefix('ppp');
     var main = findElement.function('main');
-    var c = findElement.partFind('my_part.dart').topVar('c');
+    var c = findElement.partFind('package:aaa/my_part.dart').topVar('c');
     var expected = [
       _expectId(main, SearchResultKind.REFERENCE, 'ppp.Future'),
       _expectId(main, SearchResultKind.REFERENCE, 'ppp.Stream'),
@@ -1912,8 +1916,8 @@
 ''');
     var element = findElement.class_('_C');
     Element v = findElement.topVar('v');
-    Element v1 = findElement.partFind('part1.dart').topVar('v1');
-    Element v2 = findElement.partFind('part2.dart').topVar('v2');
+    Element v1 = findElement.partFind('package:test/part1.dart').topVar('v1');
+    Element v2 = findElement.partFind('package:test/part2.dart').topVar('v2');
     var expected = [
       _expectId(v, SearchResultKind.REFERENCE, '_C v;', length: 2),
       ExpectedResult(
@@ -1948,10 +1952,11 @@
 
     await resolveTestCode(code);
 
-    ClassElement element = findElement.partFind('part1.dart').class_('_C');
+    ClassElement element =
+        findElement.partFind('package:test/part1.dart').class_('_C');
     Element v = findElement.topVar('v');
-    Element v1 = findElement.partFind('part1.dart').topVar('v1');
-    Element v2 = findElement.partFind('part2.dart').topVar('v2');
+    Element v1 = findElement.partFind('package:test/part1.dart').topVar('v1');
+    Element v2 = findElement.partFind('package:test/part2.dart').topVar('v2');
     var expected = [
       ExpectedResult(v, SearchResultKind.REFERENCE, code.indexOf('_C v;'), 2),
       ExpectedResult(
@@ -1992,8 +1997,8 @@
 
     ClassElement element = findElement.class_('_C');
     Element v = findElement.topVar('v');
-    Element v1 = findElement.partFind('part1.dart').topVar('v1');
-    Element v2 = findElement.partFind('part2.dart').topVar('v2');
+    Element v1 = findElement.partFind('package:aaa/part1.dart').topVar('v1');
+    Element v2 = findElement.partFind('package:aaa/part2.dart').topVar('v2');
     var expected = [
       ExpectedResult(
           v, SearchResultKind.REFERENCE, testCode.indexOf('_C v;'), 2),
diff --git a/pkg/analyzer/test/src/dart/element/element_test.dart b/pkg/analyzer/test/src/dart/element/element_test.dart
index 5267086b..b69f6c9 100644
--- a/pkg/analyzer/test/src/dart/element/element_test.dart
+++ b/pkg/analyzer/test/src/dart/element/element_test.dart
@@ -1292,23 +1292,6 @@
     }
   }
 
-  void test_getUnits() {
-    AnalysisContext context = TestAnalysisContext();
-    LibraryElementImpl library = ElementFactory.library(context, "test");
-    CompilationUnitElement unitLib = library.definingCompilationUnit;
-    CompilationUnitElementImpl unitA = ElementFactory.compilationUnit(
-      source: TestSource("unit_a.dart"),
-      librarySource: unitLib.source,
-    );
-    CompilationUnitElementImpl unitB = ElementFactory.compilationUnit(
-      source: TestSource("unit_b.dart"),
-      librarySource: unitLib.source,
-    );
-    library.parts = <CompilationUnitElement>[unitA, unitB];
-    expect(library.units,
-        unorderedEquals(<CompilationUnitElement>[unitLib, unitA, unitB]));
-  }
-
   void test_setImports() {
     AnalysisContext context = TestAnalysisContext();
     LibraryElementImpl library = LibraryElementImpl(
diff --git a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
index 89598f8..659f3e6 100644
--- a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
+++ b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
@@ -460,9 +460,12 @@
 var b = B(0);
 ''');
 
+    final b = newFile('/workspace/dart/test/lib/b.dart', r'''
+part of 'a.dart';
+''');
+
     result = await resolveFile(a.path);
     assertErrorsInResolvedUnit(result, [
-      error(CompileTimeErrorCode.URI_DOES_NOT_EXIST, 5, 8),
       error(CompileTimeErrorCode.UNDEFINED_FUNCTION, 24, 1),
     ]);
 
@@ -477,7 +480,7 @@
 
     // Update b.dart, but do not notify the resolver.
     // If we try to read it now, it will throw.
-    final b = newFile('/workspace/dart/test/lib/b.dart', r'''
+    newFile(b.path, r'''
 part of 'a.dart';
 
 class B {
diff --git a/pkg/analyzer/test/src/dart/resolution/part_test.dart b/pkg/analyzer/test/src/dart/resolution/part_test.dart
new file mode 100644
index 0000000..54aad7c
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/resolution/part_test.dart
@@ -0,0 +1,143 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'context_collection_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(PartDirectiveResolutionTest);
+  });
+}
+
+@reflectiveTest
+class PartDirectiveResolutionTest extends PubPackageResolutionTest {
+  test_withoutString() async {
+    await assertErrorsInCode(r'''
+part '${'foo'}.dart';
+''', [
+      error(CompileTimeErrorCode.URI_WITH_INTERPOLATION, 5, 15),
+    ]);
+
+    assertResolvedNodeText(findNode.part('.dart'), r'''
+PartDirective
+  partKeyword: part
+  uri: StringInterpolation
+    elements
+      InterpolationString
+        contents: '
+      InterpolationExpression
+        leftBracket: ${
+        expression: SimpleStringLiteral
+          literal: 'foo'
+        rightBracket: }
+      InterpolationString
+        contents: .dart'
+    staticType: String
+    stringValue: null
+  semicolon: ;
+  element: PartElement
+  uriContent: null
+  uriElement: notUnitElement
+  uriSource: <null>
+''');
+  }
+
+  test_withPart_partOfName() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+part of my.lib;
+''');
+
+    await assertNoErrorsInCode(r'''
+library my.lib;
+part 'a.dart';
+''');
+
+    assertResolvedNodeText(findNode.part('a.dart'), r'''
+PartDirective
+  partKeyword: part
+  uri: SimpleStringLiteral
+    literal: 'a.dart'
+  semicolon: ;
+  element: PartElementWithPart
+    part: package:test/a.dart
+  uriContent: null
+  uriElement: unitElement package:test/a.dart
+  uriSource: package:test/a.dart
+''');
+  }
+
+  test_withPart_partOfUri() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+part of 'test.dart';
+''');
+
+    await assertNoErrorsInCode(r'''
+part 'a.dart';
+''');
+
+    assertResolvedNodeText(findNode.part('a.dart'), r'''
+PartDirective
+  partKeyword: part
+  uri: SimpleStringLiteral
+    literal: 'a.dart'
+  semicolon: ;
+  element: PartElementWithPart
+    part: package:test/a.dart
+  uriContent: null
+  uriElement: unitElement package:test/a.dart
+  uriSource: package:test/a.dart
+''');
+  }
+
+  test_withSource_notPart_augmentation() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+library augment 'test.dart';
+''');
+
+    await assertErrorsInCode(r'''
+part 'a.dart';
+''', [
+      error(CompileTimeErrorCode.PART_OF_NON_PART, 5, 8),
+    ]);
+
+    assertResolvedNodeText(findNode.part('a.dart'), r'''
+PartDirective
+  partKeyword: part
+  uri: SimpleStringLiteral
+    literal: 'a.dart'
+  semicolon: ;
+  element: PartElementWithSource
+    source: package:test/a.dart
+  uriContent: null
+  uriElement: notUnitElement
+  uriSource: package:test/a.dart
+''');
+  }
+
+  test_withSource_notPart_library() async {
+    newFile('$testPackageLibPath/a.dart', '');
+
+    await assertErrorsInCode(r'''
+part 'a.dart';
+''', [
+      error(CompileTimeErrorCode.PART_OF_NON_PART, 5, 8),
+    ]);
+
+    assertResolvedNodeText(findNode.part('a.dart'), r'''
+PartDirective
+  partKeyword: part
+  uri: SimpleStringLiteral
+    literal: 'a.dart'
+  semicolon: ;
+  element: PartElementWithSource
+    source: package:test/a.dart
+  uriContent: null
+  uriElement: notUnitElement
+  uriSource: package:test/a.dart
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/dart/resolution/test_all.dart b/pkg/analyzer/test/src/dart/resolution/test_all.dart
index eb4521e..4c46650 100644
--- a/pkg/analyzer/test/src/dart/resolution/test_all.dart
+++ b/pkg/analyzer/test/src/dart/resolution/test_all.dart
@@ -54,6 +54,7 @@
 import 'non_nullable_bazel_workspace_test.dart' as non_nullable_bazel_workspace;
 import 'non_nullable_test.dart' as non_nullable;
 import 'optional_const_test.dart' as optional_const;
+import 'part_test.dart' as part_;
 import 'postfix_expression_test.dart' as postfix_expression;
 import 'prefix_element_test.dart' as prefix_element;
 import 'prefix_expression_test.dart' as prefix_expression;
@@ -118,6 +119,7 @@
     non_nullable_bazel_workspace.main();
     non_nullable.main();
     optional_const.main();
+    part_.main();
     postfix_expression.main();
     prefix_element.main();
     prefix_expression.main();
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index 0befcb4..73308ff 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -164,13 +164,7 @@
         _writeUnitElement(e.definingCompilationUnit);
       });
 
-      _writeElements('parts', e.parts, (CompilationUnitElement e) {
-        _writelnWithIndent(e.uri!);
-        _withIndent(() {
-          _writeMetadata(e);
-          _writeUnitElement(e);
-        });
-      });
+      _writeElements('parts', e.parts2, _writePartElement);
 
       if (withExportScope) {
         _writelnWithIndent('exportedReferences');
@@ -717,6 +711,28 @@
     _writeElements('parameters', elements, _writeParameterElement);
   }
 
+  void _writePartElement(PartElement e) {
+    if (e is PartElementWithPart) {
+      _writelnWithIndent('${e.includedUnit.source.uri}');
+      _withIndent(() {
+        _writeMetadata(e);
+        _writeUnitElement(e.includedUnit);
+      });
+    } else if (e is PartElementWithSource) {
+      _writelnWithIndent("source '${e.uriSource.uri}'");
+      _withIndent(() {
+        _writeMetadata(e);
+      });
+    } else if (e is PartElementImpl) {
+      _writelnWithIndent('noSource');
+      _withIndent(() {
+        _writeMetadata(e);
+      });
+    } else {
+      throw UnimplementedError('(${e.runtimeType}) $e');
+    }
+  }
+
   void _writePropertyAccessorElement(PropertyAccessorElement e) {
     e as PropertyAccessorElementImpl;
 
diff --git a/pkg/analyzer/test/src/summary/elements_test.dart b/pkg/analyzer/test/src/summary/elements_test.dart
index 2c410d6..b49c61b 100644
--- a/pkg/analyzer/test/src/summary/elements_test.dart
+++ b/pkg/analyzer/test/src/summary/elements_test.dart
@@ -4069,7 +4069,7 @@
           synthetic get b @-1
             returnType: double
   parts
-    a.dart
+    package:test/a.dart
       topLevelVariables
         static final a @19
           type: int
@@ -7896,7 +7896,7 @@
   nameOffset: 8
   definingUnit
   parts
-    a.dart
+    package:test/a.dart
       topLevelVariables
         static final f @19
           type: double Function(int)
@@ -20690,7 +20690,7 @@
   nameOffset: 8
   definingUnit
   parts
-    a.dart
+    package:test/a.dart
       functions
         main @16
           returnType: dynamic
@@ -25379,7 +25379,9 @@
     <unresolved>
   definingUnit
   parts
-    :[invaliduri]
+    noSource
+    source 'package:test/a3.dart'
+    noSource
 ''');
   }
 
@@ -25442,6 +25444,136 @@
 ''');
   }
 
+  test_library_parts() async {
+    addSource('$testPackageLibPath/a.dart', 'part of my.lib;');
+    addSource('$testPackageLibPath/b.dart', 'part of my.lib;');
+    var library =
+        await buildLibrary('library my.lib; part "a.dart"; part "b.dart";');
+    checkElementText(library, r'''
+library
+  name: my.lib
+  nameOffset: 8
+  definingUnit
+  parts
+    package:test/a.dart
+    package:test/b.dart
+''');
+  }
+
+  test_library_parts_noRelativeUriStr() async {
+    final library = await buildLibrary(r'''
+part '${'foo'}.dart';
+''');
+    checkElementText(library, r'''
+library
+  definingUnit
+  parts
+    noSource
+''');
+  }
+
+  test_library_parts_withPart_partOfName() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+part of my.lib;
+class B {}
+''');
+    final library = await buildLibrary(r'''
+library my.lib;
+part 'a.dart';
+class A {}
+''');
+    checkElementText(library, r'''
+library
+  name: my.lib
+  nameOffset: 8
+  definingUnit
+    classes
+      class A @37
+        constructors
+          synthetic @-1
+  parts
+    package:test/a.dart
+      classes
+        class B @22
+          constructors
+            synthetic @-1
+''');
+  }
+
+  test_library_parts_withPart_partOfUri() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+part of 'test.dart';
+class B {}
+''');
+    final library = await buildLibrary(r'''
+part 'a.dart';
+class A {}
+''');
+    checkElementText(library, r'''
+library
+  definingUnit
+    classes
+      class A @21
+        constructors
+          synthetic @-1
+  parts
+    package:test/a.dart
+      classes
+        class B @27
+          constructors
+            synthetic @-1
+''');
+  }
+
+  test_library_parts_withRelativeUri_notPart_emptyUriSelf() async {
+    final library = await buildLibrary(r'''
+part '';
+''');
+    checkElementText(library, r'''
+library
+  definingUnit
+  parts
+    source 'package:test/test.dart'
+''');
+  }
+
+  test_library_parts_withRelativeUri_notPart_library() async {
+    newFile('$testPackageLibPath/a.dart', '');
+    final library = await buildLibrary(r'''
+part 'a.dart';
+''');
+    checkElementText(library, r'''
+library
+  definingUnit
+  parts
+    source 'package:test/a.dart'
+''');
+  }
+
+  test_library_parts_withRelativeUri_notPart_notExists() async {
+    final library = await buildLibrary(r'''
+part 'a.dart';
+''');
+    checkElementText(library, r'''
+library
+  definingUnit
+  parts
+    source 'package:test/a.dart'
+''');
+  }
+
+  test_library_parts_withRelativeUriString() async {
+    final library = await buildLibrary(r'''
+part ':';
+''');
+    checkElementText(library, r'''
+library
+  definingUnit
+  parts
+    noSource
+''');
+  }
+
   test_localFunctions() async {
     var library = await buildLibrary(r'''
 f() {
@@ -29455,7 +29587,7 @@
       synthetic static get foo @-1
         returnType: int
   parts
-    a.dart
+    package:test/a.dart
       metadata
         Annotation
           atSign: @ @17
@@ -29464,7 +29596,7 @@
             staticElement: self::@getter::foo
             staticType: null
           element: self::@getter::foo
-    b.dart
+    package:test/b.dart
       metadata
         Annotation
           atSign: @ @38
@@ -29698,7 +29830,7 @@
       synthetic static get a @-1
         returnType: dynamic
   parts
-    foo.dart
+    package:test/foo.dart
       metadata
         Annotation
           atSign: @ @11
@@ -29724,7 +29856,7 @@
 
     // The difference with the test above is that we ask the part first.
     // There was a bug that we were not loading library directives.
-    expect(library.parts[0].metadata, isEmpty);
+    expect(library.parts2[0].metadata, isEmpty);
   }
 
   test_metadata_prefixed_variable() async {
@@ -32861,78 +32993,6 @@
 ''');
   }
 
-  /// TODO(scheglov) The part should disappear after finishing [PartElement].
-  test_part_emptyUri() async {
-    var library = await buildLibrary(r'''
-part '';
-class B extends A {}
-''');
-    checkElementText(library, r'''
-library
-  definingUnit
-    classes
-      class B @15
-        constructors
-          synthetic @-1
-  parts
-
-      classes
-        class B @15
-          constructors
-            synthetic @-1
-''');
-  }
-
-  test_part_uri() async {
-    var library = await buildLibrary('''
-part 'foo.dart';
-''');
-    expect(library.parts[0].uri, 'foo.dart');
-  }
-
-  test_parts() async {
-    addSource('$testPackageLibPath/a.dart', 'part of my.lib;');
-    addSource('$testPackageLibPath/b.dart', 'part of my.lib;');
-    var library =
-        await buildLibrary('library my.lib; part "a.dart"; part "b.dart";');
-    checkElementText(library, r'''
-library
-  name: my.lib
-  nameOffset: 8
-  definingUnit
-  parts
-    a.dart
-    b.dart
-''');
-  }
-
-  test_parts_invalidUri() async {
-    addSource('$testPackageLibPath/foo/bar.dart', 'part of my.lib;');
-    var library = await buildLibrary('library my.lib; part "foo/";');
-    checkElementText(library, r'''
-library
-  name: my.lib
-  nameOffset: 8
-  definingUnit
-  parts
-    foo/
-''');
-  }
-
-  test_parts_invalidUri_nullStringValue() async {
-    addSource('$testPackageLibPath/foo/bar.dart', 'part of my.lib;');
-    var library = await buildLibrary(r'''
-library my.lib;
-part "${foo}/bar.dart";
-''');
-    checkElementText(library, r'''
-library
-  name: my.lib
-  nameOffset: 8
-  definingUnit
-''');
-  }
-
   test_propagated_type_refers_to_closure() async {
     var library = await buildLibrary('''
 void f() {
@@ -34259,7 +34319,7 @@
               alias: self::@typeAlias::F
         returnType: void
   parts
-    a.dart
+    package:test/a.dart
       classes
         class C @17
           constructors
@@ -34369,7 +34429,7 @@
         aliasedElement: GenericFunctionTypeElement
           returnType: dynamic
   parts
-    a.dart
+    package:test/a.dart
       topLevelVariables
         static c @13
           type: C
@@ -34417,7 +34477,7 @@
   nameOffset: 8
   definingUnit
   parts
-    a.dart
+    package:test/a.dart
       classes
         class C @17
           constructors
@@ -34466,7 +34526,7 @@
           aliasedType: dynamic Function()
           aliasedElement: GenericFunctionTypeElement
             returnType: dynamic
-    b.dart
+    package:test/b.dart
       topLevelVariables
         static c @13
           type: C
@@ -34512,7 +34572,7 @@
   nameOffset: 8
   definingUnit
   parts
-    a.dart
+    package:test/a.dart
       classes
         class C @17
           constructors
@@ -37886,16 +37946,6 @@
 ''');
   }
 
-  test_unresolved_part() async {
-    var library = await buildLibrary("part 'foo.dart';", allowErrors: true);
-    checkElementText(library, r'''
-library
-  definingUnit
-  parts
-    foo.dart
-''');
-  }
-
   test_unused_type_parameter() async {
     var library = await buildLibrary('''
 class C<T> {
@@ -38055,7 +38105,7 @@
       static get x @39
         returnType: int
   parts
-    a.dart
+    package:test/a.dart
       topLevelVariables
         synthetic static x @-1
           type: int
@@ -38093,7 +38143,7 @@
             type: int
         returnType: void
   parts
-    a.dart
+    package:test/a.dart
       topLevelVariables
         synthetic static x @-1
           type: int
@@ -38115,14 +38165,14 @@
   nameOffset: 8
   definingUnit
   parts
-    a.dart
+    package:test/a.dart
       topLevelVariables
         synthetic static x @-1
           type: int
       accessors
         static get x @24
           returnType: int
-    b.dart
+    package:test/b.dart
       topLevelVariables
         synthetic static x @-1
           type: int
@@ -38392,7 +38442,7 @@
       synthetic static get b @-1
         returnType: double
   parts
-    a.dart
+    package:test/a.dart
       topLevelVariables
         static final a @19
           type: int
@@ -38447,7 +38497,7 @@
   nameOffset: 8
   definingUnit
   parts
-    a.dart
+    package:test/a.dart
       topLevelVariables
         synthetic static x @-1
           type: int
@@ -38457,7 +38507,7 @@
             requiredPositional _ @31
               type: int
           returnType: void
-    b.dart
+    package:test/b.dart
       topLevelVariables
         synthetic static x @-1
           type: int
diff --git a/pkg/analyzer/test/src/summary/macro_test.dart b/pkg/analyzer/test/src/summary/macro_test.dart
index 0f417e7..2a23acf 100644
--- a/pkg/analyzer/test/src/summary/macro_test.dart
+++ b/pkg/analyzer/test/src/summary/macro_test.dart
@@ -1806,7 +1806,8 @@
     }
 
     if (expected != null) {
-      final x = library.parts.single.topLevelVariables.single;
+      final partElement = library.parts2.single as PartElementWithPart;
+      final x = partElement.includedUnit.topLevelVariables.single;
       expect(x.name, 'x');
       x as ConstTopLevelVariableElementImpl;
       final actual = (x.constantInitializer as SimpleStringLiteral).value;
@@ -1868,7 +1869,8 @@
       library.definingCompilationUnit.getType('A'),
     );
 
-    var x = library.parts.single.topLevelVariables.single;
+    final partElement = library.parts2.single as PartElementWithPart;
+    final x = partElement.includedUnit.topLevelVariables.single;
     expect(x.name, 'x');
     x as ConstTopLevelVariableElementImpl;
     var x_literal = x.constantInitializer as SimpleStringLiteral;
diff --git a/pkg/analyzer/test/src/summary/resolved_ast_printer.dart b/pkg/analyzer/test/src/summary/resolved_ast_printer.dart
index f7f158b..1b9b710 100644
--- a/pkg/analyzer/test/src/summary/resolved_ast_printer.dart
+++ b/pkg/analyzer/test/src/summary/resolved_ast_printer.dart
@@ -879,7 +879,7 @@
       _writeNamedChildEntities(node);
       _writeElement('element', node.element);
       _writeRaw('uriContent', node.uriContent);
-      _writeElement('uriElement', node.uriElement);
+      _writePartUnitElement('uriElement', node.uriElement);
       _writeSource('uriSource', node.uriSource);
     });
   }
@@ -1330,6 +1330,10 @@
     return '${_referenceToString(parent)}::$name';
   }
 
+  String _stringOfSource(Source source) {
+    return '${source.uri}';
+  }
+
   String _substitutionMapStr(Map<TypeParameterElement, DartType> map) {
     var entriesStr = map.entries.map((entry) {
       return '${entry.key.name}: ${_typeStr(entry.value)}';
@@ -1377,6 +1381,8 @@
       });
     } else if (element is MultiplyDefinedElement) {
       _sink.writeln('<null>');
+    } else if (element is PartElement) {
+      _writePartElement(element);
     } else {
       final referenceStr = _elementToReferenceString(element);
       _sink.writeln(referenceStr);
@@ -1497,6 +1503,36 @@
     }
   }
 
+  void _writePartElement(PartElement element) {
+    if (element is PartElementWithPart) {
+      _writeln('PartElementWithPart');
+      _withIndent(() {
+        final uriStr = _stringOfSource(element.includedUnit.source);
+        _writelnWithIndent('part: $uriStr');
+      });
+    } else if (element is PartElementWithSource) {
+      _writeln('PartElementWithSource');
+      _withIndent(() {
+        final uriStr = _stringOfSource(element.uriSource);
+        _writelnWithIndent('source: $uriStr');
+      });
+    } else {
+      _writeln('PartElement');
+    }
+  }
+
+  void _writePartUnitElement(String name, Element? element) {
+    if (_withResolution) {
+      _sink.write(_indent);
+      _sink.write('$name: ');
+      if (element is CompilationUnitElement) {
+        _sink.writeln('unitElement ${_stringOfSource(element.source)}');
+      } else {
+        _sink.writeln('notUnitElement');
+      }
+    }
+  }
+
   void _writeRaw(String name, Object? value) {
     _writelnWithIndent('$name: $value');
   }
diff --git a/pkg/analyzer_cli/lib/src/analyzer_impl.dart b/pkg/analyzer_cli/lib/src/analyzer_impl.dart
index 7e40fff..06fe1f4 100644
--- a/pkg/analyzer_cli/lib/src/analyzer_impl.dart
+++ b/pkg/analyzer_cli/lib/src/analyzer_impl.dart
@@ -67,9 +67,8 @@
       return;
     }
     // Add compilation units.
-    addCompilationUnitSource(library.definingCompilationUnit, units);
-    for (var child in library.parts) {
-      addCompilationUnitSource(child, units);
+    for (final unitElement in library.units) {
+      addCompilationUnitSource(unitElement, units);
     }
     // Add referenced libraries.
     for (var child in library.importedLibraries) {
@@ -164,7 +163,7 @@
   bool _isAnalyzedLibrary(LibraryElement library) {
     var source = library.source;
     if (source.uri.isScheme('dart')) {
-      return options.showSdkWarnings;
+      return false;
     } else if (source.uri.isScheme('package')) {
       if (_isPathInPubCache(source.fullName)) {
         return false;
@@ -183,12 +182,8 @@
     var packageName = uri.pathSegments.first;
     if (packageName == _selfPackageName) {
       return true;
-    } else if (!options.showPackageWarnings) {
-      return false;
-    } else if (options.showPackageWarningsPrefix == null) {
-      return true;
     } else {
-      return packageName.startsWith(options.showPackageWarningsPrefix!);
+      return false;
     }
   }
 
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index 56b1585..7b82956 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -417,11 +417,6 @@
   bool _shouldBeFatal(ErrorSeverity severity, CommandLineOptions options) {
     if (severity == ErrorSeverity.ERROR) {
       return true;
-    } else if (severity == ErrorSeverity.WARNING &&
-        (options.warningsAreFatal || options.infosAreFatal)) {
-      return true;
-    } else if (severity == ErrorSeverity.INFO && options.infosAreFatal) {
-      return true;
     } else {
       return false;
     }
@@ -449,11 +444,6 @@
         _equalMaps(newOptions.declaredVariables, previous.declaredVariables) &&
         newOptions.log == previous.log &&
         newOptions.disableHints == previous.disableHints &&
-        newOptions.showPackageWarnings == previous.showPackageWarnings &&
-        newOptions.showPackageWarningsPrefix ==
-            previous.showPackageWarningsPrefix &&
-        newOptions.showSdkWarnings == previous.showSdkWarnings &&
-        newOptions.lints == previous.lints &&
         newOptions.defaultLanguageVersion == previous.defaultLanguageVersion &&
         newOptions.disableCacheFlushing == previous.disableCacheFlushing &&
         _equalLists(
diff --git a/pkg/analyzer_cli/lib/src/options.dart b/pkg/analyzer_cli/lib/src/options.dart
index 23a11be..bb914e3 100644
--- a/pkg/analyzer_cli/lib/src/options.dart
+++ b/pkg/analyzer_cli/lib/src/options.dart
@@ -23,7 +23,6 @@
 const _enableInitializingFormalAccessFlag = 'initializing-formal-access';
 const _ignoreUnrecognizedFlagsFlag = 'ignore-unrecognized-flags';
 const _implicitCastsFlag = 'implicit-casts';
-const _lintsFlag = 'lints';
 const _noImplicitDynamicFlag = 'no-implicit-dynamic';
 const _packagesOption = 'packages';
 const _sdkPathOption = 'dart-sdk';
@@ -98,24 +97,9 @@
   /// Batch mode (for unit testing)
   final bool batchMode;
 
-  /// Whether to show package: warnings
-  final bool showPackageWarnings;
-
-  /// If not null, show package: warnings only for matching packages.
-  final String? showPackageWarningsPrefix;
-
-  /// Whether to show SDK warnings
-  final bool showSdkWarnings;
-
   /// The source files to analyze
   final List<String> sourceFiles;
 
-  /// Whether to treat warnings as fatal
-  final bool warningsAreFatal;
-
-  /// Whether to treat info level items as fatal
-  final bool infosAreFatal;
-
   /// Emit output in a verbose mode.
   final bool verbose;
 
@@ -141,15 +125,7 @@
         machineFormat = args['format'] == 'machine',
         perfReport = castNullable(args['x-perf-report']),
         batchMode = cast(args['batch']),
-        showPackageWarnings = cast(args['show-package-warnings']) ||
-            cast(args['package-warnings']) ||
-            args['x-package-warnings-prefix'] != null,
-        showPackageWarningsPrefix =
-            castNullable(args['x-package-warnings-prefix']),
-        showSdkWarnings = cast(args['sdk-warnings']),
         sourceFiles = args.rest,
-        infosAreFatal = cast(args['fatal-infos']) || cast(args['fatal-hints']),
-        warningsAreFatal = cast(args['fatal-warnings']),
         trainSnapshot = cast(args['train-snapshot']),
         verbose = cast(args['verbose']),
         color = cast(args['color']) {
@@ -201,8 +177,6 @@
 
   bool? get implicitCasts => _argResults[_implicitCastsFlag] as bool?;
 
-  bool? get lints => _argResults[_lintsFlag] as bool?;
-
   bool? get noImplicitDynamic => _argResults[_noImplicitDynamicFlag] as bool?;
 
   /// Update the [analysisOptions] with flags that the user specified
@@ -233,11 +207,6 @@
       analysisOptions.implicitCasts = implicitCasts;
     }
 
-    var lints = this.lints;
-    if (lints != null) {
-      analysisOptions.lint = lints;
-    }
-
     var noImplicitDynamic = this.noImplicitDynamic;
     if (noImplicitDynamic != null) {
       analysisOptions.implicitDynamic = !noImplicitDynamic;
@@ -404,10 +373,6 @@
         defaultsTo: false,
         negatable: false,
         hide: hide || ddc);
-    if (!ddc) {
-      parser.addFlag(_lintsFlag,
-          help: 'Show lint results.', defaultsTo: null, negatable: true);
-    }
   }
 
   static String _getVersion() {
@@ -453,12 +418,6 @@
           help: 'Do not show hint results.',
           defaultsTo: false,
           negatable: false)
-      ..addFlag('fatal-infos',
-          help: 'Treat infos as fatal.', defaultsTo: false, negatable: false)
-      ..addFlag('fatal-warnings',
-          help: 'Treat non-type warnings as fatal.',
-          defaultsTo: false,
-          negatable: false)
       ..addFlag('help',
           abbr: 'h',
           help:
@@ -500,56 +459,22 @@
       ..addOption('x-perf-report',
           help: 'Writes a performance report to the given file (experimental).',
           hide: hide)
-      ..addOption('x-package-warnings-prefix',
-          help:
-              'Show warnings from package: imports that match the given prefix (deprecated).',
-          hide: hide)
       ..addFlag('enable-conditional-directives',
           help:
               'deprecated -- Enable support for conditional directives (DEP 40).',
           defaultsTo: false,
           negatable: false,
           hide: hide)
-      ..addFlag('show-package-warnings',
-          help: 'Show warnings from package: imports (deprecated).',
-          defaultsTo: false,
-          negatable: false,
-          hide: hide)
-      ..addFlag('sdk-warnings',
-          help: 'Show warnings from SDK imports (deprecated).',
-          defaultsTo: false,
-          negatable: false,
-          hide: hide)
       ..addFlag('log',
           help: 'Log additional messages and exceptions.',
           defaultsTo: false,
           negatable: false,
           hide: hide)
-      ..addFlag('enable_type_checks',
-          help: 'Check types in constant evaluation (deprecated).',
-          defaultsTo: false,
-          negatable: false,
-          hide: true)
       ..addFlag('use-analysis-driver-memory-byte-store',
           help: 'Use memory byte store, not the file system cache.',
           defaultsTo: false,
           negatable: false,
           hide: hide)
-      ..addFlag('fatal-hints',
-          help: 'Treat hints as fatal (deprecated: use --fatal-infos).',
-          defaultsTo: false,
-          negatable: false,
-          hide: hide)
-      ..addFlag('fatal-lints',
-          help: 'Treat lints as fatal.',
-          defaultsTo: false,
-          negatable: false,
-          hide: hide)
-      ..addFlag('package-warnings',
-          help: 'Show warnings from package: imports (deprecated).',
-          defaultsTo: false,
-          negatable: false,
-          hide: hide)
       ..addMultiOption('url-mapping',
           help: '--url-mapping=libraryUri,/path/to/library.dart directs the '
               'analyzer to use "library.dart" as the source for an import '
diff --git a/pkg/analyzer_cli/lib/src/perf_report.dart b/pkg/analyzer_cli/lib/src/perf_report.dart
index 04caa35..216c19a 100644
--- a/pkg/analyzer_cli/lib/src/perf_report.dart
+++ b/pkg/analyzer_cli/lib/src/perf_report.dart
@@ -35,9 +35,6 @@
 
   var optionsJson = <String, dynamic>{
     'dartSdkPath': options.dartSdkPath,
-    'showPackageWarnings': options.showPackageWarnings,
-    'showPackageWarningsPrefix': options.showPackageWarningsPrefix,
-    'showSdkWarnings': options.showSdkWarnings,
     'definedVariables': options.declaredVariables,
     'packageConfigPath': options.defaultPackagesPath,
     'sourceFiles': options.sourceFiles,
diff --git a/pkg/analyzer_cli/test/all.dart b/pkg/analyzer_cli/test/all.dart
index c56ee1b..b7f9afa 100644
--- a/pkg/analyzer_cli/test/all.dart
+++ b/pkg/analyzer_cli/test/all.dart
@@ -8,7 +8,6 @@
 import 'errors_reported_once_test.dart' as errors_reported_once;
 import 'errors_upgrade_fails_cli_test.dart' as errors_upgrade_fails_cli;
 import 'options_test.dart' as options;
-import 'package_prefix_test.dart' as package_prefix;
 import 'perf_report_test.dart' as perf_report;
 import 'reporter_test.dart' as reporter;
 import 'strong_mode_test.dart' as strong_mode;
@@ -20,7 +19,6 @@
   errors_reported_once.main();
   errors_upgrade_fails_cli.main();
   options.main();
-  package_prefix.main();
   perf_report.main();
   reporter.main();
   strong_mode.main();
diff --git a/pkg/analyzer_cli/test/driver_test.dart b/pkg/analyzer_cli/test/driver_test.dart
index c26a9e6..154362b 100644
--- a/pkg/analyzer_cli/test/driver_test.dart
+++ b/pkg/analyzer_cli/test/driver_test.dart
@@ -166,11 +166,6 @@
     expect(exitCode, 3);
   }
 
-  Future<void> test_fatalHints() async {
-    await drive('data/file_with_hint.dart', args: ['--fatal-hints']);
-    expect(exitCode, 1);
-  }
-
   Future<void> test_missingDartFile() async {
     await drive('data/NO_DART_FILE_HERE.dart');
     expect(exitCode, 3);
@@ -246,41 +241,6 @@
     expect(containsLintRuleEntry(options), false);
   }
 
-  Future<void> test_defaultLints_generatedLints() async {
-    await _runLinter_defaultLints();
-    expect(bulletToDash(outSink),
-        contains('lint - Name types using UpperCamelCase'));
-  }
-
-  Future<void> test_defaultLints_getsDefaultLints() async {
-    await _runLinter_defaultLints();
-
-    /// Lints should be enabled.
-    expect(analysisOptions.lint, isTrue);
-
-    /// Default list should include camel_case_types.
-    var lintNames = analysisOptions.lintRules.map((r) => r.name);
-    expect(lintNames, contains('camel_case_types'));
-  }
-
-  Future<void> test_lintsInOptions_generatedLints() async {
-    await _runLinter_lintsInOptions();
-    expect(bulletToDash(outSink),
-        contains('lint - Name types using UpperCamelCase'));
-  }
-
-  Future<void> test_lintsInOptions_getAnalysisOptions() async {
-    await _runLinter_lintsInOptions();
-
-    /// Lints should be enabled.
-    expect(analysisOptions.lint, isTrue);
-
-    /// The analysis options file specifies 'camel_case_types' and 'sort_pub_dependencies'.
-    var lintNames = analysisOptions.lintRules.map((r) => r.name);
-    expect(lintNames,
-        orderedEquals(['camel_case_types', 'sort_pub_dependencies']));
-  }
-
   Future<void> test_noLints_lintsDisabled() async {
     await _runLinter_noLintsFlag();
     expect(analysisOptions.lint, isFalse);
@@ -305,16 +265,6 @@
   YamlMap _parseOptions(String src) =>
       AnalysisOptionsProvider().getOptionsFromString(src);
 
-  Future<void> _runLinter_defaultLints() async {
-    await drive('data/linter_project/test_file.dart',
-        options: 'data/linter_project/$analysisOptionsYaml', args: ['--lints']);
-  }
-
-  Future<void> _runLinter_lintsInOptions() async {
-    await drive('data/linter_project/test_file.dart',
-        options: 'data/linter_project/$analysisOptionsYaml', args: ['--lints']);
-  }
-
   Future<void> _runLinter_noLintsFlag() async {
     await drive('data/no_lints_project/test_file.dart',
         options: 'data/no_lints_project/$analysisOptionsYaml');
@@ -468,24 +418,6 @@
     expect(outSink.toString(), contains('1 error and 1 warning found.'));
   }
 
-  Future<void> test_includeDirective() async {
-    var testDir = path.join(
-        testDirectory, 'data', 'options_include_directive_tests_project');
-    await drive(
-      path.join(testDir, 'lib', 'test_file.dart'),
-      args: [
-        '--fatal-warnings',
-        '--packages',
-        path.join(testDir, '_packages'),
-      ],
-      options: path.join(testDir, 'analysis_options.yaml'),
-    );
-    expect(exitCode, 3);
-    expect(outSink.toString(), contains('Unnecessary cast.'));
-    expect(outSink.toString(), contains('isn\'t defined'));
-    expect(outSink.toString(), contains('Avoid empty else statements'));
-  }
-
   Future<void> test_multiple_inputs_two_directories() async {
     await driveMany([
       'data/multiple_inputs_two_directories/bin',
@@ -507,23 +439,6 @@
     expect(outSink.toString().contains('[info]'), isFalse);
   }
 
-  Future<void> test_withFlags_overrideFatalWarning() async {
-    await drive('data/options_tests_project/test_file.dart',
-        args: ['--fatal-warnings'],
-        options: 'data/options_tests_project/$analysisOptionsYaml');
-
-    // missing_return: error
-    var undefined_function = AnalysisError(
-        TestSource(), 0, 1, CompileTimeErrorCode.UNDEFINED_FUNCTION, [
-      ['x']
-    ]);
-    expect(processorFor(undefined_function).severity, ErrorSeverity.WARNING);
-    // Should not be made fatal by `--fatal-warnings`.
-    expect(bulletToDash(outSink),
-        contains("warning - The function 'baz' isn't defined"));
-    expect(outSink.toString(), contains('1 error and 1 warning found.'));
-  }
-
   Future<void> _driveBasic() async {
     await drive('data/options_tests_project/test_file.dart',
         options: 'data/options_tests_project/$analysisOptionsYaml');
diff --git a/pkg/analyzer_cli/test/mocks.dart b/pkg/analyzer_cli/test/mocks.dart
index 3de1eb3..7b2cdc8 100644
--- a/pkg/analyzer_cli/test/mocks.dart
+++ b/pkg/analyzer_cli/test/mocks.dart
@@ -62,8 +62,6 @@
 class MockCommandLineOptions implements CommandLineOptions {
   bool enableTypeChecks = false;
   @override
-  bool infosAreFatal = false;
-  @override
   bool jsonFormat = false;
   @override
   bool machineFormat = false;
diff --git a/pkg/analyzer_cli/test/options_test.dart b/pkg/analyzer_cli/test/options_test.dart
index 690b5c9..397a42f 100644
--- a/pkg/analyzer_cli/test/options_test.dart
+++ b/pkg/analyzer_cli/test/options_test.dart
@@ -59,9 +59,7 @@
         expect(options.disableCacheFlushing, isFalse);
         expect(options.disableHints, isFalse);
         expect(options.enabledExperiments, isEmpty);
-        expect(options.lints, isNull);
         expect(options.displayVersion, isFalse);
-        expect(options.infosAreFatal, isFalse);
         expect(options.ignoreUnrecognizedFlags, isFalse);
         expect(options.implicitCasts, isNull);
         expect(options.log, isFalse);
@@ -69,10 +67,7 @@
         expect(options.machineFormat, isFalse);
         expect(options.noImplicitDynamic, isNull);
         expect(options.batchMode, isFalse);
-        expect(options.showPackageWarnings, isFalse);
-        expect(options.showSdkWarnings, isFalse);
         expect(options.sourceFiles, equals(['foo.dart']));
-        expect(options.warningsAreFatal, isFalse);
         expect(options.trainSnapshot, isFalse);
       });
 
@@ -171,16 +166,6 @@
         });
       });
 
-      test('hintsAreFatal', () {
-        var options = parse(['--dart-sdk', '.', '--fatal-hints', 'foo.dart'])!;
-        expect(options.infosAreFatal, isTrue);
-      });
-
-      test('infosAreFatal', () {
-        var options = parse(['--dart-sdk', '.', '--fatal-infos', 'foo.dart'])!;
-        expect(options.infosAreFatal, isTrue);
-      });
-
       test('log', () {
         var options = parse(['--dart-sdk', '.', '--log', 'foo.dart'])!;
         expect(options.log, isTrue);
@@ -213,22 +198,6 @@
         expect(options.defaultAnalysisOptionsPath, endsWith('options.yaml'));
       });
 
-      test('lints', () {
-        var options = parse(['--dart-sdk', '.', '--lints', 'foo.dart'])!;
-        expect(options.lints, isTrue);
-      });
-
-      test('package warnings', () {
-        var options =
-            parse(['--dart-sdk', '.', '--package-warnings', 'foo.dart'])!;
-        expect(options.showPackageWarnings, isTrue);
-      });
-
-      test('sdk warnings', () {
-        var options = parse(['--dart-sdk', '.', '--sdk-warnings', 'foo.dart'])!;
-        expect(options.showSdkWarnings, isTrue);
-      });
-
       test('sourceFiles', () {
         var options = parse([
           '--dart-sdk',
@@ -242,12 +211,6 @@
             equals(['foo.dart', 'foo2.dart', 'foo3.dart']));
       });
 
-      test('warningsAreFatal', () {
-        var options =
-            parse(['--dart-sdk', '.', '--fatal-warnings', 'foo.dart'])!;
-        expect(options.warningsAreFatal, isTrue);
-      });
-
       test('ignore unrecognized flags', () {
         var options = parse([
           '--ignore-unrecognized-flags',
@@ -464,52 +427,6 @@
     );
   }
 
-  void test_updateAnalysisOptions_lints() {
-    // Turn lints on.
-    _applyAnalysisOptions(
-      ['--lints', 'a.dart'],
-      (analysisOptions) {
-        analysisOptions.lint = false;
-      },
-      (analysisOptions) {
-        expect(analysisOptions.lint, isTrue);
-      },
-    );
-
-    // Turn lints off.
-    _applyAnalysisOptions(
-      ['--no-lints', 'a.dart'],
-      (analysisOptions) {
-        analysisOptions.lint = true;
-      },
-      (analysisOptions) {
-        expect(analysisOptions.lint, isFalse);
-      },
-    );
-
-    // Don't change if not provided, false.
-    _applyAnalysisOptions(
-      ['a.dart'],
-      (analysisOptions) {
-        analysisOptions.lint = false;
-      },
-      (analysisOptions) {
-        expect(analysisOptions.lint, isFalse);
-      },
-    );
-
-    // Don't change if not provided, true.
-    _applyAnalysisOptions(
-      ['a.dart'],
-      (analysisOptions) {
-        analysisOptions.lint = true;
-      },
-      (analysisOptions) {
-        expect(analysisOptions.lint, isTrue);
-      },
-    );
-  }
-
   void test_updateAnalysisOptions_noImplicitDynamic() {
     _applyAnalysisOptions(
       ['--no-implicit-dynamic', 'a.dart'],
diff --git a/pkg/analyzer_cli/test/package_prefix_test.dart b/pkg/analyzer_cli/test/package_prefix_test.dart
deleted file mode 100644
index 9aa0d57..0000000
--- a/pkg/analyzer_cli/test/package_prefix_test.dart
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:io' show exitCode;
-
-import 'package:analyzer_cli/src/driver.dart' show Driver, outSink, errorSink;
-import 'package:analyzer_cli/src/options.dart' show ExitHandler, exitHandler;
-import 'package:path/path.dart';
-import 'package:test/test.dart';
-
-import 'utils.dart' show testDirectory;
-
-void main() {
-  group('--x-package-warnings-prefix', () {
-    late _Runner runner;
-
-    setUp(() {
-      runner = _Runner.setUp();
-    });
-
-    tearDown(() {
-      runner.tearDown();
-    });
-
-    test('shows only the hint whose package matches the prefix', () async {
-      await runner.run2([
-        '--packages',
-        join(testDirectory, 'data', 'package_prefix', 'packagelist'),
-        '--x-package-warnings-prefix=f',
-        join(testDirectory, 'data', 'package_prefix', 'main.dart')
-      ]);
-      expect(runner.stdout, contains('1 hint found'));
-      expect(runner.stdout, contains('Unused import'));
-      expect(runner.stdout,
-          contains(join('package_prefix', 'pkg', 'foo', 'foo.dart')));
-      expect(runner.stdout, isNot(contains('bar.dart')));
-    });
-  });
-}
-
-class _Runner {
-  final _stdout = StringBuffer();
-  final _stderr = StringBuffer();
-
-  final StringSink _savedOutSink;
-  final StringSink _savedErrorSink;
-  final int _savedExitCode;
-  final ExitHandler _savedExitHandler;
-
-  _Runner.setUp()
-      : _savedOutSink = outSink,
-        _savedErrorSink = errorSink,
-        _savedExitHandler = exitHandler,
-        _savedExitCode = exitCode {
-    outSink = _stdout;
-    errorSink = _stderr;
-    exitHandler = (_) {};
-  }
-
-  String get stderr => _stderr.toString();
-
-  String get stdout => _stdout.toString();
-
-  Future<void> run2(List<String> args) async {
-    await Driver().start(args);
-    if (stderr.isNotEmpty) {
-      fail('Unexpected output to stderr:\n$stderr');
-    }
-  }
-
-  void tearDown() {
-    outSink = _savedOutSink;
-    errorSink = _savedErrorSink;
-    exitCode = _savedExitCode;
-    exitHandler = _savedExitHandler;
-  }
-}
diff --git a/pkg/analyzer_cli/test/reporter_test.dart b/pkg/analyzer_cli/test/reporter_test.dart
index 54a2964..4f65380 100644
--- a/pkg/analyzer_cli/test/reporter_test.dart
+++ b/pkg/analyzer_cli/test/reporter_test.dart
@@ -28,7 +28,6 @@
 
       options = MockCommandLineOptions();
       options.enableTypeChecks = false;
-      options.infosAreFatal = false;
       options.jsonFormat = false;
       options.machineFormat = false;
       options.verbose = false;
diff --git a/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart b/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
index 70b8e89..7257b10 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
@@ -578,7 +578,7 @@
     // Usually if the offset is greater than the token it can't be in the comment
     // but for EOF this is not the case - the offset at EOF could still be inside
     // the comment if EOF is on the same line as the comment.
-    if (token.type != TokenType.EOF && offset >= token.offset) {
+    if (!token.isEof && offset >= token.offset) {
       return null;
     }
     final startToken = token;
diff --git a/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart b/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
index 1a89f2a..29b6891 100644
--- a/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
+++ b/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
@@ -383,7 +383,21 @@
 
   @override
   void visitPartDirective(PartDirective node) {
-    _addUriDirectiveRegion(node, node.element);
+    final element = node.element;
+    if (element is PartElementWithPart) {
+      computer._addRegionForNode(node.uri, element.includedUnit);
+    } else if (element is PartElementWithSource) {
+      final uriNode = node.uri;
+      final source = element.uriSource;
+      computer.collector.addRegion(
+        uriNode.offset,
+        uriNode.length,
+        protocol.ElementKind.FILE,
+        protocol.Location(source.fullName, 0, 0, 0, 0,
+            endLine: 0, endColumn: 0),
+      );
+    }
+
     super.visitPartDirective(node);
   }
 
diff --git a/pkg/analyzer_plugin/lib/utilities/range_factory.dart b/pkg/analyzer_plugin/lib/utilities/range_factory.dart
index b967af5..cfbfea8 100644
--- a/pkg/analyzer_plugin/lib/utilities/range_factory.dart
+++ b/pkg/analyzer_plugin/lib/utilities/range_factory.dart
@@ -60,6 +60,35 @@
     }
   }
 
+  /// Return the deletion range of the [node], considering the spaces and
+  /// comments before and after it.
+  SourceRange deletionRange(AstNode node) {
+    var begin = node.beginToken;
+    begin = begin.precedingComments ?? begin;
+
+    var end = node.endToken.next!;
+    end = end.precedingComments ?? end;
+
+    int startOffset;
+    int endOffset;
+    if (end.isEof) {
+      var type = begin.type;
+      if (node is AnnotatedNode &&
+          (type == TokenType.SINGLE_LINE_COMMENT ||
+              type == TokenType.MULTI_LINE_COMMENT)) {
+        var firstToken = node.firstTokenAfterCommentAndMetadata;
+        startOffset = firstToken.previous!.end;
+      } else {
+        startOffset = begin.previous!.end;
+      }
+      endOffset = node.endToken.end;
+    } else {
+      startOffset = begin.offset;
+      endOffset = end.offset;
+    }
+    return startOffsetEndOffset(startOffset, endOffset);
+  }
+
   /// Return a source range that covers the name of the given [element].
   SourceRange elementName(Element element) {
     return SourceRange(element.nameOffset, element.nameLength);
diff --git a/pkg/analyzer_plugin/test/utilities/range_factory_test.dart b/pkg/analyzer_plugin/test/utilities/range_factory_test.dart
index 6825c53..c6757b2c 100644
--- a/pkg/analyzer_plugin/test/utilities/range_factory_test.dart
+++ b/pkg/analyzer_plugin/test/utilities/range_factory_test.dart
@@ -307,6 +307,170 @@
 
 @reflectiveTest
 class RangeFactoryTest extends AbstractSingleUnitTest {
+  Future<void> test_deletionRange_first() async {
+    await _deletionRange(declarationIndex: 0, '''
+class A {}
+
+class B {}
+''', expected: '''
+class B {}
+''');
+  }
+
+  Future<void> test_deletionRange_first_comment() async {
+    await _deletionRange(declarationIndex: 0, '''
+/// for a
+class A {}
+
+/// for b
+class B {}
+''', expected: '''
+/// for b
+class B {}
+''');
+  }
+
+  Future<void> test_deletionRange_first_directive() async {
+    await _deletionRange(declarationIndex: 0, '''
+import 'dart:collection';
+
+class A {}
+
+class B {}
+''', expected: '''
+import 'dart:collection';
+
+class B {}
+''');
+  }
+
+  Future<void> test_deletionRange_first_directive_comment() async {
+    await _deletionRange(declarationIndex: 0, '''
+import 'dart:collection';
+
+/// for a
+class A {}
+
+/// for b
+class B {}
+''', expected: '''
+import 'dart:collection';
+
+/// for b
+class B {}
+''');
+  }
+
+  Future<void> test_deletionRange_last() async {
+    await _deletionRange(declarationIndex: 1, '''
+/// for a
+class A {}
+
+class B {}
+''', expected: '''
+/// for a
+class A {}
+''');
+  }
+
+  Future<void> test_deletionRange_last_before_comment() async {
+    await _deletionRange(declarationIndex: 1, '''
+/// for a
+class A {}
+
+class B {}
+
+// another
+''', expected: '''
+/// for a
+class A {}
+
+// another
+''');
+  }
+
+  Future<void> test_deletionRange_last_multiLineComment() async {
+    await _deletionRange(declarationIndex: 1, '''
+/// for a
+class A {}
+
+/**
+ * for b
+ */
+class B {}
+''', expected: '''
+/// for a
+class A {}
+''');
+  }
+
+  Future<void> test_deletionRange_last_singeLineComment() async {
+    await _deletionRange(declarationIndex: 1, '''
+/// for a
+class A {}
+
+/// for b
+class B {}
+''', expected: '''
+/// for a
+class A {}
+''');
+  }
+
+  Future<void> test_deletionRange_middle() async {
+    await _deletionRange(declarationIndex: 1, '''
+class A {}
+
+class B {}
+
+class C {}
+''', expected: '''
+class A {}
+
+class C {}
+''');
+  }
+
+  Future<void> test_deletionRange_middle_comment() async {
+    await _deletionRange(declarationIndex: 1, '''
+/// for a
+class A {}
+
+/// for b
+class B {}
+
+/// for c
+class C {}
+''', expected: '''
+/// for a
+class A {}
+
+/// for c
+class C {}
+''');
+  }
+
+  Future<void> test_deletionRange_variableDeclaration() async {
+    await _deletionRange(declarationIndex: 0, '''
+var x = 1;
+
+class B {}
+''', expected: '''
+class B {}
+''');
+  }
+
+  Future<void> test_deletionRange_variableDeclaration_comment() async {
+    await _deletionRange(declarationIndex: 0, '''
+// something
+var x = 1;
+
+class B {}
+''', expected: '''
+class B {}
+''');
+  }
+
   Future<void> test_elementName() async {
     await resolveTestCode('class ABC {}');
     var element = findElement.class_('ABC');
@@ -403,4 +567,14 @@
     var mainName = mainFunction.name;
     expect(range.token(mainName.beginToken), SourceRange(1, 4));
   }
+
+  Future<void> _deletionRange(String code,
+      {required String expected, required int declarationIndex}) async {
+    await resolveTestCode(code);
+    var member = testUnit.declarations[declarationIndex];
+    var deletionRange = range.deletionRange(member);
+    var codeAfterDeletion = code.substring(0, deletionRange.offset) +
+        code.substring(deletionRange.end);
+    expect(codeAfterDeletion, expected);
+  }
 }
diff --git a/pkg/async_helper/analysis_options.yaml b/pkg/async_helper/analysis_options.yaml
new file mode 100644
index 0000000..c36c2c5
--- /dev/null
+++ b/pkg/async_helper/analysis_options.yaml
@@ -0,0 +1 @@
+include: package:lints/core.yaml
diff --git a/pkg/async_helper/lib/async_minitest.dart b/pkg/async_helper/lib/async_minitest.dart
index 5b58930..e529aa4 100644
--- a/pkg/async_helper/lib/async_minitest.dart
+++ b/pkg/async_helper/lib/async_minitest.dart
@@ -286,6 +286,7 @@
   void call(dynamic o);
 }
 
+// ignore: camel_case_types
 class isInstanceOf<T> implements _Matcher {
   void call(dynamic o) {
     Expect.type<T>(o);
diff --git a/pkg/async_helper/pubspec.yaml b/pkg/async_helper/pubspec.yaml
index dc909f9..daaf7a8 100644
--- a/pkg/async_helper/pubspec.yaml
+++ b/pkg/async_helper/pubspec.yaml
@@ -14,3 +14,7 @@
 # Use 'any' constraints here; we get our versions from the DEPS file.
 dependencies:
   expect: any
+
+# Use 'any' constraints here; we get our versions from the DEPS file.
+dev_dependencies:
+  lints: any
diff --git a/pkg/build_integration/analysis_options.yaml b/pkg/build_integration/analysis_options.yaml
new file mode 100644
index 0000000..572dd23
--- /dev/null
+++ b/pkg/build_integration/analysis_options.yaml
@@ -0,0 +1 @@
+include: package:lints/recommended.yaml
diff --git a/pkg/build_integration/lib/file_system/multi_root.dart b/pkg/build_integration/lib/file_system/multi_root.dart
index 7fff8e7..7b8a048 100644
--- a/pkg/build_integration/lib/file_system/multi_root.dart
+++ b/pkg/build_integration/lib/file_system/multi_root.dart
@@ -4,6 +4,7 @@
 
 import 'dart:async';
 
+// ignore: implementation_imports
 import 'package:front_end/src/api_unstable/build_integration.dart';
 
 /// Wraps a file system to create an overlay of files from multiple roots.
@@ -39,13 +40,14 @@
 
   @override
   FileSystemEntity entityForUri(Uri uri) =>
-      new MultiRootFileSystemEntity(this, uri);
+      MultiRootFileSystemEntity(this, uri);
 }
 
 /// Entity that searches the multiple roots and resolve a, possibly multi-root,
 /// entity to a plain entity under `multiRootFileSystem.original`.
 class MultiRootFileSystemEntity implements FileSystemEntity {
   final MultiRootFileSystem multiRootFileSystem;
+  @override
   final Uri uri;
   FileSystemEntity? _delegate;
   Future<FileSystemEntity> get delegate async =>
@@ -54,7 +56,7 @@
   Future<FileSystemEntity> _resolveEntity() async {
     if (uri.isScheme(multiRootFileSystem.markerScheme)) {
       if (!uri.isAbsolute) {
-        throw new FileSystemException(
+        throw FileSystemException(
             uri, "This MultiRootFileSystem only handles absolutes URIs: $uri");
       }
       var original = multiRootFileSystem.original;
diff --git a/pkg/build_integration/lib/file_system/single_root.dart b/pkg/build_integration/lib/file_system/single_root.dart
index 896dfc3..bf3d17c 100644
--- a/pkg/build_integration/lib/file_system/single_root.dart
+++ b/pkg/build_integration/lib/file_system/single_root.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// ignore: implementation_imports
 import 'package:front_end/src/api_unstable/build_integration.dart';
 
 /// A [FileSystem] that resolves custom URIs to entities under a specified root
@@ -34,17 +35,17 @@
   @override
   FileSystemEntity entityForUri(Uri uri) {
     if (!uri.isScheme(markerScheme)) {
-      throw new FileSystemException(
+      throw FileSystemException(
           uri,
           "This SingleRootFileSystem only handles URIs with the '$markerScheme'"
           " scheme and cannot handle URIs with scheme '${uri.scheme}': $uri");
     }
     if (!uri.path.startsWith('/')) {
-      throw new FileSystemException(
+      throw FileSystemException(
           uri, "This SingleRootFileSystem only handles absolutes URIs: $uri");
     }
     var path = uri.path.substring(1);
-    return new SingleRootFileSystemEntity(
+    return SingleRootFileSystemEntity(
         uri, original.entityForUri(root.resolve(path)));
   }
 }
@@ -53,6 +54,7 @@
 /// that delegates all operations to an underlying entity in the original
 /// `SingleRootFileSystem.filesystem`.
 class SingleRootFileSystemEntity implements FileSystemEntity {
+  @override
   final Uri uri;
   final FileSystemEntity delegate;
 
diff --git a/pkg/build_integration/pubspec.yaml b/pkg/build_integration/pubspec.yaml
index fbb8715..7045b18 100644
--- a/pkg/build_integration/pubspec.yaml
+++ b/pkg/build_integration/pubspec.yaml
@@ -14,4 +14,5 @@
 
 # Use 'any' constraints here; we get our versions from the DEPS file.
 dev_dependencies:
+  lints: any
   test: any
diff --git a/pkg/build_integration/test/file_system/multi_root_test.dart b/pkg/build_integration/test/file_system/multi_root_test.dart
index 09d3cc9..9ca9230 100644
--- a/pkg/build_integration/test/file_system/multi_root_test.dart
+++ b/pkg/build_integration/test/file_system/multi_root_test.dart
@@ -38,9 +38,9 @@
           .toString();
 
   setUp(() {
-    memoryFs = new MemoryFileSystem(root);
+    memoryFs = MemoryFileSystem(root);
     final rootUris = ['r1', 'r2/', 'A/B/', ''].map((r) => root.resolve(r)).toList();
-    multiRoot = new MultiRootFileSystem('multi-root', rootUris, memoryFs);
+    multiRoot = MultiRootFileSystem('multi-root', rootUris, memoryFs);
   });
 
   test('roots are normalized', () async {
@@ -120,7 +120,7 @@
 
     // If we remove '' as a root, those URIs are not resolved.
     multiRoot =
-        new MultiRootFileSystem('multi-root', [root.resolve('A/B/')], memoryFs);
+        MultiRootFileSystem('multi-root', [root.resolve('A/B/')], memoryFs);
     expect(await effectiveUriOf('multi-root:///../A/B/a/8.dart'),
         'multi-root:///A/B/a/8.dart');
     expect(await effectiveUriOf('multi-root:///../../A/B/a/8.dart'),
diff --git a/pkg/build_integration/test/file_system/single_root_test.dart b/pkg/build_integration/test/file_system/single_root_test.dart
index 50fb984..73ca23a 100644
--- a/pkg/build_integration/test/file_system/single_root_test.dart
+++ b/pkg/build_integration/test/file_system/single_root_test.dart
@@ -9,8 +9,8 @@
 
 main() {
   var root = Uri.parse('org-dartlang-test:///');
-  var fileSystem = new SingleRootFileSystem(
-      'single-root', root.resolve('A/B'), new MemoryFileSystem(root));
+  var fileSystem = SingleRootFileSystem(
+      'single-root', root.resolve('A/B'), MemoryFileSystem(root));
 
   SingleRootFileSystemEntity entityOf(String uri) =>
       fileSystem.entityForUri(Uri.parse(uri)) as SingleRootFileSystemEntity;
diff --git a/pkg/compiler/lib/src/inferrer/builder.dart b/pkg/compiler/lib/src/inferrer/builder.dart
index 01f4f58..80bb03c 100644
--- a/pkg/compiler/lib/src/inferrer/builder.dart
+++ b/pkg/compiler/lib/src/inferrer/builder.dart
@@ -572,13 +572,18 @@
     _setupBreaksAndContinues(jumpTarget);
 
     List<JumpTarget> continueTargets = <JumpTarget>[];
+    bool hasDefaultCase = false;
     for (ir.SwitchCase switchCase in node.cases) {
       JumpTarget continueTarget =
           _localsMap.getJumpTargetForSwitchCase(switchCase);
       if (continueTarget != null) {
         continueTargets.add(continueTarget);
       }
+      if (switchCase.isDefault) {
+        hasDefaultCase = true;
+      }
     }
+    LocalState stateBefore = _state;
     if (continueTargets.isNotEmpty) {
       continueTargets.forEach(_setupBreaksAndContinues);
 
@@ -586,43 +591,47 @@
       // visit all cases and update [locals] until we have reached a
       // fixed point.
       bool changed;
-      _state.startLoop(_inferrer, node);
+      stateBefore.startLoop(_inferrer, node);
       do {
         changed = false;
+        // We first visit every case and collect the updated continue states.
+        // We must do a full pass as the jumps may be to earlier cases.
+        _visitCasesForSwitch(node, stateBefore);
+
+        // We then pass back over the cases and update the state of any continue
+        // targets with the states we collected in the last pass.
         for (ir.SwitchCase switchCase in node.cases) {
-          LocalState stateBeforeCase = _state;
-          _state = LocalState.childPath(stateBeforeCase);
-          visit(switchCase);
-          LocalState stateAfterCase = _state;
-          changed =
-              stateBeforeCase.mergeAll(_inferrer, [stateAfterCase]) || changed;
-          _state = stateBeforeCase;
+          final continueTarget =
+              _localsMap.getJumpTargetForSwitchCase(switchCase);
+          if (continueTarget != null) {
+            changed |= stateBefore.mergeAll(
+                _inferrer, _getLoopBackEdges(continueTarget));
+          }
         }
       } while (changed);
-      _state.endLoop(_inferrer, node);
+      stateBefore.endLoop(_inferrer, node);
 
       continueTargets.forEach(_clearBreaksAndContinues);
     } else {
-      LocalState stateBeforeCase = _state;
-      List<LocalState> statesToMerge = <LocalState>[];
-      bool hasDefaultCase = false;
-
-      for (ir.SwitchCase switchCase in node.cases) {
-        if (switchCase.isDefault) {
-          hasDefaultCase = true;
-        }
-        _state = LocalState.childPath(stateBeforeCase);
-        visit(switchCase);
-        statesToMerge.add(_state);
-      }
-      stateBeforeCase.mergeAfterBreaks(_inferrer, statesToMerge,
-          keepOwnLocals: !hasDefaultCase);
-      _state = stateBeforeCase;
+      // Gather the termination states of each case by visiting all the breaks.
+      _visitCasesForSwitch(node, stateBefore);
     }
+
+    // Combine all the termination states accumulated from all the visited
+    // breaks that target this switch.
+    _state = stateBefore.mergeAfterBreaks(_inferrer, _getBreaks(jumpTarget),
+        keepOwnLocals: !hasDefaultCase);
     _clearBreaksAndContinues(jumpTarget);
     return null;
   }
 
+  _visitCasesForSwitch(ir.SwitchStatement node, LocalState stateBefore) {
+    for (ir.SwitchCase switchCase in node.cases) {
+      _state = LocalState.childPath(stateBefore);
+      visit(switchCase);
+    }
+  }
+
   @override
   visitSwitchCase(ir.SwitchCase node) {
     visit(node.body);
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index 83b6ac6..f27676d 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -103,6 +103,7 @@
 
   /// [FeatureOption]s which default to enabled.
   late final List<FeatureOption> shipping = [
+    deferredSerialization,
     useContentSecurityPolicy,
   ];
 
@@ -113,7 +114,6 @@
     simpleAsyncToFuture,
     cfeConstants,
     internValues,
-    deferredSerialization,
   ];
 
   /// Forces canary feature on. This must run after [Option].parse.
diff --git a/pkg/compiler/test/dump_info/data/deferred/main.dart b/pkg/compiler/test/dump_info/data/deferred/main.dart
index 2ab399c..c4f9945 100644
--- a/pkg/compiler/test/dump_info/data/deferred/main.dart
+++ b/pkg/compiler/test/dump_info/data/deferred/main.dart
@@ -4,7 +4,122 @@
 
 // @dart = 2.7
 
-/*library: 
+/*spec.library: 
+ constant=[
+  {
+  "id": "constant/B.C_Deferred = A.lib__funky$closure();\n",
+  "kind": "constant",
+  "name": "",
+  "size": 39,
+  "outputUnit": "outputUnit/1",
+  "code": "B.C_Deferred = A.lib__funky$closure();\n"
+},
+  {
+  "id": "constant/B.C_JS_CONST = function getTagFallback(o) {\n  var s = Object.prototype.toString.call(o);\n  return s.substring(8, s.length - 1);\n};\n",
+  "kind": "constant",
+  "name": "",
+  "size": 131,
+  "outputUnit": "outputUnit/main",
+  "code": "B.C_JS_CONST = function getTagFallback(o) {\n  var s = Object.prototype.toString.call(o);\n  return s.substring(8, s.length - 1);\n};\n"
+},
+  {
+  "id": "constant/B.C__RootZone = new A._RootZone();\n",
+  "kind": "constant",
+  "name": "",
+  "size": 35,
+  "outputUnit": "outputUnit/main",
+  "code": "B.C__RootZone = new A._RootZone();\n"
+},
+  {
+  "id": "constant/B.C__StringStackTrace = new A._StringStackTrace();\n",
+  "kind": "constant",
+  "name": "",
+  "size": 51,
+  "outputUnit": "outputUnit/main",
+  "code": "B.C__StringStackTrace = new A._StringStackTrace();\n"
+},
+  {
+  "id": "constant/B.Interceptor_methods = J.Interceptor.prototype;\n",
+  "kind": "constant",
+  "name": "",
+  "size": 49,
+  "outputUnit": "outputUnit/main",
+  "code": "B.Interceptor_methods = J.Interceptor.prototype;\n"
+},
+  {
+  "id": "constant/B.JSArray_methods = J.JSArray.prototype;\n",
+  "kind": "constant",
+  "name": "",
+  "size": 41,
+  "outputUnit": "outputUnit/main",
+  "code": "B.JSArray_methods = J.JSArray.prototype;\n"
+},
+  {
+  "id": "constant/B.JSInt_methods = J.JSInt.prototype;\n",
+  "kind": "constant",
+  "name": "",
+  "size": 37,
+  "outputUnit": "outputUnit/main",
+  "code": "B.JSInt_methods = J.JSInt.prototype;\n"
+},
+  {
+  "id": "constant/B.JSString_methods = J.JSString.prototype;\n",
+  "kind": "constant",
+  "name": "",
+  "size": 43,
+  "outputUnit": "outputUnit/main",
+  "code": "B.JSString_methods = J.JSString.prototype;\n"
+},
+  {
+  "id": "constant/B.JavaScriptObject_methods = J.JavaScriptObject.prototype;\n",
+  "kind": "constant",
+  "name": "",
+  "size": 59,
+  "outputUnit": "outputUnit/main",
+  "code": "B.JavaScriptObject_methods = J.JavaScriptObject.prototype;\n"
+}],
+ deferredFiles=[{
+  "main.dart": {
+    "name": "<unnamed>",
+    "imports": {
+      "lib": [
+        "out_1.part.js"
+      ]
+    }
+  }
+}],
+ dependencies=[{}],
+ library=[{
+  "id": "library/memory:sdk/tests/web/native/main.dart::",
+  "kind": "library",
+  "name": "<unnamed>",
+  "size": 301,
+  "children": [
+    "function/memory:sdk/tests/web/native/main.dart::main"
+  ],
+  "canonicalUri": "memory:sdk/tests/web/native/main.dart"
+}],
+ outputUnits=[
+  {
+  "id": "outputUnit/1",
+  "kind": "outputUnit",
+  "name": "1",
+  "size": 1087,
+  "filename": "out_1.part.js",
+  "imports": [
+    "lib"
+  ]
+},
+  {
+  "id": "outputUnit/main",
+  "kind": "outputUnit",
+  "name": "main",
+  "filename": "out",
+  "imports": []
+}]
+*/
+
+/*canary.library: 
  constant=[
   {
   "id": "constant/B.C_Deferred = A.lib__funky$closure();\n",
diff --git a/pkg/compiler/test/dump_info/data/deferred_future/main.dart b/pkg/compiler/test/dump_info/data/deferred_future/main.dart
index e95b65c..f9347fc 100644
--- a/pkg/compiler/test/dump_info/data/deferred_future/main.dart
+++ b/pkg/compiler/test/dump_info/data/deferred_future/main.dart
@@ -2,7 +2,130 @@
 // 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.
 
-/*library: 
+/*spec.library: 
+ constant=[
+  {
+  "id": "constant/B.C_A = new A.A();\n",
+  "kind": "constant",
+  "name": "",
+  "size": 19,
+  "outputUnit": "outputUnit/1",
+  "code": "B.C_A = new A.A();\n"
+},
+  {
+  "id": "constant/B.C_Deferred = B.C_A;\n",
+  "kind": "constant",
+  "name": "",
+  "size": 22,
+  "outputUnit": "outputUnit/1",
+  "code": "B.C_Deferred = B.C_A;\n"
+},
+  {
+  "id": "constant/B.C_JS_CONST = function getTagFallback(o) {\n  var s = Object.prototype.toString.call(o);\n  return s.substring(8, s.length - 1);\n};\n",
+  "kind": "constant",
+  "name": "",
+  "size": 131,
+  "outputUnit": "outputUnit/main",
+  "code": "B.C_JS_CONST = function getTagFallback(o) {\n  var s = Object.prototype.toString.call(o);\n  return s.substring(8, s.length - 1);\n};\n"
+},
+  {
+  "id": "constant/B.C__RootZone = new A._RootZone();\n",
+  "kind": "constant",
+  "name": "",
+  "size": 35,
+  "outputUnit": "outputUnit/main",
+  "code": "B.C__RootZone = new A._RootZone();\n"
+},
+  {
+  "id": "constant/B.C__StringStackTrace = new A._StringStackTrace();\n",
+  "kind": "constant",
+  "name": "",
+  "size": 51,
+  "outputUnit": "outputUnit/main",
+  "code": "B.C__StringStackTrace = new A._StringStackTrace();\n"
+},
+  {
+  "id": "constant/B.Interceptor_methods = J.Interceptor.prototype;\n",
+  "kind": "constant",
+  "name": "",
+  "size": 49,
+  "outputUnit": "outputUnit/main",
+  "code": "B.Interceptor_methods = J.Interceptor.prototype;\n"
+},
+  {
+  "id": "constant/B.JSArray_methods = J.JSArray.prototype;\n",
+  "kind": "constant",
+  "name": "",
+  "size": 41,
+  "outputUnit": "outputUnit/main",
+  "code": "B.JSArray_methods = J.JSArray.prototype;\n"
+},
+  {
+  "id": "constant/B.JSInt_methods = J.JSInt.prototype;\n",
+  "kind": "constant",
+  "name": "",
+  "size": 37,
+  "outputUnit": "outputUnit/main",
+  "code": "B.JSInt_methods = J.JSInt.prototype;\n"
+},
+  {
+  "id": "constant/B.JSString_methods = J.JSString.prototype;\n",
+  "kind": "constant",
+  "name": "",
+  "size": 43,
+  "outputUnit": "outputUnit/main",
+  "code": "B.JSString_methods = J.JSString.prototype;\n"
+},
+  {
+  "id": "constant/B.JavaScriptObject_methods = J.JavaScriptObject.prototype;\n",
+  "kind": "constant",
+  "name": "",
+  "size": 59,
+  "outputUnit": "outputUnit/main",
+  "code": "B.JavaScriptObject_methods = J.JavaScriptObject.prototype;\n"
+}],
+ deferredFiles=[{
+  "main.dart": {
+    "name": "<unnamed>",
+    "imports": {
+      "lib1": [
+        "out_1.part.js"
+      ]
+    }
+  }
+}],
+ dependencies=[{}],
+ library=[{
+  "id": "library/memory:sdk/tests/web/native/main.dart::",
+  "kind": "library",
+  "name": "<unnamed>",
+  "size": 857,
+  "children": [
+    "function/memory:sdk/tests/web/native/main.dart::main"
+  ],
+  "canonicalUri": "memory:sdk/tests/web/native/main.dart"
+}],
+ outputUnits=[
+  {
+  "id": "outputUnit/1",
+  "kind": "outputUnit",
+  "name": "1",
+  "size": 870,
+  "filename": "out_1.part.js",
+  "imports": [
+    "lib1"
+  ]
+},
+  {
+  "id": "outputUnit/main",
+  "kind": "outputUnit",
+  "name": "main",
+  "filename": "out",
+  "imports": []
+}]
+*/
+
+/*canary.library:
  constant=[
   {
   "id": "constant/B.C_A = new A.A();\n",
diff --git a/pkg/compiler/test/inference/data/issue_46770.dart b/pkg/compiler/test/inference/data/issue_46770.dart
new file mode 100644
index 0000000..739bd53
--- /dev/null
+++ b/pkg/compiler/test/inference/data/issue_46770.dart
@@ -0,0 +1,364 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class L {
+  void m1();
+}
+
+/*member: L1.:[exact=L1]*/
+class L1 implements L {
+  @pragma('dart2js:noInline')
+  /*member: L1.m1:[null]*/
+  void m1() => print("L1");
+}
+
+/*member: L2.:[exact=L2]*/
+class L2 implements L {
+  @pragma('dart2js:noInline')
+  /*member: L2.m1:[null]*/
+  void m1() => print("L2");
+}
+
+/*member: L3.:[exact=L3]*/
+class L3 implements L {
+  @pragma('dart2js:noInline')
+  /*member: L3.m1:[null]*/
+  void m1() => print("L3");
+}
+
+/*member: cTrue:[exact=JSBool]*/
+bool cTrue = confuse(true);
+/*member: value:[exact=JSUInt31]*/
+int value = confuse(1);
+
+@pragma('dart2js:noInline')
+/*member: confuse:Union([exact=JSBool], [exact=JSUInt31])*/
+confuse(/*Union([exact=JSBool], [exact=JSUInt31])*/ x) => x;
+
+/*member: test1:Union(null, [exact=L2], [exact=L3])*/
+test1() {
+  L? sourceInfo = L1();
+  switch (value) {
+    case 1:
+      if (cTrue) {
+        sourceInfo = L2();
+        break;
+      }
+      sourceInfo = L3();
+      break;
+    default:
+      return null;
+  }
+
+  sourceInfo. /*invoke: Union([exact=L2], [exact=L3])*/ m1();
+  return sourceInfo;
+}
+
+/*member: test2:Union([exact=L1], [exact=L2], [exact=L3])*/
+test2() {
+  L? sourceInfo = L1();
+  switch (value) {
+    case 1:
+      if (cTrue) {
+        sourceInfo = L2();
+        break;
+      }
+      sourceInfo = L3();
+      break;
+    default:
+    // Do nothing
+  }
+
+  sourceInfo. /*invoke: Union([exact=L1], [exact=L2], [exact=L3])*/ m1();
+  return sourceInfo;
+}
+
+/*member: test3:Union(null, [exact=L2], [exact=L3])*/
+test3() {
+  L? sourceInfo = L1();
+  switchTarget:
+  switch (value) {
+    case 1:
+      while (cTrue) {
+        sourceInfo = L2();
+        break switchTarget;
+      }
+      sourceInfo = L3();
+      break;
+    default:
+      return null;
+  }
+
+  sourceInfo. /*invoke: Union([exact=L2], [exact=L3])*/ m1();
+  return sourceInfo;
+}
+
+/*member: test4:Union(null, [exact=L1], [exact=L3])*/
+test4() {
+  L sourceInfo = L1();
+  switch (value) {
+    case 1:
+      if (cTrue) {
+        sourceInfo = L2();
+        continue otherCase;
+      }
+      sourceInfo = L3();
+      break;
+    otherCase:
+    case 2:
+      sourceInfo. /*invoke: Union([exact=L1], [exact=L2])*/ m1();
+      sourceInfo = L1();
+      break;
+    default:
+      return null;
+  }
+
+  sourceInfo. /*invoke: Union([exact=L1], [exact=L3])*/ m1();
+  return sourceInfo;
+}
+
+/*member: test5:Union(null, [exact=L1], [exact=L2], [exact=L3])*/
+test5() {
+  L sourceInfo = L1();
+  switch (value) {
+    case 1:
+      if (cTrue) {
+        sourceInfo = L2();
+        continue otherCase;
+      }
+      sourceInfo = L3();
+      break;
+    otherCase:
+    case 2:
+      break;
+    default:
+      return null;
+  }
+
+  sourceInfo. /*invoke: Union([exact=L1], [exact=L2], [exact=L3])*/ m1();
+  return sourceInfo;
+}
+
+/*member: test6:Union(null, [exact=L2], [exact=L3])*/
+test6() {
+  L sourceInfo = L1();
+  switch (value) {
+    case 1:
+      if (cTrue) {
+        sourceInfo = L2();
+        continue otherCase;
+      }
+      sourceInfo = L3();
+      break;
+    otherCase:
+    case 2:
+      sourceInfo = L2();
+      break;
+    default:
+      return null;
+  }
+
+  sourceInfo. /*invoke: Union([exact=L2], [exact=L3])*/ m1();
+  return sourceInfo;
+}
+
+/*member: test7:[null|exact=L3]*/
+test7() {
+  L? sourceInfo = L1();
+  switch (value) {
+    case 1:
+      if (cTrue) {
+        sourceInfo = L2();
+        return null;
+      }
+      sourceInfo = L3();
+      break;
+    default:
+      return null;
+  }
+
+  sourceInfo. /*invoke: [exact=L3]*/ m1();
+  return sourceInfo;
+}
+
+/*member: test8:[null|exact=L3]*/
+test8() {
+  L? sourceInfo = L1();
+  switch (value) {
+    case 1:
+      while (cTrue) {
+        sourceInfo = L2();
+        break;
+      }
+      sourceInfo = L3();
+      break;
+    default:
+      return null;
+  }
+
+  sourceInfo. /*invoke: [exact=L3]*/ m1();
+  return sourceInfo;
+}
+
+/*member: test9:[null|exact=L3]*/
+test9() {
+  L? sourceInfo = L1();
+  switch (value) {
+    case 1:
+      while (cTrue) {
+        sourceInfo = L2();
+        return null;
+      }
+      sourceInfo = L3();
+      break;
+    default:
+      return null;
+  }
+
+  sourceInfo. /*invoke: [exact=L3]*/ m1();
+  return sourceInfo;
+}
+
+/*member: test10:Union(null, [exact=L1], [exact=L2], [exact=L3])*/
+test10() {
+  L sourceInfo = L1();
+  try {
+    switch (value) {
+      case 1:
+        if (cTrue) {
+          sourceInfo = L2();
+          throw Exception();
+        }
+        sourceInfo = L3();
+        break;
+      default:
+        return null;
+    }
+  } catch (e) {
+    // Do nothing
+  }
+
+  sourceInfo. /*invoke: Union([exact=L1], [exact=L2], [exact=L3])*/ m1();
+  return sourceInfo;
+}
+
+/*member: test11:[null|exact=L3]*/
+test11() {
+  L sourceInfo = L1();
+  switch (value) {
+    case 1:
+      if (cTrue) {
+        sourceInfo = L2();
+        throw Exception();
+      }
+      sourceInfo = L3();
+      break;
+    default:
+      return null;
+  }
+  sourceInfo. /*invoke: [exact=L3]*/ m1();
+  return sourceInfo;
+}
+
+/*member: test12:Union(null, [exact=L1], [exact=L3])*/
+test12() {
+  L? sourceInfo = L1();
+  switch (value) {
+    case 1:
+      if (cTrue) {
+        sourceInfo = L2();
+        return null;
+      }
+      sourceInfo = L3();
+      break;
+    default:
+    // Do nothing
+  }
+
+  sourceInfo. /*invoke: Union([exact=L1], [exact=L3])*/ m1();
+  return sourceInfo;
+}
+
+/*member: test13:Union(null, [exact=L2], [exact=L3])*/
+test13() {
+  L? sourceInfo = L1();
+  switch (value) {
+    case 1:
+      if (cTrue) {
+        sourceInfo = L2();
+        return null;
+      }
+      sourceInfo = L3();
+      break;
+    default:
+      sourceInfo = L2();
+  }
+
+  sourceInfo. /*invoke: Union([exact=L2], [exact=L3])*/ m1();
+  return sourceInfo;
+}
+
+/*member: test14:Union(null, [exact=L1], [exact=L2], [exact=L3])*/
+test14() {
+  L sourceInfo = L1();
+  whileLabel:
+  while (true) {
+    switch (value) {
+      case 1:
+        if (cTrue) {
+          sourceInfo = L2();
+          break whileLabel;
+        }
+        sourceInfo = L3();
+        break;
+      default:
+        return null;
+    }
+    sourceInfo. /*invoke: [exact=L3]*/ m1();
+    break;
+  }
+  sourceInfo. /*invoke: Union([exact=L1], [exact=L2], [exact=L3])*/ m1();
+  return sourceInfo;
+}
+
+/*member: test15:[null|exact=L3]*/
+test15() {
+  L sourceInfo = L1();
+  switch (value) {
+    case 1:
+      if (cTrue) {
+        sourceInfo = L2();
+        continue otherCase;
+      }
+      sourceInfo = L3();
+      break;
+    otherCase:
+    case 2:
+      return null;
+    default:
+      return null;
+  }
+
+  sourceInfo. /*invoke: [exact=L3]*/ m1();
+  return sourceInfo;
+}
+
+/*member: main:[null]*/
+main() {
+  test1();
+  test2();
+  test3();
+  test4();
+  test5();
+  test6();
+  test7();
+  test8();
+  test9();
+  test10();
+  test11();
+  test12();
+  test13();
+  test14();
+  test15();
+}
diff --git a/pkg/compiler/test/inference/data/switch.dart b/pkg/compiler/test/inference/data/switch.dart
index df79306..be09435 100644
--- a/pkg/compiler/test/inference/data/switch.dart
+++ b/pkg/compiler/test/inference/data/switch.dart
@@ -90,7 +90,7 @@
 // Switch statement with continue.
 ////////////////////////////////////////////////////////////////////////////////
 
-/*member: _switchWithContinue:Union(null, [exact=JSBool], [exact=JSString], [exact=JSUInt31])*/
+/*member: _switchWithContinue:Union([exact=JSBool], [exact=JSString])*/
 _switchWithContinue(/*[exact=JSUInt31]*/ o) {
   dynamic local;
   switch (o) {
@@ -99,8 +99,7 @@
       continue label;
     label:
     case 1:
-      local = local
-          . /*Union(null, [exact=JSBool], [exact=JSString], [exact=JSUInt31])*/ isEven;
+      local = local. /*Union(null, [exact=JSString], [exact=JSUInt31])*/ isEven;
       break;
     case 2:
     default:
diff --git a/pkg/dart_internal/analysis_options.yaml b/pkg/dart_internal/analysis_options.yaml
index 6f7501d..a5a786b 100644
--- a/pkg/dart_internal/analysis_options.yaml
+++ b/pkg/dart_internal/analysis_options.yaml
@@ -1,3 +1,5 @@
+include: package:lints/recommended.yaml
+
 analyzer:
   errors:
     import_internal_library: ignore
diff --git a/pkg/dart_internal/pubspec.yaml b/pkg/dart_internal/pubspec.yaml
index 0c52966..5d59e77 100644
--- a/pkg/dart_internal/pubspec.yaml
+++ b/pkg/dart_internal/pubspec.yaml
@@ -10,3 +10,7 @@
   # Restrict the upper bound so that we can remove support for this in a later
   # version of the SDK without it being a breaking change.
   sdk: ">=2.12.0 <2.19.0"
+
+# Use 'any' constraints here; we get our versions from the DEPS file.
+dev_dependencies:
+  lints: any
diff --git a/pkg/dds_service_extensions/analysis_options.yaml b/pkg/dds_service_extensions/analysis_options.yaml
index dee8927..572dd23 100644
--- a/pkg/dds_service_extensions/analysis_options.yaml
+++ b/pkg/dds_service_extensions/analysis_options.yaml
@@ -1,30 +1 @@
-# This file configures the static analysis results for your project (errors,
-# warnings, and lints).
-#
-# This enables the 'recommended' set of lints from `package:lints`.
-# This set helps identify many issues that may lead to problems when running
-# or consuming Dart code, and enforces writing Dart using a single, idiomatic
-# style and format.
-#
-# If you want a smaller set of lints you can change this to specify
-# 'package:lints/core.yaml'. These are just the most critical lints
-# (the recommended set includes the core lints).
-# The core lints are also what is used by pub.dev for scoring packages.
-
 include: package:lints/recommended.yaml
-
-# Uncomment the following section to specify additional rules.
-
-# linter:
-#   rules:
-#     - camel_case_types
-
-# analyzer:
-#   exclude:
-#     - path/to/excluded/files/**
-
-# For more information about the core and recommended set of lints, see
-# https://dart.dev/go/core-lints
-
-# For additional information about configuring this file, see
-# https://dart.dev/guides/language/analysis-options
diff --git a/pkg/frontend_server/README.md b/pkg/frontend_server/README.md
index afebf6c..eed933c 100644
--- a/pkg/frontend_server/README.md
+++ b/pkg/frontend_server/README.md
@@ -10,7 +10,6 @@
 
 This API stability does not cover any of the source code APIs.
 
-
 ### Stable subset
 
 * The frontend_server kernel compilation and expression evaluation for kernel should be considered "stable".
diff --git a/pkg/frontend_server/analysis_options.yaml b/pkg/frontend_server/analysis_options.yaml
new file mode 100644
index 0000000..c36c2c5
--- /dev/null
+++ b/pkg/frontend_server/analysis_options.yaml
@@ -0,0 +1 @@
+include: package:lints/core.yaml
diff --git a/pkg/frontend_server/bin/frontend_server_starter.dart b/pkg/frontend_server/bin/frontend_server_starter.dart
index 82b6fb8..526c396 100644
--- a/pkg/frontend_server/bin/frontend_server_starter.dart
+++ b/pkg/frontend_server/bin/frontend_server_starter.dart
@@ -4,7 +4,7 @@
 import 'dart:async';
 import 'dart:io';
 
-import '../lib/frontend_server.dart';
+import 'package:frontend_server/frontend_server.dart';
 
 Future<Null> main(List<String> args) async {
   exitCode = await starter(args);
diff --git a/pkg/frontend_server/lib/frontend_server.dart b/pkg/frontend_server/lib/frontend_server.dart
index a3f6508..5d7088c 100644
--- a/pkg/frontend_server/lib/frontend_server.dart
+++ b/pkg/frontend_server/lib/frontend_server.dart
@@ -634,7 +634,7 @@
     return errors.isEmpty;
   }
 
-  void _outputDependenciesDelta(Iterable<Uri> compiledSources) async {
+  Future<void> _outputDependenciesDelta(Iterable<Uri> compiledSources) async {
     if (!_printIncrementalDependencies) {
       return;
     }
@@ -948,7 +948,7 @@
     final procedure = await expressionCompiler.compileExpressionToJs(
         libraryUri, line, column, jsFrameValues, expression);
 
-    final result = errors.length > 0 ? errors[0] : procedure;
+    final result = errors.isNotEmpty ? errors[0] : procedure;
 
     // TODO(annagrin): kernelBinaryFilename is too specific
     // rename to _outputFileName?
@@ -1271,8 +1271,9 @@
         if (string == boundaryKey) {
           compiler.recompileDelta(entryPoint: recompileEntryPoint);
           state = _State.READY_FOR_INSTRUCTION;
-        } else
+        } else {
           compiler.invalidate(Uri.base.resolve(string));
+        }
         break;
       case _State.COMPILE_EXPRESSION_EXPRESSION:
         compileExpressionRequest.expression = string;
diff --git a/pkg/frontend_server/lib/src/javascript_bundle.dart b/pkg/frontend_server/lib/src/javascript_bundle.dart
index 00ddccb..d6a340b 100644
--- a/pkg/frontend_server/lib/src/javascript_bundle.dart
+++ b/pkg/frontend_server/lib/src/javascript_bundle.dart
@@ -161,8 +161,7 @@
         // Source locations come through as absolute file uris. In order to
         // make relative paths in the source map we get the absolute uri for
         // the module and make them relative to that.
-        sourceMapBase =
-            p.dirname((await _packageConfig.resolve(moduleUri)).path);
+        sourceMapBase = p.dirname((_packageConfig.resolve(moduleUri)).path);
       }
 
       final code = jsProgramToCode(
diff --git a/pkg/frontend_server/lib/src/strong_components.dart b/pkg/frontend_server/lib/src/strong_components.dart
index a436b7c..3fca363 100644
--- a/pkg/frontend_server/lib/src/strong_components.dart
+++ b/pkg/frontend_server/lib/src/strong_components.dart
@@ -82,7 +82,7 @@
     final List<List<Library>> results =
         computeStrongComponents(_LibraryGraph(entrypoint, loadedLibraries));
     for (List<Library> component in results) {
-      assert(component.length > 0);
+      assert(component.isNotEmpty);
       final Uri moduleUri = component
           .firstWhere((lib) => lib.importUri == mainUri,
               orElse: () => component.first)
diff --git a/pkg/frontend_server/pubspec.yaml b/pkg/frontend_server/pubspec.yaml
index 93b3740..5218bd1 100644
--- a/pkg/frontend_server/pubspec.yaml
+++ b/pkg/frontend_server/pubspec.yaml
@@ -22,5 +22,6 @@
 
 # Use 'any' constraints here; we get our versions from the DEPS file.
 dev_dependencies:
+  lints: any
   mockito: any
   test: any
diff --git a/pkg/frontend_server/test/frontend_server_flutter.dart b/pkg/frontend_server/test/frontend_server_flutter.dart
index f0d5f2f..fee26f6 100644
--- a/pkg/frontend_server/test/frontend_server_flutter.dart
+++ b/pkg/frontend_server/test/frontend_server_flutter.dart
@@ -13,7 +13,7 @@
 import 'package:front_end/src/api_unstable/vm.dart'
     show CompilerOptions, NnbdMode, StandardFileSystem;
 
-import '../lib/frontend_server.dart';
+import 'package:frontend_server/frontend_server.dart';
 
 main(List<String> args) async {
   String flutterDir;
@@ -70,7 +70,7 @@
         f.uri
             .toString()
             .endsWith("/flutter_patched_sdk/platform_strong.dill")));
-    if (platformFiles.length < 1) {
+    if (platformFiles.isEmpty) {
       throw "Expected to find a flutter platform file but didn't.";
     }
     flutterPlatformDirectoryTmp = platformFiles.first.parent;
diff --git a/pkg/frontend_server/test/frontend_server_flutter_suite.dart b/pkg/frontend_server/test/frontend_server_flutter_suite.dart
index 0a6b249..8473358 100644
--- a/pkg/frontend_server/test/frontend_server_flutter_suite.dart
+++ b/pkg/frontend_server/test/frontend_server_flutter_suite.dart
@@ -182,8 +182,8 @@
   }
 }
 
-void writeLinesToFile(Uri uri, List<String> lines) async {
-  await File.fromUri(uri).writeAsString(lines.map((line) => "$line\n").join());
+void writeLinesToFile(Uri uri, List<String> lines) {
+  File.fromUri(uri).writeAsStringSync(lines.map((line) => "$line\n").join());
 }
 
 main([List<String> arguments = const <String>[]]) async {
@@ -254,8 +254,8 @@
   // Write results.json and logs.json.
   Uri resultJsonUri = options.outputDirectory.resolve("results.json");
   Uri logsJsonUri = options.outputDirectory.resolve("logs.json");
-  await writeLinesToFile(resultJsonUri, results);
-  await writeLinesToFile(logsJsonUri, logs);
+  writeLinesToFile(resultJsonUri, results);
+  writeLinesToFile(logsJsonUri, logs);
   print("Log files written to ${resultJsonUri.toFilePath()} and"
       " ${logsJsonUri.toFilePath()}");
 
diff --git a/pkg/frontend_server/test/frontend_server_test.dart b/pkg/frontend_server/test/frontend_server_test.dart
index d9d8b6f..9cc623d 100644
--- a/pkg/frontend_server/test/frontend_server_test.dart
+++ b/pkg/frontend_server/test/frontend_server_test.dart
@@ -1,4 +1,6 @@
 // @dart = 2.9
+// ignore_for_file: empty_catches
+
 import 'dart:async';
 import 'dart:convert';
 import 'dart:io';
@@ -7,6 +9,7 @@
 
 import 'package:_fe_analyzer_shared/src/macros/compiler/request_channel.dart';
 import 'package:front_end/src/api_unstable/vm.dart';
+import 'package:frontend_server/frontend_server.dart';
 import 'package:kernel/ast.dart' show Component;
 import 'package:kernel/binary/ast_to_binary.dart';
 import 'package:kernel/kernel.dart' show loadComponentFromBinary;
@@ -16,8 +19,6 @@
 import 'package:test/test.dart';
 import 'package:vm/incremental_compiler.dart';
 
-import '../lib/frontend_server.dart';
-
 void main() async {
   group('basic', () {
     final CompilerInterface compiler = _MockedCompiler();
@@ -499,10 +500,9 @@
       file.writeAsStringSync("main() {\n}\n");
       var dillFile = File('${tempDir.path}/app.dill');
 
-      var package_config =
-          File('${tempDir.path}/.dart_tool/package_config.json')
-            ..createSync(recursive: true)
-            ..writeAsStringSync('''
+      var packageConfig = File('${tempDir.path}/.dart_tool/package_config.json')
+        ..createSync(recursive: true)
+        ..writeAsStringSync('''
   {
     "configVersion": 2,
     "packages": [
@@ -521,7 +521,7 @@
         '--incremental',
         '--platform=${platformKernel.path}',
         '--output-dill=${dillFile.path}',
-        '--packages=${package_config.path}',
+        '--packages=${packageConfig.path}',
       ];
 
       final StreamController<List<int>> streamController =
@@ -2024,10 +2024,9 @@
     test('compile to JavaScript', () async {
       var file = File('${tempDir.path}/foo.dart')..createSync();
       file.writeAsStringSync("main() {\n}\n");
-      var package_config =
-          File('${tempDir.path}/.dart_tool/package_config.json')
-            ..createSync(recursive: true)
-            ..writeAsStringSync('''
+      var packageConfig = File('${tempDir.path}/.dart_tool/package_config.json')
+        ..createSync(recursive: true)
+        ..writeAsStringSync('''
   {
     "configVersion": 2,
     "packages": [
@@ -2048,7 +2047,7 @@
         '--incremental',
         '--platform=${ddcPlatformKernel.path}',
         '--output-dill=${dillFile.path}',
-        '--packages=${package_config.path}',
+        '--packages=${packageConfig.path}',
         '--target=dartdevc',
         file.path,
       ];
@@ -2190,10 +2189,9 @@
       var file = File('${tempDir.path}/foo.dart')..createSync();
       file.writeAsStringSync("main() {\n\n}\n");
 
-      var package_config =
-          File('${tempDir.path}/.dart_tool/package_config.json')
-            ..createSync(recursive: true)
-            ..writeAsStringSync('''
+      var packageConfig = File('${tempDir.path}/.dart_tool/package_config.json')
+        ..createSync(recursive: true)
+        ..writeAsStringSync('''
   {
     "configVersion": 2,
     "packages": [
@@ -2226,7 +2224,7 @@
         '--platform=${ddcPlatformKernel.path}',
         '--output-dill=${dillFile.path}',
         '--target=dartdevc',
-        '--packages=${package_config.path}',
+        '--packages=${packageConfig.path}',
       ];
 
       final StreamController<List<int>> streamController =
@@ -2269,10 +2267,9 @@
     test('compile to JavaScript with metadata', () async {
       var file = File('${tempDir.path}/foo.dart')..createSync();
       file.writeAsStringSync("main() {\n\n}\n");
-      var package_config =
-          File('${tempDir.path}/.dart_tool/package_config.json')
-            ..createSync(recursive: true)
-            ..writeAsStringSync('''
+      var packageConfig = File('${tempDir.path}/.dart_tool/package_config.json')
+        ..createSync(recursive: true)
+        ..writeAsStringSync('''
   {
     "configVersion": 2,
     "packages": [
@@ -2307,7 +2304,7 @@
         '--platform=${ddcPlatformKernel.path}',
         '--output-dill=${dillFile.path}',
         '--target=dartdevc',
-        '--packages=${package_config.path}',
+        '--packages=${packageConfig.path}',
         '--experimental-emit-debug-metadata',
         '--emit-debug-symbols',
       ];
@@ -2361,10 +2358,9 @@
       var dillFile = File('${tempDir.path}/app.dill');
       var sourceFile = File('${dillFile.path}.sources');
 
-      var package_config =
-          File('${tempDir.path}/.dart_tool/package_config.json')
-            ..createSync(recursive: true)
-            ..writeAsStringSync('''
+      var packageConfig = File('${tempDir.path}/.dart_tool/package_config.json')
+        ..createSync(recursive: true)
+        ..writeAsStringSync('''
     {
       "configVersion": 2,
       "packages": [
@@ -2386,7 +2382,7 @@
         '--platform=${ddcPlatformKernelWeak.path}',
         '--output-dill=${dillFile.path}',
         '--target=dartdevc',
-        '--packages=${package_config.path}'
+        '--packages=${packageConfig.path}'
       ];
 
       final StreamController<List<int>> streamController =
@@ -2444,10 +2440,9 @@
       file = File('${tempDir.path}/bar.dart')..createSync();
       file.writeAsStringSync("void Function(int) fn = (int i) => null;\n");
 
-      var package_config =
-          File('${tempDir.path}/.dart_tool/package_config.json')
-            ..createSync(recursive: true)
-            ..writeAsStringSync('''
+      var packageConfig = File('${tempDir.path}/.dart_tool/package_config.json')
+        ..createSync(recursive: true)
+        ..writeAsStringSync('''
     {
       "configVersion": 2,
       "packages": [
@@ -2471,7 +2466,7 @@
         '--platform=${ddcPlatformKernel.path}',
         '--output-dill=${dillFile.path}',
         '--target=dartdevc',
-        '--packages=${package_config.path}',
+        '--packages=${packageConfig.path}',
       ];
 
       final StreamController<List<int>> streamController =
@@ -2524,10 +2519,9 @@
     test('compile expression to Javascript', () async {
       var file = File('${tempDir.path}/foo.dart')..createSync();
       file.writeAsStringSync("main() {\n}\n");
-      var package_config =
-          File('${tempDir.path}/.dart_tool/package_config.json')
-            ..createSync(recursive: true)
-            ..writeAsStringSync('''
+      var packageConfig = File('${tempDir.path}/.dart_tool/package_config.json')
+        ..createSync(recursive: true)
+        ..writeAsStringSync('''
   {
     "configVersion": 2,
     "packages": [
@@ -2556,7 +2550,7 @@
         '--platform=${ddcPlatformKernel.path}',
         '--output-dill=${dillFile.path}',
         '--target=dartdevc',
-        '--packages=${package_config.path}',
+        '--packages=${packageConfig.path}',
       ];
 
       final StreamController<List<int>> streamController =
@@ -2645,10 +2639,9 @@
       var file = File('${tempDir.path}/foo.dart')..createSync();
       file.writeAsStringSync(
           "main() {print(const bool.fromEnvironment('dart.library.html'));}\n");
-      var package_config =
-          File('${tempDir.path}/.dart_tool/package_config.json')
-            ..createSync(recursive: true)
-            ..writeAsStringSync('''
+      var packageConfig = File('${tempDir.path}/.dart_tool/package_config.json')
+        ..createSync(recursive: true)
+        ..writeAsStringSync('''
   {
     "configVersion": 2,
     "packages": [
@@ -2677,7 +2670,7 @@
         '--platform=${ddcPlatformKernel.path}',
         '--output-dill=${dillFile.path}',
         '--target=dartdevc',
-        '--packages=${package_config.path}',
+        '--packages=${packageConfig.path}',
       ];
 
       final StreamController<List<int>> streamController =
@@ -2753,10 +2746,9 @@
     test('mixed compile expression commands with web target', () async {
       var file = File('${tempDir.path}/foo.dart')..createSync();
       file.writeAsStringSync("main() {\n\n}\n");
-      var package_config =
-          File('${tempDir.path}/.dart_tool/package_config.json')
-            ..createSync(recursive: true)
-            ..writeAsStringSync('''
+      var packageConfig = File('${tempDir.path}/.dart_tool/package_config.json')
+        ..createSync(recursive: true)
+        ..writeAsStringSync('''
   {
     "configVersion": 2,
     "packages": [
@@ -2784,7 +2776,7 @@
         '--platform=${ddcPlatformKernel.path}',
         '--output-dill=${dillFile.path}',
         '--target=dartdevc',
-        '--packages=${package_config.path}',
+        '--packages=${packageConfig.path}',
       ];
 
       final StreamController<List<int>> streamController =
@@ -3124,7 +3116,7 @@
 main() {}
 method(int i) => i?.isEven;
 """);
-        var package_config =
+        var packageConfig =
             File('${tempDir.path}/.dart_tool/package_config.json')
               ..createSync(recursive: true)
               ..writeAsStringSync('''
@@ -3148,7 +3140,7 @@
           '--incremental',
           '--platform=${ddcPlatformKernel.path}',
           '--output-dill=${dillFile.path}',
-          '--packages=${package_config.path}',
+          '--packages=${packageConfig.path}',
           '--target=dartdevc',
           if (hideWarnings) '--verbosity=error',
           file.path,
diff --git a/pkg/frontend_server/test/src/javascript_bundle_test.dart b/pkg/frontend_server/test/src/javascript_bundle_test.dart
index 488e986..ae41252 100644
--- a/pkg/frontend_server/test/src/javascript_bundle_test.dart
+++ b/pkg/frontend_server/test/src/javascript_bundle_test.dart
@@ -145,7 +145,7 @@
 
   test('converts package: uris into /packages/ uris', () async {
     var importUri = Uri.parse('package:a/a.dart');
-    var fileUri = await packageConfig.resolve(importUri);
+    var fileUri = packageConfig.resolve(importUri);
     final library = Library(
       importUri,
       fileUri: fileUri,
diff --git a/pkg/smith/lib/configuration.dart b/pkg/smith/lib/configuration.dart
index 5cf0e02..f5a7d94 100644
--- a/pkg/smith/lib/configuration.dart
+++ b/pkg/smith/lib/configuration.dart
@@ -625,7 +625,6 @@
   static const dart2js = Compiler._('dart2js');
   static const dart2analyzer = Compiler._('dart2analyzer');
   static const dart2wasm = Compiler._('dart2wasm');
-  static const compareAnalyzerCfe = Compiler._('compare_analyzer_cfe');
   static const dartdevc = Compiler._('dartdevc');
   static const dartdevk = Compiler._('dartdevk');
   static const appJitk = Compiler._('app_jitk');
@@ -641,7 +640,6 @@
     dart2js,
     dart2analyzer,
     dart2wasm,
-    compareAnalyzerCfe,
     dartdevc,
     dartdevk,
     appJitk,
@@ -700,7 +698,6 @@
           Runtime.chrome,
         ];
       case Compiler.dart2analyzer:
-      case Compiler.compareAnalyzerCfe:
         return const [Runtime.none];
       case Compiler.appJitk:
       case Compiler.dartk:
@@ -730,7 +727,6 @@
       case Compiler.dartdevk:
         return Runtime.chrome;
       case Compiler.dart2analyzer:
-      case Compiler.compareAnalyzerCfe:
         return Runtime.none;
       case Compiler.appJitk:
       case Compiler.dartk:
@@ -750,7 +746,6 @@
   Mode get defaultMode {
     switch (this) {
       case Compiler.dart2analyzer:
-      case Compiler.compareAnalyzerCfe:
       case Compiler.dart2js:
       case Compiler.dart2wasm:
       case Compiler.dartdevc:
diff --git a/pkg/telemetry/analysis_options.yaml b/pkg/telemetry/analysis_options.yaml
index bb2ae44..d2e6c14 100644
--- a/pkg/telemetry/analysis_options.yaml
+++ b/pkg/telemetry/analysis_options.yaml
@@ -3,6 +3,7 @@
 analyzer:
   language:
     strict-casts: true
+
 linter:
   rules:
     - unawaited_futures
diff --git a/pkg/test_runner/analysis_options.yaml b/pkg/test_runner/analysis_options.yaml
index e6a5912..ff809b7 100644
--- a/pkg/test_runner/analysis_options.yaml
+++ b/pkg/test_runner/analysis_options.yaml
@@ -1,83 +1,27 @@
+include: package:lints/core.yaml
+
 analyzer:
   language:
     strict-casts: true
+
 linter:
   rules:
-    # TODO: Enable these once the existing violations have been fixed.
-#    - annotate_overrides
-#    - non_constant_identifier_names
-#    - only_throw_errors
-#    - prefer_interpolation_to_compose_strings
-#    - prefer_single_quotes
-    - avoid_bool_literals_in_conditional_expressions
-    - avoid_empty_else
-    - avoid_function_literals_in_foreach_calls
-    - avoid_init_to_null
-    - avoid_null_checks_in_equality_operators
-    - avoid_relative_lib_imports
-    - avoid_renaming_method_parameters
-    - avoid_return_types_on_setters
-    - avoid_returning_null
-    - avoid_returning_null_for_void
-    - avoid_shadowing_type_parameters
-    - avoid_single_cascade_in_expression_statements
-    - avoid_types_as_parameter_names
-    - avoid_unused_constructor_parameters
-    - await_only_futures
-    - camel_case_types
-    - cancel_subscriptions
-    - comment_references
-    - constant_identifier_names
-    - control_flow_in_finally
-    - curly_braces_in_flow_control_structures
-    - directives_ordering
-    - empty_catches
-    - empty_constructor_bodies
-    - empty_statements
-    - file_names
-    - hash_and_equals
-    - implementation_imports
-    - invariant_booleans
-    - iterable_contains_unrelated_type
-    - library_names
-    - library_prefixes
-    - list_remove_unrelated_type
-    - no_duplicate_case_values
-    - null_closures
-    - omit_local_variable_types
-    - overridden_fields
-    - package_api_docs
-    - package_names
-    - package_prefixed_library_names
-    - prefer_adjacent_string_concatenation
-    - prefer_collection_literals
-    - prefer_conditional_assignment
-    - prefer_const_constructors
-    - prefer_contains
-    - prefer_equal_for_default_values
-    - prefer_final_fields
-    - prefer_generic_function_type_aliases
-    - prefer_initializing_formals
-    - prefer_is_empty
-    - prefer_is_not_empty
-    - prefer_null_aware_operators
-    - prefer_typing_uninitialized_variables
-    - recursive_getters
-    - slash_for_doc_comments
-    - throw_in_finally
-    - type_init_formals
-    - unnecessary_brace_in_string_interps
-    - unnecessary_const
-    - unnecessary_getters_setters
-    - unnecessary_lambdas
-    - unnecessary_new
-    - unnecessary_null_aware_assignments
-    - unnecessary_null_in_if_null_operators
-    - unnecessary_parenthesis
-    - unnecessary_statements
-    - unnecessary_this
-    - unnecessary_overrides
-    - unrelated_type_equality_checks
-    - use_rethrow_when_possible
-    - valid_regexps
-    - void_checks
+    avoid_bool_literals_in_conditional_expressions: true
+    avoid_returning_null: true
+    avoid_unused_constructor_parameters: true
+    cancel_subscriptions: true
+    comment_references: true
+    directives_ordering: true
+    invariant_booleans: true
+    omit_local_variable_types: true
+    package_api_docs: true
+    prefer_const_constructors: true
+    throw_in_finally: true
+    unnecessary_lambdas: true
+    unnecessary_parenthesis: true
+    unnecessary_statements: true
+
+    # Disabled due to existing violations.
+    non_constant_identifier_names: false
+    only_throw_errors: false
+    prefer_single_quotes: false
diff --git a/pkg/test_runner/lib/src/compiler_configuration.dart b/pkg/test_runner/lib/src/compiler_configuration.dart
index 85a8fc1..d59e07e 100644
--- a/pkg/test_runner/lib/src/compiler_configuration.dart
+++ b/pkg/test_runner/lib/src/compiler_configuration.dart
@@ -80,9 +80,6 @@
       case Compiler.dart2analyzer:
         return AnalyzerCompilerConfiguration(configuration);
 
-      case Compiler.compareAnalyzerCfe:
-        return CompareAnalyzerCfeCompilerConfiguration(configuration);
-
       case Compiler.dart2js:
         return Dart2jsCompilerConfiguration(configuration);
 
@@ -1249,41 +1246,6 @@
   }
 }
 
-/// Configuration for compareAnalyzerCfe.
-class CompareAnalyzerCfeCompilerConfiguration extends CompilerConfiguration {
-  CompareAnalyzerCfeCompilerConfiguration(TestConfiguration configuration)
-      : super._subclass(configuration);
-
-  int get timeoutMultiplier => 4;
-
-  String computeCompilerPath() {
-    if (_useSdk) {
-      throw "--use-sdk cannot be used with compiler compare_analyzer_cfe";
-    }
-    return 'pkg/analyzer_fe_comparison/bin/'
-        'compare_sdk_tests$shellScriptExtension';
-  }
-
-  CommandArtifact computeCompilationArtifact(String tempDir,
-      List<String> arguments, Map<String, String> environmentOverrides) {
-    // Since this is not a real compilation, no artifacts are produced.
-    return CommandArtifact([
-      CompareAnalyzerCfeCommand(
-          computeCompilerPath(), arguments.toList(), environmentOverrides)
-    ], arguments.singleWhere((argument) => argument.endsWith('.dart')),
-        'application/vnd.dart');
-  }
-
-  List<String> computeRuntimeArguments(
-      RuntimeConfiguration runtimeConfiguration,
-      TestFile testFile,
-      List<String> vmOptions,
-      List<String> originalArguments,
-      CommandArtifact? artifact) {
-    return [];
-  }
-}
-
 /// Configuration for spec_parser.
 class SpecParserCompilerConfiguration extends CompilerConfiguration {
   SpecParserCompilerConfiguration(TestConfiguration configuration)
diff --git a/pkg/test_runner/pubspec.yaml b/pkg/test_runner/pubspec.yaml
index 119ef05..c7b9622 100644
--- a/pkg/test_runner/pubspec.yaml
+++ b/pkg/test_runner/pubspec.yaml
@@ -26,3 +26,4 @@
   analyzer: any
   expect: any
   glob: any
+  lints: any
diff --git a/pkg/vm/analysis_options.yaml b/pkg/vm/analysis_options.yaml
index 4aaf9c5..6d3c447 100644
--- a/pkg/vm/analysis_options.yaml
+++ b/pkg/vm/analysis_options.yaml
@@ -2,6 +2,4 @@
 # 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.
 
-analyzer:
-  exclude:
-    - tool/**
+include: package:lints/core.yaml
diff --git a/pkg/vm/bin/kernel_service.dart b/pkg/vm/bin/kernel_service.dart
index ef6b991..f619484 100644
--- a/pkg/vm/bin/kernel_service.dart
+++ b/pkg/vm/bin/kernel_service.dart
@@ -511,7 +511,7 @@
 Future _processExpressionCompilationRequest(request) async {
   final SendPort port = request[1];
   final int isolateGroupId = request[2];
-  final dynamic dart_platform_kernel = request[3];
+  final dynamic dartPlatformKernel = request[3];
   final String expression = request[4];
   final List<String> definitions = request[5].cast<String>();
   final List<String> definitionTypes = request[6].cast<String>();
@@ -576,8 +576,8 @@
       }
       if (!foundDartCore) {
         List<int> platformKernel;
-        if (dart_platform_kernel is List<int>) {
-          platformKernel = dart_platform_kernel;
+        if (dartPlatformKernel is List<int>) {
+          platformKernel = dartPlatformKernel;
         } else {
           final Uri platformUri = computePlatformBinariesLocation()
               .resolve('vm_platform_strong.dill');
@@ -983,7 +983,7 @@
     String? multirootFilepaths, String? multirootScheme) {
   FileSystem fileSystem = new HttpAwareFileSystem(StandardFileSystem.instance);
 
-  if (!sourceFiles.isEmpty || platformKernel != null) {
+  if (sourceFiles.isNotEmpty || platformKernel != null) {
     MemoryFileSystem memoryFileSystem =
         new MemoryFileSystem(Uri.parse('file:///'));
     for (int i = 0; i < sourceFiles.length ~/ 2; i++) {
@@ -1143,17 +1143,17 @@
 }
 
 class _CompilationNullSafety extends CompilationResult {
-  final bool _null_safety;
+  final bool _nullSafety;
 
-  _CompilationNullSafety(this._null_safety) : super._() {}
+  _CompilationNullSafety(this._nullSafety) : super._() {}
 
   @override
   Status get status => Status.ok;
 
   @override
-  get payload => _null_safety;
+  get payload => _nullSafety;
 
-  String toString() => "_CompilationNullSafety($_null_safety)";
+  String toString() => "_CompilationNullSafety($_nullSafety)";
 }
 
 abstract class _CompilationFail extends CompilationResult {
@@ -1198,9 +1198,13 @@
 }
 
 Future<T> runWithPrintToStderr<T>(Future<T> f()) {
-  return runZoned(() => new Future<T>(f),
-      zoneSpecification: new ZoneSpecification(
-          print: (_1, _2, _3, String line) => stderr.writeln(line)));
+  return runZoned(
+    () => new Future<T>(f),
+    zoneSpecification: new ZoneSpecification(
+      // ignore: non_constant_identifier_names
+      print: (_1, _2, _3, String line) => stderr.writeln(line),
+    ),
+  );
 }
 
 int _debugDumpCounter = 0;
diff --git a/pkg/vm/lib/target/vm.dart b/pkg/vm/lib/target/vm.dart
index a74b718..b706bd5 100644
--- a/pkg/vm/lib/target/vm.dart
+++ b/pkg/vm/lib/target/vm.dart
@@ -248,7 +248,7 @@
                       arg.value)
                     ..fileOffset = arg.fileOffset;
                 })), keyType: coreTypes.symbolLegacyRawType)
-                  ..isConst = (arguments.named.length == 0)
+                  ..isConst = (arguments.named.isEmpty)
                   ..fileOffset = arguments.fileOffset
               ], types: [
                 coreTypes.symbolLegacyRawType,
@@ -392,7 +392,7 @@
     // handling, the current approach seems sufficient.
 
     // The 0-element list must be exactly 'const[]'.
-    if (elements.length == 0) {
+    if (elements.isEmpty) {
       return new ListLiteral([], typeArgument: typeArgument)..isConst = true;
     }
 
diff --git a/pkg/vm/lib/testing/il_matchers.dart b/pkg/vm/lib/testing/il_matchers.dart
index 1c2f883..8aec633 100644
--- a/pkg/vm/lib/testing/il_matchers.dart
+++ b/pkg/vm/lib/testing/il_matchers.dart
@@ -394,11 +394,13 @@
 
   final _AnyMatcher any = const _AnyMatcher();
 
+  // ignore: non_constant_identifier_names
   InstructionMatcher Goto(String dest) =>
       InstructionMatcher._(op: 'Goto', matchers: {
         's': _ListMatcher([_blockRef(dest)])
       });
 
+  // ignore: non_constant_identifier_names
   InstructionMatcher Branch(InstructionMatcher compare,
           {String? ifTrue, String? ifFalse}) =>
       InstructionMatcher._(op: 'Branch', matchers: {
diff --git a/pkg/vm/lib/transformations/async.dart b/pkg/vm/lib/transformations/async.dart
index ecdec2e..6a6628b 100644
--- a/pkg/vm/lib/transformations/async.dart
+++ b/pkg/vm/lib/transformations/async.dart
@@ -433,7 +433,8 @@
         new EqualsCall(expr.right, new BoolLiteral(true),
             interfaceTarget: objectEquals,
             functionType: objectEquals.getterType as FunctionType))));
-    var then, otherwise;
+    Statement then;
+    Statement? otherwise;
     if (expr.operatorEnum == LogicalExpressionOperator.AND) {
       then = rightBody;
       otherwise = null;
diff --git a/pkg/vm/lib/transformations/continuation.dart b/pkg/vm/lib/transformations/continuation.dart
index 9241252..d23954f 100644
--- a/pkg/vm/lib/transformations/continuation.dart
+++ b/pkg/vm/lib/transformations/continuation.dart
@@ -399,7 +399,7 @@
   static DartType elementTypeFrom(Class containerClass, DartType type) {
     if (type is InterfaceType) {
       if (type.classNode == containerClass) {
-        if (type.typeArguments.length == 0) {
+        if (type.typeArguments.isEmpty) {
           return const DynamicType();
         } else if (type.typeArguments.length == 1) {
           return type.typeArguments[0];
diff --git a/pkg/vm/lib/transformations/ffi/common.dart b/pkg/vm/lib/transformations/ffi/common.dart
index 3b3a837..c99635a 100644
--- a/pkg/vm/lib/transformations/ffi/common.dart
+++ b/pkg/vm/lib/transformations/ffi/common.dart
@@ -585,7 +585,7 @@
     if (fun.positionalParameters.length != fun.requiredParameterCount) {
       return null;
     }
-    if (fun.typeParameters.length != 0) return null;
+    if (fun.typeParameters.isNotEmpty) return null;
 
     final DartType? returnType = convertNativeTypeToDartType(fun.returnType,
         allowCompounds: true, allowHandle: true);
diff --git a/pkg/vm/lib/transformations/ffi/definitions.dart b/pkg/vm/lib/transformations/ffi/definitions.dart
index e859a61..50b4ca9 100644
--- a/pkg/vm/lib/transformations/ffi/definitions.dart
+++ b/pkg/vm/lib/transformations/ffi/definitions.dart
@@ -260,15 +260,15 @@
       final nativeTypeCfe = NativeTypeCfe(
               this, node.getThisType(coreTypes, Nullability.nonNullable))
           as AbiSpecificNativeTypeCfe;
-      if (nativeTypeCfe.abiSpecificTypes.length == 0) {
+      if (nativeTypeCfe.abiSpecificTypes.isEmpty) {
         // Annotation missing, multiple annotations, or invalid mapping.
         diagnosticReporter.report(messageFfiAbiSpecificIntegerMappingInvalid,
             node.fileOffset, node.name.length, node.location!.file);
       }
-      if (node.typeParameters.length != 0 ||
-          node.procedures.where((Procedure e) => !e.isSynthetic).length != 0 ||
-          node.fields.length != 0 ||
-          node.redirectingFactories.length != 0 ||
+      if (node.typeParameters.isNotEmpty ||
+          node.procedures.where((Procedure e) => !e.isSynthetic).isNotEmpty ||
+          node.fields.isNotEmpty ||
+          node.redirectingFactories.isNotEmpty ||
           node.constructors.length != 1 ||
           !node.constructors.single.isConst) {
         // We want exactly one constructor, no other members and no type arguments.
@@ -306,7 +306,7 @@
 
   /// Returns packing if any.
   int? _checkCompoundClass(Class node) {
-    if (node.typeParameters.length > 0) {
+    if (node.typeParameters.isNotEmpty) {
       diagnosticReporter.report(
           templateFfiStructGeneric.withArguments(
               node.superclass!.name, node.name),
@@ -430,7 +430,7 @@
       } else if (isPointerType(type) ||
           isCompoundSubtype(type) ||
           isArrayType(type)) {
-        if (nativeTypeAnnos.length != 0) {
+        if (nativeTypeAnnos.isNotEmpty) {
           diagnosticReporter.report(
               templateFfiFieldNoAnnotation.withArguments(f.name.text),
               f.fileOffset,
@@ -632,7 +632,7 @@
 
     final packingAnnotations = _getPackedAnnotations(node);
     final packing =
-        (!packingAnnotations.isEmpty) ? packingAnnotations.first : null;
+        (packingAnnotations.isNotEmpty) ? packingAnnotations.first : null;
 
     final compoundType = () {
       if (types.whereType<InvalidNativeTypeCfe>().isNotEmpty) {
diff --git a/pkg/vm/lib/transformations/ffi/native.dart b/pkg/vm/lib/transformations/ffi/native.dart
index fedd286..bc63d3a 100644
--- a/pkg/vm/lib/transformations/ffi/native.dart
+++ b/pkg/vm/lib/transformations/ffi/native.dart
@@ -346,7 +346,7 @@
   // annotation matches.
   bool _verifySignatures(Procedure node, FunctionType dartFunctionType,
       FunctionType ffiFunctionType, int annotationOffset) {
-    if (ffiFunctionType.namedParameters.length > 0) {
+    if (ffiFunctionType.namedParameters.isNotEmpty) {
       diagnosticReporter.report(
           templateCantHaveNamedParameters.withArguments('FfiNative'),
           annotationOffset,
diff --git a/pkg/vm/lib/transformations/ffi/native_type_cfe.dart b/pkg/vm/lib/transformations/ffi/native_type_cfe.dart
index 4a19480..871313c 100644
--- a/pkg/vm/lib/transformations/ffi/native_type_cfe.dart
+++ b/pkg/vm/lib/transformations/ffi/native_type_cfe.dart
@@ -38,7 +38,7 @@
       if (arrayDimensions == null) {
         throw "Must have array dimensions for ArrayType.";
       }
-      if (arrayDimensions.length == 0) {
+      if (arrayDimensions.isEmpty) {
         throw "Must have a size for this array dimension.";
       }
       final elementType = transformer.arraySingleElementType(dartType);
diff --git a/pkg/vm/lib/transformations/specializer/list_factory_specializer.dart b/pkg/vm/lib/transformations/specializer/list_factory_specializer.dart
index 1a3f10f..c088b62 100644
--- a/pkg/vm/lib/transformations/specializer/list_factory_specializer.dart
+++ b/pkg/vm/lib/transformations/specializer/list_factory_specializer.dart
@@ -94,7 +94,7 @@
 
   TreeNode transformListEmptyFactory(StaticInvocation node) {
     final args = node.arguments;
-    assert(args.positional.length == 0);
+    assert(args.positional.isEmpty);
     final bool? growable =
         _getConstantOptionalArgument(args, 'growable', false);
     if (growable == null) {
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index bae97d9..6ccde60 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -1865,7 +1865,7 @@
       node.members.length = writeIndex;
 
       // We only retain the extension if at least one member is retained.
-      assert(node.members.length > 0);
+      assert(node.members.isNotEmpty);
       return node;
     }
     return removalSentinel!;
diff --git a/pkg/vm/lib/transformations/type_flow/utils.dart b/pkg/vm/lib/transformations/type_flow/utils.dart
index 42f54c0..ad6ce30 100644
--- a/pkg/vm/lib/transformations/type_flow/utils.dart
+++ b/pkg/vm/lib/transformations/type_flow/utils.dart
@@ -319,7 +319,7 @@
 // Returns the smallest index 'i' such that 'list.skip(i)' is a prefix of
 // 'sublist'.
 int findOverlap(List list, List sublist) {
-  for (int i = 0; i < list.length; ++i)
+  for (int i = 0; i < list.length; ++i) {
     outer:
     {
       for (int j = 0; j < sublist.length && i + j < list.length; ++j) {
@@ -327,6 +327,7 @@
       }
       return i;
     }
+  }
   return list.length;
 }
 
diff --git a/pkg/vm/pubspec.yaml b/pkg/vm/pubspec.yaml
index 009cfeba..52c44fb 100644
--- a/pkg/vm/pubspec.yaml
+++ b/pkg/vm/pubspec.yaml
@@ -20,6 +20,7 @@
 dev_dependencies:
   expect: any
   json_rpc_2: any
+  lints: any
   path: any
   test: any
   web_socket_channel: any
diff --git a/pkg/vm/test/incremental_compiler_test.dart b/pkg/vm/test/incremental_compiler_test.dart
index 8bfa4e40..83974c9 100644
--- a/pkg/vm/test/incremental_compiler_test.dart
+++ b/pkg/vm/test/incremental_compiler_test.dart
@@ -250,9 +250,13 @@
               hits.add(pos);
             }
           }
-          for (int pos in coverage["misses"]) positions.add(pos);
+          for (int pos in coverage["misses"]) {
+            positions.add(pos);
+          }
           if (range["possibleBreakpoints"] != null) {
-            for (int pos in range["possibleBreakpoints"]) positions.add(pos);
+            for (int pos in range["possibleBreakpoints"]) {
+              positions.add(pos);
+            }
           }
           Map script = scriptIndexToScript[range["scriptIndex"]]!;
           Set<int> knownPositions = new Set<int>();
diff --git a/pkg/vm/test/transformations/ffi_test.dart b/pkg/vm/test/transformations/ffi_test.dart
index 8d4f639..3f6dd75 100644
--- a/pkg/vm/test/transformations/ffi_test.dart
+++ b/pkg/vm/test/transformations/ffi_test.dart
@@ -49,9 +49,9 @@
 }
 
 void main(List<String> args) {
-  assert(args.length == 0 || args.length == 1);
+  assert(args.isEmpty || args.length == 1);
   String? filter;
-  if (args.length > 0) {
+  if (args.isNotEmpty) {
     filter = args.first;
   }
 
diff --git a/pkg/vm/test/transformations/type_flow/transformer_test.dart b/pkg/vm/test/transformations/type_flow/transformer_test.dart
index 0dc138f..2b80881 100644
--- a/pkg/vm/test/transformations/type_flow/transformer_test.dart
+++ b/pkg/vm/test/transformations/type_flow/transformer_test.dart
@@ -68,7 +68,7 @@
 }
 
 String? argsTestName(List<String> args) {
-  if (args.length > 0) {
+  if (args.isNotEmpty) {
     return args.last;
   }
   return null;
diff --git a/pkg/wasm_builder/analysis_options.yaml b/pkg/wasm_builder/analysis_options.yaml
new file mode 100644
index 0000000..c36c2c5
--- /dev/null
+++ b/pkg/wasm_builder/analysis_options.yaml
@@ -0,0 +1 @@
+include: package:lints/core.yaml
diff --git a/pkg/wasm_builder/lib/src/instructions.dart b/pkg/wasm_builder/lib/src/instructions.dart
index f91b26f..beb2411 100644
--- a/pkg/wasm_builder/lib/src/instructions.dart
+++ b/pkg/wasm_builder/lib/src/instructions.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// ignore_for_file: non_constant_identifier_names
+
 import 'module.dart';
 import 'serialize.dart';
 import 'types.dart';
diff --git a/pkg/wasm_builder/lib/src/module.dart b/pkg/wasm_builder/lib/src/module.dart
index 592b304..3c0a55a 100644
--- a/pkg/wasm_builder/lib/src/module.dart
+++ b/pkg/wasm_builder/lib/src/module.dart
@@ -24,7 +24,7 @@
   final List<DataSegment> dataSegments = [];
   final List<Global> globals = [];
   final List<Export> exports = [];
-  BaseFunction? startFunction = null;
+  BaseFunction? startFunction;
 
   bool anyFunctionsDefined = false;
   bool anyTablesDefined = false;
@@ -277,7 +277,7 @@
   }
 
   /// Serialize the module to its binary representation.
-  Uint8List encode({bool emitNameSection: true}) {
+  Uint8List encode({bool emitNameSection = true}) {
     // Wasm module preamble: magic number, version 1.
     writeBytes(const [0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00]);
     TypeSection(this).serialize(this);
@@ -918,7 +918,7 @@
     // each stretch as an element.
     List<_Element> elements = [];
     for (DefinedTable table in module.definedTables) {
-      _Element? current = null;
+      _Element? current;
       for (int i = 0; i < table.elements.length; i++) {
         BaseFunction? function = table.elements[i];
         if (function != null) {
diff --git a/pkg/wasm_builder/lib/src/serialize.dart b/pkg/wasm_builder/lib/src/serialize.dart
index 007b6e1..3e6047a 100644
--- a/pkg/wasm_builder/lib/src/serialize.dart
+++ b/pkg/wasm_builder/lib/src/serialize.dart
@@ -40,7 +40,9 @@
     // Ensure space for at least `size` additional bytes.
     if (_data.length < _index + size) {
       int newLength = _data.length * 2;
-      while (newLength < _index + size) newLength *= 2;
+      while (newLength < _index + size) {
+        newLength *= 2;
+      }
       _data = Uint8List(newLength)..setRange(0, _data.length, _data);
     }
   }
@@ -107,7 +109,9 @@
 
   void writeList(List<Serializable> objects) {
     writeUnsigned(objects.length);
-    for (int i = 0; i < objects.length; i++) write(objects[i]);
+    for (int i = 0; i < objects.length; i++) {
+      write(objects[i]);
+    }
   }
 
   void writeData(Serializer chunk, [List<int>? watchPoints]) {
diff --git a/pkg/wasm_builder/lib/src/types.dart b/pkg/wasm_builder/lib/src/types.dart
index 8ed1f68..d867dc6 100644
--- a/pkg/wasm_builder/lib/src/types.dart
+++ b/pkg/wasm_builder/lib/src/types.dart
@@ -230,7 +230,7 @@
   @override
   String toString() {
     if (nullable == heapType.nullableByDefault) return "${heapType}ref";
-    return "ref${nullable ? " null " : " "}${heapType}";
+    return "ref${nullable ? " null " : " "}$heapType";
   }
 
   @override
@@ -553,10 +553,10 @@
   FieldType(super.type, {super.mutable = true});
 
   /// The `i8` storage type as a field type.
-  FieldType.i8({bool mutable: true}) : this(PackedType.i8, mutable: mutable);
+  FieldType.i8({bool mutable = true}) : this(PackedType.i8, mutable: mutable);
 
   /// The `i16` storage type as a field type.
-  FieldType.i16({bool mutable: true}) : this(PackedType.i16, mutable: mutable);
+  FieldType.i16({bool mutable = true}) : this(PackedType.i16, mutable: mutable);
 
   bool isSubtypeOf(FieldType other) {
     if (mutable != other.mutable) return false;
diff --git a/pkg/wasm_builder/pubspec.yaml b/pkg/wasm_builder/pubspec.yaml
index 3d59b5a..05ece99 100644
--- a/pkg/wasm_builder/pubspec.yaml
+++ b/pkg/wasm_builder/pubspec.yaml
@@ -5,3 +5,7 @@
 
 environment:
   sdk: '>=2.17.0'
+
+# Use 'any' constraints here; we get our versions from the DEPS file.
+dev_dependency:
+  lints: any
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.cc b/runtime/vm/compiler/assembler/assembler_arm64.cc
index f904733..64576491 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64.cc
@@ -482,13 +482,6 @@
     return false;
   }
 
-  // TODO(zra, kmillikin): Also load other large immediates from the object
-  // pool
-  if (target::IsSmi(object)) {
-    // If the raw smi does not fit into a 32-bit signed int, then we'll keep
-    // the raw value in the object pool.
-    return !Utils::IsInt(32, target::ToRawSmi(object));
-  }
   ASSERT(IsNotTemporaryScopedHandle(object));
   ASSERT(IsInOldSpace(object));
   return true;
@@ -535,18 +528,18 @@
       ldr(dst, Address(THR, offset));
       return;
     }
+    if (target::IsSmi(object)) {
+      LoadImmediate(dst, target::ToRawSmi(object));
+      return;
+    }
   }
-  if (CanLoadFromObjectPool(object)) {
-    const intptr_t index =
-        is_unique ? object_pool_builder().AddObject(
-                        object, ObjectPoolBuilderEntry::kPatchable)
-                  : object_pool_builder().FindObject(
-                        object, ObjectPoolBuilderEntry::kNotPatchable);
-    LoadWordFromPoolIndex(dst, index);
-    return;
-  }
-  ASSERT(target::IsSmi(object));
-  LoadImmediate(dst, target::ToRawSmi(object));
+  RELEASE_ASSERT(CanLoadFromObjectPool(object));
+  const intptr_t index =
+      is_unique ? object_pool_builder().AddObject(
+                      object, ObjectPoolBuilderEntry::kPatchable)
+                : object_pool_builder().FindObject(
+                      object, ObjectPoolBuilderEntry::kNotPatchable);
+  LoadWordFromPoolIndex(dst, index);
 }
 
 void Assembler::LoadObject(Register dst, const Object& object) {
diff --git a/runtime/vm/compiler/assembler/assembler_riscv.cc b/runtime/vm/compiler/assembler/assembler_riscv.cc
index 862bf92..10beeac 100644
--- a/runtime/vm/compiler/assembler/assembler_riscv.cc
+++ b/runtime/vm/compiler/assembler/assembler_riscv.cc
@@ -4336,28 +4336,17 @@
       return;
     }
     if (target::IsSmi(object)) {
-      intx_t raw_smi = target::ToRawSmi(object);
-      if (IsITypeImm(raw_smi)) {
-        li(dst, raw_smi);
-        return;
-      }
-      if (IsUTypeImm(raw_smi)) {
-        lui(dst, raw_smi);
-        return;
-      }
+      LoadImmediate(dst, target::ToRawSmi(object));
+      return;
     }
   }
-  if (CanLoadFromObjectPool(object)) {
-    const intptr_t index =
-        is_unique ? object_pool_builder().AddObject(
-                        object, ObjectPoolBuilderEntry::kPatchable)
-                  : object_pool_builder().FindObject(
-                        object, ObjectPoolBuilderEntry::kNotPatchable);
-    LoadWordFromPoolIndex(dst, index);
-    return;
-  }
-  ASSERT(target::IsSmi(object));
-  LoadImmediate(dst, target::ToRawSmi(object));
+  RELEASE_ASSERT(CanLoadFromObjectPool(object));
+  const intptr_t index =
+      is_unique ? object_pool_builder().AddObject(
+                      object, ObjectPoolBuilderEntry::kPatchable)
+                : object_pool_builder().FindObject(
+                      object, ObjectPoolBuilderEntry::kNotPatchable);
+  LoadWordFromPoolIndex(dst, index);
 }
 
 void Assembler::AddImmediateBranchOverflow(Register rd,
diff --git a/runtime/vm/compiler/assembler/assembler_x64.cc b/runtime/vm/compiler/assembler/assembler_x64.cc
index 8cd8bf6..f2a874a 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.cc
+++ b/runtime/vm/compiler/assembler/assembler_x64.cc
@@ -1267,11 +1267,6 @@
     return false;
   }
 
-  if (target::IsSmi(object)) {
-    // If the raw smi does not fit into a 32-bit signed int, then we'll keep
-    // the raw value in the object pool.
-    return !Utils::IsInt(32, target::ToRawSmi(object));
-  }
   ASSERT(IsNotTemporaryScopedHandle(object));
   ASSERT(IsInOldSpace(object));
   return true;
@@ -1311,18 +1306,18 @@
       movq(dst, Address(THR, offset));
       return;
     }
+    if (target::IsSmi(object)) {
+      LoadImmediate(dst, Immediate(target::ToRawSmi(object)));
+      return;
+    }
   }
-  if (CanLoadFromObjectPool(object)) {
-    const intptr_t index =
-        is_unique ? object_pool_builder().AddObject(
-                        object, ObjectPoolBuilderEntry::kPatchable)
-                  : object_pool_builder().FindObject(
-                        object, ObjectPoolBuilderEntry::kNotPatchable);
-    LoadWordFromPoolIndex(dst, index);
-    return;
-  }
-  ASSERT(target::IsSmi(object));
-  LoadImmediate(dst, Immediate(target::ToRawSmi(object)));
+  RELEASE_ASSERT(CanLoadFromObjectPool(object));
+  const intptr_t index =
+      is_unique ? object_pool_builder().AddObject(
+                      object, ObjectPoolBuilderEntry::kPatchable)
+                : object_pool_builder().FindObject(
+                      object, ObjectPoolBuilderEntry::kNotPatchable);
+  LoadWordFromPoolIndex(dst, index);
 }
 
 void Assembler::LoadObject(Register dst, const Object& object) {
@@ -1340,12 +1335,11 @@
   if (target::CanLoadFromThread(object, &offset_from_thread)) {
     movq(TMP, Address(THR, offset_from_thread));
     movq(dst, TMP);
-  } else if (CanLoadFromObjectPool(object)) {
+  } else if (target::IsSmi(object)) {
+    MoveImmediate(dst, Immediate(target::ToRawSmi(object)));
+  } else {
     LoadObject(TMP, object);
     movq(dst, TMP);
-  } else {
-    ASSERT(target::IsSmi(object));
-    MoveImmediate(dst, Immediate(target::ToRawSmi(object)));
   }
 }
 
@@ -1355,12 +1349,11 @@
   intptr_t offset_from_thread;
   if (target::CanLoadFromThread(object, &offset_from_thread)) {
     pushq(Address(THR, offset_from_thread));
-  } else if (CanLoadFromObjectPool(object)) {
+  } else if (target::IsSmi(object)) {
+    PushImmediate(Immediate(target::ToRawSmi(object)));
+  } else {
     LoadObject(TMP, object);
     pushq(TMP);
-  } else {
-    ASSERT(target::IsSmi(object));
-    PushImmediate(Immediate(target::ToRawSmi(object)));
   }
 }
 
@@ -1370,14 +1363,14 @@
   intptr_t offset_from_thread;
   if (target::CanLoadFromThread(object, &offset_from_thread)) {
     OBJ(cmp)(reg, Address(THR, offset_from_thread));
-  } else if (CanLoadFromObjectPool(object)) {
+  } else if (target::IsSmi(object)) {
+    CompareImmediate(reg, Immediate(target::ToRawSmi(object)), kObjectBytes);
+  } else {
+    RELEASE_ASSERT(CanLoadFromObjectPool(object));
     const intptr_t idx = object_pool_builder().FindObject(
         object, ObjectPoolBuilderEntry::kNotPatchable);
     const int32_t offset = target::ObjectPool::element_offset(idx);
     OBJ(cmp)(reg, Address(PP, offset - kHeapObjectTag));
-  } else {
-    ASSERT(target::IsSmi(object));
-    CompareImmediate(reg, Immediate(target::ToRawSmi(object)), kObjectBytes);
   }
 }
 
diff --git a/runtime/vm/compiler/runtime_api.cc b/runtime/vm/compiler/runtime_api.cc
index 2490c68..e666f59 100644
--- a/runtime/vm/compiler/runtime_api.cc
+++ b/runtime/vm/compiler/runtime_api.cc
@@ -924,7 +924,7 @@
 
 word ToRawSmi(const dart::Object& a) {
   RELEASE_ASSERT(IsSmi(a));
-  return static_cast<word>(static_cast<intptr_t>(a.ptr()));
+  return static_cast<compressed_word>(static_cast<intptr_t>(a.ptr()));
 }
 
 word ToRawSmi(intptr_t value) {
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index c2fc343..daba5cf 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -606,6 +606,7 @@
 // C++ ABI call registers.
 const RegList kAbiArgumentCpuRegs =
     (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3);
+const RegList kAbiVolatileCpuRegs = kAbiArgumentCpuRegs | (1 << IP) | (1 << LR);
 #if defined(DART_TARGET_OS_MACOS) || defined(DART_TARGET_OS_MACOS_IOS)
 const RegList kAbiPreservedCpuRegs =
     (1 << R4) | (1 << R5) | (1 << R6) | (1 << R8) | (1 << R10) | (1 << R11);
diff --git a/runtime/vm/constants_arm64.h b/runtime/vm/constants_arm64.h
index a6cfa13..92ca4a1 100644
--- a/runtime/vm/constants_arm64.h
+++ b/runtime/vm/constants_arm64.h
@@ -451,9 +451,9 @@
 // C++ ABI call registers.
 const RegList kAbiArgumentCpuRegs =
     R(R0) | R(R1) | R(R2) | R(R3) | R(R4) | R(R5) | R(R6) | R(R7);
-const RegList kAbiVolatileCpuRegs =
-    kAbiArgumentCpuRegs | R(R8) | R(R9) | R(R10) | R(R11) | R(R12) | R(R13) |
-    R(R14) | R(R15) | R(R16) | R(R17);
+const RegList kAbiVolatileCpuRegs = kAbiArgumentCpuRegs | R(R8) | R(R9) |
+                                    R(R10) | R(R11) | R(R12) | R(R13) | R(R14) |
+                                    R(R15) | R(R16) | R(R17) | R(LR);
 #if defined(DART_TARGET_OS_FUCHSIA)
 // We rely on R18 not being touched by Dart generated assembly or stubs at all.
 // We rely on that any calls into C++ also preserve R18.
diff --git a/runtime/vm/constants_riscv.h b/runtime/vm/constants_riscv.h
index 8ccc529..3fcfa47 100644
--- a/runtime/vm/constants_riscv.h
+++ b/runtime/vm/constants_riscv.h
@@ -449,8 +449,9 @@
 
 constexpr RegList kAbiArgumentCpuRegs =
     R(A0) | R(A1) | R(A2) | R(A3) | R(A4) | R(A5) | R(A6) | R(A7);
-constexpr RegList kAbiVolatileCpuRegs =
-    kAbiArgumentCpuRegs | R(T0) | R(T1) | R(T2) | R(T3) | R(T4) | R(T5) | R(T6);
+constexpr RegList kAbiVolatileCpuRegs = kAbiArgumentCpuRegs | R(T0) | R(T1) |
+                                        R(T2) | R(T3) | R(T4) | R(T5) | R(T6) |
+                                        R(RA);
 constexpr RegList kAbiPreservedCpuRegs = R(S1) | R(S2) | R(S3) | R(S4) | R(S5) |
                                          R(S6) | R(S7) | R(S8) | R(S9) |
                                          R(S10) | R(S11);
diff --git a/runtime/vm/globals.h b/runtime/vm/globals.h
index 559dc44..ac91f20 100644
--- a/runtime/vm/globals.h
+++ b/runtime/vm/globals.h
@@ -37,10 +37,12 @@
 static constexpr int kCompressedWordSize = kInt32Size;
 static constexpr int kCompressedWordSizeLog2 = kInt32SizeLog2;
 typedef uint32_t compressed_uword;
+typedef int32_t compressed_word;
 #else
 static constexpr int kCompressedWordSize = kWordSize;
 static constexpr int kCompressedWordSizeLog2 = kWordSizeLog2;
 typedef uintptr_t compressed_uword;
+typedef intptr_t compressed_word;
 #endif
 const int kMaxAddrSpaceMB = (kWordSize <= 4) ? 4096 : kMaxInt;
 
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index e6381eb..4a04149 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -1428,8 +1428,7 @@
           SimulatorRuntimeCall target =
               reinterpret_cast<SimulatorRuntimeCall>(external);
           target(arguments);
-          set_register(R0, icount_);  // Zap result register from void function.
-          set_register(R1, icount_);
+          ClobberVolatileRegisters();
         } else if (redirection->call_kind() == kLeafRuntimeCall) {
           ASSERT((0 <= redirection->argument_count()) &&
                  (redirection->argument_count() <= 5));
@@ -1441,8 +1440,8 @@
           SimulatorLeafRuntimeCall target =
               reinterpret_cast<SimulatorLeafRuntimeCall>(external);
           r0 = InvokeLeafRuntime(target, r0, r1, r2, r3, r4);
+          ClobberVolatileRegisters();
           set_register(R0, r0);       // Set returned result from function.
-          set_register(R1, icount_);  // Zap unused result register.
         } else if (redirection->call_kind() == kLeafFloatRuntimeCall) {
           ASSERT((0 <= redirection->argument_count()) &&
                  (redirection->argument_count() <= 2));
@@ -1454,6 +1453,7 @@
             double d0 = get_dregister(D0);
             double d1 = get_dregister(D1);
             d0 = InvokeFloatLeafRuntime(target, d0, d1);
+            ClobberVolatileRegisters();
             set_dregister(D0, d0);
           } else {
             // If we're not doing "hardfp", we must be doing "soft" or "softfp",
@@ -1467,6 +1467,7 @@
             double d0 = bit_cast<double, int64_t>(a0);
             double d1 = bit_cast<double, int64_t>(a1);
             d0 = InvokeFloatLeafRuntime(target, d0, d1);
+            ClobberVolatileRegisters();
             a0 = bit_cast<int64_t, double>(d0);
             r0 = Utils::Low32Bits(a0);
             r1 = Utils::High32Bits(a0);
@@ -1482,29 +1483,9 @@
           Dart_NativeFunction target_func =
               reinterpret_cast<Dart_NativeFunction>(get_register(R1));
           wrapper(arguments, target_func);
-          set_register(R0, icount_);  // Zap result register from void function.
-          set_register(R1, icount_);
+          ClobberVolatileRegisters();
         }
 
-        // Zap caller-saved registers, since the actual runtime call could have
-        // used them.
-        set_register(R2, icount_);
-        set_register(R3, icount_);
-        set_register(IP, icount_);
-        set_register(LR, icount_);
-          double zap_dvalue = static_cast<double>(icount_);
-          // Do not zap D0, as it may contain a float result.
-          for (int i = D1; i <= D7; i++) {
-            set_dregister(static_cast<DRegister>(i), zap_dvalue);
-          }
-// The above loop also zaps overlapping registers S2-S15.
-// Registers D8-D15 (overlapping with S16-S31) are preserved.
-#if defined(VFPv3_D32)
-          for (int i = D16; i <= D31; i++) {
-            set_dregister(static_cast<DRegister>(i), zap_dvalue);
-          }
-#endif
-
         // Return.
         set_pc(saved_lr);
       } else {
@@ -1525,6 +1506,29 @@
   }
 }
 
+void Simulator::ClobberVolatileRegisters() {
+  // Clear atomic reservation.
+  exclusive_access_addr_ = exclusive_access_value_ = 0;
+
+  for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) {
+    if ((kAbiVolatileCpuRegs & (1 << i)) != 0) {
+      registers_[i] = icount_;
+    }
+  }
+
+  double zap_dvalue = static_cast<double>(icount_);
+  for (int i = D0; i <= D7; i++) {
+    set_dregister(static_cast<DRegister>(i), zap_dvalue);
+  }
+  // The above loop also zaps overlapping registers S2-S15.
+  // Registers D8-D15 (overlapping with S16-S31) are preserved.
+#if defined(VFPv3_D32)
+  for (int i = D16; i <= D31; i++) {
+    set_dregister(static_cast<DRegister>(i), zap_dvalue);
+  }
+#endif
+}
+
 // Handle execution based on instruction types.
 
 // Instruction types 0 and 1 are both rolled into one function because they
diff --git a/runtime/vm/simulator_arm.h b/runtime/vm/simulator_arm.h
index 8851f6f..7e106a3 100644
--- a/runtime/vm/simulator_arm.h
+++ b/runtime/vm/simulator_arm.h
@@ -233,6 +233,8 @@
   // Executes ARM instructions until the PC reaches kEndSimulatingPC.
   void Execute();
 
+  void ClobberVolatileRegisters();
+
   // Returns true if tracing of executed instructions is enabled.
   bool IsTracingExecution() const;
 
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index fbb9df4..c512153 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -1711,9 +1711,7 @@
       SimulatorRuntimeCall target =
           reinterpret_cast<SimulatorRuntimeCall>(external);
       target(*arguments);
-      // Zap result register from void function.
-      set_register(instr, R0, icount_);
-      set_register(instr, R1, icount_);
+      ClobberVolatileRegisters();
     } else if (redirection->call_kind() == kLeafRuntimeCall) {
       ASSERT((0 <= redirection->argument_count()) &&
              (redirection->argument_count() <= 8));
@@ -1729,8 +1727,8 @@
       const int64_t r7 = get_register(R7);
       const int64_t res =
           InvokeLeafRuntime(target, r0, r1, r2, r3, r4, r5, r6, r7);
+      ClobberVolatileRegisters();
       set_register(instr, R0, res);      // Set returned result from function.
-      set_register(instr, R1, icount_);  // Zap unused result register.
     } else if (redirection->call_kind() == kLeafFloatRuntimeCall) {
       ASSERT((0 <= redirection->argument_count()) &&
              (redirection->argument_count() <= 8));
@@ -1746,6 +1744,7 @@
       const double d7 = bit_cast<double, int64_t>(get_vregisterd(V7, 0));
       const double res =
           InvokeFloatLeafRuntime(target, d0, d1, d2, d3, d4, d5, d6, d7);
+      ClobberVolatileRegisters();
       set_vregisterd(V0, 0, bit_cast<int64_t, double>(res));
       set_vregisterd(V0, 1, 0);
     } else {
@@ -1757,34 +1756,9 @@
       Dart_NativeFunction target =
           reinterpret_cast<Dart_NativeFunction>(get_register(R1));
       wrapper(arguments, target);
-      // Zap result register from void function.
-      set_register(instr, R0, icount_);
-      set_register(instr, R1, icount_);
+      ClobberVolatileRegisters();
     }
 
-    // Zap caller-saved registers, since the actual runtime call could have
-    // used them.
-    set_register(NULL, R2, icount_);
-    set_register(NULL, R3, icount_);
-    set_register(NULL, R4, icount_);
-    set_register(NULL, R5, icount_);
-    set_register(NULL, R6, icount_);
-    set_register(NULL, R7, icount_);
-    set_register(NULL, R8, icount_);
-    set_register(NULL, R9, icount_);
-    set_register(NULL, R10, icount_);
-    set_register(NULL, R11, icount_);
-    set_register(NULL, R12, icount_);
-    set_register(NULL, R13, icount_);
-    set_register(NULL, R14, icount_);
-    set_register(NULL, R15, icount_);
-    set_register(NULL, IP0, icount_);
-    set_register(NULL, IP1, icount_);
-    set_register(NULL, R18, icount_);
-    set_register(NULL, LR, icount_);
-
-    // TODO(zra): Zap caller-saved fpu registers.
-
     // Return.
     set_pc(saved_lr);
   } else {
@@ -1792,6 +1766,24 @@
   }
 }
 
+void Simulator::ClobberVolatileRegisters() {
+  // Clear atomic reservation.
+  exclusive_access_addr_ = exclusive_access_value_ = 0;
+
+  for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) {
+    if ((kAbiVolatileCpuRegs & (1 << i)) != 0) {
+      registers_[i] = icount_;
+    }
+  }
+
+  for (intptr_t i = 0; i < kNumberOfFpuRegisters; i++) {
+    if ((kAbiVolatileFpuRegs & (1 << i)) != 0) {
+      vregisters_[i].bits.i64[0] = icount_;
+      vregisters_[i].bits.i64[1] = icount_;
+    }
+  }
+}
+
 void Simulator::DecodeExceptionGen(Instr* instr) {
   if ((instr->Bits(0, 2) == 1) && (instr->Bits(2, 3) == 0) &&
       (instr->Bits(21, 3) == 0)) {
diff --git a/runtime/vm/simulator_arm64.h b/runtime/vm/simulator_arm64.h
index be20b2b..0c0e49c3 100644
--- a/runtime/vm/simulator_arm64.h
+++ b/runtime/vm/simulator_arm64.h
@@ -240,6 +240,8 @@
   // Executes ARM64 instructions until the PC reaches kEndSimulatingPC.
   void Execute();
 
+  void ClobberVolatileRegisters();
+
   // Returns true if tracing of executed instructions is enabled.
   bool IsTracingExecution() const;
 
diff --git a/tools/VERSION b/tools/VERSION
index 45baf3f..c5351ee 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 18
 PATCH 0
-PRERELEASE 263
+PRERELEASE 264
 PRERELEASE_PATCH 0
\ No newline at end of file