Add LibraryOrAugmentationFileKind.exports/imports

These will replace eventually FileState.exported/importedFiles,
because only libraries or augmentation can have them. Also, we will
build Export/ImportElement(s) from them, when google3 switches to
using AnalysisDriver.buildPackageBundle(), so we are free to make
changes to the way linker works.

Change-Id: I66674dc7720aa704cfc36d16fc78e17dd05a8b93
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/246681
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Konstantin Shcheglov
2022-06-01 06:35:14 +00:00
committed by Commit Bot
parent 1e7bc687a7
commit 8ded7af5f5
14 changed files with 963 additions and 67 deletions
@@ -86,7 +86,7 @@ import 'package:meta/meta.dart';
/// 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.
@@ -85,6 +85,75 @@ class AugmentationUnknownFileStateKind extends AugmentationFileStateKind {
});
}
/// 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 @@ class FileState {
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 @@ class FileState {
imports.add(
UnlinkedNamespaceDirective(
configurations: [],
isSyntheticDartCoreImport: true,
uri: 'dart:core',
),
);
@@ -1193,6 +1264,77 @@ class FileUriProperties {
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 @@ class LibraryFileStateKind extends LibraryOrAugmentationFileKind {
}
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);
}
@@ -159,12 +159,15 @@ class UnlinkedNamespaceDirective {
/// 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 @@ class UnlinkedNamespaceDirective {
() => UnlinkedNamespaceDirectiveConfiguration.read(reader),
),
uri: reader.readStringUtf8(),
isSyntheticDartCoreImport: reader.readBool(),
);
}
@@ -185,6 +189,7 @@ class UnlinkedNamespaceDirective {
},
);
sink.writeStringUtf8(uri);
sink.writeBool(isSyntheticDartCoreImport);
}
}
@@ -975,6 +975,7 @@ class _FileStateUnlinked {
imports.add(
UnlinkedNamespaceDirective(
configurations: [],
isSyntheticDartCoreImport: true,
uri: 'dart:core',
),
);
@@ -65,7 +65,13 @@ class InSummarySource extends BasicSource {
/// 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 @@ class InSummarySource extends BasicSource {
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 @@ class InSummaryUriResolver extends UriResolver {
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;
}
+3 -4
View File
@@ -43,11 +43,10 @@ abstract class SimpleWorkspace extends Workspace {
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));
}
@@ -7,6 +7,7 @@ import 'dart:typed_data';
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 @@ import 'package:analyzer/src/generated/engine.dart'
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 @@ class FileSystemState_BazelWorkspaceTest extends BazelWorkspaceResolutionTest {
@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 @@ import augment 'c.dart';
});
}
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 @@ class A2 {}
}).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 PartOfNameFileStateKind {
}
}
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;
@@ -129,6 +129,12 @@ abstract class ContextResolutionTest
/// 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 @@ abstract class ContextResolutionTest
resourceProvider: resourceProvider,
retainDataForTesting: retainDataForTesting,
sdkPath: sdkRoot.path,
sdkSummaryPath: sdkSummaryFile?.path,
librarySummaryPaths: librarySummaryFiles?.map((e) => e.path).toList(),
updateAnalysisOptions: updateAnalysisOptions,
);
@@ -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);
}
@@ -7,7 +7,6 @@ import 'package:test_reflective_loader/test_reflective_loader.dart';
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 @@ main() {
api_signature.main();
elements.main();
flat_buffers.main();
in_summary_source.main();
macro.main();
top_level_inference.main();
}, name: 'summary');
@@ -901,7 +901,11 @@ class BazelWorkspacePackageTest with ResourceProviderMixin {
Source _inSummarySource(String uriStr) {
var uri = Uri.parse(uriStr);
return InSummarySource(uri, '');
return InSummarySource(
uri: uri,
summaryPath: '',
kind: InSummarySourceKind.library,
);
}
void _setUpPackage() {
@@ -11,6 +11,12 @@ extension EqualityExtension<T> on CheckTarget<T> {
}
}
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');
@@ -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) {
@@ -29,6 +29,14 @@ void main() {
_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 @@ void main() {
});
});
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>());