From 985b752fadafd385e668ddb800721b325284f520 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Tue, 12 May 2020 11:17:49 +0700 Subject: [PATCH] Avoid inlining lambdas not from local scope When lambda is defined in the outer scope a number of problems may appear during the analysis. First, it actually could be analyzed twice producing different warnings (in inlining context, and as standalone expression). Second, trap-handling assumes that all exited expressions should appear within the current codeFragment. This could be violated when lambda comes from the outer scope, resulting in incorrect jumps. Fixes IDEA-240328 Condition always false inspection is wrong if using switch expressions GitOrigin-RevId: 11794502d2e661044fa2105402955aa54e3c1245 --- .../codeInspection/dataFlow/CFGBuilder.java | 21 ++++++++++++------- .../SwitchExpressionAndLambdaInlining.java | 11 ++++++++++ .../DataFlowInspection14Test.java | 1 + 3 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 java/java-tests/testData/inspection/dataFlow/fixture/SwitchExpressionAndLambdaInlining.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CFGBuilder.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CFGBuilder.java index 0c9030d2237f..9b26a6b7d264 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CFGBuilder.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CFGBuilder.java @@ -26,6 +26,7 @@ import com.intellij.codeInspection.dataFlow.value.DfaValueFactory; import com.intellij.codeInspection.dataFlow.value.DfaVariableValue; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; @@ -766,14 +767,18 @@ public class CFGBuilder { } PsiLocalVariable localFn = ExpressionUtils.resolveLocalVariable(stripped); if (localFn != null) { - PsiLambdaExpression localLambda = - ObjectUtils.tryCast(PsiUtil.skipParenthesizedExprDown(localFn.getInitializer()), PsiLambdaExpression.class); - if (myAnalyzer.wasAdded(localLambda)) { - PsiElement scope = PsiUtil.getVariableCodeBlock(localFn, null); - List refs = VariableAccessUtils.getVariableReferences(localFn, scope); - if (ContainerUtil.getOnlyItem(refs) == stripped) { - myAnalyzer.removeLambda(localLambda); - return tryInlineLambda(argCount, localLambda, resultNullability, pushArgs); + PsiElement parent = + PsiTreeUtil.getParentOfType(functionalExpression, PsiLambdaExpression.class, PsiClass.class, PsiMethod.class); + if (PsiTreeUtil.isAncestor(parent, localFn, true)) { + PsiLambdaExpression localLambda = + ObjectUtils.tryCast(PsiUtil.skipParenthesizedExprDown(localFn.getInitializer()), PsiLambdaExpression.class); + if (myAnalyzer.wasAdded(localLambda)) { + PsiElement scope = PsiUtil.getVariableCodeBlock(localFn, null); + List refs = VariableAccessUtils.getVariableReferences(localFn, scope); + if (ContainerUtil.getOnlyItem(refs) == stripped) { + myAnalyzer.removeLambda(localLambda); + return tryInlineLambda(argCount, localLambda, resultNullability, pushArgs); + } } } } diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/SwitchExpressionAndLambdaInlining.java b/java/java-tests/testData/inspection/dataFlow/fixture/SwitchExpressionAndLambdaInlining.java new file mode 100644 index 000000000000..cff2b4e04aea --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/SwitchExpressionAndLambdaInlining.java @@ -0,0 +1,11 @@ +import java.util.function.Predicate; + +class SwitchExpr { + void test() { + Predicate predicate = value -> switch(value) { + case "A" -> true; + default -> false; + }; + Predicate otherPredicate = value -> value.length() == 1 && predicate.test(value); + } +} diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection14Test.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection14Test.java index 5047fdf64a38..626f3cff4e64 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection14Test.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection14Test.java @@ -25,4 +25,5 @@ public class DataFlowInspection14Test extends DataFlowInspectionTestCase { myFixture.addClass("package java.lang.constant; public interface ConstantDesc {}"); doTest(); } + public void testSwitchExpressionAndLambdaInlining() { doTest(); } } \ No newline at end of file