Skip to content

Commit e8dbd65

Browse files
committed
Java: Refactor compile-time constant calculation and apply to ConstantIntegerExpr.
1 parent 77283be commit e8dbd65

File tree

3 files changed

+206
-140
lines changed

3 files changed

+206
-140
lines changed
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/**
2+
* Provdides a module to calculate constant integer and boolean values.
3+
*/
4+
5+
import java
6+
7+
signature boolean getBoolValSig(Expr e);
8+
9+
signature int getIntValSig(Expr e);
10+
11+
/**
12+
* Given predicates defining boolean and integer constants, this module
13+
* calculates additional boolean and integer constants using only the rules that
14+
* apply to compile-time constants.
15+
*
16+
* The input and output predicates are expected to be mutually recursive.
17+
*/
18+
module CalculateConstants<getBoolValSig/1 getBoolVal, getIntValSig/1 getIntVal> {
19+
/** Gets the value of a constant boolean expression. */
20+
boolean calculateBooleanValue(Expr e) {
21+
// No casts relevant to booleans.
22+
// `!` is the only unary operator that evaluates to a boolean.
23+
result = getBoolVal(e.(LogNotExpr).getExpr()).booleanNot()
24+
or
25+
// Handle binary expressions that have integer operands and a boolean result.
26+
exists(BinaryExpr b, int left, int right |
27+
b = e and
28+
left = getIntVal(b.getLeftOperand()) and
29+
right = getIntVal(b.getRightOperand())
30+
|
31+
(
32+
b instanceof LTExpr and
33+
if left < right then result = true else result = false
34+
)
35+
or
36+
(
37+
b instanceof LEExpr and
38+
if left <= right then result = true else result = false
39+
)
40+
or
41+
(
42+
b instanceof GTExpr and
43+
if left > right then result = true else result = false
44+
)
45+
or
46+
(
47+
b instanceof GEExpr and
48+
if left >= right then result = true else result = false
49+
)
50+
or
51+
(
52+
b instanceof ValueOrReferenceEqualsExpr and
53+
if left = right then result = true else result = false
54+
)
55+
or
56+
(
57+
b instanceof ValueOrReferenceNotEqualsExpr and
58+
if left != right then result = true else result = false
59+
)
60+
)
61+
or
62+
// Handle binary expressions that have boolean operands and a boolean result.
63+
exists(BinaryExpr b, boolean left, boolean right |
64+
b = e and
65+
left = getBoolVal(b.getLeftOperand()) and
66+
right = getBoolVal(b.getRightOperand())
67+
|
68+
(
69+
b instanceof ValueOrReferenceEqualsExpr and
70+
if left = right then result = true else result = false
71+
)
72+
or
73+
(
74+
b instanceof ValueOrReferenceNotEqualsExpr and
75+
if left != right then result = true else result = false
76+
)
77+
or
78+
(b instanceof AndBitwiseExpr or b instanceof AndLogicalExpr) and
79+
result = left.booleanAnd(right)
80+
or
81+
(b instanceof OrBitwiseExpr or b instanceof OrLogicalExpr) and
82+
result = left.booleanOr(right)
83+
or
84+
b instanceof XorBitwiseExpr and result = left.booleanXor(right)
85+
)
86+
or
87+
// Ternary expressions, where the `true` and `false` expressions are boolean constants.
88+
exists(ConditionalExpr ce, boolean condition |
89+
ce = e and
90+
condition = getBoolVal(ce.getCondition()) and
91+
result = getBoolVal(ce.getBranchExpr(condition))
92+
)
93+
or
94+
// If a `Variable` is final, its value is its initializer, if it exists.
95+
exists(Variable v | e = v.getAnAccess() and v.isFinal() |
96+
result = getBoolVal(v.getInitializer())
97+
)
98+
}
99+
100+
/** Gets the value of a constant integer expression. */
101+
int calculateIntValue(Expr e) {
102+
exists(IntegralType t | e.getType() = t | t.getName().toLowerCase() != "long") and
103+
(
104+
exists(CastingExpr cast, int val | cast = e and val = getIntVal(cast.getExpr()) |
105+
if cast.getType().hasName("byte")
106+
then result = (val + 128).bitAnd(255) - 128
107+
else
108+
if cast.getType().hasName("short")
109+
then result = (val + 32768).bitAnd(65535) - 32768
110+
else
111+
if cast.getType().hasName("char")
112+
then result = val.bitAnd(65535)
113+
else result = val
114+
)
115+
or
116+
result = getIntVal(e.(PlusExpr).getExpr())
117+
or
118+
result = -getIntVal(e.(MinusExpr).getExpr())
119+
or
120+
result = getIntVal(e.(BitNotExpr).getExpr()).bitNot()
121+
or
122+
// No `int` value for `LogNotExpr`.
123+
exists(BinaryExpr b, int v1, int v2 |
124+
b = e and
125+
v1 = getIntVal(b.getLeftOperand()) and
126+
v2 = getIntVal(b.getRightOperand())
127+
|
128+
b instanceof MulExpr and result = v1 * v2
129+
or
130+
b instanceof DivExpr and result = v1 / v2
131+
or
132+
b instanceof RemExpr and result = v1 % v2
133+
or
134+
b instanceof AddExpr and result = v1 + v2
135+
or
136+
b instanceof SubExpr and result = v1 - v2
137+
or
138+
b instanceof LeftShiftExpr and result = v1.bitShiftLeft(v2)
139+
or
140+
b instanceof RightShiftExpr and result = v1.bitShiftRightSigned(v2)
141+
or
142+
b instanceof UnsignedRightShiftExpr and result = v1.bitShiftRight(v2)
143+
or
144+
b instanceof AndBitwiseExpr and result = v1.bitAnd(v2)
145+
or
146+
b instanceof OrBitwiseExpr and result = v1.bitOr(v2)
147+
or
148+
b instanceof XorBitwiseExpr and result = v1.bitXor(v2)
149+
// No `int` value for `AndLogicalExpr` or `OrLogicalExpr`.
150+
// No `int` value for `LTExpr`, `GTExpr`, `LEExpr`, `GEExpr`, `ValueOrReferenceEqualsExpr` or `ValueOrReferenceNotEqualsExpr`.
151+
)
152+
or
153+
// Ternary conditional, with constant condition.
154+
exists(ConditionalExpr ce, boolean condition |
155+
ce = e and
156+
condition = getBoolVal(ce.getCondition()) and
157+
result = getIntVal(ce.getBranchExpr(condition))
158+
)
159+
or
160+
// If a `Variable` is final, its value is its initializer, if it exists.
161+
exists(Variable v | e = v.getAnAccess() and v.isFinal() |
162+
result = getIntVal(v.getInitializer())
163+
)
164+
)
165+
}
166+
}

java/ql/lib/semmle/code/java/Expr.qll

Lines changed: 10 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import java
66
private import semmle.code.java.frameworks.android.Compose
7+
private import semmle.code.java.Constants
78

89
/** A common super-class that represents all kinds of expressions. */
910
class Expr extends ExprParent, @expr {
@@ -208,71 +209,7 @@ class CompileTimeConstantExpr extends Expr {
208209
// Literal value.
209210
result = this.(BooleanLiteral).getBooleanValue()
210211
or
211-
// No casts relevant to booleans.
212-
// `!` is the only unary operator that evaluates to a boolean.
213-
result = this.(LogNotExpr).getExpr().(CompileTimeConstantExpr).getBooleanValue().booleanNot()
214-
or
215-
// Handle binary expressions that have integer operands and a boolean result.
216-
exists(BinaryExpr b, int left, int right |
217-
b = this and
218-
left = b.getLeftOperand().(CompileTimeConstantExpr).getIntValue() and
219-
right = b.getRightOperand().(CompileTimeConstantExpr).getIntValue()
220-
|
221-
(
222-
b instanceof LTExpr and
223-
if left < right then result = true else result = false
224-
)
225-
or
226-
(
227-
b instanceof LEExpr and
228-
if left <= right then result = true else result = false
229-
)
230-
or
231-
(
232-
b instanceof GTExpr and
233-
if left > right then result = true else result = false
234-
)
235-
or
236-
(
237-
b instanceof GEExpr and
238-
if left >= right then result = true else result = false
239-
)
240-
or
241-
(
242-
b instanceof ValueOrReferenceEqualsExpr and
243-
if left = right then result = true else result = false
244-
)
245-
or
246-
(
247-
b instanceof ValueOrReferenceNotEqualsExpr and
248-
if left != right then result = true else result = false
249-
)
250-
)
251-
or
252-
// Handle binary expressions that have boolean operands and a boolean result.
253-
exists(BinaryExpr b, boolean left, boolean right |
254-
b = this and
255-
left = b.getLeftOperand().(CompileTimeConstantExpr).getBooleanValue() and
256-
right = b.getRightOperand().(CompileTimeConstantExpr).getBooleanValue()
257-
|
258-
(
259-
b instanceof ValueOrReferenceEqualsExpr and
260-
if left = right then result = true else result = false
261-
)
262-
or
263-
(
264-
b instanceof ValueOrReferenceNotEqualsExpr and
265-
if left != right then result = true else result = false
266-
)
267-
or
268-
(b instanceof AndBitwiseExpr or b instanceof AndLogicalExpr) and
269-
result = left.booleanAnd(right)
270-
or
271-
(b instanceof OrBitwiseExpr or b instanceof OrLogicalExpr) and
272-
result = left.booleanOr(right)
273-
or
274-
b instanceof XorBitwiseExpr and result = left.booleanXor(right)
275-
)
212+
result = CalcCompileTimeConstants::calculateBooleanValue(this)
276213
or
277214
// Handle binary expressions that have `String` operands and a boolean result.
278215
exists(BinaryExpr b, string left, string right |
@@ -300,18 +237,6 @@ class CompileTimeConstantExpr extends Expr {
300237
)
301238
or
302239
// Note: no `getFloatValue()`, so we cannot support binary expressions with float or double operands.
303-
// Ternary expressions, where the `true` and `false` expressions are boolean compile-time constants.
304-
exists(ConditionalExpr ce, boolean condition |
305-
ce = this and
306-
condition = ce.getCondition().(CompileTimeConstantExpr).getBooleanValue() and
307-
result = ce.getBranchExpr(condition).(CompileTimeConstantExpr).getBooleanValue()
308-
)
309-
or
310-
// Simple or qualified names where the variable is final and the initializer is a constant.
311-
exists(Variable v | this = v.getAnAccess() |
312-
result = v.getInitializer().(CompileTimeConstantExpr).getBooleanValue()
313-
)
314-
or
315240
result = this.(LiveLiteral).getValue().getBooleanValue()
316241
}
317242

@@ -329,75 +254,20 @@ class CompileTimeConstantExpr extends Expr {
329254
result = this.(IntegerLiteral).getIntValue()
330255
or
331256
result = this.(CharacterLiteral).getCodePointValue()
332-
or
333-
exists(CastingExpr cast, int val |
334-
cast = this and val = cast.getExpr().(CompileTimeConstantExpr).getIntValue()
335-
|
336-
if cast.getType().hasName("byte")
337-
then result = (val + 128).bitAnd(255) - 128
338-
else
339-
if cast.getType().hasName("short")
340-
then result = (val + 32768).bitAnd(65535) - 32768
341-
else
342-
if cast.getType().hasName("char")
343-
then result = val.bitAnd(65535)
344-
else result = val
345-
)
346-
or
347-
result = this.(PlusExpr).getExpr().(CompileTimeConstantExpr).getIntValue()
348-
or
349-
result = -this.(MinusExpr).getExpr().(CompileTimeConstantExpr).getIntValue()
350-
or
351-
result = this.(BitNotExpr).getExpr().(CompileTimeConstantExpr).getIntValue().bitNot()
352-
or
353-
// No `int` value for `LogNotExpr`.
354-
exists(BinaryExpr b, int v1, int v2 |
355-
b = this and
356-
v1 = b.getLeftOperand().(CompileTimeConstantExpr).getIntValue() and
357-
v2 = b.getRightOperand().(CompileTimeConstantExpr).getIntValue()
358-
|
359-
b instanceof MulExpr and result = v1 * v2
360-
or
361-
b instanceof DivExpr and result = v1 / v2
362-
or
363-
b instanceof RemExpr and result = v1 % v2
364-
or
365-
b instanceof AddExpr and result = v1 + v2
366-
or
367-
b instanceof SubExpr and result = v1 - v2
368-
or
369-
b instanceof LeftShiftExpr and result = v1.bitShiftLeft(v2)
370-
or
371-
b instanceof RightShiftExpr and result = v1.bitShiftRightSigned(v2)
372-
or
373-
b instanceof UnsignedRightShiftExpr and result = v1.bitShiftRight(v2)
374-
or
375-
b instanceof AndBitwiseExpr and result = v1.bitAnd(v2)
376-
or
377-
b instanceof OrBitwiseExpr and result = v1.bitOr(v2)
378-
or
379-
b instanceof XorBitwiseExpr and result = v1.bitXor(v2)
380-
// No `int` value for `AndLogicalExpr` or `OrLogicalExpr`.
381-
// No `int` value for `LTExpr`, `GTExpr`, `LEExpr`, `GEExpr`, `ValueOrReferenceEqualsExpr` or `ValueOrReferenceNotEqualsExpr`.
382-
)
383-
or
384-
// Ternary conditional, with compile-time constant condition.
385-
exists(ConditionalExpr ce, boolean condition |
386-
ce = this and
387-
condition = ce.getCondition().(CompileTimeConstantExpr).getBooleanValue() and
388-
result = ce.getBranchExpr(condition).(CompileTimeConstantExpr).getIntValue()
389-
)
390-
or
391-
// If a `Variable` is a `CompileTimeConstantExpr`, its value is its initializer.
392-
exists(Variable v | this = v.getAnAccess() |
393-
result = v.getInitializer().(CompileTimeConstantExpr).getIntValue()
394-
)
395257
)
396258
or
259+
result = CalcCompileTimeConstants::calculateIntValue(this)
260+
or
397261
result = this.(LiveLiteral).getValue().getIntValue()
398262
}
399263
}
400264

265+
private boolean getBoolValue(Expr e) { result = e.(CompileTimeConstantExpr).getBooleanValue() }
266+
267+
private int getIntValue(Expr e) { result = e.(CompileTimeConstantExpr).getIntValue() }
268+
269+
private module CalcCompileTimeConstants = CalculateConstants<getBoolValue/1, getIntValue/1>;
270+
401271
/** An expression parent is an element that may have an expression as its child. */
402272
class ExprParent extends @exprparent, Top { }
403273

0 commit comments

Comments
 (0)