Chromium Code Reviews| Index: pkg/analyzer/lib/src/summary/pub_summary.dart |
| diff --git a/pkg/analyzer/lib/src/summary/pub_summary.dart b/pkg/analyzer/lib/src/summary/pub_summary.dart |
| index 527f2743aea1015af13c2372747cb6aa8fd47e3e..c4f7e128f94448c6c0dd9b79ccf3d7e42928c5ea 100644 |
| --- a/pkg/analyzer/lib/src/summary/pub_summary.dart |
| +++ b/pkg/analyzer/lib/src/summary/pub_summary.dart |
| @@ -17,8 +17,9 @@ import 'package:analyzer/src/generated/parser.dart'; |
| import 'package:analyzer/src/generated/source.dart'; |
| import 'package:analyzer/src/summary/format.dart'; |
| import 'package:analyzer/src/summary/idl.dart'; |
| +import 'package:analyzer/src/summary/link.dart'; |
| import 'package:analyzer/src/summary/package_bundle_reader.dart' |
| - show ResynthesizerResultProvider; |
| + show ResynthesizerResultProvider, SummaryDataStore; |
| import 'package:analyzer/src/summary/summarize_ast.dart' |
| show serializeAstUnlinked; |
| import 'package:analyzer/src/summary/summarize_elements.dart' |
| @@ -50,6 +51,16 @@ class PubPackage { |
| } |
| /** |
| + * Unlinked and linked information about a [PubPackage]. |
| + */ |
| +class LinkedPubPackage { |
| + final PubPackage package; |
| + final PackageBundle unlinked; |
| + final PackageBundle linked; |
| + LinkedPubPackage(this.package, this.unlinked, this.linked); |
| +} |
| + |
| +/** |
| * Class that manages summaries for pub packages. |
| * |
| * The client should call [getLinkedBundles] after creating a new |
| @@ -111,25 +122,71 @@ class PubSummaryManager { |
| pathos.Context get pathContext => resourceProvider.pathContext; |
| /** |
| - * Return the list of linked [PackageBundle]s that can be provided at this |
| + * Return the list of linked [LinkedPubPackage]s that can be provided at this |
| * time for a subset of the packages used by the given [context]. If |
| * information about some of the used packages is not available yet, schedule |
| * its computation, so that it might be available later for other contexts |
| * referencing the same packages. |
| */ |
| - List<PackageBundle> getLinkedBundles(AnalysisContext context) { |
| - Map<String, PackageBundle> unlinkedBundles = getUnlinkedBundles(context); |
| - // TODO(scheglov) actually compute available linked bundles |
| - return <PackageBundle>[]; |
| + List<LinkedPubPackage> getLinkedBundles( |
| + AnalysisContext context, PackageBundle sdkBundle) { |
| + Map<PubPackage, PackageBundle> unlinkedBundles = |
| + getUnlinkedBundles(context); |
| + |
| + // If no unlinked bundles, there is nothing we can try to link. |
| + if (unlinkedBundles.isEmpty) { |
| + return <LinkedPubPackage>[]; |
| + } |
| + |
| + // Create graph nodes for packages. |
| + List<_LinkedNode> nodes = <_LinkedNode>[]; |
| + Map<String, _LinkedNode> uriToNode = <String, _LinkedNode>{}; |
| + unlinkedBundles.forEach((package, unlinked) { |
| + _LinkedNode node = new _LinkedNode(package, unlinked, uriToNode); |
| + nodes.add(node); |
| + for (String uri in unlinked.unlinkedUnitUris) { |
| + uriToNode[uri] = node; |
| + } |
| + }); |
| + |
| + // Fill the store with unlinked bundles. |
| + SummaryDataStore store = new SummaryDataStore(const <String>[]); |
| + store.addBundle(null, sdkBundle); |
| + for (PackageBundle unlinked in unlinkedBundles.values) { |
| + store.addBundle(null, unlinked); |
| + } |
| + |
| + // Link each package node. |
| + for (_LinkedNode node in nodes) { |
| + if (!node.isEvaluated) { |
| + new _LinkedWalker(store).walk(node); |
| + } |
| + } |
| + |
| + // Create successfully linked packages. |
| + List<LinkedPubPackage> linkedPackages = <LinkedPubPackage>[]; |
| + for (_LinkedNode node in nodes) { |
| + if (node.linkedBuilder != null) { |
| + List<int> bytes = node.linkedBuilder.toBuffer(); |
| + PackageBundle linkedBundle = new PackageBundle.fromBuffer(bytes); |
| + linkedPackages.add( |
| + new LinkedPubPackage(node.package, node.unlinked, linkedBundle)); |
| + } |
| + } |
| + |
| + // TODO(scheglov) compute dependency hashes and write linked bundles. |
| + |
| + // Done. |
| + return linkedPackages; |
| } |
| /** |
| * Return all available unlinked [PackageBundle]s for the given [context], |
| - * maybe an empty list, but not `null`. |
| + * maybe an empty map, but not `null`. |
| */ |
| - Map<String, PackageBundle> getUnlinkedBundles(AnalysisContext context) { |
| - Map<String, PackageBundle> unlinkedBundles = |
| - new HashMap<String, PackageBundle>(); |
| + Map<PubPackage, PackageBundle> getUnlinkedBundles(AnalysisContext context) { |
| + Map<PubPackage, PackageBundle> unlinkedBundles = |
| + new HashMap<PubPackage, PackageBundle>(); |
| Map<String, List<Folder>> packageMap = context.sourceFactory.packageMap; |
| if (packageMap != null) { |
| packageMap.forEach((String packageName, List<Folder> libFolders) { |
| @@ -139,7 +196,7 @@ class PubSummaryManager { |
| PubPackage package = new PubPackage(packageName, libFolder); |
| PackageBundle unlinkedBundle = _getUnlinkedOrSchedule(package); |
| if (unlinkedBundle != null) { |
| - unlinkedBundles[packageName] = unlinkedBundle; |
| + unlinkedBundles[package] = unlinkedBundle; |
| } |
| } |
| } |
| @@ -314,3 +371,87 @@ class PubSummaryManager { |
| return false; |
| } |
| } |
| + |
| +/** |
| + * Specialization of [Node] for linking packages in proper dependency order. |
| + */ |
| +class _LinkedNode extends Node<_LinkedNode> { |
| + final PubPackage package; |
| + final PackageBundle unlinked; |
| + final Map<String, _LinkedNode> uriToNode; |
| + |
| + PackageBundleBuilder linkedBuilder; |
| + bool failed = false; |
| + |
| + _LinkedNode(this.package, this.unlinked, this.uriToNode); |
| + |
| + @override |
| + bool get isEvaluated => linkedBuilder != null || failed; |
| + |
| + @override |
| + List<_LinkedNode> computeDependencies() { |
| + Set<String> referencedUris = new Set<String>(); |
| + for (UnlinkedUnit unit in unlinked.unlinkedUnits) { |
| + for (UnlinkedImport import in unit.imports) { |
| + String uri = import.isImplicit ? 'dart:core' : import.uri; |
| + if (uri.startsWith('dart:')) { |
| + // Ignore SDK imports. |
|
Paul Berry
2016/08/09 22:24:10
I'm concerned that treating the SDK specially may
scheglov
2016/08/10 01:12:49
Yes, at the point when we will store linked summar
|
| + } else if (uri.startsWith('package:')) { |
| + referencedUris.add(uri); |
|
Paul Berry
2016/08/09 22:24:10
This seems unnecessarily complex. Since there's a
scheglov
2016/08/10 01:12:49
True, this can be simplified.
No, I don't plan to
|
| + } else { |
| + failed = true; |
| + return const <_LinkedNode>[]; |
| + } |
| + } |
| + } |
| + // TODO(scheglov) fail if no corresponding node |
| + return referencedUris.map((uri) => uriToNode[uri]).toSet().toList(); |
| + } |
| + |
| + @override |
| + String toString() => package.toString(); |
| +} |
| + |
| +/** |
| + * Specialization of [DependencyWalker] for linking packages. |
| + */ |
| +class _LinkedWalker extends DependencyWalker<_LinkedNode> { |
| + final SummaryDataStore store; |
| + |
| + _LinkedWalker(this.store); |
| + |
| + @override |
| + void evaluate(_LinkedNode v) { |
| + print('evaluate: $v'); |
|
Paul Berry
2016/08/09 22:24:10
Delete
scheglov
2016/08/10 01:12:49
Done.
|
| + Set<String> libraryUris = v.unlinked.unlinkedUnitUris.toSet(); |
| + Map<String, LinkedLibraryBuilder> map = link(libraryUris, (String absUri) { |
| + LinkedLibrary dependencyLibrary = store.linkedMap[absUri]; |
| + if (dependencyLibrary == null) { |
| + // TODO(scheglov) add test |
| + v.failed = true; |
| + } |
| + return dependencyLibrary; |
| + }, (String absUri) { |
| + UnlinkedUnit unlinkedUnit = store.unlinkedMap[absUri]; |
| + if (unlinkedUnit == null) { |
| + // TODO(scheglov) add test |
| + v.failed = true; |
| + } |
| + return unlinkedUnit; |
| + }, false); |
| + if (!v.failed) { |
| + PackageBundleAssembler assembler = new PackageBundleAssembler(); |
| + map.forEach((uri, linkedLibrary) { |
| + assembler.addLinkedLibrary(uri, linkedLibrary); |
| + }); |
| + v.linkedBuilder = assembler.assemble(); |
| + store.addBundle(null, v.linkedBuilder); |
| + } |
| + } |
| + |
| + @override |
| + void evaluateScc(List<_LinkedNode> scc) { |
| + print('evaluateScc: $scc'); |
| + // TODO(scheglov): implement evaluateScc |
| + } |
| +} |