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 |