OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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:convert'; | 5 import 'dart:convert'; |
6 import 'dart:typed_data'; | 6 import 'dart:typed_data'; |
7 | 7 |
8 import 'package:analyzer/dart/ast/ast.dart'; | 8 import 'package:analyzer/dart/ast/ast.dart'; |
9 import 'package:analyzer/dart/ast/token.dart'; | 9 import 'package:analyzer/dart/ast/token.dart'; |
10 import 'package:analyzer/error/listener.dart'; | 10 import 'package:analyzer/error/listener.dart'; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 /** | 69 /** |
70 * The absolute path of the file. | 70 * The absolute path of the file. |
71 */ | 71 */ |
72 final String path; | 72 final String path; |
73 | 73 |
74 /** | 74 /** |
75 * The absolute URI of the file. | 75 * The absolute URI of the file. |
76 */ | 76 */ |
77 final Uri uri; | 77 final Uri uri; |
78 | 78 |
79 Source _source; | 79 /** |
| 80 * The [Source] of the file with the [uri]. |
| 81 */ |
| 82 Source source; |
80 | 83 |
81 String _content; | 84 String _content; |
82 String _contentHash; | 85 String _contentHash; |
83 LineInfo _lineInfo; | 86 LineInfo _lineInfo; |
84 UnlinkedUnit _unlinked; | 87 UnlinkedUnit _unlinked; |
85 List<int> _apiSignature; | 88 List<int> _apiSignature; |
86 | 89 |
87 List<FileState> _importedFiles; | 90 List<FileState> _importedFiles; |
88 List<FileState> _exportedFiles; | 91 List<FileState> _exportedFiles; |
89 List<FileState> _partedFiles; | 92 List<FileState> _partedFiles; |
90 List<FileState> _dependencies; | 93 List<FileState> _dependencies; |
91 | 94 |
92 FileState(this._fsState, this.path, this.uri) { | 95 FileState._(this._fsState, this.path, this.uri, this.source); |
93 _source = new FileSource(_fsState._resourceProvider.getFile(path), uri); | |
94 } | |
95 | 96 |
96 /** | 97 /** |
97 * The unlinked API signature of the file. | 98 * The unlinked API signature of the file. |
98 */ | 99 */ |
99 List<int> get apiSignature => _apiSignature; | 100 List<int> get apiSignature => _apiSignature; |
100 | 101 |
101 /** | 102 /** |
102 * The content of the file. | 103 * The content of the file. |
103 */ | 104 */ |
104 String get content => _content; | 105 String get content => _content; |
105 | 106 |
106 /** | 107 /** |
107 * The MD5 hash of the [content]. | 108 * The MD5 hash of the [content]. |
108 */ | 109 */ |
109 String get contentHash => _contentHash; | 110 String get contentHash => _contentHash; |
110 | 111 |
111 /** | 112 /** |
112 * Return information about line in the file. | |
113 */ | |
114 LineInfo get lineInfo => _lineInfo; | |
115 | |
116 /** | |
117 * Return the list of all direct dependencies. | 113 * Return the list of all direct dependencies. |
118 */ | 114 */ |
119 List<FileState> get dependencies => _dependencies; | 115 List<FileState> get dependencies => _dependencies; |
120 | 116 |
121 /** | 117 /** |
122 * The list of files this file exports. | 118 * The list of files this file exports. |
123 */ | 119 */ |
124 List<FileState> get exportedFiles => _exportedFiles; | 120 List<FileState> get exportedFiles => _exportedFiles; |
125 | 121 |
126 /** | 122 /** |
127 * The list of files this file imports. | 123 * The list of files this file imports. |
128 */ | 124 */ |
129 List<FileState> get importedFiles => _importedFiles; | 125 List<FileState> get importedFiles => _importedFiles; |
130 | 126 |
131 /** | 127 /** |
| 128 * Return information about line in the file. |
| 129 */ |
| 130 LineInfo get lineInfo => _lineInfo; |
| 131 |
| 132 /** |
132 * The list of files this library file references as parts. | 133 * The list of files this library file references as parts. |
133 */ | 134 */ |
134 List<FileState> get partedFiles => _partedFiles; | 135 List<FileState> get partedFiles => _partedFiles; |
135 | 136 |
136 /** | 137 /** |
137 * The [Source] of the file in the [SourceFactory]. | |
138 */ | |
139 Source get source => _source; | |
140 | |
141 /** | |
142 * The [UnlinkedUnit] of the file. | 138 * The [UnlinkedUnit] of the file. |
143 */ | 139 */ |
144 UnlinkedUnit get unlinked => _unlinked; | 140 UnlinkedUnit get unlinked => _unlinked; |
145 | 141 |
146 /** | 142 /** |
147 * Read the file content and ensure that all of the file properties are | 143 * Read the file content and ensure that all of the file properties are |
148 * consistent with the read content, including API signature. | 144 * consistent with the read content, including API signature. |
149 * | 145 * |
150 * Return `true` if the API signature changed since the last refresh. | 146 * Return `true` if the API signature changed since the last refresh. |
151 */ | 147 */ |
(...skipping 28 matching lines...) Expand all Loading... |
180 signature.addBytes(contentBytes); | 176 signature.addBytes(contentBytes); |
181 unlinkedKey = '${signature.toHex()}.unlinked'; | 177 unlinkedKey = '${signature.toHex()}.unlinked'; |
182 } | 178 } |
183 | 179 |
184 // Prepare bytes of the unlinked bundle - existing or new. | 180 // Prepare bytes of the unlinked bundle - existing or new. |
185 List<int> bytes; | 181 List<int> bytes; |
186 { | 182 { |
187 bytes = _fsState._byteStore.get(unlinkedKey); | 183 bytes = _fsState._byteStore.get(unlinkedKey); |
188 if (bytes == null) { | 184 if (bytes == null) { |
189 CompilationUnit unit = | 185 CompilationUnit unit = |
190 _parse(_source, _content, _fsState._analysisOptions); | 186 _parse(source, _content, _fsState._analysisOptions); |
191 _fsState._logger.run('Create unlinked for $path', () { | 187 _fsState._logger.run('Create unlinked for $path', () { |
192 UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit); | 188 UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit); |
193 bytes = unlinkedUnit.toBuffer(); | 189 bytes = unlinkedUnit.toBuffer(); |
194 _fsState._byteStore.put(unlinkedKey, bytes); | 190 _fsState._byteStore.put(unlinkedKey, bytes); |
195 }); | 191 }); |
196 } | 192 } |
197 } | 193 } |
198 | 194 |
199 // Read the unlinked bundle. | 195 // Read the unlinked bundle. |
200 _unlinked = new UnlinkedUnit.fromBuffer(bytes); | 196 _unlinked = new UnlinkedUnit.fromBuffer(bytes); |
201 _lineInfo = new LineInfo(_unlinked.lineStarts); | 197 _lineInfo = new LineInfo(_unlinked.lineStarts); |
202 List<int> newApiSignature = _unlinked.apiSignature; | 198 List<int> newApiSignature = _unlinked.apiSignature; |
203 bool apiSignatureChanged = _apiSignature != null && | 199 bool apiSignatureChanged = _apiSignature != null && |
204 !_equalByteLists(_apiSignature, newApiSignature); | 200 !_equalByteLists(_apiSignature, newApiSignature); |
205 _apiSignature = newApiSignature; | 201 _apiSignature = newApiSignature; |
206 | 202 |
207 // Build the graph. | 203 // Build the graph. |
208 _importedFiles = <FileState>[]; | 204 _importedFiles = <FileState>[]; |
209 _exportedFiles = <FileState>[]; | 205 _exportedFiles = <FileState>[]; |
210 _partedFiles = <FileState>[]; | 206 _partedFiles = <FileState>[]; |
211 for (UnlinkedImport import in _unlinked.imports) { | 207 for (UnlinkedImport import in _unlinked.imports) { |
212 if (!import.isImplicit) { | 208 if (!import.isImplicit) { |
213 String uri = import.uri; | 209 String uri = import.uri; |
214 if (!_isDartUri(uri)) { | 210 if (!_isDartUri(uri)) { |
215 FileState file = _fileForRelativeUri(uri); | 211 FileState file = _fileForRelativeUri(uri); |
216 _importedFiles.add(file); | 212 if (file != null) { |
| 213 _importedFiles.add(file); |
| 214 } |
217 } | 215 } |
218 } | 216 } |
219 } | 217 } |
220 for (UnlinkedExportPublic export in _unlinked.publicNamespace.exports) { | 218 for (UnlinkedExportPublic export in _unlinked.publicNamespace.exports) { |
221 String uri = export.uri; | 219 String uri = export.uri; |
222 if (!_isDartUri(uri)) { | 220 if (!_isDartUri(uri)) { |
223 FileState file = _fileForRelativeUri(uri); | 221 FileState file = _fileForRelativeUri(uri); |
224 _exportedFiles.add(file); | 222 if (file != null) { |
| 223 _exportedFiles.add(file); |
| 224 } |
225 } | 225 } |
226 } | 226 } |
227 for (String uri in _unlinked.publicNamespace.parts) { | 227 for (String uri in _unlinked.publicNamespace.parts) { |
228 if (!_isDartUri(uri)) { | 228 if (!_isDartUri(uri)) { |
229 FileState file = _fileForRelativeUri(uri); | 229 FileState file = _fileForRelativeUri(uri); |
230 _partedFiles.add(file); | 230 if (file != null) { |
| 231 _partedFiles.add(file); |
| 232 } |
231 } | 233 } |
232 } | 234 } |
233 | 235 |
234 // Compute direct dependencies. | 236 // Compute direct dependencies. |
235 _dependencies = (new Set<FileState>() | 237 _dependencies = (new Set<FileState>() |
236 ..addAll(_importedFiles) | 238 ..addAll(_importedFiles) |
237 ..addAll(_exportedFiles) | 239 ..addAll(_exportedFiles) |
238 ..addAll(_partedFiles)) | 240 ..addAll(_partedFiles)) |
239 .toList(); | 241 .toList(); |
240 | 242 |
241 // Return whether the API signature changed. | 243 // Return whether the API signature changed. |
242 return apiSignatureChanged; | 244 return apiSignatureChanged; |
243 } | 245 } |
244 | 246 |
245 @override | 247 @override |
246 String toString() => path; | 248 String toString() => path; |
247 | 249 |
248 /** | 250 /** |
249 * Return the [FileState] for the given [relativeUri]. | 251 * Return the [FileState] for the given [relativeUri]. |
250 */ | 252 */ |
251 FileState _fileForRelativeUri(String relativeUri) { | 253 FileState _fileForRelativeUri(String relativeUri) { |
252 Uri absoluteUri = resolveRelativeUri(uri, FastUri.parse(relativeUri)); | 254 Uri absoluteUri = resolveRelativeUri(uri, FastUri.parse(relativeUri)); |
253 String absolutePath = _fsState._sourceFactory | 255 return _fsState.getFileForUri(absoluteUri); |
254 .resolveUri(null, absoluteUri.toString()) | |
255 .fullName; | |
256 return _fsState.getFile(absolutePath, absoluteUri); | |
257 } | 256 } |
258 | 257 |
259 /** | 258 /** |
260 * Return `true` if the given byte lists are equal. | 259 * Return `true` if the given byte lists are equal. |
261 */ | 260 */ |
262 static bool _equalByteLists(List<int> a, List<int> b) { | 261 static bool _equalByteLists(List<int> a, List<int> b) { |
263 if (a == null) { | 262 if (a == null) { |
264 return b == null; | 263 return b == null; |
265 } else if (b == null) { | 264 } else if (b == null) { |
266 return false; | 265 return false; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
306 */ | 305 */ |
307 class FileSystemState { | 306 class FileSystemState { |
308 final PerformanceLog _logger; | 307 final PerformanceLog _logger; |
309 final ResourceProvider _resourceProvider; | 308 final ResourceProvider _resourceProvider; |
310 final ByteStore _byteStore; | 309 final ByteStore _byteStore; |
311 final FileContentOverlay _contentOverlay; | 310 final FileContentOverlay _contentOverlay; |
312 final SourceFactory _sourceFactory; | 311 final SourceFactory _sourceFactory; |
313 final AnalysisOptions _analysisOptions; | 312 final AnalysisOptions _analysisOptions; |
314 final Uint32List _salt; | 313 final Uint32List _salt; |
315 | 314 |
316 final Map<String, FileState> _pathToFile = <String, FileState>{}; | 315 /** |
| 316 * Mapping from a URI to the corresponding [FileState]. |
| 317 */ |
| 318 final Map<Uri, FileState> _uriToFile = {}; |
| 319 |
| 320 /** |
| 321 * Mapping from a path to the corresponding [FileState]s, canonical or not. |
| 322 */ |
| 323 final Map<String, List<FileState>> _pathToFiles = {}; |
| 324 |
| 325 /** |
| 326 * Mapping from a path to the corresponding canonical [FileState]. |
| 327 */ |
| 328 final Map<String, FileState> _pathToCanonicalFile = {}; |
317 | 329 |
318 FileSystemState( | 330 FileSystemState( |
319 this._logger, | 331 this._logger, |
320 this._byteStore, | 332 this._byteStore, |
321 this._contentOverlay, | 333 this._contentOverlay, |
322 this._resourceProvider, | 334 this._resourceProvider, |
323 this._sourceFactory, | 335 this._sourceFactory, |
324 this._analysisOptions, | 336 this._analysisOptions, |
325 this._salt); | 337 this._salt); |
326 | 338 |
327 /** | 339 /** |
328 * Return the [FileState] for the give [path]. The returned file has the | 340 * Return the canonical [FileState] for the given absolute [path]. The |
329 * last known state since if was last refreshed. | 341 * returned file has the last known state since if was last refreshed. |
| 342 * |
| 343 * Here "canonical" means that if the [path] is in a package `lib` then the |
| 344 * returned file will have the `package:` style URI. |
330 */ | 345 */ |
331 FileState getFile(String path, [Uri uri]) { | 346 FileState getFileForPath(String path) { |
332 FileState file = _pathToFile[path]; | 347 FileState file = _pathToCanonicalFile[path]; |
333 if (file == null) { | 348 if (file == null) { |
334 uri ??= _uriForPath(path); | 349 File resource = _resourceProvider.getFile(path); |
335 file = new FileState(this, path, uri); | 350 Source fileSource = resource.createSource(); |
336 _pathToFile[path] = file; | 351 Uri uri = _sourceFactory.restoreUri(fileSource); |
| 352 // Try to get the existing instance. |
| 353 file = _uriToFile[uri]; |
| 354 // If we have a file, call it the canonical one and return it. |
| 355 if (file != null) { |
| 356 _pathToCanonicalFile[path] = file; |
| 357 return file; |
| 358 } |
| 359 // Create a new file. |
| 360 FileSource uriSource = new FileSource(resource, uri); |
| 361 file = new FileState._(this, path, uri, uriSource); |
| 362 _uriToFile[uri] = file; |
| 363 _pathToFiles.putIfAbsent(path, () => <FileState>[]).add(file); |
| 364 _pathToCanonicalFile[path] = file; |
337 file.refresh(); | 365 file.refresh(); |
338 } | 366 } |
339 return file; | 367 return file; |
340 } | 368 } |
341 | 369 |
342 /** | 370 /** |
343 * Return the default [Uri] for the given path in [_sourceFactory]. | 371 * Return the [FileState] for the given absolute [uri]. May return `null` if |
| 372 * the [uri] is invalid, e.g. a `package:` URI without a package name. The |
| 373 * returned file has the last known state since if was last refreshed. |
344 */ | 374 */ |
345 Uri _uriForPath(String path) { | 375 FileState getFileForUri(Uri uri) { |
346 Source fileSource = _resourceProvider.getFile(path).createSource(); | 376 FileState file = _uriToFile[uri]; |
347 return _sourceFactory.restoreUri(fileSource); | 377 if (file == null) { |
| 378 Source uriSource = _sourceFactory.resolveUri(null, uri.toString()); |
| 379 // If the URI is invalid, for example package:/test/d.dart (note the |
| 380 // leading '/'), then `null` is returned. We should ignore this URI. |
| 381 if (uriSource == null) { |
| 382 return null; |
| 383 } |
| 384 String path = uriSource.fullName; |
| 385 File resource = _resourceProvider.getFile(path); |
| 386 FileSource source = new FileSource(resource, uri); |
| 387 file = new FileState._(this, path, uri, source); |
| 388 _uriToFile[uri] = file; |
| 389 _pathToFiles.putIfAbsent(path, () => <FileState>[]).add(file); |
| 390 file.refresh(); |
| 391 } |
| 392 return file; |
| 393 } |
| 394 |
| 395 /** |
| 396 * Return the list of all [FileState]s corresponding to the given [path]. The |
| 397 * list has at least one item, and the first item is the canonical file. |
| 398 */ |
| 399 List<FileState> getFilesForPath(String path) { |
| 400 FileState canonicalFile = getFileForPath(path); |
| 401 List<FileState> allFiles = _pathToFiles[path].toList(); |
| 402 if (allFiles.length == 1) { |
| 403 return allFiles; |
| 404 } |
| 405 return allFiles |
| 406 ..remove(canonicalFile) |
| 407 ..insert(0, canonicalFile); |
348 } | 408 } |
349 } | 409 } |
OLD | NEW |