Find all PsiClasses in Project?
Answered
How to find all PsiClasses in the currently opened project? Currently I am using
Collection<VirtualFile> containingFiles = FileBasedIndex.getInstance()
.getContainingFiles(
FileTypeIndex.NAME,
JavaFileType.INSTANCE,
GlobalSearchScope.projectScope(myProject));
to retrive all the files in the project, then iterate over the files to get PsiFile from them and after that extract the PsiClasses. This works but is extremely slow. Is there a straightforward way to do this?
Please sign in to leave a comment.
Hey Jakub,
I tried like this:
but it returns 22k classes while my project only has 10 classes. And a lot of classes have really strange names, I think not even my dependencies contain such classes.
Update: I even tried with
AllClassesSearch.search(GlobalSearchScope.projectScope(myProject), myProject).allowParallelProcessing().forEach(psiClass -> {patterns.add(psiClass.getQualifiedName());
return true;
});
but it is even slower(tried it with allowParallelProcessing() and without it)
Norbi - sorry for that. Please try with your initial solution but pass a custom scope, like:
class MyGlobalSearchScope extends GlobalSearchScope {
private ProjectFileIndex index;
public MyGlobalSearchScope(@Nullable Project project) {
super(project);
this.index = ProjectRootManager.getInstance(project).getFileIndex();
}
@Override
public boolean isSearchInModuleContent(@NotNull Module aModule) {
return false;
}
@Override
public boolean isSearchInLibraries() {
return false;
}
@Override
public boolean contains(@NotNull VirtualFile file) {
return index.isInSourceContent(file);
}
}
Thank you! Unfortunately I am still seeing the same 22k classes returned. What is strange is that if I put a breakpoint in the isSearchInModuleContent(), isSearchInLibraries() and contains() methods, none of them is called.
These strange class names are included like: Newline, ExplicitCallForClosureParameter_after, testFilterInit, All, NewExpression, FromStringWithGenericPlaceholderFromClass, InferClassParameter8 etc.
All these classes seem to come from Intellij itself.
My complete code:
class OnlyProjectSearchScope extends GlobalSearchScope {
private ProjectFileIndex index;
public OnlyProjectSearchScope(Project project) {
super(project);
this.index = ProjectRootManager.getInstance(project).getFileIndex();
}
@Override
public boolean isSearchInModuleContent(Module aModule) {
return false;
}
@Override
public boolean isSearchInLibraries() {
return false;
}
@Override
public boolean contains(@NotNull VirtualFile file) {
return index.isInSourceContent(file);
}
}
Update: or are you referring to my initial solution in the question itself:
?
I measured the execution time and what I found is that this call is not the culprit for the slowness. The slowness comes from extracting PsiClasses from the PsiFile(the call to psiJavaFile.getClasses() takes 7 seconds in my project while everything else takes only 2 seconds)
for (VirtualFile virtualFile : containingFiles) {
PsiFile psiFile = PsiManager.getInstance(myProject).findFile(virtualFile);
if (psiFile instanceof PsiJavaFile) {
PsiJavaFile psiJavaFile = (PsiJavaFile) psiFile;
PsiClass[] javaFileClasses = psiJavaFile.getClasses();
for (PsiClass javaFileClass : javaFileClasses) {
classes.add(javaFileClass.getQualifiedName());
}
}
}
But did you swap
with MyGlobalSearchScope instance I've posted above? The point is to limit the search results to the Java files that satisfy isInSourceContent condition.
Oh, you're right, sorry. It reduced the time from 8.5s to 1.5s which is excellent. Thank you very much for your help!
Keep in mind that you still can enhance your contains filter for better results.