SyntaxTree
今回パースしてみるのは以下のサンプルソースです。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace RoslynSample { ///なんてことないValueObjectです。これをCSharpSyntaxTree.ParseText()でパースしてSyntaxTreeを取得し、中身を調べてみます。/// 氏名を表します。 /// class Name { private string m_firstName; private string m_lastName; ///名を取得します。 public string FirstName { get { return m_firstName; } } ///氏を取得します。 public string LastName { get { return m_lastName; } } ///氏名を取得します。 public string FullName { get { return m_firstName + m_lastName; } } ////// 氏名を指定してNameクラスの新しいインスタンスを初期化します。 /// /// 名 /// 氏 public Name(string firstName, string lastName) { m_firstName = firstName; m_lastName = lastName; } ////// 現在のオブジェクトを表す文字列を返します。 /// ///現在のオブジェクトを表す文字列。 public override string ToString() { return m_firstName + " " + m_lastName; } } }
SyntaxTreeは木構造なのでツリービューで表示してみました。 各ノードにはノードのクラス名とソースコード上の位置を表示しています。 見てのとおり、SyntaxTreeはCompilationUnitSyntaxをルートに様々な種類のクラスによって構成されています。
SyntaxTreeを構成するSyntaxNode
SyntaxTreeを構成するクラスは全てSyntaxNodeの派生クラスとなっています。SyntaxNodeは、ソースコード内におけるノードの位置やノードの文法上の種類を保持しており、またSyntaxTree内を渡り歩くためのメソッドも提供します。
SntaxNodeの主なプロパティとメソッドは以下の通りです。
メソッドには「Ancestors()」や「DescendantNodes()」といった LINQ to XML でお馴染みのメソッドがあります。ソースコード内のメソッド定義にアクセスする場合、これらのメソッドを用いて次のようにアクセスすることができます。
SntaxNodeの主なプロパティとメソッドは以下の通りです。
型 | プロパティ名 | 説明 |
---|---|---|
TextSpan | FullSpan | パースしたテキスト内におけるSyntaxNodeの範囲。FullSpan.Startがテキスト内でのSyntaxNodeの開始位置(0スタートの文字index)、FullSpan.LengthがSyntaxNodeの範囲長(文字数)を表す。 |
bool | HasLeadingTrivia | SyntaxNodeの前方にTrivia(コメント、改行文字、空白等)が存在するならtrue、それ以外はfalse。 |
bool | HasLeadingTrivia | SyntaxNodeの後方にTrivia(コメント、改行文字、空白等)が存在するならtrue、それ以外はfalse。 |
SyntaxKind | Kind | SyntaxNodeの文法上の種類。 |
SyntaxNode | Parent | 親のSyntaxNode。 |
SyntaxTree | SyntaxTree | SyntaxNodeが含まれるツリーへの参照。 |
メソッド名 | 説明 |
---|---|
Ancestors() | 先祖のSyntaxNodeのリストを取得。 |
ChildNodes() | 子のSyntaxNodeのリストを取得。 |
DescendantNodes() | 子孫のSyntaxNodeのリストを取得。 |
GetLocation() | SyntaxNodeの位置を取得。GetLocation().GetLineSpan()でSyntaxNodeが含まれるファイルのパスやSyntaxNodeの開始行が取得できる。 |
GetLeadingTrivia() | SyntaxNodeの前方のTriviaを取得。 |
GetTrailingTrivia() | SyntaxNodeの後方のTriviaを取得。 |
ToFullString() | SyntaxNodeを表す文字列を取得(前後のTriviaを含む)。 |
ToString() | SyntaxNodeを表す文字列を取得(前後のTriviaを含まない)。 |
メソッドには「Ancestors()」や「DescendantNodes()」といった LINQ to XML でお馴染みのメソッドがあります。ソースコード内のメソッド定義にアクセスする場合、これらのメソッドを用いて次のようにアクセスすることができます。
var tree = CSharpSyntaxTree.ParseText(sourceCode); // メソッド定義を全て取得 var methodDeclarations = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>();同様に、クラスの定義には。OfType<Classdeclarationsyntax>()、プロパティの定義にはOfType<Propertydeclarationsyntax>()でアクセスできます。
SyntaxNodeの派生クラス
SyntaxNodeクラスの派生クラスはそれぞれがクラス宣言、メソッド宣言、foreach文、ブロック、式といった文法的な要素を表します。前項で出てきた「MethodDeclarationSyntax」はメソッド宣言、「ClassDeclarationSyntax」はクラス宣言、「Propertydeclarationsyntax」プロパティ宣言を表しています。これらのクラスは(C#の場合)Microsoft.CodeAnalysis.CSharp.Syntax名前空間に***Syntaxクラスとして定義されており、各クラスのプロパティを通して文法的な値(プロパティの型や名前等)を取得できます。また各クラスのメソッドを通して文法的な値を変更することも可能です。
次回はこのSyntaxNodeの派生クラスをいくつか取り上げ、実際に文法的な値を変更してみます。
次回はこのSyntaxNodeの派生クラスをいくつか取り上げ、実際に文法的な値を変更してみます。