From 2e8b5f743b5b1e807db73d775ab78a5920346fd5 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Mon, 7 Mar 2022 20:02:23 -0500 Subject: [PATCH 1/5] [Java] Add CompileTimeConstantExpr.getStringified method Removes CharacterLiteral from CompileTimeConstantExpr.getStringValue Resolves: - https://github.com/github/codeql/pull/8325#issuecomment-1060470279 - https://github.com/github/codeql/pull/8325#issuecomment-1060587205 --- ...3-char-literal-in-compile-time-constant.md | 4 - ...7-char-literal-in-compile-time-constant.md | 5 + java/ql/lib/semmle/code/java/Expr.qll | 50 +++++- .../library-tests/constants/PrintAst.expected | 151 ++++++++++++++++++ .../constants/constants/Stringified.java | 28 ++++ .../constants/constants/Values.java | 2 + .../constants/getIntValue.expected | 1 + .../library-tests/constants/getIntValue.ql | 2 +- .../constants/getStringValue.expected | 24 ++- .../library-tests/constants/getStringValue.ql | 2 +- .../constants/getStringified.expected | 80 ++++++++++ .../library-tests/constants/getStringified.ql | 9 ++ 12 files changed, 346 insertions(+), 12 deletions(-) delete mode 100644 java/ql/lib/change-notes/2022-03-03-char-literal-in-compile-time-constant.md create mode 100644 java/ql/lib/change-notes/2022-03-07-char-literal-in-compile-time-constant.md create mode 100644 java/ql/test/library-tests/constants/constants/Stringified.java create mode 100644 java/ql/test/library-tests/constants/getStringified.expected create mode 100644 java/ql/test/library-tests/constants/getStringified.ql diff --git a/java/ql/lib/change-notes/2022-03-03-char-literal-in-compile-time-constant.md b/java/ql/lib/change-notes/2022-03-03-char-literal-in-compile-time-constant.md deleted file mode 100644 index 1ee68add8b14..000000000000 --- a/java/ql/lib/change-notes/2022-03-03-char-literal-in-compile-time-constant.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- - * Add support for `CharacterLiteral` in `CompileTimeConstantExpr.getStringValue()` diff --git a/java/ql/lib/change-notes/2022-03-07-char-literal-in-compile-time-constant.md b/java/ql/lib/change-notes/2022-03-07-char-literal-in-compile-time-constant.md new file mode 100644 index 000000000000..5be27c4f8f1a --- /dev/null +++ b/java/ql/lib/change-notes/2022-03-07-char-literal-in-compile-time-constant.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- + * Add new method `CharacterLiteral.getStringifiedValue` which attempts to compute the + `String.valueOf` compile time constant value of the expression. diff --git a/java/ql/lib/semmle/code/java/Expr.qll b/java/ql/lib/semmle/code/java/Expr.qll index d98cdbb6b0e6..fe75761fb088 100755 --- a/java/ql/lib/semmle/code/java/Expr.qll +++ b/java/ql/lib/semmle/code/java/Expr.qll @@ -161,6 +161,38 @@ class CompileTimeConstantExpr extends Expr { ) } + /** + * Gets the stringified value of this expression, where possible. + * + * The stringified version of a compile-time constant expression is the equivalent to + * the result of calling `String.valueOf(expr)` on the expression. + * + * Note that this does not handle the following cases: + * + * - mathematical computations of type `long`. + */ + pragma[nomagic] + string getStringifiedValue() { + result = getStringValue() + or + result = this.(Literal).getValue() + or + result = this.getBooleanValue().toString() + or + result = this.getIntValue().toString() + or + // Ternary conditional, with compile-time constant condition. + exists(ConditionalExpr ce, boolean condition | + ce = this and + condition = ce.getCondition().(CompileTimeConstantExpr).getBooleanValue() and + result = ce.getBranchExpr(condition).(CompileTimeConstantExpr).getStringifiedValue() + ) + or + exists(Variable v | this = v.getAnAccess() | + result = v.getInitializer().(CompileTimeConstantExpr).getStringifiedValue() + ) + } + /** * Gets the string value of this expression, where possible. */ @@ -168,11 +200,19 @@ class CompileTimeConstantExpr extends Expr { string getStringValue() { result = this.(StringLiteral).getValue() or - result = this.(CharacterLiteral).getValue() - or - result = - this.(AddExpr).getLeftOperand().(CompileTimeConstantExpr).getStringValue() + - this.(AddExpr).getRightOperand().(CompileTimeConstantExpr).getStringValue() + ( + if this.(AddExpr).getAnOperand().getType() instanceof TypeString // If either operand type is already a String: + then + // Then the stringified version of the expression can be safely used as a String will be created. + result = + this.(AddExpr).getLeftOperand().(CompileTimeConstantExpr).getStringifiedValue() + + this.(AddExpr).getRightOperand().(CompileTimeConstantExpr).getStringifiedValue() + else + // Adding two literals of primitive type will not result in a String. + result = + this.(AddExpr).getLeftOperand().(CompileTimeConstantExpr).getStringValue() + + this.(AddExpr).getRightOperand().(CompileTimeConstantExpr).getStringValue() + ) or // Ternary conditional, with compile-time constant condition. exists(ConditionalExpr ce, boolean condition | diff --git a/java/ql/test/library-tests/constants/PrintAst.expected b/java/ql/test/library-tests/constants/PrintAst.expected index 2ecc471d9811..fa7a14c94257 100644 --- a/java/ql/test/library-tests/constants/PrintAst.expected +++ b/java/ql/test/library-tests/constants/PrintAst.expected @@ -133,6 +133,151 @@ constants/Initializers.java: # 37| 0: [AssignExpr] ...=... # 37| 0: [VarAccess] f # 37| 1: [IntegerLiteral] 42 +constants/Stringified.java: +# 0| [CompilationUnit] Stringified +# 3| 1: [Class] Stringified +# 4| 2: [Method] stringified +# 4| 3: [TypeAccess] void +#-----| 4: (Parameters) +# 4| 0: [Parameter] notConstant +# 4| 0: [TypeAccess] String +# 4| 5: [BlockStmt] { ... } +# 5| 0: [LocalVariableDeclStmt] var ...; +# 5| 0: [TypeAccess] String +# 5| 1: [LocalVariableDeclExpr] withNotConstant +# 5| 0: [AddExpr] ... + ... +# 5| 0: [StringLiteral] "a" +# 5| 1: [VarAccess] notConstant +# 6| 1: [LocalVariableDeclStmt] var ...; +# 6| 0: [TypeAccess] String +# 6| 1: [LocalVariableDeclExpr] string +# 6| 0: [StringLiteral] "a" + "b" +# 7| 2: [LocalVariableDeclStmt] var ...; +# 7| 0: [TypeAccess] String +# 7| 1: [LocalVariableDeclExpr] stringWithChar +# 7| 0: [AddExpr] ... + ... +# 7| 0: [StringLiteral] "ab" +# 7| 1: [CharacterLiteral] 'c' +# 8| 3: [LocalVariableDeclStmt] var ...; +# 8| 0: [TypeAccess] String +# 8| 1: [LocalVariableDeclExpr] stringWithBool +# 8| 0: [AddExpr] ... + ... +# 8| 0: [StringLiteral] "ab" +# 8| 1: [BooleanLiteral] true +# 9| 4: [LocalVariableDeclStmt] var ...; +# 9| 0: [TypeAccess] String +# 9| 1: [LocalVariableDeclExpr] stringWithInt +# 9| 0: [AddExpr] ... + ... +# 9| 0: [StringLiteral] "ab" +# 9| 1: [IntegerLiteral] 42 +# 10| 5: [LocalVariableDeclStmt] var ...; +# 10| 0: [TypeAccess] String +# 10| 1: [LocalVariableDeclExpr] stringWithDouble +# 10| 0: [AddExpr] ... + ... +# 10| 0: [StringLiteral] "ab" +# 10| 1: [DoubleLiteral] 43.0 +# 11| 6: [LocalVariableDeclStmt] var ...; +# 11| 0: [TypeAccess] String +# 11| 1: [LocalVariableDeclExpr] stringWithFloat +# 11| 0: [AddExpr] ... + ... +# 11| 0: [StringLiteral] "ab" +# 11| 1: [FloatingPointLiteral] 44.0f +# 12| 7: [LocalVariableDeclStmt] var ...; +# 12| 0: [TypeAccess] String +# 12| 1: [LocalVariableDeclExpr] stringWithLong +# 12| 0: [AddExpr] ... + ... +# 12| 0: [StringLiteral] "ab" +# 12| 1: [LongLiteral] 45L +# 13| 8: [LocalVariableDeclStmt] var ...; +# 13| 0: [TypeAccess] String +# 13| 1: [LocalVariableDeclExpr] stringWithShort +# 13| 0: [AddExpr] ... + ... +# 13| 0: [StringLiteral] "ab" +# 13| 1: [CastExpr] (...)... +# 13| 0: [TypeAccess] short +# 13| 1: [IntegerLiteral] 46 +# 14| 9: [LocalVariableDeclStmt] var ...; +# 14| 0: [TypeAccess] String +# 14| 1: [LocalVariableDeclExpr] stringWithByte +# 14| 0: [AddExpr] ... + ... +# 14| 0: [StringLiteral] "ab" +# 14| 1: [CastExpr] (...)... +# 14| 0: [TypeAccess] byte +# 14| 1: [IntegerLiteral] 47 +# 15| 10: [LocalVariableDeclStmt] var ...; +# 15| 0: [TypeAccess] String +# 15| 1: [LocalVariableDeclExpr] charWithString +# 15| 0: [AddExpr] ... + ... +# 15| 0: [CharacterLiteral] 'a' +# 15| 1: [StringLiteral] "bc" +# 16| 11: [LocalVariableDeclStmt] var ...; +# 16| 0: [TypeAccess] String +# 16| 1: [LocalVariableDeclExpr] boolWithString +# 16| 0: [AddExpr] ... + ... +# 16| 0: [BooleanLiteral] true +# 16| 1: [StringLiteral] "bc" +# 17| 12: [LocalVariableDeclStmt] var ...; +# 17| 0: [TypeAccess] String +# 17| 1: [LocalVariableDeclExpr] intWithString +# 17| 0: [AddExpr] ... + ... +# 17| 0: [IntegerLiteral] 42 +# 17| 1: [StringLiteral] "bc" +# 18| 13: [LocalVariableDeclStmt] var ...; +# 18| 0: [TypeAccess] String +# 18| 1: [LocalVariableDeclExpr] doubleWithString +# 18| 0: [AddExpr] ... + ... +# 18| 0: [DoubleLiteral] 43.0 +# 18| 1: [StringLiteral] "bc" +# 19| 14: [LocalVariableDeclStmt] var ...; +# 19| 0: [TypeAccess] String +# 19| 1: [LocalVariableDeclExpr] floatWithString +# 19| 0: [AddExpr] ... + ... +# 19| 0: [FloatingPointLiteral] 44.0f +# 19| 1: [StringLiteral] "bc" +# 20| 15: [LocalVariableDeclStmt] var ...; +# 20| 0: [TypeAccess] String +# 20| 1: [LocalVariableDeclExpr] longWithString +# 20| 0: [AddExpr] ... + ... +# 20| 0: [LongLiteral] 45L +# 20| 1: [StringLiteral] "bc" +# 21| 16: [LocalVariableDeclStmt] var ...; +# 21| 0: [TypeAccess] String +# 21| 1: [LocalVariableDeclExpr] shortWithString +# 21| 0: [AddExpr] ... + ... +# 21| 0: [CastExpr] (...)... +# 21| 0: [TypeAccess] short +# 21| 1: [IntegerLiteral] 46 +# 21| 1: [StringLiteral] "bc" +# 22| 17: [LocalVariableDeclStmt] var ...; +# 22| 0: [TypeAccess] String +# 22| 1: [LocalVariableDeclExpr] byteWithString +# 22| 0: [AddExpr] ... + ... +# 22| 0: [CastExpr] (...)... +# 22| 0: [TypeAccess] byte +# 22| 1: [IntegerLiteral] 47 +# 22| 1: [StringLiteral] "bc" +# 24| 18: [LocalVariableDeclStmt] var ...; +# 24| 0: [TypeAccess] String +# 24| 1: [LocalVariableDeclExpr] stringWithExponent +# 24| 0: [AddExpr] ... + ... +# 24| 0: [StringLiteral] "a" +# 24| 1: [DoubleLiteral] 10e1 +# 25| 19: [LocalVariableDeclStmt] var ...; +# 25| 0: [TypeAccess] String +# 25| 1: [LocalVariableDeclExpr] stringWithBooleanOr +# 25| 0: [AddExpr] ... + ... +# 25| 0: [StringLiteral] "a" +# 25| 1: [OrLogicalExpr] ... || ... +# 25| 0: [BooleanLiteral] true +# 25| 1: [BooleanLiteral] false +# 26| 20: [LocalVariableDeclStmt] var ...; +# 26| 0: [TypeAccess] String +# 26| 1: [LocalVariableDeclExpr] stringWithIntDivide +# 26| 0: [AddExpr] ... + ... +# 26| 0: [StringLiteral] "a" +# 26| 1: [DivExpr] ... / ... +# 26| 0: [IntegerLiteral] 168 +# 26| 1: [IntegerLiteral] 4 constants/Values.java: # 0| [CompilationUnit] Values # 4| 1: [Class] Values @@ -526,3 +671,9 @@ constants/Values.java: # 92| 0: [AddExpr] ... + ... # 92| 0: [StringLiteral] "ab" # 92| 1: [CharacterLiteral] 'c' +# 94| 70: [LocalVariableDeclStmt] var ...; +# 94| 0: [TypeAccess] int +# 94| 1: [LocalVariableDeclExpr] charWithChar +# 94| 0: [AddExpr] ... + ... +# 94| 0: [CharacterLiteral] 'a' +# 94| 1: [CharacterLiteral] 'b' diff --git a/java/ql/test/library-tests/constants/constants/Stringified.java b/java/ql/test/library-tests/constants/constants/Stringified.java new file mode 100644 index 000000000000..b8836a2f0f64 --- /dev/null +++ b/java/ql/test/library-tests/constants/constants/Stringified.java @@ -0,0 +1,28 @@ +package constants; + +public class Stringified { + void stringified(final String notConstant) { + String withNotConstant = "a" + notConstant; + String string = "a" + "b"; //ab + String stringWithChar = "ab" + 'c'; //abc + String stringWithBool = "ab" + true; //abtrue + String stringWithInt = "ab" + 42; //ab42 + String stringWithDouble = "ab" + 43.0; //ab43.0 + String stringWithFloat = "ab" + 44.0f; //ab44.0 + String stringWithLong = "ab" + 45L; //ab45 + String stringWithShort = "ab" + (short) 46; //ab46 + String stringWithByte = "ab" + (byte) 47; //ab47 + String charWithString = 'a' + "bc"; //abc + String boolWithString = true + "bc"; //truebc + String intWithString = 42 + "bc"; //42bc + String doubleWithString = 43.0 + "bc"; //43.0bc + String floatWithString = 44.0f + "bc"; //44.0bc + String longWithString = 45L + "bc"; //45bc + String shortWithString = (short) 46 + "bc"; //46bc + String byteWithString = (byte) 47 + "bc"; //47bc + + String stringWithExponent = "a" + 10e1; //a100 + String stringWithBooleanOr = "a" + (true || false); //atrue + String stringWithIntDivide = "a" + (168 / 4); //a42 + } +} diff --git a/java/ql/test/library-tests/constants/constants/Values.java b/java/ql/test/library-tests/constants/constants/Values.java index b59672f96e75..0f838176202c 100644 --- a/java/ql/test/library-tests/constants/constants/Values.java +++ b/java/ql/test/library-tests/constants/constants/Values.java @@ -90,5 +90,7 @@ void values(final int notConstant) { int var_nonfinald_local = var_field; //Not constant String concatenatedString = "a" + "b"; //ab String concatenatedChar = "ab" + 'c'; //abc + + int charWithChar = 'a' + 'b'; //195 } } diff --git a/java/ql/test/library-tests/constants/getIntValue.expected b/java/ql/test/library-tests/constants/getIntValue.expected index 8dfd0fc7841a..4194479cb130 100644 --- a/java/ql/test/library-tests/constants/getIntValue.expected +++ b/java/ql/test/library-tests/constants/getIntValue.expected @@ -37,3 +37,4 @@ | constants/Values.java:86:25:86:35 | final_field | 42 | | constants/Values.java:87:33:87:34 | 42 | 42 | | constants/Values.java:88:25:88:35 | final_local | 42 | +| constants/Values.java:94:28:94:36 | ... + ... | 195 | diff --git a/java/ql/test/library-tests/constants/getIntValue.ql b/java/ql/test/library-tests/constants/getIntValue.ql index 5fc5b108032f..0e84c2d1719b 100644 --- a/java/ql/test/library-tests/constants/getIntValue.ql +++ b/java/ql/test/library-tests/constants/getIntValue.ql @@ -4,6 +4,6 @@ from Variable v, CompileTimeConstantExpr init, RefType enclosing, int constant where v.getInitializer() = init and init.getEnclosingCallable().getDeclaringType() = enclosing and - enclosing.hasQualifiedName("constants", "Values") and + enclosing.hasQualifiedName("constants", ["Values", "Stringified"]) and constant = init.getIntValue() select init, constant diff --git a/java/ql/test/library-tests/constants/getStringValue.expected b/java/ql/test/library-tests/constants/getStringValue.expected index b6afeb8052eb..2fdc29e03822 100644 --- a/java/ql/test/library-tests/constants/getStringValue.expected +++ b/java/ql/test/library-tests/constants/getStringValue.expected @@ -1,3 +1,25 @@ -| constants/Values.java:19:29:19:31 | '*' | * | +| constants/Stringified.java:6:25:6:33 | "a" + "b" | ab | +| constants/Stringified.java:7:33:7:42 | ... + ... | ab99 | +| constants/Stringified.java:7:33:7:42 | ... + ... | abc | +| constants/Stringified.java:8:33:8:43 | ... + ... | abtrue | +| constants/Stringified.java:9:32:9:40 | ... + ... | ab42 | +| constants/Stringified.java:10:35:10:45 | ... + ... | ab43.0 | +| constants/Stringified.java:11:34:11:45 | ... + ... | ab44.0 | +| constants/Stringified.java:12:33:12:42 | ... + ... | ab45 | +| constants/Stringified.java:13:34:13:50 | ... + ... | ab46 | +| constants/Stringified.java:14:33:14:48 | ... + ... | ab47 | +| constants/Stringified.java:15:33:15:42 | ... + ... | 97bc | +| constants/Stringified.java:15:33:15:42 | ... + ... | abc | +| constants/Stringified.java:16:33:16:43 | ... + ... | truebc | +| constants/Stringified.java:17:32:17:40 | ... + ... | 42bc | +| constants/Stringified.java:18:35:18:45 | ... + ... | 43.0bc | +| constants/Stringified.java:19:34:19:45 | ... + ... | 44.0bc | +| constants/Stringified.java:20:33:20:42 | ... + ... | 45bc | +| constants/Stringified.java:21:34:21:50 | ... + ... | 46bc | +| constants/Stringified.java:22:33:22:48 | ... + ... | 47bc | +| constants/Stringified.java:24:37:24:46 | ... + ... | a100.0 | +| constants/Stringified.java:25:38:25:58 | ... + ... | atrue | +| constants/Stringified.java:26:38:26:52 | ... + ... | a42 | | constants/Values.java:91:37:91:45 | "a" + "b" | ab | +| constants/Values.java:92:35:92:44 | ... + ... | ab99 | | constants/Values.java:92:35:92:44 | ... + ... | abc | diff --git a/java/ql/test/library-tests/constants/getStringValue.ql b/java/ql/test/library-tests/constants/getStringValue.ql index bbf7cd8b51e9..2ecb99067b4b 100644 --- a/java/ql/test/library-tests/constants/getStringValue.ql +++ b/java/ql/test/library-tests/constants/getStringValue.ql @@ -4,6 +4,6 @@ from Variable v, CompileTimeConstantExpr init, RefType enclosing, string constan where v.getInitializer() = init and init.getEnclosingCallable().getDeclaringType() = enclosing and - enclosing.hasQualifiedName("constants", "Values") and + enclosing.hasQualifiedName("constants", ["Values", "Stringified"]) and constant = init.getStringValue() select init, constant diff --git a/java/ql/test/library-tests/constants/getStringified.expected b/java/ql/test/library-tests/constants/getStringified.expected new file mode 100644 index 000000000000..a37bcf70543a --- /dev/null +++ b/java/ql/test/library-tests/constants/getStringified.expected @@ -0,0 +1,80 @@ +| constants/Stringified.java:6:25:6:33 | "a" + "b" | ab | +| constants/Stringified.java:7:33:7:42 | ... + ... | ab99 | +| constants/Stringified.java:7:33:7:42 | ... + ... | abc | +| constants/Stringified.java:8:33:8:43 | ... + ... | abtrue | +| constants/Stringified.java:9:32:9:40 | ... + ... | ab42 | +| constants/Stringified.java:10:35:10:45 | ... + ... | ab43.0 | +| constants/Stringified.java:11:34:11:45 | ... + ... | ab44.0 | +| constants/Stringified.java:12:33:12:42 | ... + ... | ab45 | +| constants/Stringified.java:13:34:13:50 | ... + ... | ab46 | +| constants/Stringified.java:14:33:14:48 | ... + ... | ab47 | +| constants/Stringified.java:15:33:15:42 | ... + ... | 97bc | +| constants/Stringified.java:15:33:15:42 | ... + ... | abc | +| constants/Stringified.java:16:33:16:43 | ... + ... | truebc | +| constants/Stringified.java:17:32:17:40 | ... + ... | 42bc | +| constants/Stringified.java:18:35:18:45 | ... + ... | 43.0bc | +| constants/Stringified.java:19:34:19:45 | ... + ... | 44.0bc | +| constants/Stringified.java:20:33:20:42 | ... + ... | 45bc | +| constants/Stringified.java:21:34:21:50 | ... + ... | 46bc | +| constants/Stringified.java:22:33:22:48 | ... + ... | 47bc | +| constants/Stringified.java:24:37:24:46 | ... + ... | a100.0 | +| constants/Stringified.java:25:38:25:58 | ... + ... | atrue | +| constants/Stringified.java:26:38:26:52 | ... + ... | a42 | +| constants/Values.java:6:29:6:30 | 42 | 42 | +| constants/Values.java:9:27:9:28 | 42 | 42 | +| constants/Values.java:10:36:10:46 | -2147483648 | -2147483648 | +| constants/Values.java:11:29:11:31 | 052 | 42 | +| constants/Values.java:12:38:12:41 | -... | -42 | +| constants/Values.java:13:27:13:30 | 0x2A | 42 | +| constants/Values.java:14:36:14:40 | -... | -42 | +| constants/Values.java:15:39:15:43 | 0x2_A | 42 | +| constants/Values.java:16:30:16:37 | 0b101010 | 42 | +| constants/Values.java:17:39:17:47 | -... | -42 | +| constants/Values.java:18:42:18:51 | 0b1_0101_0 | 42 | +| constants/Values.java:19:29:19:31 | '*' | 42 | +| constants/Values.java:19:29:19:31 | '*' | * | +| constants/Values.java:20:29:20:31 | 42L | 42 | +| constants/Values.java:21:35:21:38 | true | true | +| constants/Values.java:25:20:25:27 | (...)... | 42 | +| constants/Values.java:26:25:26:33 | (...)... | 42 | +| constants/Values.java:27:32:27:43 | (...)... | -42 | +| constants/Values.java:28:32:28:40 | (...)... | 42 | +| constants/Values.java:29:32:29:41 | (...)... | 42 | +| constants/Values.java:30:32:30:41 | (...)... | -42 | +| constants/Values.java:31:32:31:44 | (...)... | 42 | +| constants/Values.java:32:32:32:44 | (...)... | -32768 | +| constants/Values.java:33:36:33:44 | (...)... | 42 | +| constants/Values.java:36:26:36:28 | +... | 42 | +| constants/Values.java:39:27:39:29 | -... | -42 | +| constants/Values.java:42:23:42:27 | !... | false | +| constants/Values.java:43:27:43:28 | ~... | -1 | +| constants/Values.java:45:19:45:23 | ... * ... | 63 | +| constants/Values.java:48:19:48:25 | ... / ... | 42 | +| constants/Values.java:52:19:52:26 | ... % ... | 42 | +| constants/Values.java:56:20:56:26 | ... + ... | 42 | +| constants/Values.java:59:21:59:29 | ... - ... | 42 | +| constants/Values.java:62:22:62:28 | ... << ... | 84 | +| constants/Values.java:65:22:65:28 | ... >> ... | -1 | +| constants/Values.java:66:23:66:30 | ... >>> ... | 2147483647 | +| constants/Values.java:67:27:67:33 | ... & ... | 42 | +| constants/Values.java:68:26:68:32 | ... \| ... | 42 | +| constants/Values.java:69:27:69:33 | ... ^ ... | 42 | +| constants/Values.java:70:23:70:35 | ... && ... | false | +| constants/Values.java:71:22:71:34 | ... \|\| ... | true | +| constants/Values.java:72:22:72:28 | ... < ... | false | +| constants/Values.java:73:22:73:29 | ... <= ... | true | +| constants/Values.java:74:22:74:28 | ... > ... | false | +| constants/Values.java:75:23:75:30 | ... >= ... | true | +| constants/Values.java:76:22:76:29 | ... == ... | true | +| constants/Values.java:77:22:77:29 | ... != ... | false | +| constants/Values.java:78:23:78:41 | ...?...:... | false | +| constants/Values.java:80:23:80:36 | ... == ... | true | +| constants/Values.java:81:24:81:37 | ... != ... | false | +| constants/Values.java:83:20:83:21 | 42 | 42 | +| constants/Values.java:86:25:86:35 | final_field | 42 | +| constants/Values.java:87:33:87:34 | 42 | 42 | +| constants/Values.java:88:25:88:35 | final_local | 42 | +| constants/Values.java:91:37:91:45 | "a" + "b" | ab | +| constants/Values.java:92:35:92:44 | ... + ... | ab99 | +| constants/Values.java:92:35:92:44 | ... + ... | abc | +| constants/Values.java:94:28:94:36 | ... + ... | 195 | diff --git a/java/ql/test/library-tests/constants/getStringified.ql b/java/ql/test/library-tests/constants/getStringified.ql new file mode 100644 index 000000000000..5944d117ebf0 --- /dev/null +++ b/java/ql/test/library-tests/constants/getStringified.ql @@ -0,0 +1,9 @@ +import semmle.code.java.Variable + +from Variable v, CompileTimeConstantExpr init, RefType enclosing, string constant +where + v.getInitializer() = init and + init.getEnclosingCallable().getDeclaringType() = enclosing and + enclosing.hasQualifiedName("constants", ["Values", "Stringified"]) and + constant = init.getStringifiedValue() +select init, constant From 65457cc2e29d4e72a5b931915e0b46041819dc09 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Wed, 9 Mar 2022 10:25:05 -0500 Subject: [PATCH 2/5] Apply suggestions from code review Co-authored-by: Chris Smowton --- ...-03-07-char-literal-in-compile-time-constant.md | 4 ++-- java/ql/lib/semmle/code/java/Expr.qll | 14 +++----------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/java/ql/lib/change-notes/2022-03-07-char-literal-in-compile-time-constant.md b/java/ql/lib/change-notes/2022-03-07-char-literal-in-compile-time-constant.md index 5be27c4f8f1a..678c3c7125d9 100644 --- a/java/ql/lib/change-notes/2022-03-07-char-literal-in-compile-time-constant.md +++ b/java/ql/lib/change-notes/2022-03-07-char-literal-in-compile-time-constant.md @@ -1,5 +1,5 @@ --- category: minorAnalysis --- - * Add new method `CharacterLiteral.getStringifiedValue` which attempts to compute the - `String.valueOf` compile time constant value of the expression. + * Add new method `CompileTimeConstantExpr.getStringifiedValue` which attempts to compute the + `String.valueOf` string rendering of a constant expression. diff --git a/java/ql/lib/semmle/code/java/Expr.qll b/java/ql/lib/semmle/code/java/Expr.qll index fe75761fb088..5d8b158f5a1b 100755 --- a/java/ql/lib/semmle/code/java/Expr.qll +++ b/java/ql/lib/semmle/code/java/Expr.qll @@ -201,17 +201,9 @@ class CompileTimeConstantExpr extends Expr { result = this.(StringLiteral).getValue() or ( - if this.(AddExpr).getAnOperand().getType() instanceof TypeString // If either operand type is already a String: - then - // Then the stringified version of the expression can be safely used as a String will be created. - result = - this.(AddExpr).getLeftOperand().(CompileTimeConstantExpr).getStringifiedValue() + - this.(AddExpr).getRightOperand().(CompileTimeConstantExpr).getStringifiedValue() - else - // Adding two literals of primitive type will not result in a String. - result = - this.(AddExpr).getLeftOperand().(CompileTimeConstantExpr).getStringValue() + - this.(AddExpr).getRightOperand().(CompileTimeConstantExpr).getStringValue() + this.getType() instanceof TypeString and + this.(AddExpr).getLeftOperand().(CompileTimeConstantExpr).getStringifiedValue() + + this.(AddExpr).getRightOperand().(CompileTimeConstantExpr).getStringifiedValue() ) or // Ternary conditional, with compile-time constant condition. From 363fff23585472e8f12d33027614957fe7274627 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Wed, 9 Mar 2022 10:45:46 -0500 Subject: [PATCH 3/5] Cleanup from code review feedback --- ...2022-03-07-char-literal-in-compile-time-constant.md | 2 +- java/ql/lib/semmle/code/java/Expr.qll | 10 +++++----- .../library-tests/constants/CompileTimeConstantExpr.ql | 2 +- .../ql/test/library-tests/constants/getBooleanValue.ql | 2 +- java/ql/test/library-tests/constants/getInitializer.ql | 2 +- java/ql/test/library-tests/constants/getIntValue.ql | 2 +- java/ql/test/library-tests/constants/getStringValue.ql | 2 +- java/ql/test/library-tests/constants/getStringified.ql | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/java/ql/lib/change-notes/2022-03-07-char-literal-in-compile-time-constant.md b/java/ql/lib/change-notes/2022-03-07-char-literal-in-compile-time-constant.md index 678c3c7125d9..b5bf77c33a8c 100644 --- a/java/ql/lib/change-notes/2022-03-07-char-literal-in-compile-time-constant.md +++ b/java/ql/lib/change-notes/2022-03-07-char-literal-in-compile-time-constant.md @@ -1,5 +1,5 @@ --- category: minorAnalysis --- - * Add new method `CompileTimeConstantExpr.getStringifiedValue` which attempts to compute the + * Add new predicate `CompileTimeConstantExpr.getStringifiedValue` which attempts to compute the `String.valueOf` string rendering of a constant expression. diff --git a/java/ql/lib/semmle/code/java/Expr.qll b/java/ql/lib/semmle/code/java/Expr.qll index 5d8b158f5a1b..d8824d88cd41 100755 --- a/java/ql/lib/semmle/code/java/Expr.qll +++ b/java/ql/lib/semmle/code/java/Expr.qll @@ -166,10 +166,10 @@ class CompileTimeConstantExpr extends Expr { * * The stringified version of a compile-time constant expression is the equivalent to * the result of calling `String.valueOf(expr)` on the expression. - * + * * Note that this does not handle the following cases: * - * - mathematical computations of type `long`. + * - mathematical computations of type `long`, `float`, or `double`. */ pragma[nomagic] string getStringifiedValue() { @@ -200,11 +200,11 @@ class CompileTimeConstantExpr extends Expr { string getStringValue() { result = this.(StringLiteral).getValue() or - ( - this.getType() instanceof TypeString and + this.getType() instanceof TypeString and // When the expression type is `String` + result = + // Then the resultant string is the addition of both operands stringified value, regardless of type. this.(AddExpr).getLeftOperand().(CompileTimeConstantExpr).getStringifiedValue() + this.(AddExpr).getRightOperand().(CompileTimeConstantExpr).getStringifiedValue() - ) or // Ternary conditional, with compile-time constant condition. exists(ConditionalExpr ce, boolean condition | diff --git a/java/ql/test/library-tests/constants/CompileTimeConstantExpr.ql b/java/ql/test/library-tests/constants/CompileTimeConstantExpr.ql index 93bf17e23b4a..664df880f964 100644 --- a/java/ql/test/library-tests/constants/CompileTimeConstantExpr.ql +++ b/java/ql/test/library-tests/constants/CompileTimeConstantExpr.ql @@ -1,4 +1,4 @@ -import semmle.code.java.Expr +import java from CompileTimeConstantExpr constant, RefType tpe where diff --git a/java/ql/test/library-tests/constants/getBooleanValue.ql b/java/ql/test/library-tests/constants/getBooleanValue.ql index 460af42d3c30..0d5fa98e4364 100644 --- a/java/ql/test/library-tests/constants/getBooleanValue.ql +++ b/java/ql/test/library-tests/constants/getBooleanValue.ql @@ -1,4 +1,4 @@ -import semmle.code.java.Variable +import java from Variable v, CompileTimeConstantExpr init, RefType enclosing, boolean constant where diff --git a/java/ql/test/library-tests/constants/getInitializer.ql b/java/ql/test/library-tests/constants/getInitializer.ql index 6e4b28ee938b..dbd0f4515045 100644 --- a/java/ql/test/library-tests/constants/getInitializer.ql +++ b/java/ql/test/library-tests/constants/getInitializer.ql @@ -1,4 +1,4 @@ -import semmle.code.java.Variable +import java from Variable v, Expr init, RefType enclosing where diff --git a/java/ql/test/library-tests/constants/getIntValue.ql b/java/ql/test/library-tests/constants/getIntValue.ql index 0e84c2d1719b..e1a90be21ab6 100644 --- a/java/ql/test/library-tests/constants/getIntValue.ql +++ b/java/ql/test/library-tests/constants/getIntValue.ql @@ -1,4 +1,4 @@ -import semmle.code.java.Variable +import java from Variable v, CompileTimeConstantExpr init, RefType enclosing, int constant where diff --git a/java/ql/test/library-tests/constants/getStringValue.ql b/java/ql/test/library-tests/constants/getStringValue.ql index 2ecb99067b4b..f3391bad60a9 100644 --- a/java/ql/test/library-tests/constants/getStringValue.ql +++ b/java/ql/test/library-tests/constants/getStringValue.ql @@ -1,4 +1,4 @@ -import semmle.code.java.Variable +import java from Variable v, CompileTimeConstantExpr init, RefType enclosing, string constant where diff --git a/java/ql/test/library-tests/constants/getStringified.ql b/java/ql/test/library-tests/constants/getStringified.ql index 5944d117ebf0..4b0dc2c47aa5 100644 --- a/java/ql/test/library-tests/constants/getStringified.ql +++ b/java/ql/test/library-tests/constants/getStringified.ql @@ -1,4 +1,4 @@ -import semmle.code.java.Variable +import java from Variable v, CompileTimeConstantExpr init, RefType enclosing, string constant where From 3113b276061ba90d20ffecc49174eefbfc6da87a Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Thu, 10 Mar 2022 10:03:14 +0000 Subject: [PATCH 4/5] Fix style --- java/ql/lib/semmle/code/java/Expr.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/lib/semmle/code/java/Expr.qll b/java/ql/lib/semmle/code/java/Expr.qll index d8824d88cd41..dd85b4586300 100755 --- a/java/ql/lib/semmle/code/java/Expr.qll +++ b/java/ql/lib/semmle/code/java/Expr.qll @@ -173,7 +173,7 @@ class CompileTimeConstantExpr extends Expr { */ pragma[nomagic] string getStringifiedValue() { - result = getStringValue() + result = this.getStringValue() or result = this.(Literal).getValue() or From c99bad4047f2d05465a048bd1e5f38977f28881d Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Fri, 11 Mar 2022 10:34:09 +0100 Subject: [PATCH 5/5] Recover old change note --- .../2022-03-03-char-literal-in-compile-time-constant.md | 4 ++++ .../2022-03-07-char-literal-in-compile-time-constant.md | 5 ----- .../ql/lib/change-notes/2022-03-07-get-stringified-value.md | 6 ++++++ 3 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 java/ql/lib/change-notes/2022-03-03-char-literal-in-compile-time-constant.md delete mode 100644 java/ql/lib/change-notes/2022-03-07-char-literal-in-compile-time-constant.md create mode 100644 java/ql/lib/change-notes/2022-03-07-get-stringified-value.md diff --git a/java/ql/lib/change-notes/2022-03-03-char-literal-in-compile-time-constant.md b/java/ql/lib/change-notes/2022-03-03-char-literal-in-compile-time-constant.md new file mode 100644 index 000000000000..1ee68add8b14 --- /dev/null +++ b/java/ql/lib/change-notes/2022-03-03-char-literal-in-compile-time-constant.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- + * Add support for `CharacterLiteral` in `CompileTimeConstantExpr.getStringValue()` diff --git a/java/ql/lib/change-notes/2022-03-07-char-literal-in-compile-time-constant.md b/java/ql/lib/change-notes/2022-03-07-char-literal-in-compile-time-constant.md deleted file mode 100644 index b5bf77c33a8c..000000000000 --- a/java/ql/lib/change-notes/2022-03-07-char-literal-in-compile-time-constant.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: minorAnalysis ---- - * Add new predicate `CompileTimeConstantExpr.getStringifiedValue` which attempts to compute the - `String.valueOf` string rendering of a constant expression. diff --git a/java/ql/lib/change-notes/2022-03-07-get-stringified-value.md b/java/ql/lib/change-notes/2022-03-07-get-stringified-value.md new file mode 100644 index 000000000000..cdb643987029 --- /dev/null +++ b/java/ql/lib/change-notes/2022-03-07-get-stringified-value.md @@ -0,0 +1,6 @@ +--- +category: minorAnalysis +--- + * Add new predicate `CompileTimeConstantExpr.getStringifiedValue` which attempts to compute the + `String.valueOf` string rendering of a constant expression. This predicate is now used to + compute the string value of an `AddExpr` that has the type `String`.