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