From c7ce9a1a8cd09c3d3fb53738f28e3ec4d5327662 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Wed, 21 Nov 2018 15:44:14 +0100 Subject: [PATCH] switch expressions: inference for value breaks, correct lambda context in result expressions --- .../impl/analysis/HighlightVisitorImpl.java | 2 +- .../src/com/intellij/psi/LambdaUtil.java | 19 +++++++++++++++ .../src/com/intellij/psi/util/PsiUtil.java | 24 ++++++++++++------- .../SimpleInferenceCases.java | 8 +++++++ 4 files changed, 44 insertions(+), 9 deletions(-) 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 391aba3ba717..b2d4688b2442 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 @@ -1483,7 +1483,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (parent instanceof PsiLocalVariable) { return ((PsiLocalVariable)parent).getTypeElement().isInferredType(); } - return parent instanceof PsiExpressionStatement; + return parent instanceof PsiExpressionStatement && !(parent.getParent() instanceof PsiSwitchLabeledRuleStatement); } // 15.13 | 15.27 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 9908ca0b4d6d..3d22420fcf31 100644 --- a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java @@ -122,6 +122,21 @@ public class LambdaUtil { return isValidLambdaContext(parentContext); } } + if (context instanceof PsiBreakStatement) { + PsiElement element = ((PsiBreakStatement)context).findExitedElement(); + if (element instanceof PsiSwitchExpression) { + return isValidLambdaContext(element.getParent()); + } + } + if (context instanceof PsiExpressionStatement) { + PsiElement parent = context.getParent(); + if (parent instanceof PsiSwitchLabeledRuleStatement) { + PsiSwitchBlock switchBlock = ((PsiSwitchLabeledRuleStatement)parent).getEnclosingSwitchBlock(); + if (switchBlock != null) { + return isValidLambdaContext(switchBlock.getParent()); + } + } + } return false; } @@ -409,6 +424,10 @@ public class LambdaUtil { else if (parent instanceof PsiLambdaExpression) { return getFunctionalInterfaceTypeByContainingLambda((PsiLambdaExpression)parent); } + PsiSwitchExpression switchExpression = PsiTreeUtil.getParentOfType(element, PsiSwitchExpression.class); + if (switchExpression != null && PsiUtil.getSwitchResultExpressions(switchExpression).contains(element)) { + return getFunctionalInterfaceType(switchExpression, tryToSubstitute); + } return null; } diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java index ec954556d6e4..e16ab4cf3e7f 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java @@ -348,16 +348,23 @@ public final class PsiUtil extends PsiUtilCore { } public static List getSwitchResultExpressions(PsiSwitchExpression switchExpression) { - PsiCodeBlock body = switchExpression.getBody(); + PsiCodeBlock body = switchExpression.getBody(); if (body != null) { List result = new ArrayList<>(); PsiStatement[] statements = body.getStatements(); for (PsiStatement statement : statements) { if (statement instanceof PsiSwitchLabeledRuleStatement) { PsiStatement ruleBody = ((PsiSwitchLabeledRuleStatement)statement).getBody(); - if (ruleBody instanceof PsiExpressionStatement) {//todo break statements + if (ruleBody instanceof PsiExpressionStatement) { result.add(((PsiExpressionStatement)ruleBody).getExpression()); - + } + else if (ruleBody instanceof PsiBlockStatement) { + PsiCodeBlock codeBlock = ((PsiBlockStatement)ruleBody).getCodeBlock(); + ArrayList breaks = new ArrayList<>(); + addStatements(breaks, codeBlock, PsiBreakStatement.class); + for (PsiBreakStatement aBreak : breaks) { + ContainerUtil.addIfNotNull(result, aBreak.getExpression()); + } } } } @@ -1319,19 +1326,20 @@ public final class PsiUtil extends PsiUtilCore { public static PsiReturnStatement[] findReturnStatements(@Nullable PsiCodeBlock body) { ArrayList vector = new ArrayList<>(); if (body != null) { - addReturnStatements(vector, body); + addStatements(vector, body, PsiReturnStatement.class); } return vector.toArray(PsiReturnStatement.EMPTY_ARRAY); } - private static void addReturnStatements(List vector, PsiElement element) { - if (element instanceof PsiReturnStatement) { - vector.add((PsiReturnStatement)element); + private static void addStatements(List vector, PsiElement element, Class clazz) { + if (PsiTreeUtil.instanceOf(element, clazz)) { + //noinspection unchecked + vector.add((T)element); } else if (!(element instanceof PsiClass) && !(element instanceof PsiLambdaExpression)) { PsiElement[] children = element.getChildren(); for (PsiElement child : children) { - addReturnStatements(vector, child); + addStatements(vector, child, clazz); } } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting12/SimpleInferenceCases.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting12/SimpleInferenceCases.java index 54310857be38..44a57d48eed4 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting12/SimpleInferenceCases.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting12/SimpleInferenceCases.java @@ -23,5 +23,13 @@ no instance(s) of type variable(s) exist so that Object conforms to String">foo( default -> "str"; }); String s3 = foo(() -> switch (i) {default -> bar();}); + String s4 = foo(() -> switch (i) {default -> { break bar();}}); + String s5 = foo(() -> switch (i) {default -> { break 1;}}); + Supplier stringSupplier = switch (i) { + default -> { + break () -> 1; + } + }; } } \ No newline at end of file