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 parseDirectives; |
9 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; |
10 import 'package:analyzer/src/generated/constant.dart' show ConstantEvaluator, | 10 import 'package:analyzer/src/generated/constant.dart' show ConstantEvaluator, |
11 EvaluationResult; | 11 EvaluationResult; |
12 import 'package:analyzer/src/generated/element.dart'; | 12 import 'package:analyzer/src/generated/element.dart'; |
13 import 'package:analyzer/src/generated/engine.dart'; | 13 import 'package:analyzer/src/generated/engine.dart'; |
14 import 'package:analyzer/src/generated/java_io.dart'; | |
15 import 'package:analyzer/src/generated/sdk.dart' show DartSdk; | 14 import 'package:analyzer/src/generated/sdk.dart' show DartSdk; |
16 import 'package:analyzer/src/generated/sdk_io.dart' show DirectoryBasedDartSdk; | |
17 import 'package:analyzer/src/generated/source.dart'; | 15 import 'package:analyzer/src/generated/source.dart'; |
18 import 'package:barback/barback.dart'; | 16 import 'package:barback/barback.dart'; |
19 import 'package:code_transformers/assets.dart'; | 17 import 'package:code_transformers/assets.dart'; |
20 import 'package:path/path.dart' as native_path; | 18 import 'package:path/path.dart' as native_path; |
21 import 'package:source_maps/refactor.dart'; | 19 import 'package:source_maps/refactor.dart'; |
22 import 'package:source_maps/span.dart' show SourceFile, Span; | 20 import 'package:source_maps/span.dart' show SourceFile, Span; |
23 | 21 |
24 import 'resolver.dart'; | 22 import 'resolver.dart'; |
| 23 import 'dart_sdk.dart' show UriAnnotatedSource; |
25 | 24 |
26 // We should always be using url paths here since it's always Dart/pub code. | 25 // We should always be using url paths here since it's always Dart/pub code. |
27 final path = native_path.url; | 26 final path = native_path.url; |
28 | 27 |
29 /// Resolves and updates an AST based on Barback-based assets. | 28 /// Resolves and updates an AST based on Barback-based assets. |
30 /// | 29 /// |
31 /// This also provides a handful of useful APIs for traversing and working | 30 /// This also provides a handful of useful APIs for traversing and working |
32 /// with the resolved AST. | 31 /// with the resolved AST. |
33 class ResolverImpl implements Resolver { | 32 class ResolverImpl implements Resolver { |
34 /// Cache of all asset sources currently referenced. | 33 /// Cache of all asset sources currently referenced. |
35 final Map<AssetId, _AssetBasedSource> sources = | 34 final Map<AssetId, _AssetBasedSource> sources = |
36 <AssetId, _AssetBasedSource>{}; | 35 <AssetId, _AssetBasedSource>{}; |
37 | 36 |
38 final InternalAnalysisContext _context = | 37 final InternalAnalysisContext _context = |
39 AnalysisEngine.instance.createAnalysisContext(); | 38 AnalysisEngine.instance.createAnalysisContext(); |
40 | 39 |
41 /// Transform for which this is currently updating, or null when not updating. | 40 /// Transform for which this is currently updating, or null when not updating. |
42 Transform _currentTransform; | 41 Transform _currentTransform; |
43 | 42 |
44 /// The currently resolved entry libraries, or null if nothing is resolved. | 43 /// The currently resolved entry libraries, or null if nothing is resolved. |
45 List<LibraryElement> _entryLibraries; | 44 List<LibraryElement> _entryLibraries; |
46 Set<LibraryElement> _libraries; | 45 Set<LibraryElement> _libraries; |
47 | 46 |
48 /// Future indicating when this resolver is done in the current phase. | 47 /// Future indicating when this resolver is done in the current phase. |
49 Future _lastPhaseComplete = new Future.value(); | 48 Future _lastPhaseComplete = new Future.value(); |
50 | 49 |
51 /// Completer for wrapping up the current phase. | 50 /// Completer for wrapping up the current phase. |
52 Completer _currentPhaseComplete; | 51 Completer _currentPhaseComplete; |
53 | 52 |
54 /// Handler for all Dart SDK (dart:) sources. | 53 /// Creates a resolver with a given [sdk] implementation for resolving |
55 DirectoryBasedDartSdk _dartSdk; | 54 /// `dart:*` imports. |
56 | 55 ResolverImpl(DartSdk sdk, DartUriResolver dartUriResolver, |
57 /// Creates a resolver, where [sdkDir] is the root directory of the Dart SDK, | 56 {AnalysisOptions options}) { |
58 /// for resolving `dart:*` imports. | |
59 ResolverImpl(String sdkDir, {AnalysisOptions options}) { | |
60 if (options == null) { | 57 if (options == null) { |
61 options = new AnalysisOptionsImpl() | 58 options = new AnalysisOptionsImpl() |
62 ..cacheSize = 256 // # of sources to cache ASTs for. | 59 ..cacheSize = 256 // # of sources to cache ASTs for. |
63 ..preserveComments = false | 60 ..preserveComments = false |
64 ..analyzeFunctionBodies = true; | 61 ..analyzeFunctionBodies = true; |
65 } | 62 } |
66 _context.analysisOptions = options; | 63 _context.analysisOptions = options; |
67 | 64 sdk.context.analysisOptions = options; |
68 _dartSdk = new _DirectoryBasedDartSdkProxy(new JavaFile(sdkDir)); | 65 _context.sourceFactory = new SourceFactory([dartUriResolver, |
69 _dartSdk.context.analysisOptions = options; | |
70 | |
71 _context.sourceFactory = new SourceFactory([ | |
72 new DartUriResolverProxy(_dartSdk), | |
73 new _AssetUriResolver(this)]); | 66 new _AssetUriResolver(this)]); |
74 } | 67 } |
75 | 68 |
76 LibraryElement getLibrary(AssetId assetId) { | 69 LibraryElement getLibrary(AssetId assetId) { |
77 var source = sources[assetId]; | 70 var source = sources[assetId]; |
78 return source == null ? null : _context.computeLibraryElement(source); | 71 return source == null ? null : _context.computeLibraryElement(source); |
79 } | 72 } |
80 | 73 |
81 Future<Resolver> resolve(Transform transform, [List<AssetId> entryPoints]) { | 74 Future<Resolver> resolve(Transform transform, [List<AssetId> entryPoints]) { |
82 // Can only have one resolve in progress at a time, so chain the current | 75 // Can only have one resolve in progress at a time, so chain the current |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 Uri getImportUri(LibraryElement lib, {AssetId from}) => | 234 Uri getImportUri(LibraryElement lib, {AssetId from}) => |
242 _getSourceUri(lib, from: from); | 235 _getSourceUri(lib, from: from); |
243 | 236 |
244 | 237 |
245 /// Similar to getImportUri but will get the part URI for parts rather than | 238 /// Similar to getImportUri but will get the part URI for parts rather than |
246 /// the library URI. | 239 /// the library URI. |
247 Uri _getSourceUri(Element element, {AssetId from}) { | 240 Uri _getSourceUri(Element element, {AssetId from}) { |
248 var source = element.source; | 241 var source = element.source; |
249 if (source is _AssetBasedSource) { | 242 if (source is _AssetBasedSource) { |
250 return source.getSourceUri(from); | 243 return source.getSourceUri(from); |
251 } else if (source is _DartSourceProxy) { | 244 } else if (source is UriAnnotatedSource) { |
252 return source.uri; | 245 return source.uri; |
253 } | 246 } |
254 // Should not be able to encounter any other source types. | 247 // Should not be able to encounter any other source types. |
255 throw new StateError('Unable to resolve URI for ${source.runtimeType}'); | 248 throw new StateError('Unable to resolve URI for ${source.runtimeType}'); |
256 } | 249 } |
257 | 250 |
258 AssetId getSourceAssetId(Element element) { | 251 AssetId getSourceAssetId(Element element) { |
259 var source = element.source; | 252 var source = element.source; |
260 if (source is _AssetBasedSource) return source.assetId; | 253 if (source is _AssetBasedSource) return source.assetId; |
261 return null; | 254 return null; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
313 | 306 |
314 /// The file contents. | 307 /// The file contents. |
315 String _contents; | 308 String _contents; |
316 | 309 |
317 _AssetBasedSource(this.assetId, this._resolver); | 310 _AssetBasedSource(this.assetId, this._resolver); |
318 | 311 |
319 /// Update the dependencies of this source. This parses [contents] but avoids | 312 /// Update the dependencies of this source. This parses [contents] but avoids |
320 /// any analyzer resolution. | 313 /// any analyzer resolution. |
321 void updateDependencies(String contents) { | 314 void updateDependencies(String contents) { |
322 if (contents == _contents) return; | 315 if (contents == _contents) return; |
323 var unit = parseCompilationUnit(contents, suppressErrors: true); | 316 var unit = parseDirectives(contents, suppressErrors: true); |
324 _dependentAssets = unit.directives | 317 _dependentAssets = unit.directives |
325 .where((d) => (d is ImportDirective || d is PartDirective || | 318 .where((d) => (d is ImportDirective || d is PartDirective || |
326 d is ExportDirective)) | 319 d is ExportDirective)) |
327 .map((d) => _resolve(assetId, d.uri.stringValue, _logger, | 320 .map((d) => _resolve(assetId, d.uri.stringValue, _logger, |
328 _getSpan(d, contents))) | 321 _getSpan(d, contents))) |
329 .where((id) => id != null).toSet(); | 322 .where((id) => id != null).toSet(); |
330 } | 323 } |
331 | 324 |
332 /// Update the contents of this file with [contents]. | 325 /// Update the contents of this file with [contents]. |
333 /// | 326 /// |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
446 | 439 |
447 Source fromEncoding(UriKind kind, Uri uri) => | 440 Source fromEncoding(UriKind kind, Uri uri) => |
448 throw new UnsupportedError('fromEncoding is not supported'); | 441 throw new UnsupportedError('fromEncoding is not supported'); |
449 | 442 |
450 Uri restoreAbsolute(Source source) => | 443 Uri restoreAbsolute(Source source) => |
451 throw new UnsupportedError('restoreAbsolute is not supported'); | 444 throw new UnsupportedError('restoreAbsolute is not supported'); |
452 | 445 |
453 TransformLogger get logger => _resolver._currentTransform.logger; | 446 TransformLogger get logger => _resolver._currentTransform.logger; |
454 } | 447 } |
455 | 448 |
456 | |
457 /// Dart SDK which wraps all Dart sources to ensure they are tracked with Uris. | |
458 /// | |
459 /// Just a simple wrapper to make it easy to make sure that all sources we | |
460 /// encounter are either _AssetBasedSource or _DartSourceProxy. | |
461 class _DirectoryBasedDartSdkProxy extends DirectoryBasedDartSdk { | |
462 _DirectoryBasedDartSdkProxy(JavaFile sdkDirectory) : super(sdkDirectory); | |
463 | |
464 Source mapDartUri(String dartUri) => | |
465 _DartSourceProxy.wrap(super.mapDartUri(dartUri), Uri.parse(dartUri)); | |
466 } | |
467 | |
468 | |
469 /// Dart SDK resolver which wraps all Dart sources to ensure they are tracked | |
470 /// with URIs. | |
471 class DartUriResolverProxy implements DartUriResolver { | |
472 final DartUriResolver _proxy; | |
473 DartUriResolverProxy(DirectoryBasedDartSdk sdk) : | |
474 _proxy = new DartUriResolver(sdk); | |
475 | |
476 Source resolveAbsolute(Uri uri) => | |
477 _DartSourceProxy.wrap(_proxy.resolveAbsolute(uri), uri); | |
478 | |
479 DartSdk get dartSdk => _proxy.dartSdk; | |
480 | |
481 Source fromEncoding(UriKind kind, Uri uri) => | |
482 throw new UnsupportedError('fromEncoding is not supported'); | |
483 | |
484 Uri restoreAbsolute(Source source) => | |
485 throw new UnsupportedError('restoreAbsolute is not supported'); | |
486 } | |
487 | |
488 /// Source file for dart: sources which track the sources with dart: URIs. | |
489 /// | |
490 /// This is primarily to support [Resolver.getImportUri] for Dart SDK (dart:) | |
491 /// based libraries. | |
492 class _DartSourceProxy implements Source { | |
493 | |
494 /// Absolute URI which this source can be imported from | |
495 final Uri uri; | |
496 | |
497 /// Underlying source object. | |
498 final Source _proxy; | |
499 | |
500 _DartSourceProxy(this._proxy, this.uri); | |
501 | |
502 /// Ensures that [source] is a _DartSourceProxy. | |
503 static _DartSourceProxy wrap(Source source, Uri uri) { | |
504 if (source == null || source is _DartSourceProxy) return source; | |
505 return new _DartSourceProxy(source, uri); | |
506 } | |
507 | |
508 Source resolveRelative(Uri relativeUri) { | |
509 // Assume that the type can be accessed via this URI, since these | |
510 // should only be parts for dart core files. | |
511 return wrap(_proxy.resolveRelative(relativeUri), uri); | |
512 } | |
513 | |
514 bool exists() => _proxy.exists(); | |
515 | |
516 bool operator ==(Object other) => | |
517 (other is _DartSourceProxy && _proxy == other._proxy); | |
518 | |
519 int get hashCode => _proxy.hashCode; | |
520 | |
521 TimestampedData<String> get contents => _proxy.contents; | |
522 | |
523 String get encoding => _proxy.encoding; | |
524 | |
525 String get fullName => _proxy.fullName; | |
526 | |
527 int get modificationStamp => _proxy.modificationStamp; | |
528 | |
529 String get shortName => _proxy.shortName; | |
530 | |
531 UriKind get uriKind => _proxy.uriKind; | |
532 | |
533 bool get isInSystemLibrary => _proxy.isInSystemLibrary; | |
534 } | |
535 | |
536 /// Get an asset ID for a URL relative to another source asset. | 449 /// Get an asset ID for a URL relative to another source asset. |
537 AssetId _resolve(AssetId source, String url, TransformLogger logger, | 450 AssetId _resolve(AssetId source, String url, TransformLogger logger, |
538 Span span) { | 451 Span span) { |
539 if (url == null || url == '') return null; | 452 if (url == null || url == '') return null; |
540 var uri = Uri.parse(url); | 453 var uri = Uri.parse(url); |
541 | 454 |
542 // Workaround for dartbug.com/17156- pub transforms package: imports from | 455 // Workaround for dartbug.com/17156- pub transforms package: imports from |
543 // files of the transformers package to have absolute /packages/ URIs. | 456 // files of the transformers package to have absolute /packages/ URIs. |
544 if (uri.scheme == '' && path.isAbsolute(url) | 457 if (uri.scheme == '' && path.isAbsolute(url) |
545 && uri.pathSegments[0] == 'packages') { | 458 && uri.pathSegments[0] == 'packages') { |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
626 | 539 |
627 void apply(ChangeSet changeSet) { | 540 void apply(ChangeSet changeSet) { |
628 if (!source.updateContents(content)) return; | 541 if (!source.updateContents(content)) return; |
629 if (source._revision == 1 && source._contents != null) { | 542 if (source._revision == 1 && source._contents != null) { |
630 changeSet.addedSource(source); | 543 changeSet.addedSource(source); |
631 } else { | 544 } else { |
632 changeSet.changedSource(source); | 545 changeSet.changedSource(source); |
633 } | 546 } |
634 } | 547 } |
635 } | 548 } |
OLD | NEW |