I'm working on a large code base with multiple linked projects, so I've decided to write some source generators to auto-generate some boilerplate code. My project structure looks something like this:
GeneratorProject (.NET standard 2.0 C# source generators)
^
CoreProject (.NET 8 C# class library)
^
UIProject (.NET 8 Blazor)
GeneratorProject generates code into CoreProject, and CoreProject is used by UIProject. Everything works just fine in CoreProject. For example: GeneratorProject creates a static class named MyObjects into CoreProject with a list of static readonly objects for convenience. When I write code within CoreProject, I can type MyObjects. and Intellisense will show me a list of every static object in MyObjects.
My problem: If I'm typing code within UIProject, and I type MyObjects., no such list of suggestions appears. The suggestion for even just MyObjects doesn't appear while typing that out. If I end up typing a valid object name within MyObjects, it does get recognized and compiles (no syntax errors and hovering over the fully-typed out name shows its definition like normal).
Not having those suggestions come up while typing defeats the convenience of generating these lists of static objects - the list may be very long and the names not the easiest to remember without typing suggestions. This is just one example of what I'm using generators for to illustrate the problem.
How could I get Intellisense suggestions that show me objects built by source generators within UIProject?
Things I've tried: I can emit compiler-generated files in CoreProject, and ignore those files on build. The idea came from here when researching how to solve this problem: https://github.com/dotnet/roslyn/issues/50451#issuecomment-1609304299
I add this to CoreProject.csproj:
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(ProjectDir)_generated</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<NoWarn>1701;1702</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<NoWarn>1701;1702</NoWarn>
</PropertyGroup>
<Target Name="SkipSourceGeneratedFiles" BeforeTargets="CoreCompile">
<ItemGroup>
<Compile Remove="_generated/**/*" />
</ItemGroup>
</Target>
This causes all my generated files to appear in the solution explorer under the _generated folder. This does make typing suggestions work in UIProject, but a new problem appears: Visual Studio sees two copies of every generated file and shows an error (red squiggle) under every spot I reference something from a generated file. All the errors are CS0229: Ambiguity between 'MyObjects.something' and 'MyObjects.something'. The program still builds and runs just fine, since the csproj indicates anything in the _generated folder gets excluded from build, so only the real generator files get built. But most files now have false positive errors all over the place, which in the Visual Studio error list are indistinguishable from real errors, which will be unacceptable when working with a larger team. However, if there is a way to suppress CS0229 in Visual Studio, that would solve my problem enough that I could work with it.
Something else I've tried: I've been messing around with attaching GeneratorProject directly to UIProject, alongside CoreProject. This way I'd be creating generated code in both CoreProject and UIProject. The generators would work exactly how they do now for CoreProject. But I'd add code to the generators to detect if the current project has a reference to an assembly that references GeneratorProject. If it does, it'd basically generate the same files it's generating for CoreProject, but the generated files for UIProject would just reference the ones in CoreProject. An example:
The generator is creating this file in CoreProject:
namespace CoreProject.GeneratorOutput;
public static class MyObjects
{
public static readonly SomeObject something = new("this is an example");
}
When the generator runs on UIProject, it'd check if UIProject references a project that references GeneratorProject. It does - it finds CoreProject. In the generator, I'd know what this generator created for CoreProject. So it'd generate something like this for UIProject:
namespace UIProject.GeneratorOutput;
public static class MyObjects
{
public SomeObject something => CoreProject.GeneratorOutput.MyObjects.something;
}
This kind of pattern could work for static classes that are just a list of static objects like this, though the generator code would have to get a bit uglier. However, this MyObjects example is only one generator use case I have - I have other generators that do things like generate properties on non-static objects. This pattern wouldn't work for those - I'd have to do something like generate a class that inherits from the CoreProject class and change the property names slightly, which would get really ugly and not really usable.
Bottom line: Has anyone dealt with this issue before, and know of a workaround or a fix?
For technical details: I'm using Visual Studio 2022 Enterprise version 17.9.5, my core and UI projects are in C# and on .NET 8, and my generator project is using Microsoft.CodeAnalysis.CSharp version 4.6.0. I'd be happy to provide more info if it helps!
EDIT
I've created a minimal reproduction if this issue: https://github.com/mpagliaro98/IntellisenseTest
In the example, GeneratorProject generates a static class into CoreProject with the namespace CoreProject.GeneratorOutput. The problem can be demonstrated on Home.razor (UIProject > Components > Pages > Home.razor). You can type out the full MyObjects.something and once it's fully typed, Visual Studio recognizes it. But while you're typing, the final result doesn't appear in the text suggestions at all. But typing out CoreClass.SomeFunction(), which was not created by the generator, appears in the suggestions just fine. You can also demonstrate this in UIProject > UIProjectClass.cs, which just shows the issue on a regular cs file and not a razor file. CoreProject > CoreClass.cs also shows how this isn't a problem in the project where the generated code lives - typing out MyObjects. gives proper suggestions.
I put a block of commented-out code in CoreProject.csproj, and un-commenting that will show what I tried to do in the "things I've tried" section. Typing suggestions will work properly in UIProject with that un-commented, but now Visual Studio will think there's duplicates of every generated object, and show syntax errors even though everything compiles. You may need to clean, then build, then restart visual studio to see the syntax errors due to how Visual Studio caches generators and their output.
