Open3

Roslyn コードリーティング

いしころいしころ

2021/03/19

Roslyn コードリーディングことはじめ

roslyn のコードは
https://github.com/dotnet/roslyn
で公開されている.

https://github.com/dotnet/roslyn/blob/main/docs/contributing/Building%2C Debugging%2C and Testing on Windows.md#developing-with-visual-studio-2019

git clone して Restore.cmd を実行.
Visual Studio で開いてビルドもできた.

SourceGenerator コードリーディング

SourceGenerator のコア機能は Compilers/Core/Microsoft.CodeAnalysis/SourceGeneration 以下にある.
ISourceGenerator から参照をたどってみる.
ISourceGenerator は 100 個以上の参照があるが,てきとうにめぼしを付けて参照元をさぐっていく.

MIcrosoft.CodeAnalysis.CommonCompiler#ResolveAnalyzersFromArgumentsout 引数に 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 を使っててブラウザ上でコード読みたいとか,そういうときに役立つかもしれない.

この ArgumentsCommonCompiler の public property であり,型は CommandLineArguments となっている.これは get-only で, CommonCompiler のコンストラクタに渡された CommandLineParser string? responseFilestring[] args をもとにパースするらしい.

じゃあ,C# コンパイラのコマンドライン引数になにかしら指定すれば GeneratedFilesOutputDirectory を変えられるのではないか?
parser は C# では CSharpCommandLineParser を使っているので,この中身を調べる.
CSharpCommandLInePraser.cs#L617 でパースしているっぽくて, コマンドラインスイッチは generatedfilesout となっている.
おそらく, generatedfilesout を csc の引数として渡すことで GeneratedFilesOutputDirectory を変更可能である.

いしころいしころ

おそらく, generatedfilesout を csc の引数として渡すことで GeneratedFilesOutputDirectory を変更可能である.

しかしながら,通常の msbuild を使ったビルドでは, csc の引数をすべて指定できるわけではなさそう. msbuild 自体にそのようなスイッチが無いので,やるとしたら csc を直接叩くしかなさそう.