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:front_end/file_system.dart'; | 8 import 'package:front_end/file_system.dart'; |
| 9 import 'package:front_end/src/dependency_walker.dart' as graph; | |
| 9 import 'package:front_end/src/fasta/parser/top_level_parser.dart'; | 10 import 'package:front_end/src/fasta/parser/top_level_parser.dart'; |
| 10 import 'package:front_end/src/fasta/scanner.dart'; | 11 import 'package:front_end/src/fasta/scanner.dart'; |
| 11 import 'package:front_end/src/fasta/source/directive_listener.dart'; | 12 import 'package:front_end/src/fasta/source/directive_listener.dart'; |
| 12 import 'package:front_end/src/fasta/translate_uri.dart'; | 13 import 'package:front_end/src/fasta/translate_uri.dart'; |
| 13 | 14 |
| 14 /// Information about a file being compiled, explicitly or implicitly. | 15 /// Information about a file being compiled, explicitly or implicitly. |
| 15 /// | 16 /// |
| 16 /// It provides a consistent view on its properties. | 17 /// It provides a consistent view on its properties. |
| 17 /// | 18 /// |
| 18 /// The properties are not guaranteed to represent the most recent state | 19 /// The properties are not guaranteed to represent the most recent state |
| 19 /// of the file system. To update the file to the most recent state, [refresh] | 20 /// of the file system. To update the file to the most recent state, [refresh] |
| 20 /// should be called. | 21 /// should be called. |
| 21 class FileState { | 22 class FileState { |
| 22 final FileSystemState _fsState; | 23 final FileSystemState _fsState; |
| 23 | 24 |
| 24 /// The resolved URI of the file in the file system. | 25 /// The resolved URI of the file in the file system. |
| 25 final Uri fileUri; | 26 final Uri fileUri; |
| 26 | 27 |
| 27 bool _exists; | 28 bool _exists; |
| 28 List<int> _content; | 29 List<int> _content; |
| 29 | 30 |
| 30 List<FileState> _importedFiles; | 31 List<FileState> _importedFiles; |
| 31 List<FileState> _exportedFiles; | 32 List<FileState> _exportedFiles; |
| 32 List<FileState> _partFiles; | 33 List<FileState> _partFiles; |
| 33 | 34 |
| 34 Set<FileState> _directReferencedFiles = new Set<FileState>(); | 35 List<FileState> _directReferencedLibraries = <FileState>[]; |
| 35 | 36 |
| 36 FileState._(this._fsState, this.fileUri); | 37 FileState._(this._fsState, this.fileUri); |
| 37 | 38 |
| 38 /// The content of the file. | 39 /// The content of the file. |
| 39 List<int> get content => _content; | 40 List<int> get content => _content; |
| 40 | 41 |
| 42 /// Libraries that this library file directly imports or exports. | |
| 43 List<FileState> get directReferencedLibraries => _directReferencedLibraries; | |
| 44 | |
| 41 /// Whether the file exists. | 45 /// Whether the file exists. |
| 42 bool get exists => _exists; | 46 bool get exists => _exists; |
| 43 | 47 |
| 48 /// The list of files this file exports. | |
|
Paul Berry
2017/05/12 14:30:43
Sould we rename this to exportedLibraries?
scheglov
2017/05/12 15:40:58
Done.
| |
| 49 List<FileState> get exportedFiles => _exportedFiles; | |
| 50 | |
| 44 @override | 51 @override |
| 45 int get hashCode => fileUri.hashCode; | 52 int get hashCode => fileUri.hashCode; |
| 46 | 53 |
| 47 /// Return the set of transitive files - the file itself and all of the | 54 /// The list of files this file imports. |
|
Paul Berry
2017/05/12 14:30:43
Similar question here
scheglov
2017/05/12 15:40:58
Done.
| |
| 48 /// directly or indirectly referenced files. | 55 List<FileState> get importedFiles => _importedFiles; |
| 49 Set<FileState> get transitiveFiles { | |
| 50 // TODO(scheglov) add caching. | |
| 51 var transitiveFiles = new Set<FileState>(); | |
| 52 | 56 |
| 53 void appendReferenced(FileState file) { | 57 /// The list of files this library file references as parts. |
| 54 if (transitiveFiles.add(file)) { | 58 List<FileState> get partFiles => _partFiles; |
| 55 file._directReferencedFiles.forEach(appendReferenced); | |
| 56 } | |
| 57 } | |
| 58 | 59 |
| 59 appendReferenced(this); | 60 /// Return topologically sorted cycles of dependencies for this library. |
| 60 return transitiveFiles; | 61 List<LibraryCycle> get topologicalOrder { |
| 62 var libraryWalker = new _LibraryWalker(); | |
| 63 libraryWalker.walk(libraryWalker.getNode(this)); | |
| 64 return libraryWalker.topologicallySortedCycles; | |
| 61 } | 65 } |
| 62 | 66 |
| 63 @override | 67 @override |
| 64 bool operator ==(Object other) { | 68 bool operator ==(Object other) { |
| 65 return other is FileState && other.fileUri == fileUri; | 69 return other is FileState && other.fileUri == fileUri; |
| 66 } | 70 } |
| 67 | 71 |
| 68 /// Read the file content and ensure that all of the file properties are | 72 /// Read the file content and ensure that all of the file properties are |
| 69 /// consistent with the read content, including all its dependencies. | 73 /// consistent with the read content, including all its dependencies. |
| 70 Future<Null> refresh() async { | 74 Future<Null> refresh() async { |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 91 for (String uri in listener.imports) { | 95 for (String uri in listener.imports) { |
| 92 await _addFileForRelativeUri(_importedFiles, uri); | 96 await _addFileForRelativeUri(_importedFiles, uri); |
| 93 } | 97 } |
| 94 for (String uri in listener.exports) { | 98 for (String uri in listener.exports) { |
| 95 await _addFileForRelativeUri(_exportedFiles, uri); | 99 await _addFileForRelativeUri(_exportedFiles, uri); |
| 96 } | 100 } |
| 97 for (String uri in listener.parts) { | 101 for (String uri in listener.parts) { |
| 98 await _addFileForRelativeUri(_partFiles, uri); | 102 await _addFileForRelativeUri(_partFiles, uri); |
| 99 } | 103 } |
| 100 | 104 |
| 101 // Compute referenced files. | 105 // Compute referenced libraries. |
| 102 _directReferencedFiles = new Set<FileState>() | 106 _directReferencedLibraries = (new Set<FileState>() |
| 103 ..addAll(_importedFiles) | 107 ..addAll(_importedFiles) |
| 104 ..addAll(_exportedFiles) | 108 ..addAll(_exportedFiles)) |
| 105 ..addAll(_partFiles); | 109 .toList(); |
| 110 } | |
| 111 | |
| 112 @override | |
| 113 String toString() { | |
| 114 if (fileUri.scheme == 'file') return fileUri.path; | |
| 115 return fileUri.toString(); | |
| 106 } | 116 } |
| 107 | 117 |
| 108 /// Add the [FileState] for the given [relativeUri] to the [files]. | 118 /// Add the [FileState] for the given [relativeUri] to the [files]. |
| 109 /// Do nothing if the URI cannot be parsed, cannot correspond any file, etc. | 119 /// Do nothing if the URI cannot be parsed, cannot correspond any file, etc. |
| 110 Future<Null> _addFileForRelativeUri( | 120 Future<Null> _addFileForRelativeUri( |
| 111 List<FileState> files, String relativeUri) async { | 121 List<FileState> files, String relativeUri) async { |
| 112 if (relativeUri.isEmpty) return; | 122 if (relativeUri.isEmpty) return; |
| 113 | 123 |
| 114 // Resolve the relative URI into absolute. | 124 // Resolve the relative URI into absolute. |
| 115 // The result is either: | 125 // The result is either: |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 171 file = new FileState._(this, fileUri); | 181 file = new FileState._(this, fileUri); |
| 172 _fileUriToFile[fileUri] = file; | 182 _fileUriToFile[fileUri] = file; |
| 173 | 183 |
| 174 // Build the sub-graph of the file. | 184 // Build the sub-graph of the file. |
| 175 await file.refresh(); | 185 await file.refresh(); |
| 176 } | 186 } |
| 177 return file; | 187 return file; |
| 178 } | 188 } |
| 179 } | 189 } |
| 180 | 190 |
| 191 /// List of libraries that reference each other, so form a cycle. | |
| 192 class LibraryCycle { | |
| 193 final List<FileState> libraries = <FileState>[]; | |
| 194 | |
| 195 @override | |
| 196 String toString() => '[' + libraries.join(', ') + ']'; | |
| 197 } | |
| 198 | |
| 181 /// [FileSystemState] based implementation of [FileSystem]. | 199 /// [FileSystemState] based implementation of [FileSystem]. |
| 182 /// It provides a consistent view on the known file system state. | 200 /// It provides a consistent view on the known file system state. |
| 183 class _FileSystemView implements FileSystem { | 201 class _FileSystemView implements FileSystem { |
| 184 final FileSystemState fsState; | 202 final FileSystemState fsState; |
| 185 | 203 |
| 186 _FileSystemView(this.fsState); | 204 _FileSystemView(this.fsState); |
| 187 | 205 |
| 188 @override | 206 @override |
| 189 FileSystemEntity entityForUri(Uri uri) { | 207 FileSystemEntity entityForUri(Uri uri) { |
| 190 FileState file = fsState._fileUriToFile[uri]; | 208 FileState file = fsState._fileUriToFile[uri]; |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 219 Future<String> readAsString() async => _shouldNotBeQueried(); | 237 Future<String> readAsString() async => _shouldNotBeQueried(); |
| 220 | 238 |
| 221 /// _FileSystemViewEntry is used by the incremental kernel generator to | 239 /// _FileSystemViewEntry is used by the incremental kernel generator to |
| 222 /// provide Fasta with a consistent, race condition free view of the files | 240 /// provide Fasta with a consistent, race condition free view of the files |
| 223 /// constituting the project. It should only need to be used for reading | 241 /// constituting the project. It should only need to be used for reading |
| 224 /// file contents. | 242 /// file contents. |
| 225 dynamic _shouldNotBeQueried() { | 243 dynamic _shouldNotBeQueried() { |
| 226 throw new StateError('The method should not be invoked.'); | 244 throw new StateError('The method should not be invoked.'); |
| 227 } | 245 } |
| 228 } | 246 } |
| 247 | |
| 248 /// Node in [_LibraryWalker]. | |
| 249 class _LibraryNode extends graph.Node<_LibraryNode> { | |
| 250 final _LibraryWalker walker; | |
| 251 final FileState file; | |
| 252 | |
| 253 @override | |
| 254 bool isEvaluated = false; | |
| 255 | |
| 256 _LibraryNode(this.walker, this.file); | |
| 257 | |
| 258 @override | |
| 259 List<_LibraryNode> computeDependencies() { | |
| 260 return file.directReferencedLibraries.map(walker.getNode).toList(); | |
| 261 } | |
| 262 } | |
| 263 | |
| 264 /// Helper that organizes dependencies of a library into topologically | |
| 265 /// sorted [LibraryCycle]s. | |
| 266 class _LibraryWalker extends graph.DependencyWalker<_LibraryNode> { | |
| 267 final nodesOfFiles = <FileState, _LibraryNode>{}; | |
| 268 final topologicallySortedCycles = <LibraryCycle>[]; | |
| 269 | |
| 270 @override | |
| 271 void evaluate(_LibraryNode v) { | |
| 272 evaluateScc([v]); | |
| 273 } | |
| 274 | |
| 275 @override | |
| 276 void evaluateScc(List<_LibraryNode> scc) { | |
| 277 var cycle = new LibraryCycle(); | |
| 278 for (var node in scc) { | |
| 279 node.isEvaluated = true; | |
| 280 cycle.libraries.add(node.file); | |
| 281 } | |
| 282 topologicallySortedCycles.add(cycle); | |
| 283 } | |
| 284 | |
| 285 _LibraryNode getNode(FileState file) { | |
| 286 return nodesOfFiles.putIfAbsent(file, () => new _LibraryNode(this, file)); | |
| 287 } | |
| 288 } | |
| OLD | NEW |