From 57a78b6fab108eef44ef12d8a42627efe14dff85 Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Fri, 25 Nov 2011 21:10:08 +0400 Subject: [PATCH] IDEA-74518: Associations for variable negation haven't been cleared on flush. --- .../dataFlow/DataFlowInspection.java | 21 +++++++++++++++++-- .../dataFlow/DfaMemoryStateImpl.java | 5 +++++ .../dataFlow/IDEADEV74518/expected.xml | 9 +++++++- .../dataFlow/IDEADEV74518/src/NoWarnings.java | 13 ++++++++---- .../dataFlow/IDEADEV74518_2/expected.xml | 3 +++ .../dataFlow/IDEADEV74518_2/src/Sample.java | 17 +++++++++++++++ .../DataFlowInspectionTest.java | 1 + .../src/messages/InspectionsBundle.properties | 1 + 8 files changed, 63 insertions(+), 7 deletions(-) create mode 100644 java/java-tests/testData/inspection/dataFlow/IDEADEV74518_2/expected.xml create mode 100644 java/java-tests/testData/inspection/dataFlow/IDEADEV74518_2/src/Sample.java diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java index c48867c0b0da..59bcce017d48 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java @@ -198,6 +198,7 @@ public class DataFlowInspection extends BaseLocalInspectionTool { } else if (instruction instanceof BranchingInstruction) { PsiElement psiAnchor = ((BranchingInstruction)instruction).getPsiAnchor(); + boolean underBinary = isAtRHSOfBooleanAnd(psiAnchor); if (instruction instanceof InstanceofInstruction && visitor.isInstanceofRedundant((InstanceofInstruction)instruction)) { if (visitor.canBeNull((BinopInstruction)instruction)) { holder.registerProblem(psiAnchor, @@ -207,7 +208,7 @@ public class DataFlowInspection extends BaseLocalInspectionTool { else { final LocalQuickFix localQuickFix = createSimplifyBooleanExpressionFix(psiAnchor, true); holder.registerProblem(psiAnchor, - InspectionsBundle.message("dataflow.message.constant.condition", Boolean.toString(true)), + InspectionsBundle.message(underBinary ? "dataflow.message.constant.condition.whenriched" : "dataflow.message.constant.condition", Boolean.toString(true)), localQuickFix==null?null:new LocalQuickFix[]{localQuickFix}); } } @@ -227,7 +228,7 @@ public class DataFlowInspection extends BaseLocalInspectionTool { boolean report = !(psiAnchor.getParent() instanceof PsiAssertStatement) || !DONT_REPORT_TRUE_ASSERT_STATEMENTS || !evaluatesToTrue; if (report) { final LocalQuickFix localQuickFix = createSimplifyBooleanExpressionFix(psiAnchor, evaluatesToTrue); - holder.registerProblem(psiAnchor, InspectionsBundle.message("dataflow.message.constant.condition", + holder.registerProblem(psiAnchor, InspectionsBundle.message(underBinary ? "dataflow.message.constant.condition.whenriched" : "dataflow.message.constant.condition", Boolean.toString(evaluatesToTrue)), localQuickFix == null ? null : new LocalQuickFix[]{localQuickFix}); } @@ -279,6 +280,22 @@ public class DataFlowInspection extends BaseLocalInspectionTool { } } + private static boolean isAtRHSOfBooleanAnd(PsiElement expr) { + PsiElement cur = expr; + + while (cur != null && !(cur instanceof PsiMember)) { + PsiElement parent = cur.getParent(); + + if (parent instanceof PsiBinaryExpression && cur == ((PsiBinaryExpression)parent).getROperand()) { + return true; + } + + cur = parent; + } + + return false; + } + private static boolean isCompileConstantInIfCondition(PsiElement element) { if (!(element instanceof PsiReferenceExpression)) return false; PsiElement resolved = ((PsiReferenceExpression)element).resolve(); diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java index 82703a3ad23d..ac80fde38cd4 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java @@ -683,6 +683,11 @@ public class DfaMemoryStateImpl implements DfaMemoryState { return; } + doFlash(variable); + doFlash((DfaVariableValue)variable.createNegated()); + } + + private void doFlash(DfaVariableValue variable) { final int id = variable.getID(); int size = myEqClasses.size(); int interruptCount = 0; diff --git a/java/java-tests/testData/inspection/dataFlow/IDEADEV74518/expected.xml b/java/java-tests/testData/inspection/dataFlow/IDEADEV74518/expected.xml index 9ac879d78616..03896ee5835d 100644 --- a/java/java-tests/testData/inspection/dataFlow/IDEADEV74518/expected.xml +++ b/java/java-tests/testData/inspection/dataFlow/IDEADEV74518/expected.xml @@ -1,3 +1,10 @@ - + + + NoWarnings.java + 9 + Constant conditions & exceptions + Condition <code>i == 1</code> is always <code>true</code> when reached + + diff --git a/java/java-tests/testData/inspection/dataFlow/IDEADEV74518/src/NoWarnings.java b/java/java-tests/testData/inspection/dataFlow/IDEADEV74518/src/NoWarnings.java index 59130daee1ea..68e4c52e32c5 100644 --- a/java/java-tests/testData/inspection/dataFlow/IDEADEV74518/src/NoWarnings.java +++ b/java/java-tests/testData/inspection/dataFlow/IDEADEV74518/src/NoWarnings.java @@ -5,12 +5,17 @@ public class NoWarnings { int i = 1; boolean b = true; - while (i < 200) { - if (b && i == 1) { // Warning here: i == 1 is always true, but it is not so. + while (true) { + if (b && i == 1) { b = false; - } else { - i++; + } + else { + i = g(); } } } + + public int g() { + return 1; + } } diff --git a/java/java-tests/testData/inspection/dataFlow/IDEADEV74518_2/expected.xml b/java/java-tests/testData/inspection/dataFlow/IDEADEV74518_2/expected.xml new file mode 100644 index 000000000000..ec272abeaa3a --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/IDEADEV74518_2/expected.xml @@ -0,0 +1,3 @@ + + + diff --git a/java/java-tests/testData/inspection/dataFlow/IDEADEV74518_2/src/Sample.java b/java/java-tests/testData/inspection/dataFlow/IDEADEV74518_2/src/Sample.java new file mode 100644 index 000000000000..33f8f7f68ab4 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/IDEADEV74518_2/src/Sample.java @@ -0,0 +1,17 @@ +public abstract class NoWarnings { + public void f() { + boolean A = false; + boolean B = false; + + while (true) { + boolean f = g(); + A = A || f; + B = B || !f; + if (A && B) { + return; + } + } + } + + public abstract boolean g(); +} diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java index 625b51e84f51..e519ee0e6097 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java @@ -79,6 +79,7 @@ public class DataFlowInspectionTest extends InspectionTestCase { public void testconstantExpr() throws Exception { doTest(); } public void testIDEADEV74518() throws Exception { doTest(); } + public void testIDEADEV74518_2() throws Exception { doTest(); } public void testNotNullable() throws Exception { doTest15(); } diff --git a/platform/platform-resources-en/src/messages/InspectionsBundle.properties b/platform/platform-resources-en/src/messages/InspectionsBundle.properties index 1e3b70d16400..0ae2bc50dcba 100644 --- a/platform/platform-resources-en/src/messages/InspectionsBundle.properties +++ b/platform/platform-resources-en/src/messages/InspectionsBundle.properties @@ -49,6 +49,7 @@ dataflow.message.npe.field.access=Dereference of #ref #loc may prod dataflow.message.cce=Casting {0} to #ref #loc may produce java.lang.ClassCastException dataflow.message.redundant.instanceof=Condition #ref #loc is redundant and can be replaced with != null dataflow.message.constant.condition=Condition #ref #loc is always {0} +dataflow.message.constant.condition.whenriched=Condition #ref #loc is always {0} when reached dataflow.message.unreachable.switch.label=Switch label#ref #loc is unreachable dataflow.message.pointless.assignment.expression=Condition #ref #loc at the left side of assignment expression is always {0}. Can be simplified to normal assignment dataflow.message.passing.null.argument=Passing null argument to parameter annotated as @NotNull