org.eclipse.jdt.core.ICompilationUnit? はパッケージエクスプローラ上のソースコード一つに対応するというべきインタフェースです。このインタフェースをパッケージエクスプローラなどからアクション経由で取得して、ソースコードの解析などを行うことができます。
次のサンプルコードは、Eclipseのアクションクラス(ハンドラクラス)経由でパッケージエクスプローラからICompilationUnit?を取得し、そのインタフェースの実装メソッド
IJavaElement[] getChildren() throws JavaModelException;
を使って、コードを解析していきます。
public Object execute(ExecutionEvent event) throws ExecutionException { ISelection selection = HandlerUtil.getActiveMenuSelectionChecked(event); if (selection instanceof IStructuredSelection) { IStructuredSelection sselection = (IStructuredSelection) selection; Object firstElement = sselection.getFirstElement(); if (firstElement instanceof ICompilationUnit) { ICompilationUnit unit = (ICompilationUnit) firstElement; try { if (!unit.isStructureKnown()) { return null; } // まずは子要素を取得。取得されるのは、パッケージ宣言とか、クラス型とか // クラスが複数定義されている場合もあるし。 IJavaElement elements[] = unit.getChildren(); for (IJavaElement javaElement : elements) { // ↓型だったらば、ITypeにキャスト。 if (javaElement.getElementType() == IJavaElement.TYPE) { IType type = (IType) javaElement; // メソッド一覧を取得。 IMethod[] methods = type.getMethods(); // IMethod method = methods[methods.length - 1]; for (IMethod method : methods) { System.out.println(method.getElementName()); } } } } catch (JavaModelException e) { e.printStackTrace(); } } } return null; }
package hoge; public class Sample { public void setHoge(String hoge){ this.hoge = hoge; } private String hoge; public String getHoge() { return hoge; } }こんなコードに対して上のハンドラを実行したところ、
setHoge getHogeと表示されました。
JDT周りをやってるとIResouce系を忘れてしまいそうですが、ありました。
// ソースコードに対応するファイルのIResource IResource resource = cu.getCorrespondingResource();
これでOKですね。
EclipseのJDTのソース見てると、ファイルの先頭からの文字数をカウントして、その場所にコード挿入するとか、割と地味ーなコードがよくあります。
それを実装する基本として、ソースの先頭からある要素(ここではメソッド)までのオフセット*1位置を取得してみます。解析対象のソースは以下の通りです。
package hoge; public class Sample { public void setHoge(String hoge){ <-このメソッドの「p」の位置は、先頭から38文字目。 this.hoge = hoge; } <-また「p」前の位置からこのカッコ終わりまでの長さは、56文字 private String hoge; public String getHoge() { <-このメソッドの「p」の位置は、先頭から121文字目。 return hoge; } <-また「p」前の位置からこのカッコ終わりまでの長さは、43文字 }
オフセットを取得するコードは以下の通り。
public Object execute(ExecutionEvent event) throws ExecutionException { --- 先と同じなので、省略 --- if (firstElement instanceof ICompilationUnit) { ICompilationUnit unit = (ICompilationUnit) firstElement; try { if (!unit.isStructureKnown()) { return null; } IJavaElement elements[] = unit.getChildren(); for (IJavaElement javaElement : elements) { if (javaElement.getElementType() == IJavaElement.TYPE) { IType type = (IType) javaElement; IMethod[] methods = type.getMethods(); for (IMethod method : methods) { ISourceRange sourceRange = method .getSourceRange(); int offset = sourceRange.getOffset(); System.out.println(offset); } } } } catch (JavaModelException e) { e.printStackTrace(); // TODO: handle exception } } return null; }
この通り、IMethod method を取得して、そのインスタンスに対し
ISourceRange sourceRange = method.getSourceRange(); int offset = sourceRange.getOffset();
とすることでオフセット位置を取得することができます。ちなみに実行結果は、
38 121
となりました。
またそのメソッドの長さ(オフセット位置から、そのメソッドの終わりまでの文字数)は、
int length = sourceRange.getLength();
とやって取得できます。実行結果は、
56 43
です。これでメソッド終わり場所のオフセット位置なども取得できますね。
なるほどねーと思って上のやり方を見てたのですが、コメント文とかがある場合は、メソッドの先頭のオフセット位置を取ろうとメソッドを実行すると、コメントの上部分の位置を返してきます。
コメントの下の、ホントにメソッドの開始はどう取るんだろうとEclipse JDTのソースを見てみると、TokenScanner? というInternalなクラスを使って実装がされていました。
private int getMemberStartOffset(IMethod lastMethod, IDocument document) throws JavaModelException { ISourceRange sourceRange = lastMethod.getSourceRange(); int memberStartOffset = sourceRange.getOffset(); // 通常は上のオフセットを返すので問題ないけど、コメントとかがあると、コメントの上の位置を返してくる。 // ホントにメソッドの直上にする場合は、このようにする必要がある。 TokenScanner scanner = new TokenScanner(document, lastMethod.getJavaProject()); try { return scanner.getNextStartOffset(memberStartOffset, true); // read // to the first real non comment token } catch (CoreException e) { // ignore } return memberStartOffset; }
TokenScanner?ってやつにまかせてるんですね:-)。
この記事は
現在のアクセス:13281