インタフェースの検索

ContentAssist175のために、インタフェースを検索する方法を調べてみました。

全ての型を辿る

型が多いと、とても時間がかかります。ソースとバイナリ(Jarの中の型)で処理を分けるのが面倒くさいです。

IPackageFragmentRoot roots = javaProject.getAllPackageFragmentRoots();
for (int i = 0; i < roots.length; i++) {
  IJavaElement elements = roots[i].getChildren();
  for (int p = 0; p < elements.length; p++) {
    if (elements[p] instanceof IPackageFragment) {
      IPackageFragment pkg = (IPackageFragment) elements[p];
      String pkgName = pkg.getElementName();
      if (pkg.getKind() == IPackageFragmentRoot.K_SOURCE) {
        ICompilationUnit units = pkg.getCompilationUnits();
        for (int u = 0; u < units.length; u++) {
          IType types = units[u].getAllTypes();
          for (int t = 0; t < types.length; t++) {
            IType type = (IType) types[t];
            if (type.isInterface()) {
              String typeName = pkgName + "." + type.getElementName();
              // ここでInterfaceを処理する
            }
          }
        }
      } else if (pkg.getKind() == IPackageFragmentRoot.K_BINARY) {
        IClassFile[] classes = pkg.getClassFiles();
        for (int c = 0; c < classes.length; c++) {
          IType type = classes[c].getType();
          if (type.isInterface()) {
            String typeName = pkgName + "." + type.getElementName();
            // ここでInterfaceを処理する
          }
        }
      }

NameLookupで検索する

JDTのソースから発掘しました。prefixで始まるインタフェースだけを検索します。packageFragmentにnullを指定すると、全てのパッケージからの検索になります。初回実行時は非常に時間がかかるけど、2回目以降は速かったと思います。

IJavaElementRequestor requestor = new JavaElementRequestor() {
  public void acceptType(IType type) {
    String typeName = type.getFullyQualifiedName();
    // ここでInterfaceを処理する
  }
};
NameLookup nameLookup = javaProject.newNameLookup(compilationUnit.getOwner());
nameLookup.seekTypes(prefix, packageFragment, true,
  NameLookup.ACCEPT_INTERFACES, requestor);

SearchEngine.search()で検索する

Java検索ダイアログで使われているようです。prefixで始まる型の定義を検索します。インタフェースだけを検索することは出来ないみたいで、クラスもヒットしてしまう。それなりに時間がかかります。

SearchRequestor requestor = new SearchRequestor() {
  public void acceptSearchMatch(SearchMatch match) throws CoreException {
    Object javaElement = match.getElement();
    if (javaElement instanceof IType && ( (IType) javaElement).isInterface() ) {
      IType type = (IType) javaElement;
      String typeName = type.getFullyQualifiedName();
      // ここでInterfaceを処理する
    }
  }
};
IJavaSearchScope scope = SearchEngine.createJavaSearchScope(javaProject.getAllPackageFragmentRoots());
SearchPattern pattern = SearchPattern.createPattern(prefix,
  IJavaSearchConstants.TYPE, IJavaSearchConstants.DECLARATIONS,
  SearchPattern.R_PREFIX_MATCH);
new SearchEngine().search(pattern,
  new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() },
  scope, requestor, null);

SearchEngine.searchAllTypeNames()で検索する

JDTのコンテンツアシストのソースから発掘しました。超速く検索できますが、Eclipse3.0と3.1でバイナリ非互換になってしまいます。

char prefixCharArray = prefix.toCharArray();
ArrayList res = new ArrayList();
IPackageFragmentRoot pkgs = javaProject.getAllPackageFragmentRoots();
JavaSearchScope scope = (JavaSearchScope) SearchEngine.createJavaSearchScope(pkgs);
new SearchEngine().searchAllTypeNames(null, prefixCharArray,
  SearchPattern.R_PREFIX_MATCH, IJavaSearchConstants.INTERFACE,
  scope, new TypeInfoRequestor(res),
  IJavaSearchConstants.FORCE_IMMEDIATE_SEARCH, null);
for (int i = 0; i < res.size(); i++) {
  TypeInfo typeInfo = (TypeInfo) res.get(i);
  String typeName = typeInfo.getFullyQualifiedName();
  // ここでInterfaceを処理する
}

検索メソッドのパラメータが変更されていました。

// Eclipse 3.0
public void searchAllTypeNames(
  final char packageName, 
  final char typeName,
  final int matchRule, 
  int searchFor, 
  IJavaSearchScope scope, 
  final ITypeNameRequestor nameRequestor,
  int waitingPolicy,
  IProgressMonitor progressMonitor)  throws JavaModelException {

// Eclipse 3.1
public void searchAllTypeNames(
  final char packageName, 
  final char typeName,
  final int matchRule, 
  int searchFor, 
  IJavaSearchScope scope, 
  final TypeNameRequestor nameRequestor,
  int waitingPolicy,
  IProgressMonitor progressMonitor)  throws JavaModelException {

ContentAssist175のいきなりインタフェース検索で使ったのはコレ。パッケージとパッケージ内インタフェース検索には、NameLookupを使ってみました。
パッケージ内インタフェースの補完が、まだ手抜きなので、補完できない場合があります。それを修正したら、Kijimunaでもいきなり補完を実装したいところです。