OLD | NEW |
(Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 // This code was auto-generated, is not intended to be edited, and is subject to |
| 6 // significant change. Please see the README file for more information. |
| 7 |
| 8 library engine.source.io; |
| 9 |
| 10 import 'source.dart'; |
| 11 import 'java_core.dart'; |
| 12 import 'java_io.dart'; |
| 13 import 'utilities_general.dart'; |
| 14 import 'instrumentation.dart'; |
| 15 import 'engine.dart'; |
| 16 import 'java_engine.dart'; |
| 17 export 'source.dart'; |
| 18 |
| 19 /** |
| 20 * Instances of the class [DirectoryBasedSourceContainer] represent a source con
tainer that |
| 21 * contains all sources within a given directory. |
| 22 */ |
| 23 class DirectoryBasedSourceContainer implements SourceContainer { |
| 24 /** |
| 25 * Append the system file separator to the given path unless the path already
ends with a |
| 26 * separator. |
| 27 * |
| 28 * @param path the path to which the file separator is to be added |
| 29 * @return a path that ends with the system file separator |
| 30 */ |
| 31 static String _appendFileSeparator(String path) { |
| 32 if (path == null || path.length <= 0 || path.codeUnitAt(path.length - 1) ==
JavaFile.separatorChar) { |
| 33 return path; |
| 34 } |
| 35 return "${path}${JavaFile.separator}"; |
| 36 } |
| 37 |
| 38 /** |
| 39 * The container's path (not `null`). |
| 40 */ |
| 41 String _path; |
| 42 |
| 43 /** |
| 44 * Construct a container representing the specified directory and containing a
ny sources whose |
| 45 * [Source#getFullName] starts with the directory's path. This is a convenienc
e method, |
| 46 * fully equivalent to [DirectoryBasedSourceContainer#DirectoryBasedSourceCont
ainer] |
| 47 * . |
| 48 * |
| 49 * @param directory the directory (not `null`) |
| 50 */ |
| 51 DirectoryBasedSourceContainer.con1(JavaFile directory) : this.con2(directory.g
etPath()); |
| 52 |
| 53 /** |
| 54 * Construct a container representing the specified path and containing any so
urces whose |
| 55 * [Source#getFullName] starts with the specified path. |
| 56 * |
| 57 * @param path the path (not `null` and not empty) |
| 58 */ |
| 59 DirectoryBasedSourceContainer.con2(String path) { |
| 60 this._path = _appendFileSeparator(path); |
| 61 } |
| 62 |
| 63 @override |
| 64 bool contains(Source source) => source.fullName.startsWith(_path); |
| 65 |
| 66 @override |
| 67 bool operator ==(Object obj) => (obj is DirectoryBasedSourceContainer) && obj.
path == path; |
| 68 |
| 69 /** |
| 70 * Answer the receiver's path, used to determine if a source is contained in t
he receiver. |
| 71 * |
| 72 * @return the path (not `null`, not empty) |
| 73 */ |
| 74 String get path => _path; |
| 75 |
| 76 @override |
| 77 int get hashCode => _path.hashCode; |
| 78 |
| 79 @override |
| 80 String toString() => "SourceContainer[${_path}]"; |
| 81 } |
| 82 |
| 83 /** |
| 84 * Instances of the class `FileBasedSource` implement a source that represents a
file. |
| 85 */ |
| 86 class FileBasedSource implements Source { |
| 87 /** |
| 88 * The URI from which this source was originally derived. |
| 89 */ |
| 90 final Uri uri; |
| 91 |
| 92 /** |
| 93 * The file represented by this source. |
| 94 */ |
| 95 final JavaFile file; |
| 96 |
| 97 /** |
| 98 * The cached encoding for this source. |
| 99 */ |
| 100 String _encoding; |
| 101 |
| 102 /** |
| 103 * Initialize a newly created source object. |
| 104 * |
| 105 * @param file the file represented by this source |
| 106 */ |
| 107 FileBasedSource.con1(JavaFile file) : this.con2(file.toURI(), file); |
| 108 |
| 109 /** |
| 110 * Initialize a newly created source object. |
| 111 * |
| 112 * @param file the file represented by this source |
| 113 * @param uri the URI from which this source was originally derived |
| 114 */ |
| 115 FileBasedSource.con2(this.uri, this.file); |
| 116 |
| 117 @override |
| 118 bool operator ==(Object object) => object != null && object is FileBasedSource
&& file == object.file; |
| 119 |
| 120 @override |
| 121 bool exists() => file.isFile(); |
| 122 |
| 123 @override |
| 124 TimestampedData<String> get contents { |
| 125 TimeCounter_TimeCounterHandle handle = PerformanceStatistics.io.start(); |
| 126 try { |
| 127 return contentsFromFile; |
| 128 } finally { |
| 129 _reportIfSlowIO(handle.stop()); |
| 130 } |
| 131 } |
| 132 |
| 133 @override |
| 134 String get encoding { |
| 135 if (_encoding == null) { |
| 136 _encoding = uri.toString(); |
| 137 } |
| 138 return _encoding; |
| 139 } |
| 140 |
| 141 @override |
| 142 String get fullName => file.getAbsolutePath(); |
| 143 |
| 144 @override |
| 145 int get modificationStamp => file.lastModified(); |
| 146 |
| 147 @override |
| 148 String get shortName => file.getName(); |
| 149 |
| 150 @override |
| 151 UriKind get uriKind { |
| 152 String scheme = uri.scheme; |
| 153 if (scheme == PackageUriResolver.PACKAGE_SCHEME) { |
| 154 return UriKind.PACKAGE_URI; |
| 155 } else if (scheme == DartUriResolver.DART_SCHEME) { |
| 156 return UriKind.DART_URI; |
| 157 } else if (scheme == FileUriResolver.FILE_SCHEME) { |
| 158 return UriKind.FILE_URI; |
| 159 } |
| 160 return UriKind.FILE_URI; |
| 161 } |
| 162 |
| 163 @override |
| 164 int get hashCode => file.hashCode; |
| 165 |
| 166 @override |
| 167 bool get isInSystemLibrary => uri.scheme == DartUriResolver.DART_SCHEME; |
| 168 |
| 169 @override |
| 170 Uri resolveRelativeUri(Uri containedUri) { |
| 171 try { |
| 172 Uri baseUri = uri; |
| 173 bool isOpaque = uri.isAbsolute && !uri.path.startsWith('/'); |
| 174 if (isOpaque) { |
| 175 String scheme = uri.scheme; |
| 176 String part = uri.path; |
| 177 if (scheme == DartUriResolver.DART_SCHEME && part.indexOf('/') < 0) { |
| 178 part = "${part}/${part}.dart"; |
| 179 } |
| 180 baseUri = parseUriWithException("${scheme}:/${part}"); |
| 181 } |
| 182 Uri result = baseUri.resolveUri(containedUri); |
| 183 if (isOpaque) { |
| 184 result = parseUriWithException("${result.scheme}:${result.path.substring
(1)}"); |
| 185 } |
| 186 return result; |
| 187 } catch (exception, stackTrace) { |
| 188 throw new AnalysisException("Could not resolve URI (${containedUri}) relat
ive to source (${uri})", new CaughtException(exception, stackTrace)); |
| 189 } |
| 190 } |
| 191 |
| 192 @override |
| 193 String toString() { |
| 194 if (file == null) { |
| 195 return "<unknown source>"; |
| 196 } |
| 197 return file.getAbsolutePath(); |
| 198 } |
| 199 |
| 200 /** |
| 201 * Get the contents and timestamp of the underlying file. |
| 202 * |
| 203 * Clients should consider using the the method [AnalysisContext#getContents] |
| 204 * because contexts can have local overrides of the content of a source that t
he source is not |
| 205 * aware of. |
| 206 * |
| 207 * @return the contents of the source paired with the modification stamp of th
e source |
| 208 * @throws Exception if the contents of this source could not be accessed |
| 209 * @see #getContents() |
| 210 */ |
| 211 TimestampedData<String> get contentsFromFile { |
| 212 return new TimestampedData<String>(file.lastModified(), file.readAsStringSyn
c()); |
| 213 } |
| 214 |
| 215 /** |
| 216 * Record the time the IO took if it was slow |
| 217 */ |
| 218 void _reportIfSlowIO(int nanos) { |
| 219 //If slower than 10ms |
| 220 if (nanos > 10 * TimeCounter.NANOS_PER_MILLI) { |
| 221 InstrumentationBuilder builder = Instrumentation.builder2("SlowIO"); |
| 222 try { |
| 223 builder.data3("fileName", fullName); |
| 224 builder.metric2("IO-Time-Nanos", nanos); |
| 225 } finally { |
| 226 builder.log(); |
| 227 } |
| 228 } |
| 229 } |
| 230 } |
| 231 |
| 232 /** |
| 233 * Instances of the class `FileUriResolver` resolve `file` URI's. |
| 234 */ |
| 235 class FileUriResolver extends UriResolver { |
| 236 /** |
| 237 * The name of the `file` scheme. |
| 238 */ |
| 239 static String FILE_SCHEME = "file"; |
| 240 |
| 241 /** |
| 242 * Return `true` if the given URI is a `file` URI. |
| 243 * |
| 244 * @param uri the URI being tested |
| 245 * @return `true` if the given URI is a `file` URI |
| 246 */ |
| 247 static bool isFileUri(Uri uri) => uri.scheme == FILE_SCHEME; |
| 248 |
| 249 @override |
| 250 Source resolveAbsolute(Uri uri) { |
| 251 if (!isFileUri(uri)) { |
| 252 return null; |
| 253 } |
| 254 return new FileBasedSource.con2(uri, new JavaFile.fromUri(uri)); |
| 255 } |
| 256 } |
| 257 |
| 258 /** |
| 259 * Instances of interface `LocalSourcePredicate` are used to determine if the gi
ven |
| 260 * [Source] is "local" in some sense, so can be updated. |
| 261 */ |
| 262 abstract class LocalSourcePredicate { |
| 263 /** |
| 264 * Instance of [LocalSourcePredicate] that always returns `false`. |
| 265 */ |
| 266 static final LocalSourcePredicate FALSE = new LocalSourcePredicate_FALSE(); |
| 267 |
| 268 /** |
| 269 * Instance of [LocalSourcePredicate] that always returns `true`. |
| 270 */ |
| 271 static final LocalSourcePredicate TRUE = new LocalSourcePredicate_TRUE(); |
| 272 |
| 273 /** |
| 274 * Instance of [LocalSourcePredicate] that returns `true` for all [Source]s |
| 275 * except of SDK. |
| 276 */ |
| 277 static final LocalSourcePredicate NOT_SDK = new LocalSourcePredicate_NOT_SDK()
; |
| 278 |
| 279 /** |
| 280 * Determines if the given [Source] is local. |
| 281 * |
| 282 * @param source the [Source] to analyze |
| 283 * @return `true` if the given [Source] is local |
| 284 */ |
| 285 bool isLocal(Source source); |
| 286 } |
| 287 |
| 288 class LocalSourcePredicate_FALSE implements LocalSourcePredicate { |
| 289 @override |
| 290 bool isLocal(Source source) => false; |
| 291 } |
| 292 |
| 293 class LocalSourcePredicate_NOT_SDK implements LocalSourcePredicate { |
| 294 @override |
| 295 bool isLocal(Source source) => source.uriKind != UriKind.DART_URI; |
| 296 } |
| 297 |
| 298 class LocalSourcePredicate_TRUE implements LocalSourcePredicate { |
| 299 @override |
| 300 bool isLocal(Source source) => true; |
| 301 } |
| 302 |
| 303 /** |
| 304 * Instances of the class `PackageUriResolver` resolve `package` URI's in the co
ntext of |
| 305 * an application. |
| 306 * |
| 307 * For the purposes of sharing analysis, the path to each package under the "pac
kages" directory |
| 308 * should be canonicalized, but to preserve relative links within a package, the
remainder of the |
| 309 * path from the package directory to the leaf should not. |
| 310 */ |
| 311 class PackageUriResolver extends UriResolver { |
| 312 /** |
| 313 * The package directories that `package` URI's are assumed to be relative to. |
| 314 */ |
| 315 final List<JavaFile> _packagesDirectories; |
| 316 |
| 317 /** |
| 318 * The name of the `package` scheme. |
| 319 */ |
| 320 static String PACKAGE_SCHEME = "package"; |
| 321 |
| 322 /** |
| 323 * Log exceptions thrown with the message "Required key not available" only on
ce. |
| 324 */ |
| 325 static bool _CanLogRequiredKeyIoException = true; |
| 326 |
| 327 /** |
| 328 * Return `true` if the given URI is a `package` URI. |
| 329 * |
| 330 * @param uri the URI being tested |
| 331 * @return `true` if the given URI is a `package` URI |
| 332 */ |
| 333 static bool isPackageUri(Uri uri) => PACKAGE_SCHEME == uri.scheme; |
| 334 |
| 335 /** |
| 336 * Initialize a newly created resolver to resolve `package` URI's relative to
the given |
| 337 * package directories. |
| 338 * |
| 339 * @param packagesDirectories the package directories that `package` URI's are
assumed to be |
| 340 * relative to |
| 341 */ |
| 342 PackageUriResolver(this._packagesDirectories) { |
| 343 if (_packagesDirectories.length < 1) { |
| 344 throw new IllegalArgumentException("At least one package directory must be
provided"); |
| 345 } |
| 346 } |
| 347 |
| 348 @override |
| 349 Source resolveAbsolute(Uri uri) { |
| 350 if (!isPackageUri(uri)) { |
| 351 return null; |
| 352 } |
| 353 String path = uri.path; |
| 354 if (path == null) { |
| 355 path = uri.path; |
| 356 if (path == null) { |
| 357 return null; |
| 358 } |
| 359 } |
| 360 String pkgName; |
| 361 String relPath; |
| 362 int index = path.indexOf('/'); |
| 363 if (index == -1) { |
| 364 // No slash |
| 365 pkgName = path; |
| 366 relPath = ""; |
| 367 } else if (index == 0) { |
| 368 // Leading slash is invalid |
| 369 return null; |
| 370 } else { |
| 371 // <pkgName>/<relPath> |
| 372 pkgName = path.substring(0, index); |
| 373 relPath = path.substring(index + 1); |
| 374 } |
| 375 for (JavaFile packagesDirectory in _packagesDirectories) { |
| 376 JavaFile resolvedFile = new JavaFile.relative(packagesDirectory, path); |
| 377 if (resolvedFile.exists()) { |
| 378 JavaFile canonicalFile = getCanonicalFile(packagesDirectory, pkgName, re
lPath); |
| 379 if (_isSelfReference(packagesDirectory, canonicalFile)) { |
| 380 uri = canonicalFile.toURI(); |
| 381 } |
| 382 return new FileBasedSource.con2(uri, canonicalFile); |
| 383 } |
| 384 } |
| 385 return new FileBasedSource.con2(uri, getCanonicalFile(_packagesDirectories[0
], pkgName, relPath)); |
| 386 } |
| 387 |
| 388 @override |
| 389 Uri restoreAbsolute(Source source) { |
| 390 if (source is FileBasedSource) { |
| 391 String sourcePath = source.file.getPath(); |
| 392 for (JavaFile packagesDirectory in _packagesDirectories) { |
| 393 List<JavaFile> pkgFolders = packagesDirectory.listFiles(); |
| 394 if (pkgFolders != null) { |
| 395 for (JavaFile pkgFolder in pkgFolders) { |
| 396 try { |
| 397 String pkgCanonicalPath = pkgFolder.getCanonicalPath(); |
| 398 if (sourcePath.startsWith(pkgCanonicalPath)) { |
| 399 String relPath = sourcePath.substring(pkgCanonicalPath.length); |
| 400 return parseUriWithException("${PACKAGE_SCHEME}:${pkgFolder.getN
ame()}${relPath}"); |
| 401 } |
| 402 } catch (e) { |
| 403 } |
| 404 } |
| 405 } |
| 406 } |
| 407 } |
| 408 return null; |
| 409 } |
| 410 |
| 411 /** |
| 412 * Answer the canonical file for the specified package. |
| 413 * |
| 414 * @param packagesDirectory the "packages" directory (not `null`) |
| 415 * @param pkgName the package name (not `null`, not empty) |
| 416 * @param relPath the path relative to the package directory (not `null`, no l
eading slash, |
| 417 * but may be empty string) |
| 418 * @return the file (not `null`) |
| 419 */ |
| 420 JavaFile getCanonicalFile(JavaFile packagesDirectory, String pkgName, String r
elPath) { |
| 421 JavaFile pkgDir = new JavaFile.relative(packagesDirectory, pkgName); |
| 422 try { |
| 423 pkgDir = pkgDir.getCanonicalFile(); |
| 424 } on JavaIOException catch (e) { |
| 425 if (!e.toString().contains("Required key not available")) { |
| 426 AnalysisEngine.instance.logger.logError2("Canonical failed: ${pkgDir}",
e); |
| 427 } else if (_CanLogRequiredKeyIoException) { |
| 428 _CanLogRequiredKeyIoException = false; |
| 429 AnalysisEngine.instance.logger.logError2("Canonical failed: ${pkgDir}",
e); |
| 430 } |
| 431 } |
| 432 return new JavaFile.relative(pkgDir, relPath.replaceAll('/', new String.from
CharCode(JavaFile.separatorChar))); |
| 433 } |
| 434 |
| 435 /** |
| 436 * @return `true` if "file" was found in "packagesDir", and it is part of the
"lib" folder |
| 437 * of the application that contains in this "packagesDir". |
| 438 */ |
| 439 bool _isSelfReference(JavaFile packagesDir, JavaFile file) { |
| 440 JavaFile rootDir = packagesDir.getParentFile(); |
| 441 if (rootDir == null) { |
| 442 return false; |
| 443 } |
| 444 String rootPath = rootDir.getAbsolutePath(); |
| 445 String filePath = file.getAbsolutePath(); |
| 446 return filePath.startsWith("${rootPath}/lib"); |
| 447 } |
| 448 } |
| 449 |
| 450 /** |
| 451 * Instances of the class `RelativeFileUriResolver` resolve `file` URI's. |
| 452 */ |
| 453 class RelativeFileUriResolver extends UriResolver { |
| 454 /** |
| 455 * The name of the `file` scheme. |
| 456 */ |
| 457 static String FILE_SCHEME = "file"; |
| 458 |
| 459 /** |
| 460 * Return `true` if the given URI is a `file` URI. |
| 461 * |
| 462 * @param uri the URI being tested |
| 463 * @return `true` if the given URI is a `file` URI |
| 464 */ |
| 465 static bool isFileUri(Uri uri) => uri.scheme == FILE_SCHEME; |
| 466 |
| 467 /** |
| 468 * The directories for the relatvie URI's |
| 469 */ |
| 470 final List<JavaFile> _relativeDirectories; |
| 471 |
| 472 /** |
| 473 * The root directory for all the source trees |
| 474 */ |
| 475 final JavaFile _rootDirectory; |
| 476 |
| 477 /** |
| 478 * Initialize a newly created resolver to resolve `file` URI's relative to the
given root |
| 479 * directory. |
| 480 */ |
| 481 RelativeFileUriResolver(this._rootDirectory, this._relativeDirectories) : supe
r(); |
| 482 |
| 483 @override |
| 484 Source resolveAbsolute(Uri uri) { |
| 485 String rootPath = _rootDirectory.toURI().path; |
| 486 String uriPath = uri.path; |
| 487 if (uriPath != null && uriPath.startsWith(rootPath)) { |
| 488 String filePath = uri.path.substring(rootPath.length); |
| 489 for (JavaFile dir in _relativeDirectories) { |
| 490 JavaFile file = new JavaFile.relative(dir, filePath); |
| 491 if (file.exists()) { |
| 492 return new FileBasedSource.con2(uri, file); |
| 493 } |
| 494 } |
| 495 } |
| 496 return null; |
| 497 } |
| 498 } |
OLD | NEW |