| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 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. |
| 4 |
| 5 library analyzer.src.context.source; |
| 6 |
| 7 import 'dart:collection'; |
| 8 |
| 9 import 'package:analyzer/exception/exception.dart'; |
| 10 import 'package:analyzer/file_system/file_system.dart'; |
| 11 import 'package:analyzer/file_system/physical_file_system.dart'; |
| 12 import 'package:analyzer/source/package_map_resolver.dart'; |
| 13 import 'package:analyzer/src/generated/engine.dart'; |
| 14 import 'package:analyzer/src/generated/sdk.dart'; |
| 15 import 'package:analyzer/src/generated/source.dart'; |
| 16 import 'package:analyzer/src/generated/utilities_dart.dart' as utils; |
| 17 import 'package:analyzer/src/util/fast_uri.dart'; |
| 18 import 'package:package_config/packages.dart'; |
| 19 |
| 20 /** |
| 21 * Instances of the class `SourceFactory` resolve possibly relative URI's |
| 22 * against an existing [Source]. |
| 23 */ |
| 24 class SourceFactoryImpl implements SourceFactory { |
| 25 @override |
| 26 AnalysisContext context; |
| 27 |
| 28 /** |
| 29 * URI processor used to find mappings for `package:` URIs found in a |
| 30 * `.packages` config file. |
| 31 */ |
| 32 final Packages _packages; |
| 33 |
| 34 /** |
| 35 * Resource provider used in working with package maps. |
| 36 */ |
| 37 final ResourceProvider _resourceProvider; |
| 38 |
| 39 /** |
| 40 * The resolvers used to resolve absolute URI's. |
| 41 */ |
| 42 final List<UriResolver> resolvers; |
| 43 |
| 44 /** |
| 45 * The predicate to determine is [Source] is local. |
| 46 */ |
| 47 LocalSourcePredicate _localSourcePredicate = LocalSourcePredicate.NOT_SDK; |
| 48 |
| 49 /** |
| 50 * Cache of mapping of absolute [Uri]s to [Source]s. |
| 51 */ |
| 52 final HashMap<Uri, Source> _absoluteUriToSourceCache = |
| 53 new HashMap<Uri, Source>(); |
| 54 |
| 55 /** |
| 56 * Initialize a newly created source factory with the given absolute URI |
| 57 * [resolvers] and optional [_packages] resolution helper. |
| 58 */ |
| 59 SourceFactoryImpl(this.resolvers, |
| 60 [this._packages, ResourceProvider resourceProvider]) |
| 61 : _resourceProvider = |
| 62 resourceProvider ?? PhysicalResourceProvider.INSTANCE; |
| 63 |
| 64 @override |
| 65 DartSdk get dartSdk { |
| 66 List<UriResolver> resolvers = this.resolvers; |
| 67 int length = resolvers.length; |
| 68 for (int i = 0; i < length; i++) { |
| 69 UriResolver resolver = resolvers[i]; |
| 70 if (resolver is DartUriResolver) { |
| 71 DartUriResolver dartUriResolver = resolver; |
| 72 return dartUriResolver.dartSdk; |
| 73 } |
| 74 } |
| 75 return null; |
| 76 } |
| 77 |
| 78 @override |
| 79 void set localSourcePredicate(LocalSourcePredicate localSourcePredicate) { |
| 80 this._localSourcePredicate = localSourcePredicate; |
| 81 } |
| 82 |
| 83 @override |
| 84 Map<String, List<Folder>> get packageMap { |
| 85 // Start by looking in .packages. |
| 86 if (_packages != null) { |
| 87 Map<String, List<Folder>> packageMap = <String, List<Folder>>{}; |
| 88 _packages.asMap().forEach((String name, Uri uri) { |
| 89 if (uri.scheme == 'file' || uri.scheme == '' /* unspecified */) { |
| 90 packageMap[name] = <Folder>[ |
| 91 _resourceProvider.getFolder(uri.toFilePath()) |
| 92 ]; |
| 93 } |
| 94 }); |
| 95 return packageMap; |
| 96 } |
| 97 |
| 98 // Default to the PackageMapUriResolver. |
| 99 PackageMapUriResolver resolver = resolvers |
| 100 .firstWhere((r) => r is PackageMapUriResolver, orElse: () => null); |
| 101 return resolver?.packageMap; |
| 102 } |
| 103 |
| 104 @override |
| 105 SourceFactory clone() { |
| 106 SourceFactory factory = |
| 107 new SourceFactory(resolvers, _packages, _resourceProvider); |
| 108 factory.localSourcePredicate = _localSourcePredicate; |
| 109 return factory; |
| 110 } |
| 111 |
| 112 @override |
| 113 Source forUri(String absoluteUri) { |
| 114 try { |
| 115 Uri uri = FastUri.parse(absoluteUri); |
| 116 if (uri.isAbsolute) { |
| 117 return _internalResolveUri(null, uri); |
| 118 } |
| 119 } catch (exception, stackTrace) { |
| 120 AnalysisEngine.instance.logger.logError( |
| 121 "Could not resolve URI: $absoluteUri", |
| 122 new CaughtException(exception, stackTrace)); |
| 123 } |
| 124 return null; |
| 125 } |
| 126 |
| 127 @override |
| 128 Source forUri2(Uri absoluteUri) { |
| 129 if (absoluteUri.isAbsolute) { |
| 130 try { |
| 131 return _internalResolveUri(null, absoluteUri); |
| 132 } on AnalysisException catch (exception, stackTrace) { |
| 133 AnalysisEngine.instance.logger.logError( |
| 134 "Could not resolve URI: $absoluteUri", |
| 135 new CaughtException(exception, stackTrace)); |
| 136 } |
| 137 } |
| 138 return null; |
| 139 } |
| 140 |
| 141 @override |
| 142 Source fromEncoding(String encoding) { |
| 143 Source source = forUri(encoding); |
| 144 if (source == null) { |
| 145 throw new ArgumentError("Invalid source encoding: '$encoding'"); |
| 146 } |
| 147 return source; |
| 148 } |
| 149 |
| 150 @override |
| 151 bool isLocalSource(Source source) => _localSourcePredicate.isLocal(source); |
| 152 |
| 153 @override |
| 154 Source resolveUri(Source containingSource, String containedUri) { |
| 155 if (containedUri == null || containedUri.isEmpty) { |
| 156 return null; |
| 157 } |
| 158 try { |
| 159 // Force the creation of an escaped URI to deal with spaces, etc. |
| 160 return _internalResolveUri(containingSource, FastUri.parse(containedUri)); |
| 161 } on FormatException { |
| 162 return null; |
| 163 } catch (exception, stackTrace) { |
| 164 String containingFullName = |
| 165 containingSource != null ? containingSource.fullName : '<null>'; |
| 166 AnalysisEngine.instance.logger.logInformation( |
| 167 "Could not resolve URI ($containedUri) " |
| 168 "relative to source ($containingFullName)", |
| 169 new CaughtException(exception, stackTrace)); |
| 170 return null; |
| 171 } |
| 172 } |
| 173 |
| 174 @override |
| 175 Uri restoreUri(Source source) { |
| 176 // First see if a resolver can restore the URI. |
| 177 for (UriResolver resolver in resolvers) { |
| 178 Uri uri = resolver.restoreAbsolute(source); |
| 179 if (uri != null) { |
| 180 // Now see if there's a package mapping. |
| 181 Uri packageMappedUri = _getPackageMapping(uri); |
| 182 if (packageMappedUri != null) { |
| 183 return packageMappedUri; |
| 184 } |
| 185 // Fall back to the resolver's computed URI. |
| 186 return uri; |
| 187 } |
| 188 } |
| 189 |
| 190 return null; |
| 191 } |
| 192 |
| 193 Uri _getPackageMapping(Uri sourceUri) { |
| 194 if (_packages == null) { |
| 195 return null; |
| 196 } |
| 197 if (sourceUri.scheme != 'file') { |
| 198 //TODO(pquitslund): verify this works for non-file URIs. |
| 199 return null; |
| 200 } |
| 201 |
| 202 Uri packageUri; |
| 203 _packages.asMap().forEach((String name, Uri uri) { |
| 204 if (packageUri == null) { |
| 205 if (utils.startsWith(sourceUri, uri)) { |
| 206 packageUri = Uri.parse( |
| 207 'package:$name/${sourceUri.path.substring(uri.path.length)}'); |
| 208 } |
| 209 } |
| 210 }); |
| 211 return packageUri; |
| 212 } |
| 213 |
| 214 /** |
| 215 * Return a source object representing the URI that results from resolving |
| 216 * the given (possibly relative) contained URI against the URI associated |
| 217 * with an existing source object, or `null` if the URI could not be resolved. |
| 218 * |
| 219 * @param containingSource the source containing the given URI |
| 220 * @param containedUri the (possibly relative) URI to be resolved against the |
| 221 * containing source |
| 222 * @return the source representing the contained URI |
| 223 * @throws AnalysisException if either the contained URI is invalid or if it |
| 224 * cannot be resolved against the source object's URI |
| 225 */ |
| 226 Source _internalResolveUri(Source containingSource, Uri containedUri) { |
| 227 if (!containedUri.isAbsolute) { |
| 228 if (containingSource == null) { |
| 229 throw new AnalysisException( |
| 230 "Cannot resolve a relative URI without a containing source: " |
| 231 "$containedUri"); |
| 232 } |
| 233 containedUri = |
| 234 utils.resolveRelativeUri(containingSource.uri, containedUri); |
| 235 } |
| 236 |
| 237 Uri actualUri = containedUri; |
| 238 |
| 239 // Check .packages and update target and actual URIs as appropriate. |
| 240 if (_packages != null && containedUri.scheme == 'package') { |
| 241 Uri packageUri = null; |
| 242 try { |
| 243 packageUri = |
| 244 _packages.resolve(containedUri, notFound: (Uri packageUri) => null); |
| 245 } on ArgumentError { |
| 246 // Fall through to try resolvers. |
| 247 } |
| 248 |
| 249 if (packageUri != null) { |
| 250 // Ensure scheme is set. |
| 251 if (packageUri.scheme == '') { |
| 252 packageUri = packageUri.replace(scheme: 'file'); |
| 253 } |
| 254 containedUri = packageUri; |
| 255 } |
| 256 } |
| 257 |
| 258 return _absoluteUriToSourceCache.putIfAbsent(containedUri, () { |
| 259 for (UriResolver resolver in resolvers) { |
| 260 Source result = resolver.resolveAbsolute(containedUri, actualUri); |
| 261 if (result != null) { |
| 262 return result; |
| 263 } |
| 264 } |
| 265 return null; |
| 266 }); |
| 267 } |
| 268 } |
| OLD | NEW |