[java-highlighting] Lambda-related type errors migrated

Part of IDEA-365344 Create a new Java error highlighter with minimal dependencies (PSI only)

GitOrigin-RevId: 1fb0b4c35b4db63d8c15cb392098380d1014ebf2
This commit is contained in:
Tagir Valeev
2025-02-04 09:52:02 +00:00
committed by intellij-monorepo-bot
parent fadc5cf32c
commit 5b5abb8e13
21 changed files with 373 additions and 247 deletions
@@ -44,8 +44,18 @@ annotation.container.abstract=Container annotation ''{0}'' does not have a defau
lambda.not.a.functional.interface={0} is not a functional interface
lambda.no.target.method.found=No target method found
lambda.multiple.sam.candidates=Multiple non-overriding abstract methods found in interface {0}
lambda.multiple.sam.candidates=Multiple non-overriding abstract methods found in {0}
lambda.sam.generic=Target method is generic
lambda.sealed.functional.interface=Functional interface can't be declared as 'sealed'
lambda.not.expected=Lambda expression not expected here
lambda.parameters.inconsistent.var=Cannot mix 'var' and explicitly typed parameters in lambda expression
lambda.sealed=Lambda cannot implement a sealed interface
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
method.reference.sealed=Method reference cannot implement a sealed interface
safe.varargs.on.record.component=@SafeVarargs is not allowed on a record component
safe.varargs.on.fixed.arity=@SafeVarargs is not allowed on methods with fixed arity
@@ -371,13 +371,14 @@ final class AnnotationChecker {
if (owner instanceof PsiModifierList list) {
PsiElement parent = list.getParent();
if (parent instanceof PsiClass psiClass) {
PsiClassType type = myVisitor.factory().createType(psiClass);
switch (LambdaUtil.checkInterfaceFunctional(psiClass)) {
case NOT_INTERFACE -> myVisitor.report(JavaErrorKinds.LAMBDA_NOT_FUNCTIONAL_INTERFACE.create(annotation, psiClass));
case NO_ABSTRACT_METHOD -> myVisitor.report(JavaErrorKinds.LAMBDA_NO_TARGET_METHOD.create(annotation, psiClass));
case MULTIPLE_ABSTRACT_METHODS -> myVisitor.report(JavaErrorKinds.LAMBDA_MULTIPLE_TARGET_METHODS.create(annotation, psiClass));
case NOT_INTERFACE -> myVisitor.report(JavaErrorKinds.LAMBDA_NOT_FUNCTIONAL_INTERFACE.create(annotation, type));
case NO_ABSTRACT_METHOD -> myVisitor.report(JavaErrorKinds.LAMBDA_NO_TARGET_METHOD.create(annotation, type));
case MULTIPLE_ABSTRACT_METHODS -> myVisitor.report(JavaErrorKinds.LAMBDA_MULTIPLE_TARGET_METHODS.create(annotation, type));
}
if (psiClass.hasModifierProperty(PsiModifier.SEALED)) {
myVisitor.report(JavaErrorKinds.LAMBDA_FUNCTIONAL_INTERFACE_SEALED.create(annotation, psiClass));
myVisitor.report(JavaErrorKinds.FUNCTIONAL_INTERFACE_SEALED.create(annotation, psiClass));
}
}
}
@@ -0,0 +1,194 @@
// Copyright 2000-2025 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.core.JavaPsiBundle;
import com.intellij.java.codeserver.highlighting.errors.JavaCompilationError;
import com.intellij.java.codeserver.highlighting.errors.JavaErrorKinds;
import com.intellij.java.codeserver.highlighting.errors.JavaIncompatibleTypeErrorContext;
import com.intellij.lang.jvm.JvmModifier;
import com.intellij.psi.*;
import com.intellij.psi.impl.IncompleteModelUtil;
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.util.MethodSignature;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static com.intellij.psi.LambdaUtil.getFunction;
import static com.intellij.psi.LambdaUtil.getTargetMethod;
final class FunctionChecker {
private final @NotNull JavaErrorVisitor myVisitor;
FunctionChecker(@NotNull JavaErrorVisitor visitor) { myVisitor = visitor; }
void checkExtendsSealedClass(@NotNull PsiFunctionalExpression expression, @NotNull PsiType functionalInterfaceType) {
PsiClass functionalInterface = PsiUtil.resolveClassInClassTypeOnly(functionalInterfaceType);
if (functionalInterface == null || !functionalInterface.hasModifierProperty(PsiModifier.SEALED)) return;
if (expression instanceof PsiLambdaExpression lambda) {
myVisitor.report(JavaErrorKinds.LAMBDA_SEALED.create(lambda));
}
else if (expression instanceof PsiMethodReferenceExpression methodReference) {
myVisitor.report(JavaErrorKinds.METHOD_REFERENCE_SEALED.create(methodReference));
}
}
void checkInterfaceFunctional(@NotNull PsiFunctionalExpression context, PsiType functionalInterfaceType) {
JavaCompilationError<?, ?> error = getFunctionalInterfaceError(context, functionalInterfaceType);
if (error != null) {
myVisitor.report(error);
}
}
private static @Nullable JavaCompilationError<?, ?> getFunctionalInterfaceError(
@NotNull PsiFunctionalExpression context, PsiType functionalInterfaceType) {
if (functionalInterfaceType instanceof PsiIntersectionType intersection) {
Set<MethodSignature> signatures = new HashSet<>();
Map<PsiType, MethodSignature> typeAndSignature = new HashMap<>();
for (PsiType type : intersection.getConjuncts()) {
if (getFunctionalInterfaceError(context, type) == null) {
MethodSignature signature = getFunction(PsiUtil.resolveClassInType(type));
signatures.add(signature);
typeAndSignature.put(type, signature);
}
}
PsiType baseType = typeAndSignature.entrySet().iterator().next().getKey();
MethodSignature baseSignature = typeAndSignature.get(baseType);
LambdaUtil.TargetMethodContainer baseContainer = getTargetMethod(baseType, baseSignature, baseType);
if (baseContainer == null) {
return JavaErrorKinds.LAMBDA_NO_TARGET_METHOD.create(context, baseType);
}
PsiMethod baseMethod = baseContainer.targetMethod;
if (signatures.size() > 1) {
for (Map.Entry<PsiType, MethodSignature> entry : typeAndSignature.entrySet()) {
if (baseType == entry.getKey()) {
continue;
}
LambdaUtil.TargetMethodContainer container = getTargetMethod(entry.getKey(), baseSignature, baseType);
if (container == null) {
return JavaErrorKinds.LAMBDA_MULTIPLE_TARGET_METHODS.create(context, functionalInterfaceType);
}
if (!LambdaUtil.isLambdaSubsignature(baseMethod, baseType, container.targetMethod, entry.getKey()) ||
!container.inheritor.hasModifier(JvmModifier.ABSTRACT)) {
return JavaErrorKinds.LAMBDA_MULTIPLE_TARGET_METHODS.create(context, functionalInterfaceType);
}
}
}
for (PsiType type : intersection.getConjuncts()) {
if (typeAndSignature.containsKey(type)) {
continue;
}
LambdaUtil.TargetMethodContainer container = getTargetMethod(type, baseSignature, baseType);
if (container == null) {
continue;
}
PsiMethod inheritor = container.inheritor;
PsiMethod target = container.targetMethod;
if (!inheritor.hasModifier(JvmModifier.ABSTRACT) && LambdaUtil.isLambdaSubsignature(baseMethod, baseType, target, type)) {
return JavaErrorKinds.LAMBDA_NO_TARGET_METHOD.create(context, type);
}
}
return null;
}
PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
PsiClass aClass = resolveResult.getElement();
if (aClass != null) {
if (aClass instanceof PsiTypeParameter) return null; //should be logged as cyclic inference
MethodSignature functionalMethod = getFunction(aClass);
if (functionalMethod != null && functionalMethod.getTypeParameters().length > 0) {
return JavaErrorKinds.LAMBDA_SAM_GENERIC.create(context);
}
return switch (LambdaUtil.checkInterfaceFunctional(aClass)) {
case VALID -> null;
case NOT_INTERFACE -> JavaErrorKinds.LAMBDA_TARGET_NOT_INTERFACE.create(context, functionalInterfaceType);
case NO_ABSTRACT_METHOD -> JavaErrorKinds.LAMBDA_NO_TARGET_METHOD.create(context, functionalInterfaceType);
case MULTIPLE_ABSTRACT_METHODS -> JavaErrorKinds.LAMBDA_MULTIPLE_TARGET_METHODS.create(context, functionalInterfaceType);
};
}
if (IncompleteModelUtil.isIncompleteModel(context) &&
IncompleteModelUtil.isUnresolvedClassType(functionalInterfaceType)) {
return null;
}
return JavaErrorKinds.LAMBDA_NOT_FUNCTIONAL_INTERFACE.create(context, functionalInterfaceType);
}
private static boolean hasExplicitType(@NotNull PsiParameter parameter) {
PsiTypeElement typeElement = parameter.getTypeElement();
return typeElement != null && !typeElement.isInferredType();
}
void checkConsistentParameterDeclaration(@NotNull PsiLambdaExpression expression) {
PsiParameterList parameterList = expression.getParameterList();
PsiParameter[] parameters = parameterList.getParameters();
if (parameters.length < 2) return;
boolean hasExplicitParameterTypes = hasExplicitType(parameters[0]);
for (int i = 1; i < parameters.length; i++) {
if (hasExplicitParameterTypes != hasExplicitType(parameters[i])) {
myVisitor.report(JavaErrorKinds.LAMBDA_PARAMETERS_INCONSISTENT_VAR.create(parameterList));
}
}
}
private static boolean favorParentReport(@NotNull PsiCall methodCall, @NotNull String errorMessage) {
// Parent resolve failed as well, and it's likely more informative.
// Suppress this error to allow reporting from parent
return (errorMessage.equals(JavaPsiBundle.message("error.incompatible.type.failed.to.resolve.argument")) ||
errorMessage.equals(JavaPsiBundle.message("error.incompatible.type.declaration.for.the.method.reference.not.found"))) &&
hasSurroundingInferenceError(methodCall);
}
static boolean hasSurroundingInferenceError(@NotNull PsiElement context) {
PsiCall topCall = LambdaUtil.treeWalkUp(context);
if (topCall == null) return false;
while (context != topCall) {
context = context.getParent();
if (context instanceof PsiMethodCallExpression call &&
call.resolveMethodGenerics() instanceof MethodCandidateInfo info &&
info.getInferenceErrorMessage() != null) {
// Possibly inapplicable method reference due to the surrounding call inference failure:
// suppress method reference error in order to display more relevant inference error.
return true;
}
}
return false;
}
void checkLambdaInferenceFailure(@NotNull PsiCall methodCall,
@NotNull MethodCandidateInfo resolveResult,
@NotNull PsiLambdaExpression lambdaExpression) {
String errorMessage = resolveResult.getInferenceErrorMessage();
if (errorMessage == null) return;
if (favorParentReport(methodCall, errorMessage)) return;
PsiMethod method = resolveResult.getElement();
PsiType expectedTypeByParent = InferenceSession.getTargetTypeByParent(methodCall);
PsiType actualType =
methodCall instanceof PsiExpression ? ((PsiExpression)methodCall.copy()).getType() :
resolveResult.getSubstitutor(false).substitute(method.getReturnType());
if (expectedTypeByParent != null && actualType != null && !expectedTypeByParent.isAssignableFrom(actualType)) {
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(
methodCall, new JavaIncompatibleTypeErrorContext(expectedTypeByParent, actualType, errorMessage)));
}
else {
myVisitor.report(JavaErrorKinds.LAMBDA_INFERENCE_ERROR.create(lambdaExpression, resolveResult));
}
}
static boolean lambdaParametersMentionTypeParameter(@NotNull PsiType functionalInterfaceType,
@NotNull Set<? extends PsiTypeParameter> parameters) {
if (!(functionalInterfaceType instanceof PsiClassType classType)) return false;
PsiSubstitutor substitutor = classType.resolveGenerics().getSubstitutor();
PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType);
if (method == null) return false;
for (PsiParameter parameter : method.getParameterList().getParameters()) {
if (PsiTypesUtil.mentionsTypeParameters(substitutor.substitute(parameter.getType()), parameters)) return true;
}
return false;
}
}
@@ -23,10 +23,13 @@ import com.intellij.psi.util.*;
import com.intellij.refactoring.util.RefactoringChangeUtil;
import com.intellij.util.ObjectUtils;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import static java.util.Objects.*;
@@ -49,6 +52,7 @@ final class JavaErrorVisitor extends JavaElementVisitor {
final @NotNull TypeChecker myTypeChecker = new TypeChecker(this);
final @NotNull MethodChecker myMethodChecker = new MethodChecker(this);
private final @NotNull ReceiverChecker myReceiverChecker = new ReceiverChecker(this);
private final @NotNull FunctionChecker myFunctionChecker = new FunctionChecker(this);
final @NotNull PatternChecker myPatternChecker = new PatternChecker(this);
final @NotNull ModifierChecker myModifierChecker = new ModifierChecker(this);
final @NotNull ExpressionChecker myExpressionChecker = new ExpressionChecker(this);
@@ -367,6 +371,9 @@ final class JavaErrorVisitor extends JavaElementVisitor {
myExpressionChecker.checkStaticInterfaceCallQualifier(expression, result, containingClass);
}
}
if (functionalInterfaceType != null) {
if (!hasErrorResults()) myFunctionChecker.checkExtendsSealedClass(expression, functionalInterfaceType);
}
}
@Override
@@ -727,6 +734,64 @@ final class JavaErrorVisitor extends JavaElementVisitor {
}
}
@Override
public void visitLambdaExpression(@NotNull PsiLambdaExpression expression) {
checkFeature(expression, JavaFeature.LAMBDA_EXPRESSIONS);
PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression.getParent());
if (toReportFunctionalExpressionProblemOnParent(parent)) return;
if (!hasErrorResults() && !LambdaUtil.isValidLambdaContext(parent)) {
report(JavaErrorKinds.LAMBDA_NOT_EXPECTED.create(expression));
}
if (!hasErrorResults()) myFunctionChecker.checkConsistentParameterDeclaration(expression);
PsiType functionalInterfaceType = null;
if (!hasErrorResults()) {
functionalInterfaceType = expression.getFunctionalInterfaceType();
if (functionalInterfaceType != null) {
myFunctionChecker.checkExtendsSealedClass(expression, functionalInterfaceType);
if (!hasErrorResults()) myFunctionChecker.checkInterfaceFunctional(expression, functionalInterfaceType);
}
else if (LambdaUtil.getFunctionalInterfaceType(expression, true) != null) {
report(JavaErrorKinds.LAMBDA_TYPE_INFERENCE_FAILURE.create(expression));
}
}
if (!hasErrorResults() && functionalInterfaceType != null) {
PsiCallExpression callExpression = parent instanceof PsiExpressionList && parent.getParent() instanceof PsiCallExpression ?
(PsiCallExpression)parent.getParent() : null;
MethodCandidateInfo parentCallResolveResult =
callExpression != null ? ObjectUtils.tryCast(callExpression.resolveMethodGenerics(), MethodCandidateInfo.class) : null;
String parentInferenceErrorMessage = parentCallResolveResult != null ? parentCallResolveResult.getInferenceErrorMessage() : null;
PsiType returnType = LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType);
Map<PsiElement, @Nls String> returnErrors = null;
Set<PsiTypeParameter> parentTypeParameters =
parentCallResolveResult == null ? Set.of() : Set.of(parentCallResolveResult.getElement().getTypeParameters());
// If return type of the lambda was not fully inferred and lambda parameters don't mention the same type,
// it means that lambda is not responsible for inference failure and blaming it would be unreasonable.
boolean skipReturnCompatibility = parentCallResolveResult != null &&
PsiTypesUtil.mentionsTypeParameters(returnType, parentTypeParameters)
&& !FunctionChecker.lambdaParametersMentionTypeParameter(functionalInterfaceType, parentTypeParameters);
if (!skipReturnCompatibility) {
returnErrors = LambdaUtil.checkReturnTypeCompatible(expression, returnType);
}
if (parentInferenceErrorMessage != null && (returnErrors == null || !returnErrors.containsValue(parentInferenceErrorMessage))) {
if (returnErrors == null) return;
myFunctionChecker.checkLambdaInferenceFailure(callExpression, parentCallResolveResult, expression);
}
else if (returnErrors != null && !PsiTreeUtil.hasErrorElements(expression)) {
returnErrors.forEach((expr, message) -> report(JavaErrorKinds.LAMBDA_RETURN_TYPE_ERROR.create(expr, message)));
}
}
}
/**
* @return true for {@code functional_expression;} or {@code var l = functional_expression;}
*/
private static boolean toReportFunctionalExpressionProblemOnParent(@Nullable PsiElement parent) {
if (parent instanceof PsiLocalVariable variable) {
return variable.getTypeElement().isInferredType();
}
return parent instanceof PsiExpressionStatement && !(parent.getParent() instanceof PsiSwitchLabeledRuleStatement);
}
@Override
public void visitTypeCastExpression(@NotNull PsiTypeCastExpression expression) {
@@ -12,6 +12,7 @@ import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.pom.java.JavaFeature;
import com.intellij.psi.*;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.*;
import com.intellij.refactoring.util.RefactoringChangeUtil;
@@ -114,19 +115,36 @@ public final class JavaErrorKinds {
public static final Simple<PsiReferenceList> ANNOTATION_PERMITS = error(PsiReferenceList.class, "annotation.permits")
.withAnchor(PsiReferenceList::getFirstChild);
// Can be anchored on @FunctionalInterface annotation or at call site
public static final Parameterized<PsiElement, PsiClass> LAMBDA_NOT_FUNCTIONAL_INTERFACE =
parameterized(PsiElement.class, PsiClass.class, "lambda.not.a.functional.interface")
.withRawDescription((element, aClass) -> message("lambda.not.a.functional.interface", aClass.getName()));
// Can be anchored on @FunctionalInterface annotation or at call site
public static final Parameterized<PsiElement, PsiClass> LAMBDA_NO_TARGET_METHOD =
// Can be anchored on @FunctionalInterface annotation or at a call site
public static final Parameterized<PsiElement, PsiType> LAMBDA_NOT_FUNCTIONAL_INTERFACE =
parameterized(PsiElement.class, PsiType.class, "lambda.not.a.functional.interface")
.withRawDescription((element, type) -> message("lambda.not.a.functional.interface", formatType(type)));
// Can be anchored on @FunctionalInterface annotation or at a call site
public static final Parameterized<PsiElement, PsiType> LAMBDA_NO_TARGET_METHOD =
parameterized("lambda.no.target.method.found");
// Can be anchored on @FunctionalInterface annotation or at call site
public static final Parameterized<PsiElement, PsiClass> LAMBDA_MULTIPLE_TARGET_METHODS =
parameterized(PsiElement.class, PsiClass.class, "lambda.multiple.sam.candidates")
.withRawDescription((psi, aClass) -> message("lambda.multiple.sam.candidates", aClass.getName()));
public static final Parameterized<PsiAnnotation, PsiClass> LAMBDA_FUNCTIONAL_INTERFACE_SEALED =
// Can be anchored on @FunctionalInterface annotation or at a call site
public static final Parameterized<PsiElement, PsiType> LAMBDA_MULTIPLE_TARGET_METHODS =
parameterized(PsiElement.class, PsiType.class, "lambda.multiple.sam.candidates")
.withRawDescription((psi, type) -> message("lambda.multiple.sam.candidates",
TypeConversionUtil.erasure(type).getPresentableText()));
public static final Parameterized<PsiAnnotation, PsiClass> FUNCTIONAL_INTERFACE_SEALED =
parameterized("lambda.sealed.functional.interface");
public static final Simple<PsiLambdaExpression> LAMBDA_NOT_EXPECTED = error("lambda.not.expected");
public static final Simple<PsiParameterList> LAMBDA_PARAMETERS_INCONSISTENT_VAR = error("lambda.parameters.inconsistent.var");
public static final Simple<PsiLambdaExpression> LAMBDA_SEALED = error("lambda.sealed");
public static final Simple<PsiFunctionalExpression> LAMBDA_TYPE_INFERENCE_FAILURE = error("lambda.type.inference.failure");
public static final Simple<PsiFunctionalExpression> LAMBDA_SAM_GENERIC = error("lambda.sam.generic");
public static final Parameterized<PsiFunctionalExpression, PsiType> LAMBDA_TARGET_NOT_INTERFACE =
parameterized("lambda.target.not.interface");
public static final Parameterized<PsiLambdaExpression, MethodCandidateInfo> LAMBDA_INFERENCE_ERROR =
parameterized(PsiLambdaExpression.class, MethodCandidateInfo.class, "lambda.inference.error")
.withRawDescription((psi, candidate) -> message("lambda.inference.error", candidate.getInferenceErrorMessage()));
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 Simple<PsiMethodReferenceExpression> METHOD_REFERENCE_SEALED = error("method.reference.sealed");
public static final Parameterized<PsiAnnotation, @NotNull List<PsiAnnotation.@NotNull TargetType>> ANNOTATION_NOT_APPLICABLE =
error(PsiAnnotation.class, "annotation.not.applicable").<@NotNull List<PsiAnnotation.@NotNull TargetType>>parameterized()
.withValidator((annotation, types) -> {
@@ -9,7 +9,6 @@ import com.intellij.openapi.util.text.HtmlChunk;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.xml.util.XmlStringUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -49,15 +48,11 @@ public record JavaIncompatibleTypeErrorContext(@NotNull PsiType lType, @Nullable
}
@NotNull HtmlChunk createTooltip() {
return createTooltip(
reasonForIncompatibleTypes == null ? getReasonForIncompatibleTypes() : XmlStringUtil.escapeString(reasonForIncompatibleTypes));
}
private @NotNull HtmlChunk createTooltip(@NotNull @Nls String reason) {
String reason = reasonForIncompatibleTypes == null ? getReasonForIncompatibleTypes() : reasonForIncompatibleTypes;
HtmlChunk styledReason = reason.isEmpty() ? empty() :
tag("table").child(
tag("tr").child(
tag("td").style("padding-top: 10px; padding-left: 4px;").addRaw(reason)));
tag("td").style("padding-top: 10px; padding-left: 4px;").addText(reason)));
IncompatibleTypesTooltipComposer tooltipComposer = (lTypeString, lTypeArguments, rTypeString, rTypeArguments) ->
createRequiredProvidedTypeMessage(lTypeString, lTypeArguments, rTypeString, rTypeArguments, styledReason);
return createIncompatibleTypesTooltip(tooltipComposer);
@@ -101,16 +101,7 @@ public final class HighlightClassUtil {
return null;
}
static HighlightInfo.Builder checkExtendsSealedClass(@NotNull PsiFunctionalExpression expression, @NotNull PsiType functionalInterfaceType) {
PsiClass functionalInterface = PsiUtil.resolveClassInClassTypeOnly(functionalInterfaceType);
if (functionalInterface == null || !functionalInterface.hasModifierProperty(PsiModifier.SEALED)) return null;
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
.range(expression)
.descriptionAndTooltip(JavaErrorBundle.message("sealed.cannot.be.functional.interface"))
;
}
public static HighlightInfo.Builder checkExtendsSealedClass(@NotNull PsiClass aClass,
public static HighlightInfo.Builder checkExtendsSealedClass(@NotNull PsiClass aClass,
@NotNull PsiClass superClass,
@NotNull PsiJavaCodeReferenceElement elementToHighlight) {
if (superClass.hasModifierProperty(PsiModifier.SEALED)) {
@@ -8,17 +8,14 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.QuickFixFactory;
import com.intellij.codeInspection.LocalQuickFixOnPsiElementAsIntentionAdapter;
import com.intellij.core.JavaPsiBundle;
import com.intellij.openapi.util.NlsContexts;
import com.intellij.openapi.util.TextRange;
import com.intellij.pom.java.JavaFeature;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightRecordMethod;
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.util.*;
import com.intellij.xml.util.XmlStringUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -26,9 +23,6 @@ import org.jetbrains.annotations.Nullable;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import static com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil.asConsumer;
public final class HighlightMethodUtil {
@@ -165,57 +159,6 @@ public final class HighlightMethodUtil {
return errorResult;
}
static HighlightInfo.Builder createIncompatibleTypeHighlightInfo(@NotNull PsiCall methodCall,
@NotNull MethodCandidateInfo resolveResult,
@NotNull PsiElement elementToHighlight) {
String errorMessage = resolveResult.getInferenceErrorMessage();
if (errorMessage == null) return null;
if (favorParentReport(methodCall, errorMessage)) return null;
PsiMethod method = resolveResult.getElement();
HighlightInfo.Builder builder;
PsiType expectedTypeByParent = InferenceSession.getTargetTypeByParent(methodCall);
PsiType actualType =
methodCall instanceof PsiExpression ? ((PsiExpression)methodCall.copy()).getType() :
resolveResult.getSubstitutor(false).substitute(method.getReturnType());
TextRange fixRange = getFixRange(elementToHighlight);
if (expectedTypeByParent != null && actualType != null && !expectedTypeByParent.isAssignableFrom(actualType)) {
builder = HighlightUtil.createIncompatibleTypeHighlightInfo(
expectedTypeByParent, actualType, fixRange, 0, XmlStringUtil.escapeString(errorMessage));
if (methodCall instanceof PsiExpression) {
AdaptExpressionTypeFixUtil.registerExpectedTypeFixes(asConsumer(builder),
(PsiExpression)methodCall, expectedTypeByParent, actualType);
}
PsiElement parent = PsiUtil.skipParenthesizedExprUp(methodCall.getParent());
if (parent instanceof PsiReturnStatement) {
PsiParameterListOwner context = PsiTreeUtil.getParentOfType(parent, PsiMethod.class, PsiLambdaExpression.class);
if (context instanceof PsiMethod containingMethod) {
HighlightUtil.registerReturnTypeFixes(builder, containingMethod, actualType);
}
} else if (parent instanceof PsiLocalVariable var) {
HighlightFixUtil.registerChangeVariableTypeFixes(var, actualType, builder);
}
}
else {
builder = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip(errorMessage).range(fixRange);
}
if (methodCall instanceof PsiMethodCallExpression callExpression) {
HighlightFixUtil.registerMethodCallIntentions(asConsumer(builder), callExpression, callExpression.getArgumentList());
if (!PsiTypesUtil.mentionsTypeParameters(actualType, Set.of(method.getTypeParameters()))) {
HighlightFixUtil.registerMethodReturnFixAction(asConsumer(builder), resolveResult, methodCall);
}
HighlightFixUtil.registerTargetTypeFixesBasedOnApplicabilityInference(callExpression, resolveResult, method, asConsumer(builder));
}
return builder;
}
private static boolean favorParentReport(@NotNull PsiCall methodCall, @NotNull String errorMessage) {
// Parent resolve failed as well, and it's likely more informative.
// Suppress this error to allow reporting from parent
return (errorMessage.equals(JavaPsiBundle.message("error.incompatible.type.failed.to.resolve.argument")) ||
errorMessage.equals(JavaPsiBundle.message("error.incompatible.type.declaration.for.the.method.reference.not.found"))) &&
hasSurroundingInferenceError(methodCall);
}
static HighlightInfo.Builder checkAbstractMethodInConcreteClass(@NotNull PsiMethod method, @NotNull PsiElement elementToHighlight) {
HighlightInfo.Builder errorResult = null;
PsiClass aClass = method.getContainingClass();
@@ -98,7 +98,7 @@ public final class HighlightUtil {
IncompleteModelUtil.isPotentiallyConvertible(lType, expression)) {
return null;
}
HighlightInfo.Builder highlightInfo = createIncompatibleTypeHighlightInfo(lType, rType, textRange, 0);
HighlightInfo.Builder highlightInfo = createIncompatibleTypeHighlightInfo(lType, rType, textRange);
AddTypeArgumentsConditionalFix.register(asConsumer(highlightInfo), expression, lType);
if (expression != null) {
AdaptExpressionTypeFixUtil.registerExpectedTypeFixes(asConsumer(highlightInfo), expression, lType, rType);
@@ -127,11 +127,6 @@ public final class HighlightUtil {
};
}
static void registerReturnTypeFixes(@NotNull HighlightInfo.Builder info, @NotNull PsiMethod method, @NotNull PsiType expectedReturnType) {
IntentionAction action = getFixFactory().createMethodReturnFix(method, expectedReturnType, true, true);
info.registerFix(action, null, null, null, null);
}
public static @NotNull @NlsContexts.DetailedDescription String getUnhandledExceptionsDescriptor(@NotNull Collection<? extends PsiClassType> unhandled) {
return JavaErrorBundle.message("unhandled.exceptions", formatTypes(unhandled), unhandled.size());
}
@@ -775,23 +770,15 @@ public final class HighlightUtil {
}
// cannot derive type of conditional expression
// elseType will never be cast-able to thenType, so no quick fix here
return createIncompatibleTypeHighlightInfo(thenType, type, expression.getTextRange(), 0);
return createIncompatibleTypeHighlightInfo(thenType, type, expression.getTextRange());
}
return null;
}
static @NotNull HighlightInfo.Builder createIncompatibleTypeHighlightInfo(@NotNull PsiType lType,
static HighlightInfo.@NotNull Builder createIncompatibleTypeHighlightInfo(@NotNull PsiType lType,
@Nullable PsiType rType,
@NotNull TextRange textRange,
int navigationShift) {
return createIncompatibleTypeHighlightInfo(lType, rType, textRange, navigationShift, getReasonForIncompatibleTypes(rType));
}
static @NotNull HighlightInfo.Builder createIncompatibleTypeHighlightInfo(@NotNull PsiType lType,
@Nullable PsiType rType,
@NotNull TextRange textRange,
int navigationShift,
@NotNull String reason) {
@NotNull TextRange textRange) {
@NotNull String reason = getReasonForIncompatibleTypes(rType);
PsiType baseLType = PsiUtil.convertAnonymousToBaseType(lType);
PsiType baseRType = rType == null ? null : PsiUtil.convertAnonymousToBaseType(rType);
boolean leftAnonymous = PsiUtil.resolveClassInClassTypeOnly(lType) instanceof PsiAnonymousClass;
@@ -811,7 +798,7 @@ public final class HighlightUtil {
.range(textRange)
.description(description)
.escapedToolTip(toolTip)
.navigationShift(navigationShift);
.navigationShift(0);
}
static HighlightInfo.Builder checkExtraSemicolonBetweenImportStatements(@NotNull PsiJavaToken token,
@@ -52,7 +52,6 @@ import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.NamedColorUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -61,7 +60,6 @@ import java.util.function.Consumer;
import java.util.function.Function;
import static com.intellij.java.codeserver.highlighting.errors.JavaErrorKinds.*;
import static com.intellij.util.ObjectUtils.tryCast;
import static java.util.Objects.*;
// java highlighting: problems in java code like unresolved/incompatible symbols/methods etc.
@@ -105,10 +103,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
return myHasError;
}
private @Contract(pure = true) @NotNull Project getProject() {
return myHolder.getProject();
}
// element -> a constructor inside which this element is contained
private PsiMethod findSurroundingConstructor(@NotNull PsiElement entry) {
PsiMethod result = null;
@@ -276,86 +270,15 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
@Override
public void visitLambdaExpression(@NotNull PsiLambdaExpression expression) {
add(checkFeature(expression, JavaFeature.LAMBDA_EXPRESSIONS));
visitElement(expression);
PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression.getParent());
if (toReportFunctionalExpressionProblemOnParent(parent)) return;
if (!hasErrorResults() && !LambdaUtil.isValidLambdaContext(parent)) {
add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression)
.descriptionAndTooltip(JavaErrorBundle.message("lambda.expression.not.expected")));
}
if (!hasErrorResults()) add(LambdaHighlightingUtil.checkConsistentParameterDeclaration(expression));
if (hasErrorResults() || toReportFunctionalExpressionProblemOnParent(parent)) return;
PsiType functionalInterfaceType = null;
if (!hasErrorResults()) {
functionalInterfaceType = expression.getFunctionalInterfaceType();
if (functionalInterfaceType != null) {
add(HighlightClassUtil.checkExtendsSealedClass(expression, functionalInterfaceType));
if (!hasErrorResults()) {
String notFunctionalMessage = LambdaHighlightingUtil.checkInterfaceFunctional(expression, functionalInterfaceType);
if (notFunctionalMessage != null) {
add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression)
.descriptionAndTooltip(notFunctionalMessage));
}
else {
add(LambdaHighlightingUtil.checkFunctionalInterfaceTypeAccessible(myFile.getProject(), expression, functionalInterfaceType));
}
}
}
else if (LambdaUtil.getFunctionalInterfaceType(expression, true) != null) {
add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(
JavaErrorBundle.message("cannot.infer.functional.interface.type")));
}
}
if (!hasErrorResults() && functionalInterfaceType != null) {
PsiCallExpression callExpression = parent instanceof PsiExpressionList && parent.getParent() instanceof PsiCallExpression ?
(PsiCallExpression)parent.getParent() : null;
MethodCandidateInfo parentCallResolveResult =
callExpression != null ? tryCast(callExpression.resolveMethodGenerics(), MethodCandidateInfo.class) : null;
String parentInferenceErrorMessage = parentCallResolveResult != null ? parentCallResolveResult.getInferenceErrorMessage() : null;
PsiType returnType = LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType);
Map<PsiElement, @Nls String> returnErrors = null;
Set<PsiTypeParameter> parentTypeParameters =
parentCallResolveResult == null ? Set.of() : Set.of(parentCallResolveResult.getElement().getTypeParameters());
// If return type of the lambda was not fully inferred and lambda parameters don't mention the same type,
// it means that lambda is not responsible for inference failure and blaming it would be unreasonable.
boolean skipReturnCompatibility = parentCallResolveResult != null &&
PsiTypesUtil.mentionsTypeParameters(returnType, parentTypeParameters)
&& !LambdaHighlightingUtil.lambdaParametersMentionTypeParameter(functionalInterfaceType, parentTypeParameters);
if (!skipReturnCompatibility) {
returnErrors = LambdaUtil.checkReturnTypeCompatible(expression, returnType);
}
if (parentInferenceErrorMessage != null && (returnErrors == null || !returnErrors.containsValue(parentInferenceErrorMessage))) {
if (returnErrors == null) return;
HighlightInfo.Builder info =
HighlightMethodUtil.createIncompatibleTypeHighlightInfo(callExpression,
parentCallResolveResult, expression);
if (info != null) {
for (PsiElement errorElement : returnErrors.keySet()) {
IntentionAction action = AdjustFunctionContextFix.createFix(errorElement);
if (action != null) {
info.registerFix(action, null, null, null, null);
}
}
add(info);
}
}
else if (returnErrors != null && !PsiTreeUtil.hasErrorElements(expression)) {
for (Map.Entry<PsiElement, @Nls String> entry : returnErrors.entrySet()) {
PsiElement element = entry.getKey();
HighlightInfo.Builder info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
.range(element)
.descriptionAndTooltip(entry.getValue());
IntentionAction action = AdjustFunctionContextFix.createFix(element);
if (action != null) {
info.registerFix(action, null, null, null, null);
}
if (element instanceof PsiExpression expr) {
HighlightFixUtil.registerLambdaReturnTypeFixes(HighlightUtil.asConsumer(info), expression, expr);
}
add(info);
}
add(LambdaHighlightingUtil.checkFunctionalInterfaceTypeAccessible(myFile.getProject(), expression, functionalInterfaceType));
}
}
@@ -757,9 +680,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
}
if (functionalInterfaceType != null) {
if (!hasErrorResults()) {
add(HighlightClassUtil.checkExtendsSealedClass(expression, functionalInterfaceType));
}
if (!hasErrorResults()) {
boolean isFunctional = LambdaUtil.isFunctionalType(functionalInterfaceType);
if (!isFunctional && !(IncompleteModelUtil.isIncompleteModel(expression) &&
@@ -549,6 +549,31 @@ final class JavaErrorFixProvider {
HighlightFixUtil.registerCallInferenceFixes(callExpression, sink);
}
});
fixes(LAMBDA_INFERENCE_ERROR, (error, sink) -> {
if (error.psi().getParent() instanceof PsiExpressionList list &&
list.getParent() instanceof PsiMethodCallExpression callExpression) {
MethodCandidateInfo resolveResult = error.context();
PsiMethod method = resolveResult.getElement();
HighlightFixUtil.registerMethodCallIntentions(sink, callExpression, callExpression.getArgumentList());
if (!PsiTypesUtil.mentionsTypeParameters(((PsiExpression)callExpression.copy()).getType(), Set.of(method.getTypeParameters()))) {
HighlightFixUtil.registerMethodReturnFixAction(sink, resolveResult, callExpression);
}
HighlightFixUtil.registerTargetTypeFixesBasedOnApplicabilityInference(callExpression, resolveResult, method, sink);
LambdaUtil.getReturnExpressions(error.psi())
.stream().map(PsiExpression::getType).distinct()
.map(type -> AdjustFunctionContextFix.createFix(type, error.psi()))
.forEach(sink);
}
});
fixes(LAMBDA_RETURN_TYPE_ERROR, (error, sink) -> {
if (error.psi() instanceof PsiExpression expr) {
sink.accept(AdjustFunctionContextFix.createFix(expr));
PsiLambdaExpression lambda = PsiTreeUtil.getParentOfType(expr, PsiLambdaExpression.class);
if (lambda != null) {
HighlightFixUtil.registerLambdaReturnTypeFixes(sink, lambda, expr);
}
}
});
fixes(CALL_WRONG_ARGUMENTS, (error, sink) -> {
JavaMismatchedCallContext context = error.context();
PsiExpressionList list = context.list();
@@ -744,7 +769,7 @@ final class JavaErrorFixProvider {
ANNOTATION_NOT_ALLOWED_REF, ANNOTATION_NOT_ALLOWED_VAR,
ANNOTATION_NOT_ALLOWED_VOID, LAMBDA_MULTIPLE_TARGET_METHODS, LAMBDA_NO_TARGET_METHOD,
LAMBDA_NOT_FUNCTIONAL_INTERFACE, ANNOTATION_NOT_APPLICABLE,
LAMBDA_FUNCTIONAL_INTERFACE_SEALED, OVERRIDE_ON_STATIC_METHOD,
FUNCTIONAL_INTERFACE_SEALED, OVERRIDE_ON_STATIC_METHOD,
OVERRIDE_ON_NON_OVERRIDING_METHOD, SAFE_VARARGS_ON_FIXED_ARITY,
SAFE_VARARGS_ON_NON_FINAL_METHOD, SAFE_VARARGS_ON_RECORD_COMPONENT,
ANNOTATION_CONTAINER_WRONG_PLACE, ANNOTATION_CONTAINER_NOT_APPLICABLE)) {
@@ -149,26 +149,6 @@ public final class LambdaHighlightingUtil {
return JavaErrorBundle.message("not.a.functional.interface", functionalInterfaceType.getPresentableText());
}
static HighlightInfo.Builder checkConsistentParameterDeclaration(@NotNull PsiLambdaExpression expression) {
PsiParameter[] parameters = expression.getParameterList().getParameters();
if (parameters.length < 2) return null;
boolean hasExplicitParameterTypes = hasExplicitType(parameters[0]);
for (int i = 1; i < parameters.length; i++) {
if (hasExplicitParameterTypes != hasExplicitType(parameters[i])) {
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
.descriptionAndTooltip(JavaErrorBundle.message("lambda.parameters.consistency.message"))
.range(expression.getParameterList());
}
}
return null;
}
private static boolean hasExplicitType(@NotNull PsiParameter parameter) {
PsiTypeElement typeElement = parameter.getTypeElement();
return typeElement != null && !typeElement.isInferredType();
}
// 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.
@@ -238,15 +218,4 @@ public final class LambdaHighlightingUtil {
return null;
}
static boolean lambdaParametersMentionTypeParameter(@NotNull PsiType functionalInterfaceType, @NotNull Set<? extends PsiTypeParameter> parameters) {
if (!(functionalInterfaceType instanceof PsiClassType classType)) return false;
PsiSubstitutor substitutor = classType.resolveGenerics().getSubstitutor();
PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType);
if (method == null) return false;
for (PsiParameter parameter : method.getParameterList().getParameters()) {
if (PsiTypesUtil.mentionsTypeParameters(substitutor.substitute(parameter.getType()), parameters)) return true;
}
return false;
}
}
@@ -100,7 +100,7 @@ final class PatternHighlightingModel {
continue;
}
builder = HighlightUtil.createIncompatibleTypeHighlightInfo(substitutedRecordComponentType, deconstructionComponentType,
deconstructionComponent.getTextRange(), 0);
deconstructionComponent.getTextRange());
}
errorSink.accept(builder);
@@ -209,7 +209,7 @@ public class PatternsInSwitchBlockHighlightingModel extends SwitchBlockHighlight
if (!IncompleteModelUtil.isIncompleteModel(label) ||
(!IncompleteModelUtil.isPotentiallyConvertible(mySelectorType, patternType, label))) {
HighlightInfo.Builder error =
HighlightUtil.createIncompatibleTypeHighlightInfo(mySelectorType, patternType, elementToReport.getTextRange(), 0);
HighlightUtil.createIncompatibleTypeHighlightInfo(mySelectorType, patternType, elementToReport.getTextRange());
if (mySelectorType instanceof PsiPrimitiveType) {
HighlightInfo.Builder infoFeature =
HighlightUtil.checkFeature(elementToReport, JavaFeature.PRIMITIVE_TYPES_IN_PATTERNS,
@@ -233,7 +233,7 @@ public class PatternsInSwitchBlockHighlightingModel extends SwitchBlockHighlight
else if (label instanceof PsiExpression expr) {
if (mySelectorType.equals(PsiTypes.nullType())) {
HighlightInfo.Builder info =
HighlightUtil.createIncompatibleTypeHighlightInfo(mySelectorType, expr.getType(), expr.getTextRange(), 0);
HighlightUtil.createIncompatibleTypeHighlightInfo(mySelectorType, expr.getType(), expr.getTextRange());
errorSink.accept(info);
return true;
}
@@ -268,7 +268,7 @@ public class PatternsInSwitchBlockHighlightingModel extends SwitchBlockHighlight
PsiType unboxedType = PsiPrimitiveType.getOptionallyUnboxedType(mySelectorType);
if (unboxedType != null) {
HighlightInfo.Builder error =
HighlightUtil.createIncompatibleTypeHighlightInfo(unboxedType, expr.getType(), label.getTextRange(), 0);
HighlightUtil.createIncompatibleTypeHighlightInfo(unboxedType, expr.getType(), label.getTextRange());
errorSink.accept(error);
return true;
}
@@ -277,7 +277,7 @@ public class PatternsInSwitchBlockHighlightingModel extends SwitchBlockHighlight
}
if (ConstantExpressionUtil.computeCastTo(constValue, mySelectorType) == null) {
HighlightInfo.Builder error =
HighlightUtil.createIncompatibleTypeHighlightInfo(mySelectorType, expr.getType(), label.getTextRange(), 0);
HighlightUtil.createIncompatibleTypeHighlightInfo(mySelectorType, expr.getType(), label.getTextRange());
errorSink.accept(error);
return true;
}
@@ -79,21 +79,29 @@ public class AdjustFunctionContextFix extends PsiUpdateModCommandAction<PsiMetho
return QuickFixBundle.message("adjust.method.accepting.functional.expression.fix.family.name");
}
public static @Nullable IntentionAction createFix(@NotNull PsiElement context) {
if (!(context instanceof PsiExpression expression)) return null;
PsiFunctionalExpression fn = PsiTreeUtil.getParentOfType(context, PsiFunctionalExpression.class, false);
public static @Nullable IntentionAction createFix(@NotNull PsiExpression expression) {
PsiFunctionalExpression fn = PsiTreeUtil.getParentOfType(expression, PsiFunctionalExpression.class, false);
if (fn == null) return null;
PsiExpressionList expressionList = ObjectUtils.tryCast(fn.getParent(), PsiExpressionList.class);
if (expressionList == null || expressionList.getExpressionCount() != 1) return null;
PsiMethodCallExpression call = ObjectUtils.tryCast(expressionList.getParent(), PsiMethodCallExpression.class);
Function<PsiType, String> remapper = METHOD_NAME_ADJUSTER.mapFirst(call);
if (remapper == null) return null;
PsiType actualReturnType;
if(expression instanceof PsiMethodReferenceExpression methodRef) {
actualReturnType = PsiMethodReferenceUtil.getMethodReferenceReturnType(methodRef);
} else {
actualReturnType = expression.getType();
}
return createFix(actualReturnType, fn);
}
/**
* @param actualReturnType actual (unexpected) return type of functional expression
* @param fn functional expression
* @return a fix that aims to adjust the surroundings
*/
public static @Nullable IntentionAction createFix(@Nullable PsiType actualReturnType, @NotNull PsiFunctionalExpression fn) {
PsiExpressionList expressionList = ObjectUtils.tryCast(fn.getParent(), PsiExpressionList.class);
if (expressionList == null || expressionList.getExpressionCount() != 1) return null;
PsiMethodCallExpression call = ObjectUtils.tryCast(expressionList.getParent(), PsiMethodCallExpression.class);
Function<PsiType, String> remapper = METHOD_NAME_ADJUSTER.mapFirst(call);
if (remapper == null) return null;
String targetMethodName = remapper.apply(actualReturnType);
if (targetMethodName == null) return null;
return new AdjustFunctionContextFix(call, targetMethodName).asIntention();
@@ -16,10 +16,10 @@ final class MyFn implements Fn {
class Test {
void test() {
Fn fn = <error descr="Sealed class can not be used as functional interface">() -> 1</error>;
Fn fn1 = <error descr="Sealed class can not be used as functional interface">this::doSmth</error>;
foo(<error descr="Sealed class can not be used as functional interface">() -> 1</error>);
foo(<error descr="Sealed class can not be used as functional interface">this::doSmth</error>);
Fn fn = <error descr="Lambda cannot implement a sealed interface">() -> 1</error>;
Fn fn1 = <error descr="Method reference cannot implement a sealed interface">this::doSmth</error>;
foo(<error descr="Lambda cannot implement a sealed interface">() -> 1</error>);
foo(<error descr="Method reference cannot implement a sealed interface">this::doSmth</error>);
}
int doSmth() {
@@ -1,4 +1,4 @@
<error descr="Multiple non-overriding abstract methods found in interface Test">@FunctionalInterface</error>
<error descr="Multiple non-overriding abstract methods found in Test">@FunctionalInterface</error>
interface Test {
void foo();
void bar();
@@ -36,7 +36,7 @@ class Test2 {
}
{
F f = <error descr="Multiple non-overriding abstract methods found in interface Test2.F">() -> g()</error>;
F f = <error descr="Multiple non-overriding abstract methods found in F">() -> g()</error>;
}
void g() {}
@@ -8,7 +8,7 @@ public class NotAFIT {
}
void bar() {
foo(<error descr="Multiple non-overriding abstract methods found in interface NotAFIT.First.A">() ->{}</error>);
foo(<error descr="Multiple non-overriding abstract methods found in A">() ->{}</error>);
}
}
@@ -25,7 +25,7 @@ public class NotAFIT {
}
void bar() {
foo(<error descr="Multiple non-overriding abstract methods found in interface NotAFIT.WithInheritance.B">()->{}</error>);
foo(<error descr="Multiple non-overriding abstract methods found in B">()->{}</error>);
}
}
@@ -9,7 +9,7 @@ class Test {
<R> SuperFoo<R> foo(I<R> ax) { return null; }
SuperFoo<String> ls = foo(<error descr="Incompatible types. Found: 'Test.SuperFoo<java.lang.Number>', required: 'Test.SuperFoo<java.lang.String>'">() -> new Foo<>()</error>);
SuperFoo<String> ls = <error descr="Incompatible types. Found: 'Test.SuperFoo<java.lang.Number>', required: 'Test.SuperFoo<java.lang.String>'">foo</error>(() -> new Foo<>());
SuperFoo<Integer> li = foo(() -> new Foo<>());
SuperFoo<?> lw = foo(() -> new Foo<>());
}
@@ -12,7 +12,7 @@ class Test {
class Test1 {
{
Supplier<Runnable> x = foo(() -> <error descr="Multiple non-overriding abstract methods found in interface java.util.List">() -> null</error>);
Supplier<Runnable> x = foo(() -> <error descr="Multiple non-overriding abstract methods found in List">() -> null</error>);
}
static <T> Supplier<T> foo(Supplier<java.util.List<T>> delegate) {