【问题标题】:Testing source generator测试源生成器
【发布时间】:2021-11-06 06:00:33
【问题描述】:

我正在尝试测试源生成器。 生成器:

[Generator]
public class CustomGenerator : ISourceGenerator
{
    public void Initialize(GeneratorInitializationContext context) { }

    public void Execute(GeneratorExecutionContext context)
    {
        //...
    }
}

测试代码:

              Compilation inputCompilation = CreateCompilation(@"
namespace MyCode
{
    public class Program
    {
        public static void Main(string[] args)
        {
        }
    } 
}
");   
            var generator = new CustomGenerator();
             
            var driver = CSharpGeneratorDriver.Create(generator);
             
            driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);

            static Compilation CreateCompilation(string source)
                => CSharpCompilation.Create("compilation",
                    new[] { CSharpSyntaxTree.ParseText(source) },
                    new[] { MetadataReference.CreateFromFile(typeof(Binder).GetTypeInfo().Assembly.Location) },
                    new CSharpCompilationOptions(OutputKind.ConsoleApplication));

问题是 context.SyntaxReceiver 总是为空,如何解决?

【问题讨论】:

  • 您需要首先在您的Initialize 方法中注册一个语法接收器,方法是调用context.RegisterForSyntaxNotifications。见the cookbook

标签: c# roslyn roslyn-code-analysis


【解决方案1】:

让我们检查GeneratorExecutionContext.SyntaxReceiver属性的定义:

namespace Microsoft.CodeAnalysis
{
    public readonly struct GeneratorExecutionContext
    {
        // Summary:
        //     If the generator registered an Microsoft.CodeAnalysis.ISyntaxReceiver during
        //     initialization, this will be the instance created for this generation pass.
        public ISyntaxReceiver? SyntaxReceiver { get; }
    }
}

我们看到GeneratorExecutionContext.SyntaxReceiver 属性被声明为可为空,这意味着在某些情况下它确实应该为空。 文档注释显示我们首先必须在ISourceGenerator.Initialize 中注册我们的ISyntaxReceiver

正如canton7所指出的,我们首先需要通过GeneratorInitializationContext.RegisterForSyntaxNotifications方法注册它:

[Generator]
public class CustomGenerator : ISourceGenerator
{
    public void Initialize(GeneratorInitializationContext context)
    {
        context.RegisterForSyntaxNotifications(static () => new CustomReceiver());
    }

    public void Execute(GeneratorExecutionContext context)
    {
        Debug.Assert(context.SyntaxReceiver is not null, $"No {nameof(ISyntaxReceiver)} registerd via {nameof(GeneratorInitializationContext.RegisterForSyntaxNotifications)}.");

        if (context.SyntaxReceiver is not CustomReceiver receiver)
        {
            return;
        }

        Debug.Assert(receiver is not null);

        //...
    }
}

internal sealed class CustomReceiver : ISyntaxReceiver
{
    public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
    {
    }
}

请记住避免在 ISyntaxReceiver 中进行昂贵的操作,因为它不支持 取消 不像 Generator 本身。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-12
    • 1970-01-01
    • 1970-01-01
    • 2015-06-01
    • 2011-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多