Files
codeql/csharp/ql/src/Language Abuse/SimplifyBoolExpr.ql
2019-01-02 12:59:07 +01:00

118 lines
4.2 KiB
Plaintext

/**
* @name Unnecessarily complex Boolean expression
* @description Boolean expressions that are unnecessarily complicated hinder readability.
* @id cs/simplifiable-boolean-expression
* @kind problem
* @problem.severity recommendation
* @precision high
* @tags readability
* maintainability
*/
import csharp
/**
* Holds if expression `expr` has Boolean `value` at child `child`.
* No other child nodes are boolean literals.
*/
predicate literalChild(Expr expr, int child, boolean value) {
value = expr.getChild(child).(BoolLiteral).getBoolValue() and
forall(int c | c != child | not expr.getChild(c) instanceof BoolLiteral)
}
/**
* Expression `expr` has Boolean `value1` at child `child1`, and boolean `value2` at `child2`.
* No other child nodes are boolean literals.
*/
predicate literalChildren(Expr expr, int child1, boolean value1, int child2, boolean value2) {
value1 = expr.getChild(child1).(BoolLiteral).getBoolValue() and
value2 = expr.getChild(child2).(BoolLiteral).getBoolValue() and
forall(int c | c != child1 and c != child2 | not expr.getChild(c) instanceof BoolLiteral)
}
predicate rewriteBinaryExpr(BinaryOperation op, boolean value, string oldPattern) {
literalChild(op, 0, value) and oldPattern = value + " " + op.getOperator() + " A"
or
literalChild(op, 1, value) and oldPattern = "A " + op.getOperator() + " " + value
}
bindingset[withFalseOperand, withTrueOperand]
predicate rewriteBinaryExpr(
BinaryOperation op, string oldPattern, string withFalseOperand, string withTrueOperand,
string newPattern
) {
rewriteBinaryExpr(op, false, oldPattern) and newPattern = withFalseOperand
or
rewriteBinaryExpr(op, true, oldPattern) and newPattern = withTrueOperand
}
predicate rewriteConditionalExpr(ConditionalExpr cond, string oldPattern, string newPattern) {
literalChild(cond, 1, false) and oldPattern = "A ? false : B" and newPattern = "!A && B"
or
literalChild(cond, 1, true) and oldPattern = "A ? true : B" and newPattern = "A || B"
or
literalChild(cond, 2, false) and oldPattern = "A ? B : false" and newPattern = "A && B"
or
literalChild(cond, 2, true) and oldPattern = "A ? B : true" and newPattern = "!A || B"
or
exists(boolean b | literalChildren(cond, 1, b, 2, b) |
oldPattern = "A ? " + b + " : " + b and newPattern = b.toString()
)
or
literalChildren(cond, 1, true, 2, false) and oldPattern = "A ? true : false" and newPattern = "A"
or
literalChildren(cond, 1, false, 2, true) and oldPattern = "A ? false : true" and newPattern = "!A"
}
predicate negatedOperators(string op, string negated) {
op = "==" and negated = "!="
or
op = "<" and negated = ">="
or
op = ">" and negated = "<="
or
negatedOperators(negated, op)
}
predicate simplifyBinaryExpr(string op, string withFalseOperand, string withTrueOperand) {
op = "==" and withTrueOperand = "A" and withFalseOperand = "!A"
or
op = "!=" and withTrueOperand = "!A" and withFalseOperand = "A"
or
op = "&&" and withTrueOperand = "A" and withFalseOperand = "false"
or
op = "||" and withTrueOperand = "true" and withFalseOperand = "A"
}
predicate pushNegation(LogicalNotExpr expr, string oldPattern, string newPattern) {
expr.getOperand() instanceof LogicalNotExpr and oldPattern = "!!A" and newPattern = "A"
or
exists(string oldOperator, string newOperator |
oldOperator = expr.getOperand().(BinaryOperation).getOperator() and
negatedOperators(oldOperator, newOperator)
|
oldPattern = "!(A " + oldOperator + " B)" and
newPattern = "A " + newOperator + " B"
)
}
predicate rewrite(Expr expr, string oldPattern, string newPattern) {
exists(string withFalseOperand, string withTrueOperand |
simplifyBinaryExpr(expr.(BinaryOperation).getOperator(), withFalseOperand, withTrueOperand)
|
rewriteBinaryExpr(expr, oldPattern, withFalseOperand, withTrueOperand, newPattern)
)
or
rewriteConditionalExpr(expr, oldPattern, newPattern)
or
pushNegation(expr, oldPattern, newPattern)
}
from Expr expr, string oldPattern, string newPattern, string action
where
rewrite(expr, oldPattern, newPattern) and
if newPattern = "true" or newPattern = "false"
then action = "is always"
else action = "can be simplified to"
select expr, "The expression '" + oldPattern + "' " + action + " '" + newPattern + "'."