Chromium Code Reviews| Index: pkg/code_transformers/lib/src/resolver_impl.dart |
| diff --git a/pkg/code_transformers/lib/src/resolver_impl.dart b/pkg/code_transformers/lib/src/resolver_impl.dart |
| index e7820e6c71a955086b71e6a20ad3a22f5f3c3260..3e5d298f214b0418b1a9a5b7f518a061be427ade 100644 |
| --- a/pkg/code_transformers/lib/src/resolver_impl.dart |
| +++ b/pkg/code_transformers/lib/src/resolver_impl.dart |
| @@ -34,17 +34,14 @@ class ResolverImpl implements Resolver { |
| final Map<AssetId, _AssetBasedSource> sources = |
| <AssetId, _AssetBasedSource>{}; |
| - /// The Dart entry point file where parsing begins. |
| - final AssetId entryPoint; |
| - |
| final AnalysisContext _context = |
| AnalysisEngine.instance.createAnalysisContext(); |
| /// Transform for which this is currently updating, or null when not updating. |
| Transform _currentTransform; |
| - /// The currently resolved library, or null if unresolved. |
| - LibraryElement _entryLibrary; |
| + /// The currently resolved entry libraries, or null if nothing is resolved. |
| + List<LibraryElement> _entryLibraries; |
| /// Future indicating when this resolver is done in the current phase. |
| Future _lastPhaseComplete = new Future.value(); |
| @@ -55,12 +52,9 @@ class ResolverImpl implements Resolver { |
| /// Handler for all Dart SDK (dart:) sources. |
| DirectoryBasedDartSdk _dartSdk; |
| - /// Creates a resolver that will resolve the Dart code starting at |
| - /// [entryPoint]. |
| - /// |
| - /// [sdkDir] is the root directory of the Dart SDK, for resolving dart: |
| - /// imports. |
| - ResolverImpl(this.entryPoint, String sdkDir, {AnalysisOptions options}) { |
| + /// Creates a resolver, where [sdkDir] is the root directory of the Dart SDK, |
| + /// for resolving `dart:*` imports. |
| + ResolverImpl(String sdkDir, {AnalysisOptions options}) { |
| if (options == null) { |
| options = new AnalysisOptionsImpl() |
| ..cacheSize = 256 // # of sources to cache ASTs for. |
| @@ -77,16 +71,22 @@ class ResolverImpl implements Resolver { |
| new _AssetUriResolver(this)]); |
| } |
| - LibraryElement get entryLibrary => _entryLibrary; |
| + LibraryElement getLibrary(AssetId assetId) { |
| + var source = sources[assetId]; |
| + if (source._libraryElement == null) { |
| + source._libraryElement = _context.computeLibraryElement(source); |
|
blois
2014/03/17 16:55:45
computeLibraryElement is long-running the first ti
Siggi Cherem (dart-lang)
2014/03/17 20:13:39
Good to know, I had assumed that it didn't cache i
|
| + } |
| + return source == null ? null : source._libraryElement; |
|
blois
2014/03/17 16:55:45
If source can be null then it will crash in the if
Siggi Cherem (dart-lang)
2014/03/17 20:13:39
good catch! this was a last minute refactor and I
|
| + } |
| - Future<Resolver> resolve(Transform transform) { |
| + Future<Resolver> resolve(Transform transform, [List<AssetId> entryPoints]) { |
| // Can only have one resolve in progress at a time, so chain the current |
| // resolution to be after the last one. |
| var phaseComplete = new Completer(); |
| var future = _lastPhaseComplete.then((_) { |
| _currentPhaseComplete = phaseComplete; |
| - |
| - return _performResolve(transform); |
| + return _performResolve(transform, |
| + entryPoints == null ? [transform.primaryInput.id] : entryPoints); |
| }).then((_) => this); |
| // Advance the lastPhaseComplete to be done when this phase is all done. |
| _lastPhaseComplete = phaseComplete.future; |
| @@ -100,11 +100,13 @@ class ResolverImpl implements Resolver { |
| _currentPhaseComplete.complete(null); |
| _currentPhaseComplete = null; |
| - // Clear out the entry lib since it should not be referenced after release. |
| - _entryLibrary = null; |
| + // Clear out libraries since they should not be referenced after release. |
| + sources.values.forEach((source) { source._libraryElement = null; }); |
| + _entryLibraries = null; |
| + _currentTransform = null; |
| } |
| - Future _performResolve(Transform transform) { |
| + Future _performResolve(Transform transform, List<AssetId> entryPoints) { |
| if (_currentTransform != null) { |
| throw new StateError('Cannot be accessed by concurrent transforms'); |
| } |
| @@ -134,7 +136,7 @@ class ResolverImpl implements Resolver { |
| sources.remove(assetId); |
| })); |
| } |
| - processAsset(entryPoint); |
| + entryPoints.forEach(processAsset); |
| // Once we have all asset sources updated with the new contents then |
| // resolve everything. |
| @@ -149,13 +151,24 @@ class ResolverImpl implements Resolver { |
| // Update the analyzer context with the latest sources |
| _context.applyChanges(changeSet); |
| - // Resolve the AST |
| - _entryLibrary = _context.computeLibraryElement(sources[entryPoint]); |
| - _currentTransform = null; |
| + // Force resolve each entry point (the getter will ensure the library is |
| + // computed first). |
| + _entryLibraries = []; |
|
blois
2014/03/17 16:55:45
_entryLibraries = entryPoints.map((id) {
var sou
Siggi Cherem (dart-lang)
2014/03/17 20:13:39
Done.
|
| + for (var id in entryPoints) { |
| + var source = sources[id]; |
| + source._libraryElement = _context.computeLibraryElement(source); |
| + _entryLibraries.add(source._libraryElement); |
| + } |
| }); |
| } |
| - Iterable<LibraryElement> get libraries => entryLibrary.visibleLibraries; |
| + Iterable<LibraryElement> get libraries { |
| + var all = new Set(); |
|
blois
2014/03/17 16:55:45
=> _entryLibraries.expand((lib) => lib.visibleLibr
Siggi Cherem (dart-lang)
2014/03/17 20:13:39
Done.
|
| + for (var lib in _entryLibraries) { |
| + all.addAll(lib.visibleLibraries); |
| + } |
| + return all; |
| + } |
| LibraryElement getLibraryByName(String libraryName) => |
| libraries.firstWhere((l) => l.name == libraryName, orElse: () => null); |
| @@ -229,7 +242,7 @@ class ResolverImpl implements Resolver { |
| } |
| Span getSourceSpan(Element element) { |
| - var sourceFile = _getSourceFile(element); |
| + var sourceFile = getSourceFile(element); |
| if (sourceFile == null) return null; |
| return sourceFile.span(element.node.offset, element.node.end); |
| } |
| @@ -237,22 +250,27 @@ class ResolverImpl implements Resolver { |
| TextEditTransaction createTextEditTransaction(Element element) { |
| if (element.source is! _AssetBasedSource) return null; |
| + // Cannot edit unless there is an active transformer. |
| + if (_currentTransform == null) return null; |
| + |
| _AssetBasedSource source = element.source; |
| // Cannot modify assets in other packages. |
| - if (source.assetId.package != entryPoint.package) return null; |
| + if (source.assetId.package != _currentTransform.primaryInput.id.package) { |
| + return null; |
| + } |
| - var sourceFile = _getSourceFile(element); |
| + var sourceFile = getSourceFile(element); |
| if (sourceFile == null) return null; |
| return new TextEditTransaction(source.rawContents, sourceFile); |
| } |
| /// Gets the SourceFile for the source of the element. |
| - SourceFile _getSourceFile(Element element) { |
| + SourceFile getSourceFile(Element element) { |
| var assetId = getSourceAssetId(element); |
| if (assetId == null) return null; |
| - var importUri = _getSourceUri(element, from: entryPoint); |
| + var importUri = _getSourceUri(element); |
| var spanPath = importUri != null ? importUri.toString() : assetId.path; |
| return new SourceFile.text(spanPath, sources[assetId].rawContents); |
| } |
| @@ -276,6 +294,8 @@ class _AssetBasedSource extends Source { |
| /// The file contents. |
| String _contents; |
| + LibraryElement _libraryElement; |
| + |
| _AssetBasedSource(this.assetId, this._resolver); |
| /// Update the dependencies of this source. This parses [contents] but avoids |
| @@ -360,7 +380,7 @@ class _AssetBasedSource extends Source { |
| _getSourceFile(contents).span(node.offset, node.end); |
| /// For logging errors. |
| SourceFile _getSourceFile([String contents]) { |
| - var uri = getSourceUri(_resolver.entryPoint); |
| + var uri = getSourceUri(); |
| var path = uri != null ? uri.toString() : assetId.path; |
| return new SourceFile.text(path, contents != null ? contents : rawContents); |
| } |