roslyn-sdk
roslyn-sdk copied to clipboard
Weird behavior with Initialize
Hi,
I hope this is the right repository to report the this issue.
I'm doing some test with code generator for a new project, I'm following the samples here:
https://github.com/dotnet/roslyn-sdk/tree/main/samples/CSharp/SourceGenerators/SourceGeneratorSamples
I saw in the documentation that Roslyn apparently works only for Visual Studio, nevertheless, I tried with Rider 2020.3 on my Mac, and I found that it works pretty fine.
In Rider the code looks broken before the first build, but after building the solution looks perfect as if the code were defined in the project, I can see the generated code.
The weird behavior occurs when I register a SyntaxReceiver in the Initialize method, the build still pass and the code is executed, but neither Rider nor in Visual Studio for Mac recognize the generated code.
This is my Target
project
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<OutputType>Exe</OutputType>
<LangVersion>9</LangVersion>
</PropertyGroup>
<PropertyGroup>
<RestoreAdditionalProjectSources>https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json ;$(RestoreAdditionalProjectSources)</RestoreAdditionalProjectSources>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Source\Source.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.3" PrivateAssets="all" />
<PackageReference Include="Microsoft.Net.Compilers.Toolset" Version="3.10.0-1.final" PrivateAssets="all" />
</ItemGroup>
</Project>
This is the Source project
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<LangVersion>9</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.2" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Compilers" Version="3.10.0-1.final" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.10.0-1.final" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Features" Version="3.10.0-1.final" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.10.0-1.final" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.10.0-1.final" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.3" PrivateAssets="all" />
</ItemGroup>
</Project>
This generated code work perfect
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
namespace Source
{
[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("HelloWorld.Generated.cs", SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));
}
}
}
This is the code with the problem
using System;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
namespace Source
{
[Generator]
public class DisplayStringGenerator : ISourceGenerator
{
const string DisplayStringAttributeCode = @"using System;
namespace ModelUtils
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class DisplayStringAttribute : Attribute {
public DisplayStringAttribute() { }
public string Exclude { get; set; }
}
}
";
public void Initialize(GeneratorInitializationContext context)
{
context.RegisterForSyntaxNotifications(() => new SyntaxReceiver());
}
public void Execute(GeneratorExecutionContext context)
{
GenerateAttribute(context);
ProcessClass(context);
}
private void GenerateAttribute(GeneratorExecutionContext context)
{
context.AddSource("DisplayStringAttribute.Generated.cs",
SourceText.From(new StringBuilder(DisplayStringAttributeCode).ToString(), Encoding.UTF8));
}
private void ProcessClass(GeneratorExecutionContext context)
{
}
class SyntaxReceiver : ISyntaxContextReceiver
{
public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
{
//TODO: Implement it
}
}
}
}
I moved the Attribute code to the Execute method to make it work, because adding the code through the Initialize method has the same weird behavior.
I'm not sure if this is a bug or I'm missing something in my code.
@ovargasmahisoft were you trying to add the attribute code using context.RegisterForPostInitialization
as the AutoNotify sample does? If so that's only supported in VS16.9+
Hi @chsienki thanks for your response.
Yes I tried that way and the code builds and runs fine but the IDE doesn't recognize it, it is ok if this is a IDE issue for now. What I find weird, is that even the HelloWorld sample fails to recognize the code just after registering a SyntaxReceiver.
when I register a SyntaxReceiver in the Initialize method
You definitely don't want to do this. There is no way to use RegisterForSyntaxNotifications
from the V1 API without causing an overwhelming performance hit for anything but the smallest of solutions. For syntax callbacks, you'll want to rewrite the source generator using IIncrementalGenerator
which was added in Roslyn 4.0 and resolves this problem.
We tried hard to find viable workarounds that allow SyntaxReceiver
to work without problems, but were never successful.