前書き
.net core
でコンパイル時の自動コード生成をする上で、Roslyn API
に触る必要がある。
その手始めとして、Roslyn
が吐くAST
を除いて見たメモ。
環境
今回の実験環境
% dotnet --info
.NET Core SDK (global.json を反映):
Version: 3.1.201
Commit: b1768b4ae7
ランタイム環境:
OS Name: Mac OS X
OS Version: 10.15
OS Platform: Darwin
RID: osx.10.15-x64
Base Path: /usr/local/share/dotnet/sdk/3.1.201/
Host (useful for support):
Version: 3.1.3
Commit: 4a9f85e9f8
.NET Core SDKs installed:
3.1.201 [/usr/local/share/dotnet/sdk]
.NET Core runtimes installed:
Microsoft.AspNetCore.App 3.1.3 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 3.1.3 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
プロジェクト準備
コンソールアプリとして作成
% dotnet new console -o CodeGenDemo
Roslyn API
のパッケージを加える
% dotnet add CodeGenDemo package Microsoft.CodeAnalysis.CSharp
% dotnet list CodeGenDemo package
プロジェクト 'CodeGenDemo' に次のパッケージ参照が含まれています
[netcoreapp3.1]:
最上位レベル パッケージ 要求済み 解決済み
> Microsoft.CodeAnalysis.CSharp 3.5.0 3.5.0
作成
例として、以下のインターフェースのASTを覗く
using System;
namespace DemoGenDao {
public interface IColorDao {
ColorData? FindById(int id);
}
}
AST
の作成は、Microsoft.CodeAnalysis.CSharp名前空間のCSharpSyntaxTreeクラスのParseTextメソッドを使用する。
see: CSharpSyntaxTree.ParseText Method
AST
のルートツリーは、CSharpSyntaxTreeのGetCompilationUnitRootメソッドで取得可能。
see: CSharpSyntaxTree.GetCompilationUnitRoot(CancellationToken) Method
using System;
using Microsoft.CodeAnalysis.CSharp;
// (snip)
static void Main(string[] args) {
var programText = @"
using System;
namespace DemoGenDao {
public interface IColorDao {
ColorData? FindById(int id);
}
}
";
var tree = CSharpSyntaxTree.ParseText(programText);
var root = tree.GetCompilationUnitRoot();
}
using
で取り込んだ名前空間の情報は、Usingsプロパティから辿る。
その他クラスユニット等は、Membersプロパティから辿る。
static void Main(string[] args) {
// 続き
System.Console.WriteLine($"The tree has {root.Usings.Count} using statements. They are:");
foreach (var e in root.Usings) {
System.Console.WriteLine($"\t{e.Name}");
}
System.Console.WriteLine($"The tree is {root.Kind()} node.");
System.Console.WriteLine($"The tree has {root.Members.Count} elements in it.");
}
AST
のノードは、Microsoft.CodeAnalysis.CSharp.Syntax名前空間で定義されている。
適宜キャストして扱う。
see: Microsoft.CodeAnalysis.CSharp.Syntax
今回お世話になったのは、
- NamespaceDeclarationSyntax
- InterfaceDeclarationSyntax
- MethodDeclarationSyntax
- ParameterSyntax
- TypeSyntax
using Microsoft.CodeAnalysis.CSharp.Syntax; // 追加
// (snip)
static void Main(string[] args) {
// 続き
foreach (var m in root.Members) {
System.Console.WriteLine($"\tThe member in root is {m.Kind()}.");
var ns = (NamespaceDeclarationSyntax)m; // Microsoft.CodeAnalysis.CSharp.Syntax
System.Console.WriteLine($"\tThere are {ns.Members.Count} members declared in this namespace.");
foreach (var t in ns.Members) {
System.Console.WriteLine($"\t\tThe member in this namespace is {t.Kind()}.");
if (t is InterfaceDeclarationSyntax) {
var intf = (InterfaceDeclarationSyntax)t;
System.Console.WriteLine($"\t\tThis type is {intf.Identifier} interface.");
System.Console.WriteLine($"\t\tThis type has {intf.Members.Count} members.");
foreach (var mm in intf.Members) {
System.Console.WriteLine($"\t\t\tThe member in this type is {mm.Kind()}.");
if (mm is MethodDeclarationSyntax) {
var method = (MethodDeclarationSyntax)mm;
System.Console.WriteLine($"\t\t\tThis method name is {method.Identifier}.");
System.Console.WriteLine($"\t\t\tThis method has {method.Modifiers.Count} modifiers.");
System.Console.WriteLine($"\t\t\tThis method returns {method.ReturnType}.");
System.Console.WriteLine($"\t\t\t\tThe return type nullable in method is {method.ReturnType.IsNotNull}.");
System.Console.WriteLine($"\t\t\tThis method receives {method.ParameterList.Parameters.Count} args.");
foreach (ParameterSyntax arg in method.ParameterList.Parameters) {
System.Console.WriteLine($"\t\t\t\tThe arg in this method is {arg.Kind()}.");
System.Console.WriteLine($"\t\t\t\tThe arg name is {arg.Identifier}.");
System.Console.WriteLine($"\t\t\t\tThe arg type is {arg.Type}.");
System.Console.WriteLine($"\t\t\t\t\tThe arg nullable is {arg.Type.IsNotNull}.");
}
}
else {
System.Console.WriteLine($"\t\t???? This member syntax is {t.GetType().FullName}.");
}
}
}
else {
System.Console.WriteLine($"\t\t???? This type syntax is {t.GetType().FullName}.");
}
}
}
}
実行結果
実行結果は以下の通り
% dotnet run -p CodeGenDemo
The tree is CompilationUnit node.
The tree has 1 using statements. They are:
System
The tree has 1 elements in it.
The member in root is NamespaceDeclaration.
There are 1 members declared in this namespace.
The member in this namespace is InterfaceDeclaration.
This type is IColorDao interface.
This type has 1 members.
The member in this type is MethodDeclaration.
This method name is FindById.
This method has 0 modifiers.
This method returns ColorData?.
The return type nullable in method is False.
This method receives 1 args.
The arg in this method is Parameter.
The arg name is id.
The arg type is int.
The arg nullable is False.