recursive lambda checks for functional interfaces

This commit is contained in:
anna
2013-08-06 12:01:09 +02:00
parent 94f4462b36
commit 1bd39a6322
7 changed files with 31 additions and 14 deletions

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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>;
}
}

View File

@@ -0,0 +1,5 @@
class Demo {
public static void main(String[] args) {
Runnable r = () -> <error descr="void is not a functional interface">() -> () -> {}</error>;
}
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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);