Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit c003c1a

Browse files
scheglovcommit-bot@chromium.org
authored andcommitted
Don't read referenced files in AnalysisDriver until necessary.
Bug: dart-lang/sdk#43744 Change-Id: I06d58b2a11fdf2db9bd6800f350ac25b8aab3fb4 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/168382 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
1 parent 037cff9 commit c003c1a

File tree

3 files changed

+125
-39
lines changed

3 files changed

+125
-39
lines changed

pkg/analyzer/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
## 0.40.5-dev
22
* Deprecated `GenericTypeAliasElement`. Use `FunctionTypeAliasElement`.
3+
* Read imports, exports, and parts on demand in `AnalysisDriver`.
4+
Specifically, `parseFileSync` will not read any referenced files.
35

46
## 0.40.4
57
* Deprecated `IndexExpression.auxiliaryElements` and

pkg/analyzer/lib/src/dart/analysis/file_state.dart

Lines changed: 80 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -192,23 +192,54 @@ class FileState {
192192

193193
/// Return the set of all directly referenced files - imported, exported or
194194
/// parted.
195-
Set<FileState> get directReferencedFiles => _directReferencedFiles;
195+
Set<FileState> get directReferencedFiles {
196+
return _directReferencedFiles ??= <FileState>{
197+
...importedFiles,
198+
...exportedFiles,
199+
...partedFiles,
200+
};
201+
}
196202

197203
/// Return the set of all directly referenced libraries - imported or
198204
/// exported.
199-
Set<FileState> get directReferencedLibraries => _directReferencedLibraries;
205+
Set<FileState> get directReferencedLibraries {
206+
return _directReferencedLibraries ??= <FileState>{
207+
...importedFiles,
208+
...exportedFiles,
209+
};
210+
}
200211

201212
/// Return `true` if the file exists.
202213
bool get exists => _exists;
203214

204215
/// The list of files this file exports.
205-
List<FileState> get exportedFiles => _exportedFiles;
216+
List<FileState> get exportedFiles {
217+
if (_exportedFiles == null) {
218+
_exportedFiles = <FileState>[];
219+
for (var directive in _unlinked2.exports) {
220+
var uri = _selectRelativeUri(directive);
221+
var file = _fileForRelativeUri(uri);
222+
_exportedFiles.add(file);
223+
}
224+
}
225+
return _exportedFiles;
226+
}
206227

207228
@override
208229
int get hashCode => uri.hashCode;
209230

210231
/// The list of files this file imports.
211-
List<FileState> get importedFiles => _importedFiles;
232+
List<FileState> get importedFiles {
233+
if (_importedFiles == null) {
234+
_importedFiles = <FileState>[];
235+
for (var directive in _unlinked2.imports) {
236+
var uri = _selectRelativeUri(directive);
237+
var file = _fileForRelativeUri(uri);
238+
_importedFiles.add(file);
239+
}
240+
}
241+
return _importedFiles;
242+
}
212243

213244
LibraryCycle get internal_libraryCycle => _libraryCycle;
214245

@@ -237,6 +268,7 @@ class FileState {
237268
/// of. Return `null` if a library is not known, for example because we have
238269
/// not processed a library file yet.
239270
FileState get library {
271+
_fsState.readPartsForLibraries();
240272
List<FileState> libraries = _fsState._partToLibraries[this];
241273
if (libraries == null || libraries.isEmpty) {
242274
return null;
@@ -264,13 +296,27 @@ class FileState {
264296

265297
/// The list of files files that this library consists of, i.e. this library
266298
/// file itself and its [partedFiles].
267-
List<FileState> get libraryFiles => _libraryFiles;
299+
List<FileState> get libraryFiles {
300+
return _libraryFiles ??= [this, ...partedFiles];
301+
}
268302

269303
/// Return information about line in the file.
270304
LineInfo get lineInfo => _lineInfo;
271305

272306
/// The list of files this library file references as parts.
273-
List<FileState> get partedFiles => _partedFiles;
307+
List<FileState> get partedFiles {
308+
if (_partedFiles == null) {
309+
_partedFiles = <FileState>[];
310+
for (var uri in _unlinked2.parts) {
311+
var file = _fileForRelativeUri(uri);
312+
_partedFiles.add(file);
313+
_fsState._partToLibraries
314+
.putIfAbsent(file, () => <FileState>[])
315+
.add(this);
316+
}
317+
}
318+
return _partedFiles;
319+
}
274320

275321
/// The external names referenced by the file.
276322
Set<String> get referencedNames {
@@ -287,7 +333,7 @@ class FileState {
287333

288334
void appendReferenced(FileState file) {
289335
if (transitiveFiles.add(file)) {
290-
file._directReferencedFiles?.forEach(appendReferenced);
336+
file.directReferencedFiles.forEach(appendReferenced);
291337
}
292338
}
293339

@@ -436,39 +482,16 @@ class FileState {
436482
}
437483
}
438484

439-
// Build the graph.
440-
_importedFiles = <FileState>[];
441-
_exportedFiles = <FileState>[];
442-
_partedFiles = <FileState>[];
443-
for (var directive in _unlinked2.imports) {
444-
var uri = _selectRelativeUri(directive);
445-
var file = _fileForRelativeUri(uri);
446-
_importedFiles.add(file);
447-
}
448-
for (var directive in _unlinked2.exports) {
449-
var uri = _selectRelativeUri(directive);
450-
var file = _fileForRelativeUri(uri);
451-
_exportedFiles.add(file);
452-
}
453-
for (var uri in _unlinked2.parts) {
454-
var file = _fileForRelativeUri(uri);
455-
_partedFiles.add(file);
456-
_fsState._partToLibraries
457-
.putIfAbsent(file, () => <FileState>[])
458-
.add(this);
459-
}
460-
_libraryFiles = [this, ..._partedFiles];
485+
// Read imports/exports on demand.
486+
_importedFiles = null;
487+
_exportedFiles = null;
488+
_directReferencedFiles = null;
489+
_directReferencedLibraries = null;
461490

462-
// Compute referenced files.
463-
_directReferencedFiles = <FileState>{
464-
..._importedFiles,
465-
..._exportedFiles,
466-
..._partedFiles,
467-
};
468-
_directReferencedLibraries = <FileState>{
469-
..._importedFiles,
470-
..._exportedFiles,
471-
};
491+
// Read parts on demand.
492+
_fsState._librariesWithoutPartsRead.add(this);
493+
_partedFiles = null;
494+
_libraryFiles = null;
472495

473496
// Update mapping from subtyped names to files.
474497
for (var name in _driverUnlinkedUnit.subtypedNames) {
@@ -748,6 +771,11 @@ class FileSystemState {
748771
/// Mapping from a path to the corresponding canonical [FileState].
749772
final Map<String, FileState> _pathToCanonicalFile = {};
750773

774+
/// We don't read parts until requested, but if we need to know the
775+
/// library for a file, we need to read parts of every file to know
776+
/// which libraries reference this part.
777+
final List<FileState> _librariesWithoutPartsRead = [];
778+
751779
/// Mapping from a part to the libraries it is a part of.
752780
final Map<FileState, List<FileState>> _partToLibraries = {};
753781

@@ -950,6 +978,19 @@ class FileSystemState {
950978
_fileContentCache.remove(path);
951979
}
952980

981+
void readPartsForLibraries() {
982+
// Make a copy, because reading new files will update it.
983+
var libraryToProcess = _librariesWithoutPartsRead.toList();
984+
985+
// We will process these files, so clear it now.
986+
// It will be filled with new files during the loop below.
987+
_librariesWithoutPartsRead.clear();
988+
989+
for (var library in libraryToProcess) {
990+
library.partedFiles;
991+
}
992+
}
993+
953994
/// Remove the file with the given [path].
954995
void removeFile(String path) {
955996
markFileForReading(path);

pkg/analyzer/test/src/dart/analysis/driver_test.dart

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2349,6 +2349,49 @@ void f(A a) {}
23492349
}
23502350
}
23512351

2352+
test_parseFileSync_doesNotReadImportedFiles() async {
2353+
var a = convertPath('/test/lib/a.dart');
2354+
var b = convertPath('/test/lib/b.dart');
2355+
2356+
newFile(a, content: '');
2357+
newFile(b, content: r'''
2358+
import 'a.dart';
2359+
''');
2360+
2361+
expect(driver.fsState.knownFilePaths, isEmpty);
2362+
2363+
// Don't read `a.dart` when parse.
2364+
driver.parseFileSync(b);
2365+
expect(driver.fsState.knownFilePaths, unorderedEquals([b]));
2366+
2367+
// Still don't read `a.dart` when parse the second time.
2368+
driver.parseFileSync(b);
2369+
expect(driver.fsState.knownFilePaths, unorderedEquals([b]));
2370+
}
2371+
2372+
test_parseFileSync_doesNotReadPartedFiles() async {
2373+
var a = convertPath('/test/lib/a.dart');
2374+
var b = convertPath('/test/lib/b.dart');
2375+
2376+
newFile(a, content: r'''
2377+
part of my;
2378+
''');
2379+
newFile(b, content: r'''
2380+
library my;
2381+
part 'a.dart';
2382+
''');
2383+
2384+
expect(driver.fsState.knownFilePaths, isEmpty);
2385+
2386+
// Don't read `a.dart` when parse.
2387+
driver.parseFileSync(b);
2388+
expect(driver.fsState.knownFilePaths, unorderedEquals([b]));
2389+
2390+
// Still don't read `a.dart` when parse the second time.
2391+
driver.parseFileSync(b);
2392+
expect(driver.fsState.knownFilePaths, unorderedEquals([b]));
2393+
}
2394+
23522395
test_parseFileSync_languageVersion() async {
23532396
var path = convertPath('/test/lib/test.dart');
23542397

0 commit comments

Comments
 (0)