[ASTParser 1]ASTParser でクラス名やフィールド、メソッドの概要を取得する | 坂道で

坂道で

ゆるめ

このテーマ[Java / ASTParser]では、EclipseのASTParserという機能を利用してJavaソースコードの解析や変換の方法について、ユルク解説していく。

「ASTP・・・なんぞや?」という人は「Javaのソースコードから色々な情報を取得できるライブラリ」程度の認識でいいと思う。
もう少し詳しく知りたい場合は「Eclipse/プラグイン開発のTIPS集/ソースコードを解析するパーサASTParser」 あたりを読めばいいと思う。
セットアップ(?)の仕方は「EclipseのASTParserを単体で使う」が分かりやすい。

とりあえずサンプルコードの紹介と解説をしていく。
文字数の都合上、全てのコードをこのページに貼り付けることができない為、全体を眺めたい場合は、Githubのリポジトリの方を見て欲しい。
下に、サンプルコアとなる2つのファイル Sample1.java と SampleVisitor1.java を貼りつけている。

大雑把に言えば、Sample1.java には主にオマジナイASTParserでソースコードを解析する為の環境設定のような処理が記述されている。
そして、もう一方の SampleVisitor1.java でクラスの情報の取得を行なっている。

Sample1.java
  1. package info.haxahaxa.astparser.sample;
  2. import info.haxahaxa.astparser.Envs;
  3. import info.haxahaxa.astparser.SourceFile;
  4. import info.haxahaxa.astparser.sample.visitor.*;
  5. import java.io.File;
  6. import org.eclipse.core.runtime.NullProgressMonitor;
  7. import org.eclipse.jdt.core.dom.AST;
  8. import org.eclipse.jdt.core.dom.ASTParser;
  9. import org.eclipse.jdt.core.dom.ASTVisitor;
  10. import org.eclipse.jdt.core.dom.CompilationUnit;
  11. /**
  12. * クラス名やフィールド,メソッドの概要を表示するサンプル
  13. *
  14. * @author satanabe1
  15. *
  16. */
  17. public class Sample1 {
  18.     private static ASTVisitor visitor = new SampleVisitor1();
  19.     public static void main(String[] args) throws Exception {
  20.         SourceFile sourceFile = new SourceFile("src" + File.separator
  21.                 + "samples" + File.separator + "AntFileGen.java");
  22.         CompilationUnit unit;
  23.         ASTParser astParser = ASTParser.newParser(AST.JLS4);
  24.         // 以下の setBindingsRecovery setStatementsRecovery はおまじない.
  25.         // 完成しているソースコードを解析する時は呼ぶ必要ない.
  26.         // 詳しく知りたいならば,IMBのASTParser関連のドキュメントとかを参照すべき.
  27.         astParser.setBindingsRecovery(true);
  28.         astParser.setStatementsRecovery(true);
  29.         // 次の setResolveBindings と setEnvironment が重要!!
  30.         // setResolveBindings(true) をしておかないとまともに解析はできない.
  31.         // setResolveBindings をまともに機能させるために setEnvironment が必要.
  32.         astParser.setResolveBindings(true);
  33.         // setEnvironment の第一引数にはクラスパスの配列.第二引数にはソースコードを検索するパスの配列
  34.         // 第三第四については何も考えず null, true .納得いかない時はIBMのASTPa...
  35.         astParser.setEnvironment(Envs.getClassPath(), Envs.getSourcePath(),
  36.                 null, true);
  37.         // 解析対象のソースコードの入力とか
  38.         astParser.setUnitName(sourceFile.getFilePath());// なんでもいいから名前を設定しておく
  39.         astParser.setSource(sourceFile.getSourceCode().toCharArray());// 解析対象コードを設定する
  40.         unit = (CompilationUnit) astParser.createAST(new NullProgressMonitor());
  41.         unit.recordModifications();// ASTへの操作履歴のようなものを有効に
  42.         // 解析実行
  43.         unit.accept(visitor);
  44.     }
  45. }

SampleVisitor1.java
  1. package info.haxahaxa.astparser.sample.visitor;
  2. import info.haxahaxa.astparser.PrintUtil;
  3. import java.util.List;
  4. import org.eclipse.jdt.core.dom.ASTVisitor;
  5. import org.eclipse.jdt.core.dom.FieldDeclaration;
  6. import org.eclipse.jdt.core.dom.ITypeBinding;
  7. import org.eclipse.jdt.core.dom.IVariableBinding;
  8. import org.eclipse.jdt.core.dom.MethodDeclaration;
  9. import org.eclipse.jdt.core.dom.TypeDeclaration;
  10. import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
  11. /**
  12. * クラス名やフィールド,メソッドの概要を表示するサンプル
  13. *
  14. * @author satanabe1
  15. *
  16. */
  17. public class SampleVisitor1 extends ASTVisitor {
  18.     /**
  19.      * クラス宣言が見つかると呼ばれるメソッド
  20.      */
  21.     public boolean visit(TypeDeclaration node) {
  22.         PrintUtil.printTitle("クラス宣言");
  23.         ITypeBinding typeBinding = node.resolveBinding();// 詳細な情報をITypeBindingインスタンスを使って取得したい
  24.         ITypeBinding superClass = typeBinding.getSuperclass();// 親クラスの取得
  25.         ITypeBinding[] interfaces = typeBinding.getInterfaces();// インターフェースの取得
  26.         String className = typeBinding.getBinaryName();// クラス名の取得
  27.         int modifiers = typeBinding.getModifiers();// "public static"とかの識別子
  28.         PrintUtil.printMessage("ClassName", className);
  29.         PrintUtil.printModifiers("Modifiers", modifiers);
  30.         PrintUtil.printMessage("SuperClass", superClass.getBinaryName());
  31.         PrintUtil.printMessage("Interfaces", interfaces);
  32.         return super.visit(node);
  33.     }
  34.     /**
  35.      * フィールド宣言が見つかると呼ばれるメソッド
  36.      */
  37.     public boolean visit(FieldDeclaration node) {
  38.         PrintUtil.printTitle("フィールド宣言");
  39.         PrintUtil.printModifiers("Modifiers", node.getModifiers());
  40.         PrintUtil.printMessage("Type", node.getType().toString());
  41.         List fragments = node.fragments();
  42.         for (Object frg : fragments) {
  43.             if (frg instanceof VariableDeclarationFragment) {
  44.                 IVariableBinding variableBinding = ((VariableDeclarationFragment) frg)
  45.                         .resolveBinding();
  46.                 PrintUtil.printMessage("Name", variableBinding.getName());
  47.             }
  48.         }
  49.         return super.visit(node);
  50.     }
  51.     /**
  52.      * メソッド宣言が見つかると呼ばれるメソッド
  53.      */
  54.     public boolean visit(MethodDeclaration node) {
  55.         PrintUtil.printTitle("メソッド宣言");
  56.         PrintUtil.printMessage("MethodName", node.getName()
  57.                 .getFullyQualifiedName());
  58.         PrintUtil.printModifiers("Modifiers", node.getModifiers());
  59.         PrintUtil.printMessage("ReturnType", node.getReturnType2() + "");
  60.         PrintUtil.printMessage("Parameters", node.parameters().toString());
  61.         return super.visit(node);
  62.     }
  63. }

Sample1.java のmainメソッド内の処理で注目すべきポイントとしては、
  1. ASTParserクラスのインスタンスに対してsetResolveBindingsとかsetEnvironmentとかのメソッドで環境設定
  2. 更に前述のインスタンスに対してsetSourceメソッドで解析対象のソースコードをセット(46行目)
  3. CompilationUnitのインスタンスを取得してacceptメソッドで解析実行(50行目)
くらい。 基本的にはこの一連の処理が定型と考えていいと思う。

SampleVisitor1.java の注目すべきポイントは2つ。
  1. ASTVisitorクラスを継承(22行目)
  2. boolean visit(型名 node) メソッドの宣言  (26/45/64行目)
このクラスで宣言されている3つのvisitメソッドはいずれもASTVisitorクラスのvisitメソッドをオーバーライドしている。
ここで覚えておくべき事としては、ASTVisitorクラスのvisitメソッドをオーバーライドすることで、
visitメソッドの引数の型に該当するソースコードを解析した時、勝手にそのvisitメソッドが実行されると言うこと。
つまり、自分が解析したい構文のvisitメソッドを作ってやれば簡単に解析できる。


解析に方法についてはもっと詳しいサイトがたくさんあるので、そちらに任せる。
次回からソースコードの変換について紹介しようと思う。