はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Unity】UnityでSourceGeneratorのAdditionalFilesを用いてファイル読み込みをしたい場合はcsc.rspをasmdefと同階層に配置する

はじめに

今回はUnityでIncremental Source GeneratorAdditionalTextsProviderを利用する方法を紹介したいと思います。

その前に

どこかのバージョンから?かSource GeneratorSystem.IOを利用できなくなったみたいです。

context.RegisterSourceOutput(sampleProvider, (context, syntax) =>
{
    // 「アナライザーに対して禁止された API を使用しない」というエラーが出る
    var txt = System.IO.File.ReadAllText("path-to-txt");
});

RS1035: シンボル 'File' はアナライザーによって使用禁止です: Do not do file IO in analyzers

おそらく入力に対して一意に出力が決まるべきという思想があるのだと思います(多分)。特にIncrementalを実現するためには、それが重要なのかと。

AdditionalFilesを利用してファイルを読み込む

そこでAdditionalFilesを利用することで、指定したパスにあるファイルを読み取ることができます。やり方としては.csprojに以下を追加してあげます。

<ItemGroup>
    <AdditionalFiles Include="読み取りたいファイルへのパス" />
</ItemGroup>

これを受け取るにはAdditionalTextsProviderを利用してあげます。

[Generator(LanguageNames.CSharp)]
public class SampleSourceGenerator : IIncrementalGenerator
{
    public void Initialize(IncrementalGeneratorInitializationContext context)
    {
        var provider = context.AdditionalTextsProvider;

        context.RegisterSourceOutput(provider, static (context, additionalText) =>
        {
            var source = 
                $$$"""
                // FilePath : {{{additionalText.Path}}}
                """;
            
            context.AddSource("Sample.Generated.cs", source);
        });
    }
}

Unityでの場合

Unityでは.csprojは自動生成されるため、基本的にユーザーは追記することができません。そこでcsc.rspを利用することで実現できます。ファイルを置く場所はAdditionalFilesの定義を加えたい.asmdefと同階層です。(.asmdefを利用していない場合はAssets/csc.rps)


csc.rsp

/additionalfile:Assets/Scripts/Definition/Sample.cs

ちょっとした裏技(?)

AdditionalFilesとして.csを読み取り、SourceGenerator上で構文解析するという裏技もあったりします。これを利用すれば、アセンブリを超えて色々できちゃいます。

var provider = context.AdditionalTextsProvider
            .Where(x => x.Path.EndsWith("Hoge.cs"));

context.RegisterSourceOutput(provider, static (context, additionalText) =>
{
    // additionalTextから構文解析
    SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(additionalText.GetText());
            
    // 色々中身を解析していく...
    // やろうと思えばコンパイルもできるはず
});