Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(150)

Unified Diff: packages/analyzer/lib/src/summary/prelink.dart

Issue 2990843002: Removed fixed dependencies (Closed)
Patch Set: Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: packages/analyzer/lib/src/summary/prelink.dart
diff --git a/packages/analyzer/lib/src/summary/prelink.dart b/packages/analyzer/lib/src/summary/prelink.dart
new file mode 100644
index 0000000000000000000000000000000000000000..062676ee924d98a48bba11d8532392171bfd8492
--- /dev/null
+++ b/packages/analyzer/lib/src/summary/prelink.dart
@@ -0,0 +1,544 @@
+// 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/utilities_dart.dart';
+import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/summary/name_filter.dart';
+
+/**
+ * Create a [LinkedLibraryBuilder] corresponding to the given
+ * [definingUnit], which should be the defining compilation unit for a library.
+ * Compilation units referenced by the defining compilation unit via `part`
+ * declarations will be retrieved using [getPart]. Public namespaces for
+ * libraries referenced by the defining compilation unit via `import`
+ * declarations (and files reachable from them via `part` and `export`
+ * declarations) will be retrieved using [getImport].
+ */
+LinkedLibraryBuilder prelink(UnlinkedUnit definingUnit, GetPartCallback getPart,
+ GetImportCallback getImport, GetDeclaredVariable getDeclaredVariable) {
+ return new _Prelinker(definingUnit, getPart, getImport, getDeclaredVariable)
+ .prelink();
+}
+
+/**
+ * Return the raw string value of the variable with the given [name],
+ * or `null` of the variable is not defined.
+ */
+typedef String GetDeclaredVariable(String name);
+
+/**
+ * Type of the callback used by the prelinker to obtain public namespace
+ * information about libraries imported by the library to be prelinked (and
+ * the transitive closure of parts and exports reachable from those libraries).
+ * [relativeUri] should be interpreted relative to the defining compilation
+ * unit of the library being prelinked.
+ *
+ * If no file exists at the given uri, `null` should be returned.
+ */
+typedef UnlinkedPublicNamespace GetImportCallback(String relativeUri);
+
+/**
+ * Type of the callback used by the prelinker to obtain unlinked summaries of
+ * part files of the library to be prelinked. [relativeUri] should be
+ * interpreted relative to the defining compilation unit of the library being
+ * prelinked.
+ *
+ * If no file exists at the given uri, `null` should be returned.
+ */
+typedef UnlinkedUnit GetPartCallback(String relativeUri);
+
+/**
+ * A [_Meaning] representing a class.
+ */
+class _ClassMeaning extends _Meaning {
+ final Map<String, _Meaning> namespace;
+
+ _ClassMeaning(int unit, int dependency, int numTypeParameters, this.namespace)
+ : super(unit, ReferenceKind.classOrEnum, dependency, numTypeParameters);
+}
+
+/**
+ * A [_Meaning] stores all the information necessary to find the declaration
+ * referred to by a name in a namespace.
+ */
+class _Meaning {
+ /**
+ * Which unit in the dependent library contains the declared entity.
+ */
+ final int unit;
+
+ /**
+ * The kind of entity being referred to.
+ */
+ final ReferenceKind kind;
+
+ /**
+ * Which of the dependencies of the library being prelinked contains the
+ * declared entity.
+ */
+ final int dependency;
+
+ /**
+ * If the entity being referred to is generic, the number of type parameters
+ * it accepts. Otherwise zero.
+ */
+ final int numTypeParameters;
+
+ _Meaning(this.unit, this.kind, this.dependency, this.numTypeParameters);
+
+ /**
+ * Encode this [_Meaning] as a [LinkedExportName], using the given [name].
+ */
+ LinkedExportName encodeExportName(String name) {
+ return new LinkedExportNameBuilder(
+ name: name, dependency: dependency, unit: unit, kind: kind);
+ }
+
+/**
+ * Encode this [_Meaning] as a [LinkedReference].
+ */
+ LinkedReferenceBuilder encodeReference() {
+ return new LinkedReferenceBuilder(
+ unit: unit,
+ kind: kind,
+ dependency: dependency,
+ numTypeParameters: numTypeParameters);
+ }
+}
+
+/**
+ * A [_Meaning] representing a prefix introduced by an import directive.
+ */
+class _PrefixMeaning extends _Meaning {
+ final Map<String, _Meaning> namespace = <String, _Meaning>{};
+
+ _PrefixMeaning() : super(0, ReferenceKind.prefix, 0, 0);
+}
+
+/**
+ * Helper class containing temporary data structures needed to prelink a single
+ * library.
+ *
+ * Note: throughout this class, a `null` value for a relative URI represents
+ * the defining compilation unit of the library being prelinked.
+ */
+class _Prelinker {
+ final UnlinkedUnit definingUnit;
+ final GetPartCallback getPart;
+ final GetImportCallback getImport;
+ final GetDeclaredVariable getDeclaredVariable;
+
+ /**
+ * Cache of values returned by [getImport].
+ */
+ final Map<String, UnlinkedPublicNamespace> importCache =
+ <String, UnlinkedPublicNamespace>{};
+
+ /**
+ * Cache of values returned by [getPart].
+ */
+ final Map<String, UnlinkedUnit> partCache = <String, UnlinkedUnit>{};
+
+ /**
+ * Names defined inside the library being prelinked.
+ */
+ final Map<String, _Meaning> privateNamespace = <String, _Meaning>{
+ 'dynamic': new _Meaning(0, ReferenceKind.classOrEnum, 0, 0),
+ 'void': new _Meaning(0, ReferenceKind.classOrEnum, 0, 0)
+ };
+
+ /**
+ * List of dependencies of the library being prelinked. This will be output
+ * to [LinkedLibrary.dependencies].
+ */
+ final List<LinkedDependencyBuilder> dependencies = <LinkedDependencyBuilder>[
+ new LinkedDependencyBuilder()
+ ];
+
+ /**
+ * Map from the relative URI of a dependent library to the index of the
+ * corresponding entry in [dependencies].
+ */
+ final Map<String, int> uriToDependency = <String, int>{null: 0};
+
+ /**
+ * List of public namespaces corresponding to each entry in [dependencies].
+ */
+ final List<Map<String, _Meaning>> dependencyToPublicNamespace =
+ <Map<String, _Meaning>>[null];
+
+ _Prelinker(this.definingUnit, this.getPart, this.getImport,
+ this.getDeclaredVariable) {
+ partCache[null] = definingUnit;
+ importCache[null] = definingUnit.publicNamespace;
+ }
+
+ /**
+ * Compute the public namespace for the library whose URI is reachable from
+ * [definingUnit] via [relativeUri], by aggregating together public namespace
+ * information from all of its parts.
+ */
+ Map<String, _Meaning> aggregatePublicNamespace(String relativeUri) {
+ if (uriToDependency.containsKey(relativeUri)) {
+ return dependencyToPublicNamespace[uriToDependency[relativeUri]];
+ }
+ assert(dependencies.length == dependencyToPublicNamespace.length);
+ int dependency = dependencies.length;
+ uriToDependency[relativeUri] = dependency;
+ List<String> unitUris = getUnitUris(relativeUri);
+ LinkedDependencyBuilder linkedDependency = new LinkedDependencyBuilder(
+ uri: relativeUri, parts: unitUris.sublist(1));
+ dependencies.add(linkedDependency);
+
+ Map<String, _Meaning> aggregated = <String, _Meaning>{};
+
+ for (int unitNum = 0; unitNum < unitUris.length; unitNum++) {
+ String unitUri = unitUris[unitNum];
+ UnlinkedPublicNamespace importedNamespace = getImportCached(unitUri);
+ if (importedNamespace == null) {
+ continue;
+ }
+ for (UnlinkedPublicName name in importedNamespace.names) {
+ aggregated.putIfAbsent(name.name, () {
+ if (name.kind == ReferenceKind.classOrEnum) {
+ Map<String, _Meaning> namespace = <String, _Meaning>{};
+ name.members.forEach((executable) {
+ namespace[executable.name] = new _Meaning(
+ unitNum, executable.kind, 0, executable.numTypeParameters);
+ });
+ return new _ClassMeaning(
+ unitNum, dependency, name.numTypeParameters, namespace);
+ }
+ return new _Meaning(
+ unitNum, name.kind, dependency, name.numTypeParameters);
+ });
+ }
+ }
+
+ dependencyToPublicNamespace.add(aggregated);
+ return aggregated;
+ }
+
+ /**
+ * Compute the export namespace for the library whose URI is reachable from
+ * [definingUnit] via [relativeUri], by aggregating together public namespace
+ * information from the library and the transitive closure of its exports.
+ *
+ * If [relativeUri] is `null` (meaning the export namespace of [definingUnit]
+ * should be computed), then names defined in [definingUnit] are ignored.
+ */
+ Map<String, _Meaning> computeExportNamespace(String relativeUri) {
+ Map<String, _Meaning> exportNamespace = relativeUri == null
+ ? <String, _Meaning>{}
+ : aggregatePublicNamespace(relativeUri);
+ void chaseExports(
+ NameFilter filter, String relativeUri, Set<String> seenUris) {
+ if (seenUris.add(relativeUri)) {
+ UnlinkedPublicNamespace exportedNamespace =
+ getImportCached(relativeUri);
+ if (exportedNamespace != null) {
+ for (UnlinkedExportPublic export in exportedNamespace.exports) {
+ String relativeExportUri =
+ _selectUri(export.uri, export.configurations);
+ String exportUri = resolveUri(relativeUri, relativeExportUri);
+ NameFilter newFilter = filter.merge(
+ new NameFilter.forUnlinkedCombinators(export.combinators));
+ aggregatePublicNamespace(exportUri)
+ .forEach((String name, _Meaning meaning) {
+ if (newFilter.accepts(name) &&
+ !exportNamespace.containsKey(name)) {
+ exportNamespace[name] = meaning;
+ }
+ });
+ chaseExports(newFilter, exportUri, seenUris);
+ }
+ }
+ seenUris.remove(relativeUri);
+ }
+ }
+
+ chaseExports(NameFilter.identity, relativeUri, new Set<String>());
+ return exportNamespace;
+ }
+
+ /**
+ * Extract all the names defined in [unit] (which is the [unitNum]th unit in
+ * the library being prelinked) and store them in [privateNamespace].
+ * Excludes names introduced by `import` statements.
+ */
+ void extractPrivateNames(UnlinkedUnit unit, int unitNum) {
+ for (UnlinkedClass cls in unit.classes) {
+ privateNamespace.putIfAbsent(cls.name, () {
+ Map<String, _Meaning> namespace = <String, _Meaning>{};
+ cls.fields.forEach((field) {
+ if (field.isStatic && field.isConst) {
+ namespace[field.name] =
+ new _Meaning(unitNum, ReferenceKind.propertyAccessor, 0, 0);
+ }
+ });
+ cls.executables.forEach((executable) {
+ ReferenceKind kind = null;
+ if (executable.kind == UnlinkedExecutableKind.constructor) {
+ kind = ReferenceKind.constructor;
+ } else if (executable.kind ==
+ UnlinkedExecutableKind.functionOrMethod &&
+ executable.isStatic) {
+ kind = ReferenceKind.method;
+ } else if (executable.kind == UnlinkedExecutableKind.getter &&
+ executable.isStatic) {
+ kind = ReferenceKind.propertyAccessor;
+ }
+ if (kind != null && executable.name.isNotEmpty) {
+ namespace[executable.name] = new _Meaning(
+ unitNum, kind, 0, executable.typeParameters.length);
+ }
+ });
+ return new _ClassMeaning(
+ unitNum, 0, cls.typeParameters.length, namespace);
+ });
+ }
+ for (UnlinkedEnum enm in unit.enums) {
+ privateNamespace.putIfAbsent(enm.name, () {
+ Map<String, _Meaning> namespace = <String, _Meaning>{};
+ enm.values.forEach((UnlinkedEnumValue value) {
+ namespace[value.name] =
+ new _Meaning(unitNum, ReferenceKind.propertyAccessor, 0, 0);
+ });
+ namespace['values'] =
+ new _Meaning(unitNum, ReferenceKind.propertyAccessor, 0, 0);
+ return new _ClassMeaning(unitNum, 0, 0, namespace);
+ });
+ }
+ for (UnlinkedExecutable executable in unit.executables) {
+ privateNamespace.putIfAbsent(
+ executable.name,
+ () => new _Meaning(
+ unitNum,
+ executable.kind == UnlinkedExecutableKind.functionOrMethod
+ ? ReferenceKind.topLevelFunction
+ : ReferenceKind.topLevelPropertyAccessor,
+ 0,
+ executable.typeParameters.length));
+ }
+ for (UnlinkedTypedef typedef in unit.typedefs) {
+ privateNamespace.putIfAbsent(
+ typedef.name,
+ () => new _Meaning(unitNum, ReferenceKind.typedef, 0,
+ typedef.typeParameters.length));
+ }
+ for (UnlinkedVariable variable in unit.variables) {
+ privateNamespace.putIfAbsent(
+ variable.name,
+ () => new _Meaning(
+ unitNum, ReferenceKind.topLevelPropertyAccessor, 0, 0));
+ if (!(variable.isConst || variable.isFinal)) {
+ privateNamespace.putIfAbsent(
+ variable.name + '=',
+ () => new _Meaning(
+ unitNum, ReferenceKind.topLevelPropertyAccessor, 0, 0));
+ }
+ }
+ }
+
+ /**
+ * Filter the export namespace for the library whose URI is reachable from
+ * [definingUnit] via [relativeUri], retaining only those names accepted by
+ * [combinators], and store the resulting names in [result]. Names that
+ * already exist in [result] are not overwritten.
+ */
+ void filterExportNamespace(String relativeUri,
+ List<UnlinkedCombinator> combinators, Map<String, _Meaning> result) {
+ Map<String, _Meaning> exportNamespace = computeExportNamespace(relativeUri);
+ NameFilter filter = new NameFilter.forUnlinkedCombinators(combinators);
+ exportNamespace.forEach((String name, _Meaning meaning) {
+ if (filter.accepts(name) && !result.containsKey(name)) {
+ result[name] = meaning;
+ }
+ });
+ }
+
+ /**
+ * Wrapper around [getImport] that caches the return value in [importCache].
+ */
+ UnlinkedPublicNamespace getImportCached(String relativeUri) {
+ return importCache.putIfAbsent(relativeUri, () => getImport(relativeUri));
+ }
+
+ /**
+ * Wrapper around [getPart] that caches the return value in [partCache] and
+ * updates [importCache] appropriately.
+ */
+ UnlinkedUnit getPartCached(String relativeUri) {
+ return partCache.putIfAbsent(relativeUri, () {
+ UnlinkedUnit unit = getPart(relativeUri);
+ importCache[relativeUri] = unit?.publicNamespace;
+ return unit;
+ });
+ }
+
+ /**
+ * Compute the set of relative URIs of all the compilation units in the
+ * library whose URI is reachable from [definingUnit] via [relativeUri].
+ */
+ List<String> getUnitUris(String relativeUri) {
+ List<String> result = <String>[relativeUri];
+ UnlinkedPublicNamespace publicNamespace = getImportCached(relativeUri);
+ if (publicNamespace != null) {
+ result.addAll(publicNamespace.parts
+ .map((String uri) => resolveUri(relativeUri, uri)));
+ }
+ return result;
+ }
+
+ /**
+ * Process a single `import` declaration in the library being prelinked. The
+ * return value is the index of the imported library in [dependencies].
+ */
+ int handleImport(UnlinkedImport import) {
+ String uri = import.isImplicit
+ ? 'dart:core'
+ : _selectUri(import.uri, import.configurations);
+ Map<String, _Meaning> targetNamespace = null;
+ if (import.prefixReference != 0) {
+ // The name introduced by an import declaration can't have a prefix of
+ // its own.
+ assert(
+ definingUnit.references[import.prefixReference].prefixReference == 0);
+ String prefix = definingUnit.references[import.prefixReference].name;
+ _Meaning prefixMeaning = privateNamespace[prefix];
+ if (prefixMeaning is _PrefixMeaning) {
+ targetNamespace = prefixMeaning.namespace;
+ }
+ } else {
+ targetNamespace = privateNamespace;
+ }
+ filterExportNamespace(uri, import.combinators, targetNamespace);
+ return uriToDependency[uri];
+ }
+
+ /**
+ * Produce a [LinkedUnit] for the given [unit], by resolving every one of
+ * its references.
+ */
+ LinkedUnitBuilder linkUnit(UnlinkedUnit unit) {
+ if (unit == null) {
+ return new LinkedUnitBuilder();
+ }
+ Map<int, Map<String, _Meaning>> prefixNamespaces =
+ <int, Map<String, _Meaning>>{};
+ List<LinkedReferenceBuilder> references = <LinkedReferenceBuilder>[];
+ for (int i = 0; i < unit.references.length; i++) {
+ UnlinkedReference reference = unit.references[i];
+ Map<String, _Meaning> namespace;
+ if (reference.prefixReference == 0) {
+ namespace = privateNamespace;
+ } else {
+ // Prefix references must always point backward.
+ assert(reference.prefixReference < i);
+ namespace = prefixNamespaces[reference.prefixReference];
+ // Expressions like 'a.b.c.d' cannot be prelinked.
+ namespace ??= const <String, _Meaning>{};
+ }
+ _Meaning meaning = namespace[reference.name];
+ if (meaning != null) {
+ if (meaning is _PrefixMeaning) {
+ prefixNamespaces[i] = meaning.namespace;
+ } else if (meaning is _ClassMeaning) {
+ prefixNamespaces[i] = meaning.namespace;
+ }
+ references.add(meaning.encodeReference());
+ } else {
+ references
+ .add(new LinkedReferenceBuilder(kind: ReferenceKind.unresolved));
+ }
+ }
+ return new LinkedUnitBuilder(references: references);
+ }
+
+ /**
+ * Form the [LinkedLibrary] for the [definingUnit] that was passed to the
+ * constructor.
+ */
+ LinkedLibraryBuilder prelink() {
+ // Gather up the unlinked summaries for all the compilation units in the
+ // library.
+ List<UnlinkedUnit> units = getUnitUris(null).map(getPartCached).toList();
+
+ // Create the private namespace for the library by gathering all the names
+ // defined in its compilation units.
+ for (int unitNum = 0; unitNum < units.length; unitNum++) {
+ UnlinkedUnit unit = units[unitNum];
+ if (unit != null) {
+ extractPrivateNames(unit, unitNum);
+ }
+ }
+
+ // Fill in exported names. This must be done before filling in prefixes
+ // defined in import declarations, because prefixes shouldn't shadow
+ // exports.
+ List<LinkedExportNameBuilder> exportNames = <LinkedExportNameBuilder>[];
+ computeExportNamespace(null).forEach((String name, _Meaning meaning) {
+ if (!privateNamespace.containsKey(name)) {
+ exportNames.add(meaning.encodeExportName(name));
+ }
+ });
+
+ // Fill in prefixes defined in import declarations.
+ for (UnlinkedImport import in units[0].imports) {
+ if (import.prefixReference != 0) {
+ privateNamespace.putIfAbsent(
+ units[0].references[import.prefixReference].name,
+ () => new _PrefixMeaning());
+ }
+ }
+
+ // Fill in imported and exported names.
+ List<int> importDependencies =
+ definingUnit.imports.map(handleImport).toList();
+ List<int> exportDependencies =
+ definingUnit.publicNamespace.exports.map((UnlinkedExportPublic exp) {
+ String uri = _selectUri(exp.uri, exp.configurations);
+ return uriToDependency[uri];
+ }).toList();
+
+ // Link each compilation unit.
+ List<LinkedUnitBuilder> linkedUnits = units.map(linkUnit).toList();
+
+ return new LinkedLibraryBuilder(
+ units: linkedUnits,
+ dependencies: dependencies,
+ importDependencies: importDependencies,
+ exportDependencies: exportDependencies,
+ exportNames: exportNames,
+ numPrelinkedDependencies: dependencies.length);
+ }
+
+ /**
+ * Resolve [relativeUri] relative to [sourceUri]. Works correctly if
+ * [sourceUri] is also relative.
+ */
+ String resolveUri(String sourceUri, String relativeUri) {
+ if (sourceUri == null) {
+ return relativeUri;
+ } else {
+ return resolveRelativeUri(Uri.parse(sourceUri), Uri.parse(relativeUri))
+ .toString();
+ }
+ }
+
+ /**
+ * Return the URI of the first configuration from the given [configurations]
+ * which condition is satisfied, or the [defaultUri].
+ */
+ String _selectUri(
+ String defaultUri, List<UnlinkedConfiguration> configurations) {
+ for (UnlinkedConfiguration configuration in configurations) {
+ if (getDeclaredVariable(configuration.name) == configuration.value) {
+ return configuration.uri;
+ }
+ }
+ return defaultUri;
+ }
+}
« no previous file with comments | « packages/analyzer/lib/src/summary/package_bundle_reader.dart ('k') | packages/analyzer/lib/src/summary/pub_summary.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698