mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-20 13:31:28 +07:00
recursive lambda checks for functional interfaces
This commit is contained in:
@@ -87,7 +87,12 @@ public class LambdaHighlightingUtil {
|
||||
|
||||
@Nullable
|
||||
public static String checkInterfaceFunctional(PsiType functionalInterfaceType) {
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
|
||||
if (functionalInterfaceType instanceof PsiIntersectionType) {
|
||||
for (PsiType type : ((PsiIntersectionType)functionalInterfaceType).getConjuncts()) {
|
||||
if (checkInterfaceFunctional(type) == null) return null;
|
||||
}
|
||||
}
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(GenericsUtil.eliminateWildcards(functionalInterfaceType));
|
||||
final PsiClass aClass = resolveResult.getElement();
|
||||
if (aClass != null) {
|
||||
if (checkReturnTypeApplicable(resolveResult, aClass)) {
|
||||
@@ -95,7 +100,7 @@ public class LambdaHighlightingUtil {
|
||||
}
|
||||
return checkInterfaceFunctional(aClass);
|
||||
}
|
||||
return null;
|
||||
return functionalInterfaceType.getPresentableText() + " is not a functional interface";
|
||||
}
|
||||
|
||||
private static boolean checkReturnTypeApplicable(PsiClassType.ClassResolveResult resolveResult, final PsiClass aClass) {
|
||||
|
||||
@@ -484,23 +484,30 @@ public class LambdaUtil {
|
||||
}
|
||||
}
|
||||
else if (parent instanceof PsiReturnStatement) {
|
||||
final PsiMethod method = PsiTreeUtil.getParentOfType(parent, PsiMethod.class);
|
||||
if (method != null) {
|
||||
return method.getReturnType();
|
||||
final PsiLambdaExpression gParent = PsiTreeUtil.getParentOfType(parent, PsiLambdaExpression.class);
|
||||
if (gParent != null) {
|
||||
return getFunctionalInterfaceTypeByContainingLambda(gParent);
|
||||
} else {
|
||||
final PsiMethod method = PsiTreeUtil.getParentOfType(parent, PsiMethod.class);
|
||||
if (method != null) {
|
||||
return method.getReturnType();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (parent instanceof PsiLambdaExpression) {
|
||||
final PsiType parentInterfaceType = ((PsiLambdaExpression)parent).getFunctionalInterfaceType();
|
||||
if (parentInterfaceType != null) {
|
||||
return getFunctionalInterfaceReturnType(parentInterfaceType);
|
||||
}
|
||||
return getFunctionalInterfaceTypeByContainingLambda((PsiLambdaExpression)parent);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static PsiType getFunctionalInterfaceTypeByContainingLambda(@NotNull PsiLambdaExpression parentLambda) {
|
||||
final PsiType parentInterfaceType = parentLambda.getFunctionalInterfaceType();
|
||||
return parentInterfaceType != null ? getFunctionalInterfaceReturnType(parentInterfaceType) : null;
|
||||
}
|
||||
|
||||
private static int adjustLambdaIdx(int lambdaIdx, PsiMethod resolve, PsiParameter[] parameters) {
|
||||
final int finalLambdaIdx;
|
||||
if (((PsiMethod)resolve).isVarArgs() && lambdaIdx >= parameters.length) {
|
||||
if (resolve.isVarArgs() && lambdaIdx >= parameters.length) {
|
||||
finalLambdaIdx = parameters.length - 1;
|
||||
} else {
|
||||
finalLambdaIdx = lambdaIdx;
|
||||
@@ -524,7 +531,6 @@ public class LambdaUtil {
|
||||
final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(param, PsiLambdaExpression.class);
|
||||
if (lambdaExpression != null) {
|
||||
|
||||
final PsiParameterList parameterList = lambdaExpression.getParameterList();
|
||||
PsiType type = getFunctionalInterfaceType(lambdaExpression, true, parameterIndex);
|
||||
if (type == null) {
|
||||
type = getFunctionalInterfaceType(lambdaExpression, false);
|
||||
|
||||
@@ -22,6 +22,6 @@ class CastInContexts {
|
||||
}
|
||||
|
||||
{
|
||||
int i = <error descr="Inconvertible types; cannot cast '<lambda expression>' to 'int'">(int) ()-> 1</error>;
|
||||
int i = (int) <error descr="int is not a functional interface">()-> 1</error>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
class Demo {
|
||||
public static void main(String[] args) {
|
||||
Runnable r = () -> <error descr="void is not a functional interface">() -> () -> {}</error>;
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ class NoInferenceResult {
|
||||
|
||||
void test() {
|
||||
m((String s1) -> <error descr="Target type of a lambda conversion must be an interface">(String s2) -> s1 + s2</error>);
|
||||
m(<error descr="Incompatible return type <lambda expression> in lambda expression">(String s1) -> {return (String s2) -> s1 + s2;}</error>);
|
||||
m((String s1) -> {return <error descr="Target type of a lambda conversion must be an interface">(String s2) -> s1 + s2</error>;});
|
||||
|
||||
m((String s1) -> s1.length());
|
||||
m((String s1) -> s1);
|
||||
|
||||
@@ -48,7 +48,7 @@ class Test2 {
|
||||
}
|
||||
|
||||
{
|
||||
X<?> x = <error descr="No instance of type X<?> exists so that lambda expression can be type-checked">() -> 123</error>;
|
||||
X<?> x = () -> 123;
|
||||
X<? extends Number> x1 = () -> 123;
|
||||
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ public class LambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
public void testConflictResolution() throws Exception {doTest();}
|
||||
public void testIDEA108195() throws Exception {doTest();}
|
||||
public void testDiamondInference() throws Exception { doTest();}
|
||||
public void testFunctionalInterfaceCheck() throws Exception { doTest();}
|
||||
|
||||
private void doTest() {
|
||||
doTest(false);
|
||||
|
||||
Reference in New Issue
Block a user