困った時の自分用メモ

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

Unity、C#の話~構文解析、Roslynを使う2(クラス>メソッド情報)~

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

ルールがあり確認作業も単調なので、どうにか機械的に行う事は出来ないかと調べていたら、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 methodList = classDeclaration.DescendantNodes()
                            .OfType<MethodDeclarationSyntax>().ToList();

4. 各情報取得

       // メソッド情報の取得
        var methodList = classDeclaration.DescendantNodes()
                            .OfType<MethodDeclarationSyntax>().ToList();
        

        // 関数部分のチェック
        for (int i = 0; i < methodList.Count; i++) {

            // 1 戻り値の型
            string returnType = methodList[i].ReturnType.ToString();

            // 2 関数名
            string methodName = methodList[i].Identifier.ValueText;
            
            // 3 private,public,protected/async,virtualの修飾子名
            var modifierTexts = methodList[i].Modifiers.Select(x => x.Text).ToArray();
            
            // 4 引数調べたい
            var parameterTexts = methodList[i].ParameterList.Parameters.Select(x => x).ToArray();
            for (int i2 = 0; i2 < parameterTexts.Length; i2++) {
                string name = parameterTexts[i2].Identifier.ValueText;// test
                string fullName = parameterTexts[i2].ToString();// int test
            }

            // 5 コメント調べたい
            if (methodList[i].HasLeadingTrivia == true)
            {
                var triviaList = methodList[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
            {
                // コメント無し
            }
        }