困った時の自分用メモ

読んだ本を考察してメモったり、自分でいじった物の感想をメモったりする場。週1更新を目指します。

Unity、C#の話~構文解析、Roslynを使う4(クラス>フィールド情報)~

コードレビューをする際に、レビュー項目にコーディング規約に則した記述をしているかどうかという物がある。
チェック自体は行った方が保守性が高まり良いとは思うが、人の手で行うとかなり煩わしく、量もあるので時間もかかる。

ルールがあり確認作業も単調なので、どうにか機械的に行う事は出来ないかと調べていたら、C#にはRoslynという構文解析に使えるAPIが備わっているようだったので、試してみた。

今回は、使い方メモ書き、フィールド編。

ハッキリ言って、Roslynがどういう構造で、どういう思想なのかをきちんと理解はしておらず、
とりあえずやりたい事を、こういう風にやった、というメモ書きである。
これから使い始める人の、調査のヒントとして使ってもらえれば良いと思う。

1. まず、解析したいソースコードを、文字列として取得
方法は何でもいいけど、とりあえず文字列を生成

   [MenuItem("ShortCutCommand/Syntax4")]
    private static void Syntax4()
    {
        var fileName = "Resources/GameScene.txt";
        StreamReader sr = new StreamReader(@"./Assets/Resources/GameScene.txt", Encoding.GetEncoding("UTF-8"));
        string code = sr.ReadToEnd();// ソースコード取得
        sr.Close();

2. クラスの情報を取る為の準備

   [MenuItem("ShortCutCommand/Syntax4")]
    private static void Syntax4()
    {
        var fileName = "Resources/GameScene.txt";
        StreamReader sr = new StreamReader(@"./Assets/Resources/GameScene.txt", Encoding.GetEncoding("UTF-8"));
        string code = sr.ReadToEnd();// ソースコード取得
        sr.Close();

        // これで、とりあえず構文解析データのRootを取ってきているっぽい
        SyntaxTree tree = CSharpSyntaxTree.ParseText(code);
        var root = tree.GetCompilationUnitRoot();
        
        // ネームスペース(次の階層まとまり)を取得
        MemberDeclarationSyntax firstMember = root.Members[0];
        var nameSpaceDeclaration = (NamespaceDeclarationSyntax)firstMember;

        // ネームスペース内の最初のクラス情報を取得
        var classDeclaration = (ClassDeclarationSyntax)nameSpaceDeclaration.Members[0];

3. クラスのフィールドの情報を取得

   [MenuItem("ShortCutCommand/Syntax4")]
    private static void Syntax4()
    {
        var fileName = "Resources/GameScene.txt";
        StreamReader sr = new StreamReader(@"./Assets/Resources/GameScene.txt", Encoding.GetEncoding("UTF-8"));
        string code = sr.ReadToEnd();// ソースコード取得
        sr.Close();

        // これで、とりあえず構文解析データのRootを取ってきているっぽい
        SyntaxTree tree = CSharpSyntaxTree.ParseText(code);
        var root = tree.GetCompilationUnitRoot();
        
        // ネームスペース(次の階層まとまり)を取得
        MemberDeclarationSyntax firstMember = root.Members[0];
        var nameSpaceDeclaration = (NamespaceDeclarationSyntax)firstMember;

        // ネームスペース内の最初のクラス情報を取得
        var classDeclaration = (ClassDeclarationSyntax)nameSpaceDeclaration.Members[0];

        // フィールド情報の取得
        var fieldList = classDeclaration.DescendantNodes()
                            .OfType<FieldDeclarationSyntax>().ToList();

4. 各情報取得

       // フィールド情報の取得
        var fieldList = classDeclaration.DescendantNodes()
                            .OfType<FieldDeclarationSyntax>().ToList();
        
        for (int i = 0; i < fieldList.Count; i++) {

            // 1 フィールド名
            string fieldName = fieldList[i].ToString();
    
            // 2 フィールド指定先の戻り値の型
            string returnType = fieldList[i].Declaration.Type.ToString();
            
            // 3 フィールド指定先のprivate,public,protected/async,virtual等の修飾子
            var modifierTexts = fieldList[i].Modifiers.Select(x => x.Text).ToArray();

            // 4 フィールド指定先変数名
            var variables = fieldList[i].Declaration.Variables.ToList();
            string variable = variables[0].Identifier.ToString();
            
            // 5 コメント
            if (fieldList[i].HasLeadingTrivia == true)
            {
                var triviaList = fieldList[i].GetLeadingTrivia();
                var commentSyntaxTriviaArray = triviaList.Where(trivia => (!trivia.IsKind(SyntaxKind.WhitespaceTrivia)) && (!trivia.IsKind(SyntaxKind.EndOfLineTrivia))).ToArray();
                if (commentSyntaxTriviaArray.Length == 0)
                {
                    // コメント無し
                }
                else
                {
                    // コメントが行数分含まれる
                    for (int i2 = 0; i2 < commentSyntaxTriviaArray.Length; i2++) {
                        commentSyntaxTriviaArray[i2].ToString();
                    }
                }
            }
            else
            {
                // コメント無し
            }
        }