package org.jetbrains.plugins.clojure.psi.impl.javaView; import com.intellij.openapi.components.ProjectComponent; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiShortNamesCache; import com.intellij.psi.stubs.StubIndex; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.clojure.psi.impl.ClojurePsiManager; import org.jetbrains.plugins.clojure.psi.api.ClojureFile; import org.jetbrains.plugins.clojure.compiler.ClojureCompilerSettings; import org.jetbrains.plugins.clojure.psi.stubs.index.ClojureFullScriptNameIndex; import java.util.Collection; import java.util.List; import java.util.ArrayList; import java.util.Arrays; /** * @author ilyas */ public class ClojureClassFinder extends PsiElementFinder { private final Project myProject; public ClojureClassFinder(Project project) { myProject = project; } @Nullable public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) { return getClassByFQName(qualifiedName, scope); } @NotNull public PsiClass[] findClasses(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) { return getClassesByFQName(qualifiedName, scope); } @Nullable public PsiPackage findPackage(@NotNull String qualifiedName) { return null; } @NotNull public PsiPackage[] getSubPackages(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) { return new PsiPackage[0]; } @NotNull public PsiClass[] getClasses(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) { if (!ClojureCompilerSettings.getInstance(psiPackage.getProject()).getState().COMPILE_CLOJURE) return PsiClass.EMPTY_ARRAY; List<PsiClass> result = new ArrayList<PsiClass>(); for (final PsiDirectory dir : psiPackage.getDirectories(scope)) { for (final PsiFile file : dir.getFiles()) { if (file instanceof ClojureFile) { ClojureFile clojureFile = (ClojureFile) file; if (clojureFile.isClassDefiningFile() && clojureFile.getPackageName().equals(psiPackage.getQualifiedName())) { result.add(clojureFile.getDefinedClass()); } } } } return result.toArray(new PsiClass[result.size()]); } private Collection<PsiClass> getScriptClassesByFQName(final String name, final GlobalSearchScope scope) { Collection<ClojureFile> scripts = StubIndex.getInstance().get(ClojureFullScriptNameIndex.KEY, name.hashCode(), myProject, scope); scripts = ContainerUtil.findAll(scripts, new Condition<ClojureFile>() { public boolean value(final ClojureFile clojureFile) { final PsiClass clazz = clojureFile.getDefinedClass(); return clojureFile.isClassDefiningFile() && clazz != null && name.equals(clazz.getQualifiedName()); } }); return ContainerUtil.map(scripts, new Function<ClojureFile, PsiClass>() { public PsiClass fun(final ClojureFile clojureFile) { return clojureFile.getDefinedClass(); } }); } @Nullable private PsiClass getClassByFQName(@NotNull @NonNls String name, @NotNull GlobalSearchScope scope) { if (!areClassesCompiled()) return null; final Collection<PsiClass> scriptClasses = getScriptClassesByFQName(name, scope); for (PsiClass clazz : scriptClasses) { if (name.equals(clazz.getQualifiedName())) return clazz; } return null; } @NotNull private PsiClass[] getClassesByFQName(@NotNull @NonNls String fqn, @NotNull GlobalSearchScope scope) { if (!areClassesCompiled()) return PsiClass.EMPTY_ARRAY; final Collection<PsiClass> result = getScriptClassesByFQName(fqn, scope); ArrayList<PsiClass> filtered = new ArrayList<PsiClass>(); for (PsiClass clazz : result) { if (fqn.equals(clazz.getQualifiedName())) { filtered.add(clazz); } } return filtered.isEmpty() ? PsiClass.EMPTY_ARRAY : filtered.toArray(new PsiClass[filtered.size()]); } private boolean areClassesCompiled() { ClojureCompilerSettings settings = ClojureCompilerSettings.getInstance(myProject); return settings.getState().COMPILE_CLOJURE; } }