dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
18.74k stars 3.99k forks source link

Intellisense, Syntax highlight and Error Window are badly broken with incremental source generator in Visual Studio 17.0.4 #58523

Closed dotfede closed 2 years ago

dotfede commented 2 years ago

Version Used:

Visual Studio 2022 17.0.4 Microsoft.CodeAnalysis.Analyzers 3.3.3 Microsoft.CodeAnalysis.CSharp.Workspaces 4.0.1

Steps to Reproduce:

  1. Clone the repro project
  2. Open SourceGenerator.IntellisenseBug.Demo.sln in Visual Studio 2022 17.0.4
  3. Build the solution
  4. Observe the following behavior:

IntellisenseBugDemo

Expected Behavior:

Actual Behavior:

More details:

The source generator creates a single file with several empty C# classes named Class1, Class2, Class3 and so forth, depending on the number of classes declared in the consuming project in the first variable declaration:

Using <ProjectReference/> and <PackageReference/> to consume the source generator, in both cases the behavior is the same.

sharwell commented 2 years ago

@jasonmalinowski It seems likely that this line would either throw an exception while the new variable declaration is being typed, or fail to look specifically at the value for classes and start using the wrong variable:

https://github.com/fberasategui/SourceGenerator.IntellisenseBug.Demo/blob/59a6088c11615ed1fbd82da5a0a270c3107b17bd/SourceGenerator.IntellisenseBug.Demo/Class1.cs#L22

There is certainly a bug with the source generator itself, but it's not clear whether or not recovery is expected in this case.

jasonmalinowski commented 2 years ago

@chsienki could comment better on recovery from the incremental generator API.

jasonmalinowski commented 2 years ago

I'd expect that in the face of exceptions we'd either give no output (which maybe is what's happening here when the classes all disappear) or we'd keep reusing stale stuff. But the fact we don't snap back when there isn't an exception again is odd.

sharwell commented 2 years ago

It's also possible that c11 ends up before classes after the call to collect values, which would cause this to always evaluate to 0:

https://github.com/fberasategui/SourceGenerator.IntellisenseBug.Demo/blob/59a6088c11615ed1fbd82da5a0a270c3107b17bd/SourceGenerator.IntellisenseBug.Demo/Class1.cs#L31-L34

dotfede commented 2 years ago

@sharwell that wouldn't explain why the build actually succeeds (given that the code is referencing source-generated symbols such as Class3, Class5 and so on), but the IDE reports errors and fails to do syntax lightlight.

Though it's possible that my code is buggy, this is simply a toy project to demonstrate the issue. In practice my generator is much more complex, and involves network calls, but this was the smallest, simplest repro I could come up with.

The original source generator exhibits the same behavior: all out of a sudden, syntax highlight and intellisense stop working, Solution explorer reports "this generator is not generating files", and ctrl+clicking on source-generated classes stops working too. However, ctrl+B building the solution reports "build succeeded".

sharwell commented 2 years ago

I'm feeling more certain that this issue is a duplicate of #54098. We'll know for sure once we can test to see if an exception is getting thrown during an incremental update.

sharwell commented 2 years ago

I'm now 100% certain that the reproducer above is a duplicate of #54098. If you fix the transformation function to no longer throw a NullReferenceException the issue is completely resolved.

transform: (ctx, _) => ((VariableDeclarationSyntax)ctx.Node).Variables.FirstOrDefault()?.Initializer?.Value.ToString());

I'm not sure it's necessary to include both the call to FirstOrDefault() and null-check the Initializer, but I verified that the above does resolve the issue.

sharwell commented 2 years ago

Duplicate of #54098

sharwell commented 2 years ago

I filed #58625 for the failure to recover from an error.