-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Light bulb does not invoke code fix provider for diagnostics created in compilation end action #51653
Comments
In fact, any diagnostics I report in the compilation end action behave this way: context.RegisterCompilationEndAction(context =>
{
foreach (var tree in context.Compilation.SyntaxTrees)
{
context.ReportDiagnostic(Diagnostic.Create(
DiagnosticDescriptors.ExampleDiagnostic,
Location.Create(tree, new(0, tree.Length))));
}
}); While the same diagnostics reported in the symbol action work properly: var didReport = 0;
context.RegisterSymbolAction(context =>
{
if (Interlocked.Exchange(ref didReport, 1) == 1) return;
foreach (var tree in context.Compilation.SyntaxTrees)
{
context.ReportDiagnostic(
Diagnostic.Create(DiagnosticDescriptors.ExampleDiagnostic,
Location.Create(tree, new(0, tree.Length))));
}
}, SymbolKind.NamedType); |
Let me know if there's any trouble reproducing the behavior, and I can create a full solution or take traces. |
Tagging @mavasani . But i'm fairly certain this is a known limitation we have. Compilation-end analyzers are too expensive for us to run in the IDE, so they are just not run. This leads to this unfortunate outcome. |
Does that mean my only option (besides giving up) is to eagerly walk the entire compilation inside one of the other callbacks, just so I can report the diagnostic inside a callback where there can actually be a light bulb fix? |
But the fact is that diagnostics reported by the end action are shown in source and in the error list, so even if they are only gotten OOP, the IDE should be able to pass them to the code fix provider in-process. |
Yes, that is correct. Build-only/compilation end diagnostics only contribute to the build, not the code fix process. Otherwise, pressing Ctrl + Dot after every edit will have to analyze the whole project instead of just the current file. This was experimented in the past, and turned out to be un-dogfoodable. |
@mavasani Why is it necessary to run an analyzer to invoke the code fix provider, given that the diagnostic is already being shown in the source file and the light bulb was invoked on it? |
@jnm2 All analyzer diagnostics are potentially stale as soon as the user edits the code. Code fixes always get the up-to-date diagnostics for the latest source snapshot. |
I have two asks: A) Can rerunning the analyzer be skipped before calling the code fix provider if the source text is identical to what was originally analyzed? B) In the meantime, it looks like I'll have to analyze all operations in the compilation during some callback other than the compilation end action. I get how bad that sounds, but what's the least bad way to implement that now that I can't really use the compilation end action? Maybe I can cache information about source texts myself from analyzing previous versions of the compilation? |
Unfortunately, it cannot be skipped unless we can ensure that all of the files in the compilation and all of the references are identical, as any of this can cause compilation end diagnostics to change. |
What's the hardest part about tracking whether any source text or reference has changed? Also, I've been coding my code fixes to assume diagnostics may be stale and recheck everything as part of the process of finding the pieces needed to do the fix. Is that not a responsibility that falls to code fix providers already? If VS is sort of helping them out in case they don't do proper staleness checks, what if VS only looks for changes in the source text that contains the diagnostic before deciding whether to rerun the analyzer? |
No, the design has always been that code fixes will get up-to-date diagnostics for the document/solution snapshot handed to it.
Its probably not hard, but attempting to re-use diagnostics from previous snapshots has always been a non-goal. Compilation-end diagnostics have always been assumed to be build-only diagnostics, similar to compiler's unused field warning, it was never designed for full-fledged IDE support due to performance concerns. |
@mavasani could we have the engine instead be lazy? essentially dismiss compilation end diagnostics whenever the solution snapshot they come from is not the current one? That would mean the lightbulb item would go away as soonn as things are not up-to-date, but a user could still apply codefixes from the ide. As it stands today the only way someone could apply a codefix that does compilation-end-analysis is to use |
This is interesting. I would be curious on your thoughts here Manish. Because a code fix always needs to reanalyze the code to recreate the state needed for a diagnostic, it seems interesting to say: i will try to recreate my state, knowing that that might fail in teh current snapshot of hte world, using teh older diag. |
FYI, Stephen Toub is proposing that dotnet/runtime ships exactly the same analyzer and fixer that I created which suffers from not being fixable due to the issue I reported above: dotnet/runtime#49944 |
Design meeting notes 8/30/21:
-- We will continue talking to the platform team about how we ensure good visibility/discoverability around potentially high-impact perf changes. |
Duplicate of #1535 |
Repros in Visual Studio 3.9.0 (and 3.8.6) both as a NuGet package and a VSIX. Diagnostics are reported on all declared types.
If I report diagnostics from the compilation end action, they show up properly, but my code fix is never invoked when I bring up the light bulb. If I report the same diagnostics from the symbol action, they show up the same, and my code fix is invoked when I bring up the lightbulb. Am I abusing the API, or is there a Roslyn bug?
Repro steps:
RegisterCodeFixesAsync
was not called.RegisterCodeFixesAsync
was called.Minimal repro is below. If you want to know why I'm using this pattern, the motivating source is at https://gist.github.com/jnm2/3b45cd503e28fc3341e9e2453c148f5f.
The text was updated successfully, but these errors were encountered: