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

Side by Side Diff: pkg/code_transformers/lib/src/resolver_impl.dart

Issue 199413020: Fixes code_transformers after the latest analyzer changes (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/code_transformers/lib/src/test_harness.dart » ('j') | 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) 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/src/generated/ast.dart'; 8 import 'package:analyzer/src/generated/ast.dart';
9 import 'package:analyzer/src/generated/element.dart'; 9 import 'package:analyzer/src/generated/element.dart';
10 import 'package:analyzer/src/generated/engine.dart'; 10 import 'package:analyzer/src/generated/engine.dart';
11 import 'package:analyzer/src/generated/error.dart';
11 import 'package:analyzer/src/generated/java_io.dart'; 12 import 'package:analyzer/src/generated/java_io.dart';
13 import 'package:analyzer/src/generated/parser.dart';
14 import 'package:analyzer/src/generated/scanner.dart';
12 import 'package:analyzer/src/generated/sdk.dart' show DartSdk; 15 import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
13 import 'package:analyzer/src/generated/sdk_io.dart' show DirectoryBasedDartSdk; 16 import 'package:analyzer/src/generated/sdk_io.dart' show DirectoryBasedDartSdk;
14 import 'package:analyzer/src/generated/source.dart'; 17 import 'package:analyzer/src/generated/source.dart';
15 import 'package:barback/barback.dart'; 18 import 'package:barback/barback.dart';
16 import 'package:path/path.dart' as native_path; 19 import 'package:path/path.dart' as native_path;
17 import 'package:source_maps/refactor.dart'; 20 import 'package:source_maps/refactor.dart';
18 import 'package:source_maps/span.dart' show SourceFile, Span; 21 import 'package:source_maps/span.dart' show SourceFile, Span;
19 22
20 import 'resolver.dart'; 23 import 'resolver.dart';
21 24
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 Future _performResolve(Transform transform) { 107 Future _performResolve(Transform transform) {
105 if (_currentTransform != null) { 108 if (_currentTransform != null) {
106 throw new StateError('Cannot be accessed by concurrent transforms'); 109 throw new StateError('Cannot be accessed by concurrent transforms');
107 } 110 }
108 _currentTransform = transform; 111 _currentTransform = transform;
109 112
110 // Basic approach is to start at the first file, update it's contents 113 // Basic approach is to start at the first file, update it's contents
111 // and see if it changed, then walk all files accessed by it. 114 // and see if it changed, then walk all files accessed by it.
112 var visited = new Set<AssetId>(); 115 var visited = new Set<AssetId>();
113 var visiting = new FutureGroup(); 116 var visiting = new FutureGroup();
117 var toUpdate = [];
114 118
115 void processAsset(AssetId assetId) { 119 void processAsset(AssetId assetId) {
116 visited.add(assetId); 120 visited.add(assetId);
117 121
118 visiting.add(transform.readInputAsString(assetId).then((contents) { 122 visiting.add(transform.readInputAsString(assetId).then((contents) {
119 var source = sources[assetId]; 123 var source = sources[assetId];
120 if (source == null) { 124 if (source == null) {
121 source = new _AssetBasedSource(assetId, this); 125 source = new _AssetBasedSource(assetId, this);
122 sources[assetId] = source; 126 sources[assetId] = source;
123 } 127 }
124 source.updateContents(contents); 128 source.updateDependencies(contents);
125 129 toUpdate.add(new _PendingUpdate(source, contents));
126 source.dependentAssets 130 source.dependentAssets.where((id) => !visited.contains(id))
127 .where((id) => !visited.contains(id))
128 .forEach(processAsset); 131 .forEach(processAsset);
129
130 }, onError: (e) { 132 }, onError: (e) {
131 _context.applyChanges(new ChangeSet()..removedSource(sources[assetId])); 133 _context.applyChanges(new ChangeSet()..removedSource(sources[assetId]));
132 sources.remove(assetId); 134 sources.remove(assetId);
133 })); 135 }));
134 } 136 }
135 processAsset(entryPoint); 137 processAsset(entryPoint);
136 138
137 // Once we have all asset sources updated with the new contents then 139 // Once we have all asset sources updated with the new contents then
138 // resolve everything. 140 // resolve everything.
139 return visiting.future.then((_) { 141 return visiting.future.then((_) {
140 var changeSet = new ChangeSet(); 142 var changeSet = new ChangeSet();
143 toUpdate.forEach((pending) => pending.apply(changeSet));
141 var unreachableAssets = new Set.from(sources.keys).difference(visited); 144 var unreachableAssets = new Set.from(sources.keys).difference(visited);
142 for (var unreachable in unreachableAssets) { 145 for (var unreachable in unreachableAssets) {
143 changeSet.removedSource(sources[unreachable]); 146 changeSet.removedSource(sources[unreachable]);
144 sources.remove(unreachable); 147 sources.remove(unreachable);
145 } 148 }
146 149
147 // Update the analyzer context with the latest sources 150 // Update the analyzer context with the latest sources
148 _context.applyChanges(changeSet); 151 _context.applyChanges(changeSet);
149 // Resolve the AST 152 // Resolve the AST
150 _entryLibrary = _context.computeLibraryElement(sources[entryPoint]); 153 _entryLibrary = _context.computeLibraryElement(sources[entryPoint]);
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 Iterable<AssetId> _dependentAssets; 271 Iterable<AssetId> _dependentAssets;
269 272
270 /// The current revision of the file, incremented only when file changes. 273 /// The current revision of the file, incremented only when file changes.
271 int _revision = 0; 274 int _revision = 0;
272 275
273 /// The file contents. 276 /// The file contents.
274 String _contents; 277 String _contents;
275 278
276 _AssetBasedSource(this.assetId, this._resolver); 279 _AssetBasedSource(this.assetId, this._resolver);
277 280
281 /// Update the dependencies of this source. This parses [contents] but avoids
282 /// any analyzer resolution.
283 void updateDependencies(String contents) {
284 if (contents == _contents) return;
285 var unit = _parseCompilationUnit(contents);
286 _dependentAssets = unit.directives
287 .where((d) => (d is ImportDirective || d is PartDirective ||
288 d is ExportDirective))
289 .map((d) => _resolve(assetId, d.uri.stringValue, _logger,
290 _getSpan(d, contents)))
291 .where((id) => id != null).toSet();
292 }
293
278 /// Update the contents of this file with [contents]. 294 /// Update the contents of this file with [contents].
279 /// 295 ///
280 /// Returns true if the contents of this asset have changed. 296 /// Returns true if the contents of this asset have changed.
281 bool updateContents(String contents) { 297 bool updateContents(String contents) {
282 if (contents == _contents) return false; 298 if (contents == _contents) return false;
283 var added = _contents == null;
284 _contents = contents; 299 _contents = contents;
285 ++_revision; 300 ++_revision;
286 // Invalidate the imports so we only parse the AST when needed.
287 _dependentAssets = null;
288
289 if (added) {
290 _resolver._context.applyChanges(new ChangeSet()..addedSource(this));
291 } else {
292 _resolver._context.applyChanges(new ChangeSet()..changedSource(this));
293 }
294
295 var compilationUnit = _resolver._context.parseCompilationUnit(this);
296 _dependentAssets = compilationUnit.directives
297 .where((d) => (d is ImportDirective || d is PartDirective ||
298 d is ExportDirective))
299 .map((d) => _resolve(assetId, d.uri.stringValue,
300 _logger, _getSpan(d)))
301 .where((id) => id != null).toSet();
302 return true; 301 return true;
303 } 302 }
304 303
305 /// Contents of the file. 304 /// Contents of the file.
306 TimestampedData<String> get contents => 305 TimestampedData<String> get contents =>
307 new TimestampedData<String>(modificationStamp, _contents); 306 new TimestampedData<String>(modificationStamp, _contents);
308 307
309 /// Contents of the file. 308 /// Contents of the file.
310 String get rawContents => _contents; 309 String get rawContents => _contents;
311 310
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
350 349
351 // The entire AST should have been parsed and loaded at this point. 350 // The entire AST should have been parsed and loaded at this point.
352 var source = _resolver.sources[id]; 351 var source = _resolver.sources[id];
353 if (source == null) { 352 if (source == null) {
354 _logger.error('Could not load asset $id'); 353 _logger.error('Could not load asset $id');
355 } 354 }
356 return source; 355 return source;
357 } 356 }
358 357
359 /// For logging errors. 358 /// For logging errors.
360 Span _getSpan(AstNode node) => _sourceFile.span(node.offset, node.end); 359 Span _getSpan(AstNode node, [String contents]) =>
360 _getSourceFile(contents).span(node.offset, node.end);
361 /// For logging errors. 361 /// For logging errors.
362 SourceFile get _sourceFile { 362 SourceFile _getSourceFile([String contents]) {
363 var uri = getSourceUri(_resolver.entryPoint); 363 var uri = getSourceUri(_resolver.entryPoint);
364 var path = uri != null ? uri.toString() : assetId.path; 364 var path = uri != null ? uri.toString() : assetId.path;
365 365 return new SourceFile.text(path, contents != null ? contents : rawContents);
366 return new SourceFile.text(path, rawContents);
367 } 366 }
368 367
369 /// Gets a URI which would be appropriate for importing this file. 368 /// Gets a URI which would be appropriate for importing this file.
370 /// 369 ///
371 /// Note that this file may represent a non-importable file such as a part. 370 /// Note that this file may represent a non-importable file such as a part.
372 Uri getSourceUri([AssetId from]) { 371 Uri getSourceUri([AssetId from]) {
373 if (!assetId.path.startsWith('lib/')) { 372 if (!assetId.path.startsWith('lib/')) {
374 // Cannot do absolute imports of non lib-based assets. 373 // Cannot do absolute imports of non lib-based assets.
375 if (from == null) return null; 374 if (from == null) return null;
376 375
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
567 566
568 /** 567 /**
569 * A Future that complets with a List of the values from all the added 568 * A Future that complets with a List of the values from all the added
570 * tasks, when they have all completed. 569 * tasks, when they have all completed.
571 * 570 *
572 * If any task fails, this Future will receive the error. Only the first 571 * If any task fails, this Future will receive the error. Only the first
573 * error will be sent to the Future. 572 * error will be sent to the Future.
574 */ 573 */
575 Future<List<E>> get future => _completer.future; 574 Future<List<E>> get future => _completer.future;
576 } 575 }
576
577 /// Parse [code] using just the analyzer's parser, without actually getting the
578 /// resolver to run.
579 CompilationUnit _parseCompilationUnit(String code) {
blois 2014/03/17 16:29:46 Should be able to use package:analyzer/analyzer.da
Siggi Cherem (dart-lang) 2014/03/17 17:58:09 Done.
580 var errorListener = new _ErrorCollector();
581 var reader = new CharSequenceReader(code);
582 var scanner = new Scanner(null, reader, errorListener);
583 var token = scanner.tokenize();
584 var parser = new Parser(null, errorListener);
585 return parser.parseCompilationUnit(token);
586 }
587
588 class _ErrorCollector extends AnalysisErrorListener {
589 final errors = <AnalysisError>[];
590 onError(error) => errors.add(error);
591 }
592
593 /// A pending update to notify the resolver that a [Source] has been added or
594 /// changed. This is used by the `_performResolve` algorithm above to apply all
595 /// changes after it first discovers the transitive closure of files that are
596 /// reachable from the sources.
597 class _PendingUpdate {
598 _AssetBasedSource source;
599 String content;
600
601 _PendingUpdate(this.source, this.content);
602
603 void apply(ChangeSet changeSet) {
604 if (!source.updateContents(content)) return;
605 if (source._revision == 1 && source._contents != null) {
606 changeSet.addedSource(source);
607 } else {
608 changeSet.changedSource(source);
609 }
610 }
611 }
OLDNEW
« no previous file with comments | « no previous file | pkg/code_transformers/lib/src/test_harness.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698