Skip to content

Commit e3fed55

Browse files
committed
Java: Add tests for text blocks
1 parent 924b732 commit e3fed55

File tree

5 files changed

+117
-37
lines changed

5 files changed

+117
-37
lines changed

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,15 @@ class CharacterLiteral extends Literal, @characterliteral {
719719
override string getAPrimaryQlClass() { result = "CharacterLiteral" }
720720
}
721721

722-
/** A string literal. For example, `"hello world"`. */
722+
/**
723+
* A string literal or text block (Java 15 feature). For example, `"hello world"`
724+
* or
725+
* ```java
726+
* """
727+
* Text with "quotes"
728+
* """
729+
* ```
730+
*/
723731
class StringLiteral extends Literal, @stringliteral {
724732
/**
725733
* Gets the literal string without the quotes.

java/ql/test/library-tests/literals/stringLiterals/StringLiterals.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,64 @@ public class StringLiterals {
3232
\u0022\u0061\u0022, // "a"
3333
};
3434

35+
String[] textBlocks = {
36+
// trailing whitespaces after """ (will be ignored)
37+
"""
38+
test "text" and escaped \u0022
39+
""",
40+
// Indentation tests
41+
"""
42+
indented
43+
""",
44+
"""
45+
no indentation last line
46+
""", // Line is blank, therefore not indented
47+
"""
48+
indentation last line
49+
\s""", // Line is not blank therefore indented
50+
"""
51+
not-indented
52+
""",
53+
"""
54+
indented
55+
""",
56+
"""
57+
not-indented
58+
""",
59+
"""
60+
spaces (only single space is trimmed)
61+
tab
62+
""",
63+
"""
64+
end on same line""",
65+
"""
66+
trailing spaces ignored:
67+
not ignored: \s
68+
""",
69+
"""
70+
3 quotes:""\"""",
71+
"""
72+
line \
73+
continuation \
74+
""",
75+
"""
76+
Explicit line breaks:\n
77+
\r\n
78+
\r
79+
""",
80+
// Using Unicode escapes (which are handled during pre-processing)
81+
// Currently not detected by StringLiteral.isTextBlock()
82+
\uuu0022"\u0022
83+
test
84+
\u0022\uu0022",
85+
};
86+
3587
// The concatenation (`+`) is not a string literal
3688
String[] stringConcatenation = {
3789
// CodeQL erroneously reports this as one literal, see https://github.com/github/codeql/issues/5469
3890
"hello" + "world",
91+
"""
92+
hello""" + "world",
3993
null + "a",
4094
"a" + null,
4195
"a" + 1,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
//semmle-extractor-options: --javac-args -source 15 -target 15
Lines changed: 48 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,48 @@
1-
| StringLiterals.java:7:3:7:4 | "" | | |
2-
| StringLiterals.java:8:3:8:17 | "hello,\\tworld" | hello,\tworld | hello,\tworld |
3-
| StringLiterals.java:9:3:9:21 | "hello,\\u0009world" | hello,\tworld | hello,\tworld |
4-
| StringLiterals.java:10:3:10:10 | "\\u0061" | a | a |
5-
| StringLiterals.java:11:3:11:6 | "\\0" | \u0000 | \u0000 |
6-
| StringLiterals.java:12:3:12:10 | "\\uFFFF" | \uffff | \uffff |
7-
| StringLiterals.java:13:3:13:10 | "\\ufFfF" | \uffff | \uffff |
8-
| StringLiterals.java:14:3:14:6 | "\\"" | " | " |
9-
| StringLiterals.java:15:3:15:6 | "\\'" | ' | ' |
10-
| StringLiterals.java:16:3:16:6 | "\\n" | \n | \n |
11-
| StringLiterals.java:17:3:17:6 | "\\\\" | \\ | \\ |
12-
| StringLiterals.java:18:3:18:13 | "test \\123" | test S | test S |
13-
| StringLiterals.java:19:3:19:9 | "\\1234" | S4 | S4 |
14-
| StringLiterals.java:20:3:20:9 | "\\0000" | \u00000 | \u00000 |
15-
| StringLiterals.java:21:3:21:13 | "\\u0061567" | a567 | a567 |
16-
| StringLiterals.java:22:3:22:13 | "\\u1234567" | \u1234567 | \u1234567 |
17-
| StringLiterals.java:23:3:23:18 | "\\uaBcDeF\\u0aB1" | \uabcdeF\u0ab1 | \uabcdeF\u0ab1 |
18-
| StringLiterals.java:24:3:24:16 | "\\uD800\\uDC00" | \ud800\udc00 | \ud800\udc00 |
19-
| StringLiterals.java:25:3:25:16 | "\\uDBFF\\uDFFF" | \udbff\udfff | \udbff\udfff |
20-
| StringLiterals.java:27:3:27:10 | "\\uD800" | \ufffd | \ufffd |
21-
| StringLiterals.java:28:3:28:10 | "\\uDC00" | \ufffd | \ufffd |
22-
| StringLiterals.java:29:3:29:31 | "hello\\uD800hello\\uDC00world" | hello\ufffdhello\ufffdworld | hello\ufffdhello\ufffdworld |
23-
| StringLiterals.java:31:3:31:16 | "\\u005C\\u0022" | " | " |
24-
| StringLiterals.java:32:8:32:20 | 2\\u0061\\u0022 | a | a |
25-
| StringLiterals.java:38:3:38:19 | "hello" + "world" | helloworld | helloworld |
26-
| StringLiterals.java:39:10:39:12 | "a" | a | a |
27-
| StringLiterals.java:40:3:40:5 | "a" | a | a |
28-
| StringLiterals.java:41:3:41:5 | "a" | a | a |
29-
| StringLiterals.java:42:7:42:9 | "a" | a | a |
30-
| StringLiterals.java:43:3:43:5 | "a" | a | a |
31-
| StringLiterals.java:44:10:44:12 | "a" | a | a |
32-
| StringLiterals.java:45:3:45:5 | "a" | a | a |
33-
| StringLiterals.java:46:9:46:11 | "a" | a | a |
1+
| StringLiterals.java:7:3:7:4 | "" | | | |
2+
| StringLiterals.java:8:3:8:17 | "hello,\\tworld" | hello,\tworld | hello,\tworld | |
3+
| StringLiterals.java:9:3:9:21 | "hello,\\u0009world" | hello,\tworld | hello,\tworld | |
4+
| StringLiterals.java:10:3:10:10 | "\\u0061" | a | a | |
5+
| StringLiterals.java:11:3:11:6 | "\\0" | \u0000 | \u0000 | |
6+
| StringLiterals.java:12:3:12:10 | "\\uFFFF" | \uffff | \uffff | |
7+
| StringLiterals.java:13:3:13:10 | "\\ufFfF" | \uffff | \uffff | |
8+
| StringLiterals.java:14:3:14:6 | "\\"" | " | " | |
9+
| StringLiterals.java:15:3:15:6 | "\\'" | ' | ' | |
10+
| StringLiterals.java:16:3:16:6 | "\\n" | \n | \n | |
11+
| StringLiterals.java:17:3:17:6 | "\\\\" | \\ | \\ | |
12+
| StringLiterals.java:18:3:18:13 | "test \\123" | test S | test S | |
13+
| StringLiterals.java:19:3:19:9 | "\\1234" | S4 | S4 | |
14+
| StringLiterals.java:20:3:20:9 | "\\0000" | \u00000 | \u00000 | |
15+
| StringLiterals.java:21:3:21:13 | "\\u0061567" | a567 | a567 | |
16+
| StringLiterals.java:22:3:22:13 | "\\u1234567" | \u1234567 | \u1234567 | |
17+
| StringLiterals.java:23:3:23:18 | "\\uaBcDeF\\u0aB1" | \uabcdeF\u0ab1 | \uabcdeF\u0ab1 | |
18+
| StringLiterals.java:24:3:24:16 | "\\uD800\\uDC00" | \ud800\udc00 | \ud800\udc00 | |
19+
| StringLiterals.java:25:3:25:16 | "\\uDBFF\\uDFFF" | \udbff\udfff | \udbff\udfff | |
20+
| StringLiterals.java:27:3:27:10 | "\\uD800" | \ufffd | \ufffd | |
21+
| StringLiterals.java:28:3:28:10 | "\\uDC00" | \ufffd | \ufffd | |
22+
| StringLiterals.java:29:3:29:31 | "hello\\uD800hello\\uDC00world" | hello\ufffdhello\ufffdworld | hello\ufffdhello\ufffdworld | |
23+
| StringLiterals.java:31:3:31:16 | "\\u005C\\u0022" | " | " | |
24+
| StringLiterals.java:32:8:32:20 | 2\\u0061\\u0022 | a | a | |
25+
| StringLiterals.java:37:3:39:5 | """ \t \n\t\ttest "text" and escaped \\u0022\n\t\t""" | test "text" and escaped "\n | test "text" and escaped "\n | text-block |
26+
| StringLiterals.java:41:3:43:5 | """\n\t\t\tindented\n\t\t""" | \tindented\n | \tindented\n | text-block |
27+
| StringLiterals.java:44:3:46:5 | """\n\tno indentation last line\n\t\t""" | no indentation last line\n | no indentation last line\n | text-block |
28+
| StringLiterals.java:47:3:49:7 | """\n\tindentation last line\n\t\t\\s""" | indentation last line\n\t | indentation last line\n\t | text-block |
29+
| StringLiterals.java:50:3:52:6 | """\n\t\t\tnot-indented\n\t\t\t""" | not-indented\n | not-indented\n | text-block |
30+
| StringLiterals.java:53:3:55:4 | """\n\t\tindented\n\t""" | \tindented\n | \tindented\n | text-block |
31+
| StringLiterals.java:56:4:58:5 | """\n\t\tnot-indented\n\t\t""" | not-indented\n | not-indented\n | text-block |
32+
| StringLiterals.java:59:3:62:6 | """\n\t\t spaces (only single space is trimmed)\n\t\t\ttab\n\t\t\t""" | spaces (only single space is trimmed)\ntab\n | spaces (only single space is trimmed)\ntab\n | text-block |
33+
| StringLiterals.java:63:3:64:22 | """\n\t\t\tend on same line""" | end on same line | end on same line | text-block |
34+
| StringLiterals.java:65:3:68:5 | """\n\t\ttrailing spaces ignored: \t \n\t\tnot ignored: \t \\s\n\t\t""" | trailing spaces ignored:\nnot ignored: \t \n | trailing spaces ignored:\nnot ignored: \t \n | text-block |
35+
| StringLiterals.java:69:3:70:18 | """\n\t\t3 quotes:""\\"""" | 3 quotes:""" | 3 quotes:""" | text-block |
36+
| StringLiterals.java:71:3:74:5 | """\n\t\tline \\\n\t\tcontinuation \\\n\t\t""" | line continuation | line continuation | text-block |
37+
| StringLiterals.java:75:3:79:5 | """\n\t\tExplicit line breaks:\\n\n\t\t\\r\\n\n\t\t\\r\n\t\t""" | Explicit line breaks:\n\n\r\n\n\r\n | Explicit line breaks:\n\n\r\n\n\r\n | text-block |
38+
| StringLiterals.java:82:10:84:16 | 2"\\u0022\n\t\ttest\n\t\t\\u0022\\uu0022" | test\n | test\n | |
39+
| StringLiterals.java:90:3:90:19 | "hello" + "world" | helloworld | helloworld | |
40+
| StringLiterals.java:91:3:92:20 | """\n\t\thello""" + "world" | helloworld | helloworld | text-block |
41+
| StringLiterals.java:93:10:93:12 | "a" | a | a | |
42+
| StringLiterals.java:94:3:94:5 | "a" | a | a | |
43+
| StringLiterals.java:95:3:95:5 | "a" | a | a | |
44+
| StringLiterals.java:96:7:96:9 | "a" | a | a | |
45+
| StringLiterals.java:97:3:97:5 | "a" | a | a | |
46+
| StringLiterals.java:98:10:98:12 | "a" | a | a | |
47+
| StringLiterals.java:99:3:99:5 | "a" | a | a | |
48+
| StringLiterals.java:100:9:100:11 | "a" | a | a | |
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import semmle.code.java.Expr
22

3-
from StringLiteral lit
4-
where lit.getFile().(CompilationUnit).fromSource()
5-
select lit, lit.getValue(), lit.getRepresentedString()
3+
from StringLiteral lit, string isTextBlock
4+
where
5+
lit.getFile().(CompilationUnit).fromSource() and
6+
if lit.isTextBlock() then isTextBlock = "text-block" else isTextBlock = ""
7+
select lit, lit.getValue(), lit.getRepresentedString(), isTextBlock

0 commit comments

Comments
 (0)