| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library code_transformer.src.resolver_impl; | 5 library code_transformer.src.resolver_impl; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'package:analyzer/analyzer.dart' show parseCompilationUnit; | 8 import 'package:analyzer/analyzer.dart' show parseCompilationUnit; |
| 9 import 'package:analyzer/src/generated/ast.dart'; | 9 import 'package:analyzer/src/generated/ast.dart'; |
| 10 import 'package:analyzer/src/generated/element.dart'; | 10 import 'package:analyzer/src/generated/element.dart'; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 73 | 73 |
| 74 LibraryElement getLibrary(AssetId assetId) { | 74 LibraryElement getLibrary(AssetId assetId) { |
| 75 var source = sources[assetId]; | 75 var source = sources[assetId]; |
| 76 return source == null ? null : _context.computeLibraryElement(source); | 76 return source == null ? null : _context.computeLibraryElement(source); |
| 77 } | 77 } |
| 78 | 78 |
| 79 Future<Resolver> resolve(Transform transform, [List<AssetId> entryPoints]) { | 79 Future<Resolver> resolve(Transform transform, [List<AssetId> entryPoints]) { |
| 80 // Can only have one resolve in progress at a time, so chain the current | 80 // Can only have one resolve in progress at a time, so chain the current |
| 81 // resolution to be after the last one. | 81 // resolution to be after the last one. |
| 82 var phaseComplete = new Completer(); | 82 var phaseComplete = new Completer(); |
| 83 var future = _lastPhaseComplete.then((_) { | 83 var future = _lastPhaseComplete.whenComplete(() { |
| 84 _currentPhaseComplete = phaseComplete; | 84 _currentPhaseComplete = phaseComplete; |
| 85 return _performResolve(transform, | 85 return _performResolve(transform, |
| 86 entryPoints == null ? [transform.primaryInput.id] : entryPoints); | 86 entryPoints == null ? [transform.primaryInput.id] : entryPoints); |
| 87 }).then((_) => this); | 87 }).then((_) => this); |
| 88 // Advance the lastPhaseComplete to be done when this phase is all done. | 88 // Advance the lastPhaseComplete to be done when this phase is all done. |
| 89 _lastPhaseComplete = phaseComplete.future; | 89 _lastPhaseComplete = phaseComplete.future; |
| 90 return future; | 90 return future; |
| 91 } | 91 } |
| 92 | 92 |
| 93 void release() { | 93 void release() { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 122 var source = sources[assetId]; | 122 var source = sources[assetId]; |
| 123 if (source == null) { | 123 if (source == null) { |
| 124 source = new _AssetBasedSource(assetId, this); | 124 source = new _AssetBasedSource(assetId, this); |
| 125 sources[assetId] = source; | 125 sources[assetId] = source; |
| 126 } | 126 } |
| 127 source.updateDependencies(contents); | 127 source.updateDependencies(contents); |
| 128 toUpdate.add(new _PendingUpdate(source, contents)); | 128 toUpdate.add(new _PendingUpdate(source, contents)); |
| 129 source.dependentAssets.where((id) => !visited.contains(id)) | 129 source.dependentAssets.where((id) => !visited.contains(id)) |
| 130 .forEach(processAsset); | 130 .forEach(processAsset); |
| 131 }, onError: (e) { | 131 }, onError: (e) { |
| 132 _context.applyChanges(new ChangeSet()..removedSource(sources[assetId])); | 132 var source = sources[assetId]; |
| 133 sources.remove(assetId); | 133 if (source != null && source.exists()) { |
| 134 _context.applyChanges( |
| 135 new ChangeSet()..removedSource(source)); |
| 136 sources[assetId].updateContents(null); |
| 137 } |
| 134 })); | 138 })); |
| 135 } | 139 } |
| 136 entryPoints.forEach(processAsset); | 140 entryPoints.forEach(processAsset); |
| 137 | 141 |
| 138 // Once we have all asset sources updated with the new contents then | 142 // Once we have all asset sources updated with the new contents then |
| 139 // resolve everything. | 143 // resolve everything. |
| 140 return visiting.future.then((_) { | 144 return visiting.future.then((_) { |
| 141 var changeSet = new ChangeSet(); | 145 var changeSet = new ChangeSet(); |
| 142 toUpdate.forEach((pending) => pending.apply(changeSet)); | 146 toUpdate.forEach((pending) => pending.apply(changeSet)); |
| 143 var unreachableAssets = new Set.from(sources.keys).difference(visited); | 147 var unreachableAssets = sources.keys.toSet() |
| 148 .difference(visited) |
| 149 .map((id) => sources[id]); |
| 144 for (var unreachable in unreachableAssets) { | 150 for (var unreachable in unreachableAssets) { |
| 145 changeSet.removedSource(sources[unreachable]); | 151 changeSet.removedSource(unreachable); |
| 146 sources.remove(unreachable); | 152 unreachable.updateContents(null); |
| 153 sources.remove(unreachable.assetId); |
| 147 } | 154 } |
| 148 | 155 |
| 149 // Update the analyzer context with the latest sources | 156 // Update the analyzer context with the latest sources |
| 150 _context.applyChanges(changeSet); | 157 _context.applyChanges(changeSet); |
| 151 // Force resolve each entry point (the getter will ensure the library is | 158 // Force resolve each entry point (the getter will ensure the library is |
| 152 // computed first). | 159 // computed first). |
| 153 _entryLibraries = entryPoints | 160 _entryLibraries = entryPoints |
| 154 .map((id) => _context.computeLibraryElement(sources[id])).toList(); | 161 .map((id) => _context.computeLibraryElement(sources[id])).toList(); |
| 155 }); | 162 }); |
| 156 } | 163 } |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 315 /// | 322 /// |
| 316 /// Returns true if the contents of this asset have changed. | 323 /// Returns true if the contents of this asset have changed. |
| 317 bool updateContents(String contents) { | 324 bool updateContents(String contents) { |
| 318 if (contents == _contents) return false; | 325 if (contents == _contents) return false; |
| 319 _contents = contents; | 326 _contents = contents; |
| 320 ++_revision; | 327 ++_revision; |
| 321 return true; | 328 return true; |
| 322 } | 329 } |
| 323 | 330 |
| 324 /// Contents of the file. | 331 /// Contents of the file. |
| 325 TimestampedData<String> get contents => | 332 TimestampedData<String> get contents { |
| 326 new TimestampedData<String>(modificationStamp, _contents); | 333 if (!exists()) throw new StateError('$assetId does not exist'); |
| 334 |
| 335 return new TimestampedData<String>(modificationStamp, _contents); |
| 336 } |
| 327 | 337 |
| 328 /// Contents of the file. | 338 /// Contents of the file. |
| 329 String get rawContents => _contents; | 339 String get rawContents => _contents; |
| 330 | 340 |
| 331 /// Logger for the current transform. | 341 /// Logger for the current transform. |
| 332 /// | 342 /// |
| 333 /// Only valid while the resolver is updating assets. | 343 /// Only valid while the resolver is updating assets. |
| 334 TransformLogger get _logger => _resolver._currentTransform.logger; | 344 TransformLogger get _logger => _resolver._currentTransform.logger; |
| 335 | 345 |
| 336 /// Gets all imports/parts/exports which resolve to assets (non-Dart files). | 346 /// Gets all imports/parts/exports which resolve to assets (non-Dart files). |
| 337 Iterable<AssetId> get dependentAssets => _dependentAssets; | 347 Iterable<AssetId> get dependentAssets => _dependentAssets; |
| 338 | 348 |
| 339 bool exists() => true; | 349 bool exists() => _contents != null; |
| 340 | 350 |
| 341 bool operator ==(Object other) => | 351 bool operator ==(Object other) => |
| 342 other is _AssetBasedSource && assetId == other.assetId; | 352 other is _AssetBasedSource && assetId == other.assetId; |
| 343 | 353 |
| 344 int get hashCode => assetId.hashCode; | 354 int get hashCode => assetId.hashCode; |
| 345 | 355 |
| 346 void getContentsToReceiver(Source_ContentReceiver receiver) { | 356 void getContentsToReceiver(Source_ContentReceiver receiver) { |
| 347 receiver.accept(rawContents, modificationStamp); | 357 receiver.accept(rawContents, modificationStamp); |
| 348 } | 358 } |
| 349 | 359 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 402 } | 412 } |
| 403 } | 413 } |
| 404 | 414 |
| 405 /// Implementation of Analyzer's UriResolver for Barback based assets. | 415 /// Implementation of Analyzer's UriResolver for Barback based assets. |
| 406 class _AssetUriResolver implements UriResolver { | 416 class _AssetUriResolver implements UriResolver { |
| 407 final ResolverImpl _resolver; | 417 final ResolverImpl _resolver; |
| 408 _AssetUriResolver(this._resolver); | 418 _AssetUriResolver(this._resolver); |
| 409 | 419 |
| 410 Source resolveAbsolute(Uri uri) { | 420 Source resolveAbsolute(Uri uri) { |
| 411 var assetId = _resolve(null, uri.toString(), logger, null); | 421 var assetId = _resolve(null, uri.toString(), logger, null); |
| 422 if (assetId == null) { |
| 423 logger.error('Unable to resolve asset ID for "$uri"'); |
| 424 return null; |
| 425 } |
| 412 var source = _resolver.sources[assetId]; | 426 var source = _resolver.sources[assetId]; |
| 413 /// All resolved assets should be available by this point. | 427 // Analyzer expects that sources which are referenced but do not exist yet |
| 428 // still exist, so just make an empty source. |
| 414 if (source == null) { | 429 if (source == null) { |
| 415 logger.error('Unable to find asset for "$uri"'); | 430 source = new _AssetBasedSource(assetId, _resolver); |
| 431 _resolver.sources[assetId] = source; |
| 416 } | 432 } |
| 417 return source; | 433 return source; |
| 418 } | 434 } |
| 419 | 435 |
| 420 Source fromEncoding(UriKind kind, Uri uri) => | 436 Source fromEncoding(UriKind kind, Uri uri) => |
| 421 throw new UnsupportedError('fromEncoding is not supported'); | 437 throw new UnsupportedError('fromEncoding is not supported'); |
| 422 | 438 |
| 423 Uri restoreAbsolute(Source source) => | 439 Uri restoreAbsolute(Source source) => |
| 424 throw new UnsupportedError('restoreAbsolute is not supported'); | 440 throw new UnsupportedError('restoreAbsolute is not supported'); |
| 425 | 441 |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 571 _completer.complete(results); | 587 _completer.complete(results); |
| 572 } | 588 } |
| 573 }, onError: (e, s) { | 589 }, onError: (e, s) { |
| 574 if (_failedTask != null) return; | 590 if (_failedTask != null) return; |
| 575 _failedTask = task; | 591 _failedTask = task; |
| 576 _completer.completeError(e, s); | 592 _completer.completeError(e, s); |
| 577 }); | 593 }); |
| 578 } | 594 } |
| 579 | 595 |
| 580 /** | 596 /** |
| 581 * A Future that complets with a List of the values from all the added | 597 * A Future that completes with a List of the values from all the added |
| 582 * tasks, when they have all completed. | 598 * tasks, when they have all completed. |
| 583 * | 599 * |
| 584 * If any task fails, this Future will receive the error. Only the first | 600 * If any task fails, this Future will receive the error. Only the first |
| 585 * error will be sent to the Future. | 601 * error will be sent to the Future. |
| 586 */ | 602 */ |
| 587 Future<List<E>> get future => _completer.future; | 603 Future<List<E>> get future => _completer.future; |
| 588 } | 604 } |
| 589 | 605 |
| 590 /// A pending update to notify the resolver that a [Source] has been added or | 606 /// A pending update to notify the resolver that a [Source] has been added or |
| 591 /// changed. This is used by the `_performResolve` algorithm above to apply all | 607 /// changed. This is used by the `_performResolve` algorithm above to apply all |
| 592 /// changes after it first discovers the transitive closure of files that are | 608 /// changes after it first discovers the transitive closure of files that are |
| 593 /// reachable from the sources. | 609 /// reachable from the sources. |
| 594 class _PendingUpdate { | 610 class _PendingUpdate { |
| 595 _AssetBasedSource source; | 611 _AssetBasedSource source; |
| 596 String content; | 612 String content; |
| 597 | 613 |
| 598 _PendingUpdate(this.source, this.content); | 614 _PendingUpdate(this.source, this.content); |
| 599 | 615 |
| 600 void apply(ChangeSet changeSet) { | 616 void apply(ChangeSet changeSet) { |
| 601 if (!source.updateContents(content)) return; | 617 if (!source.updateContents(content)) return; |
| 602 if (source._revision == 1 && source._contents != null) { | 618 if (source._revision == 1 && source._contents != null) { |
| 603 changeSet.addedSource(source); | 619 changeSet.addedSource(source); |
| 604 } else { | 620 } else { |
| 605 changeSet.changedSource(source); | 621 changeSet.changedSource(source); |
| 606 } | 622 } |
| 607 } | 623 } |
| 608 } | 624 } |
| OLD | NEW |