Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 import 'dart:async'; | 5 import 'dart:async'; |
| 6 import 'dart:typed_data'; | 6 import 'dart:typed_data'; |
| 7 | 7 |
| 8 import 'package:crypto/crypto.dart'; | |
| 8 import 'package:front_end/file_system.dart'; | 9 import 'package:front_end/file_system.dart'; |
| 9 import 'package:front_end/src/dependency_walker.dart' as graph; | 10 import 'package:front_end/src/dependency_walker.dart' as graph; |
| 10 import 'package:front_end/src/fasta/parser/top_level_parser.dart'; | 11 import 'package:front_end/src/fasta/parser/top_level_parser.dart'; |
| 11 import 'package:front_end/src/fasta/scanner.dart'; | 12 import 'package:front_end/src/fasta/scanner.dart'; |
| 12 import 'package:front_end/src/fasta/source/directive_listener.dart'; | 13 import 'package:front_end/src/fasta/source/directive_listener.dart'; |
| 13 import 'package:front_end/src/fasta/translate_uri.dart'; | 14 import 'package:front_end/src/fasta/translate_uri.dart'; |
| 15 import 'package:kernel/target/vm.dart'; | |
| 14 | 16 |
| 15 /// Information about a file being compiled, explicitly or implicitly. | 17 /// Information about a file being compiled, explicitly or implicitly. |
| 16 /// | 18 /// |
| 17 /// It provides a consistent view on its properties. | 19 /// It provides a consistent view on its properties. |
| 18 /// | 20 /// |
| 19 /// The properties are not guaranteed to represent the most recent state | 21 /// The properties are not guaranteed to represent the most recent state |
| 20 /// of the file system. To update the file to the most recent state, [refresh] | 22 /// of the file system. To update the file to the most recent state, [refresh] |
| 21 /// should be called. | 23 /// should be called. |
| 22 class FileState { | 24 class FileState { |
| 23 final FileSystemState _fsState; | 25 final FileSystemState _fsState; |
| 24 | 26 |
| 27 /// The absolute URI of the file. | |
| 28 final Uri uri; | |
| 29 | |
| 25 /// The resolved URI of the file in the file system. | 30 /// The resolved URI of the file in the file system. |
| 26 final Uri fileUri; | 31 final Uri fileUri; |
| 27 | 32 |
| 28 bool _exists; | 33 bool _exists; |
| 29 List<int> _content; | 34 List<int> _content; |
| 35 List<int> _contentHash; | |
| 30 | 36 |
| 31 List<FileState> _importedLibraries; | 37 List<FileState> _importedLibraries; |
| 32 List<FileState> _exportedLibraries; | 38 List<FileState> _exportedLibraries; |
| 33 List<FileState> _partFiles; | 39 List<FileState> _partFiles; |
| 34 | 40 |
| 41 Set<FileState> _directReferencedFiles = new Set<FileState>(); | |
| 35 List<FileState> _directReferencedLibraries = <FileState>[]; | 42 List<FileState> _directReferencedLibraries = <FileState>[]; |
| 36 | 43 |
| 37 FileState._(this._fsState, this.fileUri); | 44 FileState._(this._fsState, this.uri, this.fileUri); |
| 38 | 45 |
| 39 /// The content of the file. | 46 /// The content of the file. |
| 40 List<int> get content => _content; | 47 List<int> get content => _content; |
| 41 | 48 |
| 49 /** | |
|
Siggi Cherem (dart-lang)
2017/05/16 21:37:01
nit: let's only use "///" for dartdocs
scheglov
2017/05/16 22:03:38
Fixed.
I try to follow this style.
| |
| 50 * The MD5 hash of the [content]. | |
| 51 */ | |
| 52 List<int> get contentHash => _contentHash; | |
| 53 | |
| 42 /// Libraries that this library file directly imports or exports. | 54 /// Libraries that this library file directly imports or exports. |
| 43 List<FileState> get directReferencedLibraries => _directReferencedLibraries; | 55 List<FileState> get directReferencedLibraries => _directReferencedLibraries; |
| 44 | 56 |
| 45 /// Whether the file exists. | 57 /// Whether the file exists. |
| 46 bool get exists => _exists; | 58 bool get exists => _exists; |
| 47 | 59 |
| 48 /// The list of the libraries exported by this library. | 60 /// The list of the libraries exported by this library. |
| 49 List<FileState> get exportedLibraries => _exportedLibraries; | 61 List<FileState> get exportedLibraries => _exportedLibraries; |
| 50 | 62 |
| 51 @override | 63 @override |
| 52 int get hashCode => fileUri.hashCode; | 64 int get hashCode => uri.hashCode; |
| 53 | 65 |
| 54 /// The list of the libraries imported by this library. | 66 /// The list of the libraries imported by this library. |
| 55 List<FileState> get importedLibraries => _importedLibraries; | 67 List<FileState> get importedLibraries => _importedLibraries; |
| 56 | 68 |
| 57 /// The list of files this library file references as parts. | 69 /// The list of files this library file references as parts. |
| 58 List<FileState> get partFiles => _partFiles; | 70 List<FileState> get partFiles => _partFiles; |
| 59 | 71 |
| 60 /// Return topologically sorted cycles of dependencies for this library. | 72 /// Return topologically sorted cycles of dependencies for this library. |
| 61 List<LibraryCycle> get topologicalOrder { | 73 List<LibraryCycle> get topologicalOrder { |
| 62 var libraryWalker = new _LibraryWalker(); | 74 var libraryWalker = new _LibraryWalker(); |
| 63 libraryWalker.walk(libraryWalker.getNode(this)); | 75 libraryWalker.walk(libraryWalker.getNode(this)); |
| 64 return libraryWalker.topologicallySortedCycles; | 76 return libraryWalker.topologicallySortedCycles; |
| 65 } | 77 } |
| 66 | 78 |
| 79 /// Return the set of transitive files - the file itself and all of the | |
| 80 /// directly or indirectly referenced files. | |
| 81 Set<FileState> get transitiveFiles { | |
| 82 // TODO(scheglov) add caching. | |
| 83 var transitiveFiles = new Set<FileState>(); | |
| 84 | |
| 85 void appendReferenced(FileState file) { | |
| 86 if (transitiveFiles.add(file)) { | |
| 87 file._directReferencedFiles.forEach(appendReferenced); | |
| 88 } | |
| 89 } | |
| 90 | |
| 91 appendReferenced(this); | |
| 92 return transitiveFiles; | |
| 93 } | |
| 94 | |
| 67 @override | 95 @override |
| 68 bool operator ==(Object other) { | 96 bool operator ==(Object other) { |
| 69 return other is FileState && other.fileUri == fileUri; | 97 return other is FileState && other.uri == uri; |
| 70 } | 98 } |
| 71 | 99 |
| 72 /// Read the file content and ensure that all of the file properties are | 100 /// Read the file content and ensure that all of the file properties are |
| 73 /// consistent with the read content, including all its dependencies. | 101 /// consistent with the read content, including all its dependencies. |
| 74 Future<Null> refresh() async { | 102 Future<Null> refresh() async { |
| 75 // Read the content. | 103 // Read the content. |
| 76 try { | 104 try { |
| 77 FileSystemEntity entry = _fsState.fileSystem.entityForUri(fileUri); | 105 FileSystemEntity entry = _fsState.fileSystem.entityForUri(fileUri); |
| 78 _content = await entry.readAsBytes(); | 106 _content = await entry.readAsBytes(); |
| 79 _exists = true; | 107 _exists = true; |
| 80 } catch (_) { | 108 } catch (_) { |
| 81 _content = new Uint8List(0); | 109 _content = new Uint8List(0); |
| 82 _exists = false; | 110 _exists = false; |
| 83 } | 111 } |
| 84 | 112 |
| 113 // Compute the content hash. | |
| 114 _contentHash = md5.convert(_content).bytes; | |
| 115 | |
| 85 // Parse directives. | 116 // Parse directives. |
| 86 ScannerResult scannerResults = _scan(); | 117 ScannerResult scannerResults = _scan(); |
| 87 var listener = new DirectiveListener(); | 118 var listener = new DirectiveListener(); |
| 88 new TopLevelParser(listener).parseUnit(scannerResults.tokens); | 119 new TopLevelParser(listener).parseUnit(scannerResults.tokens); |
| 89 | 120 |
| 90 // Build the graph. | 121 // Build the graph. |
| 91 _importedLibraries = <FileState>[]; | 122 _importedLibraries = <FileState>[]; |
| 92 _exportedLibraries = <FileState>[]; | 123 _exportedLibraries = <FileState>[]; |
| 93 _partFiles = <FileState>[]; | 124 _partFiles = <FileState>[]; |
| 94 await _addFileForRelativeUri(_importedLibraries, 'dart:core'); | 125 await _addFileForRelativeUri(_importedLibraries, 'dart:core'); |
| 95 for (String uri in listener.imports) { | 126 for (String uri in listener.imports) { |
| 96 await _addFileForRelativeUri(_importedLibraries, uri); | 127 await _addFileForRelativeUri(_importedLibraries, uri); |
| 97 } | 128 } |
| 129 await _addVmTargetImportsForCore(); | |
| 98 for (String uri in listener.exports) { | 130 for (String uri in listener.exports) { |
| 99 await _addFileForRelativeUri(_exportedLibraries, uri); | 131 await _addFileForRelativeUri(_exportedLibraries, uri); |
| 100 } | 132 } |
| 101 for (String uri in listener.parts) { | 133 for (String uri in listener.parts) { |
| 102 await _addFileForRelativeUri(_partFiles, uri); | 134 await _addFileForRelativeUri(_partFiles, uri); |
| 103 } | 135 } |
| 104 | 136 |
| 105 // Compute referenced libraries. | 137 // Compute referenced files. |
| 138 _directReferencedFiles = new Set<FileState>() | |
| 139 ..addAll(_importedLibraries) | |
| 140 ..addAll(_exportedLibraries) | |
| 141 ..addAll(_partFiles); | |
| 106 _directReferencedLibraries = (new Set<FileState>() | 142 _directReferencedLibraries = (new Set<FileState>() |
| 107 ..addAll(_importedLibraries) | 143 ..addAll(_importedLibraries) |
| 108 ..addAll(_exportedLibraries)) | 144 ..addAll(_exportedLibraries)) |
| 109 .toList(); | 145 .toList(); |
| 110 } | 146 } |
| 111 | 147 |
| 112 @override | 148 @override |
| 113 String toString() { | 149 String toString() { |
| 114 if (fileUri.scheme == 'file') return fileUri.path; | 150 if (fileUri.scheme == 'file') return fileUri.path; |
| 115 return fileUri.toString(); | 151 return fileUri.toString(); |
| 116 } | 152 } |
| 117 | 153 |
| 118 /// Add the [FileState] for the given [relativeUri] to the [files]. | 154 /// Add the [FileState] for the given [relativeUri] to the [files]. |
| 119 /// Do nothing if the URI cannot be parsed, cannot correspond any file, etc. | 155 /// Do nothing if the URI cannot be parsed, cannot correspond any file, etc. |
| 120 Future<Null> _addFileForRelativeUri( | 156 Future<Null> _addFileForRelativeUri( |
| 121 List<FileState> files, String relativeUri) async { | 157 List<FileState> files, String relativeUri) async { |
| 122 if (relativeUri.isEmpty) return; | 158 if (relativeUri.isEmpty) return; |
| 123 | 159 |
| 124 // Resolve the relative URI into absolute. | 160 // Resolve the relative URI into absolute. |
| 125 // The result is either: | 161 // The result is either: |
| 126 // 1) The absolute file URI. | 162 // 1) The absolute file URI. |
| 127 // 2) The absolute non-file URI, e.g. `package:foo/foo.dart`. | 163 // 2) The absolute non-file URI, e.g. `package:foo/foo.dart`. |
| 128 Uri absoluteUri; | 164 Uri absoluteUri; |
| 129 try { | 165 try { |
| 130 absoluteUri = fileUri.resolve(relativeUri); | 166 absoluteUri = fileUri.resolve(relativeUri); |
| 131 } on FormatException { | 167 } on FormatException { |
| 132 return; | 168 return; |
| 133 } | 169 } |
| 134 | 170 |
| 135 // Resolve the absolute URI into the absolute file URI. | 171 FileState file = await _fsState.getFile(absoluteUri); |
| 136 Uri resolvedUri; | 172 if (file == null) return; |
| 137 if (absoluteUri.isScheme('file')) { | 173 files.add(file); |
| 138 resolvedUri = absoluteUri; | 174 } |
| 139 } else { | 175 |
| 140 resolvedUri = _fsState.uriTranslator.translate(absoluteUri); | 176 /// Fasta unconditionally loads all VM libraries. In order to be able to |
| 141 if (resolvedUri == null) return; | 177 /// serve them using the file system view, pretend that all of them were |
| 178 /// imported into `dart:core`. | |
| 179 /// TODO(scheglov) Ask VM people whether all these libraries are required. | |
| 180 Future<Null> _addVmTargetImportsForCore() async { | |
| 181 if (uri.toString() != 'dart:core') return; | |
| 182 for (String uri in new VmTarget(null).extraRequiredLibraries) { | |
| 183 await _addFileForRelativeUri(_importedLibraries, uri); | |
| 142 } | 184 } |
| 143 | |
| 144 FileState file = await _fsState.getFile(resolvedUri); | |
| 145 files.add(file); | |
| 146 } | 185 } |
| 147 | 186 |
| 148 /// Scan the content of the file. | 187 /// Scan the content of the file. |
| 149 ScannerResult _scan() { | 188 ScannerResult _scan() { |
| 150 var zeroTerminatedBytes = new Uint8List(_content.length + 1); | 189 var zeroTerminatedBytes = new Uint8List(_content.length + 1); |
| 151 zeroTerminatedBytes.setRange(0, _content.length, _content); | 190 zeroTerminatedBytes.setRange(0, _content.length, _content); |
| 152 return scan(zeroTerminatedBytes); | 191 return scan(zeroTerminatedBytes); |
| 153 } | 192 } |
| 154 } | 193 } |
| 155 | 194 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 166 FileSystemState(this.fileSystem, this.uriTranslator); | 205 FileSystemState(this.fileSystem, this.uriTranslator); |
| 167 | 206 |
| 168 /// Return the [FileSystem] that is backed by this [FileSystemState]. The | 207 /// Return the [FileSystem] that is backed by this [FileSystemState]. The |
| 169 /// files in this [FileSystem] always have the same content as the | 208 /// files in this [FileSystem] always have the same content as the |
| 170 /// corresponding [FileState]s, thus avoiding race conditions when a file | 209 /// corresponding [FileState]s, thus avoiding race conditions when a file |
| 171 /// is updated on the actual file system. | 210 /// is updated on the actual file system. |
| 172 FileSystem get fileSystemView { | 211 FileSystem get fileSystemView { |
| 173 return _fileSystemView ??= new _FileSystemView(this); | 212 return _fileSystemView ??= new _FileSystemView(this); |
| 174 } | 213 } |
| 175 | 214 |
| 176 /// Return the [FileState] for the given resolved file [fileUri]. | 215 /// Return the [FileState] for the given [absoluteUri], or `null` if the |
| 216 /// [absoluteUri] cannot be resolved into a file URI. | |
| 217 /// | |
| 177 /// The returned file has the last known state since it was last refreshed. | 218 /// The returned file has the last known state since it was last refreshed. |
| 178 Future<FileState> getFile(Uri fileUri) async { | 219 Future<FileState> getFile(Uri absoluteUri) async { |
| 179 FileState file = _fileUriToFile[fileUri]; | 220 // Resolve the absolute URI into the absolute file URI. |
| 221 Uri fileUri; | |
| 222 if (absoluteUri.isScheme('file')) { | |
| 223 fileUri = absoluteUri; | |
| 224 } else { | |
| 225 fileUri = uriTranslator.translate(absoluteUri); | |
| 226 if (fileUri == null) return null; | |
| 227 } | |
| 228 | |
| 229 FileState file = _fileUriToFile[absoluteUri]; | |
| 180 if (file == null) { | 230 if (file == null) { |
| 181 file = new FileState._(this, fileUri); | 231 file = new FileState._(this, absoluteUri, fileUri); |
| 232 _fileUriToFile[absoluteUri] = file; | |
| 182 _fileUriToFile[fileUri] = file; | 233 _fileUriToFile[fileUri] = file; |
| 183 | 234 |
| 184 // Build the sub-graph of the file. | 235 // Build the sub-graph of the file. |
| 185 await file.refresh(); | 236 await file.refresh(); |
| 186 } | 237 } |
| 187 return file; | 238 return file; |
| 188 } | 239 } |
| 189 } | 240 } |
| 190 | 241 |
| 191 /// List of libraries that reference each other, so form a cycle. | 242 /// List of libraries that reference each other, so form a cycle. |
| 192 class LibraryCycle { | 243 class LibraryCycle { |
| 193 final List<FileState> libraries = <FileState>[]; | 244 final List<FileState> libraries = <FileState>[]; |
| 194 | 245 |
| 246 bool get _isForVm { | |
| 247 return libraries.any((l) => l.uri.toString().endsWith('dart:_vmservice')); | |
| 248 } | |
| 249 | |
| 195 @override | 250 @override |
| 196 String toString() => '[' + libraries.join(', ') + ']'; | 251 String toString() { |
| 252 if (_isForVm) { | |
| 253 return '[core + vm]'; | |
| 254 } | |
| 255 return '[' + libraries.join(', ') + ']'; | |
| 256 } | |
| 197 } | 257 } |
| 198 | 258 |
| 199 /// [FileSystemState] based implementation of [FileSystem]. | 259 /// [FileSystemState] based implementation of [FileSystem]. |
| 200 /// It provides a consistent view on the known file system state. | 260 /// It provides a consistent view on the known file system state. |
| 201 class _FileSystemView implements FileSystem { | 261 class _FileSystemView implements FileSystem { |
| 202 final FileSystemState fsState; | 262 final FileSystemState fsState; |
| 203 | 263 |
| 204 _FileSystemView(this.fsState); | 264 _FileSystemView(this.fsState); |
| 205 | 265 |
| 206 @override | 266 @override |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 279 node.isEvaluated = true; | 339 node.isEvaluated = true; |
| 280 cycle.libraries.add(node.file); | 340 cycle.libraries.add(node.file); |
| 281 } | 341 } |
| 282 topologicallySortedCycles.add(cycle); | 342 topologicallySortedCycles.add(cycle); |
| 283 } | 343 } |
| 284 | 344 |
| 285 _LibraryNode getNode(FileState file) { | 345 _LibraryNode getNode(FileState file) { |
| 286 return nodesOfFiles.putIfAbsent(file, () => new _LibraryNode(this, file)); | 346 return nodesOfFiles.putIfAbsent(file, () => new _LibraryNode(this, file)); |
| 287 } | 347 } |
| 288 } | 348 } |
| OLD | NEW |