Source Generator の Visual Studio 2019 v16.9 での新 API
Created at:
Source Generator を触っていて気づいたのですが Visual Studio 2019 version 16.9 の段階でいくつか API が追加されていました。
- dotnet/roslyn: Source Generator semantic model visitor #49873
- dotnet/roslyn: Allow access to semantic model during syntax walk #50419
- dotnet/roslyn: Implement PostInitialization in generator driver #50026
追加されたものは次のようなあるといいよねといった API が増えている感じです。
GeneratorInitializationContext.RegisterForPostInitialization
メソッドISyntaxContextReceiver
インターフェース
Visual Studio 2019 であれば 16.9 以降、NuGet パッケージであれば Microsoft.CodeAnalysis.CSharp 3.9.0 を参照すれば使用できます。
GeneratorInitializationContext.RegisterForPostInitialization
メソッド
GeneratorInitializationContext.RegisterForPostInitialization
メソッドは Source Generator が読み込まれて初期化された後に呼び出されるコールバックを登録できます。
これは Source Generator で必要となる属性用のコードを追加したいパターンに役立ちます。例えば次のようなコードがサンプルにあります。
[Generator]
public class AutoNotifyGenerator : ISourceGenerator
{
private const string attributeText = @"
using System;
namespace AutoNotify
{
[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
[System.Diagnostics.Conditional(""AutoNotifyGenerator_DEBUG"")]
sealed class AutoNotifyAttribute : Attribute
{
public AutoNotifyAttribute()
{
}
public string PropertyName { get; set; }
}
}
";
public void Initialize(GeneratorInitializationContext context)
{
// Register the attribute source
context.RegisterForPostInitialization((i) => i.AddSource("AutoNotifyAttribute", attributeText));
// Register a syntax receiver that will be created for each generation pass
context.RegisterForSyntaxNotifications(() => new SyntaxReceiver());
}
...
}
今までソースで指定したい属性をどうするかという問題があった(一度生成させてその属性を使うのか、手で追加するのかとか)のがこれで解決できそうです。
ISyntaxContextReceiver
インターフェース
コンパイラーがソースコードを処理する際に Source Generator を呼び出す ISyntaxReceiver
インターフェースがあります。
例えばクラス定義に対するコードジェネレートを行いたいときには自分でシンタックスツリーを走査して集めるのではなく、ツリーの走査はコンパイラーに任せて、 ClassDeclarationSyntax を集めておいて最後に処理するといった使い方です。
ISyntaxReceiver
インターフェースは OnVisitSyntaxNode
メソッドのみをもち引数として SyntaxNode
を受ける形でしたが、 ISyntaxContextReceiver
では GeneratorSyntaxContext
を受け取る形になります。
このコンテキストオブジェクトにはセマンティックモデルが含まれているので、Receiver で必要なものをかき集めるときに、コードの解析された情報にアクセスできるようになります。
例えば属性はセマンティックモデルを通してシンボルを取得して、GetAttributes で取得できるので、Source Generator 用の属性がついていることを Receiver が集める段階で確認できます。こちらもサンプルコードが例としてわかりやすいです。
注意
16.9 で追加された API なので古い Visual Studio や .NET SDK では動かない可能性があります(試していない)。
Rider 2021.1.2 ではビルドは問題ないのですが Rider 側が対応していないようでエディター上では正しく動作しなかったりしたので、2021年5月頭時点では使うにはちょっと早いかもしれません。