[java] method references overload resolution (IDEA-276614; IDEA-276613)

GitOrigin-RevId: a12beac2ccd0ecc2512c8b9feab5e04a868c3935
This commit is contained in:
trushev
2021-08-27 12:34:00 +02:00
committed by intellij-monorepo-bot
parent 32ec2d9a30
commit 7c1c056980
4 changed files with 70 additions and 16 deletions

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.psi.impl.source.tree.java;
import com.intellij.openapi.util.text.StringUtil;
@@ -235,12 +235,21 @@ 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;
}
}
}
@@ -259,11 +268,13 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
}
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;
}
@@ -278,6 +289,28 @@ 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,
@@ -307,6 +340,9 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
return null;
}
}
} else if (hasReceiver && varargs &&
isCorrectAssignment(parameterTypes, functionalInterfaceParamTypes, interfaceMethod, true, conflict, 1)) {
return false;
}
return true;
}

View File

@@ -0,0 +1,15 @@
class Test {
static class A {
void foo(A... as) {}
static void foo(A a) {}
}
interface I {
void bar(A a);
}
static void test() {
I i = A::<error descr="Reference to 'foo' is ambiguous, both 'foo(A)' and 'foo(A...)' match">foo</error>;
}
}

View File

@@ -0,0 +1,15 @@
class Test {
static class A {
void foo() {}
static void foo(A a, A... as) {}
}
interface I {
void bar(A a);
}
static void test() {
I i = A::<error descr="Reference to 'foo' is ambiguous, both 'foo(A, A...)' and 'foo()' match">foo</error>;
}
}

View File

@@ -1,18 +1,4 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.codeInsight.daemon.lambda;
import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
@@ -86,6 +72,8 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
.forEach(info -> Assert.assertEquals("<html>Reference to 'm' is ambiguous, both 'm(Test, String)' and 'm(String)' match</html>",
info.getToolTip()));
}
public void testStaticWithVarargsNonStaticReferenceTypeAmbiguity() { doTest(); }
public void testStaticNonStaticWithVarargsReferenceTypeAmbiguity() { doTest(); }
public void testSuperClassPotentiallyApplicableMembers() { doTest(); }
public void testExactMethodReferencePertinentToApplicabilityCheck() { doTest(); }
public void testAmbiguityVarargs() { doTest(); }