Skip to content

Commit 04613cd

Browse files
committed
Add a library for determining constant expressions
The `getValue()` provided in the database applies the conversions, which can be unhelpful when trying to write rules the refer to conversions.
1 parent a65c4cc commit 04613cd

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import cpp
2+
3+
final private class FinalExpr = Expr;
4+
5+
/**
6+
* An integer constant expression as defined by the C++17 standard.
7+
*/
8+
class IntegerConstantExpr extends FinalExpr {
9+
IntegerConstantExpr() {
10+
// An integer constant expression is a constant expression that has an
11+
// integral type.
12+
this.isConstant() and
13+
exists(Type unspecifiedType | unspecifiedType = this.getUnspecifiedType() |
14+
unspecifiedType instanceof IntegralType
15+
or
16+
// Unscoped enum type
17+
unspecifiedType instanceof Enum and
18+
not unspecifiedType instanceof ScopedEnum
19+
)
20+
}
21+
22+
/**
23+
* Gets the value of this integer constant expression.
24+
*
25+
* This is only defined for expressions that are constant expressions, and
26+
* that have a value that can be represented as a `BigInt`.
27+
*/
28+
QlBuiltins::BigInt getConstantValue() {
29+
if exists(getPreConversionConstantValue())
30+
then result = getPreConversionConstantValue()
31+
else result = this.getValue().toBigInt()
32+
}
33+
34+
/**
35+
* Gets the pre-conversion constant value of this integer constant expression, if it is different
36+
* from `getValue()`.
37+
*
38+
* This is required because `Expr.getValue()` returns the _converted constant expression value_
39+
* for non-literal constant expressions, which is the expression value after conversions have been
40+
* applied, but for validating conversions we need the _pre-conversion constant expression value_.
41+
*/
42+
private QlBuiltins::BigInt getPreConversionConstantValue() {
43+
// Access of a variable that has a constant initializer
44+
result =
45+
this.(VariableAccess)
46+
.getTarget()
47+
.getInitializer()
48+
.getExpr()
49+
.getFullyConverted()
50+
.getValue()
51+
.toBigInt()
52+
or
53+
result = this.(EnumConstantAccess).getTarget().getValue().toBigInt()
54+
or
55+
result = -this.(UnaryMinusExpr).getOperand().getFullyConverted().getValue().toBigInt()
56+
or
57+
result = this.(UnaryPlusExpr).getOperand().getFullyConverted().getValue().toBigInt()
58+
or
59+
result = this.(NotExpr).getOperand().getFullyConverted().getValue().toBigInt().bitNot()
60+
or
61+
exists(BinaryOperation op, QlBuiltins::BigInt left, QlBuiltins::BigInt right |
62+
op = this and
63+
left = op.getLeftOperand().getFullyConverted().getValue().toBigInt() and
64+
right = op.getRightOperand().getFullyConverted().getValue().toBigInt()
65+
|
66+
op instanceof AddExpr and
67+
result = left + right
68+
or
69+
op instanceof SubExpr and
70+
result = left - right
71+
or
72+
op instanceof MulExpr and
73+
result = left * right
74+
or
75+
op instanceof DivExpr and
76+
result = left / right
77+
or
78+
op instanceof RemExpr and
79+
result = left % right
80+
or
81+
op instanceof BitwiseAndExpr and
82+
result = left.bitAnd(right)
83+
or
84+
op instanceof BitwiseOrExpr and
85+
result = left.bitOr(right)
86+
or
87+
op instanceof BitwiseXorExpr and
88+
result = left.bitXor(right)
89+
or
90+
op instanceof RShiftExpr and
91+
result = left.bitShiftRightSigned(right.toInt())
92+
or
93+
op instanceof LShiftExpr and
94+
result = left.bitShiftLeft(right.toInt())
95+
)
96+
}
97+
}

0 commit comments

Comments
 (0)