mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-09 15:41:26 +07:00
method refs: take qualifier's type arguments in account
This commit is contained in:
@@ -569,26 +569,34 @@ public class LambdaUtil {
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(left);
|
||||
final PsiMethod method = getFunctionalInterfaceMethod(resolveResult);
|
||||
if (method != null) {
|
||||
final MethodSignature signature1 = method.getSignature(resolveResult.getSubstitutor());
|
||||
final MethodSignature signature2 = ((PsiMethod)resolve).getSignature(JavaPsiFacade.getElementFactory(method.getProject()).createRawSubstitutor(
|
||||
(PsiTypeParameterListOwner)resolve));
|
||||
final Ref<PsiClass> classRef = new Ref<PsiClass>();
|
||||
methodReferenceExpression.process(classRef, new Ref<PsiSubstitutor>());
|
||||
if (areAcceptable(signature1, signature2, classRef.get())) return true;
|
||||
final Ref<PsiSubstitutor> substRef = new Ref<PsiSubstitutor>();
|
||||
methodReferenceExpression.process(classRef, substRef);
|
||||
|
||||
final MethodSignature signature1 = method.getSignature(resolveResult.getSubstitutor());
|
||||
final MethodSignature signature2 = ((PsiMethod)resolve).getSignature(substRef.get());
|
||||
if (areAcceptable(signature1, signature2, classRef.get(), substRef.get())) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean areAcceptable(MethodSignature signature1, MethodSignature signature2, PsiClass psiClass) {
|
||||
public static boolean areAcceptable(MethodSignature signature1,
|
||||
MethodSignature signature2,
|
||||
PsiClass psiClass,
|
||||
PsiSubstitutor psiSubstitutor) {
|
||||
int offset = 0;
|
||||
final PsiType[] signatureParameterTypes1 = signature1.getParameterTypes();
|
||||
final PsiType[] signatureParameterTypes2 = signature2.getParameterTypes();
|
||||
if (signatureParameterTypes1.length != signatureParameterTypes2.length) {
|
||||
if (signatureParameterTypes1.length == signatureParameterTypes2.length + 1 &&
|
||||
//todo correct check needed
|
||||
PsiUtil.resolveClassInType(TypeConversionUtil.erasure(signatureParameterTypes1[0], signature1.getSubstitutor())) == psiClass) {
|
||||
offset++;
|
||||
if (signatureParameterTypes1.length == signatureParameterTypes2.length + 1) {
|
||||
final PsiClassType classType = JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass, psiSubstitutor);
|
||||
if (signatureParameterTypes1[0].equals(classType)) {
|
||||
offset++;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
|
||||
+12
-9
@@ -33,6 +33,7 @@ import com.intellij.psi.scope.processor.FilterScopeProcessor;
|
||||
import com.intellij.psi.scope.processor.MethodCandidatesProcessor;
|
||||
import com.intellij.psi.scope.util.PsiScopesUtil;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.MethodSignature;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.SmartList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -216,7 +217,7 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
|
||||
final PsiType functionalInterfaceType = getFunctionalInterfaceType();
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
|
||||
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult);
|
||||
final MethodReferenceConflictResolver conflictResolver = new MethodReferenceConflictResolver(containingClass, interfaceMethod, resolveResult.getSubstitutor());
|
||||
final MethodReferenceConflictResolver conflictResolver = new MethodReferenceConflictResolver(containingClass, substitutor, interfaceMethod != null ? interfaceMethod.getSignature(resolveResult.getSubstitutor()) : null);
|
||||
final MethodCandidatesProcessor processor = new MethodCandidatesProcessor(PsiMethodReferenceExpressionImpl.this,
|
||||
new PsiConflictResolver[]{conflictResolver}, new SmartList<CandidateInfo>());
|
||||
processor.setIsConstructor(false);
|
||||
@@ -234,27 +235,29 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
|
||||
|
||||
private class MethodReferenceConflictResolver implements PsiConflictResolver {
|
||||
private final PsiClass myContainingClass;
|
||||
private PsiMethod myFunctionalInterface;
|
||||
private final PsiSubstitutor mySubstitutor;
|
||||
|
||||
private MethodReferenceConflictResolver(PsiClass containingClass, @Nullable PsiMethod psiMethod, PsiSubstitutor substitutor) {
|
||||
private final MethodSignature mySignature;
|
||||
|
||||
private MethodReferenceConflictResolver(PsiClass containingClass,
|
||||
PsiSubstitutor psiSubstitutor,
|
||||
@Nullable MethodSignature signature) {
|
||||
myContainingClass = containingClass;
|
||||
myFunctionalInterface = psiMethod;
|
||||
mySubstitutor = substitutor;
|
||||
mySubstitutor = psiSubstitutor;
|
||||
mySignature = signature;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CandidateInfo resolveConflict(List<CandidateInfo> conflicts) {
|
||||
if (myFunctionalInterface == null) return null;
|
||||
if (mySignature == null) return null;
|
||||
|
||||
for (Iterator<CandidateInfo> iterator = conflicts.iterator(); iterator.hasNext(); ) {
|
||||
CandidateInfo conflict = iterator.next();
|
||||
if (!(conflict instanceof MethodCandidateInfo)) continue;
|
||||
final PsiMethod psiMethod = ((MethodCandidateInfo)conflict).getElement();
|
||||
if (psiMethod == null) continue;
|
||||
if (!LambdaUtil.areAcceptable(myFunctionalInterface.getSignature(mySubstitutor),
|
||||
psiMethod.getSignature(conflict.getSubstitutor()), myContainingClass)) {
|
||||
if (!LambdaUtil.areAcceptable(mySignature,
|
||||
psiMethod.getSignature(conflict.getSubstitutor()), myContainingClass, mySubstitutor)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
class MyTest {
|
||||
interface I {
|
||||
String m(Foo<String> f);
|
||||
}
|
||||
|
||||
class Foo<X> {
|
||||
String foo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
{
|
||||
I i = Foo<String> :: foo;
|
||||
<error descr="Incompatible types. Found: '<method reference>', required: 'MyTest.I'">I i1 = Foo<Integer> :: foo;</error>
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
@@ -41,6 +41,10 @@ public class MethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testQualifierTypeArgs() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() throws Exception {
|
||||
doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user