mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-highlighting] Incompatible lambda parameter types moved
Also: report every incompatible parameter, not only the first one Part of IDEA-365344 Create a new Java error highlighter with minimal dependencies (PSI only) GitOrigin-RevId: a9d75a78207d0910f0bcbb6060e38acedc3f07d3
This commit is contained in:
committed by
intellij-monorepo-bot
parent
fd581aa354
commit
caef43a5e5
@@ -54,6 +54,8 @@ lambda.type.inference.failure=Cannot infer functional interface type
|
||||
lambda.inference.error={0}
|
||||
lambda.return.type.error={0}
|
||||
lambda.target.not.interface=Target type of a lambda conversion must be an interface
|
||||
lambda.incompatible.parameter.types=Incompatible parameter type in lambda expression: expected {0} but found {1}
|
||||
lambda.wrong.number.of.parameters=Wrong number of parameters in lambda expression: expected {0} but found {1}
|
||||
|
||||
method.reference.not.expected=Method reference expression is not expected here
|
||||
method.reference.sealed=Method reference cannot implement a sealed interface
|
||||
|
||||
+26
@@ -16,6 +16,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.Objects.*;
|
||||
|
||||
|
||||
final class FunctionChecker {
|
||||
private final @NotNull JavaErrorVisitor myVisitor;
|
||||
@@ -147,6 +149,30 @@ final class FunctionChecker {
|
||||
}
|
||||
}
|
||||
|
||||
void checkParametersCompatible(@NotNull PsiLambdaExpression expression, @Nullable PsiType functionalInterfaceType) {
|
||||
PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
|
||||
PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult);
|
||||
if (interfaceMethod == null) return;
|
||||
PsiParameter[] parameters = interfaceMethod.getParameterList().getParameters();
|
||||
PsiParameter[] lambdaParameters = expression.getParameterList().getParameters();
|
||||
if (lambdaParameters.length != parameters.length) {
|
||||
myVisitor.report(JavaErrorKinds.LAMBDA_WRONG_NUMBER_OF_PARAMETERS.create(expression, interfaceMethod));
|
||||
return;
|
||||
}
|
||||
boolean hasFormalParameterTypes = expression.hasFormalParameterTypes();
|
||||
PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, resolveResult);
|
||||
for (int i = 0; i < lambdaParameters.length; i++) {
|
||||
PsiParameter lambdaParameter = lambdaParameters[i];
|
||||
PsiType lambdaParameterType = lambdaParameter.getType();
|
||||
PsiType substitutedParamType = substitutor.substitute(parameters[i].getType());
|
||||
if (hasFormalParameterTypes &&!PsiTypesUtil.compareTypes(lambdaParameterType, substitutedParamType, true) ||
|
||||
!TypeConversionUtil.isAssignable(substitutedParamType, lambdaParameterType)) {
|
||||
myVisitor.report(JavaErrorKinds.LAMBDA_INCOMPATIBLE_PARAMETER_TYPES.create(
|
||||
lambdaParameter, requireNonNullElse(substitutedParamType, PsiTypes.nullType())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable JavaCompilationError<?, ?> getFunctionalInterfaceError(
|
||||
@NotNull PsiFunctionalExpression context, PsiType functionalInterfaceType) {
|
||||
if (functionalInterfaceType instanceof PsiIntersectionType intersection) {
|
||||
|
||||
+1
-1
@@ -827,8 +827,8 @@ final class JavaErrorVisitor extends JavaElementVisitor {
|
||||
else if (returnErrors != null && !PsiTreeUtil.hasErrorElements(expression)) {
|
||||
returnErrors.forEach((expr, message) -> report(JavaErrorKinds.LAMBDA_RETURN_TYPE_ERROR.create(expr, message)));
|
||||
}
|
||||
if (!hasErrorResults()) myFunctionChecker.checkParametersCompatible(expression, functionalInterfaceType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+11
@@ -142,6 +142,17 @@ public final class JavaErrorKinds {
|
||||
public static final Parameterized<PsiElement, String> LAMBDA_RETURN_TYPE_ERROR =
|
||||
parameterized(PsiElement.class, String.class, "lambda.return.type.error")
|
||||
.withRawDescription((psi, message) -> message("lambda.return.type.error", message));
|
||||
public static final Parameterized<PsiLambdaExpression, PsiMethod> LAMBDA_WRONG_NUMBER_OF_PARAMETERS =
|
||||
parameterized(PsiLambdaExpression.class, PsiMethod.class, "lambda.wrong.number.of.parameters")
|
||||
.withAnchor((lambda, method) -> lambda.getParameterList())
|
||||
.withRawDescription((lambda, method) -> message("lambda.wrong.number.of.parameters",
|
||||
method.getParameterList().getParametersCount(),
|
||||
lambda.getParameterList().getParametersCount()));
|
||||
public static final Parameterized<PsiParameter, PsiType> LAMBDA_INCOMPATIBLE_PARAMETER_TYPES =
|
||||
parameterized(PsiParameter.class, PsiType.class, "lambda.incompatible.parameter.types")
|
||||
.withRawDescription((parameter, expectedType) -> message("lambda.incompatible.parameter.types",
|
||||
expectedType.getPresentableText(), parameter.getType().getPresentableText()));
|
||||
|
||||
|
||||
public static final Simple<PsiMethodReferenceExpression> METHOD_REFERENCE_SEALED = error("method.reference.sealed");
|
||||
public static final Simple<PsiMethodReferenceExpression> METHOD_REFERENCE_NOT_EXPECTED = error("method.reference.not.expected");
|
||||
|
||||
-10
@@ -269,16 +269,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasErrorResults() && functionalInterfaceType != null) {
|
||||
PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
|
||||
PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult);
|
||||
if (interfaceMethod != null) {
|
||||
PsiParameter[] parameters = interfaceMethod.getParameterList().getParameters();
|
||||
add(LambdaHighlightingUtil.checkParametersCompatible(expression, parameters,
|
||||
LambdaUtil.getSubstitutor(interfaceMethod, resolveResult)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasErrorResults()) {
|
||||
PsiElement body = expression.getBody();
|
||||
if (body instanceof PsiCodeBlock block) {
|
||||
|
||||
-31
@@ -2,7 +2,6 @@
|
||||
package com.intellij.codeInsight.daemon.impl.analysis;
|
||||
|
||||
import com.intellij.codeInsight.JavaModuleSystemEx.ErrorWithFixes;
|
||||
import com.intellij.codeInsight.daemon.JavaErrorBundle;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
@@ -10,43 +9,13 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.PsiClassImplUtil;
|
||||
import com.intellij.psi.util.PsiTypesUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public final class LambdaHighlightingUtil {
|
||||
|
||||
static HighlightInfo.Builder checkParametersCompatible(@NotNull PsiLambdaExpression expression,
|
||||
PsiParameter @NotNull [] methodParameters,
|
||||
@NotNull PsiSubstitutor substitutor) {
|
||||
PsiParameter[] lambdaParameters = expression.getParameterList().getParameters();
|
||||
if (lambdaParameters.length != methodParameters.length) {
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
|
||||
.range(expression.getParameterList())
|
||||
.descriptionAndTooltip(JavaErrorBundle.message("incompatible.parameter.types.in.lambda.wrong.number.of.parameters", methodParameters.length, lambdaParameters.length));
|
||||
}
|
||||
boolean hasFormalParameterTypes = expression.hasFormalParameterTypes();
|
||||
for (int i = 0; i < lambdaParameters.length; i++) {
|
||||
PsiParameter lambdaParameter = lambdaParameters[i];
|
||||
PsiType lambdaParameterType = lambdaParameter.getType();
|
||||
PsiType substitutedParamType = substitutor.substitute(methodParameters[i].getType());
|
||||
if (hasFormalParameterTypes &&!PsiTypesUtil.compareTypes(lambdaParameterType, substitutedParamType, true) ||
|
||||
!TypeConversionUtil.isAssignable(substitutedParamType, lambdaParameterType)) {
|
||||
String expectedType = substitutedParamType != null ? substitutedParamType.getPresentableText() : null;
|
||||
String actualType = lambdaParameterType.getPresentableText();
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
|
||||
.range(expression.getParameterList())
|
||||
.descriptionAndTooltip(
|
||||
JavaErrorBundle.message("incompatible.parameter.types.in.lambda", expectedType, actualType));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 15.13 | 15.27
|
||||
// It is a compile-time error if any class or interface mentioned by either U or the function type of U
|
||||
// is not accessible from the class or interface in which the method reference expression appears.
|
||||
|
||||
@@ -18,7 +18,6 @@ generics.unchecked.cast=Unchecked cast: ''{0}'' to ''{1}''
|
||||
generics.unchecked.call.to.member.of.raw.type=Unchecked call to ''{0}'' as a member of raw type ''{1}''
|
||||
generics.unchecked.call=Unchecked method ''{0}'' invocation
|
||||
unsafe.cast.in.instanceof=''{0}'' cannot be safely cast to ''{1}''
|
||||
modifiers.for.enum.constants=No modifiers allowed for enum constants
|
||||
unchecked.overriding.incompatible.return.type=Unchecked overriding: return type requires unchecked conversion. Found ''{0}'', required ''{1}''
|
||||
|
||||
class.must.be.abstract=Class ''{0}'' must either be declared abstract or implement abstract method ''{1}'' in ''{2}''
|
||||
@@ -44,10 +43,8 @@ declaration.or.variable.expected=Declaration, final or effectively final variabl
|
||||
initializer.must.be.able.to.complete.normally=Initializer must be able to complete normally
|
||||
incompatible.return.type=attempting to use incompatible return type
|
||||
exception.is.never.thrown=Exception ''{0}'' is never thrown in the method
|
||||
ambiguous.reference=Reference to ''{0}'' is ambiguous, both ''{1}'' and ''{2}'' match
|
||||
cannot.resolve.method=Cannot resolve method ''{0}''
|
||||
ambiguous.method.call.no.match=Cannot resolve method ''{0}'' in ''{1}''
|
||||
abstract.method.in.non.abstract.class=Abstract method in non-abstract class
|
||||
overrides.deprecated.method=Overrides deprecated method in ''{0}''
|
||||
overrides.marked.for.removal.method=Overrides method that is deprecated and marked for removal in ''{0}''
|
||||
deprecated.default.constructor=Default constructor in ''{0}'' is deprecated
|
||||
@@ -271,25 +268,6 @@ record.component.not.initialized=Record component ''{0}'' might not be initializ
|
||||
insufficient.language.level={0} are not supported at language level ''{1}''
|
||||
|
||||
cannot.select.from.a.type.parameter=Cannot select from a type parameter
|
||||
method.reference.expression.is.not.expected=Method reference expression is not expected here
|
||||
not.a.functional.interface={0} is not a functional interface
|
||||
cannot.find.class=Cannot find class {0}
|
||||
cannot.infer.functional.interface.type=Cannot infer functional interface type
|
||||
lambda.expression.not.expected=Lambda expression not expected here
|
||||
lambda.parameters.consistency.message=Cannot mix 'var' and explicitly typed parameters in lambda expression
|
||||
target.method.is.generic=Target method is generic
|
||||
multiple.non.overriding.abstract.methods.found.in.0=Multiple non-overriding abstract methods found in {0}
|
||||
multiple.non.overriding.abstract.methods.found.in.interface.0=Multiple non-overriding abstract methods found in interface {0}
|
||||
no.target.method.found=No target method found
|
||||
target.type.of.a.lambda.conversion.must.be.an.interface=Target type of a lambda conversion must be an interface
|
||||
incompatible.parameter.types.in.lambda=Incompatible parameter types in lambda expression: expected {0} but found {1}
|
||||
incompatible.parameter.types.in.lambda.wrong.number.of.parameters=Incompatible parameter types in lambda expression: wrong number of parameters: expected {0} but found {1}
|
||||
an.enclosing.instance.of.type.not.in.scope.method.reference.context=An enclosing instance of type {0} is not in scope
|
||||
parameterized.qualifier.on.static.method.reference.context=Parameterized qualifier on static method reference
|
||||
static.method.referenced.through.receiver.method.reference.context=Static method referenced through receiver
|
||||
static.method.referenced.through.non.static.qualifier.method.reference.context=Static method referenced through non-static qualifier
|
||||
non.static.method.cannot.be.referenced.from.a.static.context.method.reference.context=Non-static method cannot be referenced from a static context
|
||||
abstract.method.0.cannot.be.accessed.directly.method.reference.context=Abstract method ''{0}'' cannot be accessed directly
|
||||
bad.type.in.switch.expression=Bad type in switch expression: {0} cannot be converted to {1}
|
||||
switch.expression.cannot.be.void=Target type for switch expression cannot be void
|
||||
annotation.on.static.member.qualifying.type.family.name=Move type annotation
|
||||
@@ -297,7 +275,6 @@ not.allowed.in.sealed.hierarchy=''{0}'' is not allowed in the sealed hierarchy
|
||||
invalid.permits.clause.direct.implementation=Invalid permits clause: ''{0}'' must directly {1, choice, 1#extend|2#implement} ''{2}''
|
||||
permitted.subclass.must.have.modifier=All sealed class subclasses must either be final, sealed or non-sealed
|
||||
permits.list.generics.are.not.allowed=Generics are not allowed in permits list
|
||||
sealed.cannot.be.functional.interface=Sealed class can not be used as functional interface
|
||||
local.classes.must.not.extend.sealed.classes=Local classes must not extend sealed classes
|
||||
class.not.allowed.to.extend.sealed.class.from.another.package={0} ''{1}'' from another package not allowed to extend sealed {2} ''{3}'' in unnamed module
|
||||
class.not.allowed.to.extend.sealed.class.from.another.module=Class is not allowed to extend sealed class from another module
|
||||
@@ -307,7 +284,5 @@ text.class.inherits.unrelated.defaults={0} inherits unrelated defaults for {1} f
|
||||
text.class.is.not.accessible={0} is not accessible in current context
|
||||
text.class.cannot.access=Cannot access {0}
|
||||
error.cannot.infer.pattern.type=Cannot infer pattern type: {0}
|
||||
error.extra.semicolons.between.import.statements.not.allowed=Extra semicolons between import statements are not allowed
|
||||
remove.unused.imports.quickfix.text=Remove unused imports
|
||||
incomplete.project.state.pending.reference=Not resolved until the project is fully loaded
|
||||
implicit.class.with.explicit.constructor=Explicit constructor in implicitly declared class is not allowed
|
||||
+1
-1
@@ -12,7 +12,7 @@ class Test {
|
||||
I i = flag ? (() -> 123) : (() -> 222);
|
||||
I i1 = flag ? (() -> {<error descr="Missing return statement">}</error>) : (() -> 222);
|
||||
Object i2 = flag ? (<error descr="Target type of a lambda conversion must be an interface">() -> 42</error>) : (<error descr="Target type of a lambda conversion must be an interface">() -> 222</error>);
|
||||
I i3 = flag ? (<error descr="Incompatible parameter types in lambda expression: wrong number of parameters: expected 0 but found 1">(x)</error> -> 42) : (() -> 222);
|
||||
I i3 = flag ? (<error descr="Wrong number of parameters in lambda expression: expected 0 but found 1">(x)</error> -> 42) : (() -> 222);
|
||||
I i4 = flag ? (() -> 42) : new I() {
|
||||
@Override
|
||||
public int m() {
|
||||
|
||||
+1
-1
@@ -3,6 +3,6 @@ class LambdaConv10 {
|
||||
interface I<T, R> { public R call( T t); }
|
||||
|
||||
{
|
||||
I<Integer,Integer> in = <error descr="Incompatible parameter types in lambda expression: expected Integer but found int">(int i)</error> -> 2 * i;
|
||||
I<Integer,Integer> in = (<error descr="Incompatible parameter type in lambda expression: expected Integer but found int">int i</error>) -> 2 * i;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ public class Test {
|
||||
|
||||
{
|
||||
Predicate<? super Integer> p = (Number n) -> n.equals(23);
|
||||
Predicate<Integer> p1 = <error descr="Incompatible parameter types in lambda expression: expected Integer but found Number">(Number n)</error> -> n.equals(23);
|
||||
Predicate<Integer> p1 = (<error descr="Incompatible parameter type in lambda expression: expected Integer but found Number">Number n</error>) -> n.equals(23);
|
||||
Predicate<Number> p2 = (Number n) -> n.equals(23);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -11,7 +11,7 @@ class Foo {
|
||||
};
|
||||
|
||||
void bazz() {
|
||||
bar(<error descr="Incompatible parameter types in lambda expression: expected int but found String">(String s)</error> -> {
|
||||
bar((<error descr="Incompatible parameter type in lambda expression: expected int but found String">String s</error>) -> {
|
||||
System.out.println(s);});
|
||||
bar((int i) -> {System.out.println(i);});
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
class XXX {
|
||||
Runnable bar() {
|
||||
return <error descr="Incompatible parameter types in lambda expression: wrong number of parameters: expected 0 but found 1">(o)</error>->{
|
||||
return <error descr="Wrong number of parameters in lambda expression: expected 0 but found 1">(o)</error>->{
|
||||
System.out.println();
|
||||
};
|
||||
}
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@ class Foo {
|
||||
System.out.println(s);
|
||||
});
|
||||
|
||||
foo(<error descr="Incompatible parameter types in lambda expression: expected int but found String">(String p, String k)</error> -> {
|
||||
foo((<error descr="Incompatible parameter type in lambda expression: expected int but found String">String p</error>, <error descr="Incompatible parameter type in lambda expression: expected int but found String">String k</error>) -> {
|
||||
System.out.println(p);
|
||||
});
|
||||
}
|
||||
@@ -62,7 +62,7 @@ class WithTypeParams {
|
||||
System.out.println(p);
|
||||
});
|
||||
|
||||
foo(<error descr="Incompatible parameter types in lambda expression: expected String but found int">(int k)</error> -> {System.out.println(k);});
|
||||
foo((<error descr="Incompatible parameter type in lambda expression: expected String but found int">int k</error>) -> {System.out.println(k);});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
class Test {
|
||||
{
|
||||
Comparable c = <error descr="Incompatible parameter types in lambda expression: expected Object but found String">(String o)</error>->{
|
||||
Comparable c = (<error descr="Incompatible parameter type in lambda expression: expected Object but found String">String o</error>)->{
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user