Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(342)

Side by Side Diff: pkg/front_end/lib/src/incremental/file_state.dart

Issue 2871783002: Start using FileState/FileSystemState to provide consistent view. (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 import 'dart:async';
6 import 'dart:convert';
7 import 'dart:typed_data';
8
9 import 'package:front_end/file_system.dart';
10 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/source/directive_listener.dart';
13 import 'package:front_end/src/fasta/translate_uri.dart';
14
15 /// Information about a file being analyzed, explicitly or implicitly.
Siggi Cherem (dart-lang) 2017/05/08 23:55:17 nit: now that this includes compilation maybe "ana
scheglov 2017/05/09 00:16:28 I will changed it to "compiled".
16 ///
17 /// It provides a consistent view on its properties.
18 ///
19 /// 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]
21 /// should be called.
22 class FileState {
23 final FileSystemState _fsState;
24
25 /// The resolved URI of the file in the file system.
26 final Uri fileUri;
27
28 bool _exists;
29 List<int> _contentBytes;
30 String _content;
Paul Berry 2017/05/08 22:10:48 Is it necessary to keep both _contentBytes and _co
scheglov 2017/05/09 00:16:28 I think you're right. I will fix this in the next
31
32 List<FileState> _importedFiles;
33 List<FileState> _exportedFiles;
34 List<FileState> _partedFiles;
Siggi Cherem (dart-lang) 2017/05/08 23:55:18 nit: rename to _partfiles
scheglov 2017/05/09 00:16:28 Done.
35
36 Set<FileState> _directReferencedFiles = new Set<FileState>();
37
38 FileState._(this._fsState, this.fileUri);
39
40 /// The content of the file.
41 String get content => _content;
42
43 /// The content bytes of the file.
44 List<int> get contentBytes => _contentBytes;
45
46 /// Whether the file exists.
47 bool get exists => _exists;
48
49 @override
50 int get hashCode => fileUri.hashCode;
51
52 /// Return the set of transitive files - the file itself and all of the
53 /// directly or indirectly referenced files.
54 Set<FileState> get transitiveFiles {
55 // TODO(scheglov) add caching.
56 var transitiveFiles = new Set<FileState>();
57
58 void appendReferenced(FileState file) {
59 if (transitiveFiles.add(file)) {
60 file._directReferencedFiles.forEach(appendReferenced);
61 }
62 }
63
64 appendReferenced(this);
65 return transitiveFiles;
66 }
67
68 @override
69 bool operator ==(Object other) {
70 return other is FileState && other.fileUri == fileUri;
71 }
72
73 /// Read the file content and ensure that all of the file properties are
74 /// consistent with the read content, including all its dependencies.
75 Future<Null> refresh() async {
76 // Read the content.
Siggi Cherem (dart-lang) 2017/05/08 23:55:17 I expect `refresh` will only get called on files t
scheglov 2017/05/09 00:16:28 Correct. We read each file at least once when ref
77 try {
78 FileSystemEntity entry = _fsState.fileSystem.entityForUri(fileUri);
79 _contentBytes = await entry.readAsBytes();
80 _content = UTF8.decode(_contentBytes);
81 _exists = true;
82 } catch (_) {
83 _contentBytes = new Uint8List(0);
84 _content = '';
85 _exists = false;
86 }
87
88 // Parse directives.
89 ScannerResult scannerResults = scanString(_content);
90 var listener = new DirectiveListener();
91 new TopLevelParser(listener).parseUnit(scannerResults.tokens);
92
93 // Build the graph.
94 _importedFiles = <FileState>[];
95 _exportedFiles = <FileState>[];
96 _partedFiles = <FileState>[];
97 for (String import in listener.imports) {
Paul Berry 2017/05/08 22:10:49 Can we rename "import" to "importedFile" or someth
Siggi Cherem (dart-lang) 2017/05/08 23:55:18 nit: I'd use `var` instead of `String` For the va
scheglov 2017/05/09 00:16:28 Done.
scheglov 2017/05/09 00:16:28 I don't see the type of "listener.imports". It is
Siggi Cherem (dart-lang) 2017/05/09 00:26:15 Not sure why that's not working: listener.imports
scheglov 2017/05/09 00:29:43 Ah, sorry, I should have been more explicit. The t
98 await _addFileForRelativeUri(_importedFiles, import);
99 }
100 for (String export in listener.exports) {
Paul Berry 2017/05/08 22:10:49 Similar issue here
scheglov 2017/05/09 00:16:28 Done.
101 await _addFileForRelativeUri(_exportedFiles, export);
Siggi Cherem (dart-lang) 2017/05/08 23:55:17 optional - it appears to me that it is safe to par
scheglov 2017/05/09 00:16:28 That's an interesting idea. I will keep it in mind
102 }
103 for (String export in listener.parts) {
Paul Berry 2017/05/08 22:10:49 Here we should rename "export" to something like "
scheglov 2017/05/09 00:16:28 Done.
104 await _addFileForRelativeUri(_partedFiles, export);
105 }
106 // TODO(scheglov) make this optional
Paul Berry 2017/05/08 22:10:49 Why? All files import 'dart:core' (either implici
scheglov 2017/05/09 00:16:28 Well, yeah, I thought about adding it only if dart
107 await _addFileForRelativeUri(_importedFiles, 'dart:core');
108
109 // Compute referenced files.
110 _directReferencedFiles = new Set<FileState>()
111 ..addAll(_importedFiles)
112 ..addAll(_exportedFiles)
113 ..addAll(_partedFiles);
114 }
115
116 /// Add the [FileState] for the given [relativeUri] to the [files].
117 /// Do nothing if the URI cannot be parsed, cannot correspond any file, etc.
118 Future<Null> _addFileForRelativeUri(
119 List<FileState> files, String relativeUri) async {
120 if (relativeUri.isEmpty) {
Siggi Cherem (dart-lang) 2017/05/08 23:55:17 optional nit: I tend to prefer no braces on these
scheglov 2017/05/09 00:16:28 Done.
121 return;
122 }
123
124 // Resolve the relative URI into absolute.
125 // The result is either:
126 // 1) The absolute file URI.
127 // 2) The absolute non-file URI, e.g. `package:foo/foo.dart`.
128 Uri absoluteUri;
129 try {
130 absoluteUri = this.fileUri.resolve(relativeUri);
131 } on FormatException {
132 return;
133 }
134
135 // Resolve the absolute URI into the absolute file URI.
136 Uri fileUri = _fsState.uriTranslator.translate(absoluteUri);
Siggi Cherem (dart-lang) 2017/05/08 23:55:17 note that this shadows FielState.fileUri - it migh
scheglov 2017/05/09 00:16:28 Done.
137 if (fileUri == null) {
Siggi Cherem (dart-lang) 2017/05/08 23:55:17 same here about one-line if ("if (fileUri == null)
scheglov 2017/05/09 00:16:28 Done.
138 return;
139 }
140
141 FileState file = await _fsState.getFile(fileUri);
142 files.add(file);
143 }
144 }
145
146 /// Information about known file system state.
147 class FileSystemState {
148 final FileSystem fileSystem;
149 final TranslateUri uriTranslator;
150
151 _FileSystemView _fileSystemView;
152
153 /// Mapping from file URIs to corresponding [FileState]s.
154 final Map<Uri, FileState> _fileUriToFile = {};
155
156 FileSystemState(this.fileSystem, this.uriTranslator);
157
158 /// Return the [FileSystem] that is backed by this [FileSystemState]. The
159 /// files in this [FileSystem] always have the same content as the
160 /// corresponding [FileState]s, thus avoiding race conditions when a file
161 /// is updated on the actual file system.
162 FileSystem get fileSystemView {
163 return _fileSystemView ??= new _FileSystemView(this);
164 }
165
166 /// Return the [FileState] for the given resolved file [fileUri].
167 /// The returned file has the last known state since it was last refreshed.
168 Future<FileState> getFile(Uri fileUri) async {
169 FileState file = _fileUriToFile[fileUri];
170 if (file == null) {
171 file = new FileState._(this, fileUri);
172 _fileUriToFile[fileUri] = file;
173
174 // Build the sub-graph of the file.
175 await file.refresh();
176 }
177 return file;
178 }
179 }
180
181 /// [FileSystemState] based implementation of [FileSystem].
182 /// It provides a consistent view on the known file system state.
183 class _FileSystemView implements FileSystem {
184 final FileSystemState fsState;
185
186 _FileSystemView(this.fsState);
187
188 @override
189 FileSystemEntity entityForUri(Uri uri) {
190 FileState file = fsState._fileUriToFile[uri];
191 return new _FileSystemViewEntry(uri, file);
192 }
193 }
194
195 /// [FileSystemState] based implementation of [FileSystemEntity].
196 class _FileSystemViewEntry implements FileSystemEntity {
197 @override
198 final Uri uri;
199
200 final FileState file;
201
202 _FileSystemViewEntry(this.uri, this.file);
203
204 @override
205 Future<bool> exists() async => file?.exists ?? false;
206
207 @override
208 Future<DateTime> lastModified() async {
209 throw new UnimplementedError();
Paul Berry 2017/05/08 22:10:49 Maybe throw a StateError() here with a message say
scheglov 2017/05/09 00:16:28 Done. I agree, this API might not always be access
210 }
211
212 @override
213 Future<List<int>> readAsBytes() async {
214 _throwIfDoesNotExist();
215 return file.contentBytes;
216 }
217
218 @override
219 Future<String> readAsString() async {
220 _throwIfDoesNotExist();
221 return file.content;
222 }
223
224 void _throwIfDoesNotExist() {
225 if (file == null) {
226 throw new FileSystemException(uri, 'File $uri does not exist.');
227 }
228 }
229 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698