IDEA-386665 [java]: don't report lambda/method reference problems when their class type is unresolved

GitOrigin-RevId: e542751b8352847268bb6f98e83f5af33539e959
This commit is contained in:
Bas Leijdekkers
2026-04-04 17:06:12 +00:00
committed by intellij-monorepo-bot
parent d77eb20227
commit 9905bef526
10 changed files with 24 additions and 24 deletions
@@ -1,4 +1,4 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.java.codeserver.highlighting;
import com.intellij.codeInsight.UnhandledExceptions;
@@ -208,7 +208,7 @@ final class JavaErrorVisitor extends JavaElementVisitor {
if (ContainerUtil.exists(JavaErrorFilter.EP_NAME.getExtensionList(), ep -> ep.shouldSuppressError(myPsiFile, error))) return;
myErrorConsumer.accept(error);
}
@Contract(pure = true)
boolean isApplicable(@NotNull JavaFeature feature) {
return feature.isSufficient(myLanguageLevel);
@@ -242,7 +242,7 @@ final class JavaErrorVisitor extends JavaElementVisitor {
boolean hasErrorResults() {
return myHasError;
}
@Contract(pure = true)
boolean isIncompleteModel() {
return IncompleteModelUtil.isIncompleteModel(myPsiFile);
@@ -376,7 +376,7 @@ final class JavaErrorVisitor extends JavaElementVisitor {
if (!hasErrorResults()) checkFeature(annotation, JavaFeature.ANNOTATIONS);
myAnnotationChecker.checkAnnotation(annotation);
}
@Override
public void visitPackageStatement(@NotNull PsiPackageStatement statement) {
super.visitPackageStatement(statement);
@@ -517,8 +517,7 @@ final class JavaErrorVisitor extends JavaElementVisitor {
if (!hasErrorResults()) myFunctionChecker.checkMethodReferenceQualifier(expression);
if (!hasErrorResults()) {
boolean resolvedButNonApplicable = results.length == 1 && results[0] instanceof MethodCandidateInfo methodInfo &&
!methodInfo.isApplicable() &&
functionalInterfaceType != null;
!methodInfo.isApplicable() && functionalInterfaceType != null;
if (results.length != 1 || resolvedButNonApplicable) {
if (expression.isConstructor()) {
PsiClass containingClass = PsiMethodReferenceUtil.getQualifierResolveResult(expression).getContainingClass();
@@ -548,17 +547,19 @@ final class JavaErrorVisitor extends JavaElementVisitor {
}
}
if (!hasErrorResults()) myFunctionChecker.checkRawConstructorReference(expression);
PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(LambdaUtil.normalizeFunctionalType(functionalInterfaceType));
if (functionalInterfaceType != null) {
if (!hasErrorResults()) myFunctionChecker.checkExtendsSealedClass(expression, functionalInterfaceType);
boolean isFunctional = LambdaUtil.isFunctionalType(functionalInterfaceType);
if (!hasErrorResults() && !isFunctional &&
if (!hasErrorResults() && (aClass != null || !(functionalInterfaceType instanceof PsiClassType)) && !LambdaUtil.isFunctionalClass(aClass) &&
!(isIncompleteModel() && IncompleteModelUtil.isUnresolvedClassType(functionalInterfaceType))) {
report(JavaErrorKinds.LAMBDA_NOT_FUNCTIONAL_INTERFACE.create(expression, functionalInterfaceType));
}
if (!hasErrorResults()) myFunctionChecker.checkMethodReferenceContext(expression, functionalInterfaceType);
if (!hasErrorResults()) myFunctionChecker.checkFunctionalInterfaceTypeAccessible(expression, functionalInterfaceType);
}
if (!hasErrorResults()) myFunctionChecker.checkMethodReferenceResolve(expression, results, functionalInterfaceType);
if (!hasErrorResults() && (aClass != null || results.length == 0)) {
myFunctionChecker.checkMethodReferenceResolve(expression, results, functionalInterfaceType);
}
if (!hasErrorResults()) myFunctionChecker.checkMethodReferenceReturnType(expression, result, functionalInterfaceType);
if (!hasErrorResults() && method instanceof PsiModifierListOwner) checkPreviewFeature(expression);
}
@@ -918,7 +919,7 @@ final class JavaErrorVisitor extends JavaElementVisitor {
if (!hasErrorResults()) myTypeChecker.checkVarTypeApplicability(variable);
if (!hasErrorResults()) myTypeChecker.checkVariableInitializerType(variable);
}
@Override
public void visitReferenceExpression(@NotNull PsiReferenceExpression expression) {
visitElement(expression);
@@ -978,8 +979,6 @@ final class JavaErrorVisitor extends JavaElementVisitor {
if (!hasErrorResults()) myExpressionChecker.checkClassReferenceAfterQualifier(expression, resolved);
if (!hasErrorResults() && resolved instanceof PsiModifierListOwner) checkPreviewFeature(expression);
}
@Override
public void visitArrayInitializerExpression(@NotNull PsiArrayInitializerExpression expression) {
@@ -1,5 +1,6 @@
class Demo {
public static void main(String[] args) {
Runnable r = () -> <error descr="void is not a functional interface">() -> () -> {}</error>;
<error descr="Cannot resolve symbol 'Supplier'">Supplier</error><String> unresolved = String::new;
}
}
@@ -22,7 +22,7 @@ class MyTest {
{
Bar1 b1 = MyTest :: foo;
bar(MyTest :: <error descr="Reference to 'foo' is ambiguous, both 'foo(String)' and 'foo(int)' match">foo</error>);
bar<error descr="Ambiguous method call: both 'MyTest.bar(Bar1)' and 'MyTest.bar(Bar2)' match">(MyTest :: foo)</error>;
}
}
@@ -71,7 +71,7 @@ class StaticInner1 {
static void call3(I2 s) {}
static {
call3(StaticInner1.Inner :: <error descr="Cannot resolve constructor 'Inner'">new</error>);
call3<error descr="Ambiguous method call: both 'StaticInner1.call3(I1)' and 'StaticInner1.call3(I2)' match">(StaticInner1.Inner :: new)</error>;
}
}
@@ -2,7 +2,7 @@ import java.util.*;
class LambdaTest {
public void testR() {
new ArrayList<String>() :: <error descr="Reference to 'size' is ambiguous, both 'size()' and 'size()' match">size</error> = "";
<error descr="Variable expected">new ArrayList<String>() :: size</error> = "";
}
}
@@ -116,7 +116,7 @@ class MyTest2 {
static void call3(I2 s) {}
static {
call3(MyTest2::m1);
call3(MyTest2::<error descr="Reference to 'm2' is ambiguous, both 'm2(MyTest2, String)' and 'm2(String)' match">m2</error>);
call3<error descr="Ambiguous method call: both 'MyTest2.call3(I1)' and 'MyTest2.call3(I2)' match">(MyTest2::m2)</error>;
call3(MyTest2::m3);
call3(MyTest2::<error descr="Reference to 'm4' is ambiguous, both 'm4(MyTest2, String)' and 'm4(String)' match">m4</error>);
}
@@ -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(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>;
new OverloadCast<error descr="Cannot resolve constructor 'OverloadCast(<method reference>, <lambda expression>)'">(WhitespaceTokenizer::new, 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::new, src -> new LowerCaseFilter(src))</error>;
}
private OverloadCast(Supplier<Tokenizer> tokenizerFactory, Function<TokenStream, TokenFilter> filterCreator) {
@@ -16,7 +16,7 @@ class DemoApplicationTests {
Stream.of("")
.map(l -> a.get(l.length()))
.map(s -> new DemoApplicationTests()).findAny()
.map(d -> d.foo(this::<error descr="Reference to 'bar' is ambiguous, both 'bar(int)' and 'bar(long)' match">bar</error>));
.map(d -> d.foo<error descr="Ambiguous method call: both 'DemoApplicationTests.foo(Consumer<Object>)' and 'DemoApplicationTests.foo(Function<Object, Object>)' match">(this::bar)</error>);
}
<T> void foo(Consumer<T> c) {}
@@ -31,8 +31,8 @@ class Test {
String i1 = instanceCall(this::m0);
String i2 = instanceCall(this::m1);
String i3 = instanceCall(this::m2);
String i4 = instanceCall(this::<error descr="Reference to 'm01' is ambiguous, both 'm01()' and 'm01(String)' match">m01</error>);
String i5 = instanceCall(this::<error descr="Reference to 'm012' is ambiguous, both 'm012()' and 'm012(String)' match">m012</error>);
String i4 = instanceCall<error descr="Ambiguous method call: both 'Test.instanceCall(I0)' and 'Test.instanceCall(I1<Object>)' match">(this::m01)</error>;
String i5 = instanceCall<error descr="Ambiguous method call: both 'Test.instanceCall(I0)' and 'Test.instanceCall(I1<Object>)' match">(this::m012)</error>;
}
void n0() { }
@@ -53,7 +53,7 @@ class Test {
Test s1 = staticCall(Test::n0);
Test s2 = staticCall(Test::n1);
Test s3 = staticCall<error descr="Cannot resolve method 'staticCall(<method reference>)'">(Test::n2)</error>;
Test s4 = staticCall(Test::<error descr="Reference to 'n01' is ambiguous, both 'n01()' and 'n01(String)' match">n01</error>);
Test s5 = staticCall(Test::<error descr="Reference to 'n012' is ambiguous, both 'n012()' and 'n012(String)' match">n012</error>);
Test s4 = staticCall<error descr="Ambiguous method call: both 'Test.staticCall(I1<Object>)' and 'Test.staticCall(I2<Object, String>)' match">(Test::n01)</error>;
Test s5 = staticCall<error descr="Ambiguous method call: both 'Test.staticCall(I1<Object>)' and 'Test.staticCall(I2<Object, String>)' match">(Test::n012)</error>;
}
}
@@ -34,7 +34,7 @@ class Test {
{
Set<String> m = replyWith(this::query);
System.out.println(m);
Set<String> m1 = replyWith(this::<error descr="Reference to 'query1' is ambiguous, both 'query1()' and 'query1(String)' match">query1</error>);
Set<String> m1 = replyWith<error descr="Ambiguous method call: both 'Test.replyWith(Function<Object, List<Object>>)' and 'Test.replyWith(Callable<List<Object>>)' match">(this::query1)</error>;
System.out.println(m1);
}
}