mirror of
https://github.com/dart-lang/sdk
synced 2024-10-02 23:49:17 +00:00
Create a new session on a file change.
This should restore throwing InconsistentAnalysisException. Internal presubmit looks green. https://fusion2.corp.google.com/presubmit/tap/424245133/OCL:424245133:BASE:424340361:1643210802936:6f26b405 Change-Id: I286d5db0fe51e8ea00d0fe83a70d4c9d59052715 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/230040 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
17563522da
commit
da48a6fb12
|
@ -223,12 +223,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
|||
/// Whether resolved units should be indexed.
|
||||
final bool enableIndex;
|
||||
|
||||
/// The current analysis session.
|
||||
late final AnalysisSessionImpl _currentSession = AnalysisSessionImpl(this);
|
||||
|
||||
/// The current library context, consistent with the [_currentSession].
|
||||
///
|
||||
/// TODO(scheglov) We probably should tie it into the session.
|
||||
/// The context in which libraries should be analyzed.
|
||||
LibraryContext? _libraryContext;
|
||||
|
||||
/// Whether `dart:core` has been transitively discovered.
|
||||
|
@ -311,7 +306,9 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
|||
AnalysisOptions get analysisOptions => _analysisOptions;
|
||||
|
||||
/// Return the current analysis session.
|
||||
AnalysisSessionImpl get currentSession => _currentSession;
|
||||
AnalysisSessionImpl get currentSession {
|
||||
return libraryContext.elementFactory.analysisSession;
|
||||
}
|
||||
|
||||
/// Return the stream that produces [ExceptionResult]s.
|
||||
Stream<ExceptionResult> get exceptions => _exceptionController.stream;
|
||||
|
@ -337,7 +334,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
|||
LibraryContext get libraryContext {
|
||||
return _libraryContext ??= LibraryContext(
|
||||
testView: _testView.libraryContextTestView,
|
||||
session: currentSession,
|
||||
analysisSession: AnalysisSessionImpl(this),
|
||||
logger: _logger,
|
||||
byteStore: _byteStore,
|
||||
analysisOptions: _analysisOptions,
|
||||
|
@ -515,9 +512,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
|||
/// periodically.
|
||||
@visibleForTesting
|
||||
void clearLibraryContext() {
|
||||
_libraryContext?.invalidAllLibraries();
|
||||
_libraryContext = null;
|
||||
_currentSession.clearHierarchies();
|
||||
}
|
||||
|
||||
/// Some state on which analysis depends has changed, so the driver needs to be
|
||||
|
@ -654,7 +649,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
|||
|
||||
FileState file = _fileTracker.getFile(path);
|
||||
return FileResultImpl(
|
||||
_currentSession, path, file.uri, file.lineInfo, file.isPart);
|
||||
currentSession, path, file.uri, file.lineInfo, file.isPart);
|
||||
}
|
||||
|
||||
/// Return the [FileResult] for the Dart file with the given [path].
|
||||
|
@ -1328,7 +1323,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
|||
declaredVariables,
|
||||
sourceFactory,
|
||||
libraryContext.elementFactory.libraryOfUri2(library.uriStr),
|
||||
libraryContext.analysisSession.inheritanceManager,
|
||||
libraryContext.elementFactory.analysisSession.inheritanceManager,
|
||||
library,
|
||||
testingData: testingData,
|
||||
).analyzeForCompletion(
|
||||
|
@ -1441,7 +1436,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
|||
declaredVariables,
|
||||
sourceFactory,
|
||||
libraryContext.elementFactory.libraryOfUri2(library.uriStr),
|
||||
libraryContext.analysisSession.inheritanceManager,
|
||||
libraryContext.elementFactory.analysisSession.inheritanceManager,
|
||||
library,
|
||||
testingData: testingData,
|
||||
).analyze();
|
||||
|
@ -1512,7 +1507,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
|||
declaredVariables,
|
||||
sourceFactory,
|
||||
libraryContext.elementFactory.libraryOfUri2(library.uriStr),
|
||||
libraryContext.analysisSession.inheritanceManager,
|
||||
libraryContext.elementFactory.analysisSession.inheritanceManager,
|
||||
library,
|
||||
testingData: testingData)
|
||||
.analyze();
|
||||
|
@ -1779,6 +1774,10 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
|||
_libraryContext?.elementFactory.removeLibraries(
|
||||
affected.map((e) => e.uriStr).toSet(),
|
||||
);
|
||||
|
||||
_libraryContext?.elementFactory.replaceAnalysisSession(
|
||||
AnalysisSessionImpl(this),
|
||||
);
|
||||
}
|
||||
|
||||
void _reportException(String path, Object exception, StackTrace stackTrace) {
|
||||
|
|
|
@ -39,8 +39,6 @@ class LibraryContext {
|
|||
final LibraryContextTestView testView;
|
||||
final PerformanceLog logger;
|
||||
final ByteStore byteStore;
|
||||
final AnalysisSessionImpl analysisSession;
|
||||
final SummaryDataStore? externalSummaries;
|
||||
final SummaryDataStore store = SummaryDataStore([]);
|
||||
|
||||
late final AnalysisContextImpl analysisContext;
|
||||
|
@ -48,21 +46,35 @@ class LibraryContext {
|
|||
|
||||
LibraryContext({
|
||||
required this.testView,
|
||||
required AnalysisSessionImpl session,
|
||||
required AnalysisSessionImpl analysisSession,
|
||||
required PerformanceLog logger,
|
||||
required ByteStore byteStore,
|
||||
required AnalysisOptionsImpl analysisOptions,
|
||||
required DeclaredVariables declaredVariables,
|
||||
required SourceFactory sourceFactory,
|
||||
required this.externalSummaries,
|
||||
required SummaryDataStore? externalSummaries,
|
||||
}) : logger = logger,
|
||||
byteStore = byteStore,
|
||||
analysisSession = session {
|
||||
byteStore = byteStore {
|
||||
var synchronousSession =
|
||||
SynchronousSession(analysisOptions, declaredVariables);
|
||||
analysisContext = AnalysisContextImpl(synchronousSession, sourceFactory);
|
||||
|
||||
_createElementFactory();
|
||||
elementFactory = LinkedElementFactory(
|
||||
analysisContext,
|
||||
analysisSession,
|
||||
Reference.root(),
|
||||
);
|
||||
if (externalSummaries != null) {
|
||||
for (var bundle in externalSummaries.bundles) {
|
||||
elementFactory.addBundle(
|
||||
BundleReader(
|
||||
elementFactory: elementFactory,
|
||||
resolutionBytes: bundle.resolutionBytes,
|
||||
unitsInformativeBytes: {},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes a [CompilationUnitElement] for the given library/unit pair.
|
||||
|
@ -86,11 +98,6 @@ class LibraryContext {
|
|||
return elementFactory.libraryOfUriIfReady(uriStr);
|
||||
}
|
||||
|
||||
/// We are about to discard this context, mark all libraries invalid.
|
||||
void invalidAllLibraries() {
|
||||
elementFactory.invalidateAllLibraries();
|
||||
}
|
||||
|
||||
/// Load data required to access elements of the given [targetLibrary].
|
||||
void load2(FileState targetLibrary) {
|
||||
timerLoad2.start();
|
||||
|
@ -222,25 +229,6 @@ class LibraryContext {
|
|||
timerLoad2.stop();
|
||||
}
|
||||
|
||||
void _createElementFactory() {
|
||||
elementFactory = LinkedElementFactory(
|
||||
analysisContext,
|
||||
analysisSession,
|
||||
Reference.root(),
|
||||
);
|
||||
if (externalSummaries != null) {
|
||||
for (var bundle in externalSummaries!.bundles) {
|
||||
elementFactory.addBundle(
|
||||
BundleReader(
|
||||
elementFactory: elementFactory,
|
||||
resolutionBytes: bundle.resolutionBytes,
|
||||
unitsInformativeBytes: {},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensure that type provider is created.
|
||||
void _createElementFactoryTypeProvider() {
|
||||
if (!analysisContext.hasTypeProvider) {
|
||||
|
|
|
@ -3586,13 +3586,7 @@ class LibraryElementImpl extends _ExistingElementImpl
|
|||
final AnalysisContext context;
|
||||
|
||||
@override
|
||||
final AnalysisSession session;
|
||||
|
||||
/// If `true`, then this library is valid in the session.
|
||||
///
|
||||
/// A library becomes invalid when one of its files, or one of its
|
||||
/// dependencies, changes.
|
||||
bool isValid = true;
|
||||
AnalysisSession session;
|
||||
|
||||
/// The language version for the library.
|
||||
LibraryLanguageVersion? _languageVersion;
|
||||
|
|
|
@ -13,7 +13,7 @@ import 'package:analyzer/src/summary2/reference.dart';
|
|||
|
||||
class LinkedElementFactory {
|
||||
final AnalysisContextImpl analysisContext;
|
||||
final AnalysisSessionImpl analysisSession;
|
||||
AnalysisSessionImpl analysisSession;
|
||||
final Reference rootReference;
|
||||
final Map<String, LibraryReader> _libraryReaders = {};
|
||||
final Map<String, List<Reference>> _exportsOfLibrary = {};
|
||||
|
@ -165,13 +165,6 @@ class LinkedElementFactory {
|
|||
return _libraryReaders[uriStr] != null;
|
||||
}
|
||||
|
||||
/// We are about to discard this factory, mark all libraries invalid.
|
||||
void invalidateAllLibraries() {
|
||||
for (var libraryReference in rootReference.children) {
|
||||
_invalidateLibrary(libraryReference);
|
||||
}
|
||||
}
|
||||
|
||||
LibraryElementImpl? libraryOfUri(String uriStr) {
|
||||
var reference = rootReference.getChild(uriStr);
|
||||
return elementOfReference(reference) as LibraryElementImpl?;
|
||||
|
@ -204,8 +197,7 @@ class LinkedElementFactory {
|
|||
for (var uriStr in uriStrSet) {
|
||||
_exportsOfLibrary.remove(uriStr);
|
||||
_libraryReaders.remove(uriStr);
|
||||
var libraryReference = rootReference.removeChild(uriStr);
|
||||
_invalidateLibrary(libraryReference);
|
||||
rootReference.removeChild(uriStr);
|
||||
}
|
||||
|
||||
analysisSession.classHierarchy.removeOfLibraries(uriStrSet);
|
||||
|
@ -230,6 +222,16 @@ class LinkedElementFactory {
|
|||
}
|
||||
}
|
||||
|
||||
void replaceAnalysisSession(AnalysisSessionImpl newSession) {
|
||||
analysisSession = newSession;
|
||||
for (var libraryReference in rootReference.children) {
|
||||
var libraryElement = libraryReference.element;
|
||||
if (libraryElement is LibraryElementImpl) {
|
||||
libraryElement.session = newSession;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Set exports of the library with [uriStr], after building exports during
|
||||
/// linking, or after reading a linked bundle.
|
||||
void setExportsOfLibrary(String uriStr, List<Reference> exports) {
|
||||
|
@ -255,11 +257,4 @@ class LinkedElementFactory {
|
|||
|
||||
libraryElement.createLoadLibraryFunction();
|
||||
}
|
||||
|
||||
void _invalidateLibrary(Reference? libraryReference) {
|
||||
var libraryElement = libraryReference?.element;
|
||||
if (libraryElement is LibraryElementImpl) {
|
||||
libraryElement.isValid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -819,12 +819,13 @@ import 'c.dart';
|
|||
],
|
||||
);
|
||||
|
||||
// All libraries are valid.
|
||||
expect(a_element.isValid, true);
|
||||
expect(b_element.isValid, true);
|
||||
expect(c_element.isValid, true);
|
||||
expect(d_element.isValid, true);
|
||||
expect(e_element.isValid, true);
|
||||
// All libraries have the current session.
|
||||
var session1 = driver.currentSession;
|
||||
expect(a_element.session, session1);
|
||||
expect(b_element.session, session1);
|
||||
expect(c_element.session, session1);
|
||||
expect(d_element.session, session1);
|
||||
expect(e_element.session, session1);
|
||||
|
||||
// Change `b.dart`, also removes `c.dart` and `d.dart` that import it.
|
||||
// But `a.dart` and `d.dart` is not affected.
|
||||
|
@ -841,12 +842,17 @@ import 'c.dart';
|
|||
],
|
||||
);
|
||||
|
||||
// Only `a.dart` and `e.dart` are still valid.
|
||||
expect(a_element.isValid, true);
|
||||
expect(b_element.isValid, false);
|
||||
expect(c_element.isValid, false);
|
||||
expect(d_element.isValid, false);
|
||||
expect(e_element.isValid, true);
|
||||
// We have a new session.
|
||||
var session2 = driver.currentSession;
|
||||
expect(session2, isNot(session1));
|
||||
|
||||
// `a.dart` and `e.dart` moved to the new session.
|
||||
// Invalidated libraries stuck with the old session.
|
||||
expect(a_element.session, session2);
|
||||
expect(b_element.session, session1);
|
||||
expect(c_element.session, session1);
|
||||
expect(d_element.session, session1);
|
||||
expect(e_element.session, session2);
|
||||
}
|
||||
|
||||
test_changeFile_potentiallyAffected_part() async {
|
||||
|
@ -880,10 +886,11 @@ import 'b.dart';
|
|||
],
|
||||
);
|
||||
|
||||
// All libraries are valid.
|
||||
expect(b_element.isValid, true);
|
||||
expect(c_element.isValid, true);
|
||||
expect(d_element.isValid, true);
|
||||
// All libraries have the current session.
|
||||
var session1 = driver.currentSession;
|
||||
expect(b_element.session, session1);
|
||||
expect(c_element.session, session1);
|
||||
expect(d_element.session, session1);
|
||||
|
||||
// Change `a.dart`, remove `b.dart` that part it.
|
||||
// Removes `c.dart` that imports `b.dart`.
|
||||
|
@ -899,10 +906,15 @@ import 'b.dart';
|
|||
],
|
||||
);
|
||||
|
||||
// Only `d.dart` is still valid.
|
||||
expect(b_element.isValid, false);
|
||||
expect(c_element.isValid, false);
|
||||
expect(d_element.isValid, true);
|
||||
// We have a new session.
|
||||
var session2 = driver.currentSession;
|
||||
expect(session2, isNot(session1));
|
||||
|
||||
// `d.dart` moved to the new session.
|
||||
// Invalidated libraries stuck with the old session.
|
||||
expect(b_element.session, session1);
|
||||
expect(c_element.session, session1);
|
||||
expect(d_element.session, session2);
|
||||
}
|
||||
|
||||
test_changeFile_selfConsistent() async {
|
||||
|
@ -1180,9 +1192,8 @@ const x = 1;
|
|||
var session2 = driver.currentSession;
|
||||
expect(session2, isNotNull);
|
||||
|
||||
// We don't discard the session anymore.
|
||||
// So, the session is always the same.
|
||||
expect(session2, same(session1));
|
||||
// We get a new session.
|
||||
expect(session2, isNot(session1));
|
||||
}
|
||||
|
||||
test_discoverAvailableFiles_packages() async {
|
||||
|
|
|
@ -134,6 +134,16 @@ class AnalysisSessionImplTest extends PubPackageResolutionTest {
|
|||
expect(errorsResult.errors, isNotEmpty);
|
||||
}
|
||||
|
||||
test_getErrors_inconsistent() async {
|
||||
var test = newFile(testFilePath, content: '');
|
||||
var session = contextFor(test.path).currentSession;
|
||||
driverFor(test.path).changeFile(test.path);
|
||||
expect(
|
||||
() => session.getErrors(test.path),
|
||||
throwsA(isA<InconsistentAnalysisException>()),
|
||||
);
|
||||
}
|
||||
|
||||
test_getErrors_invalidPath_notAbsolute() async {
|
||||
var session = contextFor(testFilePath).currentSession;
|
||||
var errorsResult = await session.getErrors('not_absolute.dart');
|
||||
|
@ -146,6 +156,16 @@ class AnalysisSessionImplTest extends PubPackageResolutionTest {
|
|||
expect(errorsResult, isA<InvalidPathResult>());
|
||||
}
|
||||
|
||||
test_getFileSync_inconsistent() async {
|
||||
var test = newFile(testFilePath, content: '');
|
||||
var session = contextFor(test.path).currentSession;
|
||||
driverFor(test.path).changeFile(test.path);
|
||||
expect(
|
||||
() => session.getFile(test.path),
|
||||
throwsA(isA<InconsistentAnalysisException>()),
|
||||
);
|
||||
}
|
||||
|
||||
test_getFileSync_library() async {
|
||||
var a = newFile('$testPackageLibPath/a.dart', content: '');
|
||||
|
||||
|
@ -180,6 +200,16 @@ class B {}
|
|||
expect(library.getType('C'), isNull);
|
||||
}
|
||||
|
||||
test_getLibraryByUri_inconsistent() async {
|
||||
var test = newFile(testFilePath, content: '');
|
||||
var session = contextFor(test.path).currentSession;
|
||||
driverFor(test.path).changeFile(test.path);
|
||||
expect(
|
||||
() => session.getLibraryByUriValid('package:test/test.dart'),
|
||||
throwsA(isA<InconsistentAnalysisException>()),
|
||||
);
|
||||
}
|
||||
|
||||
test_getLibraryByUri_unresolvedUri() async {
|
||||
var session = contextFor(testFilePath).currentSession;
|
||||
var result = await session.getLibraryByUri('package:foo/foo.dart');
|
||||
|
@ -267,6 +297,16 @@ int foo = 0;
|
|||
expect(parsedLibrary.getElementDeclaration(fooElement.setter!), isNull);
|
||||
}
|
||||
|
||||
test_getParsedLibrary_inconsistent() async {
|
||||
var test = newFile(testFilePath, content: '');
|
||||
var session = contextFor(test.path).currentSession;
|
||||
driverFor(test.path).changeFile(test.path);
|
||||
expect(
|
||||
() => session.getParsedLibrary(test.path),
|
||||
throwsA(isA<InconsistentAnalysisException>()),
|
||||
);
|
||||
}
|
||||
|
||||
test_getParsedLibrary_invalidPartUri() async {
|
||||
var test = newFile(testFilePath, content: r'''
|
||||
part 'a.dart';
|
||||
|
@ -407,6 +447,16 @@ class B {}
|
|||
expect(unitResult.unit.declarations, hasLength(2));
|
||||
}
|
||||
|
||||
test_getParsedUnit_inconsistent() async {
|
||||
var test = newFile(testFilePath, content: '');
|
||||
var session = contextFor(test.path).currentSession;
|
||||
driverFor(test.path).changeFile(test.path);
|
||||
expect(
|
||||
() => session.getParsedUnit(test.path),
|
||||
throwsA(isA<InconsistentAnalysisException>()),
|
||||
);
|
||||
}
|
||||
|
||||
test_getParsedUnit_invalidPath_notAbsolute() async {
|
||||
var session = contextFor(testFilePath).currentSession;
|
||||
var result = session.getParsedUnit('not_absolute.dart');
|
||||
|
@ -512,6 +562,16 @@ int foo = 0;
|
|||
expect(resolvedLibrary.getElementDeclaration(fooElement.setter!), isNull);
|
||||
}
|
||||
|
||||
test_getResolvedLibrary_inconsistent() async {
|
||||
var test = newFile(testFilePath, content: '');
|
||||
var session = contextFor(test.path).currentSession;
|
||||
driverFor(test.path).changeFile(test.path);
|
||||
expect(
|
||||
() => session.getResolvedLibrary(test.path),
|
||||
throwsA(isA<InconsistentAnalysisException>()),
|
||||
);
|
||||
}
|
||||
|
||||
test_getResolvedLibrary_invalidPartUri() async {
|
||||
var test = newFile(testFilePath, content: r'''
|
||||
part 'a.dart';
|
||||
|
@ -600,6 +660,16 @@ class B {}
|
|||
expect(unitResult.libraryElement, isNotNull);
|
||||
}
|
||||
|
||||
test_getResolvedUnit_inconsistent() async {
|
||||
var test = newFile(testFilePath, content: '');
|
||||
var session = contextFor(test.path).currentSession;
|
||||
driverFor(test.path).changeFile(test.path);
|
||||
expect(
|
||||
() => session.getResolvedUnit(test.path),
|
||||
throwsA(isA<InconsistentAnalysisException>()),
|
||||
);
|
||||
}
|
||||
|
||||
test_getUnitElement() async {
|
||||
var test = newFile(testFilePath, content: r'''
|
||||
class A {}
|
||||
|
@ -614,6 +684,16 @@ class B {}
|
|||
expect(unitResult.element.classes, hasLength(2));
|
||||
}
|
||||
|
||||
test_getUnitElement_inconsistent() async {
|
||||
var test = newFile(testFilePath, content: '');
|
||||
var session = contextFor(test.path).currentSession;
|
||||
driverFor(test.path).changeFile(test.path);
|
||||
expect(
|
||||
() => session.getUnitElement(test.path),
|
||||
throwsA(isA<InconsistentAnalysisException>()),
|
||||
);
|
||||
}
|
||||
|
||||
test_resourceProvider() async {
|
||||
var session = contextFor(testFilePath).currentSession;
|
||||
expect(session.resourceProvider, resourceProvider);
|
||||
|
|
Loading…
Reference in a new issue