I'm writing a Roslyn source generator, where I need to grab the initializer from the VariableDeclaratorSyntax.Initializer of a field, and echo it back into a generated file.
For example, if I wrote this code....
using MyNamespace.SomeStuff;
...
partial class Bar
{
[Convert]
Foo _fooField = Foo.Baz;
}
My source generator might produce...
partial class Bar
{
MyNamespace.SomeStuff.Foo _fooField = MyNamespace.SomeStuff.Foo.Baz;
}
I can get the fully-qualified field Type easily, via IFieldSymbol. However, I don't know how to get a fully-qualified version of the initializer.
This value can be anything. It need not be a static; it could be nested constructors for custom classes; etc. I need to fully-qualify all of the symbols, and print out the result as a string that I can insert into my generated code without bothering with usings.
I think I need to make a custom CSharpSyntaxRewriter that visits the proper nodes and replaces the names with a resolved version from the SemanticModel. But there isn't much information on the internet on how to do this.
Here's what I've got so far:
public override SyntaxNode? VisitMemberAccessExpression(MemberAccessExpressionSyntax node)
{
var symbol = SemanticModel.GetSymbolInfo(node);
if (symbol.Symbol is not null)
return node.WithName(SyntaxFactory.IdentifierName(symbol.Symbol.ToString()));
else return base.VisitMemberAccessExpression(node);
}
But instead of MyNamespace.SomeStuff.Foo.Baz it produces Foo.MyNamespace.SomeStuff.Foo.Baz which obviously doesn't work. I need to use WithExpression instead of WithName, but the expression could be anything and I don't know how to narrow it down.
Any ideas? Is there a better way of doing this?
EDIT: As requested, here's the full context:
[Generator]
public class StyleSourceGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// find any field tagged with [Convert]
var fields = context.SyntaxProvider.ForAttributeWithMetadataName(typeof(ConvertAttribute).FullName,
(node, token) =>
{
return node is VariableDeclaratorSyntax;
},
(ctx, token) =>
{
var syntax = (VariableDeclaratorSyntax)ctx.TargetNode;
syntax.Initializer.Value.ToString(); // this will print Foo.Baz, when I need it to print MyNamespace.SomeStuff.Foo.Baz
});
}
}
var symbol = SemanticModel.GetSymbolInfo(node);where does SemanticModel come from? More generally, can you provide a MRE of your source generator and syntax rewriter?