[java-highlighting] Do not report incompatible type on calls when found type is lambda

Fixes IDEA-336129 Incorrect error if excess arguments passed to a function with lambda

GitOrigin-RevId: 712960416933e710740b9053b3604039c9a9b2ef
This commit is contained in:
Tagir Valeev
2025-03-21 10:11:38 +01:00
committed by intellij-monorepo-bot
parent c855231a3b
commit a8dac43c9e
6 changed files with 38 additions and 13 deletions

View File

@@ -330,10 +330,16 @@ final class ExpressionChecker {
if (mismatchedExpressions.size() == list.getExpressions().length || mismatchedExpressions.isEmpty()) {
PsiElement anchor = list.getTextRange().isEmpty() ? ObjectUtils.notNull(list.getPrevSibling(), list) : list;
if (!mismatchedExpressions.isEmpty() && !context.argCountMismatch() &&
ContainerUtil.and(mismatchedExpressions, e -> e.getType() instanceof PsiLambdaParameterType)) {
// Likely, the problem is induced
return;
}
myVisitor.report(JavaErrorKinds.CALL_WRONG_ARGUMENTS.create(anchor, context));
}
else {
for (PsiExpression wrongArg : mismatchedExpressions) {
if (wrongArg.getType() instanceof PsiLambdaParameterType) continue;
myVisitor.report(JavaErrorKinds.CALL_WRONG_ARGUMENTS.create(wrongArg, context));
}
}

View File

@@ -32,10 +32,9 @@ public record JavaMismatchedCallContext(@NotNull PsiExpressionList list,
@NotNull List<PsiExpression> mismatchedExpressions) {
@NotNull @Nls String createDescription() {
PsiMethod resolvedMethod = candidate.getElement();
PsiExpression[] expressions = list.getExpressions();
PsiParameter[] parameters = resolvedMethod.getParameterList().getParameters();
if (argCountMismatch(parameters, expressions)) {
return JavaCompilationErrorBundle.message("call.wrong.arguments.count.mismatch", parameters.length, expressions.length);
if (argCountMismatch()) {
int parametersCount = resolvedMethod.getParameterList().getParametersCount();
return JavaCompilationErrorBundle.message("call.wrong.arguments.count.mismatch", parametersCount, list.getExpressionCount());
}
PsiClass parent = resolvedMethod.getContainingClass();
PsiSubstitutor substitutor = candidate.getSubstitutor();
@@ -44,6 +43,13 @@ public record JavaMismatchedCallContext(@NotNull PsiExpressionList list,
String methodName = HighlightMessageUtil.getSymbolName(resolvedMethod, substitutor);
return JavaCompilationErrorBundle.message("call.wrong.arguments", methodName, containerName, argTypes);
}
public boolean argCountMismatch() {
PsiMethod resolvedMethod = candidate.getElement();
PsiExpression[] expressions = list.getExpressions();
PsiParameter[] parameters = resolvedMethod.getParameterList().getParameters();
return argCountMismatch(parameters, expressions);
}
@NotNull HtmlChunk createTooltip() {
PsiMethod resolvedMethod = candidate.getElement();
@@ -69,11 +75,6 @@ public record JavaMismatchedCallContext(@NotNull PsiExpressionList list,
PsiMethod method = candidate.getElement();
PsiSubstitutor substitutor = candidate.getSubstitutor();
PsiParameter[] parameters = method.getParameterList().getParameters();
return createMismatchedArgumentsHtmlTooltip(parameters, substitutor);
}
private @NotNull HtmlChunk createMismatchedArgumentsHtmlTooltip(PsiParameter @NotNull [] parameters,
@NotNull PsiSubstitutor substitutor) {
PsiExpression[] expressions = list.getExpressions();
if (argCountMismatch(parameters, expressions)) {
return createMismatchedArgumentCountTooltip(parameters.length, expressions.length);

View File

@@ -4,8 +4,8 @@ import java.util.function.Supplier;
class OverloadCast {
public void runMe() {
new OverloadCast<error descr="Cannot resolve constructor 'OverloadCast(<method reference>, <lambda expression>)'">(WhitespaceTokenizer::<error descr="Cannot resolve constructor 'WhitespaceTokenizer'">new</error>, src -> new LowerCaseFilter<error descr="'LowerCaseFilter(OverloadCast.TokenStream)' in 'OverloadCast.LowerCaseFilter' cannot be applied to '(<lambda parameter>)'">(src)</error>)</error>;
overloadCast<error descr="Ambiguous method call: both 'OverloadCast.overloadCast(Supplier<Tokenizer>, Function<TokenStream, TokenFilter>)' and 'OverloadCast.overloadCast(Function<TokenStream, TokenFilter>, Function<String, String>)' match">(WhitespaceTokenizer::<error descr="Cannot resolve constructor 'WhitespaceTokenizer'">new</error>, src -> new LowerCaseFilter<error descr="'LowerCaseFilter(OverloadCast.TokenStream)' in 'OverloadCast.LowerCaseFilter' cannot be applied to '(<lambda parameter>)'">(src)</error>)</error>;
new OverloadCast<error descr="Cannot resolve constructor 'OverloadCast(<method reference>, <lambda expression>)'">(WhitespaceTokenizer::<error descr="Cannot resolve constructor 'WhitespaceTokenizer'">new</error>, src -> new LowerCaseFilter(src))</error>;
overloadCast<error descr="Ambiguous method call: both 'OverloadCast.overloadCast(Supplier<Tokenizer>, Function<TokenStream, TokenFilter>)' and 'OverloadCast.overloadCast(Function<TokenStream, TokenFilter>, Function<String, String>)' match">(WhitespaceTokenizer::<error descr="Cannot resolve constructor 'WhitespaceTokenizer'">new</error>, src -> new LowerCaseFilter(src))</error>;
}
private OverloadCast(Supplier<Tokenizer> tokenizerFactory, Function<TokenStream, TokenFilter> filterCreator) {

View File

@@ -1,7 +1,7 @@
class MyTest {
void m(String[] refInfos){
refInfos = <error descr="Cannot resolve method 'unresolved' in 'MyTest'">unresolved</error>(refInfos, refInfo -> {
refInfo = n<error descr="'n(java.lang.String)' in 'MyTest' cannot be applied to '(<lambda parameter>)'">(refInfo)</error>;
refInfo = n(refInfo);
return refInfo;
});
}

View File

@@ -5,4 +5,22 @@ class Test {
x = "hello";
}</error>;
}
void test2() {
Object obj = <error descr="Target type of a lambda conversion must be an interface">x -> consume(x)</error>;
Object obj1 = <error descr="Target type of a lambda conversion must be an interface">x -> consume2(x, 1)</error>;
Object obj2 = x -> consume2<error descr="'consume2(java.lang.String, int)' in 'Test' cannot be applied to '(<lambda parameter>, java.lang.String)'">(x, "hello")</error>;
Object obj3 = x -> consume3(x, <error descr="'consume3(java.lang.String, int, int)' in 'Test' cannot be applied to '(<lambda parameter>, java.lang.String, int)'">"hello"</error>, 1);
Object obj4 = x -> consume<error descr="Expected 1 argument but found 2">(x, x)</error>;
}
void consume(String s) {}
void consume2(String s, int i) {}
void consume3(String s, int i, int y) {}
}

View File

@@ -2,7 +2,7 @@ class MyTest {
void m(String[] refInfos){
refInfos = <error descr="Cannot resolve method 'unresolved' in 'MyTest'">unresolved</error>(refInfos, refInfo -> {
refInfo = refInfo.<error descr="Cannot resolve method 'replaceAll(String, String)'">replaceAll</error>("a", "b");
refInfo = n<error descr="'n(java.lang.String)' in 'MyTest' cannot be applied to '(<lambda parameter>)'">(refInfo)</error>;
refInfo = n(refInfo);
return refInfo;
});
}