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
This commit is contained in:
Tagir Valeev
2020-05-12 04:34:42 +00:00
committed by intellij-monorepo-bot
parent 507268f2bd
commit 985b752fad
3 changed files with 25 additions and 8 deletions
@@ -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<PsiReferenceExpression> 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<PsiReferenceExpression> refs = VariableAccessUtils.getVariableReferences(localFn, scope);
if (ContainerUtil.getOnlyItem(refs) == stripped) {
myAnalyzer.removeLambda(localLambda);
return tryInlineLambda(argCount, localLambda, resultNullability, pushArgs);
}
}
}
}
@@ -0,0 +1,11 @@
import java.util.function.Predicate;
class SwitchExpr {
void test() {
Predicate<String> predicate = value -> switch(value) {
case "A" -> true;
default -> false;
};
Predicate<String> otherPredicate = value -> value.length() == 1 && predicate.test(value);
}
}
@@ -25,4 +25,5 @@ public class DataFlowInspection14Test extends DataFlowInspectionTestCase {
myFixture.addClass("package java.lang.constant; public interface ConstantDesc {}");
doTest();
}
public void testSwitchExpressionAndLambdaInlining() { doTest(); }
}