mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
substitute type parameter bounds with current substitution when method signatures in the hierarchy are checked (IDEA-159801)
This commit is contained in:
+24
-19
@@ -1302,16 +1302,16 @@ public class HighlightMethodUtil {
|
||||
private static HighlightInfo checkInterfaceInheritedMethodsReturnTypes(@NotNull List<? extends MethodSignatureBackedByPsiMethod> superMethodSignatures,
|
||||
@NotNull LanguageLevel languageLevel) {
|
||||
if (superMethodSignatures.size() < 2) return null;
|
||||
MethodSignatureBackedByPsiMethod returnTypeSubstitutable = superMethodSignatures.get(0);
|
||||
final MethodSignatureBackedByPsiMethod[] returnTypeSubstitutable = {superMethodSignatures.get(0)};
|
||||
for (int i = 1; i < superMethodSignatures.size(); i++) {
|
||||
PsiMethod currentMethod = returnTypeSubstitutable.getMethod();
|
||||
PsiType currentType = returnTypeSubstitutable.getSubstitutor().substitute(currentMethod.getReturnType());
|
||||
PsiMethod currentMethod = returnTypeSubstitutable[0].getMethod();
|
||||
PsiType currentType = returnTypeSubstitutable[0].getSubstitutor().substitute(currentMethod.getReturnType());
|
||||
|
||||
MethodSignatureBackedByPsiMethod otherSuperSignature = superMethodSignatures.get(i);
|
||||
PsiMethod otherSuperMethod = otherSuperSignature.getMethod();
|
||||
PsiType otherSuperReturnType = otherSuperSignature.getSubstitutor().substitute(otherSuperMethod.getReturnType());
|
||||
|
||||
PsiSubstitutor unifyingSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(returnTypeSubstitutable,
|
||||
PsiSubstitutor otherSubstitutor = otherSuperSignature.getSubstitutor();
|
||||
PsiType otherSuperReturnType = otherSubstitutor.substitute(otherSuperMethod.getReturnType());
|
||||
PsiSubstitutor unifyingSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(returnTypeSubstitutable[0],
|
||||
otherSuperSignature);
|
||||
if (unifyingSubstitutor != null) {
|
||||
otherSuperReturnType = unifyingSubstitutor.substitute(otherSuperReturnType);
|
||||
@@ -1319,20 +1319,25 @@ public class HighlightMethodUtil {
|
||||
}
|
||||
|
||||
if (otherSuperReturnType == null || currentType == null || otherSuperReturnType.equals(currentType)) continue;
|
||||
|
||||
if (languageLevel.isAtLeast(LanguageLevel.JDK_1_5)) {
|
||||
//http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.8 Example 8.1.5-3
|
||||
if (!(otherSuperReturnType instanceof PsiPrimitiveType || currentType instanceof PsiPrimitiveType)) {
|
||||
if (otherSuperReturnType.isAssignableFrom(currentType)) continue;
|
||||
if (currentType.isAssignableFrom(otherSuperReturnType)) {
|
||||
returnTypeSubstitutable = otherSuperSignature;
|
||||
continue;
|
||||
PsiType otherReturnType = otherSuperReturnType;
|
||||
PsiType curType = currentType;
|
||||
final HighlightInfo info =
|
||||
LambdaUtil.performWithSubstitutedParameterBounds(otherSuperMethod.getTypeParameters(), otherSubstitutor, () -> {
|
||||
if (languageLevel.isAtLeast(LanguageLevel.JDK_1_5)) {
|
||||
//http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.8 Example 8.1.5-3
|
||||
if (!(otherReturnType instanceof PsiPrimitiveType || curType instanceof PsiPrimitiveType)) {
|
||||
if (otherReturnType.isAssignableFrom(curType)) return null;
|
||||
if (curType.isAssignableFrom(otherReturnType)) {
|
||||
returnTypeSubstitutable[0] = otherSuperSignature;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (otherSuperMethod.getTypeParameters().length > 0 && JavaGenericsUtil.isRawToGeneric(curType, otherReturnType)) return null;
|
||||
}
|
||||
}
|
||||
if (otherSuperMethod.getTypeParameters().length > 0 && JavaGenericsUtil.isRawToGeneric(currentType, otherSuperReturnType)) continue;
|
||||
}
|
||||
return createIncompatibleReturnTypeMessage(otherSuperMethod, currentMethod, currentType, otherSuperReturnType,
|
||||
JavaErrorMessages.message("unrelated.overriding.methods.return.types"), TextRange.EMPTY_RANGE);
|
||||
return createIncompatibleReturnTypeMessage(otherSuperMethod, currentMethod, curType, otherReturnType,
|
||||
JavaErrorMessages.message("unrelated.overriding.methods.return.types"), TextRange.EMPTY_RANGE);
|
||||
});
|
||||
if (info != null) return info;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,10 @@ import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil
|
||||
import com.intellij.psi.infos.MethodCandidateInfo;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.Producer;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -821,6 +824,34 @@ public class LambdaUtil {
|
||||
return copyCall;
|
||||
}
|
||||
|
||||
public static <T> T performWithSubstitutedParameterBounds(final PsiTypeParameter[] typeParameters,
|
||||
final PsiSubstitutor substitutor,
|
||||
final Producer<T> producer) {
|
||||
try {
|
||||
for (PsiTypeParameter parameter : typeParameters) {
|
||||
final PsiClassType[] types = parameter.getExtendsListTypes();
|
||||
if (types.length > 0) {
|
||||
final List<PsiType> conjuncts = ContainerUtil.map(types, new Function<PsiClassType, PsiType>() {
|
||||
@Override
|
||||
public PsiType fun(PsiClassType type) {
|
||||
return substitutor.substitute(type);
|
||||
}
|
||||
});
|
||||
//don't glb to avoid flattening = Object&Interface would be preserved
|
||||
//otherwise methods with different signatures could get same erasure
|
||||
final PsiType upperBound = PsiIntersectionType.createIntersection(false, conjuncts.toArray(new PsiType[conjuncts.size()]));
|
||||
getFunctionalTypeMap().put(parameter, upperBound);
|
||||
}
|
||||
}
|
||||
return producer.produce();
|
||||
}
|
||||
finally {
|
||||
for (PsiTypeParameter parameter : typeParameters) {
|
||||
getFunctionalTypeMap().remove(parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class TypeParamsChecker extends PsiTypeVisitor<Boolean> {
|
||||
private PsiMethod myMethod;
|
||||
private final PsiClass myClass;
|
||||
|
||||
+9
-25
@@ -32,6 +32,7 @@ import com.intellij.psi.util.*;
|
||||
import com.intellij.util.ArrayUtilRt;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.Producer;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -1651,36 +1652,19 @@ public class InferenceSession {
|
||||
/**
|
||||
* 18.5.4 More Specific Method Inference
|
||||
*/
|
||||
public static boolean isMoreSpecific(PsiMethod m1,
|
||||
public static boolean isMoreSpecific(final PsiMethod m1,
|
||||
final PsiMethod m2,
|
||||
final PsiSubstitutor siteSubstitutor1,
|
||||
final PsiSubstitutor siteSubstitutor1,
|
||||
final PsiExpression[] args,
|
||||
final PsiElement context,
|
||||
final boolean varargs) {
|
||||
final PsiTypeParameter[] typeParameters = m1.getTypeParameters();
|
||||
try {
|
||||
for (PsiTypeParameter parameter : typeParameters) {
|
||||
final PsiClassType[] types = parameter.getExtendsListTypes();
|
||||
if (types.length > 0) {
|
||||
final List<PsiType> conjuncts = ContainerUtil.map(types, new Function<PsiClassType, PsiType>() {
|
||||
@Override
|
||||
public PsiType fun(PsiClassType type) {
|
||||
return siteSubstitutor1.substitute(type);
|
||||
}
|
||||
});
|
||||
//don't glb to avoid flattening = Object&Interface would be preserved
|
||||
//otherwise methods with different signatures could get same erasure
|
||||
final PsiType upperBound = PsiIntersectionType.createIntersection(false, conjuncts.toArray(new PsiType[conjuncts.size()]));
|
||||
LambdaUtil.getFunctionalTypeMap().put(parameter, upperBound);
|
||||
}
|
||||
return LambdaUtil.performWithSubstitutedParameterBounds(m1.getTypeParameters(), siteSubstitutor1, new Producer<Boolean>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Boolean produce() {
|
||||
return isMoreSpecificInternal(m1, m2, siteSubstitutor1, args, context, varargs);
|
||||
}
|
||||
return isMoreSpecificInternal(m1, m2, siteSubstitutor1, args, context, varargs);
|
||||
}
|
||||
finally {
|
||||
for (PsiTypeParameter parameter : typeParameters) {
|
||||
LambdaUtil.getFunctionalTypeMap().remove(parameter);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean isMoreSpecificInternal(PsiMethod m1,
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import java.util.List;
|
||||
|
||||
interface A {
|
||||
String save(String world);
|
||||
}
|
||||
|
||||
interface Test2 extends A, CR<String> {}
|
||||
interface Test1 extends CR<String>, A {}
|
||||
interface CR<T> {
|
||||
<S extends T> S save(S var1);
|
||||
<S extends T> List<S> save(Iterable<S> var1);
|
||||
}
|
||||
+4
@@ -1005,4 +1005,8 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase {
|
||||
public void testMembersContainedInCapturedWildcardType() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testTypeParameterBoundsWithSubstitutionWhenMethodHierarchyIsChecked() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user