Use PartDirectiveState(s) in LibraryFileStateKind to model parts.

Change-Id: Id0f799f73ffbb9ef1eec537819e93ed62495752c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/250021
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 6cb9aa0..26b77d4 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 = 225;
+  static const int DATA_VERSION = 226;
 
   /// 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/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index 4a45f96..f344151 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -280,7 +280,6 @@
   List<FileState?> _augmentationFiles = [];
   List<FileState?>? _importedFiles;
   List<FileState?>? _exportedFiles;
-  List<FileState?> _partedFiles = [];
   List<FileState> _libraryFiles = [];
 
   Set<FileState>? _directReferencedFiles;
@@ -331,6 +330,7 @@
 
   /// Return the set of all directly referenced files - imported, exported or
   /// parted.
+  /// TODO(scheglov) Stop using [partedFiles].
   Set<FileState> get directReferencedFiles {
     return _directReferencedFiles ??= <FileState>{
       ...importedFiles.whereNotNull(),
@@ -405,7 +405,18 @@
 
   /// The list of files this library file references as parts.
   List<FileState?> get partedFiles {
-    return _partedFiles;
+    final kind = _kind;
+    if (kind is LibraryFileStateKind) {
+      return kind.parts.map((part) {
+        if (part is PartDirectiveWithFile) {
+          return part.includedFile;
+        } else {
+          return null;
+        }
+      }).toList();
+    } else {
+      return [];
+    }
   }
 
   /// The external names referenced by the file.
@@ -666,12 +677,16 @@
   /// TODO(scheglov) Make it a method of `PartFileStateKind`?
   void _invalidatesLibrariesOfThisPart() {
     if (_kind is PartFileStateKind) {
-      for (final library in _fsState._pathToFile.values) {
-        if (library._kind is LibraryFileStateKind) {
-          if (library.partedFiles.contains(this)) {
-            final libraryKind = library.kind;
-            if (libraryKind is LibraryFileStateKind) {
-              libraryKind._libraryCycle?.invalidate();
+      final libraries = _fsState._pathToFile.values
+          .map((file) => file._kind)
+          .whereType<LibraryFileStateKind>()
+          .toList();
+
+      for (final library in libraries) {
+        for (final partDirective in library.parts) {
+          if (partDirective is PartDirectiveWithFile) {
+            if (partDirective.includedFile == this) {
+              library._libraryCycle?.invalidate();
             }
           }
         }
@@ -712,8 +727,8 @@
     for (final directive in unlinked2.exports) {
       addRelativeUri(directive.uri);
     }
-    for (final uri in unlinked2.parts) {
-      addRelativeUri(uri);
+    for (final directive in unlinked2.parts) {
+      addRelativeUri(directive.uri);
     }
 
     prefetchFiles(paths.toList());
@@ -746,7 +761,6 @@
     removeForOne(_augmentationFiles);
     removeForOne(_exportedFiles);
     removeForOne(_importedFiles);
-    removeForOne(_partedFiles);
   }
 
   void _updateAugmentationFiles() {
@@ -762,7 +776,7 @@
   }
 
   void _updateKind() {
-    _fsState._libraryNameToFiles.remove(_kind);
+    _kind?.dispose();
 
     final libraryAugmentationDirective = unlinked2.libraryAugmentationDirective;
     final libraryDirective = unlinked2.libraryDirective;
@@ -770,6 +784,7 @@
     final partOfUriDirective = unlinked2.partOfUriDirective;
     if (libraryAugmentationDirective != null) {
       final uri = libraryAugmentationDirective.uri;
+      // TODO(scheglov) This could be a useful method of `Either`.
       final uriFile = _fileForRelativeUri(uri).map(
         (file) => file,
         (_) => null,
@@ -825,17 +840,8 @@
     _invalidatesLibrariesOfThisPart();
   }
 
+  /// TODO(scheglov) Stop using [partedFiles].
   void _updatePartedFiles() {
-    _partedFiles = unlinked2.parts.map((uri) {
-      return _fileForRelativeUri(uri).map(
-        (part) {
-          part?.referencingFiles.add(this);
-          return part;
-        },
-        (_) => null,
-      );
-    }).toList();
-
     _libraryFiles = [
       this,
       ...partedFiles.whereNotNull(),
@@ -850,7 +856,7 @@
     var augmentations = <UnlinkedImportAugmentationDirective>[];
     var exports = <UnlinkedNamespaceDirective>[];
     var imports = <UnlinkedNamespaceDirective>[];
-    var parts = <String>[];
+    var parts = <UnlinkedPartDirective>[];
     var macroClasses = <MacroClass>[];
     var hasDartCoreImport = false;
     for (var directive in unit.directives) {
@@ -888,8 +894,11 @@
           name: directive.name.name,
         );
       } else if (directive is PartDirective) {
-        var uriStr = directive.uri.stringValue;
-        parts.add(uriStr ?? '');
+        parts.add(
+          UnlinkedPartDirective(
+            uri: directive.uri.stringValue ?? '',
+          ),
+        );
       } else if (directive is PartOfDirective) {
         final libraryName = directive.libraryName;
         final uri = directive.uri;
@@ -1587,6 +1596,8 @@
   /// Or `null` if no `library` directive.
   final String? name;
 
+  List<PartDirectiveState>? _parts;
+
   LibraryCycle? _libraryCycle;
 
   LibraryFileStateKind({
@@ -1609,13 +1620,59 @@
     return _libraryCycle!;
   }
 
+  List<PartDirectiveState> get parts {
+    return _parts ??= file.unlinked2.parts.map((directive) {
+      return file._fileForRelativeUri(directive.uri).map(
+        (refFile) {
+          if (refFile != null) {
+            refFile.referencingFiles.add(file);
+            return PartDirectiveWithFile(
+              library: this,
+              directive: directive,
+              includedFile: refFile,
+            );
+          } else {
+            return PartDirectiveState(
+              library: this,
+              directive: directive,
+            );
+          }
+        },
+        (externalLibrary) {
+          return PartDirectiveState(
+            library: this,
+            directive: directive,
+          );
+        },
+      );
+    }).toList();
+  }
+
   @override
   void dispose() {
     invalidateLibraryCycle();
+
+    final parts = _parts;
+    if (parts != null) {
+      for (final part in parts) {
+        if (part is PartDirectiveWithFile) {
+          part.includedFile.referencingFiles.remove(file);
+        }
+      }
+    }
+
+    file._fsState._libraryNameToFiles.remove(this);
   }
 
-  bool hasPart(PartFileStateKind part) {
-    return file.partedFiles.contains(part.file);
+  bool hasPart(PartFileStateKind partKind) {
+    for (final partDirective in parts) {
+      if (partDirective is PartDirectiveWithFile) {
+        if (partDirective.includedFile == partKind.file) {
+          return true;
+        }
+      }
+    }
+    return false;
   }
 
   void internal_setLibraryCycle(LibraryCycle? cycle) {
@@ -1695,11 +1752,54 @@
   }
 }
 
+/// Information about a single `part` directive.
+class PartDirectiveState {
+  final LibraryFileStateKind library;
+  final UnlinkedPartDirective directive;
+
+  PartDirectiveState({
+    required this.library,
+    required this.directive,
+  });
+
+  /// Returns a [Source] that is referenced by this directive.
+  ///
+  /// Returns `null` if the URI cannot be resolved into a [Source].
+  Source? get includedSource => null;
+}
+
+/// [PartDirectiveState] that has a valid URI that references a file.
+class PartDirectiveWithFile extends PartDirectiveState {
+  final FileState includedFile;
+
+  PartDirectiveWithFile({
+    required super.library,
+    required super.directive,
+    required this.includedFile,
+  });
+
+  /// If [includedFile] is a [PartFileStateKind], and it confirms that it
+  /// is a part of the [library], returns the [includedFile].
+  PartFileStateKind? get includedPart {
+    final kind = includedFile.kind;
+    if (kind is PartFileStateKind && kind.isPartOf(library)) {
+      return kind;
+    }
+    return null;
+  }
+
+  @override
+  Source? get includedSource => includedFile.source;
+}
+
 /// The file has `part of` directive.
 abstract class PartFileStateKind extends FileStateKind {
   PartFileStateKind({
     required super.file,
   });
+
+  /// Returns `true` if the `part of` directive confirms the [library].
+  bool isPartOf(LibraryFileStateKind library);
 }
 
 /// The file has `part of name` directive.
@@ -1757,6 +1857,11 @@
       }
     }
   }
+
+  @override
+  bool isPartOf(LibraryFileStateKind library) {
+    return directive.name == library.name;
+  }
 }
 
 /// The file has `part of URI` directive.
@@ -1789,6 +1894,11 @@
     }
     return null;
   }
+
+  @override
+  bool isPartOf(LibraryFileStateKind library) {
+    return uriFile == library.file;
+  }
 }
 
 /// The file has `part of URI` directive, and the URI cannot be resolved.
@@ -1800,6 +1910,9 @@
 
   @override
   LibraryFileStateKind? get library => null;
+
+  @override
+  bool isPartOf(LibraryFileStateKind library) => false;
 }
 
 class StoredFileContent implements FileContent {
@@ -1849,6 +1962,7 @@
   }
 
   /// If [kind] is a named library, register it.
+  /// TODO(scheglov) Use [LibraryFileStateKind]
   void add(FileStateKind? kind) {
     if (kind is LibraryFileStateKind) {
       final name = kind.name;
@@ -1864,6 +1978,7 @@
   }
 
   /// If [kind] is a named library, unregister it.
+  /// TODO(scheglov) Use [LibraryFileStateKind]
   void remove(FileStateKind? kind) {
     if (kind is LibraryFileStateKind) {
       final name = kind.name;
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index d6d1f1e..bbadd99 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -651,11 +651,16 @@
       } else if (directive is PartDirectiveImpl) {
         StringLiteral partUri = directive.uri;
 
-        var partFile = _library.file.partedFiles[partDirectiveIndex++];
-        if (partFile == null) {
+        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;
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_context.dart b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
index 7d7b781..f1c3600 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_context.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
@@ -193,7 +193,7 @@
 
             String? partUriStr;
             if (partIndex >= 0) {
-              partUriStr = libraryFile.unlinked2.parts[partIndex];
+              partUriStr = libraryFile.unlinked2.parts[partIndex].uri;
             }
             partIndex++;
 
diff --git a/pkg/analyzer/lib/src/dart/analysis/unlinked_data.dart b/pkg/analyzer/lib/src/dart/analysis/unlinked_data.dart
index 18152a3..41dc29c 100644
--- a/pkg/analyzer/lib/src/dart/analysis/unlinked_data.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/unlinked_data.dart
@@ -228,6 +228,26 @@
   }
 }
 
+class UnlinkedPartDirective {
+  final String uri;
+
+  UnlinkedPartDirective({
+    required this.uri,
+  });
+
+  factory UnlinkedPartDirective.read(
+    SummaryDataReader reader,
+  ) {
+    return UnlinkedPartDirective(
+      uri: reader.readStringUtf8(),
+    );
+  }
+
+  void write(BufferedSink sink) {
+    sink.writeStringUtf8(uri);
+  }
+}
+
 class UnlinkedPartOfNameDirective {
   final String name;
   final UnlinkedSourceRange nameRange;
@@ -313,10 +333,10 @@
   /// `import augmentation` directives.
   final List<UnlinkedImportAugmentationDirective> augmentations;
 
-  /// URIs of `export` directives.
+  /// `export` directives.
   final List<UnlinkedNamespaceDirective> exports;
 
-  /// URIs of `import` directives.
+  /// `import` directives.
   final List<UnlinkedNamespaceDirective> imports;
 
   /// Encoded informative data.
@@ -334,8 +354,8 @@
   /// The list of `macro` classes.
   final List<MacroClass> macroClasses;
 
-  /// URIs of `part` directives.
-  final List<String> parts;
+  /// `part` directives.
+  final List<UnlinkedPartDirective> parts;
 
   /// The `part of my.name';` directive.
   final UnlinkedPartOfNameDirective? partOfNameDirective;
@@ -385,7 +405,9 @@
       macroClasses: reader.readTypedList(
         () => MacroClass.read(reader),
       ),
-      parts: reader.readStringUtf8List(),
+      parts: reader.readTypedList(
+        () => UnlinkedPartDirective.read(reader),
+      ),
       partOfNameDirective: reader.readOptionalObject(
         UnlinkedPartOfNameDirective.read,
       ),
@@ -420,7 +442,9 @@
     sink.writeList<MacroClass>(macroClasses, (x) {
       x.write(sink);
     });
-    sink.writeStringUtf8Iterable(parts);
+    sink.writeList<UnlinkedPartDirective>(parts, (x) {
+      x.write(sink);
+    });
     sink.writeOptionalObject<UnlinkedPartOfNameDirective>(
       partOfNameDirective,
       (x) => x.write(sink),
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 62534d7..a791c54 100644
--- a/pkg/analyzer/test/src/dart/analysis/analyzer_state_printer.dart
+++ b/pkg/analyzer/test/src/dart/analysis/analyzer_state_printer.dart
@@ -77,6 +77,14 @@
     return idProvider.libraryCycle(cycle);
   }
 
+  String _stringOfUriStr(String uriStr) {
+    if (uriStr.trim().isEmpty) {
+      return "'$uriStr'";
+    } else {
+      return uriStr;
+    }
+  }
+
   void _withIndent(void Function() f) {
     var indent = _indent;
     _indent = '$_indent  ';
@@ -174,7 +182,7 @@
         sink.writeln();
       } else {
         sink.write(_indent);
-        sink.write('uri: ${export.directive.uri}');
+        sink.write('uri: ${_stringOfUriStr(export.directive.uri)}');
         sink.writeln();
       }
     });
@@ -219,7 +227,7 @@
         sink.writeln();
       } else {
         sink.write(_indent);
-        sink.write('uri: ${import.directive.uri}');
+        sink.write('uri: ${_stringOfUriStr(import.directive.uri)}');
         if (import.isSyntheticDartCoreImport) {
           sink.write(' synthetic');
         }
@@ -505,13 +513,27 @@
     });
   }
 
-  /// TODO(scheglov) Support unresolved URIs, not parts, etc.
   void _writeLibraryParts(LibraryFileStateKind library) {
-    final parts = library.file.partedFiles.whereNotNull();
-    if (parts.isNotEmpty) {
-      final partKeys = parts.map(idProvider.fileState).join(' ');
-      _writelnWithIndent('parts: $partKeys');
-    }
+    _writeElements<PartDirectiveState>('parts', library.parts, (part) {
+      expect(part.library, same(library));
+      if (part is PartDirectiveWithFile) {
+        final file = part.includedFile;
+        sink.write(_indent);
+
+        final includedPart = part.includedPart;
+        if (includedPart != null) {
+          expect(includedPart.file, file);
+          sink.write(idProvider.fileStateKind(includedPart));
+        } else {
+          sink.write('notPart ${idProvider.fileState(file)}');
+        }
+        sink.writeln();
+      } else {
+        sink.write(_indent);
+        sink.write('uri: ${_stringOfUriStr(part.directive.uri)}');
+        sink.writeln();
+      }
+    });
   }
 
   void _writelnWithIndent(String line) {
diff --git a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
index 7c46946..96095cf 100644
--- a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
@@ -14,7 +14,6 @@
 import 'package:analyzer/src/dart/analysis/feature_set_provider.dart';
 import 'package:analyzer/src/dart/analysis/file_content_cache.dart';
 import 'package:analyzer/src/dart/analysis/file_state.dart';
-import 'package:analyzer/src/dart/analysis/library_graph.dart';
 import 'package:analyzer/src/dart/analysis/performance_logger.dart';
 import 'package:analyzer/src/dart/sdk/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -1656,6 +1655,34 @@
 ''');
   }
 
+  test_newFile_library_exports_invalidRelativeUri_empty() {
+    final a = newFile('$testPackageLibPath/a.dart', r'''
+export '';
+''');
+
+    fileStateFor(a);
+
+    assertDriverStateString(testFile, r'''
+files
+  /home/test/lib/a.dart
+    uri: package:test/a.dart
+    current
+      id: file_0
+      kind: library_0
+        imports
+          library_1 dart:core synthetic
+        exports
+          uri: ''
+        cycle_0
+          dependencies: dart:core
+          libraries: library_0
+          apiSignature_0
+      unlinkedKey: k00
+libraryCycles
+elementFactory
+''');
+  }
+
   test_newFile_library_exports_package() async {
     final c = newFile('$testPackageLibPath/c.dart', r'''
 export 'a.dart';
@@ -1834,6 +1861,33 @@
 ''');
   }
 
+  test_newFile_library_imports_invalidRelativeUri_empty() {
+    final a = newFile('$testPackageLibPath/a.dart', r'''
+import '';
+''');
+
+    fileStateFor(a);
+
+    assertDriverStateString(testFile, r'''
+files
+  /home/test/lib/a.dart
+    uri: package:test/a.dart
+    current
+      id: file_0
+      kind: library_0
+        imports
+          uri: ''
+          library_1 dart:core synthetic
+        cycle_0
+          dependencies: dart:core
+          libraries: library_0
+          apiSignature_0
+      unlinkedKey: k00
+libraryCycles
+elementFactory
+''');
+  }
+
   test_newFile_library_imports_library_dart() async {
     final a = newFile('$testPackageLibPath/a.dart', r'''
 import 'dart:async';
@@ -2231,7 +2285,8 @@
       kind: library_0
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          notPart file_1
         cycle_0
           dependencies: dart:core
           libraries: library_0
@@ -2265,7 +2320,8 @@
       kind: library_7
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          notPart file_1
         cycle_3
           dependencies: dart:core
           libraries: library_7
@@ -2289,6 +2345,204 @@
 ''');
   }
 
+  test_newFile_library_parts_invalidRelativeUri() {
+    final a = newFile('$testPackageLibPath/a.dart', r'''
+part 'da:';
+''');
+
+    fileStateFor(a);
+
+    assertDriverStateString(testFile, r'''
+files
+  /home/test/lib/a.dart
+    uri: package:test/a.dart
+    current
+      id: file_0
+      kind: library_0
+        imports
+          library_1 dart:core synthetic
+        parts
+          uri: da:
+        cycle_0
+          dependencies: dart:core
+          libraries: library_0
+          apiSignature_0
+      unlinkedKey: k00
+libraryCycles
+elementFactory
+''');
+  }
+
+  test_newFile_library_parts_invalidRelativeUri_empty() {
+    final a = newFile('$testPackageLibPath/a.dart', r'''
+part '';
+''');
+
+    fileStateFor(a);
+
+    assertDriverStateString(testFile, r'''
+files
+  /home/test/lib/a.dart
+    uri: package:test/a.dart
+    current
+      id: file_0
+      kind: library_0
+        imports
+          library_1 dart:core synthetic
+        parts
+          uri: ''
+        cycle_0
+          dependencies: dart:core
+          libraries: library_0
+          apiSignature_0
+      unlinkedKey: k00
+libraryCycles
+elementFactory
+''');
+  }
+
+  test_newFile_library_parts_ofUri_two() {
+    final a = newFile('$testPackageLibPath/a.dart', r'''
+part of 'c.dart';
+class A {}
+''');
+
+    final b = newFile('$testPackageLibPath/b.dart', r'''
+part of 'c.dart';
+class B {}
+''');
+
+    final c = newFile('$testPackageLibPath/c.dart', r'''
+part 'a.dart';
+part 'b.dart';
+''');
+
+    fileStateFor(c);
+
+    assertDriverStateString(testFile, r'''
+files
+  /home/test/lib/a.dart
+    uri: package:test/a.dart
+    current
+      id: file_0
+      kind: partOfUriKnown_0
+        library: library_2
+      referencingFiles: file_2
+      unlinkedKey: k00
+  /home/test/lib/b.dart
+    uri: package:test/b.dart
+    current
+      id: file_1
+      kind: partOfUriKnown_1
+        library: library_2
+      referencingFiles: file_2
+      unlinkedKey: k01
+  /home/test/lib/c.dart
+    uri: package:test/c.dart
+    current
+      id: file_2
+      kind: library_2
+        imports
+          library_3 dart:core synthetic
+        parts
+          partOfUriKnown_0
+          partOfUriKnown_1
+        cycle_0
+          dependencies: dart:core
+          libraries: library_2
+          apiSignature_0
+      unlinkedKey: k02
+libraryCycles
+elementFactory
+''');
+
+    // Update `a.dart`, updates the library.
+    newFile(a.path, r'''
+part of 'c.dart';
+class A2 {}
+''');
+    fileStateFor(a).refresh();
+    assertDriverStateString(testFile, r'''
+files
+  /home/test/lib/a.dart
+    uri: package:test/a.dart
+    current
+      id: file_0
+      kind: partOfUriKnown_8
+        library: library_2
+      referencingFiles: file_2
+      unlinkedKey: k03
+  /home/test/lib/b.dart
+    uri: package:test/b.dart
+    current
+      id: file_1
+      kind: partOfUriKnown_1
+        library: library_2
+      referencingFiles: file_2
+      unlinkedKey: k01
+  /home/test/lib/c.dart
+    uri: package:test/c.dart
+    current
+      id: file_2
+      kind: library_2
+        imports
+          library_3 dart:core synthetic
+        parts
+          partOfUriKnown_8
+          partOfUriKnown_1
+        cycle_2
+          dependencies: dart:core
+          libraries: library_2
+          apiSignature_1
+      unlinkedKey: k02
+libraryCycles
+elementFactory
+''');
+
+    // Update `b.dart`, updates the library.
+    newFile(b.path, r'''
+part of 'c.dart';
+class B2 {}
+''');
+    fileStateFor(b).refresh();
+    assertDriverStateString(testFile, r'''
+files
+  /home/test/lib/a.dart
+    uri: package:test/a.dart
+    current
+      id: file_0
+      kind: partOfUriKnown_8
+        library: library_2
+      referencingFiles: file_2
+      unlinkedKey: k03
+  /home/test/lib/b.dart
+    uri: package:test/b.dart
+    current
+      id: file_1
+      kind: partOfUriKnown_9
+        library: library_2
+      referencingFiles: file_2
+      unlinkedKey: k04
+  /home/test/lib/c.dart
+    uri: package:test/c.dart
+    current
+      id: file_2
+      kind: library_2
+        imports
+          library_3 dart:core synthetic
+        parts
+          partOfUriKnown_8
+          partOfUriKnown_9
+        cycle_3
+          dependencies: dart:core
+          libraries: library_2
+          apiSignature_2
+      unlinkedKey: k02
+libraryCycles
+elementFactory
+''');
+  }
+
   test_newFile_libraryDirective() async {
     final a = newFile('$testPackageLibPath/a.dart', r'''
 library my;
@@ -2391,7 +2645,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_0
+        parts
+          partOfName_0
         cycle_0
           dependencies: dart:core
           libraries: library_1
@@ -2425,7 +2680,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          notPart file_1
         cycle_0
           dependencies: dart:core
           libraries: library_0
@@ -2458,7 +2714,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          notPart file_1
         cycle_0
           dependencies: dart:core
           libraries: library_0
@@ -2505,7 +2762,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfName_1
         cycle_0
           dependencies: dart:core
           libraries: library_0
@@ -2537,7 +2795,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfName_1
         cycle_0
           dependencies: dart:core
           libraries: library_0
@@ -2551,7 +2810,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfName_1
         cycle_2
           dependencies: dart:core
           libraries: library_7
@@ -2582,7 +2842,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfName_1
         cycle_0
           dependencies: dart:core
           libraries: library_0
@@ -2596,7 +2857,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfName_1
         cycle_3
           dependencies: dart:core
           libraries: library_8
@@ -2627,7 +2889,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfName_1
         cycle_4
           dependencies: dart:core
           libraries: library_9
@@ -2641,7 +2904,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfName_1
         cycle_3
           dependencies: dart:core
           libraries: library_8
@@ -2685,7 +2949,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfName_1
         cycle_3
           dependencies: dart:core
           libraries: library_8
@@ -2772,7 +3037,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfName_1
         cycle_7
           dependencies: dart:core
           libraries: library_12
@@ -2807,7 +3073,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfName_1
         cycle_8
           dependencies: dart:core
           libraries: library_13
@@ -2821,7 +3088,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfName_1
         cycle_7
           dependencies: dart:core
           libraries: library_12
@@ -2898,7 +3166,8 @@
       kind: library_7
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfUriKnown_1
         cycle_2
           dependencies: dart:core
           libraries: library_7
@@ -2927,7 +3196,8 @@
       kind: library_7
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfUriKnown_8
         cycle_3
           dependencies: dart:core
           libraries: library_7
@@ -2968,7 +3238,8 @@
       kind: library_0
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfUriKnown_1
         cycle_0
           dependencies: dart:core
           libraries: library_0
@@ -2997,7 +3268,8 @@
       kind: library_0
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfUriKnown_7
         cycle_2
           dependencies: dart:core
           libraries: library_0
@@ -3091,7 +3363,8 @@
       kind: library_1
         imports
           library_2 dart:core synthetic
-        parts: file_0
+        parts
+          notPart file_0
         cycle_0
           dependencies: dart:core
           libraries: library_1
@@ -3119,12 +3392,11 @@
 part 'c.dart';
 ''');
 
-    final c = newFile('$testPackageLibPath/c.dart', r'''
+    newFile('$testPackageLibPath/c.dart', r'''
 part of 'a.dart';
 ''');
 
     final aState = fileStateFor(a);
-    _assertPartedFiles(aState, [c]);
 
     // We set the library while reading `a.dart` file.
     assertDriverStateString(testFile, r'''
@@ -3136,7 +3408,8 @@
       kind: library_0
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfUriKnown_1
         cycle_0
           dependencies: dart:core
           libraries: library_0
@@ -3165,7 +3438,8 @@
       kind: library_0
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfUriKnown_1
         cycle_0
           dependencies: dart:core
           libraries: library_0
@@ -3178,7 +3452,8 @@
       kind: library_7
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          notPart file_1
         cycle_2
           dependencies: dart:core
           libraries: library_7
@@ -3207,7 +3482,8 @@
       kind: library_0
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfUriKnown_1
         cycle_0
           dependencies: dart:core
           libraries: library_0
@@ -3220,7 +3496,8 @@
       kind: library_8
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          notPart file_1
         cycle_3
           dependencies: dart:core
           libraries: library_8
@@ -3249,7 +3526,8 @@
       kind: library_9
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfUriKnown_1
         cycle_4
           dependencies: dart:core
           libraries: library_9
@@ -3262,7 +3540,8 @@
       kind: library_8
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          notPart file_1
         cycle_3
           dependencies: dart:core
           libraries: library_8
@@ -3305,7 +3584,8 @@
       kind: library_8
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          notPart file_1
         cycle_3
           dependencies: dart:core
           libraries: library_8
@@ -3389,7 +3669,8 @@
       kind: library_12
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          notPart file_1
         cycle_7
           dependencies: dart:core
           libraries: library_12
@@ -3421,7 +3702,8 @@
       kind: library_13
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfUriKnown_1
         cycle_8
           dependencies: dart:core
           libraries: library_13
@@ -3434,7 +3716,8 @@
       kind: library_12
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          notPart file_1
         cycle_7
           dependencies: dart:core
           libraries: library_12
@@ -3699,7 +3982,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfName_7
         cycle_3
           dependencies: dart:core
           libraries: library_9
@@ -3840,7 +4124,8 @@
       kind: library_9
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfUriKnown_7
         cycle_3
           dependencies: dart:core
           libraries: library_9
@@ -3905,7 +4190,9 @@
         name: my
         imports
           library_3 dart:core synthetic
-        parts: file_0 file_1
+        parts
+          partOfName_0
+          partOfName_1
         cycle_0
           dependencies: dart:core
           libraries: library_2
@@ -3949,7 +4236,8 @@
         name: my
         imports
           library_3 dart:core synthetic
-        parts: file_1
+        parts
+          partOfName_1
         cycle_2
           dependencies: dart:core
           libraries: library_8
@@ -4002,7 +4290,9 @@
       kind: library_2
         imports
           library_3 dart:core synthetic
-        parts: file_0 file_1
+        parts
+          partOfUriKnown_0
+          partOfUriKnown_1
         cycle_0
           dependencies: dart:core
           libraries: library_2
@@ -4044,7 +4334,8 @@
         name: my
         imports
           library_3 dart:core synthetic
-        parts: file_1
+        parts
+          partOfUriKnown_1
         cycle_2
           dependencies: dart:core
           libraries: library_8
@@ -4157,7 +4448,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          notPart file_1
         cycle_0
           dependencies: dart:core
           libraries: library_0
@@ -4197,7 +4489,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfName_7
         cycle_3
           dependencies: dart:core
           libraries: library_0
@@ -4284,7 +4577,8 @@
       kind: library_0
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          notPart file_1
         cycle_0
           dependencies: dart:core
           libraries: library_0
@@ -4324,7 +4618,8 @@
       kind: library_0
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfUriKnown_7
         cycle_3
           dependencies: dart:core
           libraries: library_0
@@ -4380,7 +4675,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_0
+        parts
+          partOfName_0
         cycle_0
           dependencies: dart:core
           libraries: library_1
@@ -4411,7 +4707,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_0
+        parts
+          partOfName_0
         cycle_0
           dependencies: dart:core
           libraries: library_1
@@ -4425,7 +4722,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_0
+        parts
+          partOfName_0
         cycle_2
           dependencies: dart:core
           libraries: library_7
@@ -4465,7 +4763,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_0
+        parts
+          partOfName_8
         cycle_3
           dependencies: dart:core
           libraries: library_1
@@ -4479,7 +4778,8 @@
         name: my.lib
         imports
           library_2 dart:core synthetic
-        parts: file_0
+        parts
+          partOfName_8
         cycle_4
           dependencies: dart:core
           libraries: library_7
@@ -4511,7 +4811,8 @@
       kind: library_0
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfUriKnown_1
         cycle_0
           dependencies: dart:core
           libraries: library_0
@@ -4546,7 +4847,8 @@
       kind: library_0
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          notPart file_1
         cycle_2
           dependencies: dart:core
           libraries: library_0
@@ -4602,7 +4904,8 @@
       kind: library_1
         imports
           library_2 dart:core synthetic
-        parts: file_0
+        parts
+          partOfUriKnown_0
         cycle_0
           dependencies: dart:core
           libraries: library_1
@@ -4630,7 +4933,8 @@
       kind: library_1
         imports
           library_2 dart:core synthetic
-        parts: file_0
+        parts
+          partOfUriKnown_0
         cycle_0
           dependencies: dart:core
           libraries: library_1
@@ -4643,7 +4947,8 @@
       kind: library_7
         imports
           library_2 dart:core synthetic
-        parts: file_0
+        parts
+          notPart file_0
         cycle_2
           dependencies: dart:core
           libraries: library_7
@@ -4681,7 +4986,8 @@
       kind: library_1
         imports
           library_2 dart:core synthetic
-        parts: file_0
+        parts
+          partOfUriKnown_8
         cycle_3
           dependencies: dart:core
           libraries: library_1
@@ -4694,7 +5000,8 @@
       kind: library_7
         imports
           library_2 dart:core synthetic
-        parts: file_0
+        parts
+          notPart file_0
         cycle_4
           dependencies: dart:core
           libraries: library_7
@@ -4705,15 +5012,6 @@
 ''');
   }
 
-  void _assertPartedFiles(FileState fileState, List<File> expected) {
-    final actualFiles = fileState.partedFiles.map((part) {
-      if (part != null) {
-        return getFile(part.path);
-      }
-    }).toList();
-    expect(actualFiles, expected);
-  }
-
   Future<File> _writeSdkSummary() async {
     final file = getFile('/home/summaries/sdk.sum');
     final bytes = await buildSdkSummary2(
@@ -4879,20 +5177,6 @@
         unorderedEquals(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']));
   }
 
-  test_getFileForPath_emptyUri() {
-    String path = convertPath('/test.dart');
-    newFile(path, r'''
-import '';
-export '';
-part '';
-''');
-
-    FileState file = fileSystemState.getFileForPath(path);
-    _assertIsUnresolvedFile(file.importedFiles[0]);
-    _assertIsUnresolvedFile(file.exportedFiles[0]);
-    _assertIsUnresolvedFile(file.partedFiles[0]);
-  }
-
   test_getFileForPath_hasLibraryDirective_hasPartOfDirective() {
     String a = convertPath('/test/lib/a.dart');
     newFile(a, r'''
@@ -4903,68 +5187,6 @@
     expect(file.isPart, isFalse);
   }
 
-  test_getFileForPath_invalidUri() {
-    String a = convertPath('/aaa/lib/a.dart');
-    String a1 = convertPath('/aaa/lib/a1.dart');
-    String a2 = convertPath('/aaa/lib/a2.dart');
-    String a3 = convertPath('/aaa/lib/a3.dart');
-    String content_a1 = r'''
-import 'package:aaa/a1.dart';
-import ':[invalid uri]';
-
-export 'package:aaa/a2.dart';
-export ':[invalid uri]';
-
-part 'a3.dart';
-part ':[invalid uri]';
-''';
-    newFile(a, content_a1);
-
-    FileState file = fileSystemState.getFileForPath(a);
-
-    expect(_excludeSdk(file.importedFiles), hasLength(2));
-    expect(file.importedFiles[0]!.path, a1);
-    expect(file.importedFiles[0]!.uri, Uri.parse('package:aaa/a1.dart'));
-    expect(file.importedFiles[0]!.source, isNotNull);
-    _assertIsUnresolvedFile(file.importedFiles[1]);
-
-    expect(_excludeSdk(file.exportedFiles), hasLength(2));
-    expect(file.exportedFiles[0]!.path, a2);
-    expect(file.exportedFiles[0]!.uri, Uri.parse('package:aaa/a2.dart'));
-    expect(file.exportedFiles[0]!.source, isNotNull);
-    _assertIsUnresolvedFile(file.exportedFiles[1]);
-
-    expect(_excludeSdk(file.partedFiles), hasLength(2));
-    expect(file.partedFiles[0]!.path, a3);
-    expect(file.partedFiles[0]!.uri, Uri.parse('package:aaa/a3.dart'));
-    expect(file.partedFiles[0]!.source, isNotNull);
-    _assertIsUnresolvedFile(file.partedFiles[1]);
-  }
-
-  test_getFileForPath_onlyDartFiles() {
-    String not_dart = convertPath('/test/lib/not_dart.txt');
-    String a = convertPath('/test/lib/a.dart');
-    String b = convertPath('/test/lib/b.dart');
-    String c = convertPath('/test/lib/c.dart');
-    String d = convertPath('/test/lib/d.dart');
-    newFile(a, r'''
-library lib;
-import 'dart:math';
-import 'b.dart';
-import 'not_dart.txt';
-export 'c.dart';
-export 'not_dart.txt';
-part 'd.dart';
-part 'not_dart.txt';
-''');
-    FileState file = fileSystemState.getFileForPath(a);
-    expect(_excludeSdk(file.importedFiles).map((f) => f!.path), [b, not_dart]);
-    expect(file.exportedFiles.map((f) => f!.path), [c, not_dart]);
-    expect(file.partedFiles.map((f) => f!.path), [d, not_dart]);
-    expect(_excludeSdk(fileSystemState.knownFilePaths),
-        unorderedEquals([a, b, c, d, not_dart]));
-  }
-
   test_getFileForPath_samePath() {
     String path = convertPath('/aaa/lib/a.dart');
     FileState file1 = fileSystemState.getFileForPath(path);
@@ -5188,24 +5410,6 @@
     FileState file = fileSystemState.getFileForPath(path);
     expect(file.referencedNames, unorderedEquals(['A', 'B', 'C', 'D']));
   }
-
-  void _assertIsUnresolvedFile(FileState? file) {
-    expect(file, isNull);
-  }
-
-  List<T> _excludeSdk<T>(Iterable<T> files) {
-    return files.where((file) {
-      if (file is LibraryCycle) {
-        return !file.libraries.any((file) => file.uri.isScheme('dart'));
-      } else if (file is FileState) {
-        return !file.uri.isScheme('dart');
-      } else if (file == null) {
-        return true;
-      } else {
-        return !(file as String).startsWith(convertPath('/sdk'));
-      }
-    }).toList();
-  }
 }
 
 class _GeneratedUriResolverMock extends UriResolver {
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 f0c08d1..c837ac0 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
@@ -535,7 +535,8 @@
       kind: library_0
         imports
           library_2 dart:core synthetic
-        parts: file_1
+        parts
+          partOfUriKnown_1
         cycle_0
           dependencies: dart:core
           libraries: library_0
@@ -599,7 +600,8 @@
       kind: library_7
         imports
           library_2 dart:core synthetic
-        parts: file_8
+        parts
+          partOfUriKnown_8
         cycle_2
           dependencies: dart:core
           libraries: library_7
@@ -659,7 +661,8 @@
       kind: library_0
         imports
           library_3 dart:core synthetic
-        parts: file_1
+        parts
+          partOfUriKnown_1
         cycle_0
           dependencies: dart:core
           libraries: library_0
@@ -754,7 +757,8 @@
       kind: library_8
         imports
           library_3 dart:core synthetic
-        parts: file_9
+        parts
+          partOfUriKnown_9
         cycle_3
           dependencies: dart:core
           libraries: library_8