mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-indexing] Search sealed inheritors without index and fix scope for scratches
Fixes IDEA-370469 Optimize sealed class inheritor search to explicitly permitted ones Fixes IDEA-326216 Good code is red: "Sealed class must have subclasses" in scratch files with java 17 GitOrigin-RevId: d500a91d39003ef30e420bce12f3a1a38cefa6f0
This commit is contained in:
committed by
intellij-monorepo-bot
parent
cfc242b33f
commit
7e12b8c8c5
+55
-12
@@ -12,6 +12,7 @@ import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Predicates;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
@@ -31,6 +32,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public final class JavaDirectInheritorsSearcher implements QueryExecutor<PsiClass, DirectClassInheritorsSearch.SearchParameters> {
|
||||
@Override
|
||||
@@ -151,20 +153,31 @@ public final class JavaDirectInheritorsSearcher implements QueryExecutor<PsiClas
|
||||
private static PsiClass @NotNull [] getOrCalculateDirectSubClasses(@NotNull Project project,
|
||||
@NotNull PsiClass baseClass,
|
||||
@NotNull DirectClassInheritorsSearch.SearchParameters parameters) {
|
||||
List<PsiClass> sealedInheritors = DumbService.getInstance(project).runReadActionInSmartMode(() -> processSealed(baseClass));
|
||||
if (sealedInheritors != null) {
|
||||
if (parameters.restrictSealedHierarchy()) {
|
||||
// Do not cache: this list is fast to compute
|
||||
return sealedInheritors.toArray(PsiClass.EMPTY_ARRAY);
|
||||
}
|
||||
}
|
||||
ConcurrentMap<PsiClass, PsiClass[]> map = HighlightingCaches.getInstance(project).DIRECT_SUB_CLASSES;
|
||||
PsiClass[] cache = map.get(baseClass);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
if (cache == null) {
|
||||
final String baseClassName = ReadAction.compute(baseClass::getName);
|
||||
if (StringUtil.isEmpty(baseClassName)) {
|
||||
return PsiClass.EMPTY_ARRAY;
|
||||
}
|
||||
cache = calculateDirectSubClasses(project, baseClass, baseClassName, parameters);
|
||||
// for non-physical elements ignore the cache completely because non-physical elements created so often/unpredictably so I can't figure out when to clear caches in this case
|
||||
if (ReadAction.compute(baseClass::isPhysical)) {
|
||||
cache = ConcurrencyUtil.cacheOrGet(map, baseClass, cache);
|
||||
}
|
||||
}
|
||||
|
||||
final String baseClassName = ReadAction.compute(baseClass::getName);
|
||||
if (StringUtil.isEmpty(baseClassName)) {
|
||||
return PsiClass.EMPTY_ARRAY;
|
||||
}
|
||||
cache = calculateDirectSubClasses(project, baseClass, baseClassName, parameters);
|
||||
// for non-physical elements ignore the cache completely because non-physical elements created so often/unpredictably so I can't figure out when to clear caches in this case
|
||||
if (ReadAction.compute(baseClass::isPhysical)) {
|
||||
cache = ConcurrencyUtil.cacheOrGet(map, baseClass, cache);
|
||||
if (sealedInheritors != null) {
|
||||
// Do not cache invalid sealed inheritors
|
||||
return Stream.concat(sealedInheritors.stream(), Stream.of(cache))
|
||||
.distinct()
|
||||
.toArray(PsiClass[]::new);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
@@ -186,6 +199,7 @@ public final class JavaDirectInheritorsSearcher implements QueryExecutor<PsiClas
|
||||
@NotNull PsiClass baseClass,
|
||||
@NotNull String baseClassName,
|
||||
@NotNull DirectClassInheritorsSearch.SearchParameters parameters) {
|
||||
DumbService dumbService = DumbService.getInstance(project);
|
||||
SearchScope useScope;
|
||||
CompilerDirectHierarchyInfo info = performSearchUsingCompilerIndices(parameters, project);
|
||||
useScope = ReadAction.compute(() -> {
|
||||
@@ -194,7 +208,6 @@ public final class JavaDirectInheritorsSearcher implements QueryExecutor<PsiClas
|
||||
return resultScope.intersectWith(info.getDirtyScope());
|
||||
});
|
||||
|
||||
DumbService dumbService = DumbService.getInstance(project);
|
||||
GlobalSearchScope globalUseScope = ReadAction.compute(
|
||||
() -> new JavaSourceFilterScope(GlobalSearchScopeUtil.toGlobalSearchScope(useScope, project)));
|
||||
Collection<PsiReferenceList> candidates =
|
||||
@@ -307,6 +320,36 @@ public final class JavaDirectInheritorsSearcher implements QueryExecutor<PsiClas
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable List<PsiClass> processSealed(@NotNull PsiClass baseClass) {
|
||||
if (!baseClass.hasModifierProperty(PsiModifier.SEALED)) return null;
|
||||
PsiReferenceList permitsList = baseClass.getPermitsList();
|
||||
if (permitsList == null) {
|
||||
// all inheritors are in the current file
|
||||
PsiFile file = baseClass.getContainingFile();
|
||||
List<PsiClass> result = new ArrayList<>();
|
||||
if (file instanceof PsiClassOwner owner) {
|
||||
ArrayDeque<PsiClass> queue = new ArrayDeque<>();
|
||||
Collections.addAll(queue, owner.getClasses());
|
||||
while (!queue.isEmpty()) {
|
||||
PsiClass aClass = queue.pop();
|
||||
if (aClass.isInheritor(baseClass, false)) {
|
||||
result.add(aClass);
|
||||
}
|
||||
Collections.addAll(queue, aClass.getInnerClasses());
|
||||
for (PsiField field : aClass.getFields()) {
|
||||
if (field instanceof PsiEnumConstant constant) {
|
||||
ContainerUtil.addIfNotNull(queue, constant.getInitializingClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return Arrays.stream(permitsList.getReferencedTypes()).map(PsiClassType::resolve)
|
||||
.filter(Predicates.nonNull())
|
||||
.toList();
|
||||
}
|
||||
|
||||
private static VirtualFile getJarFile(@NotNull PsiClass aClass) {
|
||||
return ReadAction.compute(() -> PsiUtil.getJarFile(aClass));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user