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

Side by Side Diff: pkg/analyzer/lib/src/summary/pub_summary.dart

Issue 2375383004: Don't use actual dependency walker in pub summaries. (Closed)
Patch Set: Extract _ContextLinker for computing linked bundles of a context. Created 4 years, 2 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 unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 import 'dart:async'; 5 import 'dart:async';
6 import 'dart:collection'; 6 import 'dart:collection';
7 import 'dart:core'; 7 import 'dart:core';
8 8
9 import 'package:analyzer/dart/ast/ast.dart'; 9 import 'package:analyzer/dart/ast/ast.dart';
10 import 'package:analyzer/dart/ast/token.dart'; 10 import 'package:analyzer/dart/ast/token.dart';
(...skipping 15 matching lines...) Expand all
26 show serializeAstUnlinked; 26 show serializeAstUnlinked;
27 import 'package:analyzer/src/summary/summarize_elements.dart' 27 import 'package:analyzer/src/summary/summarize_elements.dart'
28 show PackageBundleAssembler; 28 show PackageBundleAssembler;
29 import 'package:analyzer/src/util/fast_uri.dart'; 29 import 'package:analyzer/src/util/fast_uri.dart';
30 import 'package:convert/convert.dart'; 30 import 'package:convert/convert.dart';
31 import 'package:crypto/crypto.dart'; 31 import 'package:crypto/crypto.dart';
32 import 'package:meta/meta.dart'; 32 import 'package:meta/meta.dart';
33 import 'package:path/path.dart' as pathos; 33 import 'package:path/path.dart' as pathos;
34 34
35 /** 35 /**
36 * Return the raw string value of the variable with the given [name],
37 * or `null` of the variable is not defined.
38 */
39 typedef String _GetDeclaredVariable(String name);
40
41 /**
42 * Unlinked and linked information about a [PubPackage]. 36 * Unlinked and linked information about a [PubPackage].
43 */ 37 */
44 class LinkedPubPackage { 38 class LinkedPubPackage {
45 final PubPackage package; 39 final PubPackage package;
46 final PackageBundle unlinked; 40 final PackageBundle unlinked;
47 final PackageBundle linked; 41 final PackageBundle linked;
48 42
49 final String linkedHash; 43 final String linkedHash;
50 44
51 LinkedPubPackage(this.package, this.unlinked, this.linked, this.linkedHash); 45 LinkedPubPackage(this.package, this.unlinked, this.linked, this.linkedHash);
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 } 167 }
174 168
175 /** 169 /**
176 * Return the list of linked [LinkedPubPackage]s that can be provided at this 170 * Return the list of linked [LinkedPubPackage]s that can be provided at this
177 * time for a subset of the packages used by the given [context]. If 171 * time for a subset of the packages used by the given [context]. If
178 * information about some of the used packages is not available yet, schedule 172 * information about some of the used packages is not available yet, schedule
179 * its computation, so that it might be available later for other contexts 173 * its computation, so that it might be available later for other contexts
180 * referencing the same packages. 174 * referencing the same packages.
181 */ 175 */
182 List<LinkedPubPackage> getLinkedBundles(AnalysisContext context) { 176 List<LinkedPubPackage> getLinkedBundles(AnalysisContext context) {
183 // Stopwatch timer = new Stopwatch()..start(); 177 return new _ContextLinker(this, context).getLinkedBundles();
184
185 _GetDeclaredVariable getDeclaredVariable = context.declaredVariables.get;
186 SourceFactory sourceFactory = context.sourceFactory;
187 _ListedPackages listedPackages = new _ListedPackages(sourceFactory);
188
189 PackageBundle sdkBundle = sourceFactory.dartSdk.getLinkedBundle();
190 if (sdkBundle == null) {
191 return const <LinkedPubPackage>[];
192 }
193
194 bool strong = context.analysisOptions.strongMode;
195 Map<PubPackage, PackageBundle> unlinkedBundles =
196 getUnlinkedBundles(context);
197
198 // TODO(scheglov) remove debug output after optimizing
199 // print('LOADED ${unlinkedBundles.length} unlinked bundles'
200 // ' in ${timer.elapsedMilliseconds} ms');
201 // timer..reset();
202
203 // If no unlinked bundles, there is nothing we can try to link.
204 if (unlinkedBundles.isEmpty) {
205 return const <LinkedPubPackage>[];
206 }
207
208 // Create graph nodes for packages.
209 List<_LinkNode> nodes = <_LinkNode>[];
210 Map<String, _LinkNode> packageToNode = <String, _LinkNode>{};
211 unlinkedBundles.forEach((package, unlinked) {
212 _LinkNode node = new _LinkNode(sdkBundle, getDeclaredVariable,
213 listedPackages, package, unlinked, packageToNode);
214 nodes.add(node);
215 packageToNode[package.name] = node;
216 });
217
218 // Compute transitive dependencies, mark some nodes as failed.
219 for (_LinkNode node in nodes) {
220 node.computeTransitiveDependencies();
221 }
222
223 // Attempt to read existing linked bundles.
224 for (_LinkNode node in nodes) {
225 _readLinked(node, strong);
226 }
227
228 // Link new bundles, if allowed.
229 if (allowLinking) {
230 // Fill the store with bundles.
231 // Append the linked SDK bundle.
232 // Append unlinked and (if read from a cache) linked package bundles.
233 SummaryDataStore store = new SummaryDataStore(const <String>[]);
234 store.addBundle(null, sdkBundle);
235 for (_LinkNode node in nodes) {
236 store.addBundle(null, node.unlinked);
237 if (node.linked != null) {
238 store.addBundle(null, node.linked);
239 }
240 }
241
242 // Link each package node.
243 for (_LinkNode node in nodes) {
244 if (!node.isEvaluated) {
245 new _LinkWalker(getDeclaredVariable, listedPackages, store, strong)
246 .walk(node);
247 }
248 }
249
250 // Write newly linked bundles.
251 for (_LinkNode node in nodes) {
252 _writeLinked(node, strong);
253 }
254 }
255
256 // Create successfully linked packages.
257 List<LinkedPubPackage> linkedPackages = <LinkedPubPackage>[];
258 for (_LinkNode node in nodes) {
259 if (node.linked != null) {
260 linkedPackages.add(new LinkedPubPackage(
261 node.package, node.unlinked, node.linked, node.linkedHash));
262 }
263 }
264
265 // TODO(scheglov) remove debug output after optimizing
266 // print('LINKED ${linkedPackages.length} bundles'
267 // ' in ${timer.elapsedMilliseconds} ms');
268
269 // Done.
270 return linkedPackages;
271 } 178 }
272 179
273 /** 180 /**
274 * Return all available unlinked [PackageBundle]s for the given [context], 181 * Return all available unlinked [PackageBundle]s for the given [context],
275 * maybe an empty map, but not `null`. 182 * maybe an empty map, but not `null`.
276 */ 183 */
277 @visibleForTesting 184 @visibleForTesting
278 Map<PubPackage, PackageBundle> getUnlinkedBundles(AnalysisContext context) { 185 Map<PubPackage, PackageBundle> getUnlinkedBundles(AnalysisContext context) {
279 bool strong = context.analysisOptions.strongMode; 186 bool strong = context.analysisOptions.strongMode;
280 Map<PubPackage, PackageBundle> unlinkedBundles = 187 Map<PubPackage, PackageBundle> unlinkedBundles =
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
374 bundleWriter.majorVersion = majorVersion; 281 bundleWriter.majorVersion = majorVersion;
375 List<int> bytes = bundleWriter.toBuffer(); 282 List<int> bytes = bundleWriter.toBuffer();
376 String fileName = _getUnlinkedName(strong); 283 String fileName = _getUnlinkedName(strong);
377 _writeAtomic(package.folder, fileName, bytes); 284 _writeAtomic(package.folder, fileName, bytes);
378 } on FileSystemException { 285 } on FileSystemException {
379 // Ignore file system exceptions. 286 // Ignore file system exceptions.
380 } 287 }
381 } 288 }
382 289
383 /** 290 /**
384 * Return the name of the file for a linked bundle, in strong or spec mode.
385 */
386 String _getLinkedName(String hash, bool strong) {
387 if (strong) {
388 return 'linked_$hash.ds';
389 } else {
390 return 'linked_spec_$hash.ds';
391 }
392 }
393
394 /**
395 * Return the name of the file for an unlinked bundle, in strong or spec mode. 291 * Return the name of the file for an unlinked bundle, in strong or spec mode.
396 */ 292 */
397 String _getUnlinkedName(bool strong) { 293 String _getUnlinkedName(bool strong) {
398 if (strong) { 294 if (strong) {
399 return UNLINKED_NAME; 295 return UNLINKED_NAME;
400 } else { 296 } else {
401 return UNLINKED_SPEC_NAME; 297 return UNLINKED_SPEC_NAME;
402 } 298 }
403 } 299 }
404 300
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
504 Token token = scanner.tokenize(); 400 Token token = scanner.tokenize();
505 LineInfo lineInfo = new LineInfo(scanner.lineStarts); 401 LineInfo lineInfo = new LineInfo(scanner.lineStarts);
506 Parser parser = new Parser(source, errorListener); 402 Parser parser = new Parser(source, errorListener);
507 parser.parseGenericMethodComments = strong; 403 parser.parseGenericMethodComments = strong;
508 CompilationUnit unit = parser.parseCompilationUnit(token); 404 CompilationUnit unit = parser.parseCompilationUnit(token);
509 unit.lineInfo = lineInfo; 405 unit.lineInfo = lineInfo;
510 return unit; 406 return unit;
511 } 407 }
512 408
513 /** 409 /**
514 * Attempt to find the linked bundle that corresponds to the given [node]
515 * with all its transitive dependencies and put it into [_LinkNode.linked].
516 */
517 void _readLinked(_LinkNode node, bool strong) {
518 String hash = node.linkedHash;
519 if (hash != null) {
520 String fileName = _getLinkedName(hash, strong);
521 File file = node.package.folder.getChildAssumingFile(fileName);
522 // Try to find in the cache.
523 PackageBundle linked = linkedBundleMap[file.path];
524 if (linked != null) {
525 node.linked = linked;
526 return;
527 }
528 // Try to read from the file system.
529 if (file.exists) {
530 try {
531 List<int> bytes = file.readAsBytesSync();
532 linked = new PackageBundle.fromBuffer(bytes);
533 linkedBundleMap[file.path] = linked;
534 node.linked = linked;
535 } on FileSystemException {
536 // Ignore file system exceptions.
537 }
538 }
539 }
540 }
541
542 /**
543 * Schedule delayed computation of the next package unlinked bundle from the 410 * Schedule delayed computation of the next package unlinked bundle from the
544 * set of [packagesToComputeUnlinked]. We delay each computation because we 411 * set of [packagesToComputeUnlinked]. We delay each computation because we
545 * want operations in analysis server to proceed, and computing bundles of 412 * want operations in analysis server to proceed, and computing bundles of
546 * packages is a background task. 413 * packages is a background task.
547 */ 414 */
548 void _scheduleNextUnlinked() { 415 void _scheduleNextUnlinked() {
549 new Future.delayed(new Duration(milliseconds: 10), _computeNextUnlinked); 416 new Future.delayed(new Duration(milliseconds: 10), _computeNextUnlinked);
550 } 417 }
551 418
552 /** 419 /**
(...skipping 10 matching lines...) Expand all
563 * Atomically write the given [bytes] into the file in the [folder]. 430 * Atomically write the given [bytes] into the file in the [folder].
564 */ 431 */
565 void _writeAtomic(Folder folder, String fileName, List<int> bytes) { 432 void _writeAtomic(Folder folder, String fileName, List<int> bytes) {
566 String filePath = folder.getChildAssumingFile(fileName).path; 433 String filePath = folder.getChildAssumingFile(fileName).path;
567 File tempFile = folder.getChildAssumingFile(tempFileName); 434 File tempFile = folder.getChildAssumingFile(tempFileName);
568 tempFile.writeAsBytesSync(bytes); 435 tempFile.writeAsBytesSync(bytes);
569 tempFile.renameSync(filePath); 436 tempFile.renameSync(filePath);
570 } 437 }
571 438
572 /** 439 /**
573 * If a new linked bundle was linked for the given [node], write the bundle
574 * into the memory cache and the file system.
575 */
576 void _writeLinked(_LinkNode node, bool strong) {
577 String hash = node.linkedHash;
578 if (hash != null && node.linkedNewBytes != null) {
579 String fileName = _getLinkedName(hash, strong);
580 File file = node.package.folder.getChildAssumingFile(fileName);
581 linkedBundleMap[file.path] = node.linked;
582 _writeAtomic(node.package.folder, fileName, node.linkedNewBytes);
583 }
584 }
585
586 /**
587 * If the given [uri] has the `package` scheme, return the name of the 440 * If the given [uri] has the `package` scheme, return the name of the
588 * package that contains the referenced resource. Otherwise return `null`. 441 * package that contains the referenced resource. Otherwise return `null`.
589 * 442 *
590 * For example `package:foo/bar.dart` => `foo`. 443 * For example `package:foo/bar.dart` => `foo`.
591 */ 444 */
592 static String getPackageName(String uri) { 445 static String getPackageName(String uri) {
593 const String PACKAGE_SCHEME = 'package:'; 446 const String PACKAGE_SCHEME = 'package:';
594 if (uri.startsWith(PACKAGE_SCHEME)) { 447 if (uri.startsWith(PACKAGE_SCHEME)) {
595 int index = uri.indexOf('/'); 448 int index = uri.indexOf('/');
596 if (index != -1) { 449 if (index != -1) {
(...skipping 13 matching lines...) Expand all
610 return true; 463 return true;
611 } 464 }
612 if (parts[i] == 'Pub' && parts[i + 1] == 'Cache') { 465 if (parts[i] == 'Pub' && parts[i + 1] == 'Cache') {
613 return true; 466 return true;
614 } 467 }
615 } 468 }
616 return false; 469 return false;
617 } 470 }
618 } 471 }
619 472
473 class _ContextLinker {
474 final PubSummaryManager manager;
475 final AnalysisContext context;
476
477 final strong;
478 final _ListedPackages listedPackages;
479 final PackageBundle sdkBundle;
480
481 final List<_LinkNode> nodes = <_LinkNode>[];
482 final Map<String, _LinkNode> packageToNode = <String, _LinkNode>{};
483
484 _ContextLinker(this.manager, AnalysisContext context)
485 : context = context,
486 strong = context.analysisOptions.strongMode,
487 listedPackages = new _ListedPackages(context.sourceFactory),
488 sdkBundle = context.sourceFactory.dartSdk.getLinkedBundle();
489
490 /**
491 * Return the list of linked [LinkedPubPackage]s that can be provided at this
492 * time for a subset of the packages used by the [context].
493 */
494 List<LinkedPubPackage> getLinkedBundles() {
495 // Stopwatch timer = new Stopwatch()..start();
496
497 if (sdkBundle == null) {
498 return const <LinkedPubPackage>[];
499 }
500
501 Map<PubPackage, PackageBundle> unlinkedBundles =
502 manager.getUnlinkedBundles(context);
503
504 // TODO(scheglov) remove debug output after optimizing
505 // print('LOADED ${unlinkedBundles.length} unlinked bundles'
506 // ' in ${timer.elapsedMilliseconds} ms');
507 // timer..reset();
508
509 // If no unlinked bundles, there is nothing we can try to link.
510 if (unlinkedBundles.isEmpty) {
511 return const <LinkedPubPackage>[];
512 }
513
514 // Create nodes for packages.
515 unlinkedBundles.forEach((package, unlinked) {
516 _LinkNode node = new _LinkNode(this, package, unlinked);
517 nodes.add(node);
518 packageToNode[package.name] = node;
519 });
520
521 // Compute transitive dependencies, mark some nodes as failed.
522 for (_LinkNode node in nodes) {
523 node.computeTransitiveDependencies();
524 }
525
526 // Attempt to read existing linked bundles.
527 for (_LinkNode node in nodes) {
528 _readLinked(node);
529 }
530
531 // Link new packages, if allowed.
532 if (manager.allowLinking) {
533 _link();
534 }
535
536 // Create successfully linked packages.
537 List<LinkedPubPackage> linkedPackages = <LinkedPubPackage>[];
538 for (_LinkNode node in nodes) {
539 if (node.linked != null) {
540 linkedPackages.add(new LinkedPubPackage(
541 node.package, node.unlinked, node.linked, node.linkedHash));
542 }
543 }
544
545 // TODO(scheglov) remove debug output after optimizing
546 // print('LINKED ${linkedPackages.length} bundles'
547 // ' in ${timer.elapsedMilliseconds} ms');
548
549 // Done.
550 return linkedPackages;
551 }
552
553 String _getDeclaredVariable(String name) {
554 return context.declaredVariables.get(name);
555 }
556
557 /**
558 * Return the name of the file for a linked bundle, in strong or spec mode.
559 */
560 String _getLinkedName(String hash) {
561 if (strong) {
562 return 'linked_$hash.ds';
563 } else {
564 return 'linked_spec_$hash.ds';
565 }
566 }
567
568 void _link() {
569 // Fill the store with bundles.
570 // Append the linked SDK bundle.
571 // Append unlinked and (if read from a cache) linked package bundles.
572 SummaryDataStore store = new SummaryDataStore(const <String>[]);
573 store.addBundle(null, sdkBundle);
574 for (_LinkNode node in nodes) {
575 store.addBundle(null, node.unlinked);
576 if (node.linked != null) {
577 store.addBundle(null, node.linked);
578 }
579 }
580
581 // Prepare URIs to link.
582 Map<String, _LinkNode> uriToNode = <String, _LinkNode>{};
583 for (_LinkNode node in nodes) {
584 if (!node.isReady) {
585 for (String uri in node.unlinked.unlinkedUnitUris) {
586 uriToNode[uri] = node;
587 }
588 }
589 }
590 Set<String> libraryUris = uriToNode.keys.toSet();
591
592 // Perform linking.
593 Map<String, LinkedLibraryBuilder> linkedLibraries =
594 link(libraryUris, (String uri) {
595 return store.linkedMap[uri];
596 }, (String uri) {
597 return store.unlinkedMap[uri];
598 }, _getDeclaredVariable, strong);
599
600 // Assemble newly linked bundles.
601 for (_LinkNode node in nodes) {
602 if (!node.isReady) {
603 PackageBundleAssembler assembler = new PackageBundleAssembler();
604 linkedLibraries.forEach((uri, linkedLibrary) {
605 if (identical(uriToNode[uri], node)) {
606 assembler.addLinkedLibrary(uri, linkedLibrary);
607 }
608 });
609 List<int> bytes = assembler.assemble().toBuffer();
610 node.linkedNewBytes = bytes;
611 node.linked = new PackageBundle.fromBuffer(bytes);
612 }
613 }
614
615 // Write newly linked bundles.
616 for (_LinkNode node in nodes) {
617 _writeLinked(node);
618 }
619 }
620
621 /**
622 * Attempt to find the linked bundle that corresponds to the given [node]
623 * with all its transitive dependencies and put it into [_LinkNode.linked].
624 */
625 void _readLinked(_LinkNode node) {
626 String hash = node.linkedHash;
627 if (hash != null) {
628 String fileName = _getLinkedName(hash);
629 File file = node.package.folder.getChildAssumingFile(fileName);
630 // Try to find in the cache.
631 PackageBundle linked = manager.linkedBundleMap[file.path];
632 if (linked != null) {
633 node.linked = linked;
634 return;
635 }
636 // Try to read from the file system.
637 if (file.exists) {
638 try {
639 List<int> bytes = file.readAsBytesSync();
640 linked = new PackageBundle.fromBuffer(bytes);
641 manager.linkedBundleMap[file.path] = linked;
642 node.linked = linked;
643 } on FileSystemException {
644 // Ignore file system exceptions.
645 }
646 }
647 }
648 }
649
650 /**
651 * If a new linked bundle was linked for the given [node], write the bundle
652 * into the memory cache and the file system.
653 */
654 void _writeLinked(_LinkNode node) {
655 String hash = node.linkedHash;
656 if (hash != null && node.linkedNewBytes != null) {
657 String fileName = _getLinkedName(hash);
658 File file = node.package.folder.getChildAssumingFile(fileName);
659 manager.linkedBundleMap[file.path] = node.linked;
660 manager._writeAtomic(node.package.folder, fileName, node.linkedNewBytes);
661 }
662 }
663 }
664
620 /** 665 /**
621 * Specialization of [Node] for linking packages in proper dependency order. 666 * Information about a package to link.
622 */ 667 */
623 class _LinkNode extends Node<_LinkNode> { 668 class _LinkNode {
624 final PackageBundle sdkBundle; 669 final _ContextLinker linker;
625 final _GetDeclaredVariable getDeclaredVariable;
626 final _ListedPackages listedPackages;
627 final PubPackage package; 670 final PubPackage package;
628 final PackageBundle unlinked; 671 final PackageBundle unlinked;
629 final Map<String, _LinkNode> packageToNode;
630 672
631 bool failed = false; 673 bool failed = false;
632 Set<_LinkNode> transitiveDependencies; 674 Set<_LinkNode> transitiveDependencies;
675
676 List<_LinkNode> _dependencies;
633 String _linkedHash; 677 String _linkedHash;
634 678
635 List<int> linkedNewBytes; 679 List<int> linkedNewBytes;
636 PackageBundle linked; 680 PackageBundle linked;
637 681
638 _LinkNode(this.sdkBundle, this.getDeclaredVariable, this.listedPackages, 682 _LinkNode(this.linker, this.package, this.unlinked);
639 this.package, this.unlinked, this.packageToNode); 683
640 684 /**
641 @override 685 * Retrieve the dependencies of this node.
642 bool get isEvaluated => linked != null || failed; 686 */
687 List<_LinkNode> get dependencies {
688 if (_dependencies == null) {
689 Set<_LinkNode> dependencies = new Set<_LinkNode>();
690
691 void appendDependency(String uriStr) {
692 Uri uri = FastUri.parse(uriStr);
693 if (!uri.hasScheme) {
694 // A relative path in this package, skip it.
695 } else if (uri.scheme == 'dart') {
696 // Dependency on the SDK is implicit and always added.
697 // The SDK linked bundle is precomputed before linking packages.
698 } else if (uriStr.startsWith('package:')) {
699 String package = PubSummaryManager.getPackageName(uriStr);
700 _LinkNode packageNode = linker.packageToNode[package];
701 if (packageNode == null && linker.listedPackages.isListed(uriStr)) {
702 failed = true;
703 }
704 if (packageNode != null) {
705 dependencies.add(packageNode);
706 }
707 } else {
708 failed = true;
709 }
710 }
711
712 for (UnlinkedUnit unit in unlinked.unlinkedUnits) {
713 for (UnlinkedImport import in unit.imports) {
714 if (!import.isImplicit) {
715 appendDependency(import.uri);
716 }
717 }
718 for (UnlinkedExportPublic export in unit.publicNamespace.exports) {
719 appendDependency(export.uri);
720 }
721 }
722
723 _dependencies = dependencies.toList();
724 }
725 return _dependencies;
726 }
727
728 /**
729 * Return `true` is the node is ready - has the linked bundle or failed (does
730 * not have all required dependencies).
731 */
732 bool get isReady => linked != null || failed;
643 733
644 /** 734 /**
645 * Return the hash string that corresponds to this linked bundle in the 735 * Return the hash string that corresponds to this linked bundle in the
646 * context of its [sdkBundle] and transitive dependencies. Return `null` if 736 * context of its SDK bundle and transitive dependencies. Return `null` if
647 * the hash computation fails, because for example the full transitive 737 * the hash computation fails, because for example the full transitive
648 * dependencies cannot computed. 738 * dependencies cannot computed.
649 */ 739 */
650 String get linkedHash { 740 String get linkedHash {
651 if (_linkedHash == null && transitiveDependencies != null) { 741 if (_linkedHash == null && transitiveDependencies != null) {
652 ApiSignature signature = new ApiSignature(); 742 ApiSignature signature = new ApiSignature();
653 // Add all unlinked API signatures. 743 // Add all unlinked API signatures.
654 List<String> signatures = <String>[]; 744 List<String> signatures = <String>[];
655 signatures.add(sdkBundle.apiSignature); 745 signatures.add(linker.sdkBundle.apiSignature);
656 transitiveDependencies 746 transitiveDependencies
657 .map((node) => node.unlinked.apiSignature) 747 .map((node) => node.unlinked.apiSignature)
658 .forEach(signatures.add); 748 .forEach(signatures.add);
659 signatures.sort(); 749 signatures.sort();
660 signatures.forEach(signature.addString); 750 signatures.forEach(signature.addString);
661 // Combine into a single hash. 751 // Combine into a single hash.
662 _appendDeclaredVariables(signature); 752 appendDeclaredVariables(signature);
663 _linkedHash = signature.toHex(); 753 _linkedHash = signature.toHex();
664 } 754 }
665 return _linkedHash; 755 return _linkedHash;
666 } 756 }
667 757
668 @override 758 /**
669 List<_LinkNode> computeDependencies() { 759 * Append names and values of all referenced declared variables (even the
670 Set<_LinkNode> dependencies = new Set<_LinkNode>(); 760 * ones without actually declared values) to the given [signature].
671 761 */
672 void appendDependency(String uriStr) { 762 void appendDeclaredVariables(ApiSignature signature) {
673 Uri uri = FastUri.parse(uriStr); 763 Set<String> nameSet = new Set<String>();
674 if (!uri.hasScheme) { 764 for (_LinkNode node in transitiveDependencies) {
675 // A relative path in this package, skip it. 765 for (UnlinkedUnit unit in node.unlinked.unlinkedUnits) {
676 } else if (uri.scheme == 'dart') { 766 for (UnlinkedImport import in unit.imports) {
677 // Dependency on the SDK is implicit and always added. 767 for (UnlinkedConfiguration configuration in import.configurations) {
678 // The SDK linked bundle is precomputed before linking packages. 768 nameSet.add(configuration.name);
679 } else if (uriStr.startsWith('package:')) { 769 }
680 String package = PubSummaryManager.getPackageName(uriStr);
681 _LinkNode packageNode = packageToNode[package];
682 if (packageNode == null && listedPackages.isListed(uriStr)) {
683 failed = true;
684 } 770 }
685 if (packageNode != null) { 771 for (UnlinkedExportPublic export in unit.publicNamespace.exports) {
686 dependencies.add(packageNode); 772 for (UnlinkedConfiguration configuration in export.configurations) {
773 nameSet.add(configuration.name);
774 }
687 } 775 }
688 } else {
689 failed = true;
690 } 776 }
691 } 777 }
692 778 List<String> sortedNameList = nameSet.toList()..sort();
693 for (UnlinkedUnit unit in unlinked.unlinkedUnits) { 779 signature.addInt(sortedNameList.length);
694 for (UnlinkedImport import in unit.imports) { 780 for (String name in sortedNameList) {
695 if (!import.isImplicit) { 781 signature.addString(name);
696 appendDependency(import.uri); 782 signature.addString(linker._getDeclaredVariable(name) ?? '');
697 }
698 }
699 for (UnlinkedExportPublic export in unit.publicNamespace.exports) {
700 appendDependency(export.uri);
701 }
702 } 783 }
703
704 return dependencies.toList();
705 } 784 }
706 785
707 /** 786 /**
708 * Compute the set of existing transitive dependencies for this node. 787 * Compute the set of existing transitive dependencies for this node.
709 * If any `package` dependency cannot be resolved, but it is one of the 788 * If any `package` dependency cannot be resolved, but it is one of the
710 * [listedPackages] then set [failed] to `true`. 789 * [listedPackages] then set [failed] to `true`.
711 * Only [unlinked] is used, so this method can be called before linking. 790 * Only [unlinked] is used, so this method can be called before linking.
712 */ 791 */
713 void computeTransitiveDependencies() { 792 void computeTransitiveDependencies() {
714 if (transitiveDependencies == null) { 793 if (transitiveDependencies == null) {
715 transitiveDependencies = new Set<_LinkNode>(); 794 transitiveDependencies = new Set<_LinkNode>();
716 795
717 void appendDependencies(_LinkNode node) { 796 void appendDependencies(_LinkNode node) {
718 if (transitiveDependencies.add(node)) { 797 if (transitiveDependencies.add(node)) {
719 node.dependencies.forEach(appendDependencies); 798 node.dependencies.forEach(appendDependencies);
720 } 799 }
721 } 800 }
722 801
723 appendDependencies(this); 802 appendDependencies(this);
724 if (transitiveDependencies.any((node) => node.failed)) { 803 if (transitiveDependencies.any((node) => node.failed)) {
725 failed = true; 804 failed = true;
726 } 805 }
727 } 806 }
728 } 807 }
729 808
730 @override 809 @override
731 String toString() => package.toString(); 810 String toString() => package.toString();
732
733 /**
734 * Append names and values of all referenced declared variables (even the
735 * ones without actually declared values) to the given [signature].
736 */
737 void _appendDeclaredVariables(ApiSignature signature) {
738 Set<String> nameSet = new Set<String>();
739 for (_LinkNode node in transitiveDependencies) {
740 for (UnlinkedUnit unit in node.unlinked.unlinkedUnits) {
741 for (UnlinkedImport import in unit.imports) {
742 for (UnlinkedConfiguration configuration in import.configurations) {
743 nameSet.add(configuration.name);
744 }
745 }
746 for (UnlinkedExportPublic export in unit.publicNamespace.exports) {
747 for (UnlinkedConfiguration configuration in export.configurations) {
748 nameSet.add(configuration.name);
749 }
750 }
751 }
752 }
753 List<String> sortedNameList = nameSet.toList()..sort();
754 signature.addInt(sortedNameList.length);
755 for (String name in sortedNameList) {
756 signature.addString(name);
757 signature.addString(getDeclaredVariable(name) ?? '');
758 }
759 }
760 } 811 }
761 812
762 /** 813 /**
763 * Specialization of [DependencyWalker] for linking packages.
764 */
765 class _LinkWalker extends DependencyWalker<_LinkNode> {
766 final _GetDeclaredVariable getDeclaredVariable;
767 final _ListedPackages listedPackages;
768 final SummaryDataStore store;
769 final bool strong;
770
771 _LinkWalker(
772 this.getDeclaredVariable, this.listedPackages, this.store, this.strong);
773
774 @override
775 void evaluate(_LinkNode node) {
776 evaluateScc([node]);
777 }
778
779 @override
780 void evaluateScc(List<_LinkNode> scc) {
781 Map<String, _LinkNode> uriToNode = <String, _LinkNode>{};
782 for (_LinkNode node in scc) {
783 for (String uri in node.unlinked.unlinkedUnitUris) {
784 uriToNode[uri] = node;
785 }
786 }
787 Set<String> libraryUris = uriToNode.keys.toSet();
788 // Perform linking.
789 Map<String, LinkedLibraryBuilder> linkedLibraries =
790 link(libraryUris, (String uri) {
791 return store.linkedMap[uri];
792 }, (String uri) {
793 return store.unlinkedMap[uri];
794 }, getDeclaredVariable, strong);
795 // Assemble linked bundles and put them into the store.
796 for (_LinkNode node in scc) {
797 PackageBundleAssembler assembler = new PackageBundleAssembler();
798 linkedLibraries.forEach((uri, linkedLibrary) {
799 if (identical(uriToNode[uri], node)) {
800 assembler.addLinkedLibrary(uri, linkedLibrary);
801 }
802 });
803 List<int> bytes = assembler.assemble().toBuffer();
804 node.linkedNewBytes = bytes;
805 node.linked = new PackageBundle.fromBuffer(bytes);
806 store.addBundle(null, node.linked);
807 }
808 }
809 }
810
811 /**
812 * The set of package names that are listed in the `.packages` file of a 814 * The set of package names that are listed in the `.packages` file of a
813 * context. These are the only packages, references to which can 815 * context. These are the only packages, references to which can
814 * be possibly resolved in the context. Nodes that reference a `package:` URI 816 * be possibly resolved in the context. Nodes that reference a `package:` URI
815 * without the unlinked bundle, so without the node, cannot be linked. 817 * without the unlinked bundle, so without the node, cannot be linked.
816 */ 818 */
817 class _ListedPackages { 819 class _ListedPackages {
818 final Set<String> names = new Set<String>(); 820 final Set<String> names = new Set<String>();
819 821
820 _ListedPackages(SourceFactory sourceFactory) { 822 _ListedPackages(SourceFactory sourceFactory) {
821 Map<String, List<Folder>> map = sourceFactory.packageMap; 823 Map<String, List<Folder>> map = sourceFactory.packageMap;
822 if (map != null) { 824 if (map != null) {
823 names.addAll(map.keys); 825 names.addAll(map.keys);
824 } 826 }
825 } 827 }
826 828
827 /** 829 /**
828 * Check whether the given `package:` [uri] is listed in the package map. 830 * Check whether the given `package:` [uri] is listed in the package map.
829 */ 831 */
830 bool isListed(String uri) { 832 bool isListed(String uri) {
831 String package = PubSummaryManager.getPackageName(uri); 833 String package = PubSummaryManager.getPackageName(uri);
832 return names.contains(package); 834 return names.contains(package);
833 } 835 }
834 } 836 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698