mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +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 PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(left);
|
||||||
final PsiMethod method = getFunctionalInterfaceMethod(resolveResult);
|
final PsiMethod method = getFunctionalInterfaceMethod(resolveResult);
|
||||||
if (method != null) {
|
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>();
|
final Ref<PsiClass> classRef = new Ref<PsiClass>();
|
||||||
methodReferenceExpression.process(classRef, new Ref<PsiSubstitutor>());
|
final Ref<PsiSubstitutor> substRef = new Ref<PsiSubstitutor>();
|
||||||
if (areAcceptable(signature1, signature2, classRef.get())) return true;
|
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;
|
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;
|
int offset = 0;
|
||||||
final PsiType[] signatureParameterTypes1 = signature1.getParameterTypes();
|
final PsiType[] signatureParameterTypes1 = signature1.getParameterTypes();
|
||||||
final PsiType[] signatureParameterTypes2 = signature2.getParameterTypes();
|
final PsiType[] signatureParameterTypes2 = signature2.getParameterTypes();
|
||||||
if (signatureParameterTypes1.length != signatureParameterTypes2.length) {
|
if (signatureParameterTypes1.length != signatureParameterTypes2.length) {
|
||||||
if (signatureParameterTypes1.length == signatureParameterTypes2.length + 1 &&
|
if (signatureParameterTypes1.length == signatureParameterTypes2.length + 1) {
|
||||||
//todo correct check needed
|
final PsiClassType classType = JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass, psiSubstitutor);
|
||||||
PsiUtil.resolveClassInType(TypeConversionUtil.erasure(signatureParameterTypes1[0], signature1.getSubstitutor())) == psiClass) {
|
if (signatureParameterTypes1[0].equals(classType)) {
|
||||||
offset++;
|
offset++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return false;
|
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.processor.MethodCandidatesProcessor;
|
||||||
import com.intellij.psi.scope.util.PsiScopesUtil;
|
import com.intellij.psi.scope.util.PsiScopesUtil;
|
||||||
import com.intellij.psi.tree.IElementType;
|
import com.intellij.psi.tree.IElementType;
|
||||||
|
import com.intellij.psi.util.MethodSignature;
|
||||||
import com.intellij.psi.util.PsiUtil;
|
import com.intellij.psi.util.PsiUtil;
|
||||||
import com.intellij.util.SmartList;
|
import com.intellij.util.SmartList;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -216,7 +217,7 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
|
|||||||
final PsiType functionalInterfaceType = getFunctionalInterfaceType();
|
final PsiType functionalInterfaceType = getFunctionalInterfaceType();
|
||||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
|
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
|
||||||
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult);
|
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,
|
final MethodCandidatesProcessor processor = new MethodCandidatesProcessor(PsiMethodReferenceExpressionImpl.this,
|
||||||
new PsiConflictResolver[]{conflictResolver}, new SmartList<CandidateInfo>());
|
new PsiConflictResolver[]{conflictResolver}, new SmartList<CandidateInfo>());
|
||||||
processor.setIsConstructor(false);
|
processor.setIsConstructor(false);
|
||||||
@@ -234,27 +235,29 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
|
|||||||
|
|
||||||
private class MethodReferenceConflictResolver implements PsiConflictResolver {
|
private class MethodReferenceConflictResolver implements PsiConflictResolver {
|
||||||
private final PsiClass myContainingClass;
|
private final PsiClass myContainingClass;
|
||||||
private PsiMethod myFunctionalInterface;
|
|
||||||
private final PsiSubstitutor mySubstitutor;
|
private final PsiSubstitutor mySubstitutor;
|
||||||
|
private final MethodSignature mySignature;
|
||||||
private MethodReferenceConflictResolver(PsiClass containingClass, @Nullable PsiMethod psiMethod, PsiSubstitutor substitutor) {
|
|
||||||
|
private MethodReferenceConflictResolver(PsiClass containingClass,
|
||||||
|
PsiSubstitutor psiSubstitutor,
|
||||||
|
@Nullable MethodSignature signature) {
|
||||||
myContainingClass = containingClass;
|
myContainingClass = containingClass;
|
||||||
myFunctionalInterface = psiMethod;
|
mySubstitutor = psiSubstitutor;
|
||||||
mySubstitutor = substitutor;
|
mySignature = signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public CandidateInfo resolveConflict(List<CandidateInfo> conflicts) {
|
public CandidateInfo resolveConflict(List<CandidateInfo> conflicts) {
|
||||||
if (myFunctionalInterface == null) return null;
|
if (mySignature == null) return null;
|
||||||
|
|
||||||
for (Iterator<CandidateInfo> iterator = conflicts.iterator(); iterator.hasNext(); ) {
|
for (Iterator<CandidateInfo> iterator = conflicts.iterator(); iterator.hasNext(); ) {
|
||||||
CandidateInfo conflict = iterator.next();
|
CandidateInfo conflict = iterator.next();
|
||||||
if (!(conflict instanceof MethodCandidateInfo)) continue;
|
if (!(conflict instanceof MethodCandidateInfo)) continue;
|
||||||
final PsiMethod psiMethod = ((MethodCandidateInfo)conflict).getElement();
|
final PsiMethod psiMethod = ((MethodCandidateInfo)conflict).getElement();
|
||||||
if (psiMethod == null) continue;
|
if (psiMethod == null) continue;
|
||||||
if (!LambdaUtil.areAcceptable(myFunctionalInterface.getSignature(mySubstitutor),
|
if (!LambdaUtil.areAcceptable(mySignature,
|
||||||
psiMethod.getSignature(conflict.getSubstitutor()), myContainingClass)) {
|
psiMethod.getSignature(conflict.getSubstitutor()), myContainingClass, mySubstitutor)) {
|
||||||
iterator.remove();
|
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();
|
doTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testQualifierTypeArgs() throws Exception {
|
||||||
|
doTest();
|
||||||
|
}
|
||||||
|
|
||||||
private void doTest() throws Exception {
|
private void doTest() throws Exception {
|
||||||
doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
|
doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user