I created a simple source generator that works fine
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System.Text;
namespace TestGenerator;
[Generator]
public class TestGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// Register a syntax receiver to collect information during the initial parsing phase
var classDeclarations = context.SyntaxProvider.ForAttributeWithMetadataName(
"TestGenerator.TestSourceGeneratorAttribute",
predicate: static (s, _) => (s is ClassDeclarationSyntax || s is StructDeclarationSyntax) && s is TypeDeclarationSyntax type && type.Modifiers.Any(SyntaxKind.PartialKeyword),
transform: static (ctx, _) =>
{
if (ctx.TargetNode is TypeDeclarationSyntax typeDeclarationSyntax)
{
return typeDeclarationSyntax.Identifier.ToString();
}
return null;
})
.Where(static m => m is not null);
var compilationAndClasses = classDeclarations.Collect();
// Set up the generation phase
context.RegisterSourceOutput(compilationAndClasses, static (spc, classes) =>
{
foreach (var typeDefinition in classes)
{
// Add the generated source to the output
spc.AddSource($"{typeDefinition}.g.cs",
SourceText.From(GetSource(typeDefinition), Encoding.UTF8));
}
});
}
private static string GetSource(string source)
{
return $"""
//<auto-generated/>
#nullable enable
using System;
/// {source}
""";
}
}
Added a class to a test project
namespace TestGenerator.Test
{
[TestSourceGenerator]
public partial class TestClassGenerated
{
}
}
and the source generated fine
//<auto-generated/>
#nullable enable
using System;
/// TestClassGenerated
then I created a unit test
using Microsoft.CodeAnalysis.CSharp.Testing;
using Microsoft.CodeAnalysis.Testing;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Threading.Tasks;
namespace TestGenerator.Test;
[TestClass]
public class TestGeneratorUnitTest
{
[TestMethod]
public async Task Test123()
{
// Arrange
var source = """
using System;
namespace TestGenerator.Test
{
[TestSourceGenerator]
public partial class MyClass
{
}
}
""";
var expectedGeneratedCode = @"
//<auto-generated/>
#nullable enable
using System;
/// MyClass
";
var test = new CSharpSourceGeneratorTest<TestGenerator, DefaultVerifier>
{
TestState =
{
Sources = { source },
GeneratedSources =
{
(typeof(TestGenerator), "MyClass.g.cs", expectedGeneratedCode)
}
}
};
// Act & Assert
await test.RunAsync();
}
}
and for the test it doesn't filter the class, the predicate is true but it doesn't enter in the transform
I created a repro to add here
https://github.com/luizfbicalho/TestSourceGenerator
I expect the test to generate the MyClass File
I got help and this is the solution
I missed the references
var references = AppDomain.CurrentDomain.GetAssemblies()
.Where(a => !a.IsDynamic && !string.IsNullOrWhiteSpace(a.Location))
.Select(a => MetadataReference.CreateFromFile(a.Location))
CSharpCompilation compilation = CSharpCompilation.Create(
assemblyName: "Tests",
syntaxTrees: new[] { syntaxTree },
references: references,
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, nullableContextOptions: NullableContextOptions.Enable));