From 035b6d9d1f502c90ed3fb070033618eeb873a9e5 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Thu, 21 Jul 2016 18:59:50 +0200 Subject: [PATCH] lambda return type inconsistency: highlight all found errors (IDEA-158853) --- .../impl/analysis/HighlightVisitorImpl.java | 14 ++++---- .../src/com/intellij/psi/LambdaUtil.java | 36 +++++++++++++------ ...HighlightFaultyLambdaReturnExpression.java | 15 ++++++++ .../lambda/NewLambdaHighlightingTest.java | 4 +++ 4 files changed, 52 insertions(+), 17 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/HighlightFaultyLambdaReturnExpression.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 6093e21abb82..b8b6849b1e34 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -337,14 +337,14 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh myHolder.add(result); } else { - final String incompatibleReturnTypesMessage = LambdaUtil + final Map returnErrors = LambdaUtil .checkReturnTypeCompatible(expression, LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType)); - if (incompatibleReturnTypesMessage != null) { - final List returnExpressions = LambdaUtil.getReturnExpressions(expression); - final PsiElement returnStatementToHighlight = returnExpressions.size() == 1 ? returnExpressions.get(0) : expression.getBody(); - HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(returnStatementToHighlight != null ? returnStatementToHighlight : expression) - .descriptionAndTooltip(incompatibleReturnTypesMessage).create(); - myHolder.add(result); + if (returnErrors != null) { + for (Map.Entry entry : returnErrors.entrySet()) { + myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .range(entry.getKey()) + .descriptionAndTooltip(entry.getValue()).create()); + } } else { final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); diff --git a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java index 7376042ef16e..3f5bc1359b53 100644 --- a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java @@ -651,25 +651,32 @@ public class LambdaUtil { return map; } - public static String checkReturnTypeCompatible(PsiLambdaExpression lambdaExpression, PsiType functionalInterfaceReturnType) { + public static Map checkReturnTypeCompatible(PsiLambdaExpression lambdaExpression, PsiType functionalInterfaceReturnType) { + Map errors = new LinkedHashMap(); if (PsiType.VOID.equals(functionalInterfaceReturnType)) { final PsiElement body = lambdaExpression.getBody(); if (body instanceof PsiCodeBlock) { - if (!getReturnExpressions(lambdaExpression).isEmpty()) return "Unexpected return value"; - } else if (body instanceof PsiExpression) { + for (PsiExpression expression : getReturnExpressions(lambdaExpression)) { + errors.put(expression, "Unexpected return value"); + } + } + else if (body instanceof PsiExpression) { final PsiType type = ((PsiExpression)body).getType(); try { if (!PsiUtil.isStatement(JavaPsiFacade.getElementFactory(body.getProject()).createStatementFromText(body.getText(), body))) { if (PsiType.VOID.equals(type)) { - return "Lambda body must be a statement expression"; + errors.put(body, "Lambda body must be a statement expression"); + } + else { + errors.put(body, "Bad return type in lambda expression: " + (type == PsiType.NULL || type == null ? "" : type.getPresentableText()) + " cannot be converted to void"); } - return "Bad return type in lambda expression: " + (type == PsiType.NULL || type == null ? "" : type.getPresentableText()) + " cannot be converted to void"; } } catch (IncorrectOperationException ignore) { } } - } else if (functionalInterfaceReturnType != null) { + } + else if (functionalInterfaceReturnType != null) { final List returnExpressions = getReturnExpressions(lambdaExpression); for (final PsiExpression expression : returnExpressions) { final PsiType expressionType = PsiResolveHelper.ourGraphGuard.doPreventingRecursion(expression, true, new Computable() { @@ -679,14 +686,23 @@ public class LambdaUtil { } }); if (expressionType != null && !functionalInterfaceReturnType.isAssignableFrom(expressionType)) { - return "Bad return type in lambda expression: " + expressionType.getPresentableText() + " cannot be converted to " + functionalInterfaceReturnType.getPresentableText(); + errors.put(expression, "Bad return type in lambda expression: " + expressionType.getPresentableText() + " cannot be converted to " + functionalInterfaceReturnType.getPresentableText()); } } - if (getReturnStatements(lambdaExpression).length > returnExpressions.size() || returnExpressions.isEmpty() && !lambdaExpression.isVoidCompatible()) { - return "Missing return value"; + final PsiReturnStatement[] returnStatements = getReturnStatements(lambdaExpression); + if (returnStatements.length > returnExpressions.size()) { + for (PsiReturnStatement statement : returnStatements) { + final PsiExpression value = statement.getReturnValue(); + if (value == null) { + errors.put(statement, "Missing return value"); + } + } + } + else if (returnExpressions.isEmpty() && !lambdaExpression.isVoidCompatible()) { + errors.put(lambdaExpression, "Missing return value"); } } - return null; + return errors.isEmpty() ? null : errors; } @Nullable diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/HighlightFaultyLambdaReturnExpression.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/HighlightFaultyLambdaReturnExpression.java new file mode 100644 index 000000000000..fdd1faa3c54a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/HighlightFaultyLambdaReturnExpression.java @@ -0,0 +1,15 @@ + +import java.util.function.Supplier; + +class Test { + public static void bar(boolean f) { + foo(() -> { + if (f) return; + if (false) return; + if (!f) return 1; + return null; + }); + } + + public static void foo(Supplier consumer) {} +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java index 050113fd5ffe..05ab0e4e53d6 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java @@ -327,6 +327,10 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testHighlightFaultyLambdaReturnExpression() throws Exception { + doTest(); + } + private void doTest() { doTest(false); }