[java-inspections] IDEA-328239 Casting with conjunction

- Check if SAM is implemented in conjunction
- check lambda Methods signature with generic from types

GitOrigin-RevId: 981b75d4417e08bb6e392a2ab78d6104de19b84f
This commit is contained in:
Mikhail Pyltsin
2023-08-29 22:47:41 +02:00
committed by intellij-monorepo-bot
parent 320f621750
commit bdf1d8226d
3 changed files with 108 additions and 15 deletions

View File

@@ -7,16 +7,15 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.NlsContexts;
import com.intellij.psi.*;
import com.intellij.psi.util.MethodSignature;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.psi.util.*;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static com.intellij.psi.LambdaUtil.getFunction;
public final class LambdaHighlightingUtil {
private static final Logger LOG = Logger.getInstance(LambdaHighlightingUtil.class);
@@ -73,17 +72,43 @@ public final class LambdaHighlightingUtil {
public static @NlsContexts.DetailedDescription String checkInterfaceFunctional(@NotNull PsiType functionalInterfaceType) {
if (functionalInterfaceType instanceof PsiIntersectionType) {
Set<MethodSignature> signatures = new HashSet<>();
MultiMap<MethodSignature, PsiType> signatures = new MultiMap<>();
for (PsiType type : ((PsiIntersectionType)functionalInterfaceType).getConjuncts()) {
if (checkInterfaceFunctional(type) == null) {
MethodSignature signature = LambdaUtil.getFunction(PsiUtil.resolveClassInType(type));
MethodSignature signature = getFunction(PsiUtil.resolveClassInType(type));
LOG.assertTrue(signature != null, type.getCanonicalText());
signatures.add(signature);
signatures.putValue(signature, type);
}
}
if (signatures.size() > 1) {
return JavaErrorBundle.message("multiple.non.overriding.abstract.methods.found.in.0", functionalInterfaceType.getPresentableText());
PsiType baseType = signatures.entrySet().iterator().next().getValue().iterator().next();
MethodSignature baseSignature = getLambdaSignatureWithCommonSubstitutor(baseType);
for (PsiType type : signatures.values()) {
if (baseType == type) {
continue;
}
if (!TypeConversionUtil.isAssignable(baseType, type) &&
!TypeConversionUtil.isAssignable(type, baseType)) {
return JavaErrorBundle.message("multiple.non.overriding.abstract.methods.found.in.0",
functionalInterfaceType.getPresentableText());
}
MethodSignature currentSignature = getLambdaSignatureWithCommonSubstitutor(baseType);
if (baseSignature == null ||
currentSignature == null ||
!MethodSignatureUtil.areSignaturesEqual(baseSignature, currentSignature)) {
return JavaErrorBundle.message("multiple.non.overriding.abstract.methods.found.in.0",
functionalInterfaceType.getPresentableText());
}
}
}
if (signatures.size() == 1) {
PsiType baseType = signatures.entrySet().iterator().next().getValue().iterator().next();
for (PsiType type : ((PsiIntersectionType)functionalInterfaceType).getConjuncts()) {
if (TypeConversionUtil.isAssignable(baseType, type) && getFunction(PsiUtil.resolveClassInType(type)) == null) {
return JavaErrorBundle.message("no.target.method.found");
}
}
}
return null;
}
@@ -91,14 +116,34 @@ public final class LambdaHighlightingUtil {
PsiClass aClass = resolveResult.getElement();
if (aClass != null) {
if (aClass instanceof PsiTypeParameter) return null; //should be logged as cyclic inference
MethodSignature functionalMethod = LambdaUtil.getFunction(aClass);
if (functionalMethod != null && functionalMethod.getTypeParameters().length > 0) return JavaErrorBundle
.message("target.method.is.generic");
MethodSignature functionalMethod = getFunction(aClass);
if (functionalMethod != null && functionalMethod.getTypeParameters().length > 0) {
return JavaErrorBundle
.message("target.method.is.generic");
}
return checkInterfaceFunctional(aClass);
}
return JavaErrorBundle.message("not.a.functional.interface",functionalInterfaceType.getPresentableText());
return JavaErrorBundle.message("not.a.functional.interface", functionalInterfaceType.getPresentableText());
}
@Nullable
private static MethodSignature getLambdaSignature(PsiType psiType) {
PsiClassType.ClassResolveResult classResolveResult = PsiUtil.resolveGenericsClassInType(psiType);
PsiClass aClass = classResolveResult.getElement();
if (aClass instanceof PsiTypeParameter) return null;
return LambdaUtil.getFunction(aClass);
}
@Nullable
private static MethodSignature getLambdaSignatureWithCommonSubstitutor(PsiType psiType) {
PsiClassType.ClassResolveResult classResolveResult = PsiUtil.resolveGenericsClassInType(psiType);
MethodSignature signatureFromFunction = getLambdaSignature(psiType);
if (signatureFromFunction == null) return null;
PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(psiType);
if (method == null) return null;
PsiSubstitutor fullSubstitutor = classResolveResult.getSubstitutor().putAll(signatureFromFunction.getSubstitutor());
return method.getSignature(fullSubstitutor);
}
static HighlightInfo.Builder checkConsistentParameterDeclaration(@NotNull PsiLambdaExpression expression) {
PsiParameter[] parameters = expression.getParameterList().getParameters();
if (parameters.length < 2) return null;