Files
sdk/pkg/kernel/lib/import_table.dart
T
Johnni Winther 8467186ca0 [kernel] Initial migration of package kernel wave 1
This CL completes the migration of the first wave of
interdependent libraries in package:kernel, including ast.dart.

In order to ensure non-nullability on AST properties, the Transformer
has been split in 2 variants: Transformer which doesn't support
removal of nodes and RemovingTransformer which supports removal where
allowed by the context using 'removal sentinels'.

Start reviewing Transformer and RemovingTransformer in visitors.dart
since many of the changes are caused by the changes here.

Included in the migration are the mixin_deduplication.dart and
unreachable_code_elimination.dart since these needed porting to
the RemovingTransformer which was aided by opting in the libraries
which only depended on ast.dart.

TEST=existing

Change-Id: I9e63b985bd24896c25edd4ee51e37770187bcc17
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/184786
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Jens Johansen <jensj@google.com>
2021-02-18 16:01:17 +00:00

160 lines
4.9 KiB
Dart

// 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.
library kernel.import_table;
import 'ast.dart';
abstract class ImportTable {
int getImportIndex(Library library);
}
class ComponentImportTable implements ImportTable {
final Map<Library, int> _libraryIndex = <Library, int>{};
ComponentImportTable(Component component) {
for (int i = 0; i < component.libraries.length; ++i) {
_libraryIndex[component.libraries[i]] = i;
}
}
int getImportIndex(Library library) => _libraryIndex[library] ?? -1;
}
class LibraryImportTable implements ImportTable {
final List<String> _importPaths = <String>[];
final List<Library> _importedLibraries = <Library>[];
final Map<Library, int> _libraryIndex = <Library, int>{};
factory LibraryImportTable(Library lib) {
return new _ImportTableBuilder(lib).build();
}
LibraryImportTable.empty();
/// The list of imports.
///
/// Should not be modified directly, as the index map would go out of sync.
List<String> get importPaths => _importPaths;
List<Library> get importedLibraries => _importedLibraries;
int addImport(Library target, String importPath) {
int? index = _libraryIndex[target];
if (index != null) return index;
index = _importPaths.length;
_importPaths.add(importPath);
_importedLibraries.add(target);
_libraryIndex[target] = index;
return index;
}
/// Returns the index of the given import, or -1 if not found.
int getImportIndex(Library library) {
return _libraryIndex[library] ?? -1;
}
String getImportPath(Library library) {
return _importPaths[getImportIndex(library)];
}
}
/// Builds the import table for a given library.
class _ImportTableBuilder extends RecursiveVisitor {
final LibraryImportTable table = new LibraryImportTable.empty();
final Library referenceLibrary;
LibraryImportTable build() {
referenceLibrary.accept(this);
return table;
}
_ImportTableBuilder(this.referenceLibrary) {
table.addImport(referenceLibrary, '');
}
void addLibraryImport(Library? target) {
if (target == referenceLibrary) return; // Self-reference is special.
if (target == null) return;
Uri referenceUri = referenceLibrary.importUri;
Uri? targetUri = target.importUri;
// ignore: unnecessary_null_comparison
if (targetUri == null) {
throw '$referenceUri cannot refer to library without an import URI';
}
// To support using custom-uris in unit tests, we don't check directly
// whether the scheme is 'file:', but instead we check that is not 'dart:'
// or 'package:'.
bool isFileOrCustomScheme(Uri uri) =>
uri.scheme != '' && uri.scheme != 'package' && uri.scheme != 'dart';
bool isTargetSchemeFileOrCustom = isFileOrCustomScheme(targetUri);
bool isReferenceSchemeFileOrCustom = isFileOrCustomScheme(referenceUri);
if (isTargetSchemeFileOrCustom && isReferenceSchemeFileOrCustom) {
String relativeUri = relativeUriPath(targetUri, referenceUri);
table.addImport(target, relativeUri);
} else if (isTargetSchemeFileOrCustom) {
// Cannot import a file:URI from a dart:URI or package:URI.
// We may want to remove this restriction, but for now it's just a sanity
// check.
throw '$referenceUri cannot refer to application library $targetUri';
} else {
table.addImport(target, target.importUri.toString());
}
}
visitClassReference(Class node) {
addLibraryImport(node.enclosingLibrary);
}
visitLibrary(Library node) {
super.visitLibrary(node);
for (Reference exportedReference in node.additionalExports) {
addLibraryImport(exportedReference.node!.parent as Library);
}
}
defaultMemberReference(Member node) {
addLibraryImport(node.enclosingLibrary);
}
visitName(Name name) {
if (name.library != null) {
addLibraryImport(name.library);
}
}
}
String relativeUriPath(Uri target, Uri ref) {
List<String> targetSegments = target.pathSegments;
List<String> refSegments = ref.pathSegments;
int to = refSegments.length;
if (targetSegments.length < to) to = targetSegments.length;
to--; // The last entry is the filename, here we compare only directories.
int same = -1;
for (int i = 0; i < to; i++) {
if (targetSegments[i] == refSegments[i]) {
same = i;
} else {
break;
}
}
if (same == targetSegments.length - 2 &&
targetSegments.length == refSegments.length) {
// Both parts have the same number of segments,
// and they agree on all directories.
if (targetSegments.last == "") return ".";
return targetSegments.last;
}
List<String> path = <String>[];
int oked = same + 1;
while (oked < refSegments.length - 1) {
path.add("..");
oked++;
}
path.addAll(targetSegments.skip(same + 1));
if (path.isEmpty) path.add(".");
return path.join("/");
}