Recently I was struggling with actually getting the 'roslyn source code generator' to generate things available to my other project inside Rider.
Storing this as a memo for the exact things that made this work so I have a good baseline to branch out from in the future. Might help someone.
Setup the project
- New Solution
-- Generator (class library, netstandard2.0)
-- MyConsoleApp (console app, netstandard2.0)
ManageNuGetPackages
- Microsoft.CodeAnalysis.Analyzers
- Microsoft.CodeAnalysisCSharp.Workspaces
- Microsoft.Compilers.Toolset
- NetStandard.Library 2.x.x
MyConsoleApp-project
Add a dependency to Generator, and then modify the .csproj file like this
<!-- Add this as a new ItemGroup, replacing paths and names appropriately -->
<ItemGroup>
<ProjectReference Include="..\Generator\Generator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Net.Compilers.Toolset" Version="4.3.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
Generator-project
Adding launchsettings.json
Create a file at ./Properties/launchSettings.json and paste the following code inside it (I had to create the Properties-Directory inside Rider)
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"Generators": {
"commandName": "DebugRoslynComponent",
"targetProject": "../MyConsoleApp/MyConsoleApp.csproj"
}
}
}
Create the Generator-file
Create a file called HelloWorldGenerator.cs and paste this content inside it
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
namespace Generator;
[Generator]
public class HelloWorldGenerator : ISourceGenerator
{
public void Initialize(GeneratorInitializationContext context)
{
}
public void Execute(GeneratorExecutionContext context)
{
// begin creating the source we'll inject into the users compilation
var sourceBuilder = new StringBuilder(@"
using System;
namespace HelloWorldGenerated
{
public static class HelloWorld
{
public static void SayHello()
{
Console.WriteLine(""Hello from generated code!"");
Console.WriteLine(""The following syntax trees existed in the compilation that created this program:"");
");
// using the context, get a list of syntax trees in the users compilation
var syntaxTrees = context.Compilation.SyntaxTrees;
// add the filepath of each tree to the class we're building
foreach (SyntaxTree tree in syntaxTrees)
{
sourceBuilder.AppendLine($@"Console.WriteLine(@"" - {tree.FilePath}"");");
}
// finish creating the source to inject
sourceBuilder.Append(@"
}
}
}");
// inject the created source into the users compilation
context.AddSource("helloWorldGenerator", SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));
}
}
End result
after doing a couple of attempts at
- Reload project
- Restart Rider
- Rebuild Solution
Inside the console app it should now be possible to write
HelloWorldGenerated.HelloWorld.SayHello();
And inside the 'solution view' you should be able to see the following by expanding
/MyConsoleApp/Dependencies/.NetStandard2.0/Source Generators/Generator.HelloWorldGenerator