-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Analysis driver returns cached results from a previous session after an exception occurs during analysis #53839
Comments
Actually, it's unrelated to the assignment, it fails when the file is not modified (there's no overlay). If I update the code like:
This still fails as long as the file is saved and has no overlay (note: in VS Code/LSP we no longer create overlays until their contents is different to what's on disk). @scheglov I'm failing to reproduce this in a test (by creating a file with the contents above, then initializing the server, then testing Go-to-Definition). Any ideas what could be triggering it? (I wondered if there was some different between loading the cached data from disk versus when it's analyzed in memory but I feel like I'm doing the same thing in a test). |
Works for me, I can navigate from |
It also works for me using VSCode with an SDK built yesterday. |
Ok, this is weird :-)
So deleting everything in I'll do some more investigation.. there's definitely some bug here! |
Ok, I tracked this down. It seems to happen when I have another file in my project with the contents from another bug I had repro'd: enum MyEnum {
enumValue(["text"].map((x) => x));
const MyEnum(this.strings);
final Iterable<String> strings;
} When I have that file, my instrumentation log has this error for that other file (#53793):
And when that occurs, it seems to prevent this Go-to-Definition from working (in the original file, not the one failing analysis). I don't know why it stops that from working but doesn't stop other things from working. So my project contains the two files above looking like this, and both files are saved, and then I run Developer: Reload Window so that they have not been modified (and don't have overlays). Then Go-to-Definition on My theory is that when initial analysis fails for a file, maybe it's not fully analyzing the rest of the project. Modifying the file triggers new analysis of that file that fills in some missing data? |
Just to confirm, are you using a recent build? @kallentu In case you have context. |
I can repro running from current source. I'm struggling to repro in a test, however I found some new information... it only happens if I already have the file open when I open the project (eg. VS Code restores the open file). If I open the project with no open files, then open the file, it doesn't reproduce. If I run Developer: Reload Window it then repros. I feel like it should be easy to reproduce this at least in an integration test, I'll review the log and see if I'm missing something different in my test. |
I should have reviewed the log more closely earlier. The server isn't returning no definitions, it's returning an error:
This is not a timing issue, because I can wait 5 minutes and then try to invoke |
I still haven't been able to trigger this in a test (I think it's quite timing dependent), but I did strip down the VS Code impl to a clearer log.. It happens because when we're getting definitions, we end up getting a resolved unit that has an older session than the one the driver has and then the consistency check fails. Log here: It seems that during the definition request we try to get a I'll continue digging tomorrow. My feeling is that this only occurs when there is an analysis exception during initial analysis, but it seems to also rely on specific timing of when we open the file (at least, that's the only real difference between this and my integration test that I can see). |
I was able to get a repro for this in an integration test. It requires The issue seems to be that (after there was an exception analyzing the other file during initialisation), when we need to get
A change that adds a failing test and some debugging info (note: it has hard-coded paths) is here: branch: https://github.com/DanTup/sdk/tree/bad-definition-issue I'm not sure whether the bug here is a) creating a new session when fetching the LineInfo or b) later getting a resolved unit with an older session. My feeling is that it's the former, but I'm not certain. This might need some input from someone with a better understanding of this than I have. |
The intent is that we should create a new session whenever something has changed in a way that might make new results incompatible with old results. I'm not sure why getting an exception while attempting to analyze a file would cause us to create a new session, so (a) might be a bug. But once we've created a new session we ought to fail any attempt to use an older session. So if that's what's causing the exception in (b), then that's expected. |
To clarify, we're not creating a new session when the exception occurs - the new session is created when we're trying to create the LineInfo (we call
Yep, that makes sense. But it seems odd that we create a new session (ID 4 in my log above, triggered by |
That sounds like a bug. If the The only hole I could think of is if we asked the old session (3) for a result before it was obsolete but didn't get a result back until after it was obsolete. I suspect we only check the state of the session on entry and not on exit from each method. But given the nature of async code I don't think that checking on exit would completely protect against such an event anyway. |
I feel like something is definitely wrong here then. I added this code into the definition handler: {
final log = AnalysisEngine.instance.instrumentationService.logInfo;
log('##### START #####');
var driver = server.getAnalysisDriver(path)!;
log('Driver session ID is ${driver.currentSession.thisId}');
final result = await driver.getResult(path) as ResolvedUnitResult;
log('Result has session ID ${(result.session as AnalysisSessionImpl).thisId}');
log('##### END #####');
} And this is what's in the log:
As far as I can tell, no other code was running at the same time as this. The code to get a I'll try to debug more to understand what's going on. I thought it was worth posting my findings here in case it rang any bells for those more familiar with this code than I. Seems like this behaviour might be as surprising to you as me though :-) |
@scheglov In case you have ideas. |
Ok, I think I understand what's happening. Whenever there is an analysis exception, we call
However, there are cached (priority) results that are still hanging around referencing the previous session:
That means Driver with Session X can still serve up cached results with session X-1. I'm not too familiar with this code so this is probably one for @scheglov, but I wonder if Note: Because #53793 is fixed, it'll be harder to repro this. I'm still using a branch that doesn't include that change: https://github.com/DanTup/sdk/tree/bad-definition-issue |
I think you are right, and we should clear everything, including cached resolved units, on exception. |
…tAfterException(). Bug: #53839 Change-Id: I7de4e5b518b51239d4bd0251286960e619e6bc6a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/332747 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Thanks! :) |
Given this file:
If I invoke Go-to-Definition on
Person2
at the end (4), it doesn't work:However if I add
var a =
in front of the call, it then works,If I then remove
var a =
again, the original reference works.The text was updated successfully, but these errors were encountered: