mirror of
https://github.com/github/codeql.git
synced 2026-02-12 05:01:06 +01:00
118 lines
4.2 KiB
Plaintext
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 + "'."
|