| OLD | NEW |
| 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' hide Resource; | 7 import 'dart:core' hide Resource; |
| 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'; |
| 11 import 'package:analyzer/file_system/file_system.dart'; | 11 import 'package:analyzer/file_system/file_system.dart'; |
| 12 import 'package:analyzer/src/dart/scanner/reader.dart'; | 12 import 'package:analyzer/src/dart/scanner/reader.dart'; |
| 13 import 'package:analyzer/src/dart/scanner/scanner.dart'; | 13 import 'package:analyzer/src/dart/scanner/scanner.dart'; |
| 14 import 'package:analyzer/src/dart/sdk/sdk.dart'; | |
| 15 import 'package:analyzer/src/generated/engine.dart'; | 14 import 'package:analyzer/src/generated/engine.dart'; |
| 16 import 'package:analyzer/src/generated/error.dart'; | 15 import 'package:analyzer/src/generated/error.dart'; |
| 17 import 'package:analyzer/src/generated/parser.dart'; | 16 import 'package:analyzer/src/generated/parser.dart'; |
| 18 import 'package:analyzer/src/generated/source.dart'; | 17 import 'package:analyzer/src/generated/source.dart'; |
| 19 import 'package:analyzer/src/generated/utilities_dart.dart'; | |
| 20 import 'package:analyzer/src/summary/api_signature.dart'; | 18 import 'package:analyzer/src/summary/api_signature.dart'; |
| 21 import 'package:analyzer/src/summary/format.dart'; | 19 import 'package:analyzer/src/summary/format.dart'; |
| 22 import 'package:analyzer/src/summary/idl.dart'; | 20 import 'package:analyzer/src/summary/idl.dart'; |
| 23 import 'package:analyzer/src/summary/link.dart'; | 21 import 'package:analyzer/src/summary/link.dart'; |
| 24 import 'package:analyzer/src/summary/package_bundle_reader.dart' | 22 import 'package:analyzer/src/summary/package_bundle_reader.dart' |
| 25 show ResynthesizerResultProvider, SummaryDataStore; | 23 show ResynthesizerResultProvider, SummaryDataStore; |
| 26 import 'package:analyzer/src/summary/summarize_ast.dart' | 24 import 'package:analyzer/src/summary/summarize_ast.dart' |
| 27 show serializeAstUnlinked; | 25 show serializeAstUnlinked; |
| 28 import 'package:analyzer/src/summary/summarize_elements.dart' | 26 import 'package:analyzer/src/summary/summarize_elements.dart' |
| 29 show PackageBundleAssembler; | 27 show PackageBundleAssembler; |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 132 _onUnlinkedCompleteCompleter ??= new Completer(); | 130 _onUnlinkedCompleteCompleter ??= new Completer(); |
| 133 return _onUnlinkedCompleteCompleter.future; | 131 return _onUnlinkedCompleteCompleter.future; |
| 134 } | 132 } |
| 135 | 133 |
| 136 /** | 134 /** |
| 137 * Return the [pathos.Context] corresponding to the [resourceProvider]. | 135 * Return the [pathos.Context] corresponding to the [resourceProvider]. |
| 138 */ | 136 */ |
| 139 pathos.Context get pathContext => resourceProvider.pathContext; | 137 pathos.Context get pathContext => resourceProvider.pathContext; |
| 140 | 138 |
| 141 /** | 139 /** |
| 142 * Compute and return the linked bundle for the SDK extension for the given | |
| 143 * [context], or `null` if none of the packages has an SDK extension. At most | |
| 144 * one extension library is supported, if more than one is found, then an | |
| 145 * error will be logged, and `null` returned. | |
| 146 */ | |
| 147 PackageBundle computeSdkExtension( | |
| 148 AnalysisContext context, PackageBundle sdkBundle) { | |
| 149 // Prepare SDK extension library files. | |
| 150 String libUriStr; | |
| 151 String libPath; | |
| 152 { | |
| 153 Map<String, List<Folder>> packageMap = context.sourceFactory.packageMap; | |
| 154 SdkExtensionFinder extFinder = new SdkExtensionFinder(packageMap); | |
| 155 Map<String, String> sdkExtMappings = extFinder.urlMappings; | |
| 156 if (sdkExtMappings.length == 1) { | |
| 157 libUriStr = sdkExtMappings.keys.first; | |
| 158 libPath = sdkExtMappings.values.first; | |
| 159 } else if (sdkExtMappings.length > 1) { | |
| 160 AnalysisEngine.instance.logger | |
| 161 .logError('At most one _sdkext file is supported, ' | |
| 162 'with at most one extension library. $sdkExtMappings found.'); | |
| 163 return null; | |
| 164 } else { | |
| 165 return null; | |
| 166 } | |
| 167 } | |
| 168 // Compute the extension unlinked bundle. | |
| 169 bool strong = context.analysisOptions.strongMode; | |
| 170 PackageBundleAssembler assembler = new PackageBundleAssembler(); | |
| 171 try { | |
| 172 File libFile = resourceProvider.getFile(libPath); | |
| 173 Uri libUri = FastUri.parse(libUriStr); | |
| 174 Source libSource = libFile.createSource(libUri); | |
| 175 CompilationUnit libraryUnit = _parse(libSource, strong); | |
| 176 // Add the library unit. | |
| 177 assembler.addUnlinkedUnit(libSource, serializeAstUnlinked(libraryUnit)); | |
| 178 // Add part units. | |
| 179 for (Directive directive in libraryUnit.directives) { | |
| 180 if (directive is PartDirective) { | |
| 181 Source partSource; | |
| 182 { | |
| 183 String partUriStr = directive.uri.stringValue; | |
| 184 Uri partUri = resolveRelativeUri(libUri, FastUri.parse(partUriStr)); | |
| 185 pathos.Context pathContext = resourceProvider.pathContext; | |
| 186 String partPath = | |
| 187 pathContext.join(pathContext.dirname(libPath), partUriStr); | |
| 188 File partFile = resourceProvider.getFile(partPath); | |
| 189 partSource = partFile.createSource(partUri); | |
| 190 } | |
| 191 CompilationUnit partUnit = _parse(partSource, strong); | |
| 192 assembler.addUnlinkedUnit(partSource, serializeAstUnlinked(partUnit)); | |
| 193 } | |
| 194 } | |
| 195 // Add the SDK and the unlinked extension bundle. | |
| 196 PackageBundleBuilder unlinkedBuilder = assembler.assemble(); | |
| 197 SummaryDataStore store = new SummaryDataStore(const <String>[]); | |
| 198 store.addBundle(null, sdkBundle); | |
| 199 store.addBundle(null, unlinkedBuilder); | |
| 200 // Link the extension bundle. | |
| 201 Map<String, LinkedLibraryBuilder> linkedLibraries = | |
| 202 link([libUriStr].toSet(), (String absoluteUri) { | |
| 203 return store.linkedMap[absoluteUri]; | |
| 204 }, (String absoluteUri) { | |
| 205 return store.unlinkedMap[absoluteUri]; | |
| 206 }, strong); | |
| 207 if (linkedLibraries.length != 1) { | |
| 208 return null; | |
| 209 } | |
| 210 // Append linked libraries into the assembler. | |
| 211 linkedLibraries.forEach((uri, library) { | |
| 212 assembler.addLinkedLibrary(uri, library); | |
| 213 }); | |
| 214 List<int> bytes = assembler.assemble().toBuffer(); | |
| 215 return new PackageBundle.fromBuffer(bytes); | |
| 216 } on FileSystemException { | |
| 217 return null; | |
| 218 } | |
| 219 } | |
| 220 | |
| 221 /** | |
| 222 * Complete when the unlinked bundles for the package with the given [name] | 140 * Complete when the unlinked bundles for the package with the given [name] |
| 223 * and the [libFolder] are computed and written to the files. | 141 * and the [libFolder] are computed and written to the files. |
| 224 * | 142 * |
| 225 * This method is intended to be used for generating unlinked bundles for | 143 * This method is intended to be used for generating unlinked bundles for |
| 226 * the `Flutter` packages. | 144 * the `Flutter` packages. |
| 227 */ | 145 */ |
| 228 Future<Null> computeUnlinkedForFolder(String name, Folder libFolder) async { | 146 Future<Null> computeUnlinkedForFolder(String name, Folder libFolder) async { |
| 229 PubPackage package = new PubPackage(name, libFolder); | 147 PubPackage package = new PubPackage(name, libFolder); |
| 230 _scheduleUnlinked(package); | 148 _scheduleUnlinked(package); |
| 231 await onUnlinkedComplete; | 149 await onUnlinkedComplete; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 242 // Stopwatch timer = new Stopwatch()..start(); | 160 // Stopwatch timer = new Stopwatch()..start(); |
| 243 | 161 |
| 244 SourceFactory sourceFactory = context.sourceFactory; | 162 SourceFactory sourceFactory = context.sourceFactory; |
| 245 _ListedPackages listedPackages = new _ListedPackages(sourceFactory); | 163 _ListedPackages listedPackages = new _ListedPackages(sourceFactory); |
| 246 | 164 |
| 247 PackageBundle sdkBundle = sourceFactory.dartSdk.getLinkedBundle(); | 165 PackageBundle sdkBundle = sourceFactory.dartSdk.getLinkedBundle(); |
| 248 if (sdkBundle == null) { | 166 if (sdkBundle == null) { |
| 249 return const <LinkedPubPackage>[]; | 167 return const <LinkedPubPackage>[]; |
| 250 } | 168 } |
| 251 | 169 |
| 252 // Prepare all SDK bundles. | |
| 253 List<PackageBundle> sdkBundles = <PackageBundle>[sdkBundle]; | |
| 254 { | |
| 255 PackageBundle extension = computeSdkExtension(context, sdkBundle); | |
| 256 if (extension != null) { | |
| 257 sdkBundles.add(extension); | |
| 258 } | |
| 259 } | |
| 260 | |
| 261 bool strong = context.analysisOptions.strongMode; | 170 bool strong = context.analysisOptions.strongMode; |
| 262 Map<PubPackage, PackageBundle> unlinkedBundles = | 171 Map<PubPackage, PackageBundle> unlinkedBundles = |
| 263 getUnlinkedBundles(context); | 172 getUnlinkedBundles(context); |
| 264 | 173 |
| 265 // TODO(scheglov) remove debug output after optimizing | 174 // TODO(scheglov) remove debug output after optimizing |
| 266 // print('LOADED ${unlinkedBundles.length} unlinked bundles' | 175 // print('LOADED ${unlinkedBundles.length} unlinked bundles' |
| 267 // ' in ${timer.elapsedMilliseconds} ms'); | 176 // ' in ${timer.elapsedMilliseconds} ms'); |
| 268 // timer..reset(); | 177 // timer..reset(); |
| 269 | 178 |
| 270 // If no unlinked bundles, there is nothing we can try to link. | 179 // If no unlinked bundles, there is nothing we can try to link. |
| 271 if (unlinkedBundles.isEmpty) { | 180 if (unlinkedBundles.isEmpty) { |
| 272 return const <LinkedPubPackage>[]; | 181 return const <LinkedPubPackage>[]; |
| 273 } | 182 } |
| 274 | 183 |
| 275 // Create graph nodes for packages. | 184 // Create graph nodes for packages. |
| 276 List<_LinkedNode> nodes = <_LinkedNode>[]; | 185 List<_LinkedNode> nodes = <_LinkedNode>[]; |
| 277 Map<String, _LinkedNode> packageToNode = <String, _LinkedNode>{}; | 186 Map<String, _LinkedNode> packageToNode = <String, _LinkedNode>{}; |
| 278 unlinkedBundles.forEach((package, unlinked) { | 187 unlinkedBundles.forEach((package, unlinked) { |
| 279 _LinkedNode node = new _LinkedNode( | 188 _LinkedNode node = new _LinkedNode( |
| 280 sdkBundles, listedPackages, package, unlinked, packageToNode); | 189 sdkBundle, listedPackages, package, unlinked, packageToNode); |
| 281 nodes.add(node); | 190 nodes.add(node); |
| 282 packageToNode[package.name] = node; | 191 packageToNode[package.name] = node; |
| 283 }); | 192 }); |
| 284 | 193 |
| 285 // Compute transitive dependencies, mark some nodes as failed. | 194 // Compute transitive dependencies, mark some nodes as failed. |
| 286 for (_LinkedNode node in nodes) { | 195 for (_LinkedNode node in nodes) { |
| 287 node.computeTransitiveDependencies(); | 196 node.computeTransitiveDependencies(); |
| 288 } | 197 } |
| 289 | 198 |
| 290 // Attempt to read existing linked bundles. | 199 // Attempt to read existing linked bundles. |
| 291 for (_LinkedNode node in nodes) { | 200 for (_LinkedNode node in nodes) { |
| 292 _readLinked(node, strong); | 201 _readLinked(node, strong); |
| 293 } | 202 } |
| 294 | 203 |
| 295 // Fill the store with bundles. | 204 // Fill the store with bundles. |
| 296 // Append linked SDK bundles. | 205 // Append the linked SDK bundle. |
| 297 // Append unlinked and (if read from a cache) linked package bundles. | 206 // Append unlinked and (if read from a cache) linked package bundles. |
| 298 SummaryDataStore store = new SummaryDataStore(const <String>[]); | 207 SummaryDataStore store = new SummaryDataStore(const <String>[]); |
| 299 sdkBundles.forEach((bundle) => store.addBundle(null, bundle)); | 208 store.addBundle(null, sdkBundle); |
| 300 for (_LinkedNode node in nodes) { | 209 for (_LinkedNode node in nodes) { |
| 301 store.addBundle(null, node.unlinked); | 210 store.addBundle(null, node.unlinked); |
| 302 if (node.linked != null) { | 211 if (node.linked != null) { |
| 303 store.addBundle(null, node.linked); | 212 store.addBundle(null, node.linked); |
| 304 } | 213 } |
| 305 } | 214 } |
| 306 | 215 |
| 307 // Link each package node. | 216 // Link each package node. |
| 308 for (_LinkedNode node in nodes) { | 217 for (_LinkedNode node in nodes) { |
| 309 if (!node.isEvaluated) { | 218 if (!node.isEvaluated) { |
| (...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 619 } | 528 } |
| 620 } | 529 } |
| 621 return false; | 530 return false; |
| 622 } | 531 } |
| 623 } | 532 } |
| 624 | 533 |
| 625 /** | 534 /** |
| 626 * Specialization of [Node] for linking packages in proper dependency order. | 535 * Specialization of [Node] for linking packages in proper dependency order. |
| 627 */ | 536 */ |
| 628 class _LinkedNode extends Node<_LinkedNode> { | 537 class _LinkedNode extends Node<_LinkedNode> { |
| 629 final List<PackageBundle> sdkBundles; | 538 final PackageBundle sdkBundle; |
| 630 final _ListedPackages listedPackages; | 539 final _ListedPackages listedPackages; |
| 631 final PubPackage package; | 540 final PubPackage package; |
| 632 final PackageBundle unlinked; | 541 final PackageBundle unlinked; |
| 633 final Map<String, _LinkedNode> packageToNode; | 542 final Map<String, _LinkedNode> packageToNode; |
| 634 | 543 |
| 635 bool failed = false; | 544 bool failed = false; |
| 636 Set<_LinkedNode> transitiveDependencies; | 545 Set<_LinkedNode> transitiveDependencies; |
| 637 String _linkedHash; | 546 String _linkedHash; |
| 638 | 547 |
| 639 List<int> linkedNewBytes; | 548 List<int> linkedNewBytes; |
| 640 PackageBundle linked; | 549 PackageBundle linked; |
| 641 | 550 |
| 642 _LinkedNode(this.sdkBundles, this.listedPackages, this.package, this.unlinked, | 551 _LinkedNode(this.sdkBundle, this.listedPackages, this.package, this.unlinked, |
| 643 this.packageToNode); | 552 this.packageToNode); |
| 644 | 553 |
| 645 @override | 554 @override |
| 646 bool get isEvaluated => linked != null || failed; | 555 bool get isEvaluated => linked != null || failed; |
| 647 | 556 |
| 648 /** | 557 /** |
| 649 * Return the hash string that corresponds to this linked bundle in the | 558 * Return the hash string that corresponds to this linked bundle in the |
| 650 * context of its [sdkBundles] and transitive dependencies. Return `null` if | 559 * context of its [sdkBundles] and transitive dependencies. Return `null` if |
| 651 * the hash computation fails, because for example the full transitive | 560 * the hash computation fails, because for example the full transitive |
| 652 * dependencies cannot computed. | 561 * dependencies cannot computed. |
| 653 */ | 562 */ |
| 654 String get linkedHash { | 563 String get linkedHash { |
| 655 if (_linkedHash == null && transitiveDependencies != null) { | 564 if (_linkedHash == null && transitiveDependencies != null) { |
| 656 // Collect all unlinked API signatures. | 565 // Collect all unlinked API signatures. |
| 657 List<String> signatures = <String>[]; | 566 List<String> signatures = <String>[]; |
| 658 sdkBundles | 567 signatures.add(sdkBundle.apiSignature); |
| 659 .map((sdkBundle) => sdkBundle.apiSignature) | |
| 660 .forEach(signatures.add); | |
| 661 transitiveDependencies | 568 transitiveDependencies |
| 662 .map((node) => node.unlinked.apiSignature) | 569 .map((node) => node.unlinked.apiSignature) |
| 663 .forEach(signatures.add); | 570 .forEach(signatures.add); |
| 664 signatures.sort(); | 571 signatures.sort(); |
| 665 // Combine sorted unlinked API signatures into a single hash. | 572 // Combine sorted unlinked API signatures into a single hash. |
| 666 ApiSignature signature = new ApiSignature(); | 573 ApiSignature signature = new ApiSignature(); |
| 667 signatures.forEach(signature.addString); | 574 signatures.forEach(signature.addString); |
| 668 _linkedHash = signature.toHex(); | 575 _linkedHash = signature.toHex(); |
| 669 } | 576 } |
| 670 return _linkedHash; | 577 return _linkedHash; |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 800 } | 707 } |
| 801 | 708 |
| 802 /** | 709 /** |
| 803 * Check whether the given `package:` [uri] is listed in the package map. | 710 * Check whether the given `package:` [uri] is listed in the package map. |
| 804 */ | 711 */ |
| 805 bool isListed(String uri) { | 712 bool isListed(String uri) { |
| 806 String package = PubSummaryManager.getPackageName(uri); | 713 String package = PubSummaryManager.getPackageName(uri); |
| 807 return names.contains(package); | 714 return names.contains(package); |
| 808 } | 715 } |
| 809 } | 716 } |
| OLD | NEW |