mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Detect recursive type parameter definition when checking for assignability
Fixes EA-137370 - SOE: TypeConversionUtil.isNarrowingReferenceConversionAllowed
This commit is contained in:
+1
-26
@@ -606,7 +606,7 @@ public class HighlightClassUtil {
|
||||
|
||||
@Nullable
|
||||
static HighlightInfo checkCyclicInheritance(@NotNull PsiClass aClass) {
|
||||
PsiClass circularClass = getCircularClass(aClass, new HashSet<>());
|
||||
PsiClass circularClass = InheritanceUtil.getCircularClass(aClass);
|
||||
if (circularClass != null) {
|
||||
String description = JavaErrorMessages.message("cyclic.inheritance", HighlightUtil.formatClass(circularClass));
|
||||
TextRange range = HighlightNamesUtil.getClassDeclarationTextRange(aClass);
|
||||
@@ -615,31 +615,6 @@ public class HighlightClassUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiClass getCircularClass(@NotNull PsiClass aClass, @NotNull Collection<? super PsiClass> usedClasses) {
|
||||
if (usedClasses.contains(aClass)) {
|
||||
return aClass;
|
||||
}
|
||||
try {
|
||||
usedClasses.add(aClass);
|
||||
PsiClass[] superTypes = aClass.getSupers();
|
||||
for (PsiElement superType : superTypes) {
|
||||
while (superType instanceof PsiClass) {
|
||||
if (!CommonClassNames.JAVA_LANG_OBJECT.equals(((PsiClass)superType).getQualifiedName())) {
|
||||
PsiClass circularClass = getCircularClass((PsiClass)superType, usedClasses);
|
||||
if (circularClass != null) return circularClass;
|
||||
}
|
||||
// check class qualifier
|
||||
superType = superType.getParent();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
usedClasses.remove(aClass);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static HighlightInfo checkExtendsDuplicate(@NotNull PsiJavaCodeReferenceElement element, @Nullable PsiElement resolved, @NotNull PsiFile containingFile) {
|
||||
if (!(element.getParent() instanceof PsiReferenceList)) return null;
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
@@ -188,4 +189,38 @@ public class InheritanceUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiClass getCircularClass(@NotNull PsiClass aClass, @NotNull Collection<? super PsiClass> usedClasses) {
|
||||
if (usedClasses.contains(aClass)) {
|
||||
return aClass;
|
||||
}
|
||||
try {
|
||||
usedClasses.add(aClass);
|
||||
PsiClass[] superTypes = aClass.getSupers();
|
||||
for (PsiElement superType : superTypes) {
|
||||
while (superType instanceof PsiClass) {
|
||||
if (!CommonClassNames.JAVA_LANG_OBJECT.equals(((PsiClass)superType).getQualifiedName())) {
|
||||
PsiClass circularClass = getCircularClass((PsiClass)superType, usedClasses);
|
||||
if (circularClass != null) return circularClass;
|
||||
}
|
||||
// check class qualifier
|
||||
superType = superType.getParent();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
usedClasses.remove(aClass);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects a circular inheritance
|
||||
* @param aClass a class to check
|
||||
* @return a class which is a part of the inheritance loop; null if no circular inheritance was detected
|
||||
*/
|
||||
@Nullable
|
||||
public static PsiClass getCircularClass(@NotNull PsiClass aClass) {
|
||||
return getCircularClass(aClass, new HashSet<>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,8 +320,12 @@ public class TypeConversionUtil {
|
||||
final PsiClassType.ClassResolveResult result = superType.resolveGenerics();
|
||||
final PsiClass superClass = result.getElement();
|
||||
if (superClass != null) {
|
||||
PsiElementFactory factory = JavaPsiFacade.getElementFactory(typeParameter.getProject());
|
||||
if (superClass instanceof PsiTypeParameter && InheritanceUtil.getCircularClass(superClass) != null) {
|
||||
return factory.createTypeByFQClassName(JAVA_LANG_OBJECT, typeParameter.getResolveScope());
|
||||
}
|
||||
final PsiSubstitutor substitutor = result.getSubstitutor().put(typeParameter, null);
|
||||
return JavaPsiFacade.getElementFactory(typeParameter.getProject()).createType(superClass, substitutor);
|
||||
return factory.createType(superClass, substitutor);
|
||||
}
|
||||
return superType;
|
||||
}
|
||||
|
||||
+13
@@ -49,3 +49,16 @@ class TestNonNarrowingConversion<T extends Z> {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
class TestRecursiveTypeParameter {
|
||||
static <<error descr="Cyclic inheritance involving 'T'"></error>T extends T> void test(T t) {
|
||||
<error descr="Incompatible types. Found: 'T', required: 'java.lang.String'">String x = t;</error>
|
||||
<error descr="Incompatible types. Found: 'java.lang.String', required: 'T'">t = x</error>;
|
||||
}
|
||||
|
||||
static <<error descr="Cyclic inheritance involving 'A'"></error>A extends B, B extends A> void test(A a, B b) {
|
||||
a = b;
|
||||
b = a;
|
||||
<error descr="Incompatible types. Found: 'A', required: 'java.lang.String'">String x = a;</error>
|
||||
<error descr="Incompatible types. Found: 'java.lang.String', required: 'A'">a = x</error>;
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -2,7 +2,6 @@
|
||||
package org.jetbrains.plugins.groovy.annotator;
|
||||
|
||||
import com.intellij.codeInsight.ClassUtil;
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.HighlightClassUtil;
|
||||
import com.intellij.codeInsight.generation.OverrideImplementExploreUtil;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.codeInsight.intention.QuickFixFactory;
|
||||
@@ -1959,7 +1958,7 @@ public class GroovyAnnotator extends GroovyElementVisitor {
|
||||
|
||||
private static void checkCyclicInheritance(AnnotationHolder holder,
|
||||
@NotNull GrTypeDefinition typeDefinition) {
|
||||
final PsiClass psiClass = HighlightClassUtil.getCircularClass(typeDefinition, new HashSet<>());
|
||||
final PsiClass psiClass = InheritanceUtil.getCircularClass(typeDefinition);
|
||||
if (psiClass != null) {
|
||||
String qname = psiClass.getQualifiedName();
|
||||
assert qname != null;
|
||||
|
||||
Reference in New Issue
Block a user