mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-05 01:50:56 +07:00
[java] method references overload resolution (IDEA-276614; IDEA-276613)
check static conflicts between applicable methods vs most specific method of another search, as the spec says GitOrigin-RevId: d11508968a88888c41f6d69e416ab8fa5e915e5d
This commit is contained in:
committed by
intellij-monorepo-bot
parent
7c1c056980
commit
f47a4e818b
@@ -235,46 +235,49 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
|
||||
|
||||
List<CandidateInfo> firstCandidates = new ArrayList<>();
|
||||
List<CandidateInfo> secondCandidates = new ArrayList<>();
|
||||
boolean thereIsStaticInTheFirst = false;
|
||||
boolean thereIsNonStaticInTheSecond = false;
|
||||
|
||||
for (CandidateInfo conflict : conflicts) {
|
||||
if (!(conflict instanceof MethodCandidateInfo)) continue;
|
||||
Boolean applicableByFirstSearch = isApplicableByFirstSearch(conflict, argTypes, hasReceiver, myReferenceExpression, myFunctionalMethodVarArgs, myInterfaceMethod);
|
||||
if (applicableByFirstSearch != null) {
|
||||
(applicableByFirstSearch ? firstCandidates : secondCandidates).add(conflict);
|
||||
boolean isStatic = isStaticMethod(conflict);
|
||||
if (isStatic && applicableByFirstSearch) {
|
||||
thereIsStaticInTheFirst = true;
|
||||
}
|
||||
if (!isStatic && !applicableByFirstSearch) {
|
||||
thereIsNonStaticInTheSecond = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (myQualifierResolveResult.isReferenceTypeQualified() && myReferenceExpression.getReferenceNameElement() instanceof PsiIdentifier) {
|
||||
int firstApplicability = checkApplicability(firstCandidates);
|
||||
ArrayList<CandidateInfo> firstResults = new ArrayList<>(firstCandidates);
|
||||
checkSpecifics(firstResults, firstApplicability, map, 0);
|
||||
|
||||
int secondApplicability = checkApplicability(secondCandidates);
|
||||
ArrayList<CandidateInfo> secondResults = new ArrayList<>(secondCandidates);
|
||||
checkSpecifics(secondResults, secondApplicability, map, 1);
|
||||
|
||||
//If the first search produces a static method, and no non-static method is applicable for the second search, then the result of the first search is the compile-time declaration.
|
||||
CandidateInfo candidateInfo = filterStaticCorrectCandidates(firstCandidates, secondCandidates, true);
|
||||
CandidateInfo candidateInfo = filterStaticCorrectCandidates(firstResults, secondCandidates, true);
|
||||
if (candidateInfo != null) {
|
||||
return candidateInfo;
|
||||
}
|
||||
|
||||
//If the second search produces a non-static method, and no static method is applicable for the first search, then the result of the second search is the compile-time declaration.
|
||||
candidateInfo = filterStaticCorrectCandidates(secondCandidates, firstCandidates, false);
|
||||
candidateInfo = filterStaticCorrectCandidates(secondResults, firstCandidates, false);
|
||||
if (candidateInfo != null) {
|
||||
return candidateInfo;
|
||||
}
|
||||
|
||||
conflicts.clear();
|
||||
conflicts.addAll(firstResults);
|
||||
conflicts.addAll(secondResults);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
CandidateInfo candidateInfo = resolveConflicts(firstCandidates, secondCandidates, map, MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY);
|
||||
candidateInfo = checkStaticNonStaticConflict(candidateInfo, firstCandidates, secondCandidates, thereIsStaticInTheFirst, thereIsNonStaticInTheSecond);
|
||||
if (candidateInfo != null) {
|
||||
return candidateInfo;
|
||||
}
|
||||
|
||||
candidateInfo = resolveConflicts(firstCandidates, secondCandidates, map, MethodCandidateInfo.ApplicabilityLevel.VARARGS);
|
||||
candidateInfo = checkStaticNonStaticConflict(candidateInfo, firstCandidates, secondCandidates, thereIsStaticInTheFirst, thereIsNonStaticInTheSecond);
|
||||
if (candidateInfo != null) {
|
||||
return candidateInfo;
|
||||
}
|
||||
@@ -289,28 +292,6 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
|
||||
return null;
|
||||
}
|
||||
|
||||
private CandidateInfo checkStaticNonStaticConflict(CandidateInfo candidateInfo,
|
||||
@NotNull List<CandidateInfo> firstCandidates,
|
||||
@NotNull List<CandidateInfo> secondCandidates,
|
||||
boolean thereIsStaticInTheFirst,
|
||||
boolean thereIsNonStaticInTheSecond) {
|
||||
if (candidateInfo == null ||
|
||||
!myQualifierResolveResult.isReferenceTypeQualified() ||
|
||||
!(myReferenceExpression.getReferenceNameElement() instanceof PsiIdentifier)) {
|
||||
return candidateInfo;
|
||||
}
|
||||
boolean isStatic = isStaticMethod(candidateInfo);
|
||||
if (isStatic && !thereIsNonStaticInTheSecond && firstCandidates.contains(candidateInfo) ||
|
||||
!isStatic && !thereIsStaticInTheFirst && secondCandidates.contains(candidateInfo)) {
|
||||
return candidateInfo;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isStaticMethod(@NotNull CandidateInfo candidateInfo) {
|
||||
return ((MethodCandidateInfo) candidateInfo).getElement().hasModifierProperty(PsiModifier.STATIC);
|
||||
}
|
||||
|
||||
private static Boolean isApplicableByFirstSearch(@NotNull CandidateInfo conflict,
|
||||
PsiType @NotNull [] functionalInterfaceParamTypes,
|
||||
boolean hasReceiver,
|
||||
@@ -328,6 +309,14 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
|
||||
if (varargs && (!psiMethod.isVarArgs() || functionalMethodVarArgs)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//prefer statically correct search variant when a vararg method is applicable both as first and second search
|
||||
if (hasReceiver &&
|
||||
varargs &&
|
||||
isCorrectAssignment(parameterTypes, functionalInterfaceParamTypes, interfaceMethod, true, conflict, 0) &&
|
||||
isCorrectAssignment(parameterTypes, functionalInterfaceParamTypes, interfaceMethod, true, conflict, 1)) {
|
||||
return psiMethod.hasModifierProperty(PsiModifier.STATIC);
|
||||
}
|
||||
|
||||
if ((varargs || functionalInterfaceParamTypes.length == parameterTypes.length) &&
|
||||
isCorrectAssignment(parameterTypes, functionalInterfaceParamTypes, interfaceMethod, varargs, conflict, 0)) {
|
||||
@@ -340,9 +329,6 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else if (hasReceiver && varargs &&
|
||||
isCorrectAssignment(parameterTypes, functionalInterfaceParamTypes, interfaceMethod, true, conflict, 1)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ class AlienTest {
|
||||
static {
|
||||
IInt i1 = MyTest::<error descr="Cannot resolve method 'abracadabra'">abracadabra</error>;
|
||||
IInt i2 = MyTest::<error descr="Incompatible types: int is not convertible to String">foo</error>;
|
||||
IInt i3 = MyTest::<error descr="Reference to 'bar' is ambiguous, both 'bar(Integer, Number)' and 'bar(Number, Integer)' match">bar</error>;
|
||||
IInt i3 = MyTest::<error descr="Cannot resolve method 'bar'">bar</error>;
|
||||
IIntInt i4 = MyTest::<error descr="Reference to 'bar' is ambiguous, both 'bar(Integer, Number)' and 'bar(Number, Integer)' match">bar</error>;
|
||||
IInt i5 = <error descr="Non-static method cannot be referenced from a static context">MyTest::baz</error>;
|
||||
IInt i6 = <error descr="'foo(int)' is not public in 'MyTest.Foo'. Cannot be accessed from outside package">MyTest.foo::foo</error>;
|
||||
|
||||
@@ -122,7 +122,7 @@ class MyTest4 {
|
||||
}
|
||||
|
||||
{
|
||||
bar(MyTest4:: <error descr="Reference to 'foo' is ambiguous, both 'foo(int)' and 'foo(String)' match">foo</error>);
|
||||
bar(MyTest4:: <error descr="Cannot resolve method 'foo'">foo</error>);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ class Test {
|
||||
|
||||
class Test1 {
|
||||
{
|
||||
Runnable b = Test1 :: <error descr="Reference to 'length' is ambiguous, both 'length(String)' and 'length(Integer)' match">length</error>;
|
||||
Runnable b = Test1 :: <error descr="Cannot resolve method 'length'">length</error>;
|
||||
Comparable<String> c = Test1 :: length;
|
||||
Comparable<Integer> c1 = Test1 :: length;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ class MyTest {
|
||||
I1 i1 = MyTest::static_1;
|
||||
I1 i2 = MyTest::<error descr="Cannot resolve method 'static_2'">static_2</error>;
|
||||
I1 i3 = MyTest::<error descr="Incompatible types: int is not convertible to String">static_3</error>;
|
||||
I1 i4 = MyTest::<error descr="Reference to 'static_4' is ambiguous, both 'static_4(String...)' and 'static_4(String...)' match">static_4</error>;
|
||||
I1 i4 = MyTest::<error descr="Cannot resolve method 'static_4'">static_4</error>;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ class MyTest {
|
||||
I1 i_1 = <error descr="Non-static method cannot be referenced from a static context">MyTest::_1</error>;
|
||||
I1 i_2 = <error descr="Non-static method cannot be referenced from a static context">MyTest::_2</error>;
|
||||
I1 i_3 = <error descr="Non-static method cannot be referenced from a static context">MyTest::_3</error>;
|
||||
I1 i_4 = MyTest::<error descr="Reference to '_4' is ambiguous, both '_4(String...)' and '_4(String...)' match">_4</error>;
|
||||
I1 i_4 = MyTest::<error descr="Cannot resolve method '_4'">_4</error>;
|
||||
|
||||
I1 i1 = this::_1;
|
||||
I1 i2 = this::<error descr="Cannot resolve method '_2'">_2</error>;
|
||||
|
||||
Reference in New Issue
Block a user