| 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 9322ccd5f8af4f7d409342c36fff0b9141478acc..9d0cb2d0924718eee1fad8207876a8356bcc4de1 100644
|
| --- a/pkg/code_transformers/lib/src/resolver_impl.dart
|
| +++ b/pkg/code_transformers/lib/src/resolver_impl.dart
|
| @@ -5,10 +5,14 @@
|
| library code_transformer.src.resolver_impl;
|
|
|
| import 'dart:async';
|
| +import 'package:analyzer/analyzer.dart' show parseCompilationUnit;
|
| import 'package:analyzer/src/generated/ast.dart';
|
| import 'package:analyzer/src/generated/element.dart';
|
| import 'package:analyzer/src/generated/engine.dart';
|
| +import 'package:analyzer/src/generated/error.dart';
|
| import 'package:analyzer/src/generated/java_io.dart';
|
| +import 'package:analyzer/src/generated/parser.dart';
|
| +import 'package:analyzer/src/generated/scanner.dart';
|
| import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
|
| import 'package:analyzer/src/generated/sdk_io.dart' show DirectoryBasedDartSdk;
|
| import 'package:analyzer/src/generated/source.dart';
|
| @@ -111,6 +115,7 @@ class ResolverImpl implements Resolver {
|
| // and see if it changed, then walk all files accessed by it.
|
| var visited = new Set<AssetId>();
|
| var visiting = new FutureGroup();
|
| + var toUpdate = [];
|
|
|
| void processAsset(AssetId assetId) {
|
| visited.add(assetId);
|
| @@ -121,12 +126,10 @@ class ResolverImpl implements Resolver {
|
| source = new _AssetBasedSource(assetId, this);
|
| sources[assetId] = source;
|
| }
|
| - source.updateContents(contents);
|
| -
|
| - source.dependentAssets
|
| - .where((id) => !visited.contains(id))
|
| + source.updateDependencies(contents);
|
| + toUpdate.add(new _PendingUpdate(source, contents));
|
| + source.dependentAssets.where((id) => !visited.contains(id))
|
| .forEach(processAsset);
|
| -
|
| }, onError: (e) {
|
| _context.applyChanges(new ChangeSet()..removedSource(sources[assetId]));
|
| sources.remove(assetId);
|
| @@ -138,6 +141,7 @@ class ResolverImpl implements Resolver {
|
| // resolve everything.
|
| return visiting.future.then((_) {
|
| var changeSet = new ChangeSet();
|
| + toUpdate.forEach((pending) => pending.apply(changeSet));
|
| var unreachableAssets = new Set.from(sources.keys).difference(visited);
|
| for (var unreachable in unreachableAssets) {
|
| changeSet.removedSource(sources[unreachable]);
|
| @@ -275,30 +279,26 @@ class _AssetBasedSource extends Source {
|
|
|
| _AssetBasedSource(this.assetId, this._resolver);
|
|
|
| + /// Update the dependencies of this source. This parses [contents] but avoids
|
| + /// any analyzer resolution.
|
| + void updateDependencies(String contents) {
|
| + if (contents == _contents) return;
|
| + var unit = parseCompilationUnit(contents);
|
| + _dependentAssets = unit.directives
|
| + .where((d) => (d is ImportDirective || d is PartDirective ||
|
| + d is ExportDirective))
|
| + .map((d) => _resolve(assetId, d.uri.stringValue, _logger,
|
| + _getSpan(d, contents)))
|
| + .where((id) => id != null).toSet();
|
| + }
|
| +
|
| /// Update the contents of this file with [contents].
|
| ///
|
| /// Returns true if the contents of this asset have changed.
|
| bool updateContents(String contents) {
|
| if (contents == _contents) return false;
|
| - var added = _contents == null;
|
| _contents = contents;
|
| ++_revision;
|
| - // Invalidate the imports so we only parse the AST when needed.
|
| - _dependentAssets = null;
|
| -
|
| - if (added) {
|
| - _resolver._context.applyChanges(new ChangeSet()..addedSource(this));
|
| - } else {
|
| - _resolver._context.applyChanges(new ChangeSet()..changedSource(this));
|
| - }
|
| -
|
| - var compilationUnit = _resolver._context.parseCompilationUnit(this);
|
| - _dependentAssets = compilationUnit.directives
|
| - .where((d) => (d is ImportDirective || d is PartDirective ||
|
| - d is ExportDirective))
|
| - .map((d) => _resolve(assetId, d.uri.stringValue,
|
| - _logger, _getSpan(d)))
|
| - .where((id) => id != null).toSet();
|
| return true;
|
| }
|
|
|
| @@ -357,13 +357,13 @@ class _AssetBasedSource extends Source {
|
| }
|
|
|
| /// For logging errors.
|
| - Span _getSpan(AstNode node) => _sourceFile.span(node.offset, node.end);
|
| + Span _getSpan(AstNode node, [String contents]) =>
|
| + _getSourceFile(contents).span(node.offset, node.end);
|
| /// For logging errors.
|
| - SourceFile get _sourceFile {
|
| + SourceFile _getSourceFile([String contents]) {
|
| var uri = getSourceUri(_resolver.entryPoint);
|
| var path = uri != null ? uri.toString() : assetId.path;
|
| -
|
| - return new SourceFile.text(path, rawContents);
|
| + return new SourceFile.text(path, contents != null ? contents : rawContents);
|
| }
|
|
|
| /// Gets a URI which would be appropriate for importing this file.
|
| @@ -574,3 +574,23 @@ class FutureGroup<E> {
|
| */
|
| Future<List<E>> get future => _completer.future;
|
| }
|
| +
|
| +/// A pending update to notify the resolver that a [Source] has been added or
|
| +/// changed. This is used by the `_performResolve` algorithm above to apply all
|
| +/// changes after it first discovers the transitive closure of files that are
|
| +/// reachable from the sources.
|
| +class _PendingUpdate {
|
| + _AssetBasedSource source;
|
| + String content;
|
| +
|
| + _PendingUpdate(this.source, this.content);
|
| +
|
| + void apply(ChangeSet changeSet) {
|
| + if (!source.updateContents(content)) return;
|
| + if (source._revision == 1 && source._contents != null) {
|
| + changeSet.addedSource(source);
|
| + } else {
|
| + changeSet.changedSource(source);
|
| + }
|
| + }
|
| +}
|
|
|