mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
redo "Pointless boolean expression" inspection and remove double negation checking which is already reported by another inspection
This commit is contained in:
@@ -1327,7 +1327,7 @@ negated.if.else.ignore.negated.null.option=Ignore '!= null' comparisons
|
||||
negated.if.else.ignore.negated.zero.option=Ignore '!= 0' comparisons
|
||||
negated.if.else.invert.quickfix=Invert If Condition
|
||||
overly.complex.boolean.expression.max.terms.option=Maximum number of terms:
|
||||
pointless.boolean.expression.ignore.option=Ignore named constant in determining pointless expressions
|
||||
pointless.boolean.expression.ignore.option=Ignore named constants in determining pointless expressions
|
||||
simplifiable.conditional.expression.problem.descriptor=<code>#ref</code> can be simplified to ''{0}'' #loc
|
||||
simplifiable.if.statement.problem.descriptor=<code>#ref</code> statement can be replaced with ''{0}'' #loc
|
||||
switch.statement.density.min.option=Minimum density of branches: %
|
||||
|
||||
+311
-296
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2011 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2012 Dave Griffith, Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.siyeh.ig.controlflow;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.SimplifyBooleanExpressionFix;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -28,37 +27,37 @@ import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import com.siyeh.ig.psiutils.ComparisonUtils;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import com.siyeh.ig.psiutils.ParenthesesUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class PointlessBooleanExpressionInspection extends BaseInspection {
|
||||
|
||||
private static final Set<IElementType> booleanTokens = new HashSet<IElementType>() {{
|
||||
add(JavaTokenType.ANDAND);
|
||||
add(JavaTokenType.AND);
|
||||
add(JavaTokenType.OROR);
|
||||
add(JavaTokenType.OR);
|
||||
add(JavaTokenType.XOR);
|
||||
add(JavaTokenType.EQEQ);
|
||||
add(JavaTokenType.NE);
|
||||
}};
|
||||
private static final Set<IElementType> booleanTokens = new HashSet<IElementType>();
|
||||
static {
|
||||
booleanTokens.add(JavaTokenType.ANDAND);
|
||||
booleanTokens.add(JavaTokenType.AND);
|
||||
booleanTokens.add(JavaTokenType.OROR);
|
||||
booleanTokens.add(JavaTokenType.OR);
|
||||
booleanTokens.add(JavaTokenType.XOR);
|
||||
booleanTokens.add(JavaTokenType.EQEQ);
|
||||
booleanTokens.add(JavaTokenType.NE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @noinspection PublicField
|
||||
*/
|
||||
@SuppressWarnings("PublicField")
|
||||
public boolean m_ignoreExpressionsContainingConstants = false;
|
||||
|
||||
@Override
|
||||
public JComponent createOptionsPanel() {
|
||||
return new SingleCheckboxOptionsPanel(
|
||||
InspectionGadgetsBundle.message("pointless.boolean.expression.ignore.option"),
|
||||
this,
|
||||
"m_ignoreExpressionsContainingConstants"
|
||||
InspectionGadgetsBundle.message("pointless.boolean.expression.ignore.option"), this, "m_ignoreExpressionsContainingConstants"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -76,27 +75,198 @@ public class PointlessBooleanExpressionInspection extends BaseInspection {
|
||||
@Override
|
||||
@NotNull
|
||||
public String buildErrorString(Object... infos) {
|
||||
if (infos[0] instanceof PsiPolyadicExpression) {
|
||||
if (infos[0] instanceof PsiBinaryExpression) {
|
||||
final PsiBinaryExpression expression = (PsiBinaryExpression)infos[0];
|
||||
return InspectionGadgetsBundle.message(
|
||||
"boolean.expression.can.be.simplified.problem.descriptor",
|
||||
calculateSimplifiedBinaryExpression(expression)
|
||||
);
|
||||
final PsiExpression expression = (PsiExpression)infos[0];
|
||||
return InspectionGadgetsBundle.message("boolean.expression.can.be.simplified.problem.descriptor",
|
||||
buildSimplifiedExpression(expression, new StringBuilder()).toString());
|
||||
}
|
||||
|
||||
private StringBuilder buildSimplifiedExpression(@Nullable PsiExpression expression, StringBuilder out) {
|
||||
if (expression instanceof PsiPolyadicExpression) {
|
||||
buildSimplifiedPolyadicExpression((PsiPolyadicExpression)expression, out);
|
||||
}
|
||||
else if (expression instanceof PsiPrefixExpression) {
|
||||
buildSimplifiedPrefixExpression((PsiPrefixExpression)expression, out);
|
||||
}
|
||||
else if (expression instanceof PsiParenthesizedExpression) {
|
||||
final PsiParenthesizedExpression parenthesizedExpression = (PsiParenthesizedExpression)expression;
|
||||
final PsiExpression expression1 = parenthesizedExpression.getExpression();
|
||||
out.append('(');
|
||||
buildSimplifiedExpression(expression1, out);
|
||||
out.append(')');
|
||||
}
|
||||
else if (expression != null) {
|
||||
out.append(expression.getText());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private void buildSimplifiedPolyadicExpression(PsiPolyadicExpression expression, StringBuilder out) {
|
||||
final IElementType tokenType = expression.getOperationTokenType();
|
||||
final PsiExpression[] operands = expression.getOperands();
|
||||
final List<PsiExpression> expressions = new ArrayList();
|
||||
if (tokenType.equals(JavaTokenType.ANDAND) || tokenType.equals(JavaTokenType.AND)) {
|
||||
for (PsiExpression operand : operands) {
|
||||
if (evaluate(operand) == Boolean.TRUE) {
|
||||
continue;
|
||||
}
|
||||
else if (evaluate(operand) == Boolean.FALSE) {
|
||||
out.append(PsiKeyword.FALSE);
|
||||
return;
|
||||
}
|
||||
expressions.add(operand);
|
||||
}
|
||||
if (expressions.isEmpty()) {
|
||||
out.append(PsiKeyword.TRUE);
|
||||
return;
|
||||
}
|
||||
buildSimplifiedExpression(expressions, tokenType.equals(JavaTokenType.ANDAND) ? "&&" : "&", false, out);
|
||||
} else if (tokenType.equals(JavaTokenType.OROR) || tokenType.equals(JavaTokenType.OR)) {
|
||||
for (PsiExpression operand : operands) {
|
||||
if (evaluate(operand) == Boolean.FALSE) {
|
||||
continue;
|
||||
}
|
||||
else if (evaluate(operand) == Boolean.TRUE) {
|
||||
out.append(PsiKeyword.TRUE);
|
||||
return;
|
||||
}
|
||||
expressions.add(operand);
|
||||
}
|
||||
if (expressions.isEmpty()) {
|
||||
out.append(PsiKeyword.FALSE);
|
||||
return;
|
||||
}
|
||||
buildSimplifiedExpression(expressions, tokenType.equals(JavaTokenType.OROR) ? "||" : "|", false, out);
|
||||
}
|
||||
else if (tokenType.equals(JavaTokenType.XOR) || tokenType.equals(JavaTokenType.NE)) {
|
||||
boolean negate = false;
|
||||
for (PsiExpression operand : operands) {
|
||||
if (evaluate(operand) == Boolean.FALSE) {
|
||||
continue;
|
||||
}
|
||||
else if (evaluate(operand) == Boolean.TRUE) {
|
||||
negate = !negate;
|
||||
continue;
|
||||
}
|
||||
expressions.add(operand);
|
||||
}
|
||||
if (expressions.isEmpty()) {
|
||||
if (negate) {
|
||||
out.append(PsiKeyword.TRUE);
|
||||
}
|
||||
else {
|
||||
out.append(PsiKeyword.FALSE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
buildSimplifiedExpression(expressions, tokenType.equals(JavaTokenType.XOR) ? "^" : "!=", negate, out);
|
||||
}
|
||||
else if (tokenType.equals(JavaTokenType.EQEQ)) {
|
||||
boolean negate = false;
|
||||
for (PsiExpression operand : operands) {
|
||||
if (evaluate(operand) == Boolean.TRUE) {
|
||||
continue;
|
||||
}
|
||||
else if (evaluate(operand) == Boolean.FALSE) {
|
||||
negate = !negate;
|
||||
continue;
|
||||
}
|
||||
expressions.add(operand);
|
||||
}
|
||||
if (expressions.isEmpty()) {
|
||||
if (negate) {
|
||||
out.append(PsiKeyword.FALSE);
|
||||
}
|
||||
else {
|
||||
out.append(PsiKeyword.TRUE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
buildSimplifiedExpression(expressions, "==", negate, out);
|
||||
}
|
||||
}
|
||||
|
||||
private void buildSimplifiedExpression(List<PsiExpression> expressions, String token, boolean negate, StringBuilder out) {
|
||||
if (expressions.size() == 1) {
|
||||
final PsiExpression expression = expressions.get(0);
|
||||
if (!negate) {
|
||||
out.append(expression.getText());
|
||||
return;
|
||||
}
|
||||
if (ComparisonUtils.isComparison(expression)) {
|
||||
final PsiBinaryExpression binaryExpression = (PsiBinaryExpression)expression;
|
||||
final String negatedComparison = ComparisonUtils.getNegatedComparison(binaryExpression.getOperationTokenType());
|
||||
final PsiExpression lhs = binaryExpression.getLOperand();
|
||||
final PsiExpression rhs = binaryExpression.getROperand();
|
||||
assert rhs != null;
|
||||
out.append(lhs.getText()).append(negatedComparison).append(rhs.getText());
|
||||
}
|
||||
else {
|
||||
if (ParenthesesUtils.getPrecedence(expression) > ParenthesesUtils.PREFIX_PRECEDENCE) {
|
||||
out.append("!(").append(expression.getText()).append(')');
|
||||
}
|
||||
else {
|
||||
out.append('!').append(expression.getText());
|
||||
}
|
||||
}
|
||||
return InspectionGadgetsBundle.message("boolean.expression.can.be.simplified.polyadic.problem.descriptor");
|
||||
}
|
||||
else {
|
||||
final PsiPrefixExpression expression = (PsiPrefixExpression)infos[0];
|
||||
final PsiExpression e = removeRedundantNots(expression);
|
||||
|
||||
if (e == null) {
|
||||
return InspectionGadgetsBundle.message("boolean.expression.can.be.simplified.problem.descriptor", "");
|
||||
if (negate) {
|
||||
out.append("!(");
|
||||
}
|
||||
boolean useToken = false;
|
||||
for (PsiExpression expression : expressions) {
|
||||
if (useToken) {
|
||||
out.append(token);
|
||||
}
|
||||
else {
|
||||
useToken = true;
|
||||
}
|
||||
buildSimplifiedExpression(expression, out);
|
||||
}
|
||||
if (negate) {
|
||||
out.append(')');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return InspectionGadgetsBundle.message(
|
||||
"boolean.expression.can.be.simplified.problem.descriptor",
|
||||
e instanceof PsiPrefixExpression ? calculateSimplifiedPrefixExpression((PsiPrefixExpression)e) : e.getText());
|
||||
private void buildSimplifiedPrefixExpression(PsiPrefixExpression expression, StringBuilder out) {
|
||||
final PsiJavaToken sign = expression.getOperationSign();
|
||||
final IElementType tokenType = sign.getTokenType();
|
||||
final PsiExpression operand = expression.getOperand();
|
||||
if (JavaTokenType.EXCL.equals(tokenType)) {
|
||||
final Boolean value = evaluate(operand);
|
||||
if (value == Boolean.TRUE) {
|
||||
out.append(PsiKeyword.FALSE);
|
||||
return;
|
||||
}
|
||||
else if (value == Boolean.FALSE) {
|
||||
out.append(PsiKeyword.TRUE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
buildSimplifiedExpression(operand, out.append(sign.getText()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public InspectionGadgetsFix buildFix(Object... infos) {
|
||||
return new PointlessBooleanExpressionFix();
|
||||
}
|
||||
|
||||
private class PointlessBooleanExpressionFix extends InspectionGadgetsFix {
|
||||
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return InspectionGadgetsBundle.message("constant.conditional.expression.simplify.quickfix");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
|
||||
final PsiElement element = descriptor.getPsiElement();
|
||||
if (!(element instanceof PsiExpression)) {
|
||||
return;
|
||||
}
|
||||
final PsiExpression expression = (PsiExpression)element;
|
||||
replaceExpression(expression, buildSimplifiedExpression(expression, new StringBuilder()).toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,297 +275,142 @@ public class PointlessBooleanExpressionInspection extends BaseInspection {
|
||||
return new PointlessBooleanExpressionVisitor();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String calculateSimplifiedBinaryExpression(
|
||||
PsiBinaryExpression expression) {
|
||||
final PsiExpression lhs = expression.getLOperand();
|
||||
|
||||
final PsiExpression rhs = expression.getROperand();
|
||||
if (rhs == null) {
|
||||
return null;
|
||||
}
|
||||
final IElementType tokenType = expression.getOperationTokenType();
|
||||
final String rhsText = rhs.getText();
|
||||
final String lhsText = lhs.getText();
|
||||
if (tokenType.equals(JavaTokenType.ANDAND) ||
|
||||
tokenType.equals(JavaTokenType.AND)) {
|
||||
if (isAlwaysTrue(lhs)) {
|
||||
return rhsText;
|
||||
}
|
||||
else if (isAlwaysFalse(lhs) || isAlwaysFalse(rhs)) {
|
||||
return "false";
|
||||
}
|
||||
else {
|
||||
return lhsText;
|
||||
}
|
||||
}
|
||||
else if (tokenType.equals(JavaTokenType.OROR) ||
|
||||
tokenType.equals(JavaTokenType.OR)) {
|
||||
if (isAlwaysFalse(lhs)) {
|
||||
return rhsText;
|
||||
}
|
||||
else {
|
||||
return lhsText;
|
||||
}
|
||||
}
|
||||
else if (tokenType.equals(JavaTokenType.XOR) ||
|
||||
tokenType.equals(JavaTokenType.NE)) {
|
||||
if (isAlwaysFalse(lhs)) {
|
||||
return rhsText;
|
||||
}
|
||||
else if (isAlwaysFalse(rhs)) {
|
||||
return lhsText;
|
||||
}
|
||||
else if (isAlwaysTrue(lhs)) {
|
||||
return createStringForNegatedExpression(rhs);
|
||||
}
|
||||
else {
|
||||
return createStringForNegatedExpression(lhs);
|
||||
}
|
||||
}
|
||||
else if (tokenType.equals(JavaTokenType.EQEQ)) {
|
||||
if (isAlwaysTrue(lhs)) {
|
||||
return rhsText;
|
||||
}
|
||||
else if (isAlwaysTrue(rhs)) {
|
||||
return lhsText;
|
||||
}
|
||||
else if (isAlwaysFalse(lhs)) {
|
||||
return createStringForNegatedExpression(rhs);
|
||||
}
|
||||
else {
|
||||
return createStringForNegatedExpression(lhs);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private static String createStringForNegatedExpression(PsiExpression exp) {
|
||||
if (ComparisonUtils.isComparison(exp)) {
|
||||
final PsiBinaryExpression binaryExpression = (PsiBinaryExpression)exp;
|
||||
final String negatedComparison = ComparisonUtils.getNegatedComparison(binaryExpression.getOperationTokenType());
|
||||
final PsiExpression lhs = binaryExpression.getLOperand();
|
||||
final PsiExpression rhs = binaryExpression.getROperand();
|
||||
assert rhs != null;
|
||||
return lhs.getText() + negatedComparison + rhs.getText();
|
||||
}
|
||||
else {
|
||||
if (ParenthesesUtils.getPrecedence(exp) >
|
||||
ParenthesesUtils.PREFIX_PRECEDENCE) {
|
||||
return "!(" + exp.getText() + ')';
|
||||
}
|
||||
else {
|
||||
return '!' + exp.getText();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String calculateSimplifiedPrefixExpression(PsiPrefixExpression e) {
|
||||
final PsiExpression expression = e.getOperand();
|
||||
|
||||
final Boolean value = evaluate(expression);
|
||||
|
||||
if (value == Boolean.TRUE) {
|
||||
return PsiKeyword.FALSE;
|
||||
}
|
||||
|
||||
if (value == Boolean.FALSE) {
|
||||
return PsiKeyword.TRUE;
|
||||
}
|
||||
|
||||
return expression != null ? expression.getText() : "";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiExpression removeRedundantNots(@NotNull PsiPrefixExpression expression) {
|
||||
if (!JavaTokenType.EXCL.equals(expression.getOperationTokenType())) {
|
||||
return expression;
|
||||
}
|
||||
|
||||
final PsiExpression operand = expression.getOperand();
|
||||
if (operand == null || !(operand instanceof PsiPrefixExpression)) {
|
||||
return expression;
|
||||
}
|
||||
|
||||
final PsiPrefixExpression prefixOperand = (PsiPrefixExpression)operand;
|
||||
if (!JavaTokenType.EXCL.equals(prefixOperand.getOperationTokenType())) {
|
||||
return expression;
|
||||
}
|
||||
|
||||
final PsiExpression op = prefixOperand.getOperand();
|
||||
return op != null && op instanceof PsiPrefixExpression ? removeRedundantNots((PsiPrefixExpression)op) : op;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InspectionGadgetsFix buildFix(Object... infos) {
|
||||
return new BooleanLiteralComparisonFix();
|
||||
}
|
||||
|
||||
private class BooleanLiteralComparisonFix extends InspectionGadgetsFix {
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return InspectionGadgetsBundle.message("constant.conditional.expression.simplify.quickfix");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFix(Project project, ProblemDescriptor descriptor)
|
||||
throws IncorrectOperationException {
|
||||
final PsiElement element = descriptor.getPsiElement();
|
||||
processSubExpressions(project, (PsiExpression)element);
|
||||
}
|
||||
|
||||
private boolean processSubExpressions(Project project, PsiExpression element) {
|
||||
if (element instanceof PsiPrefixExpression) {
|
||||
return processPrefixExpression(project, (PsiPrefixExpression)element);
|
||||
}
|
||||
|
||||
if (element instanceof PsiPolyadicExpression) {
|
||||
final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)element;
|
||||
for (PsiExpression operand : polyadicExpression.getOperands()) {
|
||||
final Boolean bool = evaluate(operand);
|
||||
if (bool != null) {
|
||||
SimplifyBooleanExpressionFix.simplifyExpression(project, operand, bool);
|
||||
return true;
|
||||
}
|
||||
if (processSubExpressions(project, operand)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean processPrefixExpression(Project project, PsiPrefixExpression expression) {
|
||||
final Boolean value = evaluate(expression);
|
||||
|
||||
if (value == null && JavaTokenType.EXCL.equals(expression.getOperationTokenType())) {
|
||||
final PsiExpression fixed = removeRedundantNots(expression);
|
||||
if (fixed != null && fixed != expression) {
|
||||
expression.replace(fixed);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SimplifyBooleanExpressionFix.simplifyExpression(project, expression, value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class PointlessBooleanExpressionVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitClass(@NotNull PsiClass aClass) {
|
||||
//to avoid drilldown
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPolyadicExpression(PsiPolyadicExpression expression) {
|
||||
super.visitPolyadicExpression(expression);
|
||||
final IElementType sign = expression.getOperationTokenType();
|
||||
if (!booleanTokens.contains(sign)) {
|
||||
checkExpression(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPrefixExpression(PsiPrefixExpression expression) {
|
||||
super.visitPrefixExpression(expression);
|
||||
checkExpression(expression);
|
||||
}
|
||||
|
||||
private void checkExpression(PsiExpression expression) {
|
||||
if (!isPointlessBooleanExpression(expression)) {
|
||||
return;
|
||||
}
|
||||
final PsiExpression[] operands = expression.getOperands();
|
||||
for (PsiExpression operand : operands) {
|
||||
if (operand == null) {
|
||||
return;
|
||||
}
|
||||
final PsiType opType = operand.getType();
|
||||
if (opType == null) {
|
||||
return;
|
||||
}
|
||||
if (!opType.equals(PsiType.BOOLEAN) &&
|
||||
!opType.equalsToText(CommonClassNames.JAVA_LANG_BOOLEAN)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final boolean isPointless;
|
||||
if (sign.equals(JavaTokenType.EQEQ) || sign.equals(JavaTokenType.NE)) {
|
||||
isPointless = equalityExpressionIsPointless(operands);
|
||||
}
|
||||
else if (sign.equals(JavaTokenType.ANDAND) || sign.equals(JavaTokenType.AND)) {
|
||||
isPointless = andExpressionIsPointless(operands);
|
||||
}
|
||||
else if (sign.equals(JavaTokenType.OROR) || sign.equals(JavaTokenType.OR)) {
|
||||
isPointless = orExpressionIsPointless(operands);
|
||||
}
|
||||
else if (sign.equals(JavaTokenType.XOR)) {
|
||||
isPointless = xorExpressionIsPointless(operands);
|
||||
}
|
||||
else {
|
||||
isPointless = false;
|
||||
}
|
||||
if (!isPointless) {
|
||||
final PsiElement parent = ParenthesesUtils.getParentSkipParentheses(expression);
|
||||
if (parent instanceof PsiExpression && isPointlessBooleanExpression((PsiExpression)parent)) {
|
||||
return;
|
||||
}
|
||||
registerError(expression, expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPrefixExpression(@NotNull PsiPrefixExpression expression) {
|
||||
super.visitPrefixExpression(expression);
|
||||
final PsiExpression operand = expression.getOperand();
|
||||
final IElementType tokenType = expression.getOperationTokenType();
|
||||
if (JavaTokenType.EXCL.equals(tokenType) && notExpressionIsPointless(operand)) {
|
||||
registerError(expression, expression);
|
||||
private boolean isPointlessBooleanExpression(PsiExpression expression) {
|
||||
if (expression instanceof PsiPrefixExpression) {
|
||||
return evaluate(expression) != null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean equalityExpressionIsPointless(PsiExpression... lhs) {
|
||||
for (PsiExpression expression : lhs) {
|
||||
if (evaluate(expression) != null) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean andExpressionIsPointless(PsiExpression... lhs) {
|
||||
return equalityExpressionIsPointless(lhs);
|
||||
}
|
||||
|
||||
private boolean orExpressionIsPointless(PsiExpression... lhs) {
|
||||
for (PsiExpression expression : lhs) {
|
||||
if (isAlwaysFalse(expression)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean xorExpressionIsPointless(PsiExpression... lhs) {
|
||||
return equalityExpressionIsPointless(lhs);
|
||||
}
|
||||
|
||||
private boolean notExpressionIsPointless(PsiExpression arg) {
|
||||
if (arg instanceof PsiPrefixExpression) {
|
||||
final PsiPrefixExpression prefixExpression = (PsiPrefixExpression)arg;
|
||||
if (JavaTokenType.EXCL.equals(prefixExpression.getOperationTokenType())) {
|
||||
return true;
|
||||
else if (expression instanceof PsiPolyadicExpression) {
|
||||
final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)expression;
|
||||
final IElementType sign = polyadicExpression.getOperationTokenType();
|
||||
if (!booleanTokens.contains(sign)) {
|
||||
return false;
|
||||
}
|
||||
final PsiExpression[] operands = polyadicExpression.getOperands();
|
||||
boolean containsConstant = false;
|
||||
for (PsiExpression operand : operands) {
|
||||
if (operand == null) {
|
||||
return false;
|
||||
}
|
||||
final PsiType type = operand.getType();
|
||||
if (type == null || !type.equals(PsiType.BOOLEAN) && !type.equalsToText(CommonClassNames.JAVA_LANG_BOOLEAN)) {
|
||||
return false;
|
||||
}
|
||||
containsConstant |= (evaluate(operand) != null);
|
||||
}
|
||||
if (!containsConstant) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return equalityExpressionIsPointless(arg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Boolean evaluate(@Nullable PsiExpression expression) {
|
||||
if (m_ignoreExpressionsContainingConstants && !(expression instanceof PsiLiteralExpression)) {
|
||||
if (expression == null || m_ignoreExpressionsContainingConstants && containsReference(expression)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (expression == null) {
|
||||
return null;
|
||||
if (expression instanceof PsiParenthesizedExpression) {
|
||||
final PsiParenthesizedExpression parenthesizedExpression = (PsiParenthesizedExpression)expression;
|
||||
return evaluate(parenthesizedExpression.getExpression());
|
||||
}
|
||||
else if (expression instanceof PsiPolyadicExpression) {
|
||||
final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)expression;
|
||||
final IElementType tokenType = polyadicExpression.getOperationTokenType();
|
||||
if (tokenType.equals(JavaTokenType.OROR)) {
|
||||
final PsiExpression[] operands = polyadicExpression.getOperands();
|
||||
for (PsiExpression operand : operands) {
|
||||
if (evaluate(operand) == Boolean.TRUE) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tokenType.equals(JavaTokenType.ANDAND)) {
|
||||
final PsiExpression[] operands = polyadicExpression.getOperands();
|
||||
for (PsiExpression operand : operands) {
|
||||
if (evaluate(operand) == Boolean.FALSE) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (expression instanceof PsiPrefixExpression) {
|
||||
final PsiPrefixExpression prefixExpression = (PsiPrefixExpression)expression;
|
||||
final IElementType tokenType = prefixExpression.getOperationTokenType();
|
||||
if (JavaTokenType.EXCL.equals(tokenType)) {
|
||||
final PsiExpression operand = prefixExpression.getOperand();
|
||||
final Boolean b = evaluate(operand);
|
||||
if (b == Boolean.FALSE) {
|
||||
return Boolean.TRUE;
|
||||
} else if (b == Boolean.TRUE) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
final Boolean value = (Boolean)ConstantExpressionUtil.computeCastTo(expression, PsiType.BOOLEAN);
|
||||
return value != null ? value.booleanValue() : null;
|
||||
}
|
||||
|
||||
private boolean isAlwaysTrue(@Nullable PsiExpression expression) {
|
||||
return evaluate(expression) == Boolean.TRUE;
|
||||
private static boolean containsReference(@Nullable PsiExpression expression) {
|
||||
if (expression == null) {
|
||||
return false;
|
||||
}
|
||||
final ReferenceVisitor visitor = new ReferenceVisitor();
|
||||
expression.accept(visitor);
|
||||
return visitor.containsReference();
|
||||
}
|
||||
|
||||
private boolean isAlwaysFalse(@Nullable PsiExpression expression) {
|
||||
return evaluate(expression) == Boolean.FALSE;
|
||||
private static class ReferenceVisitor extends JavaRecursiveElementVisitor {
|
||||
|
||||
private boolean referenceFound = false;
|
||||
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
if (referenceFound) {
|
||||
return;
|
||||
}
|
||||
super.visitElement(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
final PsiElement target = expression.resolve();
|
||||
if (target instanceof PsiField && ExpressionUtils.isConstant((PsiField)target)) {
|
||||
referenceFound = true;
|
||||
}
|
||||
else {
|
||||
super.visitReferenceExpression(expression);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean containsReference() {
|
||||
return referenceFound;
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -1,13 +1,15 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection reports pointless or pointlessly
|
||||
complicated boolean expressions. Such expressions include <b>and</b>ing with true,
|
||||
<b>or</b>ing with false,
|
||||
complicated boolean expressions. Such expressions include <b>and</b>ing with <b>true</b>,
|
||||
<b>or</b>ing with <b>false</b>,
|
||||
equality comparison with a boolean literal, or negation of a boolean literal. Such expressions may be the result of automated refactorings
|
||||
not completely followed through to completion, and in any case are unlikely to be what the developer
|
||||
intended to do.
|
||||
<!-- tooltip end -->
|
||||
<p>
|
||||
Use the checkbox below to ignore named constants when determining if an expression is pointless.
|
||||
<p>
|
||||
<small>Powered by InspectionGadgets</small>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,5 +1,8 @@
|
||||
class C {
|
||||
void m() {
|
||||
final boolean isCxf = true;
|
||||
if (false) {
|
||||
//comment
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
@@ -18,4 +18,14 @@ public class Bug {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
class PointlessBooleanExpression {
|
||||
void foo(boolean a, boolean b) {
|
||||
boolean c = !(b && false);
|
||||
boolean d = a ^ b ^ true;
|
||||
boolean x = a ^ !true ^ b;
|
||||
|
||||
boolean y = false || c;
|
||||
boolean z = b != true;
|
||||
}
|
||||
}
|
||||
+36
@@ -6,4 +6,40 @@
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless boolean expression</problem_class>
|
||||
<description>'!true' can be simplified 'false'</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>PointlessBooleanExpression.java</file>
|
||||
<line>24</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless boolean expression</problem_class>
|
||||
<description><code>!(b && false)</code> can be simplified to 'true' #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>PointlessBooleanExpression.java</file>
|
||||
<line>25</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless boolean expression</problem_class>
|
||||
<description><code>a ^ b ^ true</code> can be simplified to '!(a^b)' #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>PointlessBooleanExpression.java</file>
|
||||
<line>26</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless boolean expression</problem_class>
|
||||
<description><code>a ^ !true ^ b</code> can be simplified to 'a^b' #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>PointlessBooleanExpression.java</file>
|
||||
<line>28</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless boolean expression</problem_class>
|
||||
<description><code>false || c</code> can be simplified to 'c' #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>PointlessBooleanExpression.java</file>
|
||||
<line>29</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless boolean expression</problem_class>
|
||||
<description><code>b != true</code> can be simplified to '!b' #loc</description>
|
||||
</problem>
|
||||
|
||||
</problems>
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ import com.siyeh.ig.IGInspectionTestCase;
|
||||
*/
|
||||
public class PointlessBooleanExpressionInspectionTest extends IGInspectionTestCase {
|
||||
|
||||
public void testIgnoreExpressionsContainingConstants() throws Exception {
|
||||
public void test() throws Exception {
|
||||
final PointlessBooleanExpressionInspection inspection = new PointlessBooleanExpressionInspection();
|
||||
inspection.m_ignoreExpressionsContainingConstants = true;
|
||||
doTest("com/siyeh/igtest/controlflow/pointless_boolean_expression_ignore_cont_const", inspection);
|
||||
|
||||
Reference in New Issue
Block a user