mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 00:58:29 +00:00
Use ImportDirectiveState and others in LibraryAnalyzer.
Change-Id: I9cdeedcb8f3e9b35814bb457547bb52ac85f7f4c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/250263 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
ffb598f3b5
commit
1ed8748dcd
|
@ -1330,7 +1330,6 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
|||
var results = LibraryAnalyzer(
|
||||
analysisOptions as AnalysisOptionsImpl,
|
||||
declaredVariables,
|
||||
sourceFactory,
|
||||
libraryContext.elementFactory.libraryOfUri2(library.file.uri),
|
||||
libraryContext.elementFactory.analysisSession.inheritanceManager,
|
||||
library,
|
||||
|
@ -1397,7 +1396,6 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
|||
var unitResults = LibraryAnalyzer(
|
||||
analysisOptions as AnalysisOptionsImpl,
|
||||
declaredVariables,
|
||||
sourceFactory,
|
||||
libraryContext.elementFactory.libraryOfUri2(library.file.uri),
|
||||
libraryContext.elementFactory.analysisSession.inheritanceManager,
|
||||
library,
|
||||
|
@ -1771,7 +1769,6 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
|||
var analysisResult = LibraryAnalyzer(
|
||||
analysisOptions as AnalysisOptionsImpl,
|
||||
declaredVariables,
|
||||
sourceFactory,
|
||||
libraryContext.elementFactory.libraryOfUri2(library.file.uri),
|
||||
libraryContext.elementFactory.analysisSession.inheritanceManager,
|
||||
library,
|
||||
|
|
|
@ -131,12 +131,82 @@ class DirectiveState {
|
|||
void dispose() {}
|
||||
}
|
||||
|
||||
/// Information about a single `import` directive.
|
||||
class ExportDirectiveState extends DirectiveState {
|
||||
/// Meaning of a URI referenced in a directive.
|
||||
class DirectiveUri {
|
||||
Source? get source => null;
|
||||
}
|
||||
|
||||
/// [DirectiveUriWithUri] with URI that resolves to a [FileState].
|
||||
class DirectiveUriWithFile extends DirectiveUriWithUri {
|
||||
final FileState file;
|
||||
|
||||
DirectiveUriWithFile({
|
||||
required super.relativeUriStr,
|
||||
required super.relativeUri,
|
||||
required this.file,
|
||||
});
|
||||
|
||||
@override
|
||||
Source? get source => file.source;
|
||||
|
||||
@override
|
||||
String toString() => '$file';
|
||||
}
|
||||
|
||||
/// [DirectiveUriWithUri] with URI that resolves to a [InSummarySource].
|
||||
class DirectiveUriWithInSummarySource extends DirectiveUriWithUri {
|
||||
@override
|
||||
final InSummarySource source;
|
||||
|
||||
DirectiveUriWithInSummarySource({
|
||||
required super.relativeUriStr,
|
||||
required super.relativeUri,
|
||||
required this.source,
|
||||
});
|
||||
|
||||
@override
|
||||
String toString() => '$source';
|
||||
}
|
||||
|
||||
/// [DirectiveUri] for which we can get its relative URI string.
|
||||
class DirectiveUriWithString extends DirectiveUri {
|
||||
final String relativeUriStr;
|
||||
|
||||
DirectiveUriWithString({
|
||||
required this.relativeUriStr,
|
||||
});
|
||||
|
||||
@override
|
||||
String toString() => relativeUriStr;
|
||||
}
|
||||
|
||||
/// [DirectiveUriWithString] that can be parsed into a relative URI.
|
||||
class DirectiveUriWithUri extends DirectiveUriWithString {
|
||||
final Uri relativeUri;
|
||||
|
||||
DirectiveUriWithUri({
|
||||
required super.relativeUriStr,
|
||||
required this.relativeUri,
|
||||
});
|
||||
|
||||
bool get isValid {
|
||||
return relativeUri.path.isNotEmpty;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => '$relativeUri';
|
||||
}
|
||||
|
||||
/// Information about a single `export` directive.
|
||||
class ExportDirectiveState<U extends DirectiveUri> extends DirectiveState {
|
||||
final UnlinkedNamespaceDirective directive;
|
||||
final U selectedUri;
|
||||
final NamespaceDirectiveUris uris;
|
||||
|
||||
ExportDirectiveState({
|
||||
required this.directive,
|
||||
required this.selectedUri,
|
||||
required this.uris,
|
||||
});
|
||||
|
||||
/// If [exportedSource] corresponds to a library, returns it.
|
||||
|
@ -151,19 +221,21 @@ class ExportDirectiveState extends DirectiveState {
|
|||
}
|
||||
|
||||
/// [ExportDirectiveWithUri] that has a valid URI that references a file.
|
||||
class ExportDirectiveWithFile extends ExportDirectiveWithUri {
|
||||
class ExportDirectiveWithFile
|
||||
extends ExportDirectiveWithUri<DirectiveUriWithFile> {
|
||||
final LibraryOrAugmentationFileKind container;
|
||||
final FileState exportedFile;
|
||||
|
||||
ExportDirectiveWithFile({
|
||||
required this.container,
|
||||
required super.directive,
|
||||
required this.exportedFile,
|
||||
required super.selectedUriStr,
|
||||
required super.selectedUri,
|
||||
required super.uris,
|
||||
}) {
|
||||
exportedFile.referencingFiles.add(container.file);
|
||||
}
|
||||
|
||||
FileState get exportedFile => selectedUri.file;
|
||||
|
||||
/// Returns [exportedFile] if it is a library.
|
||||
LibraryFileStateKind? get exportedLibrary {
|
||||
final kind = exportedFile.kind;
|
||||
|
@ -191,14 +263,12 @@ class ExportDirectiveWithFile extends ExportDirectiveWithUri {
|
|||
}
|
||||
|
||||
/// [ExportDirectiveWithUri] with a URI that resolves to [InSummarySource].
|
||||
class ExportDirectiveWithInSummarySource extends ExportDirectiveWithUri {
|
||||
@override
|
||||
final InSummarySource exportedSource;
|
||||
|
||||
class ExportDirectiveWithInSummarySource
|
||||
extends ExportDirectiveWithUri<DirectiveUriWithInSummarySource> {
|
||||
ExportDirectiveWithInSummarySource({
|
||||
required super.directive,
|
||||
required this.exportedSource,
|
||||
required super.selectedUriStr,
|
||||
required super.selectedUri,
|
||||
required super.uris,
|
||||
});
|
||||
|
||||
@override
|
||||
|
@ -209,15 +279,18 @@ class ExportDirectiveWithInSummarySource extends ExportDirectiveWithUri {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
InSummarySource get exportedSource => selectedUri.source;
|
||||
}
|
||||
|
||||
/// [ExportDirectiveState] that has a valid URI string.
|
||||
class ExportDirectiveWithUri extends ExportDirectiveState {
|
||||
final String selectedUriStr;
|
||||
|
||||
/// [ExportDirectiveState] that has a valid URI.
|
||||
class ExportDirectiveWithUri<U extends DirectiveUriWithUri>
|
||||
extends ExportDirectiveState<U> {
|
||||
ExportDirectiveWithUri({
|
||||
required super.directive,
|
||||
required this.selectedUriStr,
|
||||
required super.selectedUri,
|
||||
required super.uris,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -593,6 +666,70 @@ class FileState {
|
|||
return '$uri = $path';
|
||||
}
|
||||
|
||||
DirectiveUri _buildDirectiveUri(String? relativeUriStr) {
|
||||
if (relativeUriStr == null) {
|
||||
return DirectiveUri();
|
||||
}
|
||||
|
||||
final relativeUri = Uri.tryParse(relativeUriStr);
|
||||
if (relativeUri == null) {
|
||||
return DirectiveUriWithString(
|
||||
relativeUriStr: relativeUriStr,
|
||||
);
|
||||
}
|
||||
|
||||
final absoluteUri = resolveRelativeUri(uri, relativeUri);
|
||||
return _fsState.getFileForUri(absoluteUri).map(
|
||||
(file) {
|
||||
if (file != null) {
|
||||
return DirectiveUriWithFile(
|
||||
relativeUriStr: relativeUriStr,
|
||||
relativeUri: relativeUri,
|
||||
file: file,
|
||||
);
|
||||
} else {
|
||||
return DirectiveUriWithUri(
|
||||
relativeUriStr: relativeUriStr,
|
||||
relativeUri: relativeUri,
|
||||
);
|
||||
}
|
||||
},
|
||||
(externalLibrary) {
|
||||
return DirectiveUriWithInSummarySource(
|
||||
relativeUriStr: relativeUriStr,
|
||||
relativeUri: relativeUri,
|
||||
source: externalLibrary.source,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// TODO(scheglov) move to _fsState?
|
||||
NamespaceDirectiveUris _buildNamespaceDirectiveUris(
|
||||
UnlinkedNamespaceDirective directive,
|
||||
) {
|
||||
final primaryUri = _buildDirectiveUri(directive.uri);
|
||||
|
||||
final configurationUris = <DirectiveUri>[];
|
||||
DirectiveUri? selectedConfigurationUri;
|
||||
for (final configuration in directive.configurations) {
|
||||
final configurationUri = _buildDirectiveUri(configuration.uri);
|
||||
configurationUris.add(configurationUri);
|
||||
// Maybe select this URI.
|
||||
final name = configuration.name;
|
||||
final value = configuration.valueOrTrue;
|
||||
if (_fsState._declaredVariables.get(name) == value) {
|
||||
selectedConfigurationUri ??= configurationUri;
|
||||
}
|
||||
}
|
||||
|
||||
return NamespaceDirectiveUris(
|
||||
primary: primaryUri,
|
||||
configurations: configurationUris,
|
||||
selected: selectedConfigurationUri ?? primaryUri,
|
||||
);
|
||||
}
|
||||
|
||||
/// Return the [FileState] for the given [relativeUri], or `null` if the
|
||||
/// URI cannot be parsed, cannot correspond any file, etc.
|
||||
Either2<FileState?, ExternalLibrary> _fileForRelativeUri(
|
||||
|
@ -1092,17 +1229,13 @@ class FileSystemState {
|
|||
|
||||
_uriToFile.remove(file.uri);
|
||||
|
||||
// The removed file does not reference other file anymore.
|
||||
for (var referencedFile in file.directReferencedFiles) {
|
||||
referencedFile.referencingFiles.remove(file);
|
||||
}
|
||||
// The removed file does not reference other files anymore.
|
||||
file._kind?.dispose();
|
||||
|
||||
// Recursively remove files that reference the removed file.
|
||||
for (var reference in file.referencingFiles.toList()) {
|
||||
changeFile(reference.path, removedFiles);
|
||||
}
|
||||
|
||||
file._kind?.dispose();
|
||||
}
|
||||
|
||||
/// Collected files that transitively reference a file with the [path].
|
||||
|
@ -1454,11 +1587,14 @@ class FileUriProperties {
|
|||
}
|
||||
|
||||
/// Information about a single `import augment` directive.
|
||||
class ImportAugmentationDirectiveState extends DirectiveState {
|
||||
class ImportAugmentationDirectiveState<U extends DirectiveUri>
|
||||
extends DirectiveState {
|
||||
final UnlinkedImportAugmentationDirective directive;
|
||||
final U uri;
|
||||
|
||||
ImportAugmentationDirectiveState({
|
||||
required this.directive,
|
||||
required this.uri,
|
||||
});
|
||||
|
||||
/// Returns a [Source] that is referenced by this directive.
|
||||
|
@ -1469,14 +1605,13 @@ class ImportAugmentationDirectiveState extends DirectiveState {
|
|||
|
||||
/// [ImportAugmentationWithUri] that has a valid URI that references a file.
|
||||
class ImportAugmentationDirectiveWithFile
|
||||
extends ImportAugmentationDirectiveState {
|
||||
extends ImportAugmentationWithUri<DirectiveUriWithFile> {
|
||||
final LibraryOrAugmentationFileKind container;
|
||||
final FileState importedFile;
|
||||
|
||||
ImportAugmentationDirectiveWithFile({
|
||||
required this.container,
|
||||
required super.directive,
|
||||
required this.importedFile,
|
||||
required super.uri,
|
||||
}) {
|
||||
importedFile.referencingFiles.add(container.file);
|
||||
}
|
||||
|
@ -1491,6 +1626,8 @@ class ImportAugmentationDirectiveWithFile
|
|||
return null;
|
||||
}
|
||||
|
||||
FileState get importedFile => uri.file;
|
||||
|
||||
@override
|
||||
Source? get importedSource => importedFile.source;
|
||||
|
||||
|
@ -1501,21 +1638,24 @@ class ImportAugmentationDirectiveWithFile
|
|||
}
|
||||
|
||||
/// [ImportAugmentationDirectiveState] that has a valid URI.
|
||||
class ImportAugmentationWithUri extends ImportAugmentationDirectiveState {
|
||||
final String uriStr;
|
||||
|
||||
class ImportAugmentationWithUri<U extends DirectiveUriWithUri>
|
||||
extends ImportAugmentationDirectiveState<U> {
|
||||
ImportAugmentationWithUri({
|
||||
required super.directive,
|
||||
required this.uriStr,
|
||||
required super.uri,
|
||||
});
|
||||
}
|
||||
|
||||
/// Information about a single `import` directive.
|
||||
class ImportDirectiveState extends DirectiveState {
|
||||
class ImportDirectiveState<U extends DirectiveUri> extends DirectiveState {
|
||||
final UnlinkedNamespaceDirective directive;
|
||||
final U selectedUri;
|
||||
final NamespaceDirectiveUris uris;
|
||||
|
||||
ImportDirectiveState({
|
||||
required this.directive,
|
||||
required this.selectedUri,
|
||||
required this.uris,
|
||||
});
|
||||
|
||||
/// If [importedSource] corresponds to a library, returns it.
|
||||
|
@ -1532,19 +1672,21 @@ class ImportDirectiveState extends DirectiveState {
|
|||
}
|
||||
|
||||
/// [ImportDirectiveWithUri] that has a valid URI that references a file.
|
||||
class ImportDirectiveWithFile extends ImportDirectiveWithUri {
|
||||
class ImportDirectiveWithFile
|
||||
extends ImportDirectiveWithUri<DirectiveUriWithFile> {
|
||||
final LibraryOrAugmentationFileKind container;
|
||||
final FileState importedFile;
|
||||
|
||||
ImportDirectiveWithFile({
|
||||
required this.container,
|
||||
required super.directive,
|
||||
required this.importedFile,
|
||||
required super.selectedUriStr,
|
||||
required super.selectedUri,
|
||||
required super.uris,
|
||||
}) {
|
||||
importedFile.referencingFiles.add(container.file);
|
||||
}
|
||||
|
||||
FileState get importedFile => selectedUri.file;
|
||||
|
||||
/// Returns [importedFile] if it is a library.
|
||||
LibraryFileStateKind? get importedLibrary {
|
||||
final kind = importedFile.kind;
|
||||
|
@ -1572,14 +1714,12 @@ class ImportDirectiveWithFile extends ImportDirectiveWithUri {
|
|||
}
|
||||
|
||||
/// [ImportDirectiveWithUri] with a URI that resolves to [InSummarySource].
|
||||
class ImportDirectiveWithInSummarySource extends ImportDirectiveWithUri {
|
||||
@override
|
||||
final InSummarySource importedSource;
|
||||
|
||||
class ImportDirectiveWithInSummarySource
|
||||
extends ImportDirectiveWithUri<DirectiveUriWithInSummarySource> {
|
||||
ImportDirectiveWithInSummarySource({
|
||||
required super.directive,
|
||||
required this.importedSource,
|
||||
required super.selectedUriStr,
|
||||
required super.selectedUri,
|
||||
required super.uris,
|
||||
});
|
||||
|
||||
@override
|
||||
|
@ -1590,15 +1730,18 @@ class ImportDirectiveWithInSummarySource extends ImportDirectiveWithUri {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
InSummarySource get importedSource => selectedUri.source;
|
||||
}
|
||||
|
||||
/// [ImportDirectiveState] that has a valid URI.
|
||||
class ImportDirectiveWithUri extends ImportDirectiveState {
|
||||
final String selectedUriStr;
|
||||
|
||||
class ImportDirectiveWithUri<U extends DirectiveUriWithUri>
|
||||
extends ImportDirectiveState<U> {
|
||||
ImportDirectiveWithUri({
|
||||
required super.directive,
|
||||
required this.selectedUriStr,
|
||||
required super.selectedUri,
|
||||
required super.uris,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1658,37 +1801,24 @@ class LibraryFileStateKind extends LibraryOrAugmentationFileKind {
|
|||
|
||||
List<PartDirectiveState> get parts {
|
||||
return _parts ??= file.unlinked2.parts.map((directive) {
|
||||
final uriStr = directive.uri;
|
||||
if (uriStr != null) {
|
||||
return file._fileForRelativeUri(uriStr).map(
|
||||
(refFile) {
|
||||
if (refFile != null) {
|
||||
return PartDirectiveWithFile(
|
||||
library: this,
|
||||
directive: directive,
|
||||
includedFile: refFile,
|
||||
uriStr: uriStr,
|
||||
);
|
||||
} else {
|
||||
return PartDirectiveWithUri(
|
||||
library: this,
|
||||
directive: directive,
|
||||
uriStr: uriStr,
|
||||
);
|
||||
}
|
||||
},
|
||||
(externalLibrary) {
|
||||
return PartDirectiveWithUri(
|
||||
library: this,
|
||||
directive: directive,
|
||||
uriStr: uriStr,
|
||||
);
|
||||
},
|
||||
final uri = file._buildDirectiveUri(directive.uri);
|
||||
if (uri is DirectiveUriWithFile) {
|
||||
return PartDirectiveWithFile(
|
||||
library: this,
|
||||
directive: directive,
|
||||
uri: uri,
|
||||
);
|
||||
} else if (uri is DirectiveUriWithUri) {
|
||||
return PartDirectiveWithUri(
|
||||
library: this,
|
||||
directive: directive,
|
||||
uri: uri,
|
||||
);
|
||||
} else {
|
||||
return PartDirectiveState(
|
||||
library: this,
|
||||
directive: directive,
|
||||
uri: uri,
|
||||
);
|
||||
}
|
||||
}).toList();
|
||||
|
@ -1750,105 +1880,90 @@ abstract class LibraryOrAugmentationFileKind extends FileStateKind {
|
|||
|
||||
List<ImportAugmentationDirectiveState> get augmentations {
|
||||
return _augmentations ??= file.unlinked2.augmentations.map((directive) {
|
||||
final uriStr = directive.uri;
|
||||
if (uriStr != null) {
|
||||
return file._fileForRelativeUri(uriStr).map(
|
||||
(refFile) {
|
||||
if (refFile != null) {
|
||||
return ImportAugmentationDirectiveWithFile(
|
||||
container: this,
|
||||
directive: directive,
|
||||
importedFile: refFile,
|
||||
);
|
||||
} else {
|
||||
return ImportAugmentationWithUri(
|
||||
directive: directive,
|
||||
uriStr: uriStr,
|
||||
);
|
||||
}
|
||||
},
|
||||
(externalLibrary) {
|
||||
return ImportAugmentationWithUri(
|
||||
directive: directive,
|
||||
uriStr: uriStr,
|
||||
);
|
||||
},
|
||||
final uri = file._buildDirectiveUri(directive.uri);
|
||||
if (uri is DirectiveUriWithFile) {
|
||||
return ImportAugmentationDirectiveWithFile(
|
||||
container: this,
|
||||
directive: directive,
|
||||
uri: uri,
|
||||
);
|
||||
} else if (uri is DirectiveUriWithUri) {
|
||||
return ImportAugmentationWithUri(
|
||||
directive: directive,
|
||||
uri: uri,
|
||||
);
|
||||
} else {
|
||||
return ImportAugmentationDirectiveState(
|
||||
directive: directive,
|
||||
uri: uri,
|
||||
);
|
||||
}
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<ExportDirectiveState> get exports {
|
||||
return _exports ??= file.unlinked2.exports.map((directive) {
|
||||
final uriStr = file._selectRelativeUri(directive);
|
||||
if (uriStr != null) {
|
||||
return file._fileForRelativeUri(uriStr).map(
|
||||
(refFile) {
|
||||
if (refFile != null) {
|
||||
return ExportDirectiveWithFile(
|
||||
container: this,
|
||||
directive: directive,
|
||||
exportedFile: refFile,
|
||||
selectedUriStr: uriStr,
|
||||
);
|
||||
} else {
|
||||
return ExportDirectiveWithUri(
|
||||
directive: directive,
|
||||
selectedUriStr: uriStr,
|
||||
);
|
||||
}
|
||||
},
|
||||
(externalLibrary) {
|
||||
return ExportDirectiveWithInSummarySource(
|
||||
directive: directive,
|
||||
exportedSource: externalLibrary.source,
|
||||
selectedUriStr: uriStr,
|
||||
);
|
||||
},
|
||||
return _exports ??=
|
||||
file.unlinked2.exports.map<ExportDirectiveState>((directive) {
|
||||
final uris = file._buildNamespaceDirectiveUris(directive);
|
||||
final selectedUri = uris.selected;
|
||||
if (selectedUri is DirectiveUriWithFile) {
|
||||
return ExportDirectiveWithFile(
|
||||
container: this,
|
||||
directive: directive,
|
||||
selectedUri: selectedUri,
|
||||
uris: uris,
|
||||
);
|
||||
} else if (selectedUri is DirectiveUriWithInSummarySource) {
|
||||
return ExportDirectiveWithInSummarySource(
|
||||
directive: directive,
|
||||
selectedUri: selectedUri,
|
||||
uris: uris,
|
||||
);
|
||||
} else if (selectedUri is DirectiveUriWithUri) {
|
||||
return ExportDirectiveWithUri(
|
||||
directive: directive,
|
||||
selectedUri: selectedUri,
|
||||
uris: uris,
|
||||
);
|
||||
} else {
|
||||
return ExportDirectiveState(
|
||||
directive: directive,
|
||||
selectedUri: selectedUri,
|
||||
uris: uris,
|
||||
);
|
||||
}
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<ImportDirectiveState> get imports {
|
||||
return _imports ??= file.unlinked2.imports.map((directive) {
|
||||
final uriStr = file._selectRelativeUri(directive);
|
||||
if (uriStr != null) {
|
||||
return file._fileForRelativeUri(uriStr).map(
|
||||
(refFile) {
|
||||
if (refFile != null) {
|
||||
return ImportDirectiveWithFile(
|
||||
container: this,
|
||||
directive: directive,
|
||||
importedFile: refFile,
|
||||
selectedUriStr: uriStr,
|
||||
);
|
||||
} else {
|
||||
return ImportDirectiveWithUri(
|
||||
directive: directive,
|
||||
selectedUriStr: uriStr,
|
||||
);
|
||||
}
|
||||
},
|
||||
(externalLibrary) {
|
||||
return ImportDirectiveWithInSummarySource(
|
||||
directive: directive,
|
||||
importedSource: externalLibrary.source,
|
||||
selectedUriStr: uriStr,
|
||||
);
|
||||
},
|
||||
return _imports ??=
|
||||
file.unlinked2.imports.map<ImportDirectiveState>((directive) {
|
||||
final uris = file._buildNamespaceDirectiveUris(directive);
|
||||
final selectedUri = uris.selected;
|
||||
if (selectedUri is DirectiveUriWithFile) {
|
||||
return ImportDirectiveWithFile(
|
||||
container: this,
|
||||
directive: directive,
|
||||
selectedUri: selectedUri,
|
||||
uris: uris,
|
||||
);
|
||||
} else if (selectedUri is DirectiveUriWithInSummarySource) {
|
||||
return ImportDirectiveWithInSummarySource(
|
||||
directive: directive,
|
||||
selectedUri: selectedUri,
|
||||
uris: uris,
|
||||
);
|
||||
} else if (selectedUri is DirectiveUriWithUri) {
|
||||
return ImportDirectiveWithUri(
|
||||
directive: directive,
|
||||
selectedUri: selectedUri,
|
||||
uris: uris,
|
||||
);
|
||||
} else {
|
||||
return ImportDirectiveState(
|
||||
directive: directive,
|
||||
selectedUri: selectedUri,
|
||||
uris: uris,
|
||||
);
|
||||
}
|
||||
}).toList();
|
||||
|
@ -1912,14 +2027,28 @@ abstract class LibraryOrAugmentationFileKind extends FileStateKind {
|
|||
}
|
||||
}
|
||||
|
||||
class NamespaceDirectiveUris {
|
||||
final DirectiveUri primary;
|
||||
final List<DirectiveUri> configurations;
|
||||
final DirectiveUri selected;
|
||||
|
||||
NamespaceDirectiveUris({
|
||||
required this.primary,
|
||||
required this.configurations,
|
||||
required this.selected,
|
||||
});
|
||||
}
|
||||
|
||||
/// Information about a single `part` directive.
|
||||
class PartDirectiveState extends DirectiveState {
|
||||
class PartDirectiveState<U extends DirectiveUri> extends DirectiveState {
|
||||
final LibraryFileStateKind library;
|
||||
final UnlinkedPartDirective directive;
|
||||
final U uri;
|
||||
|
||||
PartDirectiveState({
|
||||
required this.library,
|
||||
required this.directive,
|
||||
required this.uri,
|
||||
});
|
||||
|
||||
/// Returns a [Source] that is referenced by this directive.
|
||||
|
@ -1929,18 +2058,17 @@ class PartDirectiveState extends DirectiveState {
|
|||
}
|
||||
|
||||
/// [PartDirectiveWithUri] that has a valid URI that references a file.
|
||||
class PartDirectiveWithFile extends PartDirectiveWithUri {
|
||||
final FileState includedFile;
|
||||
|
||||
class PartDirectiveWithFile extends PartDirectiveWithUri<DirectiveUriWithFile> {
|
||||
PartDirectiveWithFile({
|
||||
required super.library,
|
||||
required super.directive,
|
||||
required super.uriStr,
|
||||
required this.includedFile,
|
||||
required super.uri,
|
||||
}) {
|
||||
includedFile.referencingFiles.add(library.file);
|
||||
}
|
||||
|
||||
FileState get includedFile => uri.file;
|
||||
|
||||
/// If [includedFile] is a [PartFileStateKind], and it confirms that it
|
||||
/// is a part of the [library], returns the [includedFile].
|
||||
PartFileStateKind? get includedPart {
|
||||
|
@ -1961,13 +2089,12 @@ class PartDirectiveWithFile extends PartDirectiveWithUri {
|
|||
}
|
||||
|
||||
/// [PartDirectiveState] that has a valid URI.
|
||||
class PartDirectiveWithUri extends PartDirectiveState {
|
||||
final String uriStr;
|
||||
|
||||
class PartDirectiveWithUri<U extends DirectiveUriWithUri>
|
||||
extends PartDirectiveState<U> {
|
||||
PartDirectiveWithUri({
|
||||
required super.library,
|
||||
required super.directive,
|
||||
required this.uriStr,
|
||||
required super.uri,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -41,16 +41,13 @@ import 'package:analyzer/src/generated/error_verifier.dart';
|
|||
import 'package:analyzer/src/generated/ffi_verifier.dart';
|
||||
import 'package:analyzer/src/generated/resolver.dart';
|
||||
import 'package:analyzer/src/generated/source.dart';
|
||||
import 'package:analyzer/src/generated/utilities_dart.dart';
|
||||
import 'package:analyzer/src/hint/sdk_constraint_verifier.dart';
|
||||
import 'package:analyzer/src/ignore_comments/ignore_info.dart';
|
||||
import 'package:analyzer/src/lint/linter.dart';
|
||||
import 'package:analyzer/src/lint/linter_visitor.dart';
|
||||
import 'package:analyzer/src/services/lint.dart';
|
||||
import 'package:analyzer/src/summary/package_bundle_reader.dart';
|
||||
import 'package:analyzer/src/task/strong/checker.dart';
|
||||
import 'package:analyzer/src/util/performance/operation_performance.dart';
|
||||
import 'package:analyzer/src/util/uri.dart';
|
||||
|
||||
class AnalysisForCompletionResult {
|
||||
final CompilationUnit parsedUnit;
|
||||
|
@ -66,7 +63,6 @@ class AnalysisForCompletionResult {
|
|||
class LibraryAnalyzer {
|
||||
final AnalysisOptionsImpl _analysisOptions;
|
||||
final DeclaredVariables _declaredVariables;
|
||||
final SourceFactory _sourceFactory;
|
||||
final LibraryFileStateKind _library;
|
||||
final InheritanceManager3 _inheritance;
|
||||
|
||||
|
@ -79,13 +75,8 @@ class LibraryAnalyzer {
|
|||
final Map<FileState, ErrorReporter> _errorReporters = {};
|
||||
final TestingData? _testingData;
|
||||
|
||||
LibraryAnalyzer(
|
||||
this._analysisOptions,
|
||||
this._declaredVariables,
|
||||
this._sourceFactory,
|
||||
this._libraryElement,
|
||||
this._inheritance,
|
||||
this._library,
|
||||
LibraryAnalyzer(this._analysisOptions, this._declaredVariables,
|
||||
this._libraryElement, this._inheritance, this._library,
|
||||
{TestingData? testingData})
|
||||
: _testingData = testingData;
|
||||
|
||||
|
@ -296,13 +287,17 @@ class LibraryAnalyzer {
|
|||
// This must happen after all other diagnostics have been computed but
|
||||
// before the list of diagnostics has been filtered.
|
||||
for (var file in _library.files) {
|
||||
IgnoreValidator(
|
||||
_getErrorReporter(file),
|
||||
_getErrorListener(file).errors,
|
||||
_fileToIgnoreInfo[file]!,
|
||||
_fileToLineInfo[file]!,
|
||||
_analysisOptions.unignorableNames,
|
||||
).reportErrors();
|
||||
final ignoreInfo = _fileToIgnoreInfo[file];
|
||||
// TODO(scheglov) make it safer
|
||||
if (ignoreInfo != null) {
|
||||
IgnoreValidator(
|
||||
_getErrorReporter(file),
|
||||
_getErrorListener(file).errors,
|
||||
ignoreInfo,
|
||||
_fileToLineInfo[file]!,
|
||||
_analysisOptions.unignorableNames,
|
||||
).reportErrors();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -439,11 +434,6 @@ class LibraryAnalyzer {
|
|||
checker.visitCompilationUnit(unit);
|
||||
}
|
||||
|
||||
//
|
||||
// Validate the directives.
|
||||
//
|
||||
_validateUriBasedDirectives(file, unit);
|
||||
|
||||
//
|
||||
// Use the ConstantVerifier to compute errors.
|
||||
//
|
||||
|
@ -515,42 +505,6 @@ class LibraryAnalyzer {
|
|||
});
|
||||
}
|
||||
|
||||
/// Return the name of the library that the given part is declared to be a
|
||||
/// part of, or `null` if the part does not contain a part-of directive.
|
||||
_NameOrSource? _getPartLibraryNameOrUri(Source partSource,
|
||||
CompilationUnit partUnit, List<Directive> directivesToResolve) {
|
||||
for (Directive directive in partUnit.directives) {
|
||||
if (directive is PartOfDirective) {
|
||||
directivesToResolve.add(directive);
|
||||
LibraryIdentifier? libraryName = directive.libraryName;
|
||||
if (libraryName != null) {
|
||||
return _NameOrSource(libraryName.name, null);
|
||||
}
|
||||
String? uri = directive.uri?.stringValue;
|
||||
if (uri != null) {
|
||||
Source? librarySource = _sourceFactory.resolveUri(partSource, uri);
|
||||
if (librarySource != null) {
|
||||
return _NameOrSource(null, librarySource);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
bool _isExistingSource(Source source) {
|
||||
if (source is InSummarySource) {
|
||||
return true;
|
||||
}
|
||||
for (var file in _library.file.directReferencedFiles) {
|
||||
if (file.uri == source.uri) {
|
||||
return file.exists;
|
||||
}
|
||||
}
|
||||
// A library can refer to itself with an empty URI.
|
||||
return source == _library.file.source;
|
||||
}
|
||||
|
||||
/// Return a new parsed unresolved [CompilationUnit].
|
||||
CompilationUnitImpl _parse(FileState file) {
|
||||
AnalysisErrorListener errorListener = _getErrorListener(file);
|
||||
|
@ -565,21 +519,28 @@ class LibraryAnalyzer {
|
|||
|
||||
/// Parse and resolve all files in [_library].
|
||||
Map<FileState, CompilationUnitImpl> _parseAndResolve() {
|
||||
var units = <FileState, CompilationUnitImpl>{};
|
||||
|
||||
// Parse all files.
|
||||
for (FileState file in _library.files) {
|
||||
units[file] = _parse(file);
|
||||
final libraryFile = _library.file;
|
||||
final libraryUnit = _parse(libraryFile);
|
||||
final units = <FileState, CompilationUnitImpl>{
|
||||
libraryFile: libraryUnit,
|
||||
};
|
||||
for (final part in _library.parts) {
|
||||
if (part is PartDirectiveWithFile) {
|
||||
final partFile = part.includedPart?.file;
|
||||
if (partFile != null) {
|
||||
units[partFile] = _parse(partFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve URIs in directives to corresponding sources.
|
||||
FeatureSet featureSet = units[_library.file]!.featureSet;
|
||||
final featureSet = _libraryElement.featureSet;
|
||||
units.forEach((file, unit) {
|
||||
_validateFeatureSet(unit, featureSet);
|
||||
_resolveUriBasedDirectives(file, unit);
|
||||
});
|
||||
|
||||
_resolveDirectives(units);
|
||||
_resolveDirectives(units, libraryUnit);
|
||||
|
||||
units.forEach((file, unit) {
|
||||
_resolveFile(file, unit);
|
||||
|
@ -590,136 +551,56 @@ class LibraryAnalyzer {
|
|||
return units;
|
||||
}
|
||||
|
||||
void _resolveDirectives(Map<FileState, CompilationUnitImpl> units) {
|
||||
var definingCompilationUnit = units[_library.file]!;
|
||||
definingCompilationUnit.element = _libraryElement.definingCompilationUnit;
|
||||
|
||||
bool matchNodeElement(Directive node, Element element) {
|
||||
return node.keyword.offset == element.nameOffset;
|
||||
}
|
||||
void _resolveDirectives(
|
||||
Map<FileState, CompilationUnitImpl> units,
|
||||
CompilationUnitImpl libraryUnit,
|
||||
) {
|
||||
libraryUnit.element = _libraryElement.definingCompilationUnit;
|
||||
|
||||
ErrorReporter libraryErrorReporter = _getErrorReporter(_library.file);
|
||||
|
||||
var importIndex = 0;
|
||||
var exportIndex = 0;
|
||||
|
||||
LibraryIdentifier? libraryNameNode;
|
||||
var seenPartSources = <Source>{};
|
||||
var directivesToResolve = <DirectiveImpl>[];
|
||||
int partDirectiveIndex = 0;
|
||||
int partElementIndex = 0;
|
||||
for (Directive directive in definingCompilationUnit.directives) {
|
||||
final partIndexes = _PartDirectiveIndexes();
|
||||
for (Directive directive in libraryUnit.directives) {
|
||||
if (directive is LibraryDirectiveImpl) {
|
||||
libraryNameNode = directive.name;
|
||||
directivesToResolve.add(directive);
|
||||
} else if (directive is ImportDirectiveImpl) {
|
||||
// TODO(scheglov) Rewrite to iterating `ImportDirectiveState`.
|
||||
for (var index = 0; index < _libraryElement.imports.length; index++) {
|
||||
final importElement = _libraryElement.imports[index];
|
||||
if (matchNodeElement(directive, importElement)) {
|
||||
directive.element = importElement;
|
||||
directive.prefix?.staticElement = importElement.prefix;
|
||||
final importDirectiveState = _library.imports[index];
|
||||
// TODO(scheglov) rewrite
|
||||
if (importDirectiveState is ImportDirectiveWithUri) {
|
||||
if (importDirectiveState.importedSource != null) {
|
||||
if (importDirectiveState.importedLibrarySource == null) {
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY,
|
||||
directive.uri,
|
||||
[importDirectiveState.selectedUriStr],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (directive.augmentKeyword != null) {
|
||||
// TODO(scheglov) implement
|
||||
throw UnimplementedError();
|
||||
} else {
|
||||
_resolveImportDirective(
|
||||
directive: directive,
|
||||
importElement: _libraryElement.imports[importIndex],
|
||||
importState: _library.imports[importIndex],
|
||||
libraryErrorReporter: libraryErrorReporter,
|
||||
);
|
||||
importIndex++;
|
||||
}
|
||||
} else if (directive is ExportDirectiveImpl) {
|
||||
// TODO(scheglov) Rewrite to iterating `ExportDirectiveState`.
|
||||
for (var index = 0; index < _libraryElement.exports.length; index++) {
|
||||
final exportElement = _libraryElement.exports[index];
|
||||
if (matchNodeElement(directive, exportElement)) {
|
||||
directive.element = exportElement;
|
||||
final exportDirectiveState = _library.exports[index];
|
||||
// TODO(scheglov) rewrite
|
||||
if (exportDirectiveState is ExportDirectiveWithUri) {
|
||||
if (exportDirectiveState.exportedSource != null) {
|
||||
if (exportDirectiveState.exportedLibrarySource == null) {
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
|
||||
directive.uri,
|
||||
[exportDirectiveState.selectedUriStr],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_resolveExportDirective(
|
||||
directive: directive,
|
||||
exportElement: _libraryElement.exports[exportIndex],
|
||||
exportState: _library.exports[exportIndex],
|
||||
libraryErrorReporter: libraryErrorReporter,
|
||||
);
|
||||
exportIndex++;
|
||||
} else if (directive is PartDirectiveImpl) {
|
||||
StringLiteral partUri = directive.uri;
|
||||
|
||||
if (partElementIndex >= _libraryElement.parts.length) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final partState = _library.parts[partDirectiveIndex++];
|
||||
if (partState is! PartDirectiveWithFile) {
|
||||
continue;
|
||||
}
|
||||
final partFile = partState.includedFile;
|
||||
|
||||
var partUnit = units[partFile]!;
|
||||
var partElement = _libraryElement.parts[partElementIndex++];
|
||||
partUnit.element = partElement;
|
||||
directive.element = partElement;
|
||||
|
||||
Source? partSource = directive.uriSource;
|
||||
if (partSource == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// Validate that the part source is unique in the library.
|
||||
//
|
||||
if (!seenPartSources.add(partSource)) {
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.DUPLICATE_PART, partUri, [partSource.uri]);
|
||||
}
|
||||
|
||||
//
|
||||
// Validate that the part contains a part-of directive with the same
|
||||
// name or uri as the library.
|
||||
//
|
||||
if (_isExistingSource(partSource)) {
|
||||
_NameOrSource? nameOrSource = _getPartLibraryNameOrUri(
|
||||
partSource, partUnit, directivesToResolve);
|
||||
if (nameOrSource == null) {
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.PART_OF_NON_PART,
|
||||
partUri,
|
||||
[partUri.toSource()]);
|
||||
} else {
|
||||
String? name = nameOrSource.name;
|
||||
if (name != null) {
|
||||
if (libraryNameNode == null) {
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.PART_OF_UNNAMED_LIBRARY,
|
||||
partUri,
|
||||
[name]);
|
||||
} else if (libraryNameNode.name != name) {
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.PART_OF_DIFFERENT_LIBRARY,
|
||||
partUri,
|
||||
[libraryNameNode.name, name]);
|
||||
}
|
||||
} else {
|
||||
Source source = nameOrSource.source!;
|
||||
if (source != _library.file.source) {
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.PART_OF_DIFFERENT_LIBRARY,
|
||||
partUri,
|
||||
[_library.file.uriStr, source.uri]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_resolvePartDirective(
|
||||
directive: directive,
|
||||
partIndexes: partIndexes,
|
||||
libraryErrorReporter: libraryErrorReporter,
|
||||
libraryNameNode: libraryNameNode,
|
||||
units: units,
|
||||
directivesToResolve: directivesToResolve,
|
||||
seenPartSources: seenPartSources,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -734,6 +615,62 @@ class LibraryAnalyzer {
|
|||
}
|
||||
}
|
||||
|
||||
void _resolveExportDirective({
|
||||
required ExportDirectiveImpl directive,
|
||||
required ExportElement exportElement,
|
||||
required ExportDirectiveState exportState,
|
||||
required ErrorReporter libraryErrorReporter,
|
||||
}) {
|
||||
directive.element = exportElement;
|
||||
_resolveNamespaceDirective(
|
||||
directive: directive,
|
||||
primaryUriNode: directive.uri,
|
||||
primaryUriState: exportState.uris.primary,
|
||||
configurationNodes: directive.configurations,
|
||||
configurationUris: exportState.uris.configurations,
|
||||
selectedUriState: exportState.selectedUri,
|
||||
);
|
||||
if (exportState is ExportDirectiveWithUri) {
|
||||
final selectedUriStr = exportState.selectedUri.relativeUriStr;
|
||||
if (selectedUriStr.startsWith('dart-ext:')) {
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.USE_OF_NATIVE_EXTENSION,
|
||||
directive.uri,
|
||||
);
|
||||
} else if (exportState.exportedSource == null) {
|
||||
final errorCode = exportState.selectedUri.isValid
|
||||
? CompileTimeErrorCode.URI_DOES_NOT_EXIST
|
||||
: CompileTimeErrorCode.INVALID_URI;
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
errorCode,
|
||||
directive.uri,
|
||||
[selectedUriStr],
|
||||
);
|
||||
} else if (exportState is ExportDirectiveWithFile &&
|
||||
!exportState.exportedFile.exists) {
|
||||
final errorCode = isGeneratedSource(exportState.exportedSource)
|
||||
? CompileTimeErrorCode.URI_HAS_NOT_BEEN_GENERATED
|
||||
: CompileTimeErrorCode.URI_DOES_NOT_EXIST;
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
errorCode,
|
||||
directive.uri,
|
||||
[selectedUriStr],
|
||||
);
|
||||
} else if (exportState.exportedLibrarySource == null) {
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
|
||||
directive.uri,
|
||||
[selectedUriStr],
|
||||
);
|
||||
}
|
||||
} else {
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.URI_WITH_INTERPOLATION,
|
||||
directive.uri,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _resolveFile(FileState file, CompilationUnit unit) {
|
||||
var source = file.source;
|
||||
RecordingErrorListener errorListener = _getErrorListener(file);
|
||||
|
@ -772,86 +709,202 @@ class LibraryAnalyzer {
|
|||
featureSet: unit.featureSet, flowAnalysisHelper: flowAnalysisHelper));
|
||||
}
|
||||
|
||||
Uri? _resolveRelativeUri(String relativeUriStr) {
|
||||
Uri relativeUri;
|
||||
try {
|
||||
relativeUri = Uri.parse(relativeUriStr);
|
||||
} on FormatException {
|
||||
return null;
|
||||
void _resolveImportDirective({
|
||||
required ImportDirectiveImpl directive,
|
||||
required ImportElement importElement,
|
||||
required ImportDirectiveState importState,
|
||||
required ErrorReporter libraryErrorReporter,
|
||||
}) {
|
||||
directive.element = importElement;
|
||||
directive.prefix?.staticElement = importElement.prefix;
|
||||
_resolveNamespaceDirective(
|
||||
directive: directive,
|
||||
primaryUriNode: directive.uri,
|
||||
primaryUriState: importState.uris.primary,
|
||||
configurationNodes: directive.configurations,
|
||||
configurationUris: importState.uris.configurations,
|
||||
selectedUriState: importState.selectedUri,
|
||||
);
|
||||
if (importState is ImportDirectiveWithUri) {
|
||||
final selectedUriStr = importState.selectedUri.relativeUriStr;
|
||||
if (selectedUriStr.startsWith('dart-ext:')) {
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.USE_OF_NATIVE_EXTENSION,
|
||||
directive.uri,
|
||||
);
|
||||
} else if (importState.importedSource == null) {
|
||||
final errorCode = importState.selectedUri.isValid
|
||||
? CompileTimeErrorCode.URI_DOES_NOT_EXIST
|
||||
: CompileTimeErrorCode.INVALID_URI;
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
errorCode,
|
||||
directive.uri,
|
||||
[selectedUriStr],
|
||||
);
|
||||
} else if (importState is ImportDirectiveWithFile &&
|
||||
!importState.importedFile.exists) {
|
||||
final errorCode = isGeneratedSource(importState.importedSource)
|
||||
? CompileTimeErrorCode.URI_HAS_NOT_BEEN_GENERATED
|
||||
: CompileTimeErrorCode.URI_DOES_NOT_EXIST;
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
errorCode,
|
||||
directive.uri,
|
||||
[selectedUriStr],
|
||||
);
|
||||
} else if (importState.importedLibrarySource == null) {
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY,
|
||||
directive.uri,
|
||||
[selectedUriStr],
|
||||
);
|
||||
}
|
||||
} else {
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.URI_WITH_INTERPOLATION,
|
||||
directive.uri,
|
||||
);
|
||||
}
|
||||
|
||||
var absoluteUri = resolveRelativeUri(_library.file.uri, relativeUri);
|
||||
return rewriteToCanonicalUri(_sourceFactory, absoluteUri);
|
||||
}
|
||||
|
||||
/// Return the result of resolve the given [uriContent], reporting errors
|
||||
/// against the [uriLiteral].
|
||||
Source? _resolveUri(FileState file, bool isImport, StringLiteral uriLiteral,
|
||||
String? uriContent) {
|
||||
UriValidationCode? code =
|
||||
UriBasedDirectiveImpl.validateUri(isImport, uriLiteral, uriContent);
|
||||
if (code == null) {
|
||||
try {
|
||||
Uri.parse(uriContent!);
|
||||
} on FormatException {
|
||||
return null;
|
||||
}
|
||||
return _sourceFactory.resolveUri(file.source, uriContent);
|
||||
} else if (code == UriValidationCode.URI_WITH_INTERPOLATION) {
|
||||
_getErrorReporter(file).reportErrorForNode(
|
||||
CompileTimeErrorCode.URI_WITH_INTERPOLATION, uriLiteral);
|
||||
return null;
|
||||
} else if (code == UriValidationCode.INVALID_URI) {
|
||||
// It is safe to assume [uriContent] is non-null because the only way for
|
||||
// it to be null is if the string literal contained an interpolation, and
|
||||
// in that case the validation code would have been
|
||||
// UriValidationCode.URI_WITH_INTERPOLATION.
|
||||
assert(uriContent != null);
|
||||
_getErrorReporter(file).reportErrorForNode(
|
||||
CompileTimeErrorCode.INVALID_URI, uriLiteral, [uriContent!]);
|
||||
return null;
|
||||
void _resolveNamespaceDirective({
|
||||
required NamespaceDirectiveImpl directive,
|
||||
required StringLiteralImpl primaryUriNode,
|
||||
required DirectiveUri primaryUriState,
|
||||
required DirectiveUri selectedUriState,
|
||||
required List<Configuration> configurationNodes,
|
||||
required List<DirectiveUri> configurationUris,
|
||||
}) {
|
||||
for (var i = 0; i < configurationNodes.length; i++) {
|
||||
final configurationNode = configurationNodes[i];
|
||||
configurationNode as ConfigurationImpl;
|
||||
configurationNode.uriSource = configurationUris[i].source;
|
||||
}
|
||||
|
||||
if (primaryUriState is DirectiveUriWithString) {
|
||||
directive.uriContent = primaryUriState.relativeUriStr;
|
||||
directive.uriSource = primaryUriState.source;
|
||||
}
|
||||
|
||||
if (selectedUriState is DirectiveUriWithString) {
|
||||
directive.selectedUriContent = selectedUriState.relativeUriStr;
|
||||
directive.selectedSource = selectedUriState.source;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void _resolveUriBasedDirectives(FileState file, CompilationUnit unit) {
|
||||
for (var directive in unit.directives) {
|
||||
if (directive is UriBasedDirectiveImpl) {
|
||||
StringLiteral uriLiteral = directive.uri;
|
||||
String? uriContent = uriLiteral.stringValue?.trim();
|
||||
directive.uriContent = uriContent;
|
||||
Source? defaultSource = _resolveUri(
|
||||
file, directive is ImportDirective, uriLiteral, uriContent);
|
||||
directive.uriSource = defaultSource;
|
||||
void _resolvePartDirective({
|
||||
required PartDirectiveImpl directive,
|
||||
required _PartDirectiveIndexes partIndexes,
|
||||
required ErrorReporter libraryErrorReporter,
|
||||
required LibraryIdentifier? libraryNameNode,
|
||||
required Map<FileState, CompilationUnitImpl> units,
|
||||
required List<DirectiveImpl> directivesToResolve,
|
||||
required Set<Source> seenPartSources,
|
||||
}) {
|
||||
StringLiteral partUri = directive.uri;
|
||||
|
||||
final partState = _library.parts[partIndexes.directive++];
|
||||
directive.uriSource = partState.includedSource;
|
||||
if (partState is! PartDirectiveWithUri) {
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.URI_WITH_INTERPOLATION,
|
||||
directive.uri,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(scheglov) This should not be necessary if we build `PartElement`
|
||||
// for every `part` directive.
|
||||
if (partIndexes.element >= _libraryElement.parts.length) {
|
||||
final errorCode = partState.uri.isValid
|
||||
? CompileTimeErrorCode.URI_DOES_NOT_EXIST
|
||||
: CompileTimeErrorCode.INVALID_URI;
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
errorCode,
|
||||
directive.uri,
|
||||
[partState.uri.relativeUriStr],
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (partState is! PartDirectiveWithFile) {
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.URI_DOES_NOT_EXIST,
|
||||
directive.uri,
|
||||
[partState.uri.relativeUriStr],
|
||||
);
|
||||
return;
|
||||
}
|
||||
final includedFile = partState.includedFile;
|
||||
final includedKind = includedFile.kind;
|
||||
|
||||
if (includedKind is! PartFileStateKind) {
|
||||
if (includedFile.exists) {
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.PART_OF_NON_PART,
|
||||
partUri,
|
||||
[partUri.toSource()],
|
||||
);
|
||||
} else {
|
||||
final errorCode = isGeneratedSource(includedFile.source)
|
||||
? CompileTimeErrorCode.URI_HAS_NOT_BEEN_GENERATED
|
||||
: CompileTimeErrorCode.URI_DOES_NOT_EXIST;
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
errorCode,
|
||||
directive.uri,
|
||||
[partUri.toSource()],
|
||||
);
|
||||
}
|
||||
if (directive is NamespaceDirectiveImpl) {
|
||||
var relativeUriStr = _selectRelativeUri(directive);
|
||||
directive.selectedUriContent = relativeUriStr;
|
||||
var absoluteUri = _resolveRelativeUri(relativeUriStr);
|
||||
if (absoluteUri != null) {
|
||||
directive.selectedSource = _sourceFactory.forUri2(absoluteUri);
|
||||
}
|
||||
for (var configuration in directive.configurations) {
|
||||
configuration as ConfigurationImpl;
|
||||
var uriLiteral = configuration.uri;
|
||||
String? uriContent = uriLiteral.stringValue?.trim();
|
||||
Source? defaultSource = _resolveUri(
|
||||
file, directive is ImportDirective, uriLiteral, uriContent);
|
||||
configuration.uriSource = defaultSource;
|
||||
return;
|
||||
}
|
||||
|
||||
if (includedKind is PartOfNameFileStateKind) {
|
||||
if (!includedKind.libraries.contains(_library)) {
|
||||
final name = includedKind.directive.name;
|
||||
if (libraryNameNode == null) {
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.PART_OF_UNNAMED_LIBRARY,
|
||||
partUri,
|
||||
[name],
|
||||
);
|
||||
} else {
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.PART_OF_DIFFERENT_LIBRARY,
|
||||
partUri,
|
||||
[libraryNameNode.name, name],
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else if (includedKind.library != _library) {
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.PART_OF_DIFFERENT_LIBRARY,
|
||||
partUri,
|
||||
[_library.file.uriStr, includedFile.uriStr],
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String _selectRelativeUri(NamespaceDirective directive) {
|
||||
for (var configuration in directive.configurations) {
|
||||
var name = configuration.name.components.join('.');
|
||||
var value = configuration.value?.stringValue ?? 'true';
|
||||
if (_declaredVariables.get(name) == value) {
|
||||
return configuration.uri.stringValue ?? '';
|
||||
var partUnit = units[includedFile]!;
|
||||
var partElement = _libraryElement.parts[partIndexes.element++];
|
||||
partUnit.element = partElement;
|
||||
directive.element = partElement;
|
||||
|
||||
final partSource = includedKind.file.source;
|
||||
directive.uriSource = partSource;
|
||||
|
||||
for (final directive in partUnit.directives) {
|
||||
if (directive is PartOfDirectiveImpl) {
|
||||
directivesToResolve.add(directive);
|
||||
}
|
||||
}
|
||||
return directive.uri.stringValue ?? '';
|
||||
|
||||
//
|
||||
// Validate that the part source is unique in the library.
|
||||
//
|
||||
if (!seenPartSources.add(partSource)) {
|
||||
libraryErrorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.DUPLICATE_PART, partUri, [partSource.uri]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Validate that the feature set associated with the compilation [unit] is
|
||||
|
@ -863,61 +916,6 @@ class LibraryAnalyzer {
|
|||
}
|
||||
}
|
||||
|
||||
/// Check the given [directive] to see if the referenced source exists and
|
||||
/// report an error if it does not.
|
||||
void _validateUriBasedDirective(
|
||||
FileState file, UriBasedDirectiveImpl directive) {
|
||||
String? uriContent;
|
||||
Source? source;
|
||||
if (directive is NamespaceDirectiveImpl) {
|
||||
uriContent = directive.selectedUriContent;
|
||||
source = directive.selectedSource;
|
||||
} else {
|
||||
uriContent = directive.uriContent;
|
||||
source = directive.uriSource;
|
||||
}
|
||||
if (source != null) {
|
||||
if (_isExistingSource(source)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Don't report errors already reported by ParseDartTask.resolveDirective
|
||||
// TODO(scheglov) we don't use this task here
|
||||
if (directive.validate() != null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (uriContent != null && uriContent.startsWith('dart-ext:')) {
|
||||
_getErrorReporter(file).reportErrorForNode(
|
||||
CompileTimeErrorCode.USE_OF_NATIVE_EXTENSION,
|
||||
directive.uri,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
CompileTimeErrorCode errorCode = CompileTimeErrorCode.URI_DOES_NOT_EXIST;
|
||||
if (isGeneratedSource(source)) {
|
||||
errorCode = CompileTimeErrorCode.URI_HAS_NOT_BEEN_GENERATED;
|
||||
}
|
||||
// It is safe to assume that [uriContent] is non-null because the only way
|
||||
// for it to be null is if the string literal contained an interpolation,
|
||||
// and in that case the call to `directive.validate()` above would have
|
||||
// returned a non-null validation code.
|
||||
_getErrorReporter(file)
|
||||
.reportErrorForNode(errorCode, directive.uri, [uriContent!]);
|
||||
}
|
||||
|
||||
/// Check each directive in the given [unit] to see if the referenced source
|
||||
/// exists and report an error if it does not.
|
||||
void _validateUriBasedDirectives(FileState file, CompilationUnit unit) {
|
||||
for (Directive directive in unit.directives) {
|
||||
if (directive is UriBasedDirectiveImpl) {
|
||||
_validateUriBasedDirective(file, directive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Find constants in [unit] to compute.
|
||||
static List<ConstantEvaluationTarget> _findConstants(CompilationUnit unit) {
|
||||
ConstantFinder constantFinder = ConstantFinder();
|
||||
|
@ -1016,10 +1014,7 @@ class UnitAnalysisResult {
|
|||
UnitAnalysisResult(this.file, this.unit, this.errors);
|
||||
}
|
||||
|
||||
/// Either the name or the source associated with a part-of directive.
|
||||
class _NameOrSource {
|
||||
final String? name;
|
||||
final Source? source;
|
||||
|
||||
_NameOrSource(this.name, this.source);
|
||||
class _PartDirectiveIndexes {
|
||||
int directive = 0;
|
||||
int element = 0;
|
||||
}
|
||||
|
|
|
@ -221,6 +221,14 @@ class UnlinkedNamespaceDirectiveConfiguration {
|
|||
);
|
||||
}
|
||||
|
||||
String get valueOrTrue {
|
||||
if (value.isEmpty) {
|
||||
return 'true';
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
void write(BufferedSink sink) {
|
||||
sink.writeStringUtf8(name);
|
||||
sink.writeOptionalStringUtf8(uri);
|
||||
|
|
|
@ -581,7 +581,6 @@ class FileResolver {
|
|||
var libraryAnalyzer = LibraryAnalyzer(
|
||||
fileContext.analysisOptions,
|
||||
contextObjects!.declaredVariables,
|
||||
sourceFactory,
|
||||
elementFactory.libraryOfUri2(libraryKind.file.uri),
|
||||
analysisSession.inheritanceManager,
|
||||
libraryKind,
|
||||
|
@ -647,7 +646,6 @@ class FileResolver {
|
|||
var libraryAnalyzer = LibraryAnalyzer(
|
||||
fileContext.analysisOptions,
|
||||
contextObjects!.declaredVariables,
|
||||
sourceFactory,
|
||||
libraryContext!.elementFactory.libraryOfUri2(libraryKind.file.uri),
|
||||
libraryContext!.elementFactory.analysisSession.inheritanceManager,
|
||||
libraryKind,
|
||||
|
|
|
@ -111,7 +111,7 @@ class AnalyzerStatePrinter {
|
|||
}
|
||||
sink.writeln();
|
||||
} else if (import is ImportAugmentationWithUri) {
|
||||
final uriStr = _stringOfUriStr(import.uriStr);
|
||||
final uriStr = _stringOfUriStr(import.uri.relativeUriStr);
|
||||
_writelnWithIndent('uri: $uriStr');
|
||||
} else {
|
||||
_writelnWithIndent('noUri');
|
||||
|
@ -204,7 +204,7 @@ class AnalyzerStatePrinter {
|
|||
}
|
||||
sink.writeln();
|
||||
} else if (export is ExportDirectiveWithUri) {
|
||||
final uriStr = _stringOfUriStr(export.selectedUriStr);
|
||||
final uriStr = _stringOfUriStr(export.selectedUri.relativeUriStr);
|
||||
_writelnWithIndent('uri: $uriStr');
|
||||
} else {
|
||||
_writelnWithIndent('noUri');
|
||||
|
@ -255,8 +255,9 @@ class AnalyzerStatePrinter {
|
|||
}
|
||||
sink.writeln();
|
||||
} else if (import is ImportDirectiveWithUri) {
|
||||
final uriStr = _stringOfUriStr(import.selectedUri.relativeUriStr);
|
||||
sink.write(_indent);
|
||||
sink.write('uri: ${_stringOfUriStr(import.selectedUriStr)}');
|
||||
sink.write('uri: $uriStr');
|
||||
if (import.isSyntheticDartCoreImport) {
|
||||
sink.write(' synthetic');
|
||||
}
|
||||
|
@ -553,7 +554,7 @@ class AnalyzerStatePrinter {
|
|||
}
|
||||
sink.writeln();
|
||||
} else if (part is PartDirectiveWithUri) {
|
||||
final uriStr = _stringOfUriStr(part.uriStr);
|
||||
final uriStr = _stringOfUriStr(part.uri.relativeUriStr);
|
||||
_writelnWithIndent('uri: $uriStr');
|
||||
} else {
|
||||
_writelnWithIndent('noUri');
|
||||
|
|
|
@ -670,19 +670,11 @@ part 'c.dart';
|
|||
var session = contextFor(testFilePath).currentSession;
|
||||
var resolvedLibrary = await session.getResolvedLibraryValid(test.path);
|
||||
|
||||
expect(resolvedLibrary.units, hasLength(3));
|
||||
expect(resolvedLibrary.units, hasLength(1));
|
||||
expect(
|
||||
resolvedLibrary.units[0].path,
|
||||
convertPath('/home/test/lib/test.dart'),
|
||||
);
|
||||
expect(
|
||||
resolvedLibrary.units[1].path,
|
||||
convertPath('/home/test/lib/a.dart'),
|
||||
);
|
||||
expect(
|
||||
resolvedLibrary.units[2].path,
|
||||
convertPath('/home/test/lib/c.dart'),
|
||||
);
|
||||
}
|
||||
|
||||
test_getResolvedLibrary_invalidPath_notAbsolute() async {
|
||||
|
|
|
@ -34,11 +34,19 @@ export 'unknown.dart';
|
|||
]);
|
||||
}
|
||||
|
||||
test_export_cannotResolve() async {
|
||||
await assertErrorsInCode(r'''
|
||||
export 'dart:foo';
|
||||
''', [
|
||||
error(CompileTimeErrorCode.URI_DOES_NOT_EXIST, 7, 10),
|
||||
]);
|
||||
}
|
||||
|
||||
test_export_dart() async {
|
||||
await assertErrorsInCode('''
|
||||
export 'dart:foo/bar.dart';
|
||||
export 'dart:math/bar.dart';
|
||||
''', [
|
||||
error(CompileTimeErrorCode.URI_DOES_NOT_EXIST, 7, 19),
|
||||
error(CompileTimeErrorCode.URI_DOES_NOT_EXIST, 7, 20),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -72,11 +80,19 @@ import 'target.dart';
|
|||
]);
|
||||
}
|
||||
|
||||
test_import_cannotResolve() async {
|
||||
await assertErrorsInCode(r'''
|
||||
import 'dart:foo';
|
||||
''', [
|
||||
error(CompileTimeErrorCode.URI_DOES_NOT_EXIST, 7, 10),
|
||||
]);
|
||||
}
|
||||
|
||||
test_import_dart() async {
|
||||
await assertErrorsInCode('''
|
||||
import 'dart:foo/bar.dart';
|
||||
import 'dart:math/bar.dart';
|
||||
''', [
|
||||
error(CompileTimeErrorCode.URI_DOES_NOT_EXIST, 7, 19),
|
||||
error(CompileTimeErrorCode.URI_DOES_NOT_EXIST, 7, 20),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -107,4 +123,12 @@ part 'unknown.dart';
|
|||
error(CompileTimeErrorCode.URI_DOES_NOT_EXIST, 18, 14),
|
||||
]);
|
||||
}
|
||||
|
||||
test_part_cannotResolve() async {
|
||||
await assertErrorsInCode(r'''
|
||||
part 'dart:foo';
|
||||
''', [
|
||||
error(CompileTimeErrorCode.URI_DOES_NOT_EXIST, 5, 10),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,21 +15,27 @@ main() {
|
|||
|
||||
@reflectiveTest
|
||||
class UriWithInterpolationTest extends PubPackageResolutionTest {
|
||||
test_constant() async {
|
||||
await assertErrorsInCode('''
|
||||
import 'stuff_\$platform.dart';
|
||||
test_export() async {
|
||||
await assertErrorsInCode(r'''
|
||||
export '${'foo'}.dart';
|
||||
''', [
|
||||
error(CompileTimeErrorCode.URI_WITH_INTERPOLATION, 7, 22),
|
||||
error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 15, 8),
|
||||
error(CompileTimeErrorCode.URI_WITH_INTERPOLATION, 7, 15),
|
||||
]);
|
||||
}
|
||||
|
||||
test_nonConstant() async {
|
||||
test_import() async {
|
||||
await assertErrorsInCode(r'''
|
||||
library lib;
|
||||
part '${'a'}.dart';
|
||||
import '${'foo'}.dart';
|
||||
''', [
|
||||
error(CompileTimeErrorCode.URI_WITH_INTERPOLATION, 18, 13),
|
||||
error(CompileTimeErrorCode.URI_WITH_INTERPOLATION, 7, 15),
|
||||
]);
|
||||
}
|
||||
|
||||
test_part() async {
|
||||
await assertErrorsInCode(r'''
|
||||
part '${'foo'}.dart';
|
||||
''', [
|
||||
error(CompileTimeErrorCode.URI_WITH_INTERPOLATION, 5, 15),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue