Version 2.18.0-248.0.dev

Merge commit '245f7a003cb206d53de11d312d65916da0dd790a' into 'dev'
diff --git a/DEPS b/DEPS
index 6ba6564..7fd03d1 100644
--- a/DEPS
+++ b/DEPS
@@ -109,7 +109,7 @@
   "dart_style_rev": "d7b73536a8079331c888b7da539b80e6825270ea", # manually rev'd
 
   "dartdoc_rev": "900432d8cb1e75c4f28c79d94c3036fd3b3ec21d",
-  "devtools_rev": "0aa619c42a68d6db4c94a7838121811aba8f5eb1",
+  "devtools_rev": "95d292626da26505b02417735f77e8922783b477",
   "ffi_rev": "18b2b549d55009ff594600b04705ff6161681e07",
   "file_rev": "0132eeedea2933513bf230513a766a8baeab0c4f",
   "fixnum_rev": "164712f6547cdfb2709b752188186baf31fd1730",
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index a00f66a..5f2d688 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -365,6 +365,8 @@
 
   R? visitAssignmentExpression(AssignmentExpression node);
 
+  R? visitAugmentationImportDirective(AugmentationImportDirective node);
+
   R? visitAwaitExpression(AwaitExpression node);
 
   R? visitBinaryExpression(BinaryExpression node);
@@ -617,6 +619,29 @@
   R? visitYieldStatement(YieldStatement node);
 }
 
+/// An augmentation import directive.
+///
+///    importDirective ::=
+///        [Annotation] 'import' 'augment' [StringLiteral] ';'
+///
+/// Clients may not extend, implement or mix-in this class.
+@experimental
+abstract class AugmentationImportDirective implements UriBasedDirective {
+  /// The token representing the 'augment' keyword.
+  Token get augmentKeyword;
+
+  /// Return the element associated with this directive, or `null` if the AST
+  /// structure has not been resolved.
+  @override
+  AugmentationImportElement? get element;
+
+  /// The token representing the 'import' keyword.
+  Token get importKeyword;
+
+  /// Return the semicolon terminating the directive.
+  Token get semicolon;
+}
+
 /// An await expression.
 ///
 ///    awaitExpression ::=
diff --git a/pkg/analyzer/lib/dart/ast/visitor.dart b/pkg/analyzer/lib/dart/ast/visitor.dart
index 92ab86a..2c43bc6 100644
--- a/pkg/analyzer/lib/dart/ast/visitor.dart
+++ b/pkg/analyzer/lib/dart/ast/visitor.dart
@@ -154,6 +154,10 @@
       visitExpression(node);
 
   @override
+  R? visitAugmentationImportDirective(AugmentationImportDirective node) =>
+      visitUriBasedDirective(node);
+
+  @override
   R? visitAwaitExpression(AwaitExpression node) => visitExpression(node);
 
   @override
@@ -698,6 +702,12 @@
   }
 
   @override
+  R? visitAugmentationImportDirective(AugmentationImportDirective node) {
+    node.visitChildren(this);
+    return null;
+  }
+
+  @override
   R? visitAwaitExpression(AwaitExpression node) {
     node.visitChildren(this);
     return null;
@@ -1481,6 +1491,9 @@
   R? visitAssignmentExpression(AssignmentExpression node) => null;
 
   @override
+  R? visitAugmentationImportDirective(AugmentationImportDirective node) => null;
+
+  @override
   R? visitAwaitExpression(AwaitExpression node) => null;
 
   @override
@@ -1897,6 +1910,10 @@
   R? visitAssignmentExpression(AssignmentExpression node) => _throw(node);
 
   @override
+  R? visitAugmentationImportDirective(AugmentationImportDirective node) =>
+      _throw(node);
+
+  @override
   R? visitAwaitExpression(AwaitExpression node) => _throw(node);
 
   @override
@@ -2363,6 +2380,14 @@
   }
 
   @override
+  T? visitAugmentationImportDirective(AugmentationImportDirective node) {
+    stopwatch.start();
+    T? result = _baseVisitor.visitAugmentationImportDirective(node);
+    stopwatch.stop();
+    return result;
+  }
+
+  @override
   T? visitAwaitExpression(AwaitExpression node) {
     stopwatch.start();
     T? result = _baseVisitor.visitAwaitExpression(node);
@@ -3401,6 +3426,10 @@
   R? visitAssignmentExpression(AssignmentExpression node) => visitNode(node);
 
   @override
+  R? visitAugmentationImportDirective(AugmentationImportDirective node) =>
+      visitNode(node);
+
+  @override
   R? visitAwaitExpression(AwaitExpression node) => visitNode(node);
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index bd9d063..cb70639 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -1330,7 +1330,6 @@
         var results = LibraryAnalyzer(
           analysisOptions as AnalysisOptionsImpl,
           declaredVariables,
-          sourceFactory,
           libraryContext.elementFactory.libraryOfUri2(library.file.uri),
           libraryContext.elementFactory.analysisSession.inheritanceManager,
           library,
@@ -1397,7 +1396,6 @@
       var unitResults = LibraryAnalyzer(
               analysisOptions as AnalysisOptionsImpl,
               declaredVariables,
-              sourceFactory,
               libraryContext.elementFactory.libraryOfUri2(library.file.uri),
               libraryContext.elementFactory.analysisSession.inheritanceManager,
               library,
@@ -1771,7 +1769,6 @@
     var analysisResult = LibraryAnalyzer(
       analysisOptions as AnalysisOptionsImpl,
       declaredVariables,
-      sourceFactory,
       libraryContext.elementFactory.libraryOfUri2(library.file.uri),
       libraryContext.elementFactory.analysisSession.inheritanceManager,
       library,
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index 9fd787f..6c7347f 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -131,12 +131,82 @@
   void dispose() {}
 }
 
-/// Information about a single `import` directive.
-class ExportDirectiveState extends DirectiveState {
+/// Meaning of a URI referenced in a directive.
+class DirectiveUri {
+  Source? get source => null;
+}
+
+/// [DirectiveUriWithUri] with URI that resolves to a [FileState].
+class DirectiveUriWithFile extends DirectiveUriWithUri {
+  final FileState file;
+
+  DirectiveUriWithFile({
+    required super.relativeUriStr,
+    required super.relativeUri,
+    required this.file,
+  });
+
+  @override
+  Source? get source => file.source;
+
+  @override
+  String toString() => '$file';
+}
+
+/// [DirectiveUriWithUri] with URI that resolves to a [InSummarySource].
+class DirectiveUriWithInSummarySource extends DirectiveUriWithUri {
+  @override
+  final InSummarySource source;
+
+  DirectiveUriWithInSummarySource({
+    required super.relativeUriStr,
+    required super.relativeUri,
+    required this.source,
+  });
+
+  @override
+  String toString() => '$source';
+}
+
+/// [DirectiveUri] for which we can get its relative URI string.
+class DirectiveUriWithString extends DirectiveUri {
+  final String relativeUriStr;
+
+  DirectiveUriWithString({
+    required this.relativeUriStr,
+  });
+
+  @override
+  String toString() => relativeUriStr;
+}
+
+/// [DirectiveUriWithString] that can be parsed into a relative URI.
+class DirectiveUriWithUri extends DirectiveUriWithString {
+  final Uri relativeUri;
+
+  DirectiveUriWithUri({
+    required super.relativeUriStr,
+    required this.relativeUri,
+  });
+
+  bool get isValid {
+    return relativeUri.path.isNotEmpty;
+  }
+
+  @override
+  String toString() => '$relativeUri';
+}
+
+/// Information about a single `export` directive.
+class ExportDirectiveState<U extends DirectiveUri> extends DirectiveState {
   final UnlinkedNamespaceDirective directive;
+  final U selectedUri;
+  final NamespaceDirectiveUris uris;
 
   ExportDirectiveState({
     required this.directive,
+    required this.selectedUri,
+    required this.uris,
   });
 
   /// If [exportedSource] corresponds to a library, returns it.
@@ -151,19 +221,21 @@
 }
 
 /// [ExportDirectiveWithUri] that has a valid URI that references a file.
-class ExportDirectiveWithFile extends ExportDirectiveWithUri {
+class ExportDirectiveWithFile
+    extends ExportDirectiveWithUri<DirectiveUriWithFile> {
   final LibraryOrAugmentationFileKind container;
-  final FileState exportedFile;
 
   ExportDirectiveWithFile({
     required this.container,
     required super.directive,
-    required this.exportedFile,
-    required super.selectedUriStr,
+    required super.selectedUri,
+    required super.uris,
   }) {
     exportedFile.referencingFiles.add(container.file);
   }
 
+  FileState get exportedFile => selectedUri.file;
+
   /// Returns [exportedFile] if it is a library.
   LibraryFileStateKind? get exportedLibrary {
     final kind = exportedFile.kind;
@@ -191,14 +263,12 @@
 }
 
 /// [ExportDirectiveWithUri] with a URI that resolves to [InSummarySource].
-class ExportDirectiveWithInSummarySource extends ExportDirectiveWithUri {
-  @override
-  final InSummarySource exportedSource;
-
+class ExportDirectiveWithInSummarySource
+    extends ExportDirectiveWithUri<DirectiveUriWithInSummarySource> {
   ExportDirectiveWithInSummarySource({
     required super.directive,
-    required this.exportedSource,
-    required super.selectedUriStr,
+    required super.selectedUri,
+    required super.uris,
   });
 
   @override
@@ -209,15 +279,18 @@
       return null;
     }
   }
+
+  @override
+  InSummarySource get exportedSource => selectedUri.source;
 }
 
-/// [ExportDirectiveState] that has a valid URI string.
-class ExportDirectiveWithUri extends ExportDirectiveState {
-  final String selectedUriStr;
-
+/// [ExportDirectiveState] that has a valid URI.
+class ExportDirectiveWithUri<U extends DirectiveUriWithUri>
+    extends ExportDirectiveState<U> {
   ExportDirectiveWithUri({
     required super.directive,
-    required this.selectedUriStr,
+    required super.selectedUri,
+    required super.uris,
   });
 }
 
@@ -593,6 +666,70 @@
     return '$uri = $path';
   }
 
+  DirectiveUri _buildDirectiveUri(String? relativeUriStr) {
+    if (relativeUriStr == null) {
+      return DirectiveUri();
+    }
+
+    final relativeUri = Uri.tryParse(relativeUriStr);
+    if (relativeUri == null) {
+      return DirectiveUriWithString(
+        relativeUriStr: relativeUriStr,
+      );
+    }
+
+    final absoluteUri = resolveRelativeUri(uri, relativeUri);
+    return _fsState.getFileForUri(absoluteUri).map(
+      (file) {
+        if (file != null) {
+          return DirectiveUriWithFile(
+            relativeUriStr: relativeUriStr,
+            relativeUri: relativeUri,
+            file: file,
+          );
+        } else {
+          return DirectiveUriWithUri(
+            relativeUriStr: relativeUriStr,
+            relativeUri: relativeUri,
+          );
+        }
+      },
+      (externalLibrary) {
+        return DirectiveUriWithInSummarySource(
+          relativeUriStr: relativeUriStr,
+          relativeUri: relativeUri,
+          source: externalLibrary.source,
+        );
+      },
+    );
+  }
+
+  /// TODO(scheglov) move to _fsState?
+  NamespaceDirectiveUris _buildNamespaceDirectiveUris(
+    UnlinkedNamespaceDirective directive,
+  ) {
+    final primaryUri = _buildDirectiveUri(directive.uri);
+
+    final configurationUris = <DirectiveUri>[];
+    DirectiveUri? selectedConfigurationUri;
+    for (final configuration in directive.configurations) {
+      final configurationUri = _buildDirectiveUri(configuration.uri);
+      configurationUris.add(configurationUri);
+      // Maybe select this URI.
+      final name = configuration.name;
+      final value = configuration.valueOrTrue;
+      if (_fsState._declaredVariables.get(name) == value) {
+        selectedConfigurationUri ??= configurationUri;
+      }
+    }
+
+    return NamespaceDirectiveUris(
+      primary: primaryUri,
+      configurations: configurationUris,
+      selected: selectedConfigurationUri ?? primaryUri,
+    );
+  }
+
   /// Return the [FileState] for the given [relativeUri], or `null` if the
   /// URI cannot be parsed, cannot correspond any file, etc.
   Either2<FileState?, ExternalLibrary> _fileForRelativeUri(
@@ -794,19 +931,17 @@
       if (directive is ExportDirective) {
         var builder = _serializeNamespaceDirective(directive);
         exports.add(builder);
+      } else if (directive is AugmentationImportDirectiveImpl) {
+        augmentations.add(
+          UnlinkedImportAugmentationDirective(
+            uri: directive.uri.stringValue,
+          ),
+        );
       } else if (directive is ImportDirectiveImpl) {
-        if (directive.augmentKeyword != null) {
-          augmentations.add(
-            UnlinkedImportAugmentationDirective(
-              uri: directive.uri.stringValue,
-            ),
-          );
-        } else {
-          var builder = _serializeNamespaceDirective(directive);
-          imports.add(builder);
-          if (builder.uri == 'dart:core') {
-            hasDartCoreImport = true;
-          }
+        var builder = _serializeNamespaceDirective(directive);
+        imports.add(builder);
+        if (builder.uri == 'dart:core') {
+          hasDartCoreImport = true;
         }
       } else if (directive is LibraryAugmentationDirective) {
         final uri = directive.uri;
@@ -1092,17 +1227,13 @@
 
     _uriToFile.remove(file.uri);
 
-    // The removed file does not reference other file anymore.
-    for (var referencedFile in file.directReferencedFiles) {
-      referencedFile.referencingFiles.remove(file);
-    }
+    // The removed file does not reference other files anymore.
+    file._kind?.dispose();
 
     // Recursively remove files that reference the removed file.
     for (var reference in file.referencingFiles.toList()) {
       changeFile(reference.path, removedFiles);
     }
-
-    file._kind?.dispose();
   }
 
   /// Collected files that transitively reference a file with the [path].
@@ -1454,11 +1585,14 @@
 }
 
 /// Information about a single `import augment` directive.
-class ImportAugmentationDirectiveState extends DirectiveState {
+class ImportAugmentationDirectiveState<U extends DirectiveUri>
+    extends DirectiveState {
   final UnlinkedImportAugmentationDirective directive;
+  final U uri;
 
   ImportAugmentationDirectiveState({
     required this.directive,
+    required this.uri,
   });
 
   /// Returns a [Source] that is referenced by this directive.
@@ -1469,14 +1603,13 @@
 
 /// [ImportAugmentationWithUri] that has a valid URI that references a file.
 class ImportAugmentationDirectiveWithFile
-    extends ImportAugmentationDirectiveState {
+    extends ImportAugmentationWithUri<DirectiveUriWithFile> {
   final LibraryOrAugmentationFileKind container;
-  final FileState importedFile;
 
   ImportAugmentationDirectiveWithFile({
     required this.container,
     required super.directive,
-    required this.importedFile,
+    required super.uri,
   }) {
     importedFile.referencingFiles.add(container.file);
   }
@@ -1491,6 +1624,8 @@
     return null;
   }
 
+  FileState get importedFile => uri.file;
+
   @override
   Source? get importedSource => importedFile.source;
 
@@ -1501,21 +1636,24 @@
 }
 
 /// [ImportAugmentationDirectiveState] that has a valid URI.
-class ImportAugmentationWithUri extends ImportAugmentationDirectiveState {
-  final String uriStr;
-
+class ImportAugmentationWithUri<U extends DirectiveUriWithUri>
+    extends ImportAugmentationDirectiveState<U> {
   ImportAugmentationWithUri({
     required super.directive,
-    required this.uriStr,
+    required super.uri,
   });
 }
 
 /// Information about a single `import` directive.
-class ImportDirectiveState extends DirectiveState {
+class ImportDirectiveState<U extends DirectiveUri> extends DirectiveState {
   final UnlinkedNamespaceDirective directive;
+  final U selectedUri;
+  final NamespaceDirectiveUris uris;
 
   ImportDirectiveState({
     required this.directive,
+    required this.selectedUri,
+    required this.uris,
   });
 
   /// If [importedSource] corresponds to a library, returns it.
@@ -1532,19 +1670,21 @@
 }
 
 /// [ImportDirectiveWithUri] that has a valid URI that references a file.
-class ImportDirectiveWithFile extends ImportDirectiveWithUri {
+class ImportDirectiveWithFile
+    extends ImportDirectiveWithUri<DirectiveUriWithFile> {
   final LibraryOrAugmentationFileKind container;
-  final FileState importedFile;
 
   ImportDirectiveWithFile({
     required this.container,
     required super.directive,
-    required this.importedFile,
-    required super.selectedUriStr,
+    required super.selectedUri,
+    required super.uris,
   }) {
     importedFile.referencingFiles.add(container.file);
   }
 
+  FileState get importedFile => selectedUri.file;
+
   /// Returns [importedFile] if it is a library.
   LibraryFileStateKind? get importedLibrary {
     final kind = importedFile.kind;
@@ -1572,14 +1712,12 @@
 }
 
 /// [ImportDirectiveWithUri] with a URI that resolves to [InSummarySource].
-class ImportDirectiveWithInSummarySource extends ImportDirectiveWithUri {
-  @override
-  final InSummarySource importedSource;
-
+class ImportDirectiveWithInSummarySource
+    extends ImportDirectiveWithUri<DirectiveUriWithInSummarySource> {
   ImportDirectiveWithInSummarySource({
     required super.directive,
-    required this.importedSource,
-    required super.selectedUriStr,
+    required super.selectedUri,
+    required super.uris,
   });
 
   @override
@@ -1590,15 +1728,18 @@
       return null;
     }
   }
+
+  @override
+  InSummarySource get importedSource => selectedUri.source;
 }
 
 /// [ImportDirectiveState] that has a valid URI.
-class ImportDirectiveWithUri extends ImportDirectiveState {
-  final String selectedUriStr;
-
+class ImportDirectiveWithUri<U extends DirectiveUriWithUri>
+    extends ImportDirectiveState<U> {
   ImportDirectiveWithUri({
     required super.directive,
-    required this.selectedUriStr,
+    required super.selectedUri,
+    required super.uris,
   });
 }
 
@@ -1658,37 +1799,24 @@
 
   List<PartDirectiveState> get parts {
     return _parts ??= file.unlinked2.parts.map((directive) {
-      final uriStr = directive.uri;
-      if (uriStr != null) {
-        return file._fileForRelativeUri(uriStr).map(
-          (refFile) {
-            if (refFile != null) {
-              return PartDirectiveWithFile(
-                library: this,
-                directive: directive,
-                includedFile: refFile,
-                uriStr: uriStr,
-              );
-            } else {
-              return PartDirectiveWithUri(
-                library: this,
-                directive: directive,
-                uriStr: uriStr,
-              );
-            }
-          },
-          (externalLibrary) {
-            return PartDirectiveWithUri(
-              library: this,
-              directive: directive,
-              uriStr: uriStr,
-            );
-          },
+      final uri = file._buildDirectiveUri(directive.uri);
+      if (uri is DirectiveUriWithFile) {
+        return PartDirectiveWithFile(
+          library: this,
+          directive: directive,
+          uri: uri,
+        );
+      } else if (uri is DirectiveUriWithUri) {
+        return PartDirectiveWithUri(
+          library: this,
+          directive: directive,
+          uri: uri,
         );
       } else {
         return PartDirectiveState(
           library: this,
           directive: directive,
+          uri: uri,
         );
       }
     }).toList();
@@ -1750,105 +1878,90 @@
 
   List<ImportAugmentationDirectiveState> get augmentations {
     return _augmentations ??= file.unlinked2.augmentations.map((directive) {
-      final uriStr = directive.uri;
-      if (uriStr != null) {
-        return file._fileForRelativeUri(uriStr).map(
-          (refFile) {
-            if (refFile != null) {
-              return ImportAugmentationDirectiveWithFile(
-                container: this,
-                directive: directive,
-                importedFile: refFile,
-              );
-            } else {
-              return ImportAugmentationWithUri(
-                directive: directive,
-                uriStr: uriStr,
-              );
-            }
-          },
-          (externalLibrary) {
-            return ImportAugmentationWithUri(
-              directive: directive,
-              uriStr: uriStr,
-            );
-          },
+      final uri = file._buildDirectiveUri(directive.uri);
+      if (uri is DirectiveUriWithFile) {
+        return ImportAugmentationDirectiveWithFile(
+          container: this,
+          directive: directive,
+          uri: uri,
+        );
+      } else if (uri is DirectiveUriWithUri) {
+        return ImportAugmentationWithUri(
+          directive: directive,
+          uri: uri,
         );
       } else {
         return ImportAugmentationDirectiveState(
           directive: directive,
+          uri: uri,
         );
       }
     }).toList();
   }
 
   List<ExportDirectiveState> get exports {
-    return _exports ??= file.unlinked2.exports.map((directive) {
-      final uriStr = file._selectRelativeUri(directive);
-      if (uriStr != null) {
-        return file._fileForRelativeUri(uriStr).map(
-          (refFile) {
-            if (refFile != null) {
-              return ExportDirectiveWithFile(
-                container: this,
-                directive: directive,
-                exportedFile: refFile,
-                selectedUriStr: uriStr,
-              );
-            } else {
-              return ExportDirectiveWithUri(
-                directive: directive,
-                selectedUriStr: uriStr,
-              );
-            }
-          },
-          (externalLibrary) {
-            return ExportDirectiveWithInSummarySource(
-              directive: directive,
-              exportedSource: externalLibrary.source,
-              selectedUriStr: uriStr,
-            );
-          },
+    return _exports ??=
+        file.unlinked2.exports.map<ExportDirectiveState>((directive) {
+      final uris = file._buildNamespaceDirectiveUris(directive);
+      final selectedUri = uris.selected;
+      if (selectedUri is DirectiveUriWithFile) {
+        return ExportDirectiveWithFile(
+          container: this,
+          directive: directive,
+          selectedUri: selectedUri,
+          uris: uris,
+        );
+      } else if (selectedUri is DirectiveUriWithInSummarySource) {
+        return ExportDirectiveWithInSummarySource(
+          directive: directive,
+          selectedUri: selectedUri,
+          uris: uris,
+        );
+      } else if (selectedUri is DirectiveUriWithUri) {
+        return ExportDirectiveWithUri(
+          directive: directive,
+          selectedUri: selectedUri,
+          uris: uris,
         );
       } else {
         return ExportDirectiveState(
           directive: directive,
+          selectedUri: selectedUri,
+          uris: uris,
         );
       }
     }).toList();
   }
 
   List<ImportDirectiveState> get imports {
-    return _imports ??= file.unlinked2.imports.map((directive) {
-      final uriStr = file._selectRelativeUri(directive);
-      if (uriStr != null) {
-        return file._fileForRelativeUri(uriStr).map(
-          (refFile) {
-            if (refFile != null) {
-              return ImportDirectiveWithFile(
-                container: this,
-                directive: directive,
-                importedFile: refFile,
-                selectedUriStr: uriStr,
-              );
-            } else {
-              return ImportDirectiveWithUri(
-                directive: directive,
-                selectedUriStr: uriStr,
-              );
-            }
-          },
-          (externalLibrary) {
-            return ImportDirectiveWithInSummarySource(
-              directive: directive,
-              importedSource: externalLibrary.source,
-              selectedUriStr: uriStr,
-            );
-          },
+    return _imports ??=
+        file.unlinked2.imports.map<ImportDirectiveState>((directive) {
+      final uris = file._buildNamespaceDirectiveUris(directive);
+      final selectedUri = uris.selected;
+      if (selectedUri is DirectiveUriWithFile) {
+        return ImportDirectiveWithFile(
+          container: this,
+          directive: directive,
+          selectedUri: selectedUri,
+          uris: uris,
+        );
+      } else if (selectedUri is DirectiveUriWithInSummarySource) {
+        return ImportDirectiveWithInSummarySource(
+          directive: directive,
+          selectedUri: selectedUri,
+          uris: uris,
+        );
+      } else if (selectedUri is DirectiveUriWithUri) {
+        return ImportDirectiveWithUri(
+          directive: directive,
+          selectedUri: selectedUri,
+          uris: uris,
         );
       } else {
         return ImportDirectiveState(
           directive: directive,
+          selectedUri: selectedUri,
+          uris: uris,
         );
       }
     }).toList();
@@ -1912,14 +2025,28 @@
   }
 }
 
+class NamespaceDirectiveUris {
+  final DirectiveUri primary;
+  final List<DirectiveUri> configurations;
+  final DirectiveUri selected;
+
+  NamespaceDirectiveUris({
+    required this.primary,
+    required this.configurations,
+    required this.selected,
+  });
+}
+
 /// Information about a single `part` directive.
-class PartDirectiveState extends DirectiveState {
+class PartDirectiveState<U extends DirectiveUri> extends DirectiveState {
   final LibraryFileStateKind library;
   final UnlinkedPartDirective directive;
+  final U uri;
 
   PartDirectiveState({
     required this.library,
     required this.directive,
+    required this.uri,
   });
 
   /// Returns a [Source] that is referenced by this directive.
@@ -1929,18 +2056,17 @@
 }
 
 /// [PartDirectiveWithUri] that has a valid URI that references a file.
-class PartDirectiveWithFile extends PartDirectiveWithUri {
-  final FileState includedFile;
-
+class PartDirectiveWithFile extends PartDirectiveWithUri<DirectiveUriWithFile> {
   PartDirectiveWithFile({
     required super.library,
     required super.directive,
-    required super.uriStr,
-    required this.includedFile,
+    required super.uri,
   }) {
     includedFile.referencingFiles.add(library.file);
   }
 
+  FileState get includedFile => uri.file;
+
   /// If [includedFile] is a [PartFileStateKind], and it confirms that it
   /// is a part of the [library], returns the [includedFile].
   PartFileStateKind? get includedPart {
@@ -1961,13 +2087,12 @@
 }
 
 /// [PartDirectiveState] that has a valid URI.
-class PartDirectiveWithUri extends PartDirectiveState {
-  final String uriStr;
-
+class PartDirectiveWithUri<U extends DirectiveUriWithUri>
+    extends PartDirectiveState<U> {
   PartDirectiveWithUri({
     required super.library,
     required super.directive,
-    required this.uriStr,
+    required super.uri,
   });
 }
 
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index a584d14..7983d90 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -41,16 +41,13 @@
 import 'package:analyzer/src/generated/ffi_verifier.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:analyzer/src/hint/sdk_constraint_verifier.dart';
 import 'package:analyzer/src/ignore_comments/ignore_info.dart';
 import 'package:analyzer/src/lint/linter.dart';
 import 'package:analyzer/src/lint/linter_visitor.dart';
 import 'package:analyzer/src/services/lint.dart';
-import 'package:analyzer/src/summary/package_bundle_reader.dart';
 import 'package:analyzer/src/task/strong/checker.dart';
 import 'package:analyzer/src/util/performance/operation_performance.dart';
-import 'package:analyzer/src/util/uri.dart';
 
 class AnalysisForCompletionResult {
   final CompilationUnit parsedUnit;
@@ -66,7 +63,6 @@
 class LibraryAnalyzer {
   final AnalysisOptionsImpl _analysisOptions;
   final DeclaredVariables _declaredVariables;
-  final SourceFactory _sourceFactory;
   final LibraryFileStateKind _library;
   final InheritanceManager3 _inheritance;
 
@@ -79,13 +75,8 @@
   final Map<FileState, ErrorReporter> _errorReporters = {};
   final TestingData? _testingData;
 
-  LibraryAnalyzer(
-      this._analysisOptions,
-      this._declaredVariables,
-      this._sourceFactory,
-      this._libraryElement,
-      this._inheritance,
-      this._library,
+  LibraryAnalyzer(this._analysisOptions, this._declaredVariables,
+      this._libraryElement, this._inheritance, this._library,
       {TestingData? testingData})
       : _testingData = testingData;
 
@@ -296,13 +287,17 @@
     // This must happen after all other diagnostics have been computed but
     // before the list of diagnostics has been filtered.
     for (var file in _library.files) {
-      IgnoreValidator(
-        _getErrorReporter(file),
-        _getErrorListener(file).errors,
-        _fileToIgnoreInfo[file]!,
-        _fileToLineInfo[file]!,
-        _analysisOptions.unignorableNames,
-      ).reportErrors();
+      final ignoreInfo = _fileToIgnoreInfo[file];
+      // TODO(scheglov) make it safer
+      if (ignoreInfo != null) {
+        IgnoreValidator(
+          _getErrorReporter(file),
+          _getErrorListener(file).errors,
+          ignoreInfo,
+          _fileToLineInfo[file]!,
+          _analysisOptions.unignorableNames,
+        ).reportErrors();
+      }
     }
   }
 
@@ -440,11 +435,6 @@
     }
 
     //
-    // Validate the directives.
-    //
-    _validateUriBasedDirectives(file, unit);
-
-    //
     // Use the ConstantVerifier to compute errors.
     //
     _computeConstantErrors(errorReporter, unit);
@@ -515,42 +505,6 @@
     });
   }
 
-  /// Return the name of the library that the given part is declared to be a
-  /// part of, or `null` if the part does not contain a part-of directive.
-  _NameOrSource? _getPartLibraryNameOrUri(Source partSource,
-      CompilationUnit partUnit, List<Directive> directivesToResolve) {
-    for (Directive directive in partUnit.directives) {
-      if (directive is PartOfDirective) {
-        directivesToResolve.add(directive);
-        LibraryIdentifier? libraryName = directive.libraryName;
-        if (libraryName != null) {
-          return _NameOrSource(libraryName.name, null);
-        }
-        String? uri = directive.uri?.stringValue;
-        if (uri != null) {
-          Source? librarySource = _sourceFactory.resolveUri(partSource, uri);
-          if (librarySource != null) {
-            return _NameOrSource(null, librarySource);
-          }
-        }
-      }
-    }
-    return null;
-  }
-
-  bool _isExistingSource(Source source) {
-    if (source is InSummarySource) {
-      return true;
-    }
-    for (var file in _library.file.directReferencedFiles) {
-      if (file.uri == source.uri) {
-        return file.exists;
-      }
-    }
-    // A library can refer to itself with an empty URI.
-    return source == _library.file.source;
-  }
-
   /// Return a new parsed unresolved [CompilationUnit].
   CompilationUnitImpl _parse(FileState file) {
     AnalysisErrorListener errorListener = _getErrorListener(file);
@@ -565,21 +519,28 @@
 
   /// Parse and resolve all files in [_library].
   Map<FileState, CompilationUnitImpl> _parseAndResolve() {
-    var units = <FileState, CompilationUnitImpl>{};
-
     // Parse all files.
-    for (FileState file in _library.files) {
-      units[file] = _parse(file);
+    final libraryFile = _library.file;
+    final libraryUnit = _parse(libraryFile);
+    final units = <FileState, CompilationUnitImpl>{
+      libraryFile: libraryUnit,
+    };
+    for (final part in _library.parts) {
+      if (part is PartDirectiveWithFile) {
+        final partFile = part.includedPart?.file;
+        if (partFile != null) {
+          units[partFile] = _parse(partFile);
+        }
+      }
     }
 
     // Resolve URIs in directives to corresponding sources.
-    FeatureSet featureSet = units[_library.file]!.featureSet;
+    final featureSet = _libraryElement.featureSet;
     units.forEach((file, unit) {
       _validateFeatureSet(unit, featureSet);
-      _resolveUriBasedDirectives(file, unit);
     });
 
-    _resolveDirectives(units);
+    _resolveDirectives(units, libraryUnit);
 
     units.forEach((file, unit) {
       _resolveFile(file, unit);
@@ -590,136 +551,54 @@
     return units;
   }
 
-  void _resolveDirectives(Map<FileState, CompilationUnitImpl> units) {
-    var definingCompilationUnit = units[_library.file]!;
-    definingCompilationUnit.element = _libraryElement.definingCompilationUnit;
-
-    bool matchNodeElement(Directive node, Element element) {
-      return node.keyword.offset == element.nameOffset;
-    }
+  void _resolveDirectives(
+    Map<FileState, CompilationUnitImpl> units,
+    CompilationUnitImpl libraryUnit,
+  ) {
+    libraryUnit.element = _libraryElement.definingCompilationUnit;
 
     ErrorReporter libraryErrorReporter = _getErrorReporter(_library.file);
 
+    var importIndex = 0;
+    var exportIndex = 0;
+
     LibraryIdentifier? libraryNameNode;
     var seenPartSources = <Source>{};
     var directivesToResolve = <DirectiveImpl>[];
-    int partDirectiveIndex = 0;
-    int partElementIndex = 0;
-    for (Directive directive in definingCompilationUnit.directives) {
+    final partIndexes = _PartDirectiveIndexes();
+    for (Directive directive in libraryUnit.directives) {
       if (directive is LibraryDirectiveImpl) {
         libraryNameNode = directive.name;
         directivesToResolve.add(directive);
+      } else if (directive is AugmentationImportDirective) {
+        // TODO(scheglov) implement
+        throw UnimplementedError();
       } else if (directive is ImportDirectiveImpl) {
-        // TODO(scheglov) Rewrite to iterating `ImportDirectiveState`.
-        for (var index = 0; index < _libraryElement.imports.length; index++) {
-          final importElement = _libraryElement.imports[index];
-          if (matchNodeElement(directive, importElement)) {
-            directive.element = importElement;
-            directive.prefix?.staticElement = importElement.prefix;
-            final importDirectiveState = _library.imports[index];
-            // TODO(scheglov) rewrite
-            if (importDirectiveState is ImportDirectiveWithUri) {
-              if (importDirectiveState.importedSource != null) {
-                if (importDirectiveState.importedLibrarySource == null) {
-                  libraryErrorReporter.reportErrorForNode(
-                    CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY,
-                    directive.uri,
-                    [importDirectiveState.selectedUriStr],
-                  );
-                }
-              }
-            }
-          }
-        }
+        _resolveImportDirective(
+          directive: directive,
+          importElement: _libraryElement.imports[importIndex],
+          importState: _library.imports[importIndex],
+          libraryErrorReporter: libraryErrorReporter,
+        );
+        importIndex++;
       } else if (directive is ExportDirectiveImpl) {
-        // TODO(scheglov) Rewrite to iterating `ExportDirectiveState`.
-        for (var index = 0; index < _libraryElement.exports.length; index++) {
-          final exportElement = _libraryElement.exports[index];
-          if (matchNodeElement(directive, exportElement)) {
-            directive.element = exportElement;
-            final exportDirectiveState = _library.exports[index];
-            // TODO(scheglov) rewrite
-            if (exportDirectiveState is ExportDirectiveWithUri) {
-              if (exportDirectiveState.exportedSource != null) {
-                if (exportDirectiveState.exportedLibrarySource == null) {
-                  libraryErrorReporter.reportErrorForNode(
-                    CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
-                    directive.uri,
-                    [exportDirectiveState.selectedUriStr],
-                  );
-                }
-              }
-            }
-          }
-        }
+        _resolveExportDirective(
+          directive: directive,
+          exportElement: _libraryElement.exports[exportIndex],
+          exportState: _library.exports[exportIndex],
+          libraryErrorReporter: libraryErrorReporter,
+        );
+        exportIndex++;
       } else if (directive is PartDirectiveImpl) {
-        StringLiteral partUri = directive.uri;
-
-        if (partElementIndex >= _libraryElement.parts.length) {
-          continue;
-        }
-
-        final partState = _library.parts[partDirectiveIndex++];
-        if (partState is! PartDirectiveWithFile) {
-          continue;
-        }
-        final partFile = partState.includedFile;
-
-        var partUnit = units[partFile]!;
-        var partElement = _libraryElement.parts[partElementIndex++];
-        partUnit.element = partElement;
-        directive.element = partElement;
-
-        Source? partSource = directive.uriSource;
-        if (partSource == null) {
-          continue;
-        }
-
-        //
-        // Validate that the part source is unique in the library.
-        //
-        if (!seenPartSources.add(partSource)) {
-          libraryErrorReporter.reportErrorForNode(
-              CompileTimeErrorCode.DUPLICATE_PART, partUri, [partSource.uri]);
-        }
-
-        //
-        // Validate that the part contains a part-of directive with the same
-        // name or uri as the library.
-        //
-        if (_isExistingSource(partSource)) {
-          _NameOrSource? nameOrSource = _getPartLibraryNameOrUri(
-              partSource, partUnit, directivesToResolve);
-          if (nameOrSource == null) {
-            libraryErrorReporter.reportErrorForNode(
-                CompileTimeErrorCode.PART_OF_NON_PART,
-                partUri,
-                [partUri.toSource()]);
-          } else {
-            String? name = nameOrSource.name;
-            if (name != null) {
-              if (libraryNameNode == null) {
-                libraryErrorReporter.reportErrorForNode(
-                    CompileTimeErrorCode.PART_OF_UNNAMED_LIBRARY,
-                    partUri,
-                    [name]);
-              } else if (libraryNameNode.name != name) {
-                libraryErrorReporter.reportErrorForNode(
-                    CompileTimeErrorCode.PART_OF_DIFFERENT_LIBRARY,
-                    partUri,
-                    [libraryNameNode.name, name]);
-              }
-            } else {
-              Source source = nameOrSource.source!;
-              if (source != _library.file.source) {
-                libraryErrorReporter.reportErrorForNode(
-                    CompileTimeErrorCode.PART_OF_DIFFERENT_LIBRARY,
-                    partUri,
-                    [_library.file.uriStr, source.uri]);
-              }
-            }
-          }
-        }
+        _resolvePartDirective(
+          directive: directive,
+          partIndexes: partIndexes,
+          libraryErrorReporter: libraryErrorReporter,
+          libraryNameNode: libraryNameNode,
+          units: units,
+          directivesToResolve: directivesToResolve,
+          seenPartSources: seenPartSources,
+        );
       }
     }
 
@@ -734,6 +613,62 @@
     }
   }
 
+  void _resolveExportDirective({
+    required ExportDirectiveImpl directive,
+    required ExportElement exportElement,
+    required ExportDirectiveState exportState,
+    required ErrorReporter libraryErrorReporter,
+  }) {
+    directive.element = exportElement;
+    _resolveNamespaceDirective(
+      directive: directive,
+      primaryUriNode: directive.uri,
+      primaryUriState: exportState.uris.primary,
+      configurationNodes: directive.configurations,
+      configurationUris: exportState.uris.configurations,
+      selectedUriState: exportState.selectedUri,
+    );
+    if (exportState is ExportDirectiveWithUri) {
+      final selectedUriStr = exportState.selectedUri.relativeUriStr;
+      if (selectedUriStr.startsWith('dart-ext:')) {
+        libraryErrorReporter.reportErrorForNode(
+          CompileTimeErrorCode.USE_OF_NATIVE_EXTENSION,
+          directive.uri,
+        );
+      } else if (exportState.exportedSource == null) {
+        final errorCode = exportState.selectedUri.isValid
+            ? CompileTimeErrorCode.URI_DOES_NOT_EXIST
+            : CompileTimeErrorCode.INVALID_URI;
+        libraryErrorReporter.reportErrorForNode(
+          errorCode,
+          directive.uri,
+          [selectedUriStr],
+        );
+      } else if (exportState is ExportDirectiveWithFile &&
+          !exportState.exportedFile.exists) {
+        final errorCode = isGeneratedSource(exportState.exportedSource)
+            ? CompileTimeErrorCode.URI_HAS_NOT_BEEN_GENERATED
+            : CompileTimeErrorCode.URI_DOES_NOT_EXIST;
+        libraryErrorReporter.reportErrorForNode(
+          errorCode,
+          directive.uri,
+          [selectedUriStr],
+        );
+      } else if (exportState.exportedLibrarySource == null) {
+        libraryErrorReporter.reportErrorForNode(
+          CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
+          directive.uri,
+          [selectedUriStr],
+        );
+      }
+    } else {
+      libraryErrorReporter.reportErrorForNode(
+        CompileTimeErrorCode.URI_WITH_INTERPOLATION,
+        directive.uri,
+      );
+    }
+  }
+
   void _resolveFile(FileState file, CompilationUnit unit) {
     var source = file.source;
     RecordingErrorListener errorListener = _getErrorListener(file);
@@ -772,86 +707,202 @@
         featureSet: unit.featureSet, flowAnalysisHelper: flowAnalysisHelper));
   }
 
-  Uri? _resolveRelativeUri(String relativeUriStr) {
-    Uri relativeUri;
-    try {
-      relativeUri = Uri.parse(relativeUriStr);
-    } on FormatException {
-      return null;
+  void _resolveImportDirective({
+    required ImportDirectiveImpl directive,
+    required ImportElement importElement,
+    required ImportDirectiveState importState,
+    required ErrorReporter libraryErrorReporter,
+  }) {
+    directive.element = importElement;
+    directive.prefix?.staticElement = importElement.prefix;
+    _resolveNamespaceDirective(
+      directive: directive,
+      primaryUriNode: directive.uri,
+      primaryUriState: importState.uris.primary,
+      configurationNodes: directive.configurations,
+      configurationUris: importState.uris.configurations,
+      selectedUriState: importState.selectedUri,
+    );
+    if (importState is ImportDirectiveWithUri) {
+      final selectedUriStr = importState.selectedUri.relativeUriStr;
+      if (selectedUriStr.startsWith('dart-ext:')) {
+        libraryErrorReporter.reportErrorForNode(
+          CompileTimeErrorCode.USE_OF_NATIVE_EXTENSION,
+          directive.uri,
+        );
+      } else if (importState.importedSource == null) {
+        final errorCode = importState.selectedUri.isValid
+            ? CompileTimeErrorCode.URI_DOES_NOT_EXIST
+            : CompileTimeErrorCode.INVALID_URI;
+        libraryErrorReporter.reportErrorForNode(
+          errorCode,
+          directive.uri,
+          [selectedUriStr],
+        );
+      } else if (importState is ImportDirectiveWithFile &&
+          !importState.importedFile.exists) {
+        final errorCode = isGeneratedSource(importState.importedSource)
+            ? CompileTimeErrorCode.URI_HAS_NOT_BEEN_GENERATED
+            : CompileTimeErrorCode.URI_DOES_NOT_EXIST;
+        libraryErrorReporter.reportErrorForNode(
+          errorCode,
+          directive.uri,
+          [selectedUriStr],
+        );
+      } else if (importState.importedLibrarySource == null) {
+        libraryErrorReporter.reportErrorForNode(
+          CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY,
+          directive.uri,
+          [selectedUriStr],
+        );
+      }
+    } else {
+      libraryErrorReporter.reportErrorForNode(
+        CompileTimeErrorCode.URI_WITH_INTERPOLATION,
+        directive.uri,
+      );
     }
-
-    var absoluteUri = resolveRelativeUri(_library.file.uri, relativeUri);
-    return rewriteToCanonicalUri(_sourceFactory, absoluteUri);
   }
 
-  /// Return the result of resolve the given [uriContent], reporting errors
-  /// against the [uriLiteral].
-  Source? _resolveUri(FileState file, bool isImport, StringLiteral uriLiteral,
-      String? uriContent) {
-    UriValidationCode? code =
-        UriBasedDirectiveImpl.validateUri(isImport, uriLiteral, uriContent);
-    if (code == null) {
-      try {
-        Uri.parse(uriContent!);
-      } on FormatException {
-        return null;
-      }
-      return _sourceFactory.resolveUri(file.source, uriContent);
-    } else if (code == UriValidationCode.URI_WITH_INTERPOLATION) {
-      _getErrorReporter(file).reportErrorForNode(
-          CompileTimeErrorCode.URI_WITH_INTERPOLATION, uriLiteral);
-      return null;
-    } else if (code == UriValidationCode.INVALID_URI) {
-      // It is safe to assume [uriContent] is non-null because the only way for
-      // it to be null is if the string literal contained an interpolation, and
-      // in that case the validation code would have been
-      // UriValidationCode.URI_WITH_INTERPOLATION.
-      assert(uriContent != null);
-      _getErrorReporter(file).reportErrorForNode(
-          CompileTimeErrorCode.INVALID_URI, uriLiteral, [uriContent!]);
-      return null;
+  void _resolveNamespaceDirective({
+    required NamespaceDirectiveImpl directive,
+    required StringLiteralImpl primaryUriNode,
+    required DirectiveUri primaryUriState,
+    required DirectiveUri selectedUriState,
+    required List<Configuration> configurationNodes,
+    required List<DirectiveUri> configurationUris,
+  }) {
+    for (var i = 0; i < configurationNodes.length; i++) {
+      final configurationNode = configurationNodes[i];
+      configurationNode as ConfigurationImpl;
+      configurationNode.uriSource = configurationUris[i].source;
     }
-    return null;
+
+    if (primaryUriState is DirectiveUriWithString) {
+      directive.uriContent = primaryUriState.relativeUriStr;
+      directive.uriSource = primaryUriState.source;
+    }
+
+    if (selectedUriState is DirectiveUriWithString) {
+      directive.selectedUriContent = selectedUriState.relativeUriStr;
+      directive.selectedSource = selectedUriState.source;
+    }
   }
 
-  void _resolveUriBasedDirectives(FileState file, CompilationUnit unit) {
-    for (var directive in unit.directives) {
-      if (directive is UriBasedDirectiveImpl) {
-        StringLiteral uriLiteral = directive.uri;
-        String? uriContent = uriLiteral.stringValue?.trim();
-        directive.uriContent = uriContent;
-        Source? defaultSource = _resolveUri(
-            file, directive is ImportDirective, uriLiteral, uriContent);
-        directive.uriSource = defaultSource;
+  void _resolvePartDirective({
+    required PartDirectiveImpl directive,
+    required _PartDirectiveIndexes partIndexes,
+    required ErrorReporter libraryErrorReporter,
+    required LibraryIdentifier? libraryNameNode,
+    required Map<FileState, CompilationUnitImpl> units,
+    required List<DirectiveImpl> directivesToResolve,
+    required Set<Source> seenPartSources,
+  }) {
+    StringLiteral partUri = directive.uri;
+
+    final partState = _library.parts[partIndexes.directive++];
+    directive.uriSource = partState.includedSource;
+    if (partState is! PartDirectiveWithUri) {
+      libraryErrorReporter.reportErrorForNode(
+        CompileTimeErrorCode.URI_WITH_INTERPOLATION,
+        directive.uri,
+      );
+      return;
+    }
+
+    // TODO(scheglov) This should not be necessary if we build `PartElement`
+    // for every `part` directive.
+    if (partIndexes.element >= _libraryElement.parts.length) {
+      final errorCode = partState.uri.isValid
+          ? CompileTimeErrorCode.URI_DOES_NOT_EXIST
+          : CompileTimeErrorCode.INVALID_URI;
+      libraryErrorReporter.reportErrorForNode(
+        errorCode,
+        directive.uri,
+        [partState.uri.relativeUriStr],
+      );
+      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;
+
+    if (includedKind is! PartFileStateKind) {
+      if (includedFile.exists) {
+        libraryErrorReporter.reportErrorForNode(
+          CompileTimeErrorCode.PART_OF_NON_PART,
+          partUri,
+          [partUri.toSource()],
+        );
+      } else {
+        final errorCode = isGeneratedSource(includedFile.source)
+            ? CompileTimeErrorCode.URI_HAS_NOT_BEEN_GENERATED
+            : CompileTimeErrorCode.URI_DOES_NOT_EXIST;
+        libraryErrorReporter.reportErrorForNode(
+          errorCode,
+          directive.uri,
+          [partUri.toSource()],
+        );
       }
-      if (directive is NamespaceDirectiveImpl) {
-        var relativeUriStr = _selectRelativeUri(directive);
-        directive.selectedUriContent = relativeUriStr;
-        var absoluteUri = _resolveRelativeUri(relativeUriStr);
-        if (absoluteUri != null) {
-          directive.selectedSource = _sourceFactory.forUri2(absoluteUri);
+      return;
+    }
+
+    if (includedKind is PartOfNameFileStateKind) {
+      if (!includedKind.libraries.contains(_library)) {
+        final name = includedKind.directive.name;
+        if (libraryNameNode == null) {
+          libraryErrorReporter.reportErrorForNode(
+            CompileTimeErrorCode.PART_OF_UNNAMED_LIBRARY,
+            partUri,
+            [name],
+          );
+        } else {
+          libraryErrorReporter.reportErrorForNode(
+            CompileTimeErrorCode.PART_OF_DIFFERENT_LIBRARY,
+            partUri,
+            [libraryNameNode.name, name],
+          );
         }
-        for (var configuration in directive.configurations) {
-          configuration as ConfigurationImpl;
-          var uriLiteral = configuration.uri;
-          String? uriContent = uriLiteral.stringValue?.trim();
-          Source? defaultSource = _resolveUri(
-              file, directive is ImportDirective, uriLiteral, uriContent);
-          configuration.uriSource = defaultSource;
-        }
+        return;
       }
+    } else if (includedKind.library != _library) {
+      libraryErrorReporter.reportErrorForNode(
+        CompileTimeErrorCode.PART_OF_DIFFERENT_LIBRARY,
+        partUri,
+        [_library.file.uriStr, includedFile.uriStr],
+      );
+      return;
     }
-  }
 
-  String _selectRelativeUri(NamespaceDirective directive) {
-    for (var configuration in directive.configurations) {
-      var name = configuration.name.components.join('.');
-      var value = configuration.value?.stringValue ?? 'true';
-      if (_declaredVariables.get(name) == value) {
-        return configuration.uri.stringValue ?? '';
+    var partUnit = units[includedFile]!;
+    var partElement = _libraryElement.parts[partIndexes.element++];
+    partUnit.element = partElement;
+    directive.element = partElement;
+
+    final partSource = includedKind.file.source;
+    directive.uriSource = partSource;
+
+    for (final directive in partUnit.directives) {
+      if (directive is PartOfDirectiveImpl) {
+        directivesToResolve.add(directive);
       }
     }
-    return directive.uri.stringValue ?? '';
+
+    //
+    // Validate that the part source is unique in the library.
+    //
+    if (!seenPartSources.add(partSource)) {
+      libraryErrorReporter.reportErrorForNode(
+          CompileTimeErrorCode.DUPLICATE_PART, partUri, [partSource.uri]);
+    }
   }
 
   /// Validate that the feature set associated with the compilation [unit] is
@@ -863,61 +914,6 @@
     }
   }
 
-  /// Check the given [directive] to see if the referenced source exists and
-  /// report an error if it does not.
-  void _validateUriBasedDirective(
-      FileState file, UriBasedDirectiveImpl directive) {
-    String? uriContent;
-    Source? source;
-    if (directive is NamespaceDirectiveImpl) {
-      uriContent = directive.selectedUriContent;
-      source = directive.selectedSource;
-    } else {
-      uriContent = directive.uriContent;
-      source = directive.uriSource;
-    }
-    if (source != null) {
-      if (_isExistingSource(source)) {
-        return;
-      }
-    } else {
-      // Don't report errors already reported by ParseDartTask.resolveDirective
-      // TODO(scheglov) we don't use this task here
-      if (directive.validate() != null) {
-        return;
-      }
-    }
-
-    if (uriContent != null && uriContent.startsWith('dart-ext:')) {
-      _getErrorReporter(file).reportErrorForNode(
-        CompileTimeErrorCode.USE_OF_NATIVE_EXTENSION,
-        directive.uri,
-      );
-      return;
-    }
-
-    CompileTimeErrorCode errorCode = CompileTimeErrorCode.URI_DOES_NOT_EXIST;
-    if (isGeneratedSource(source)) {
-      errorCode = CompileTimeErrorCode.URI_HAS_NOT_BEEN_GENERATED;
-    }
-    // It is safe to assume that [uriContent] is non-null because the only way
-    // for it to be null is if the string literal contained an interpolation,
-    // and in that case the call to `directive.validate()` above would have
-    // returned a non-null validation code.
-    _getErrorReporter(file)
-        .reportErrorForNode(errorCode, directive.uri, [uriContent!]);
-  }
-
-  /// Check each directive in the given [unit] to see if the referenced source
-  /// exists and report an error if it does not.
-  void _validateUriBasedDirectives(FileState file, CompilationUnit unit) {
-    for (Directive directive in unit.directives) {
-      if (directive is UriBasedDirectiveImpl) {
-        _validateUriBasedDirective(file, directive);
-      }
-    }
-  }
-
   /// Find constants in [unit] to compute.
   static List<ConstantEvaluationTarget> _findConstants(CompilationUnit unit) {
     ConstantFinder constantFinder = ConstantFinder();
@@ -1016,10 +1012,7 @@
   UnitAnalysisResult(this.file, this.unit, this.errors);
 }
 
-/// Either the name or the source associated with a part-of directive.
-class _NameOrSource {
-  final String? name;
-  final Source? source;
-
-  _NameOrSource(this.name, this.source);
+class _PartDirectiveIndexes {
+  int directive = 0;
+  int element = 0;
 }
diff --git a/pkg/analyzer/lib/src/dart/analysis/unlinked_data.dart b/pkg/analyzer/lib/src/dart/analysis/unlinked_data.dart
index 0f37cef..116cd36 100644
--- a/pkg/analyzer/lib/src/dart/analysis/unlinked_data.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/unlinked_data.dart
@@ -221,6 +221,14 @@
     );
   }
 
+  String get valueOrTrue {
+    if (value.isEmpty) {
+      return 'true';
+    } else {
+      return value;
+    }
+  }
+
   void write(BufferedSink sink) {
     sink.writeStringUtf8(name);
     sink.writeOptionalStringUtf8(uri);
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 7a61f73..463df80 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -875,6 +875,64 @@
   }
 }
 
+/// An augmentation import directive.
+///
+///    importDirective ::=
+///        [Annotation] 'import' 'augment' [StringLiteral] ';'
+class AugmentationImportDirectiveImpl extends UriBasedDirectiveImpl
+    implements AugmentationImportDirective {
+  @override
+  Token importKeyword;
+
+  @override
+  Token augmentKeyword;
+
+  @override
+  Token semicolon;
+
+  AugmentationImportDirectiveImpl({
+    required CommentImpl? comment,
+    required List<Annotation>? metadata,
+    required this.importKeyword,
+    required this.augmentKeyword,
+    required this.semicolon,
+    required StringLiteralImpl uri,
+  }) : super(comment, metadata, uri) {
+    _becomeParentOf(_uri);
+  }
+
+  @override
+  AugmentationImportElement? get element {
+    return super.element as AugmentationImportElement?;
+  }
+
+  @override
+  Token get endToken => semicolon;
+
+  @override
+  Token get firstTokenAfterCommentAndMetadata => keyword;
+
+  @override
+  Token get keyword => importKeyword;
+
+  @override
+  LibraryAugmentationElement? get uriElement {
+    return element?.augmentation;
+  }
+
+  @override
+  ChildEntities get _childEntities => super._childEntities
+    ..addToken('keyword', keyword)
+    ..addToken('augmentKeyword', augmentKeyword)
+    ..addNode('uri', uri)
+    ..addToken('semicolon', semicolon);
+
+  @override
+  E? accept<E>(AstVisitor<E> visitor) {
+    return visitor.visitAugmentationImportDirective(this);
+  }
+}
+
 /// An await expression.
 ///
 ///    awaitExpression ::=
@@ -6311,10 +6369,6 @@
 //         [Combinator]* ';'
 class ImportDirectiveImpl extends NamespaceDirectiveImpl
     implements ImportDirective {
-  /// The token representing the 'augment' keyword, or `null` if the import is
-  /// not a library augmentation import.
-  Token? augmentKeyword;
-
   /// The token representing the 'deferred' keyword, or `null` if the imported
   /// is not deferred.
   @override
@@ -6339,7 +6393,6 @@
       CommentImpl? comment,
       List<Annotation>? metadata,
       Token keyword,
-      this.augmentKeyword,
       StringLiteralImpl libraryUri,
       List<Configuration>? configurations,
       this.deferredKeyword,
@@ -6370,7 +6423,6 @@
   @override
   ChildEntities get _childEntities => super._childEntities
     ..addToken('keyword', keyword)
-    ..addToken('augmentKeyword', augmentKeyword)
     ..addNode('uri', uri)
     ..addToken('deferredKeyword', deferredKeyword)
     ..addToken('asKeyword', asKeyword)
diff --git a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
index 6bade88..0e45fe4 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
@@ -735,22 +735,21 @@
           typeArgumentTypes: typeArgumentTypes);
 
   ImportDirectiveImpl importDirective(
-          Comment? comment,
-          List<Annotation>? metadata,
-          Token keyword,
-          StringLiteral libraryUri,
-          List<Configuration>? configurations,
-          Token? deferredKeyword,
-          Token? asKeyword,
-          SimpleIdentifier? prefix,
-          List<Combinator>? combinators,
-          Token semicolon,
-          {Token? augmentKeyword}) =>
+    Comment? comment,
+    List<Annotation>? metadata,
+    Token keyword,
+    StringLiteral libraryUri,
+    List<Configuration>? configurations,
+    Token? deferredKeyword,
+    Token? asKeyword,
+    SimpleIdentifier? prefix,
+    List<Combinator>? combinators,
+    Token semicolon,
+  ) =>
       ImportDirectiveImpl(
           comment as CommentImpl?,
           metadata,
           keyword,
-          augmentKeyword,
           libraryUri as StringLiteralImpl,
           configurations,
           deferredKeyword,
diff --git a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
index becc0af..5a83d20 100644
--- a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
@@ -78,6 +78,14 @@
   }
 
   @override
+  void visitAugmentationImportDirective(AugmentationImportDirective node) {
+    _visitNodeList(node.metadata, separator: ' ', suffix: ' ');
+    sink.write('import augment ');
+    _visitNode(node.uri);
+    sink.write(';');
+  }
+
+  @override
   void visitAwaitExpression(AwaitExpression node) {
     sink.write('await ');
     _visitNode(node.expression);
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index f024ba6..46b2fb6 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -162,6 +162,17 @@
   }
 
   @override
+  bool visitAugmentationImportDirective(AugmentationImportDirective node) {
+    final other = _other as AugmentationImportDirective;
+    return isEqualNodes(
+            node.documentationComment, other.documentationComment) &&
+        _isEqualNodeLists(node.metadata, other.metadata) &&
+        isEqualTokens(node.keyword, other.keyword) &&
+        isEqualNodes(node.uri, other.uri) &&
+        isEqualTokens(node.semicolon, other.semicolon);
+  }
+
+  @override
   bool visitAwaitExpression(AwaitExpression node) {
     AwaitExpression other = _other as AwaitExpression;
     return isEqualTokens(node.awaitKeyword, other.awaitKeyword) &&
@@ -1698,6 +1709,13 @@
   }
 
   @override
+  bool visitAugmentationImportDirective(
+    covariant AugmentationImportDirectiveImpl node,
+  ) {
+    return visitUriBasedDirective(node);
+  }
+
+  @override
   bool visitAwaitExpression(covariant AwaitExpressionImpl node) {
     if (identical(node.expression, _oldNode)) {
       node.expression = _newNode as Expression;
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index 9bac236..055b894 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -581,7 +581,6 @@
         var libraryAnalyzer = LibraryAnalyzer(
           fileContext.analysisOptions,
           contextObjects!.declaredVariables,
-          sourceFactory,
           elementFactory.libraryOfUri2(libraryKind.file.uri),
           analysisSession.inheritanceManager,
           libraryKind,
@@ -647,7 +646,6 @@
         var libraryAnalyzer = LibraryAnalyzer(
           fileContext.analysisOptions,
           contextObjects!.declaredVariables,
-          sourceFactory,
           libraryContext!.elementFactory.libraryOfUri2(libraryKind.file.uri),
           libraryContext!.elementFactory.analysisSession.inheritanceManager,
           libraryKind,
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index a84eac9..b40172c 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -1824,7 +1824,7 @@
     var asKeyword = pop(NullValue.As) as Token?;
     var prefix = pop(NullValue.Prefix) as SimpleIdentifier?;
     var configurations = pop() as List<Configuration>?;
-    var uri = pop() as StringLiteral;
+    var uri = pop() as StringLiteralImpl;
     var metadata = pop() as List<Annotation>?;
     var comment = _findComment(metadata, importKeyword);
 
@@ -1839,18 +1839,33 @@
       }
     }
 
-    directives.add(ast.importDirective(
-        comment,
-        metadata,
-        importKeyword,
-        uri,
-        configurations,
-        deferredKeyword,
-        asKeyword,
-        prefix,
-        combinators,
-        semicolon ?? Tokens.semicolon(),
-        augmentKeyword: augmentToken));
+    if (augmentToken != null) {
+      directives.add(
+        AugmentationImportDirectiveImpl(
+          comment: comment,
+          uri: uri,
+          importKeyword: importKeyword,
+          augmentKeyword: augmentToken,
+          metadata: metadata,
+          semicolon: semicolon ?? Tokens.semicolon(),
+        ),
+      );
+    } else {
+      directives.add(
+        ast.importDirective(
+          comment,
+          metadata,
+          importKeyword,
+          uri,
+          configurations,
+          deferredKeyword,
+          asKeyword,
+          prefix,
+          combinators,
+          semicolon ?? Tokens.semicolon(),
+        ),
+      );
+    }
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/test_utilities/find_node.dart b/pkg/analyzer/lib/src/test_utilities/find_node.dart
index 2c0aee8..e933186 100644
--- a/pkg/analyzer/lib/src/test_utilities/find_node.dart
+++ b/pkg/analyzer/lib/src/test_utilities/find_node.dart
@@ -55,6 +55,10 @@
     return _node(search, (n) => n is AssignmentExpression);
   }
 
+  AugmentationImportDirective augmentationImportDirective(String search) {
+    return _node(search, (n) => n is AugmentationImportDirective);
+  }
+
   AwaitExpression awaitExpression(String search) {
     return _node(search, (n) => n is AwaitExpression);
   }
diff --git a/pkg/analyzer/test/generated/utilities_test.dart b/pkg/analyzer/test/generated/utilities_test.dart
index 4db863b..711e8e8 100644
--- a/pkg/analyzer/test/generated/utilities_test.dart
+++ b/pkg/analyzer/test/generated/utilities_test.dart
@@ -277,6 +277,24 @@
     );
   }
 
+  void test_augmentationImportDirective() {
+    var findNode = _parseStringToFindNode(r'''
+@myA1
+@myA2
+import augment 'a.dart';
+import augment 'b.dart';
+''');
+    var node = findNode.augmentationImportDirective('a.dart');
+    _assertAnnotatedNode(node);
+    _assertReplacementForChildren<AugmentationImportDirective>(
+      destination: findNode.augmentationImportDirective('b.dart'),
+      source: node,
+      childAccessors: [
+        (node) => node.uri,
+      ],
+    );
+  }
+
   void test_awaitExpression() {
     var findNode = _parseStringToFindNode(r'''
 void f() async {
diff --git a/pkg/analyzer/test/src/dart/analysis/analyzer_state_printer.dart b/pkg/analyzer/test/src/dart/analysis/analyzer_state_printer.dart
index 3580fac..f55b678 100644
--- a/pkg/analyzer/test/src/dart/analysis/analyzer_state_printer.dart
+++ b/pkg/analyzer/test/src/dart/analysis/analyzer_state_printer.dart
@@ -111,7 +111,7 @@
           }
           sink.writeln();
         } else if (import is ImportAugmentationWithUri) {
-          final uriStr = _stringOfUriStr(import.uriStr);
+          final uriStr = _stringOfUriStr(import.uri.relativeUriStr);
           _writelnWithIndent('uri: $uriStr');
         } else {
           _writelnWithIndent('noUri');
@@ -204,7 +204,7 @@
           }
           sink.writeln();
         } else if (export is ExportDirectiveWithUri) {
-          final uriStr = _stringOfUriStr(export.selectedUriStr);
+          final uriStr = _stringOfUriStr(export.selectedUri.relativeUriStr);
           _writelnWithIndent('uri: $uriStr');
         } else {
           _writelnWithIndent('noUri');
@@ -255,8 +255,9 @@
           }
           sink.writeln();
         } else if (import is ImportDirectiveWithUri) {
+          final uriStr = _stringOfUriStr(import.selectedUri.relativeUriStr);
           sink.write(_indent);
-          sink.write('uri: ${_stringOfUriStr(import.selectedUriStr)}');
+          sink.write('uri: $uriStr');
           if (import.isSyntheticDartCoreImport) {
             sink.write(' synthetic');
           }
@@ -553,7 +554,7 @@
         }
         sink.writeln();
       } else if (part is PartDirectiveWithUri) {
-        final uriStr = _stringOfUriStr(part.uriStr);
+        final uriStr = _stringOfUriStr(part.uri.relativeUriStr);
         _writelnWithIndent('uri: $uriStr');
       } else {
         _writelnWithIndent('noUri');
diff --git a/pkg/analyzer/test/src/dart/analysis/session_test.dart b/pkg/analyzer/test/src/dart/analysis/session_test.dart
index 3c9ebab..40c4384 100644
--- a/pkg/analyzer/test/src/dart/analysis/session_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/session_test.dart
@@ -670,19 +670,11 @@
     var session = contextFor(testFilePath).currentSession;
     var resolvedLibrary = await session.getResolvedLibraryValid(test.path);
 
-    expect(resolvedLibrary.units, hasLength(3));
+    expect(resolvedLibrary.units, hasLength(1));
     expect(
       resolvedLibrary.units[0].path,
       convertPath('/home/test/lib/test.dart'),
     );
-    expect(
-      resolvedLibrary.units[1].path,
-      convertPath('/home/test/lib/a.dart'),
-    );
-    expect(
-      resolvedLibrary.units[2].path,
-      convertPath('/home/test/lib/c.dart'),
-    );
   }
 
   test_getResolvedLibrary_invalidPath_notAbsolute() async {
diff --git a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
index 9a9a099..9fd743c 100644
--- a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
@@ -105,6 +105,16 @@
             TokenType.EQ, AstTestFactory.identifier3("b")));
   }
 
+  void test_visitAugmentationImportDirective() {
+    var findNode = _parseStringToFindNode(r'''
+import augment 'a.dart';
+''');
+    _assertSource(
+      "import augment 'a.dart';",
+      findNode.augmentationImportDirective('import'),
+    );
+  }
+
   void test_visitAwaitExpression() {
     var findNode = _parseStringToFindNode(r'''
 void f() async => await e;
diff --git a/pkg/analyzer/test/src/diagnostics/uri_does_not_exist_test.dart b/pkg/analyzer/test/src/diagnostics/uri_does_not_exist_test.dart
index 8bf563c..0486dd4 100644
--- a/pkg/analyzer/test/src/diagnostics/uri_does_not_exist_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/uri_does_not_exist_test.dart
@@ -34,11 +34,19 @@
     ]);
   }
 
+  test_export_cannotResolve() async {
+    await assertErrorsInCode(r'''
+export 'dart:foo';
+''', [
+      error(CompileTimeErrorCode.URI_DOES_NOT_EXIST, 7, 10),
+    ]);
+  }
+
   test_export_dart() async {
     await assertErrorsInCode('''
-export 'dart:foo/bar.dart';
+export 'dart:math/bar.dart';
 ''', [
-      error(CompileTimeErrorCode.URI_DOES_NOT_EXIST, 7, 19),
+      error(CompileTimeErrorCode.URI_DOES_NOT_EXIST, 7, 20),
     ]);
   }
 
@@ -72,11 +80,19 @@
     ]);
   }
 
+  test_import_cannotResolve() async {
+    await assertErrorsInCode(r'''
+import 'dart:foo';
+''', [
+      error(CompileTimeErrorCode.URI_DOES_NOT_EXIST, 7, 10),
+    ]);
+  }
+
   test_import_dart() async {
     await assertErrorsInCode('''
-import 'dart:foo/bar.dart';
+import 'dart:math/bar.dart';
 ''', [
-      error(CompileTimeErrorCode.URI_DOES_NOT_EXIST, 7, 19),
+      error(CompileTimeErrorCode.URI_DOES_NOT_EXIST, 7, 20),
     ]);
   }
 
@@ -107,4 +123,12 @@
       error(CompileTimeErrorCode.URI_DOES_NOT_EXIST, 18, 14),
     ]);
   }
+
+  test_part_cannotResolve() async {
+    await assertErrorsInCode(r'''
+part 'dart:foo';
+''', [
+      error(CompileTimeErrorCode.URI_DOES_NOT_EXIST, 5, 10),
+    ]);
+  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/uri_with_interpolation_test.dart b/pkg/analyzer/test/src/diagnostics/uri_with_interpolation_test.dart
index f637890..a011990 100644
--- a/pkg/analyzer/test/src/diagnostics/uri_with_interpolation_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/uri_with_interpolation_test.dart
@@ -15,21 +15,27 @@
 
 @reflectiveTest
 class UriWithInterpolationTest extends PubPackageResolutionTest {
-  test_constant() async {
-    await assertErrorsInCode('''
-import 'stuff_\$platform.dart';
+  test_export() async {
+    await assertErrorsInCode(r'''
+export '${'foo'}.dart';
 ''', [
-      error(CompileTimeErrorCode.URI_WITH_INTERPOLATION, 7, 22),
-      error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 15, 8),
+      error(CompileTimeErrorCode.URI_WITH_INTERPOLATION, 7, 15),
     ]);
   }
 
-  test_nonConstant() async {
+  test_import() async {
     await assertErrorsInCode(r'''
-library lib;
-part '${'a'}.dart';
+import '${'foo'}.dart';
 ''', [
-      error(CompileTimeErrorCode.URI_WITH_INTERPOLATION, 18, 13),
+      error(CompileTimeErrorCode.URI_WITH_INTERPOLATION, 7, 15),
+    ]);
+  }
+
+  test_part() async {
+    await assertErrorsInCode(r'''
+part '${'foo'}.dart';
+''', [
+      error(CompileTimeErrorCode.URI_WITH_INTERPOLATION, 5, 15),
     ]);
   }
 }
diff --git a/pkg/compiler/pubspec.yaml b/pkg/compiler/pubspec.yaml
index ff1ae62..d25829f 100644
--- a/pkg/compiler/pubspec.yaml
+++ b/pkg/compiler/pubspec.yaml
@@ -34,3 +34,4 @@
   modular_test: any
   sourcemap_testing: any
   testing: any
+  vm: any
diff --git a/pkg/compiler/tool/null_safety/candidates.dart b/pkg/compiler/tool/null_safety/candidates.dart
new file mode 100644
index 0000000..6dc4dde
--- /dev/null
+++ b/pkg/compiler/tool/null_safety/candidates.dart
@@ -0,0 +1,152 @@
+// 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.
+
+/// Script to identify good opportunities for null safety migration.
+///
+/// This script sorts libraries based on a "migratable" order. We compute
+/// this order by counting how many of a library's dependencies have been
+/// migrated.
+
+import 'dart:io';
+
+import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
+import 'package:_fe_analyzer_shared/src/parser/parser.dart';
+import 'package:_fe_analyzer_shared/src/scanner/io.dart'
+    show readBytesFromFileSync;
+import 'package:_fe_analyzer_shared/src/scanner/scanner.dart';
+import 'package:front_end/src/api_prototype/front_end.dart';
+import 'package:front_end/src/api_prototype/language_version.dart';
+import 'package:front_end/src/api_prototype/terminal_color_support.dart'
+    show printDiagnosticMessage;
+import 'package:front_end/src/base/processed_options.dart';
+import 'package:front_end/src/fasta/compiler_context.dart';
+import 'package:front_end/src/fasta/source/diet_parser.dart';
+import 'package:front_end/src/fasta/source/directive_listener.dart';
+import 'package:front_end/src/fasta/uri_translator.dart' show UriTranslator;
+import 'package:kernel/target/targets.dart' show TargetFlags;
+import 'package:vm/target/vm.dart' show VmTarget;
+
+void main(List<String> args) async {
+  var prefix = args.isEmpty ? 'pkg/compiler/' : args.first;
+  var files = <Uri, List<int>>{};
+  var isLegacy = <Uri>{};
+  var isNullSafe = <Uri>{};
+
+  var entryUri = Uri.parse('package:compiler/src/dart2js.dart');
+  var options = CompilerOptions()
+    ..sdkRoot = Uri.base.resolve("sdk/")
+    ..onDiagnostic = _onDiagnosticMessageHandler
+    ..compileSdk = true
+    ..packagesFileUri = Uri.base.resolve('.dart_tool/package_config.json')
+    ..target = VmTarget(TargetFlags());
+  var pOptions = ProcessedOptions(options: options);
+  var uriResolver = await pOptions.getUriTranslator();
+  var context = CompilerContext(pOptions);
+  await context.runInContext((_) async {
+    collectSources(uriResolver, entryUri, files);
+  });
+
+  for (var file in files.keys) {
+    if (await uriUsesLegacyLanguageVersion(file, options)) {
+      isLegacy.add(file);
+    } else {
+      isNullSafe.add(file);
+    }
+  }
+
+  var fileSummary = <Uri, FileData>{};
+  for (var file in files.keys) {
+    if (!file.path.contains(prefix)) continue;
+    var directives = extractDirectiveUris(files[file]!)
+        .map(file.resolve)
+        .where((uri) => uri.path.contains('pkg/compiler/'));
+    var migrated = directives.where(isNullSafe.contains).length;
+    var total = directives.length;
+    fileSummary[file] = FileData(isNullSafe.contains(file), total, migrated);
+  }
+
+  var keys = fileSummary.keys.toList();
+  keys.sort((a, b) {
+    var fa = fileSummary[a]!;
+    var fb = fileSummary[b]!;
+    if (fa.isNullSafe && !fb.isNullSafe) return -1;
+    if (fb.isNullSafe && !fa.isNullSafe) return 1;
+    if (fa.totalDependencies == 0 && fb.totalDependencies != 0) return -1;
+    if (fb.totalDependencies == 0 && fa.totalDependencies != 0) return 1;
+    if (fa.ratio != fb.ratio) return fb.ratio.compareTo(fa.ratio);
+    return fb.migratedDependencies.compareTo(fb.migratedDependencies);
+  });
+
+  for (var file in keys) {
+    var data = fileSummary[file]!;
+    String status;
+    String text = shorten(file);
+    if (data.isNullSafe) {
+      status = '\x1b[33mmigrated ---\x1b[0m | $text';
+    } else if (data.totalDependencies == 0) {
+      status = '\x1b[32mready    ---\x1b[0m | $text';
+    } else if (data.ratio == 1.0) {
+      status = '\x1b[32mready   100%\x1b[0m | $text';
+    } else {
+      var perc = (data.ratio * 100).toStringAsFixed(0).padLeft(3);
+      status = '\x1b[31mwait    $perc%\x1b[0m'
+          ' | $text [${data.migratedDependencies} / ${data.totalDependencies}]';
+    }
+    print(status);
+  }
+}
+
+class FileData {
+  final bool isNullSafe;
+  final int totalDependencies;
+  final int migratedDependencies;
+
+  double get ratio => migratedDependencies / totalDependencies;
+  FileData(this.isNullSafe, this.totalDependencies, this.migratedDependencies);
+}
+
+void _onDiagnosticMessageHandler(DiagnosticMessage m) {
+  if (m.severity == Severity.internalProblem || m.severity == Severity.error) {
+    printDiagnosticMessage(m, stderr.writeln);
+    exitCode = 1;
+  }
+}
+
+/// Add to [files] all sources reachable from [start].
+void collectSources(
+    UriTranslator uriResolver, Uri start, Map<Uri, List<int>> files) {
+  void helper(Uri uri) {
+    if (uri.scheme == 'dart') return;
+    uri = uriResolver.translate(uri) ?? uri;
+    if (!uri.path.contains('pkg/compiler/')) return;
+    if (files.containsKey(uri)) return;
+    var contents = readBytesFromFileSync(uri);
+    files[uri] = contents;
+    for (var directiveUri in extractDirectiveUris(contents)) {
+      helper(uri.resolve(directiveUri));
+    }
+  }
+
+  helper(start);
+}
+
+/// Parse [contents] as a Dart program and return the URIs that appear in its
+/// import, export, and part directives.
+Set<String> extractDirectiveUris(List<int> contents) {
+  var listener = new DirectiveListener();
+  new TopLevelParser(listener,
+          useImplicitCreationExpression: useImplicitCreationExpressionInCfe)
+      .parseUnit(scan(contents).tokens);
+  // Note: this purposely ignores part files (listener.parts).
+  return new Set<String>()
+    ..addAll(listener.imports.map((directive) => directive.uri!))
+    ..addAll(listener.exports.map((directive) => directive.uri!));
+}
+
+String shorten(Uri uri) {
+  if (uri.scheme != 'file') return uri.toString();
+  final prefix = Uri.base.path;
+  if (uri.path.startsWith(prefix)) return uri.path.substring(prefix.length);
+  return uri.toString();
+}
diff --git a/pkg/compiler/tool/null_safety/tally.dart b/pkg/compiler/tool/null_safety/tally.dart
new file mode 100644
index 0000000..33a2d1a
--- /dev/null
+++ b/pkg/compiler/tool/null_safety/tally.dart
@@ -0,0 +1,91 @@
+// 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.
+
+/// Script to count progress of the pkg/compiler/lib/ migration
+
+import 'dart:io';
+
+void main(List<String> args) {
+  var path = args.isEmpty ? 'pkg/compiler/lib/' : args.first;
+  var dart2jsDir = Directory.fromUri(Uri.base.resolve(path));
+  var entries = <FileData>[];
+  for (var file in dart2jsDir.listSync(recursive: true)) {
+    if (file is File && file.uri.path.endsWith('.dart')) {
+      entries.add(FileData(file));
+    }
+  }
+
+  var tally = Tally();
+  for (var e in entries) {
+    tally.totalFiles++;
+    tally.totalBytes += e.sizeBytes;
+    tally.totalLOC += e.sizeLOC;
+    if (e.nullSafe) {
+      tally.migratedFiles++;
+      tally.migratedBytes += e.sizeBytes;
+      tally.migratedLOC += e.sizeLOC;
+    }
+  }
+
+  print(tally.formatString());
+  //print(tally.csvRow());
+}
+
+/// Details about each file in the package to properly count migration progress.
+class FileData {
+  final Uri path;
+  final int sizeBytes;
+  final int sizeLOC;
+  final bool nullSafe;
+
+  FileData._(this.path, this.sizeBytes, this.sizeLOC, this.nullSafe);
+
+  factory FileData(File file) {
+    var contents = file.readAsStringSync();
+    var length = contents.length;
+    var sizeLOC = '\n'.allMatches(contents).length;
+    var nullSafe = !contents.contains("// @dart = 2.10");
+    return FileData._(file.uri, length, sizeLOC, nullSafe);
+  }
+}
+
+/// Cumulative information about the status of the null safety migration.
+class Tally {
+  int totalFiles = 0;
+  int migratedFiles = 0;
+  int totalBytes = 0;
+  int migratedBytes = 0;
+  int totalLOC = 0;
+  int migratedLOC = 0;
+
+  /// Emit a readable table representation of the null safety progress.
+  String formatString() {
+    String _pad(String text, int width) {
+      return (' ' * (10 - text.length)) + text;
+    }
+
+    String _row(String name, int a, int b) {
+      var padA = _pad('$a', 10);
+      var padB = _pad('$b', 10);
+      var padC = _pad((a * 100 / b).toStringAsFixed(2), 10);
+      return '${_pad(name, 8)} $padA $padB $padC%';
+    }
+
+    return '${_pad("", 10)} ${_pad("migrated", 10)} ${_pad("total", 10)} ${_pad("%", 10)}\n'
+        '${_row('Files', migratedFiles, totalFiles)}\n'
+        '${_row('Lines', migratedLOC, totalLOC)}\n'
+        '${_row('Bytes', migratedBytes, totalBytes)}';
+  }
+
+  /// Emit a csv representation of the null safety progress, useful to track
+  /// data over time.
+  String csvRow() => [
+        totalFiles,
+        migratedFiles,
+        totalBytes,
+        migratedBytes,
+        totalLOC,
+        migratedLOC,
+      ].join(',');
+}
diff --git a/tools/VERSION b/tools/VERSION
index 8bf1802..926f549 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 18
 PATCH 0
-PRERELEASE 247
+PRERELEASE 248
 PRERELEASE_PATCH 0
\ No newline at end of file