Skip to content

Commit f006cd0

Browse files
authored
Merge pull request #8360 from JLLeitschuh/feat/JLL/compile_time_constant_getStringified
[Java] Add CompileTimeConstantExpr.getStringified method
2 parents df9533f + c99bad4 commit f006cd0

14 files changed

+343
-12
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Add new predicate `CompileTimeConstantExpr.getStringifiedValue` which attempts to compute the
5+
`String.valueOf` string rendering of a constant expression. This predicate is now used to
6+
compute the string value of an `AddExpr` that has the type `String`.

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

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,18 +161,50 @@ class CompileTimeConstantExpr extends Expr {
161161
)
162162
}
163163

164+
/**
165+
* Gets the stringified value of this expression, where possible.
166+
*
167+
* The stringified version of a compile-time constant expression is the equivalent to
168+
* the result of calling `String.valueOf(expr)` on the expression.
169+
*
170+
* Note that this does not handle the following cases:
171+
*
172+
* - mathematical computations of type `long`, `float`, or `double`.
173+
*/
174+
pragma[nomagic]
175+
string getStringifiedValue() {
176+
result = this.getStringValue()
177+
or
178+
result = this.(Literal).getValue()
179+
or
180+
result = this.getBooleanValue().toString()
181+
or
182+
result = this.getIntValue().toString()
183+
or
184+
// Ternary conditional, with compile-time constant condition.
185+
exists(ConditionalExpr ce, boolean condition |
186+
ce = this and
187+
condition = ce.getCondition().(CompileTimeConstantExpr).getBooleanValue() and
188+
result = ce.getBranchExpr(condition).(CompileTimeConstantExpr).getStringifiedValue()
189+
)
190+
or
191+
exists(Variable v | this = v.getAnAccess() |
192+
result = v.getInitializer().(CompileTimeConstantExpr).getStringifiedValue()
193+
)
194+
}
195+
164196
/**
165197
* Gets the string value of this expression, where possible.
166198
*/
167199
pragma[nomagic]
168200
string getStringValue() {
169201
result = this.(StringLiteral).getValue()
170202
or
171-
result = this.(CharacterLiteral).getValue()
172-
or
203+
this.getType() instanceof TypeString and // When the expression type is `String`
173204
result =
174-
this.(AddExpr).getLeftOperand().(CompileTimeConstantExpr).getStringValue() +
175-
this.(AddExpr).getRightOperand().(CompileTimeConstantExpr).getStringValue()
205+
// Then the resultant string is the addition of both operands stringified value, regardless of type.
206+
this.(AddExpr).getLeftOperand().(CompileTimeConstantExpr).getStringifiedValue() +
207+
this.(AddExpr).getRightOperand().(CompileTimeConstantExpr).getStringifiedValue()
176208
or
177209
// Ternary conditional, with compile-time constant condition.
178210
exists(ConditionalExpr ce, boolean condition |

java/ql/test/library-tests/constants/CompileTimeConstantExpr.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import semmle.code.java.Expr
1+
import java
22

33
from CompileTimeConstantExpr constant, RefType tpe
44
where

java/ql/test/library-tests/constants/PrintAst.expected

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,151 @@ constants/Initializers.java:
133133
# 37| 0: [AssignExpr] ...=...
134134
# 37| 0: [VarAccess] f
135135
# 37| 1: [IntegerLiteral] 42
136+
constants/Stringified.java:
137+
# 0| [CompilationUnit] Stringified
138+
# 3| 1: [Class] Stringified
139+
# 4| 2: [Method] stringified
140+
# 4| 3: [TypeAccess] void
141+
#-----| 4: (Parameters)
142+
# 4| 0: [Parameter] notConstant
143+
# 4| 0: [TypeAccess] String
144+
# 4| 5: [BlockStmt] { ... }
145+
# 5| 0: [LocalVariableDeclStmt] var ...;
146+
# 5| 0: [TypeAccess] String
147+
# 5| 1: [LocalVariableDeclExpr] withNotConstant
148+
# 5| 0: [AddExpr] ... + ...
149+
# 5| 0: [StringLiteral] "a"
150+
# 5| 1: [VarAccess] notConstant
151+
# 6| 1: [LocalVariableDeclStmt] var ...;
152+
# 6| 0: [TypeAccess] String
153+
# 6| 1: [LocalVariableDeclExpr] string
154+
# 6| 0: [StringLiteral] "a" + "b"
155+
# 7| 2: [LocalVariableDeclStmt] var ...;
156+
# 7| 0: [TypeAccess] String
157+
# 7| 1: [LocalVariableDeclExpr] stringWithChar
158+
# 7| 0: [AddExpr] ... + ...
159+
# 7| 0: [StringLiteral] "ab"
160+
# 7| 1: [CharacterLiteral] 'c'
161+
# 8| 3: [LocalVariableDeclStmt] var ...;
162+
# 8| 0: [TypeAccess] String
163+
# 8| 1: [LocalVariableDeclExpr] stringWithBool
164+
# 8| 0: [AddExpr] ... + ...
165+
# 8| 0: [StringLiteral] "ab"
166+
# 8| 1: [BooleanLiteral] true
167+
# 9| 4: [LocalVariableDeclStmt] var ...;
168+
# 9| 0: [TypeAccess] String
169+
# 9| 1: [LocalVariableDeclExpr] stringWithInt
170+
# 9| 0: [AddExpr] ... + ...
171+
# 9| 0: [StringLiteral] "ab"
172+
# 9| 1: [IntegerLiteral] 42
173+
# 10| 5: [LocalVariableDeclStmt] var ...;
174+
# 10| 0: [TypeAccess] String
175+
# 10| 1: [LocalVariableDeclExpr] stringWithDouble
176+
# 10| 0: [AddExpr] ... + ...
177+
# 10| 0: [StringLiteral] "ab"
178+
# 10| 1: [DoubleLiteral] 43.0
179+
# 11| 6: [LocalVariableDeclStmt] var ...;
180+
# 11| 0: [TypeAccess] String
181+
# 11| 1: [LocalVariableDeclExpr] stringWithFloat
182+
# 11| 0: [AddExpr] ... + ...
183+
# 11| 0: [StringLiteral] "ab"
184+
# 11| 1: [FloatingPointLiteral] 44.0f
185+
# 12| 7: [LocalVariableDeclStmt] var ...;
186+
# 12| 0: [TypeAccess] String
187+
# 12| 1: [LocalVariableDeclExpr] stringWithLong
188+
# 12| 0: [AddExpr] ... + ...
189+
# 12| 0: [StringLiteral] "ab"
190+
# 12| 1: [LongLiteral] 45L
191+
# 13| 8: [LocalVariableDeclStmt] var ...;
192+
# 13| 0: [TypeAccess] String
193+
# 13| 1: [LocalVariableDeclExpr] stringWithShort
194+
# 13| 0: [AddExpr] ... + ...
195+
# 13| 0: [StringLiteral] "ab"
196+
# 13| 1: [CastExpr] (...)...
197+
# 13| 0: [TypeAccess] short
198+
# 13| 1: [IntegerLiteral] 46
199+
# 14| 9: [LocalVariableDeclStmt] var ...;
200+
# 14| 0: [TypeAccess] String
201+
# 14| 1: [LocalVariableDeclExpr] stringWithByte
202+
# 14| 0: [AddExpr] ... + ...
203+
# 14| 0: [StringLiteral] "ab"
204+
# 14| 1: [CastExpr] (...)...
205+
# 14| 0: [TypeAccess] byte
206+
# 14| 1: [IntegerLiteral] 47
207+
# 15| 10: [LocalVariableDeclStmt] var ...;
208+
# 15| 0: [TypeAccess] String
209+
# 15| 1: [LocalVariableDeclExpr] charWithString
210+
# 15| 0: [AddExpr] ... + ...
211+
# 15| 0: [CharacterLiteral] 'a'
212+
# 15| 1: [StringLiteral] "bc"
213+
# 16| 11: [LocalVariableDeclStmt] var ...;
214+
# 16| 0: [TypeAccess] String
215+
# 16| 1: [LocalVariableDeclExpr] boolWithString
216+
# 16| 0: [AddExpr] ... + ...
217+
# 16| 0: [BooleanLiteral] true
218+
# 16| 1: [StringLiteral] "bc"
219+
# 17| 12: [LocalVariableDeclStmt] var ...;
220+
# 17| 0: [TypeAccess] String
221+
# 17| 1: [LocalVariableDeclExpr] intWithString
222+
# 17| 0: [AddExpr] ... + ...
223+
# 17| 0: [IntegerLiteral] 42
224+
# 17| 1: [StringLiteral] "bc"
225+
# 18| 13: [LocalVariableDeclStmt] var ...;
226+
# 18| 0: [TypeAccess] String
227+
# 18| 1: [LocalVariableDeclExpr] doubleWithString
228+
# 18| 0: [AddExpr] ... + ...
229+
# 18| 0: [DoubleLiteral] 43.0
230+
# 18| 1: [StringLiteral] "bc"
231+
# 19| 14: [LocalVariableDeclStmt] var ...;
232+
# 19| 0: [TypeAccess] String
233+
# 19| 1: [LocalVariableDeclExpr] floatWithString
234+
# 19| 0: [AddExpr] ... + ...
235+
# 19| 0: [FloatingPointLiteral] 44.0f
236+
# 19| 1: [StringLiteral] "bc"
237+
# 20| 15: [LocalVariableDeclStmt] var ...;
238+
# 20| 0: [TypeAccess] String
239+
# 20| 1: [LocalVariableDeclExpr] longWithString
240+
# 20| 0: [AddExpr] ... + ...
241+
# 20| 0: [LongLiteral] 45L
242+
# 20| 1: [StringLiteral] "bc"
243+
# 21| 16: [LocalVariableDeclStmt] var ...;
244+
# 21| 0: [TypeAccess] String
245+
# 21| 1: [LocalVariableDeclExpr] shortWithString
246+
# 21| 0: [AddExpr] ... + ...
247+
# 21| 0: [CastExpr] (...)...
248+
# 21| 0: [TypeAccess] short
249+
# 21| 1: [IntegerLiteral] 46
250+
# 21| 1: [StringLiteral] "bc"
251+
# 22| 17: [LocalVariableDeclStmt] var ...;
252+
# 22| 0: [TypeAccess] String
253+
# 22| 1: [LocalVariableDeclExpr] byteWithString
254+
# 22| 0: [AddExpr] ... + ...
255+
# 22| 0: [CastExpr] (...)...
256+
# 22| 0: [TypeAccess] byte
257+
# 22| 1: [IntegerLiteral] 47
258+
# 22| 1: [StringLiteral] "bc"
259+
# 24| 18: [LocalVariableDeclStmt] var ...;
260+
# 24| 0: [TypeAccess] String
261+
# 24| 1: [LocalVariableDeclExpr] stringWithExponent
262+
# 24| 0: [AddExpr] ... + ...
263+
# 24| 0: [StringLiteral] "a"
264+
# 24| 1: [DoubleLiteral] 10e1
265+
# 25| 19: [LocalVariableDeclStmt] var ...;
266+
# 25| 0: [TypeAccess] String
267+
# 25| 1: [LocalVariableDeclExpr] stringWithBooleanOr
268+
# 25| 0: [AddExpr] ... + ...
269+
# 25| 0: [StringLiteral] "a"
270+
# 25| 1: [OrLogicalExpr] ... || ...
271+
# 25| 0: [BooleanLiteral] true
272+
# 25| 1: [BooleanLiteral] false
273+
# 26| 20: [LocalVariableDeclStmt] var ...;
274+
# 26| 0: [TypeAccess] String
275+
# 26| 1: [LocalVariableDeclExpr] stringWithIntDivide
276+
# 26| 0: [AddExpr] ... + ...
277+
# 26| 0: [StringLiteral] "a"
278+
# 26| 1: [DivExpr] ... / ...
279+
# 26| 0: [IntegerLiteral] 168
280+
# 26| 1: [IntegerLiteral] 4
136281
constants/Values.java:
137282
# 0| [CompilationUnit] Values
138283
# 4| 1: [Class] Values
@@ -526,3 +671,9 @@ constants/Values.java:
526671
# 92| 0: [AddExpr] ... + ...
527672
# 92| 0: [StringLiteral] "ab"
528673
# 92| 1: [CharacterLiteral] 'c'
674+
# 94| 70: [LocalVariableDeclStmt] var ...;
675+
# 94| 0: [TypeAccess] int
676+
# 94| 1: [LocalVariableDeclExpr] charWithChar
677+
# 94| 0: [AddExpr] ... + ...
678+
# 94| 0: [CharacterLiteral] 'a'
679+
# 94| 1: [CharacterLiteral] 'b'
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package constants;
2+
3+
public class Stringified {
4+
void stringified(final String notConstant) {
5+
String withNotConstant = "a" + notConstant;
6+
String string = "a" + "b"; //ab
7+
String stringWithChar = "ab" + 'c'; //abc
8+
String stringWithBool = "ab" + true; //abtrue
9+
String stringWithInt = "ab" + 42; //ab42
10+
String stringWithDouble = "ab" + 43.0; //ab43.0
11+
String stringWithFloat = "ab" + 44.0f; //ab44.0
12+
String stringWithLong = "ab" + 45L; //ab45
13+
String stringWithShort = "ab" + (short) 46; //ab46
14+
String stringWithByte = "ab" + (byte) 47; //ab47
15+
String charWithString = 'a' + "bc"; //abc
16+
String boolWithString = true + "bc"; //truebc
17+
String intWithString = 42 + "bc"; //42bc
18+
String doubleWithString = 43.0 + "bc"; //43.0bc
19+
String floatWithString = 44.0f + "bc"; //44.0bc
20+
String longWithString = 45L + "bc"; //45bc
21+
String shortWithString = (short) 46 + "bc"; //46bc
22+
String byteWithString = (byte) 47 + "bc"; //47bc
23+
24+
String stringWithExponent = "a" + 10e1; //a100
25+
String stringWithBooleanOr = "a" + (true || false); //atrue
26+
String stringWithIntDivide = "a" + (168 / 4); //a42
27+
}
28+
}

java/ql/test/library-tests/constants/constants/Values.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,5 +90,7 @@ void values(final int notConstant) {
9090
int var_nonfinald_local = var_field; //Not constant
9191
String concatenatedString = "a" + "b"; //ab
9292
String concatenatedChar = "ab" + 'c'; //abc
93+
94+
int charWithChar = 'a' + 'b'; //195
9395
}
9496
}

java/ql/test/library-tests/constants/getBooleanValue.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import semmle.code.java.Variable
1+
import java
22

33
from Variable v, CompileTimeConstantExpr init, RefType enclosing, boolean constant
44
where

java/ql/test/library-tests/constants/getInitializer.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import semmle.code.java.Variable
1+
import java
22

33
from Variable v, Expr init, RefType enclosing
44
where

java/ql/test/library-tests/constants/getIntValue.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,4 @@
3737
| constants/Values.java:86:25:86:35 | final_field | 42 |
3838
| constants/Values.java:87:33:87:34 | 42 | 42 |
3939
| constants/Values.java:88:25:88:35 | final_local | 42 |
40+
| constants/Values.java:94:28:94:36 | ... + ... | 195 |
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import semmle.code.java.Variable
1+
import java
22

33
from Variable v, CompileTimeConstantExpr init, RefType enclosing, int constant
44
where
55
v.getInitializer() = init and
66
init.getEnclosingCallable().getDeclaringType() = enclosing and
7-
enclosing.hasQualifiedName("constants", "Values") and
7+
enclosing.hasQualifiedName("constants", ["Values", "Stringified"]) and
88
constant = init.getIntValue()
99
select init, constant
Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,25 @@
1-
| constants/Values.java:19:29:19:31 | '*' | * |
1+
| constants/Stringified.java:6:25:6:33 | "a" + "b" | ab |
2+
| constants/Stringified.java:7:33:7:42 | ... + ... | ab99 |
3+
| constants/Stringified.java:7:33:7:42 | ... + ... | abc |
4+
| constants/Stringified.java:8:33:8:43 | ... + ... | abtrue |
5+
| constants/Stringified.java:9:32:9:40 | ... + ... | ab42 |
6+
| constants/Stringified.java:10:35:10:45 | ... + ... | ab43.0 |
7+
| constants/Stringified.java:11:34:11:45 | ... + ... | ab44.0 |
8+
| constants/Stringified.java:12:33:12:42 | ... + ... | ab45 |
9+
| constants/Stringified.java:13:34:13:50 | ... + ... | ab46 |
10+
| constants/Stringified.java:14:33:14:48 | ... + ... | ab47 |
11+
| constants/Stringified.java:15:33:15:42 | ... + ... | 97bc |
12+
| constants/Stringified.java:15:33:15:42 | ... + ... | abc |
13+
| constants/Stringified.java:16:33:16:43 | ... + ... | truebc |
14+
| constants/Stringified.java:17:32:17:40 | ... + ... | 42bc |
15+
| constants/Stringified.java:18:35:18:45 | ... + ... | 43.0bc |
16+
| constants/Stringified.java:19:34:19:45 | ... + ... | 44.0bc |
17+
| constants/Stringified.java:20:33:20:42 | ... + ... | 45bc |
18+
| constants/Stringified.java:21:34:21:50 | ... + ... | 46bc |
19+
| constants/Stringified.java:22:33:22:48 | ... + ... | 47bc |
20+
| constants/Stringified.java:24:37:24:46 | ... + ... | a100.0 |
21+
| constants/Stringified.java:25:38:25:58 | ... + ... | atrue |
22+
| constants/Stringified.java:26:38:26:52 | ... + ... | a42 |
223
| constants/Values.java:91:37:91:45 | "a" + "b" | ab |
24+
| constants/Values.java:92:35:92:44 | ... + ... | ab99 |
325
| constants/Values.java:92:35:92:44 | ... + ... | abc |
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import semmle.code.java.Variable
1+
import java
22

33
from Variable v, CompileTimeConstantExpr init, RefType enclosing, string constant
44
where
55
v.getInitializer() = init and
66
init.getEnclosingCallable().getDeclaringType() = enclosing and
7-
enclosing.hasQualifiedName("constants", "Values") and
7+
enclosing.hasQualifiedName("constants", ["Values", "Stringified"]) and
88
constant = init.getStringValue()
99
select init, constant

0 commit comments

Comments
 (0)