[java-dfa] IDEA-307660 Avoid double reporting between "Constant values" and "Pointless boolean expression"

GitOrigin-RevId: 97cf073bd5bcd69b8903e5cf2e915fb2a4261b6b
This commit is contained in:
Tagir Valeev
2022-12-05 18:07:45 +00:00
committed by intellij-monorepo-bot
parent 1a4b34963b
commit e0f8104e43
4 changed files with 87 additions and 40 deletions
@@ -32,6 +32,7 @@ import com.intellij.util.IncorrectOperationException;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.siyeh.ig.bugs.EqualsWithItselfInspection;
import com.siyeh.ig.controlflow.PointlessBooleanExpressionInspection;
import com.siyeh.ig.fixes.EqualsToEqualityFix;
import com.siyeh.ig.numeric.ComparisonToNaNInspection;
import com.siyeh.ig.psiutils.*;
@@ -325,6 +326,11 @@ public class ConstantValueInspection extends AbstractBaseJavaLocalInspectionTool
if (method == null || !JavaMethodContractUtil.isPure(method)) return true;
}
}
if (new PointlessBooleanExpressionInspection().getExpressionKind(expression) !=
PointlessBooleanExpressionInspection.BooleanExpressionKind.UNKNOWN) {
// avoid double reporting
return true;
}
while (expression != null && BoolUtils.isNegation(expression)) {
expression = BoolUtils.getNegated(expression);
}
@@ -0,0 +1,33 @@
// IDEA-304296
class BooleanOrEquals {
void foo(boolean a, boolean b) {
boolean c = !(b && false);
boolean d = a ^ b ^ true;
boolean x = a ^ !true ^ b;
boolean y = false || <warning descr="Condition 'c' is always 'true' when reached">c</warning>;
boolean z = b != true;
}
static int i = 1;
public static void main(String[] args) {
boolean b = false;
if (i == 1 && (b |= true))
System.out.println("i == 1");
if (i == 1 && (<warning descr="Condition 'b' at the left side of assignment expression is always 'true'. Can be simplified">b</warning> |= false))
System.out.println("i == 1");
if (<warning descr="Variable update does nothing">b</warning> |= false)
System.out.println("i == 1");
if (b |= true)
System.out.println("i == 1");
if (<warning descr="Variable is already assigned to this value">b</warning> = true)
System.out.println("i == 1");
System.out.println(b);
if (i == 1 && (<warning descr="Condition 'b' at the left side of assignment expression is always 'true'. Can be simplified">b</warning> &= true)) { }
if (<warning descr="Condition 'i == 1 && (b &= false)' is always 'false'">i == 1 && (<warning descr="Condition 'b' at the left side of assignment expression is always 'true'. Can be simplified">b</warning> &= false)</warning>) { }
if (<warning descr="Variable update does nothing">b</warning> &= true) {}
if (b &= false) {}
}
}
@@ -723,4 +723,5 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase {
public void testRewiringSubclassMethod() { doTest(); }
public void testTryWithResourcesCloseThrows() { doTest(); }
public void testBooleanOrEquals() { doTest(); }
public void testDuplicatedByPointlessBooleanInspection() { doTest(); }
}
@@ -41,7 +41,7 @@ import java.util.function.Predicate;
import java.util.function.Supplier;
public class PointlessBooleanExpressionInspection extends BaseInspection implements CleanupLocalInspectionTool {
private enum BooleanExpressionKind {
public enum BooleanExpressionKind {
USELESS, USELESS_WITH_SIDE_EFFECTS, UNKNOWN
}
@@ -441,9 +441,6 @@ public class PointlessBooleanExpressionInspection extends BaseInspection impleme
if (parent instanceof PsiExpression && getExpressionKind((PsiExpression)parent) != BooleanExpressionKind.UNKNOWN) {
return;
}
if (containsEscapingPatternVariable(expression)) {
return;
}
final String replacement = buildSimplifiedExpression(expression, new StringBuilder(), new CommentTracker()).toString();
final Supplier<PsiElement> newBodySupplier =
@@ -457,52 +454,62 @@ public class PointlessBooleanExpressionInspection extends BaseInspection impleme
}
@NotNull
private BooleanExpressionKind getExpressionKind(PsiExpression expression) {
public BooleanExpressionKind getExpressionKind(PsiExpression expression) {
if ((expression instanceof PsiPrefixExpression || expression instanceof PsiPolyadicExpression)
&& containsEscapingPatternVariable(expression)) {
return BooleanExpressionKind.UNKNOWN;
}
if (expression instanceof PsiPrefixExpression || expression instanceof PsiAssignmentExpression) {
return evaluate(expression) != null ? BooleanExpressionKind.USELESS : BooleanExpressionKind.UNKNOWN;
}
if (expression instanceof PsiPolyadicExpression polyadicExpression) {
final IElementType sign = polyadicExpression.getOperationTokenType();
if (!booleanTokens.contains(sign)) {
return getPolyadicKind(polyadicExpression);
}
return BooleanExpressionKind.UNKNOWN;
}
@NotNull
private BooleanExpressionKind getPolyadicKind(PsiPolyadicExpression expression) {
final IElementType sign = expression.getOperationTokenType();
if (!booleanTokens.contains(sign)) {
return BooleanExpressionKind.UNKNOWN;
}
final PsiExpression[] operands = expression.getOperands();
boolean containsConstant = false;
boolean stopCheckingSideEffects = false;
boolean sideEffectMayBeRemoved = false;
boolean reducedToConstant = false;
for (PsiExpression operand : operands) {
if (operand == null) {
return BooleanExpressionKind.UNKNOWN;
}
final PsiExpression[] operands = polyadicExpression.getOperands();
boolean containsConstant = false;
boolean stopCheckingSideEffects = false;
boolean sideEffectMayBeRemoved = false;
boolean reducedToConstant = false;
for (PsiExpression operand : operands) {
if (operand == null) {
return BooleanExpressionKind.UNKNOWN;
final PsiType type = operand.getType();
if (type == null || !type.equals(PsiType.BOOLEAN) && !type.equalsToText(CommonClassNames.JAVA_LANG_BOOLEAN)) {
return BooleanExpressionKind.UNKNOWN;
}
if (!stopCheckingSideEffects && SideEffectChecker.mayHaveSideEffects(operand)) {
sideEffectMayBeRemoved = true;
continue;
}
Boolean value = evaluate(operand);
if (value != null) {
containsConstant = true;
if ((JavaTokenType.ANDAND.equals(sign) && !value) || (JavaTokenType.OROR.equals(sign) && value)) {
stopCheckingSideEffects = true;
reducedToConstant = true;
}
final PsiType type = operand.getType();
if (type == null || !type.equals(PsiType.BOOLEAN) && !type.equalsToText(CommonClassNames.JAVA_LANG_BOOLEAN)) {
return BooleanExpressionKind.UNKNOWN;
}
if (!stopCheckingSideEffects && SideEffectChecker.mayHaveSideEffects(operand)) {
sideEffectMayBeRemoved = true;
continue;
}
Boolean value = evaluate(operand);
if (value != null) {
containsConstant = true;
if ((JavaTokenType.ANDAND.equals(sign) && !value) || (JavaTokenType.OROR.equals(sign) && value)) {
stopCheckingSideEffects = true;
reducedToConstant = true;
}
if ((JavaTokenType.AND.equals(sign) && !value) || (JavaTokenType.OR.equals(sign) && value)) {
reducedToConstant = true;
}
if ((JavaTokenType.AND.equals(sign) && !value) || (JavaTokenType.OR.equals(sign) && value)) {
reducedToConstant = true;
}
}
if (containsConstant) {
if (sideEffectMayBeRemoved && reducedToConstant) {
return CodeBlockSurrounder.canSurround(expression)
? BooleanExpressionKind.USELESS_WITH_SIDE_EFFECTS
: BooleanExpressionKind.UNKNOWN;
}
return BooleanExpressionKind.USELESS;
}
if (containsConstant) {
if (sideEffectMayBeRemoved && reducedToConstant) {
return CodeBlockSurrounder.canSurround(expression)
? BooleanExpressionKind.USELESS_WITH_SIDE_EFFECTS
: BooleanExpressionKind.UNKNOWN;
}
return BooleanExpressionKind.USELESS;
}
return BooleanExpressionKind.UNKNOWN;
}