Roslyn コードリーティング
2021/03/19
Roslyn コードリーディングことはじめ
roslyn のコードは
で公開されている.
git clone して Restore.cmd を実行.
Visual Studio で開いてビルドもできた.
SourceGenerator コードリーディング
SourceGenerator のコア機能は Compilers/Core/Microsoft.CodeAnalysis/SourceGeneration
以下にある.
ISourceGenerator
から参照をたどってみる.
ISourceGenerator
は 100 個以上の参照があるが,てきとうにめぼしを付けて参照元をさぐっていく.
MIcrosoft.CodeAnalysis.CommonCompiler#ResolveAnalyzersFromArguments
の out
引数に ImmutableArray<ISourceGenerator> generatos
を発見. ImmutableArray<ISourceGenerator>
の精製方法が気になるが,ここでは後回しにして,これの参照元をたどっていく.
するとこれは Microsoft.CodeAnalysis.CSharp.CSharpCompiler
で override されていることがわかる.
さらにこれは Microsoft.CodeAnalysis.CommonCompiler#RunCore
で呼ばれていることがわかり,ここでSourceGenerator のインスタンスを得たあと,RunCore
-> CompileAndEmit
-> RunGenerators
-> CSharpCompiler#RunGenerators
-> CSharpGeneratorDriver.Create
と渡されていく.あとは driver.RunGeneratorsAndUpdateCompilation
で実際に SourceGenerator によるコード生成が行われるようだ.
ここで RunGenerators の呼び出し元である CommonCompiler#RunGenerators
にもどってみると,なにやら SourceGenerator で生成された SourceText をファイルに書き出している箇所 (CommonCompiler.cs#L992) を発見.
ではこれはどこに吐き出されるのだろうか?
パスは Path.Combine(Arguments.GeneratedFilesOutputDirectory!, tree.FilePath)
と書かれている.
ここで tree は 生成された syntax tree であり,これに元のテキストや AddSource
時の hintname にもとづいた保存先のファイル名が書かれているっぽい.
ここで, Arguments.GeneratedFilesOutputDirectory
が気になる.これをいじれば,ファイル出力先をプロジェクトのソースファイルがあるディレクトリにして,生成されたファイルもソース管理に含めることもできそうな気がする.普通に開発しているぶんにはメリットはないけど, github を使っててブラウザ上でコード読みたいとか,そういうときに役立つかもしれない.
この Arguments
は CommonCompiler
の public property であり,型は CommandLineArguments
となっている.これは get-only で, CommonCompiler
のコンストラクタに渡された CommandLineParser
string? responseFile
と string[] args
をもとにパースするらしい.
じゃあ,C# コンパイラのコマンドライン引数になにかしら指定すれば GeneratedFilesOutputDirectory
を変えられるのではないか?
parser は C# では CSharpCommandLineParser
を使っているので,この中身を調べる.
CSharpCommandLInePraser.cs#L617 でパースしているっぽくて, コマンドラインスイッチは generatedfilesout
となっている.
おそらく, generatedfilesout
を csc の引数として渡すことで GeneratedFilesOutputDirectory
を変更可能である.
おそらく, generatedfilesout を csc の引数として渡すことで GeneratedFilesOutputDirectory を変更可能である.
しかしながら,通常の msbuild を使ったビルドでは, csc の引数をすべて指定できるわけではなさそう. msbuild 自体にそのようなスイッチが無いので,やるとしたら csc を直接叩くしかなさそう.