mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
method refs: ensure raw substitutor is not used for second search case to build return type constraints (IDEA-165239)
This commit is contained in:
+15
-12
@@ -74,7 +74,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
|
||||
final PsiClass applicableMemberContainingClass = applicableMember.getContainingClass();
|
||||
final PsiClass containingClass = qualifierResolveResult.getContainingClass();
|
||||
|
||||
PsiSubstitutor psiSubstitutor = getSubstitutor(signature, qualifierResolveResult, applicableMember, applicableMemberContainingClass);
|
||||
PsiSubstitutor psiSubstitutor = getSubstitutor(signature, qualifierResolveResult, applicableMember, applicableMemberContainingClass, myExpression);
|
||||
|
||||
int idx = 0;
|
||||
for (PsiTypeParameter param : ((PsiTypeParameterListOwner)applicableMember).getTypeParameters()) {
|
||||
@@ -167,7 +167,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
|
||||
final PsiType referencedMethodReturnType;
|
||||
final PsiClass containingClass = method.getContainingClass();
|
||||
LOG.assertTrue(containingClass != null, method);
|
||||
PsiSubstitutor psiSubstitutor = getSubstitutor(signature, qualifierResolveResult, method, containingClass);
|
||||
PsiSubstitutor psiSubstitutor = getSubstitutor(signature, qualifierResolveResult, method, containingClass, myExpression);
|
||||
|
||||
if (method.isConstructor()) {
|
||||
referencedMethodReturnType = JavaPsiFacade.getElementFactory(method.getProject()).createType(containingClass, PsiSubstitutor.EMPTY);
|
||||
@@ -218,19 +218,22 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
|
||||
return true;
|
||||
}
|
||||
|
||||
private PsiSubstitutor getSubstitutor(MethodSignature signature,
|
||||
PsiMethodReferenceUtil.QualifierResolveResult qualifierResolveResult,
|
||||
PsiMember member,
|
||||
@Nullable PsiClass containingClass) {
|
||||
public static PsiSubstitutor getSubstitutor(MethodSignature signature,
|
||||
PsiMethodReferenceUtil.QualifierResolveResult qualifierResolveResult,
|
||||
PsiMember member,
|
||||
@Nullable PsiClass containingClass,
|
||||
final PsiMethodReferenceExpression methodReferenceExpression) {
|
||||
final PsiClass qContainingClass = qualifierResolveResult.getContainingClass();
|
||||
PsiSubstitutor psiSubstitutor = qualifierResolveResult.getSubstitutor();
|
||||
if (qContainingClass != null && containingClass != null) {
|
||||
// 15.13.1 If the ReferenceType is a raw type, and there exists a parameterization of this type, T, that is a supertype of P1,
|
||||
// the type to search is the result of capture conversion (5.1.10) applied to T;
|
||||
// otherwise, the type to search is the same as the type of the first search. Again, the type arguments, if any, are given by the method reference.
|
||||
if ( PsiUtil.isRawSubstitutor(qContainingClass, psiSubstitutor)) {
|
||||
if (member instanceof PsiMethod && PsiMethodReferenceUtil.isSecondSearchPossible(signature.getParameterTypes(), qualifierResolveResult, myExpression)) {
|
||||
final PsiType pType = PsiUtil.captureToplevelWildcards(signature.getParameterTypes()[0], myExpression);
|
||||
if (PsiUtil.isRawSubstitutor(qContainingClass, psiSubstitutor)) {
|
||||
if (member instanceof PsiMethod &&
|
||||
PsiMethodReferenceUtil.isSecondSearchPossible(signature.getParameterTypes(), qualifierResolveResult,
|
||||
methodReferenceExpression)) {
|
||||
final PsiType pType = PsiUtil.captureToplevelWildcards(signature.getParameterTypes()[0], methodReferenceExpression);
|
||||
psiSubstitutor = getParameterizedTypeSubstitutor(qContainingClass, pType);
|
||||
}
|
||||
else if (member instanceof PsiMethod && ((PsiMethod)member).isConstructor() || member instanceof PsiClass) {
|
||||
@@ -238,16 +241,16 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
|
||||
//If ClassType is a raw type, but is not a non-static member type of a raw type,
|
||||
//the candidate notional member methods are those specified in §15.9.3 for a class instance creation expression that uses <>
|
||||
//to elide the type arguments to a class.
|
||||
final PsiResolveHelper helper = JavaPsiFacade.getInstance(myExpression.getProject()).getResolveHelper();
|
||||
final PsiResolveHelper helper = JavaPsiFacade.getInstance(methodReferenceExpression.getProject()).getResolveHelper();
|
||||
final PsiType[] paramTypes =
|
||||
member instanceof PsiMethod ? ((PsiMethod)member).getSignature(PsiSubstitutor.EMPTY).getParameterTypes() : PsiType.EMPTY_ARRAY;
|
||||
LOG.assertTrue(paramTypes.length == signature.getParameterTypes().length, "expr: " + myExpression + "; " +
|
||||
LOG.assertTrue(paramTypes.length == signature.getParameterTypes().length, "expr: " + methodReferenceExpression + "; " +
|
||||
paramTypes.length + "; " +
|
||||
Arrays.toString(signature.getParameterTypes()));
|
||||
psiSubstitutor = helper.inferTypeArguments(qContainingClass.getTypeParameters(),
|
||||
paramTypes,
|
||||
signature.getParameterTypes(),
|
||||
PsiUtil.getLanguageLevel(myExpression));
|
||||
PsiUtil.getLanguageLevel(methodReferenceExpression));
|
||||
}
|
||||
else {
|
||||
psiSubstitutor = PsiSubstitutor.EMPTY;
|
||||
|
||||
+3
-1
@@ -21,6 +21,7 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy;
|
||||
import com.intellij.psi.impl.source.resolve.ResolveCache;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.constraints.PsiMethodReferenceCompatibilityConstraint;
|
||||
import com.intellij.psi.infos.CandidateInfo;
|
||||
import com.intellij.psi.infos.ClassCandidateInfo;
|
||||
import com.intellij.psi.infos.MethodCandidateInfo;
|
||||
@@ -127,7 +128,8 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
|
||||
}
|
||||
|
||||
if (includeReturnConstraint && !PsiType.VOID.equals(interfaceMethodReturnType) && interfaceMethodReturnType != null) {
|
||||
final PsiType returnType = method.isConstructor() ? composeReturnType(containingClass, substitutor) : substitutor.substitute(method.getReturnType());
|
||||
PsiSubstitutor subst = PsiMethodReferenceCompatibilityConstraint.getSubstitutor(signature, qualifierResolveResult, method, containingClass, reference);
|
||||
final PsiType returnType = method.isConstructor() ? composeReturnType(containingClass, subst) : subst.substitute(method.getReturnType());
|
||||
if (returnType != null) {
|
||||
session.registerReturnTypeConstraints(returnType, interfaceMethodReturnType);
|
||||
}
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
|
||||
class Test {
|
||||
public interface Copier<TypeT> {
|
||||
TypeT m(TypeT value);
|
||||
}
|
||||
|
||||
public static class A<PhantomT> {
|
||||
public <OtherT extends A<?>> OtherT copy() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static <TypeT> void foo(TypeT value, Copier<TypeT> copier) {}
|
||||
|
||||
public static void foo() {
|
||||
A<?> val = new A<>();
|
||||
foo(val, A::copy);
|
||||
}
|
||||
}
|
||||
+4
@@ -529,6 +529,10 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testReturnTypeCompatibilityConstraintForSecondSearchCase() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user