Version 2.18.0-159.0.dev Merge commit 'e1e5cf45810fff6fa43824c713c85001a1b71bdb' into 'dev'
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart index 17a79a5..3aa510f 100644 --- a/pkg/analyzer/lib/src/dart/analysis/driver.dart +++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -86,7 +86,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 = 221; + static const int DATA_VERSION = 222; /// 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 a6763f8..66b5ac0 100644 --- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart +++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -85,6 +85,75 @@ }); } +/// Information about a single `import` directive. +class ExportDirectiveState { + final UnlinkedNamespaceDirective directive; + + ExportDirectiveState({ + required this.directive, + }); + + /// If [exportedSource] corresponds to a library, returns it. + Source? get exportedLibrarySource => null; + + /// Returns a [Source] that is referenced by this directive. If the are + /// configurations, selects the one which satisfies the conditions. + /// + /// Returns `null` if the selected URI is not valid, or cannot be resolved + /// into a [Source]. + Source? get exportedSource => null; +} + +/// [ExportDirectiveState] that has a valid URI that references a file. +class ExportDirectiveWithFile extends ExportDirectiveState { + final FileState exportedFile; + + ExportDirectiveWithFile({ + required super.directive, + required this.exportedFile, + }); + + /// Returns [exportedFile] if it is a library. + LibraryFileStateKind? get exportedLibrary { + final kind = exportedFile.kind; + if (kind is LibraryFileStateKind) { + return kind; + } + return null; + } + + @override + Source? get exportedLibrarySource { + if (exportedFile.kind is LibraryFileStateKind) { + return exportedSource; + } + return null; + } + + @override + Source get exportedSource => exportedFile.source; +} + +/// [ExportDirectiveState] with a URI that resolves to [InSummarySource]. +class ExportDirectiveWithInSummarySource extends ExportDirectiveState { + @override + final InSummarySource exportedSource; + + ExportDirectiveWithInSummarySource({ + required super.directive, + required this.exportedSource, + }); + + @override + Source? get exportedLibrarySource { + if (exportedSource.kind == InSummarySourceKind.library) { + return exportedSource; + } else { + return null; + } + } +} + /// A library from [SummaryDataStore]. class ExternalLibrary { final InSummarySource source; @@ -587,6 +656,7 @@ return unit; } + /// TODO(scheglov) move to _fsState? String _selectRelativeUri(UnlinkedNamespaceDirective directive) { for (var configuration in directive.configurations) { var name = configuration.name; @@ -805,6 +875,7 @@ imports.add( UnlinkedNamespaceDirective( configurations: [], + isSyntheticDartCoreImport: true, uri: 'dart:core', ), ); @@ -1193,6 +1264,77 @@ bool get isSrc => (_flags & _isSrc) != 0; } +/// Information about a single `import` directive. +class ImportDirectiveState { + final UnlinkedNamespaceDirective directive; + + ImportDirectiveState({ + required this.directive, + }); + + /// If [importedSource] corresponds to a library, returns it. + Source? get importedLibrarySource => null; + + /// Returns a [Source] that is referenced by this directive. If the are + /// configurations, selects the one which satisfies the conditions. + /// + /// Returns `null` if the selected URI is not valid, or cannot be resolved + /// into a [Source]. + Source? get importedSource => null; + + bool get isSyntheticDartCoreImport => directive.isSyntheticDartCoreImport; +} + +/// [ImportDirectiveState] that has a valid URI that references a file. +class ImportDirectiveWithFile extends ImportDirectiveState { + final FileState importedFile; + + ImportDirectiveWithFile({ + required super.directive, + required this.importedFile, + }); + + /// Returns [importedFile] if it is a library. + LibraryFileStateKind? get importedLibrary { + final kind = importedFile.kind; + if (kind is LibraryFileStateKind) { + return kind; + } + return null; + } + + @override + Source? get importedLibrarySource { + if (importedFile.kind is LibraryFileStateKind) { + return importedSource; + } + return null; + } + + @override + Source get importedSource => importedFile.source; +} + +/// [ImportDirectiveState] with a URI that resolves to [InSummarySource]. +class ImportDirectiveWithInSummarySource extends ImportDirectiveState { + @override + final InSummarySource importedSource; + + ImportDirectiveWithInSummarySource({ + required super.directive, + required this.importedSource, + }); + + @override + Source? get importedLibrarySource { + if (importedSource.kind == InSummarySourceKind.library) { + return importedSource; + } else { + return null; + } + } +} + class LibraryFileStateKind extends LibraryOrAugmentationFileKind { /// The name of the library from the `library` directive. /// Or `null` if no `library` directive. @@ -1209,10 +1351,67 @@ } abstract class LibraryOrAugmentationFileKind extends FileStateKind { + List<ExportDirectiveState>? _exports; + List<ImportDirectiveState>? _imports; + LibraryOrAugmentationFileKind({ required super.file, }); + List<ExportDirectiveState> get exports { + return _exports ??= file.unlinked2.exports.map((directive) { + final uriStr = file._selectRelativeUri(directive); + return file._fileForRelativeUri(uriStr).map( + (refFile) { + if (refFile != null) { + refFile.referencingFiles.add(file); + return ExportDirectiveWithFile( + directive: directive, + exportedFile: refFile, + ); + } else { + return ExportDirectiveState( + directive: directive, + ); + } + }, + (externalLibrary) { + return ExportDirectiveWithInSummarySource( + directive: directive, + exportedSource: externalLibrary.source, + ); + }, + ); + }).toList(); + } + + List<ImportDirectiveState> get imports { + return _imports ??= file.unlinked2.imports.map((directive) { + final uriStr = file._selectRelativeUri(directive); + return file._fileForRelativeUri(uriStr).map( + (refFile) { + if (refFile != null) { + refFile.referencingFiles.add(file); + return ImportDirectiveWithFile( + directive: directive, + importedFile: refFile, + ); + } else { + return ImportDirectiveState( + directive: directive, + ); + } + }, + (externalLibrary) { + return ImportDirectiveWithInSummarySource( + directive: directive, + importedSource: externalLibrary.source, + ); + }, + ); + }).toList(); + } + bool hasAugmentation(AugmentationFileStateKind augmentation) { return file.augmentationFiles.contains(augmentation.file); }
diff --git a/pkg/analyzer/lib/src/dart/analysis/unlinked_data.dart b/pkg/analyzer/lib/src/dart/analysis/unlinked_data.dart index 605461c..d9a7714 100644 --- a/pkg/analyzer/lib/src/dart/analysis/unlinked_data.dart +++ b/pkg/analyzer/lib/src/dart/analysis/unlinked_data.dart
@@ -159,12 +159,15 @@ /// The configurations that control which library will actually be used. final List<UnlinkedNamespaceDirectiveConfiguration> configurations; + final bool isSyntheticDartCoreImport; + /// The URI referenced by this directive, nad used by default when none /// of the [configurations] matches. final String uri; UnlinkedNamespaceDirective({ required this.configurations, + this.isSyntheticDartCoreImport = false, required this.uri, }); @@ -174,6 +177,7 @@ () => UnlinkedNamespaceDirectiveConfiguration.read(reader), ), uri: reader.readStringUtf8(), + isSyntheticDartCoreImport: reader.readBool(), ); } @@ -185,6 +189,7 @@ }, ); sink.writeStringUtf8(uri); + sink.writeBool(isSyntheticDartCoreImport); } }
diff --git a/pkg/analyzer/lib/src/dart/micro/library_graph.dart b/pkg/analyzer/lib/src/dart/micro/library_graph.dart index f560b03..4a51ff1 100644 --- a/pkg/analyzer/lib/src/dart/micro/library_graph.dart +++ b/pkg/analyzer/lib/src/dart/micro/library_graph.dart
@@ -975,6 +975,7 @@ imports.add( UnlinkedNamespaceDirective( configurations: [], + isSyntheticDartCoreImport: true, uri: 'dart:core', ), );
diff --git a/pkg/analyzer/lib/src/summary/package_bundle_reader.dart b/pkg/analyzer/lib/src/summary/package_bundle_reader.dart index 34780d5..8648d55 100644 --- a/pkg/analyzer/lib/src/summary/package_bundle_reader.dart +++ b/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
@@ -65,7 +65,13 @@ /// The summary file where this source was defined. final String summaryPath; - InSummarySource(super.uri, this.summaryPath); + final InSummarySourceKind kind; + + InSummarySource({ + required Uri uri, + required this.summaryPath, + required this.kind, + }) : super(uri); @override TimestampedData<String> get contents => TimestampedData<String>(0, ''); @@ -77,6 +83,8 @@ String toString() => uri.toString(); } +enum InSummarySourceKind { library, part } + /// The [UriResolver] that knows about sources that are served from their /// summaries. class InSummaryUriResolver extends UriResolver { @@ -92,7 +100,13 @@ String uriString = uri.toString(); String? summaryPath = _dataStore.uriToSummaryPath[uriString]; if (summaryPath != null) { - return InSummarySource(uri, summaryPath); + final isLibrary = _dataStore._libraryUris.contains(uriString); + return InSummarySource( + uri: uri, + summaryPath: summaryPath, + kind: + isLibrary ? InSummarySourceKind.library : InSummarySourceKind.part, + ); } return null; }
diff --git a/pkg/analyzer/lib/src/workspace/simple.dart b/pkg/analyzer/lib/src/workspace/simple.dart index dc9b694..6430e61 100644 --- a/pkg/analyzer/lib/src/workspace/simple.dart +++ b/pkg/analyzer/lib/src/workspace/simple.dart
@@ -43,11 +43,10 @@ DartSdk? sdk, SummaryDataStore? summaryData, ) { - if (summaryData != null) { - throw UnsupportedError( - 'Summary files are not supported in a Pub workspace.'); - } List<UriResolver> resolvers = <UriResolver>[]; + if (summaryData != null) { + resolvers.add(InSummaryUriResolver(summaryData)); + } if (sdk != null) { resolvers.add(DartUriResolver(sdk)); }
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 c0b0ac1..8dd3040 100644 --- a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart +++ b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
@@ -7,6 +7,7 @@ import 'package:analyzer/dart/analysis/declared_variables.dart'; import 'package:analyzer/dart/analysis/features.dart'; +import 'package:analyzer/dart/sdk/build_sdk_summary.dart'; import 'package:analyzer/file_system/file_system.dart'; import 'package:analyzer/src/context/packages.dart'; import 'package:analyzer/src/dart/analysis/byte_store.dart'; @@ -21,12 +22,15 @@ show AnalysisOptions, AnalysisOptionsImpl; import 'package:analyzer/src/generated/source.dart'; import 'package:analyzer/src/source/package_map_resolver.dart'; +import 'package:analyzer/src/summary/package_bundle_reader.dart'; import 'package:analyzer/src/test_utilities/mock_sdk.dart'; import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart'; import 'package:analyzer/src/util/either.dart'; import 'package:analyzer/src/workspace/basic.dart'; +import 'package:analyzer_utilities/check/check.dart'; import 'package:convert/convert.dart'; import 'package:crypto/crypto.dart'; +import 'package:meta/meta.dart'; import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; @@ -121,10 +125,31 @@ @reflectiveTest class FileSystemState_PubPackageTest extends PubPackageResolutionTest { + FileState get _dartAsyncState { + return fileStateForUriStr('dart:async'); + } + + FileState get _dartCoreState { + return fileStateForUriStr('dart:core'); + } + + FileState get _dartMathState { + return fileStateForUriStr('dart:math'); + } + FileState fileStateFor(File file) { return fsStateFor(file).getFileForPath(file.path); } + FileState fileStateForUri(Uri uri) { + return fsStateFor(testFile).getFileForUri(uri).t1!; + } + + FileState fileStateForUriStr(String uriStr) { + final uri = Uri.parse(uriStr); + return fileStateForUri(uri); + } + FileSystemState fsStateFor(File file) { return driverFor(file.path).fsState; } @@ -539,6 +564,487 @@ }); } + test_newFile_library_exports_dart() async { + final a = newFile('$testPackageLibPath/a.dart', r''' +export 'dart:async'; +export 'dart:math'; +'''); + + final aState = fileStateFor(a); + aState.assertKind((kind) { + kind as LibraryFileStateKind; + check(kind.exports).matches([ + (export) => export.isLibrary(_dartAsyncState), + (export) => export.isLibrary(_dartMathState), + ]); + }); + } + + test_newFile_library_exports_inSummary_library() async { + // Prepare a bundle where `package:foo/foo.dart` is a library. + final librarySummaryFiles = <File>[]; + { + final fooRoot = getFolder('$workspaceRootPath/foo'); + + newFile('${fooRoot.path}/lib/foo.dart', 'class F {}'); + + final fooPackageConfigFile = getFile( + '${fooRoot.path}/.dart_tool/package_config.json', + ); + + writePackageConfig( + fooPackageConfigFile.path, + PackageConfigFileBuilder()..add(name: 'foo', rootPath: fooRoot.path), + ); + + final analysisDriver = driverFor(fooRoot.path); + final bundleBytes = await analysisDriver.buildPackageBundle( + uriList: [ + Uri.parse('package:foo/foo.dart'), + ], + ); + + final bundleFile = + resourceProvider.getFile('/home/summaries/packages.sum'); + bundleFile.writeAsBytesSync(bundleBytes); + + librarySummaryFiles.add(bundleFile); + + // Delete, so it is not available as a file. + // We don't have a package config for it anyway, but just to be sure. + fooRoot.delete(); + } + + // Prepare for recreating the collection, with summaries. + sdkSummaryFile = await _writeSdkSummary(); + this.librarySummaryFiles = librarySummaryFiles; + + disposeAnalysisContextCollection(); + + final a = newFile('$testPackageLibPath/a.dart', r''' +export 'dart:async'; +export 'package:foo/foo.dart'; +export 'b.dart'; +'''); + + final b = getFile('$testPackageLibPath/b.dart'); + + final aState = fileStateFor(a); + final bState = fileStateFor(b); + + aState.assertKind((kind) { + kind as LibraryFileStateKind; + check(kind.exports).matches([ + (import) { + final expected = Uri.parse('dart:async'); + import.withInSummaryLibrary(expected); + }, + (import) { + final expected = Uri.parse('package:foo/foo.dart'); + import.withInSummaryLibrary(expected); + }, + (import) => import.isLibrary(bState), + ]); + }); + } + + test_newFile_library_exports_inSummary_part() async { + // Prepare a bundle where `package:foo/foo2.dart` is a part. + final librarySummaryFiles = <File>[]; + { + final fooRoot = getFolder('$workspaceRootPath/foo'); + + newFile('${fooRoot.path}/lib/foo.dart', r''' +part 'foo2.dart'; +'''); + + newFile('${fooRoot.path}/lib/foo2.dart', r''' +part of 'foo.dart'; +'''); + + final fooPackageConfigFile = getFile( + '${fooRoot.path}/.dart_tool/package_config.json', + ); + + writePackageConfig( + fooPackageConfigFile.path, + PackageConfigFileBuilder()..add(name: 'foo', rootPath: fooRoot.path), + ); + + final analysisDriver = driverFor(fooRoot.path); + final bundleBytes = await analysisDriver.buildPackageBundle( + uriList: [ + Uri.parse('package:foo/foo.dart'), + ], + ); + + final bundleFile = + resourceProvider.getFile('/home/summaries/packages.sum'); + bundleFile.writeAsBytesSync(bundleBytes); + + librarySummaryFiles.add(bundleFile); + + // Delete, so it is not available as a file. + // We don't have a package config for it anyway, but just to be sure. + fooRoot.delete(); + } + + // Prepare for recreating the collection, with summaries. + sdkSummaryFile = await _writeSdkSummary(); + this.librarySummaryFiles = librarySummaryFiles; + + disposeAnalysisContextCollection(); + + final a = newFile('$testPackageLibPath/a.dart', r''' +export 'package:foo/foo2.dart'; +export 'b.dart'; +'''); + + final b = getFile('$testPackageLibPath/b.dart'); + + final aState = fileStateFor(a); + final bState = fileStateFor(b); + + aState.assertKind((kind) { + kind as LibraryFileStateKind; + check(kind.exports).matches([ + (export) { + final expected = Uri.parse('package:foo/foo2.dart'); + export.withInSummaryNotLibrary(expected); + }, + (export) => export.isLibrary(bState), + ]); + }); + } + + test_newFile_library_exports_invalidRelativeUri() async { + final a = newFile('$testPackageLibPath/a.dart', r''' +export '::net'; +'''); + + final aState = fileStateFor(a); + aState.assertKind((kind) { + kind as LibraryFileStateKind; + check(kind.exports).matches([ + (export) => export.isNotFile(), + ]); + }); + } + + test_newFile_library_exports_package() async { + final a = newFile('$testPackageLibPath/a.dart', ''); + final b = newFile('$testPackageLibPath/b.dart', ''); + + final c = newFile('$testPackageLibPath/c.dart', r''' +export 'a.dart'; +export 'package:test/b.dart'; +'''); + + final aState = fileStateFor(a); + final bState = fileStateFor(b); + final cState = fileStateFor(c); + + cState.assertKind((kind) { + kind as LibraryFileStateKind; + check(kind.exports).matches([ + (export) => export.isLibrary(aState), + (export) => export.isLibrary(bState), + ]); + }); + } + + test_newFile_library_exports_part() async { + final a = newFile('$testPackageLibPath/a.dart', r''' +part of my.lib; +'''); + + final b = newFile('$testPackageLibPath/b.dart', r''' +export 'a.dart'; +'''); + + final aState = fileStateFor(a); + final bState = fileStateFor(b); + + bState.assertKind((kind) { + kind as LibraryFileStateKind; + check(kind.exports).matches([ + (export) => export.isFile(aState), + ]); + }); + } + + test_newFile_library_imports_library_augmentation() async { + final b = newFile('$testPackageLibPath/b.dart', r''' +library augment 'a.dart'; +'''); + + final c = newFile('$testPackageLibPath/c.dart', r''' +import 'b.dart'; +'''); + + final bState = fileStateFor(b); + final cState = fileStateFor(c); + + cState.assertKind((kind) { + kind as LibraryFileStateKind; + check(kind.imports).matches([ + (import) => import.isFile(bState), + (import) => import + ..isLibrary(_dartCoreState) + ..isSyntheticDartCoreImport.isTrue, + ]); + }); + } + + test_newFile_library_imports_library_dart() async { + final a = newFile('$testPackageLibPath/a.dart', r''' +import 'dart:async'; +import 'dart:math'; +'''); + + final aState = fileStateFor(a); + aState.assertKind((kind) { + kind as LibraryFileStateKind; + check(kind.imports).matches([ + (import) => import.isLibrary(_dartAsyncState), + (import) => import.isLibrary(_dartMathState), + (import) => import + ..isLibrary(_dartCoreState) + ..isSyntheticDartCoreImport.isTrue, + ]); + }); + } + + test_newFile_library_imports_library_dart_explicitDartCore() async { + final a = newFile('$testPackageLibPath/a.dart', r''' +import 'dart:core'; +import 'dart:math'; +'''); + + final aState = fileStateFor(a); + aState.assertKind((kind) { + kind as LibraryFileStateKind; + check(kind.imports).matches([ + (import) => import + ..isLibrary(_dartCoreState) + ..isSyntheticDartCoreImport.isFalse, + (import) => import.isLibrary(_dartMathState), + ]); + }); + } + + test_newFile_library_imports_library_inSummary_library() async { + // Prepare a bundle where `package:foo/foo.dart` is a library. + final librarySummaryFiles = <File>[]; + { + final fooRoot = getFolder('$workspaceRootPath/foo'); + + newFile('${fooRoot.path}/lib/foo.dart', 'class F {}'); + + final fooPackageConfigFile = getFile( + '${fooRoot.path}/.dart_tool/package_config.json', + ); + + writePackageConfig( + fooPackageConfigFile.path, + PackageConfigFileBuilder()..add(name: 'foo', rootPath: fooRoot.path), + ); + + final analysisDriver = driverFor(fooRoot.path); + final bundleBytes = await analysisDriver.buildPackageBundle( + uriList: [ + Uri.parse('package:foo/foo.dart'), + ], + ); + + final bundleFile = + resourceProvider.getFile('/home/summaries/packages.sum'); + bundleFile.writeAsBytesSync(bundleBytes); + + librarySummaryFiles.add(bundleFile); + + // Delete, so it is not available as a file. + // We don't have a package config for it anyway, but just to be sure. + fooRoot.delete(); + } + + // Prepare for recreating the collection, with summaries. + sdkSummaryFile = await _writeSdkSummary(); + this.librarySummaryFiles = librarySummaryFiles; + + disposeAnalysisContextCollection(); + + final a = newFile('$testPackageLibPath/a.dart', r''' +import 'dart:async'; +import 'package:foo/foo.dart'; +import 'b.dart'; +'''); + + final b = getFile('$testPackageLibPath/b.dart'); + + final aState = fileStateFor(a); + final bState = fileStateFor(b); + + aState.assertKind((kind) { + kind as LibraryFileStateKind; + check(kind.imports).matches([ + (import) { + final expected = Uri.parse('dart:async'); + import.withInSummaryLibrary(expected); + }, + (import) { + final expected = Uri.parse('package:foo/foo.dart'); + import.withInSummaryLibrary(expected); + }, + (import) => import.isLibrary(bState), + (import) { + final expected = Uri.parse('dart:core'); + import + ..withInSummaryLibrary(expected) + ..isSyntheticDartCoreImport.isTrue; + }, + ]); + }); + } + + test_newFile_library_imports_library_inSummary_part() async { + // Prepare a bundle where `package:foo/foo2.dart` is a part. + final librarySummaryFiles = <File>[]; + { + final fooRoot = getFolder('$workspaceRootPath/foo'); + + newFile('${fooRoot.path}/lib/foo.dart', r''' +part 'foo2.dart'; +'''); + + newFile('${fooRoot.path}/lib/foo2.dart', r''' +part of 'foo.dart'; +'''); + + final fooPackageConfigFile = getFile( + '${fooRoot.path}/.dart_tool/package_config.json', + ); + + writePackageConfig( + fooPackageConfigFile.path, + PackageConfigFileBuilder()..add(name: 'foo', rootPath: fooRoot.path), + ); + + final analysisDriver = driverFor(fooRoot.path); + final bundleBytes = await analysisDriver.buildPackageBundle( + uriList: [ + Uri.parse('package:foo/foo.dart'), + ], + ); + + final bundleFile = + resourceProvider.getFile('/home/summaries/packages.sum'); + bundleFile.writeAsBytesSync(bundleBytes); + + librarySummaryFiles.add(bundleFile); + + // Delete, so it is not available as a file. + // We don't have a package config for it anyway, but just to be sure. + fooRoot.delete(); + } + + // Prepare for recreating the collection, with summaries. + sdkSummaryFile = await _writeSdkSummary(); + this.librarySummaryFiles = librarySummaryFiles; + + disposeAnalysisContextCollection(); + + final a = newFile('$testPackageLibPath/a.dart', r''' +import 'package:foo/foo2.dart'; +import 'b.dart'; +'''); + + final b = getFile('$testPackageLibPath/b.dart'); + + final aState = fileStateFor(a); + final bState = fileStateFor(b); + + aState.assertKind((kind) { + kind as LibraryFileStateKind; + check(kind.imports).matches([ + (export) { + final expected = Uri.parse('package:foo/foo2.dart'); + export.withInSummaryNotLibrary(expected); + }, + (export) => export.isLibrary(bState), + (export) { + final expected = Uri.parse('dart:core'); + export + ..withInSummaryLibrary(expected) + ..isSyntheticDartCoreImport.isTrue; + }, + ]); + }); + } + + test_newFile_library_imports_library_invalidRelativeUri() async { + final a = newFile('$testPackageLibPath/a.dart', r''' +import '::net'; +'''); + + final aState = fileStateFor(a); + aState.assertKind((kind) { + kind as LibraryFileStateKind; + check(kind.imports).matches([ + (import) => import.isNotFile(), + (import) => import.isLibrary(_dartCoreState), + ]); + }); + } + + test_newFile_library_imports_library_package() async { + final a = newFile('$testPackageLibPath/a.dart', ''); + final b = newFile('$testPackageLibPath/b.dart', ''); + + final c = newFile('$testPackageLibPath/c.dart', r''' +import 'a.dart'; +import 'package:test/b.dart'; +'''); + + final aState = fileStateFor(a); + final bState = fileStateFor(b); + final cState = fileStateFor(c); + + cState.assertKind((kind) { + kind as LibraryFileStateKind; + check(kind.imports).matches([ + (import) => import.isLibrary(aState), + (import) => import.isLibrary(bState), + (import) => import + ..isLibrary(_dartCoreState) + ..isSyntheticDartCoreImport.isTrue, + ]); + }); + } + + test_newFile_library_imports_library_part() async { + final a = newFile('$testPackageLibPath/a.dart', r''' +part of my.lib; +'''); + + final b = newFile('$testPackageLibPath/b.dart', r''' +import 'a.dart'; +'''); + + final aState = fileStateFor(a); + final bState = fileStateFor(b); + + bState.assertKind((kind) { + kind as LibraryFileStateKind; + check(kind.imports).matches([ + (import) => import.isFile(aState), + (import) => import + ..isLibrary(_dartCoreState) + ..isSyntheticDartCoreImport.isTrue, + ]); + }); + } + test_newFile_library_includePart_withoutPartOf() async { final a = newFile('$testPackageLibPath/a.dart', r''' part 'b.dart'; @@ -1609,6 +2115,16 @@ }).toList(); expect(actualFiles, expected); } + + Future<File> _writeSdkSummary() async { + final file = resourceProvider.getFile('/home/summaries/sdk.sum'); + final bytes = await buildSdkSummary2( + resourceProvider: resourceProvider, + sdkPath: sdkRoot.path, + ); + file.writeAsBytesSync(bytes); + return file; + } } @reflectiveTest @@ -2466,6 +2982,188 @@ } } +extension on CheckTarget<ImportDirectiveState> { + @useResult + CheckTarget<Source?> get importedLibrarySource { + return nest( + value.importedLibrarySource, + (selected) => 'importedLibrarySource ${valueStr(selected)}', + ); + } + + @useResult + CheckTarget<bool> get isSyntheticDartCoreImport { + return nest( + value.isSyntheticDartCoreImport, + (selected) => 'isSyntheticDartCoreImport ${valueStr(selected)}', + ); + } + + /// Is [ImportDirectiveWithFile], but not a library. + void isFile(FileState expected) { + this.isA<ImportDirectiveWithFile>() + ..importedFile.isIdenticalTo(expected) + ..importedSource.uri.isEqualTo(expected.uri) + ..importedLibrary.isNull + ..importedLibrarySource.isNull; + } + + /// Is [ImportDirectiveWithFile], and is a library. + void isLibrary(FileState expected) { + final expectedKind = expected.kind as LibraryFileStateKind; + this.isA<ImportDirectiveWithFile>() + ..importedFile.isIdenticalTo(expected) + ..importedSource.uri.isEqualTo(expected.uri) + ..importedLibrary.isNotNull.isIdenticalTo(expectedKind) + ..importedLibrarySource.isNotNull.uri.isEqualTo(expected.uri); + } + + /// Exactly [ImportDirectiveState], even the file is not known. + void isNotFile() { + hasExactType<ImportDirectiveState>(); + } + + void withInSummaryLibrary(Uri expected) { + this.isA<ImportDirectiveWithInSummarySource>() + ..importedSource.uri.isEqualTo(expected) + ..importedLibrarySource.isNotNull.uri.isEqualTo(expected); + } + + void withInSummaryNotLibrary(Uri expected) { + this.isA<ImportDirectiveWithInSummarySource>() + ..importedSource.uri.isEqualTo(expected) + ..importedLibrarySource.isNull; + } +} + +extension on CheckTarget<ExportDirectiveState> { + @useResult + CheckTarget<Source?> get exportedLibrarySource { + return nest( + value.exportedLibrarySource, + (selected) => 'exportedLibrarySource ${valueStr(selected)}', + ); + } + + /// Is [ExportDirectiveWithFile], but not a library. + void isFile(FileState expected) { + this.isA<ExportDirectiveWithFile>() + ..exportedFile.isIdenticalTo(expected) + ..exportedSource.uri.isEqualTo(expected.uri) + ..exportedLibrary.isNull + ..exportedLibrarySource.isNull; + } + + /// Is [ExportDirectiveWithFile], and is a library. + void isLibrary(FileState expected) { + final expectedKind = expected.kind as LibraryFileStateKind; + this.isA<ExportDirectiveWithFile>() + ..exportedFile.isIdenticalTo(expected) + ..exportedSource.uri.isEqualTo(expected.uri) + ..exportedLibrary.isIdenticalTo(expectedKind) + ..exportedLibrarySource.isNotNull.uri.isEqualTo(expected.uri); + } + + /// Exactly [ExportDirectiveState], even the file is not known. + void isNotFile() { + hasExactType<ExportDirectiveState>(); + } + + void withInSummaryLibrary(Uri expected) { + this.isA<ExportDirectiveWithInSummarySource>() + ..exportedSource.uri.isEqualTo(expected) + ..exportedLibrarySource.isNotNull.uri.isEqualTo(expected); + } + + void withInSummaryNotLibrary(Uri expected) { + this.isA<ExportDirectiveWithInSummarySource>() + ..exportedSource.uri.isEqualTo(expected) + ..exportedLibrarySource.isNull; + } +} + +extension on CheckTarget<ImportDirectiveWithFile> { + @useResult + CheckTarget<FileState> get importedFile { + return nest( + value.importedFile, + (selected) => 'importedFile ${valueStr(selected)}', + ); + } + + @useResult + CheckTarget<LibraryFileStateKind?> get importedLibrary { + return nest( + value.importedLibrary, + (selected) => 'importedLibrary ${valueStr(selected)}', + ); + } + + @useResult + CheckTarget<Source> get importedSource { + return nest( + value.importedSource, + (selected) => 'importedSource ${valueStr(selected)}', + ); + } +} + +extension on CheckTarget<ExportDirectiveWithFile> { + @useResult + CheckTarget<FileState> get exportedFile { + return nest( + value.exportedFile, + (selected) => 'exportedFile ${valueStr(selected)}', + ); + } + + @useResult + CheckTarget<LibraryFileStateKind?> get exportedLibrary { + return nest( + value.exportedLibrary, + (selected) => 'exportedLibrary ${valueStr(selected)}', + ); + } + + @useResult + CheckTarget<Source> get exportedSource { + return nest( + value.exportedSource, + (selected) => 'exportedSource ${valueStr(selected)}', + ); + } +} + +extension on CheckTarget<ImportDirectiveWithInSummarySource> { + @useResult + CheckTarget<InSummarySource> get importedSource { + return nest( + value.importedSource, + (selected) => 'importedSource ${valueStr(selected)}', + ); + } +} + +extension on CheckTarget<ExportDirectiveWithInSummarySource> { + @useResult + CheckTarget<InSummarySource> get exportedSource { + return nest( + value.exportedSource, + (selected) => 'exportedSource ${valueStr(selected)}', + ); + } +} + +extension on CheckTarget<Source> { + @useResult + CheckTarget<Uri> get uri { + return nest( + value.uri, + (selected) => 'uri ${valueStr(selected)}', + ); + } +} + extension _Either2Extension<T1, T2> on Either2<T1, T2> { T1 get t1 { late T1 result;
diff --git a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart index 8773df4..c2aa845 100644 --- a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart +++ b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
@@ -129,6 +129,12 @@ /// to this path, instead of the given path. String? pathForContextSelection; + /// Optional Dart SDK summary file, to be used instead of [sdkRoot]. + File? sdkSummaryFile; + + /// Optional summaries to provide for the collection. + List<File>? librarySummaryFiles; + List<MockSdkLibrary> get additionalMockSdkLibraries => []; List<String> get collectionIncludedPaths; @@ -259,6 +265,8 @@ resourceProvider: resourceProvider, retainDataForTesting: retainDataForTesting, sdkPath: sdkRoot.path, + sdkSummaryPath: sdkSummaryFile?.path, + librarySummaryPaths: librarySummaryFiles?.map((e) => e.path).toList(), updateAnalysisOptions: updateAnalysisOptions, );
diff --git a/pkg/analyzer/test/src/summary/in_summary_source_test.dart b/pkg/analyzer/test/src/summary/in_summary_source_test.dart deleted file mode 100644 index 0587667..0000000 --- a/pkg/analyzer/test/src/summary/in_summary_source_test.dart +++ /dev/null
@@ -1,57 +0,0 @@ -// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:analyzer/src/generated/source.dart'; -import 'package:analyzer/src/summary/package_bundle_reader.dart'; -import 'package:test/test.dart'; -import 'package:test_reflective_loader/test_reflective_loader.dart'; - -main() { - defineReflectiveSuite(() { - defineReflectiveTests(InSummarySourceTest); - }); -} - -@reflectiveTest -class InSummarySourceTest { - test_InSummarySource() { - var sourceFactory = SourceFactory([ - InSummaryUriResolver( - MockSummaryDataStore.fake({ - 'package:foo/foo.dart': 'foo.sum', - 'package:foo/src/foo_impl.dart': 'foo.sum', - 'package:bar/baz.dart': 'bar.sum', - }), - ) - ]); - - var source = - sourceFactory.forUri('package:foo/foo.dart') as InSummarySource; - expect(source, isNotNull); - expect(source.summaryPath, 'foo.sum'); - - source = sourceFactory.forUri('package:foo/src/foo_impl.dart') - as InSummarySource; - expect(source, isNotNull); - expect(source.summaryPath, 'foo.sum'); - - source = sourceFactory.forUri('package:bar/baz.dart') as InSummarySource; - expect(source, isNotNull); - expect(source.summaryPath, 'bar.sum'); - } -} - -class MockSummaryDataStore implements SummaryDataStore { - @override - final Map<String, String> uriToSummaryPath; - - MockSummaryDataStore(this.uriToSummaryPath); - - factory MockSummaryDataStore.fake(Map<String, String> uriToSummary) { - return MockSummaryDataStore(uriToSummary); - } - - @override - noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); -}
diff --git a/pkg/analyzer/test/src/summary/test_all.dart b/pkg/analyzer/test/src/summary/test_all.dart index 41786a1..9c87739 100644 --- a/pkg/analyzer/test/src/summary/test_all.dart +++ b/pkg/analyzer/test/src/summary/test_all.dart
@@ -7,7 +7,6 @@ import 'api_signature_test.dart' as api_signature; import 'elements_test.dart' as elements; import 'flat_buffers_test.dart' as flat_buffers; -import 'in_summary_source_test.dart' as in_summary_source; import 'macro_test.dart' as macro; import 'top_level_inference_test.dart' as top_level_inference; @@ -16,7 +15,6 @@ api_signature.main(); elements.main(); flat_buffers.main(); - in_summary_source.main(); macro.main(); top_level_inference.main(); }, name: 'summary');
diff --git a/pkg/analyzer/test/src/workspace/bazel_test.dart b/pkg/analyzer/test/src/workspace/bazel_test.dart index a79b85e..784c9b8 100644 --- a/pkg/analyzer/test/src/workspace/bazel_test.dart +++ b/pkg/analyzer/test/src/workspace/bazel_test.dart
@@ -901,7 +901,11 @@ Source _inSummarySource(String uriStr) { var uri = Uri.parse(uriStr); - return InSummarySource(uri, ''); + return InSummarySource( + uri: uri, + summaryPath: '', + kind: InSummarySourceKind.library, + ); } void _setUpPackage() {
diff --git a/pkg/analyzer_utilities/lib/check/equality.dart b/pkg/analyzer_utilities/lib/check/equality.dart index 2d265b8..9701bb3 100644 --- a/pkg/analyzer_utilities/lib/check/equality.dart +++ b/pkg/analyzer_utilities/lib/check/equality.dart
@@ -11,6 +11,12 @@ } } + void isIdenticalTo(Object? other) { + if (!identical(value, other)) { + fail('is not identical to $other'); + } + } + void isNotEqualTo(Object? other) { if (value == other) { fail('is equal to $other');
diff --git a/pkg/analyzer_utilities/lib/check/type.dart b/pkg/analyzer_utilities/lib/check/type.dart index ea28b9e..c261e2a 100644 --- a/pkg/analyzer_utilities/lib/check/type.dart +++ b/pkg/analyzer_utilities/lib/check/type.dart
@@ -5,6 +5,15 @@ import 'package:analyzer_utilities/check/check.dart'; extension IsExtension<T> on CheckTarget<T> { + CheckTarget<U> hasExactType<U extends T>() { + final value = this.value; + if (value.runtimeType == U) { + return nest(value as U, (_) => 'is of type $U'); + } else { + fail('is not of type $U'); + } + } + CheckTarget<U> isA<U extends T>() { final value = this.value; if (value is U) {
diff --git a/pkg/analyzer_utilities/test/check/check_test.dart b/pkg/analyzer_utilities/test/check/check_test.dart index 9e5ee83..0f9bda1 100644 --- a/pkg/analyzer_utilities/test/check/check_test.dart +++ b/pkg/analyzer_utilities/test/check/check_test.dart
@@ -29,6 +29,14 @@ _fails(() => check(false).isTrue); }); }); + group('equality', () { + test('isIdenticalTo', () { + final a = Object(); + final b = Object(); + check(a).isIdenticalTo(a); + _fails(() => check(a).isIdenticalTo(b)); + }); + }); group('int', () { test('isEqualTo', () { check(0).isEqualTo(0); @@ -332,6 +340,10 @@ }); }); group('type', () { + test('hasExactType', () { + check(42).hasExactType<int>(); + _fails(() => check(42 as dynamic).hasExactType<num>()); + }); test('isA', () { check(0).isA<int>(); _fails(() => check('abc' as dynamic).isA<int>());
diff --git a/pkg/dart2js_info/lib/info.dart b/pkg/dart2js_info/lib/info.dart index 55c3c50..ef0c1a5 100644 --- a/pkg/dart2js_info/lib/info.dart +++ b/pkg/dart2js_info/lib/info.dart
@@ -334,7 +334,7 @@ late final bool isConst; /// When [isConst] is true, the constant initializer expression. - late final ConstantInfo initializer; + ConstantInfo? initializer; FieldInfo( {required String name,
diff --git a/tools/VERSION b/tools/VERSION index 72045af..affbc14 100644 --- a/tools/VERSION +++ b/tools/VERSION
@@ -27,5 +27,5 @@ MAJOR 2 MINOR 18 PATCH 0 -PRERELEASE 158 +PRERELEASE 159 PRERELEASE_PATCH 0 \ No newline at end of file