Issue 47804. Recompute invlaidated libraries after processing all changed files.

The issue has the discussion.

Bug: https://github.com/dart-lang/sdk/issues/47804
Change-Id: I301fe8fe44b0e8e7e3b413df0363fabc44061c7d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/221564
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2021-11-30 00:26:44 +00:00 committed by Commit Bot
parent 44b93338d9
commit 6091533c6e
2 changed files with 108 additions and 11 deletions

View file

@ -504,6 +504,10 @@ class DeclarationsTracker {
/// The list of changed file paths. /// The list of changed file paths.
final List<String> _changedPaths = []; final List<String> _changedPaths = [];
/// While processing [_changedPaths] we accumulate libraries here.
/// Then we process all of them at once, and reset to the empty set.
Set<_File> _invalidatedLibraries = {};
/// The list of files scheduled for processing. It may include parts and /// The list of files scheduled for processing. It may include parts and
/// libraries, but parts are ignored when we detect them. /// libraries, but parts are ignored when we detect them.
final List<_ScheduledFile> _scheduledFiles = []; final List<_ScheduledFile> _scheduledFiles = [];
@ -529,7 +533,9 @@ class DeclarationsTracker {
_whenKnownFilesPulled = now; _whenKnownFilesPulled = now;
pullKnownFiles(); pullKnownFiles();
} }
return _changedPaths.isNotEmpty || _scheduledFiles.isNotEmpty; return _changedPaths.isNotEmpty ||
_invalidatedLibraries.isNotEmpty ||
_scheduledFiles.isNotEmpty;
} }
/// Add the [analysisContext], so that its libraries are reported via the /// Add the [analysisContext], so that its libraries are reported via the
@ -595,6 +601,13 @@ class DeclarationsTracker {
return; return;
} }
// There are no more changes as far as we know.
// So, recompute exported declarations for all invalidated libraries.
if (_invalidatedLibraries.isNotEmpty) {
_processInvalidatedLibraries(_invalidatedLibraries);
_invalidatedLibraries = {};
}
if (_scheduledFiles.isNotEmpty) { if (_scheduledFiles.isNotEmpty) {
var scheduledFile = _scheduledFiles.removeLast(); var scheduledFile = _scheduledFiles.removeLast();
var file = _getFileByPath(scheduledFile.context, [], scheduledFile.path)!; var file = _getFileByPath(scheduledFile.context, [], scheduledFile.path)!;
@ -794,10 +807,32 @@ class DeclarationsTracker {
_invalidateExportedDeclarations(invalidatedLibraries, newLibrary); _invalidateExportedDeclarations(invalidatedLibraries, newLibrary);
} }
} }
_computeExportedDeclarations(invalidatedLibraries);
var changedLibraries = <Library>[]; // Don't compute exported declarations now, there might be more changes.
// Instead, accumulate invalidated libraries, and recompute all later.
_invalidatedLibraries.addAll(invalidatedLibraries);
var removedLibraries = <int>[]; var removedLibraries = <int>[];
for (var libraryFile in invalidatedLibraries) {
if (!libraryFile.exists) {
_idToLibrary.remove(libraryFile.id);
removedLibraries.add(libraryFile.id);
}
}
for (var file in notLibraries) {
_idToLibrary.remove(file.id);
removedLibraries.add(file.id);
}
if (removedLibraries.isNotEmpty) {
_changesController.add(
LibraryChange._([], removedLibraries),
);
}
}
void _processInvalidatedLibraries(Set<_File> invalidatedLibraries) {
_computeExportedDeclarations(invalidatedLibraries);
var changedLibraries = <Library>[];
for (var libraryFile in invalidatedLibraries) { for (var libraryFile in invalidatedLibraries) {
if (libraryFile.exists) { if (libraryFile.exists) {
var library = Library._( var library = Library._(
@ -809,17 +844,10 @@ class DeclarationsTracker {
); );
_idToLibrary[library.id] = library; _idToLibrary[library.id] = library;
changedLibraries.add(library); changedLibraries.add(library);
} else {
_idToLibrary.remove(libraryFile.id);
removedLibraries.add(libraryFile.id);
} }
} }
for (var file in notLibraries) {
_idToLibrary.remove(file.id);
removedLibraries.add(file.id);
}
_changesController.add( _changesController.add(
LibraryChange._(changedLibraries, removedLibraries), LibraryChange._(changedLibraries, []),
); );
} }

View file

@ -914,6 +914,75 @@ class C2 {}
]); ]);
} }
/// https://github.com/dart-lang/sdk/issues/47804
test_updated_exported2() async {
var a = convertPath('/home/test/lib/a.dart');
var b = convertPath('/home/test/lib/b.dart');
var c = convertPath('/home/test/lib/c.dart');
newFile(a, content: r'''
class A {}
''');
newFile(b, content: r'''
class B {}
''');
newFile(c, content: r'''
export 'a.dart';
export 'b.dart';
class C {}
''');
tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
_assertHasLibrary('package:test/c.dart', declarations: [
_ExpectedDeclaration.class_('A', [
_ExpectedDeclaration.constructor(''),
]),
_ExpectedDeclaration.class_('B', [
_ExpectedDeclaration.constructor(''),
]),
_ExpectedDeclaration.class_('C', [
_ExpectedDeclaration.constructor(''),
]),
]);
changes.clear();
newFile(a, content: r'''
class A2 {}
''');
newFile(b, content: r'''
class B2 {}
''');
tracker.changeFile(a);
tracker.changeFile(b);
await _doAllTrackerWork();
// In general it is OK to get duplicate libraries.
// But here we notified about both `a.dart` and `b.dart` changes before
// performing any work. So, there is no reason do handle `c.dart` twice.
var uniquePathSet = <String>{};
for (var change in changes) {
for (var library in change.changed) {
if (!uniquePathSet.add(library.path)) {
fail('Not unique path: ${library.path}');
}
}
}
_assertHasLibrary('package:test/c.dart', declarations: [
_ExpectedDeclaration.class_('A2', [
_ExpectedDeclaration.constructor(''),
]),
_ExpectedDeclaration.class_('B2', [
_ExpectedDeclaration.constructor(''),
]),
_ExpectedDeclaration.class_('C', [
_ExpectedDeclaration.constructor(''),
]),
]);
}
test_updated_library() async { test_updated_library() async {
var a = convertPath('/home/test/lib/a.dart'); var a = convertPath('/home/test/lib/a.dart');
var b = convertPath('/home/test/lib/b.dart'); var b = convertPath('/home/test/lib/b.dart');