我正在编写一个Roslyn源代码生成器,我需要从字段的VariableDeclaratorSyntax.Initializer
中获取初始化器,并将其回显到生成的文件中。
例如,如果我写了这段代码...
using MyNamespace.SomeStuff;
...
partial class Bar
{
[Convert]
Foo _fooField = Foo.Baz;
}
我的源发生器可能会产生...
partial class Bar
{
MyNamespace.SomeStuff.Foo _fooField = MyNamespace.SomeStuff.Foo.Baz;
}
我可以通过IFieldSymbol
轻松获得完全限定的字段Type
。但是,我不知道如何获得初始化器的完全限定版本。
这个值可以是任何值。它不必是静态的;它可以是自定义类的嵌套构造函数;我需要完全限定所有的符号,并将结果打印为一个字符串,我可以将其插入到生成的代码中,而无需使用。
我想我需要做一个自定义的CSharpSyntaxRewriter
,它访问正确的节点,并将名称替换为SemanticModel
的解析版本。但是在互联网上没有太多关于如何做到这一点的信息。
这是我目前得到的:
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);
}
但是它产生的不是MyNamespace.SomeStuff.Foo.Baz
,而是Foo.MyNamespace.SomeStuff.Foo.Baz
,这显然不起作用。我需要使用WithExpression
而不是WithName
,但表达式可以是任何东西,我不知道如何缩小范围。
有办法吗?有更好的办法吗?
编辑:根据要求,这里是完整的背景:
[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
});
}
}
1条答案
按热度按时间ujv3wf0j1#
我找到了一个解决我案子的办法,但我不知道它是否无懈可击。可能有一些东西(比如构造函数,也许?),这将不会举行了,但这工程的成员访问。
我很感激关于如何使它更强大的建议/编辑。
从我原来的例子中,得到正确的初始化器: