[java] Faster test for throwable class

Fixes IDEA-374948 Improve throwable test inside ElementPresentationUtil.getClassKind

GitOrigin-RevId: 93f39f49aa22558c1d58c9d3dbce921107702639
This commit is contained in:
Tagir Valeev
2025-06-24 18:59:52 +00:00
committed by intellij-monorepo-bot
parent 57a58b57ff
commit 5042e748e8
3 changed files with 24 additions and 8 deletions
@@ -360,8 +360,7 @@ public final class SideEffectChecker {
// all Throwable descendants from java.lang are side effects free
if (CommonClassNames.DEFAULT_PACKAGE.equals(packageName) || "java.io".equals(packageName)) {
PsiClass throwableClass = JavaPsiFacade.getInstance(aClass.getProject()).findClass(CommonClassNames.JAVA_LANG_THROWABLE, aClass.getResolveScope());
if (throwableClass != null && com.intellij.psi.util.InheritanceUtil.isInheritorOrSelf(aClass, throwableClass, true)) {
if (PsiClassUtil.isThrowable(aClass)) {
return ThreeState.NO;
}
}
@@ -1,6 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.psi.util;
import com.intellij.psi.CommonClassNames;
import com.intellij.psi.PsiAnonymousClass;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiModifier;
@@ -8,6 +9,8 @@ import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
public final class PsiClassUtil {
private PsiClassUtil() { }
@@ -34,4 +37,22 @@ public final class PsiClassUtil {
return Comparator.comparing(c -> PsiUtilCore.getVirtualFile(c),
Comparator.nullsFirst((file1, file2) -> scope.compare(file2, file1)));
}
/**
* Checks if the given class is a throwable. The behavior is unspecified if the class or any of its superclasses is malformed.
*
* @param psiClass class to test
* @return true if class is {@code java.lang.Throwable} or legally inherits from it.
*/
public static boolean isThrowable(@NotNull PsiClass psiClass) {
Set<PsiClass> supers = new HashSet<>();
while (true) {
if (CommonClassNames.JAVA_LANG_THROWABLE.equals(psiClass.getQualifiedName())) return true;
if (psiClass.isInterface()) return false;
if (psiClass.getTypeParameters().length > 0) return false; // Valid throwables are never generic
PsiClass next = psiClass.getSuperClass();
if (next == null || !supers.add(next)) return false;
psiClass = next;
}
}
}
@@ -20,7 +20,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import org.jetbrains.annotations.NotNull;
import javax.swing.Icon;
import javax.swing.*;
public final class ElementPresentationUtil {
private ElementPresentationUtil() {
@@ -116,11 +116,7 @@ public final class ElementPresentationUtil {
}
if (!DumbService.getInstance(aClass.getProject()).isDumb()) {
final PsiManager manager = aClass.getManager();
final PsiClass javaLangTrowable =
JavaPsiFacade.getInstance(manager.getProject()).findClass(CommonClassNames.JAVA_LANG_THROWABLE, aClass.getResolveScope());
final boolean isException = javaLangTrowable != null && InheritanceUtil.isInheritorOrSelf(aClass, javaLangTrowable, true);
if (isException) {
if (PsiClassUtil.isThrowable(aClass)) {
return CLASS_KIND_EXCEPTION;
}