mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[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:
committed by
intellij-monorepo-bot
parent
320f621750
commit
bdf1d8226d
+59
-14
@@ -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;
|
||||
|
||||
@@ -539,7 +539,18 @@ public final class LambdaUtil {
|
||||
}
|
||||
conjunct = psiType;
|
||||
}
|
||||
|
||||
if (conjunct == null) {
|
||||
return null;
|
||||
}
|
||||
for (PsiType typeConjunct : type.getConjuncts()) {
|
||||
if (typeConjunct == conjunct) {
|
||||
continue;
|
||||
}
|
||||
if (TypeConversionUtil.isAssignable(conjunct, typeConjunct) &&
|
||||
getFunction(PsiUtil.resolveClassInClassTypeOnly(typeConjunct)) == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return conjunct;
|
||||
}
|
||||
|
||||
|
||||
+37
@@ -5,4 +5,41 @@ class Test {
|
||||
public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K, V>> foo() {
|
||||
return (Comparator<Map.Entry<K, V>> & Serializable)(c1, c2) -> c1.getKey().compareTo(c2.getKey());
|
||||
}
|
||||
public static void main(String... args) {
|
||||
var shouldCompile = (Consumer<Integer> & IntConsumerAdapter1)
|
||||
i -> System.out.println("Cons3uming dd" + i);
|
||||
System.out.println(shouldCompile.getClass());
|
||||
shouldCompile.accept(42);
|
||||
shouldCompile.accept(Integer.valueOf(52));
|
||||
|
||||
var shouldNotCompile = (Consumer<Integer> & IntConsumerAdapter2)
|
||||
<error descr="No target method found">i -> System.out.println("Consumins2gs " + i)</error>;
|
||||
shouldNotCompile.accept(42);
|
||||
shouldNotCompile.accept(Integer.valueOf(52));
|
||||
}
|
||||
|
||||
public interface Consumer<T> {
|
||||
void accept(T t);
|
||||
}
|
||||
|
||||
public interface IntConsumer {
|
||||
|
||||
void accept(int value);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface IntConsumerAdapter1 extends IntConsumer, Consumer<Integer> {
|
||||
default void accept(int value) {
|
||||
accept(Integer.valueOf(value));
|
||||
}
|
||||
}
|
||||
|
||||
interface IntConsumerAdapter2 extends IntConsumer, Consumer<Integer> {
|
||||
default void accept(int value) {
|
||||
accept(Integer.valueOf(value));
|
||||
}
|
||||
|
||||
default void accept(Integer integer) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user