From d7a8f48c1c6caedd00512b10600d2631b4ee56cd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Jul 2026 10:11:27 +0000 Subject: [PATCH] Commit 3: Add test.cpp corpus wrapped in std::regex stubs; generate .expected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces cpp/ql/test/library-tests/regex/test.cpp with the Ruby regex corpus mechanically translated to C++ string literals and wrapped in std::regex construction calls using fully self-contained in-file stubs (no #include of any external/standard header). Stub surface: std::basic_regex constructor(const char*), constructor(const char*, int), assign(const char*) std::regex typedef for basic_regex std::regex_match / regex_search / regex_replace free functions 1:1 corpus mapping from regexp.rb: - All Ruby /regex/ literals translated to C++ "string" literals (each backslash doubled: /\d/ -> "\\d") - Dropped: /#{A}bc/ (Ruby string interpolation, no string-literal form) - Kept: a{,8}, .*m, \A, \z, \G, \h\H, (?'foo'...) — these are removed in commits 4 and 5 (keeping them here preserves 1:1 mapping) Also removes `abstract` from RegExp class in ParseRegExp.qll so that all StringLiterals are regex candidates (trivial syntactic gate; no dataflow). .expected generated by: codeql test run --learn --search-path=. cpp/ql/test/library-tests/regex/ (CodeQL CLI 2.26.1, bundled C/C++ extractor) All 2 tests passed. --- .../code/cpp/regex/internal/ParseRegExp.qll | 6 +- .../test/library-tests/regex/parse.expected | 487 ++++++++++++++++++ .../test/library-tests/regex/regexp.expected | 268 ++++++++++ cpp/ql/test/library-tests/regex/test.cpp | 107 ++++ 4 files changed, 867 insertions(+), 1 deletion(-) create mode 100644 cpp/ql/test/library-tests/regex/test.cpp diff --git a/cpp/ql/lib/semmle/code/cpp/regex/internal/ParseRegExp.qll b/cpp/ql/lib/semmle/code/cpp/regex/internal/ParseRegExp.qll index d34ec10eb53..bd7b2544a5b 100644 --- a/cpp/ql/lib/semmle/code/cpp/regex/internal/ParseRegExp.qll +++ b/cpp/ql/lib/semmle/code/cpp/regex/internal/ParseRegExp.qll @@ -11,8 +11,12 @@ private import semmle.code.cpp.exprs.Literal * A C++ string literal that contains a regular expression term, that is, either * a regular expression literal, or a string literal used in a context where * it is parsed as a regular expression. + * + * All string literals are considered potential regexes for now. Future work + * will restrict this to only string literals actually used as regular + * expressions (via construction-site flow analysis). */ -abstract class RegExp extends StringLiteral { +class RegExp extends StringLiteral { /** * Holds if this `RegExp` has the `s` flag for multi-line matching. */ diff --git a/cpp/ql/test/library-tests/regex/parse.expected b/cpp/ql/test/library-tests/regex/parse.expected index e69de29bb2d..f5e1a63fbd9 100644 --- a/cpp/ql/test/library-tests/regex/parse.expected +++ b/cpp/ql/test/library-tests/regex/parse.expected @@ -0,0 +1,487 @@ +test.cpp: +# 31| [RegExpConstant, RegExpNormalChar] abc + +# 34| [RegExpConstant, RegExpNormalChar] a + +# 34| [RegExpStar] a* +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 34| [RegExpSequence] a*b+c?d +#-----| 0 -> [RegExpStar] a* +#-----| 1 -> [RegExpPlus] b+ +#-----| 2 -> [RegExpOpt] c? +#-----| 3 -> [RegExpConstant, RegExpNormalChar] d + +# 34| [RegExpConstant, RegExpNormalChar] b + +# 34| [RegExpPlus] b+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] b + +# 34| [RegExpConstant, RegExpNormalChar] c + +# 34| [RegExpOpt] c? +#-----| 0 -> [RegExpConstant, RegExpNormalChar] c + +# 34| [RegExpConstant, RegExpNormalChar] d + +# 35| [RegExpConstant, RegExpNormalChar] a + +# 35| [RegExpRange] a{4,8} +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 36| [RegExpConstant, RegExpNormalChar] a + +# 36| [RegExpRange] a{,8} +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 37| [RegExpConstant, RegExpNormalChar] a + +# 37| [InfiniteRepetitionQuantifier, RegExpRange] a{3,} +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 38| [RegExpConstant, RegExpNormalChar] a + +# 38| [RegExpRange] a{7} +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 41| [RegExpConstant, RegExpNormalChar] foo + +# 41| [RegExpAlt] foo|bar +#-----| 0 -> [RegExpConstant, RegExpNormalChar] foo +#-----| 1 -> [RegExpConstant, RegExpNormalChar] bar + +# 41| [RegExpConstant, RegExpNormalChar] bar + +# 44| [RegExpCharacterClass] [abc] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b +#-----| 2 -> [RegExpConstant, RegExpNormalChar] c + +# 44| [RegExpConstant, RegExpNormalChar] a + +# 44| [RegExpConstant, RegExpNormalChar] b + +# 44| [RegExpConstant, RegExpNormalChar] c + +# 45| [RegExpCharacterClass] [a-fA-F0-9_] +#-----| 0 -> [RegExpCharacterRange] a-f +#-----| 1 -> [RegExpCharacterRange] A-F +#-----| 2 -> [RegExpCharacterRange] 0-9 +#-----| 3 -> [RegExpConstant, RegExpNormalChar] _ + +# 45| [RegExpConstant, RegExpNormalChar] a + +# 45| [RegExpCharacterRange] a-f +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] f + +# 45| [RegExpConstant, RegExpNormalChar] f + +# 45| [RegExpConstant, RegExpNormalChar] A + +# 45| [RegExpCharacterRange] A-F +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A +#-----| 1 -> [RegExpConstant, RegExpNormalChar] F + +# 45| [RegExpConstant, RegExpNormalChar] F + +# 45| [RegExpConstant, RegExpNormalChar] 0 + +# 45| [RegExpCharacterRange] 0-9 +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 0 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 + +# 45| [RegExpConstant, RegExpNormalChar] 9 + +# 45| [RegExpConstant, RegExpNormalChar] _ + +# 46| [RegExpCaret] \A + +# 46| [RegExpSequence] \A[+-]?\d+ +#-----| 0 -> [RegExpCaret] \A +#-----| 1 -> [RegExpOpt] [+-]? +#-----| 2 -> [RegExpPlus] \d+ + +# 46| [RegExpCharacterClass] [+-] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] + +#-----| 1 -> [RegExpConstant, RegExpNormalChar] - + +# 46| [RegExpOpt] [+-]? +#-----| 0 -> [RegExpCharacterClass] [+-] + +# 46| [RegExpConstant, RegExpNormalChar] + + +# 46| [RegExpConstant, RegExpNormalChar] - + +# 46| [RegExpCharacterClassEscape] \d + +# 46| [RegExpPlus] \d+ +#-----| 0 -> [RegExpCharacterClassEscape] \d + +# 47| [RegExpCharacterClass] [\w] +#-----| 0 -> [RegExpCharacterClassEscape] \w + +# 47| [RegExpPlus] [\w]+ +#-----| 0 -> [RegExpCharacterClass] [\w] + +# 47| [RegExpCharacterClassEscape] \w + +# 48| [RegExpConstant, RegExpEscape] \[ + +# 48| [RegExpSequence] \[\][123] +#-----| 0 -> [RegExpConstant, RegExpEscape] \[ +#-----| 1 -> [RegExpConstant, RegExpEscape] \] +#-----| 2 -> [RegExpCharacterClass] [123] + +# 48| [RegExpConstant, RegExpEscape] \] + +# 48| [RegExpCharacterClass] [123] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] 1 +#-----| 1 -> [RegExpConstant, RegExpNormalChar] 2 +#-----| 2 -> [RegExpConstant, RegExpNormalChar] 3 + +# 48| [RegExpConstant, RegExpNormalChar] 1 + +# 48| [RegExpConstant, RegExpNormalChar] 2 + +# 48| [RegExpConstant, RegExpNormalChar] 3 + +# 49| [RegExpCharacterClass] [^A-Z] +#-----| 0 -> [RegExpCharacterRange] A-Z + +# 49| [RegExpConstant, RegExpNormalChar] A + +# 49| [RegExpCharacterRange] A-Z +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A +#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z + +# 49| [RegExpConstant, RegExpNormalChar] Z + +# 50| [RegExpCharacterClass] []] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ] + +# 50| [RegExpConstant, RegExpNormalChar] ] + +# 51| [RegExpCharacterClass] [^]] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] ] + +# 51| [RegExpConstant, RegExpNormalChar] ] + +# 52| [RegExpCharacterClass] [^-] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] - + +# 52| [RegExpConstant, RegExpNormalChar] - + +# 53| [RegExpCharacterClass] [|] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] | + +# 53| [RegExpConstant, RegExpNormalChar] | + +# 56| [RegExpCharacterClass] [[a-f] +#-----| 0 -> [RegExpConstant, RegExpNormalChar] [ +#-----| 1 -> [RegExpCharacterRange] a-f + +# 56| [RegExpSequence] [[a-f]A-F] +#-----| 0 -> [RegExpCharacterClass] [[a-f] +#-----| 1 -> [RegExpConstant, RegExpNormalChar] A-F] + +# 56| [RegExpConstant, RegExpNormalChar] [ + +# 56| [RegExpConstant, RegExpNormalChar] a + +# 56| [RegExpCharacterRange] a-f +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] f + +# 56| [RegExpConstant, RegExpNormalChar] f + +# 56| [RegExpConstant, RegExpNormalChar] A-F] + +# 59| [RegExpDot] . + +# 59| [RegExpStar] .* +#-----| 0 -> [RegExpDot] . + +# 60| [RegExpDot] . + +# 60| [RegExpStar] .* +#-----| 0 -> [RegExpDot] . + +# 61| [RegExpCharacterClassEscape] \w + +# 61| [RegExpPlus] \w+ +#-----| 0 -> [RegExpCharacterClassEscape] \w + +# 61| [RegExpSequence] \w+\W +#-----| 0 -> [RegExpPlus] \w+ +#-----| 1 -> [RegExpCharacterClassEscape] \W + +# 61| [RegExpCharacterClassEscape] \W + +# 62| [RegExpCharacterClassEscape] \s + +# 62| [RegExpSequence] \s\S +#-----| 0 -> [RegExpCharacterClassEscape] \s +#-----| 1 -> [RegExpCharacterClassEscape] \S + +# 62| [RegExpCharacterClassEscape] \S + +# 63| [RegExpCharacterClassEscape] \d + +# 63| [RegExpSequence] \d\D +#-----| 0 -> [RegExpCharacterClassEscape] \d +#-----| 1 -> [RegExpCharacterClassEscape] \D + +# 63| [RegExpCharacterClassEscape] \D + +# 64| [RegExpCharacterClassEscape] \h + +# 64| [RegExpSequence] \h\H +#-----| 0 -> [RegExpCharacterClassEscape] \h +#-----| 1 -> [RegExpCharacterClassEscape] \H + +# 64| [RegExpCharacterClassEscape] \H + +# 65| [RegExpConstant, RegExpEscape] \n + +# 65| [RegExpSequence] \n\r\t +#-----| 0 -> [RegExpConstant, RegExpEscape] \n +#-----| 1 -> [RegExpConstant, RegExpEscape] \r +#-----| 2 -> [RegExpConstant, RegExpEscape] \t + +# 65| [RegExpConstant, RegExpEscape] \r + +# 65| [RegExpConstant, RegExpEscape] \t + +# 68| [RegExpSpecialChar] \G + +# 68| [RegExpSequence] \Gabc +#-----| 0 -> [RegExpSpecialChar] \G +#-----| 1 -> [RegExpConstant, RegExpNormalChar] abc + +# 68| [RegExpConstant, RegExpNormalChar] abc + +# 69| [RegExpSpecialChar] \b + +# 69| [RegExpSequence] \b!a\B +#-----| 0 -> [RegExpSpecialChar] \b +#-----| 1 -> [RegExpConstant, RegExpNormalChar] !a +#-----| 2 -> [RegExpNonWordBoundary] \B + +# 69| [RegExpConstant, RegExpNormalChar] !a + +# 69| [RegExpNonWordBoundary] \B + +# 72| [RegExpGroup] (foo) +#-----| 0 -> [RegExpConstant, RegExpNormalChar] foo + +# 72| [RegExpStar] (foo)* +#-----| 0 -> [RegExpGroup] (foo) + +# 72| [RegExpSequence] (foo)*bar +#-----| 0 -> [RegExpStar] (foo)* +#-----| 1 -> [RegExpConstant, RegExpNormalChar] bar + +# 72| [RegExpConstant, RegExpNormalChar] foo + +# 72| [RegExpConstant, RegExpNormalChar] bar + +# 73| [RegExpConstant, RegExpNormalChar] fo + +# 73| [RegExpSequence] fo(o|b)ar +#-----| 0 -> [RegExpConstant, RegExpNormalChar] fo +#-----| 1 -> [RegExpGroup] (o|b) +#-----| 2 -> [RegExpConstant, RegExpNormalChar] ar + +# 73| [RegExpGroup] (o|b) +#-----| 0 -> [RegExpAlt] o|b + +# 73| [RegExpConstant, RegExpNormalChar] o + +# 73| [RegExpAlt] o|b +#-----| 0 -> [RegExpConstant, RegExpNormalChar] o +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b + +# 73| [RegExpConstant, RegExpNormalChar] b + +# 73| [RegExpConstant, RegExpNormalChar] ar + +# 74| [RegExpGroup] (a|b|cd) +#-----| 0 -> [RegExpAlt] a|b|cd + +# 74| [RegExpSequence] (a|b|cd)e +#-----| 0 -> [RegExpGroup] (a|b|cd) +#-----| 1 -> [RegExpConstant, RegExpNormalChar] e + +# 74| [RegExpConstant, RegExpNormalChar] a + +# 74| [RegExpAlt] a|b|cd +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] b +#-----| 2 -> [RegExpConstant, RegExpNormalChar] cd + +# 74| [RegExpConstant, RegExpNormalChar] b + +# 74| [RegExpConstant, RegExpNormalChar] cd + +# 74| [RegExpConstant, RegExpNormalChar] e + +# 75| [RegExpGroup] (?::+) +#-----| 0 -> [RegExpPlus] :+ + +# 75| [RegExpSequence] (?::+)\w +#-----| 0 -> [RegExpGroup] (?::+) +#-----| 1 -> [RegExpCharacterClassEscape] \w + +# 75| [RegExpConstant, RegExpNormalChar] : + +# 75| [RegExpPlus] :+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] : + +# 75| [RegExpCharacterClassEscape] \w + +# 78| [RegExpGroup] (?\w+) +#-----| 0 -> [RegExpPlus] \w+ + +# 78| [RegExpCharacterClassEscape] \w + +# 78| [RegExpPlus] \w+ +#-----| 0 -> [RegExpCharacterClassEscape] \w + +# 79| [RegExpGroup] (?'foo'fo+) +#-----| 0 -> [RegExpSequence] fo+ + +# 79| [RegExpConstant, RegExpNormalChar] f + +# 79| [RegExpSequence] fo+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] f +#-----| 1 -> [RegExpPlus] o+ + +# 79| [RegExpConstant, RegExpNormalChar] o + +# 79| [RegExpPlus] o+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] o + +# 82| [RegExpGroup] (a+) +#-----| 0 -> [RegExpPlus] a+ + +# 82| [RegExpSequence] (a+)b+\1 +#-----| 0 -> [RegExpGroup] (a+) +#-----| 1 -> [RegExpPlus] b+ +#-----| 2 -> [RegExpBackRef] \1 + +# 82| [RegExpConstant, RegExpNormalChar] a + +# 82| [RegExpPlus] a+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a + +# 82| [RegExpConstant, RegExpNormalChar] b + +# 82| [RegExpPlus] b+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] b + +# 82| [RegExpBackRef] \1 + +# 83| [RegExpGroup] (?q+) +#-----| 0 -> [RegExpPlus] q+ + +# 83| [RegExpSequence] (?q+)\s+\k+ +#-----| 0 -> [RegExpGroup] (?q+) +#-----| 1 -> [RegExpPlus] \s+ +#-----| 2 -> [RegExpPlus] \k+ + +# 83| [RegExpConstant, RegExpNormalChar] q + +# 83| [RegExpPlus] q+ +#-----| 0 -> [RegExpConstant, RegExpNormalChar] q + +# 83| [RegExpCharacterClassEscape] \s + +# 83| [RegExpPlus] \s+ +#-----| 0 -> [RegExpCharacterClassEscape] \s + +# 83| [RegExpBackRef] \k + +# 83| [RegExpPlus] \k+ +#-----| 0 -> [RegExpBackRef] \k + +# 86| [RegExpNamedCharacterProperty] \p{Word} + +# 86| [RegExpStar] \p{Word}* +#-----| 0 -> [RegExpNamedCharacterProperty] \p{Word} + +# 87| [RegExpNamedCharacterProperty] \P{Digit} + +# 87| [RegExpPlus] \P{Digit}+ +#-----| 0 -> [RegExpNamedCharacterProperty] \P{Digit} + +# 88| [RegExpNamedCharacterProperty] \p{^Alnum} + +# 88| [RegExpRange] \p{^Alnum}{2,3} +#-----| 0 -> [RegExpNamedCharacterProperty] \p{^Alnum} + +# 89| [RegExpCharacterClass] [a-f\p{Digit}] +#-----| 0 -> [RegExpCharacterRange] a-f +#-----| 1 -> [RegExpNamedCharacterProperty] \p{Digit} + +# 89| [RegExpPlus] [a-f\p{Digit}]+ +#-----| 0 -> [RegExpCharacterClass] [a-f\p{Digit}] + +# 89| [RegExpConstant, RegExpNormalChar] a + +# 89| [RegExpCharacterRange] a-f +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] f + +# 89| [RegExpConstant, RegExpNormalChar] f + +# 89| [RegExpNamedCharacterProperty] \p{Digit} + +# 92| [RegExpCharacterClass] [[:alpha:]] +#-----| 0 -> [RegExpNamedCharacterProperty] [:alpha:] + +# 92| [RegExpSequence] [[:alpha:]][[:digit:]] +#-----| 0 -> [RegExpCharacterClass] [[:alpha:]] +#-----| 1 -> [RegExpCharacterClass] [[:digit:]] + +# 92| [RegExpNamedCharacterProperty] [:alpha:] + +# 92| [RegExpCharacterClass] [[:digit:]] +#-----| 0 -> [RegExpNamedCharacterProperty] [:digit:] + +# 92| [RegExpNamedCharacterProperty] [:digit:] + +# 95| [RegExpCharacterClass] [[:alpha:][:digit:]] +#-----| 0 -> [RegExpNamedCharacterProperty] [:alpha:] +#-----| 1 -> [RegExpNamedCharacterProperty] [:digit:] + +# 95| [RegExpNamedCharacterProperty] [:alpha:] + +# 95| [RegExpNamedCharacterProperty] [:digit:] + +# 98| [RegExpCharacterClass] [A-F[:digit:]a-f] +#-----| 0 -> [RegExpCharacterRange] A-F +#-----| 1 -> [RegExpNamedCharacterProperty] [:digit:] +#-----| 2 -> [RegExpCharacterRange] a-f + +# 98| [RegExpConstant, RegExpNormalChar] A + +# 98| [RegExpCharacterRange] A-F +#-----| 0 -> [RegExpConstant, RegExpNormalChar] A +#-----| 1 -> [RegExpConstant, RegExpNormalChar] F + +# 98| [RegExpConstant, RegExpNormalChar] F + +# 98| [RegExpNamedCharacterProperty] [:digit:] + +# 98| [RegExpConstant, RegExpNormalChar] a + +# 98| [RegExpCharacterRange] a-f +#-----| 0 -> [RegExpConstant, RegExpNormalChar] a +#-----| 1 -> [RegExpConstant, RegExpNormalChar] f + +# 98| [RegExpConstant, RegExpNormalChar] f + +# 101| [RegExpNamedCharacterProperty] [:digit:] + +# 106| [RegExpConstant, RegExpEscape] \u{987 diff --git a/cpp/ql/test/library-tests/regex/regexp.expected b/cpp/ql/test/library-tests/regex/regexp.expected index e69de29bb2d..5842f67797f 100644 --- a/cpp/ql/test/library-tests/regex/regexp.expected +++ b/cpp/ql/test/library-tests/regex/regexp.expected @@ -0,0 +1,268 @@ +groupName +| test.cpp:78:21:78:30 | (?\\w+) | id | +| test.cpp:79:21:79:31 | (?'foo'fo+) | foo | +| test.cpp:83:23:83:32 | (?q+) | qux | +groupNumber +| test.cpp:72:22:72:26 | (foo) | 1 | +| test.cpp:73:24:73:28 | (o\|b) | 1 | +| test.cpp:74:22:74:29 | (a\|b\|cd) | 1 | +| test.cpp:79:21:79:31 | (?'foo'fo+) | 1 | +| test.cpp:82:23:82:26 | (a+) | 1 | +term +| test.cpp:31:21:31:23 | abc | RegExpConstant,RegExpNormalChar | +| test.cpp:34:22:34:22 | a | RegExpConstant,RegExpNormalChar | +| test.cpp:34:22:34:23 | a* | RegExpStar | +| test.cpp:34:22:34:28 | a*b+c?d | RegExpSequence | +| test.cpp:34:24:34:24 | b | RegExpConstant,RegExpNormalChar | +| test.cpp:34:24:34:25 | b+ | RegExpPlus | +| test.cpp:34:26:34:26 | c | RegExpConstant,RegExpNormalChar | +| test.cpp:34:26:34:27 | c? | RegExpOpt | +| test.cpp:34:28:34:28 | d | RegExpConstant,RegExpNormalChar | +| test.cpp:35:22:35:22 | a | RegExpConstant,RegExpNormalChar | +| test.cpp:35:22:35:27 | a{4,8} | RegExpRange | +| test.cpp:36:22:36:22 | a | RegExpConstant,RegExpNormalChar | +| test.cpp:36:22:36:26 | a{,8} | RegExpRange | +| test.cpp:37:22:37:22 | a | RegExpConstant,RegExpNormalChar | +| test.cpp:37:22:37:26 | a{3,} | InfiniteRepetitionQuantifier,RegExpRange | +| test.cpp:38:22:38:22 | a | RegExpConstant,RegExpNormalChar | +| test.cpp:38:22:38:25 | a{7} | RegExpRange | +| test.cpp:41:21:41:23 | foo | RegExpConstant,RegExpNormalChar | +| test.cpp:41:21:41:27 | foo\|bar | RegExpAlt | +| test.cpp:41:25:41:27 | bar | RegExpConstant,RegExpNormalChar | +| test.cpp:44:21:44:25 | [abc] | RegExpCharacterClass | +| test.cpp:44:22:44:22 | a | RegExpConstant,RegExpNormalChar | +| test.cpp:44:23:44:23 | b | RegExpConstant,RegExpNormalChar | +| test.cpp:44:24:44:24 | c | RegExpConstant,RegExpNormalChar | +| test.cpp:45:21:45:32 | [a-fA-F0-9_] | RegExpCharacterClass | +| test.cpp:45:22:45:22 | a | RegExpConstant,RegExpNormalChar | +| test.cpp:45:22:45:24 | a-f | RegExpCharacterRange | +| test.cpp:45:24:45:24 | f | RegExpConstant,RegExpNormalChar | +| test.cpp:45:25:45:25 | A | RegExpConstant,RegExpNormalChar | +| test.cpp:45:25:45:27 | A-F | RegExpCharacterRange | +| test.cpp:45:27:45:27 | F | RegExpConstant,RegExpNormalChar | +| test.cpp:45:28:45:28 | 0 | RegExpConstant,RegExpNormalChar | +| test.cpp:45:28:45:30 | 0-9 | RegExpCharacterRange | +| test.cpp:45:30:45:30 | 9 | RegExpConstant,RegExpNormalChar | +| test.cpp:45:31:45:31 | _ | RegExpConstant,RegExpNormalChar | +| test.cpp:46:21:46:22 | \\A | RegExpCaret | +| test.cpp:46:21:46:30 | \\A[+-]?\\d+ | RegExpSequence | +| test.cpp:46:23:46:26 | [+-] | RegExpCharacterClass | +| test.cpp:46:23:46:27 | [+-]? | RegExpOpt | +| test.cpp:46:24:46:24 | + | RegExpConstant,RegExpNormalChar | +| test.cpp:46:25:46:25 | - | RegExpConstant,RegExpNormalChar | +| test.cpp:46:28:46:29 | \\d | RegExpCharacterClassEscape | +| test.cpp:46:28:46:30 | \\d+ | RegExpPlus | +| test.cpp:47:21:47:24 | [\\w] | RegExpCharacterClass | +| test.cpp:47:21:47:25 | [\\w]+ | RegExpPlus | +| test.cpp:47:22:47:23 | \\w | RegExpCharacterClassEscape | +| test.cpp:48:21:48:22 | \\[ | RegExpConstant,RegExpEscape | +| test.cpp:48:21:48:29 | \\[\\][123] | RegExpSequence | +| test.cpp:48:23:48:24 | \\] | RegExpConstant,RegExpEscape | +| test.cpp:48:25:48:29 | [123] | RegExpCharacterClass | +| test.cpp:48:26:48:26 | 1 | RegExpConstant,RegExpNormalChar | +| test.cpp:48:27:48:27 | 2 | RegExpConstant,RegExpNormalChar | +| test.cpp:48:28:48:28 | 3 | RegExpConstant,RegExpNormalChar | +| test.cpp:49:21:49:26 | [^A-Z] | RegExpCharacterClass | +| test.cpp:49:23:49:23 | A | RegExpConstant,RegExpNormalChar | +| test.cpp:49:23:49:25 | A-Z | RegExpCharacterRange | +| test.cpp:49:25:49:25 | Z | RegExpConstant,RegExpNormalChar | +| test.cpp:50:21:50:23 | []] | RegExpCharacterClass | +| test.cpp:50:22:50:22 | ] | RegExpConstant,RegExpNormalChar | +| test.cpp:51:21:51:24 | [^]] | RegExpCharacterClass | +| test.cpp:51:23:51:23 | ] | RegExpConstant,RegExpNormalChar | +| test.cpp:52:21:52:24 | [^-] | RegExpCharacterClass | +| test.cpp:52:23:52:23 | - | RegExpConstant,RegExpNormalChar | +| test.cpp:53:22:53:24 | [\|] | RegExpCharacterClass | +| test.cpp:53:23:53:23 | \| | RegExpConstant,RegExpNormalChar | +| test.cpp:56:24:56:29 | [[a-f] | RegExpCharacterClass | +| test.cpp:56:24:56:33 | [[a-f]A-F] | RegExpSequence | +| test.cpp:56:25:56:25 | [ | RegExpConstant,RegExpNormalChar | +| test.cpp:56:26:56:26 | a | RegExpConstant,RegExpNormalChar | +| test.cpp:56:26:56:28 | a-f | RegExpCharacterRange | +| test.cpp:56:28:56:28 | f | RegExpConstant,RegExpNormalChar | +| test.cpp:56:30:56:33 | A-F] | RegExpConstant,RegExpNormalChar | +| test.cpp:59:23:59:23 | . | RegExpDot | +| test.cpp:59:23:59:24 | .* | RegExpStar | +| test.cpp:60:24:60:24 | . | RegExpDot | +| test.cpp:60:24:60:25 | .* | RegExpStar | +| test.cpp:61:23:61:24 | \\w | RegExpCharacterClassEscape | +| test.cpp:61:23:61:25 | \\w+ | RegExpPlus | +| test.cpp:61:23:61:27 | \\w+\\W | RegExpSequence | +| test.cpp:61:26:61:27 | \\W | RegExpCharacterClassEscape | +| test.cpp:62:23:62:24 | \\s | RegExpCharacterClassEscape | +| test.cpp:62:23:62:26 | \\s\\S | RegExpSequence | +| test.cpp:62:25:62:26 | \\S | RegExpCharacterClassEscape | +| test.cpp:63:23:63:24 | \\d | RegExpCharacterClassEscape | +| test.cpp:63:23:63:26 | \\d\\D | RegExpSequence | +| test.cpp:63:25:63:26 | \\D | RegExpCharacterClassEscape | +| test.cpp:64:23:64:24 | \\h | RegExpCharacterClassEscape | +| test.cpp:64:23:64:26 | \\h\\H | RegExpSequence | +| test.cpp:64:25:64:26 | \\H | RegExpCharacterClassEscape | +| test.cpp:65:23:65:24 | \\n | RegExpConstant,RegExpEscape | +| test.cpp:65:23:65:28 | \\n\\r\\t | RegExpSequence | +| test.cpp:65:25:65:26 | \\r | RegExpConstant,RegExpEscape | +| test.cpp:65:27:65:28 | \\t | RegExpConstant,RegExpEscape | +| test.cpp:68:22:68:23 | \\G | RegExpSpecialChar | +| test.cpp:68:22:68:26 | \\Gabc | RegExpSequence | +| test.cpp:68:24:68:26 | abc | RegExpConstant,RegExpNormalChar | +| test.cpp:69:22:69:23 | \\b | RegExpSpecialChar | +| test.cpp:69:22:69:27 | \\b!a\\B | RegExpSequence | +| test.cpp:69:24:69:25 | !a | RegExpConstant,RegExpNormalChar | +| test.cpp:69:26:69:27 | \\B | RegExpNonWordBoundary | +| test.cpp:72:22:72:26 | (foo) | RegExpGroup | +| test.cpp:72:22:72:27 | (foo)* | RegExpStar | +| test.cpp:72:22:72:30 | (foo)*bar | RegExpSequence | +| test.cpp:72:23:72:25 | foo | RegExpConstant,RegExpNormalChar | +| test.cpp:72:28:72:30 | bar | RegExpConstant,RegExpNormalChar | +| test.cpp:73:22:73:23 | fo | RegExpConstant,RegExpNormalChar | +| test.cpp:73:22:73:30 | fo(o\|b)ar | RegExpSequence | +| test.cpp:73:24:73:28 | (o\|b) | RegExpGroup | +| test.cpp:73:25:73:25 | o | RegExpConstant,RegExpNormalChar | +| test.cpp:73:25:73:27 | o\|b | RegExpAlt | +| test.cpp:73:27:73:27 | b | RegExpConstant,RegExpNormalChar | +| test.cpp:73:29:73:30 | ar | RegExpConstant,RegExpNormalChar | +| test.cpp:74:22:74:29 | (a\|b\|cd) | RegExpGroup | +| test.cpp:74:22:74:30 | (a\|b\|cd)e | RegExpSequence | +| test.cpp:74:23:74:23 | a | RegExpConstant,RegExpNormalChar | +| test.cpp:74:23:74:28 | a\|b\|cd | RegExpAlt | +| test.cpp:74:25:74:25 | b | RegExpConstant,RegExpNormalChar | +| test.cpp:74:27:74:28 | cd | RegExpConstant,RegExpNormalChar | +| test.cpp:74:30:74:30 | e | RegExpConstant,RegExpNormalChar | +| test.cpp:75:22:75:27 | (?::+) | RegExpGroup | +| test.cpp:75:22:75:29 | (?::+)\\w | RegExpSequence | +| test.cpp:75:25:75:25 | : | RegExpConstant,RegExpNormalChar | +| test.cpp:75:25:75:26 | :+ | RegExpPlus | +| test.cpp:75:28:75:29 | \\w | RegExpCharacterClassEscape | +| test.cpp:78:21:78:30 | (?\\w+) | RegExpGroup | +| test.cpp:78:27:78:28 | \\w | RegExpCharacterClassEscape | +| test.cpp:78:27:78:29 | \\w+ | RegExpPlus | +| test.cpp:79:21:79:31 | (?'foo'fo+) | RegExpGroup | +| test.cpp:79:28:79:28 | f | RegExpConstant,RegExpNormalChar | +| test.cpp:79:28:79:30 | fo+ | RegExpSequence | +| test.cpp:79:29:79:29 | o | RegExpConstant,RegExpNormalChar | +| test.cpp:79:29:79:30 | o+ | RegExpPlus | +| test.cpp:82:23:82:26 | (a+) | RegExpGroup | +| test.cpp:82:23:82:30 | (a+)b+\\1 | RegExpSequence | +| test.cpp:82:24:82:24 | a | RegExpConstant,RegExpNormalChar | +| test.cpp:82:24:82:25 | a+ | RegExpPlus | +| test.cpp:82:27:82:27 | b | RegExpConstant,RegExpNormalChar | +| test.cpp:82:27:82:28 | b+ | RegExpPlus | +| test.cpp:82:29:82:30 | \\1 | RegExpBackRef | +| test.cpp:83:23:83:32 | (?q+) | RegExpGroup | +| test.cpp:83:23:83:43 | (?q+)\\s+\\k+ | RegExpSequence | +| test.cpp:83:30:83:30 | q | RegExpConstant,RegExpNormalChar | +| test.cpp:83:30:83:31 | q+ | RegExpPlus | +| test.cpp:83:33:83:34 | \\s | RegExpCharacterClassEscape | +| test.cpp:83:33:83:35 | \\s+ | RegExpPlus | +| test.cpp:83:36:83:42 | \\k | RegExpBackRef | +| test.cpp:83:36:83:43 | \\k+ | RegExpPlus | +| test.cpp:86:23:86:30 | \\p{Word} | RegExpNamedCharacterProperty | +| test.cpp:86:23:86:31 | \\p{Word}* | RegExpStar | +| test.cpp:87:23:87:31 | \\P{Digit} | RegExpNamedCharacterProperty | +| test.cpp:87:23:87:32 | \\P{Digit}+ | RegExpPlus | +| test.cpp:88:23:88:32 | \\p{^Alnum} | RegExpNamedCharacterProperty | +| test.cpp:88:23:88:37 | \\p{^Alnum}{2,3} | RegExpRange | +| test.cpp:89:23:89:36 | [a-f\\p{Digit}] | RegExpCharacterClass | +| test.cpp:89:23:89:37 | [a-f\\p{Digit}]+ | RegExpPlus | +| test.cpp:89:24:89:24 | a | RegExpConstant,RegExpNormalChar | +| test.cpp:89:24:89:26 | a-f | RegExpCharacterRange | +| test.cpp:89:26:89:26 | f | RegExpConstant,RegExpNormalChar | +| test.cpp:89:27:89:35 | \\p{Digit} | RegExpNamedCharacterProperty | +| test.cpp:92:24:92:34 | [[:alpha:]] | RegExpCharacterClass | +| test.cpp:92:24:92:45 | [[:alpha:]][[:digit:]] | RegExpSequence | +| test.cpp:92:25:92:33 | [:alpha:] | RegExpNamedCharacterProperty | +| test.cpp:92:35:92:45 | [[:digit:]] | RegExpCharacterClass | +| test.cpp:92:36:92:44 | [:digit:] | RegExpNamedCharacterProperty | +| test.cpp:95:24:95:43 | [[:alpha:][:digit:]] | RegExpCharacterClass | +| test.cpp:95:25:95:33 | [:alpha:] | RegExpNamedCharacterProperty | +| test.cpp:95:34:95:42 | [:digit:] | RegExpNamedCharacterProperty | +| test.cpp:98:24:98:40 | [A-F[:digit:]a-f] | RegExpCharacterClass | +| test.cpp:98:25:98:25 | A | RegExpConstant,RegExpNormalChar | +| test.cpp:98:25:98:27 | A-F | RegExpCharacterRange | +| test.cpp:98:27:98:27 | F | RegExpConstant,RegExpNormalChar | +| test.cpp:98:28:98:36 | [:digit:] | RegExpNamedCharacterProperty | +| test.cpp:98:37:98:37 | a | RegExpConstant,RegExpNormalChar | +| test.cpp:98:37:98:39 | a-f | RegExpCharacterRange | +| test.cpp:98:39:98:39 | f | RegExpConstant,RegExpNormalChar | +| test.cpp:101:24:101:32 | [:digit:] | RegExpNamedCharacterProperty | +| test.cpp:106:21:106:26 | \\u{987 | RegExpConstant,RegExpEscape | +regExpNormalCharValue +| test.cpp:31:21:31:23 | abc | abc | +| test.cpp:34:22:34:22 | a | a | +| test.cpp:34:24:34:24 | b | b | +| test.cpp:34:26:34:26 | c | c | +| test.cpp:34:28:34:28 | d | d | +| test.cpp:35:22:35:22 | a | a | +| test.cpp:36:22:36:22 | a | a | +| test.cpp:37:22:37:22 | a | a | +| test.cpp:38:22:38:22 | a | a | +| test.cpp:41:21:41:23 | foo | foo | +| test.cpp:41:25:41:27 | bar | bar | +| test.cpp:44:22:44:22 | a | a | +| test.cpp:44:23:44:23 | b | b | +| test.cpp:44:24:44:24 | c | c | +| test.cpp:45:22:45:22 | a | a | +| test.cpp:45:24:45:24 | f | f | +| test.cpp:45:25:45:25 | A | A | +| test.cpp:45:27:45:27 | F | F | +| test.cpp:45:28:45:28 | 0 | 0 | +| test.cpp:45:30:45:30 | 9 | 9 | +| test.cpp:45:31:45:31 | _ | _ | +| test.cpp:46:24:46:24 | + | + | +| test.cpp:46:25:46:25 | - | - | +| test.cpp:46:28:46:29 | \\d | d | +| test.cpp:47:22:47:23 | \\w | w | +| test.cpp:48:21:48:22 | \\[ | [ | +| test.cpp:48:23:48:24 | \\] | ] | +| test.cpp:48:26:48:26 | 1 | 1 | +| test.cpp:48:27:48:27 | 2 | 2 | +| test.cpp:48:28:48:28 | 3 | 3 | +| test.cpp:49:23:49:23 | A | A | +| test.cpp:49:25:49:25 | Z | Z | +| test.cpp:50:22:50:22 | ] | ] | +| test.cpp:51:23:51:23 | ] | ] | +| test.cpp:52:23:52:23 | - | - | +| test.cpp:53:23:53:23 | \| | \| | +| test.cpp:56:25:56:25 | [ | [ | +| test.cpp:56:26:56:26 | a | a | +| test.cpp:56:28:56:28 | f | f | +| test.cpp:56:30:56:33 | A-F] | A-F] | +| test.cpp:61:23:61:24 | \\w | w | +| test.cpp:61:26:61:27 | \\W | W | +| test.cpp:62:23:62:24 | \\s | s | +| test.cpp:62:25:62:26 | \\S | S | +| test.cpp:63:23:63:24 | \\d | d | +| test.cpp:63:25:63:26 | \\D | D | +| test.cpp:64:23:64:24 | \\h | h | +| test.cpp:64:25:64:26 | \\H | H | +| test.cpp:65:23:65:24 | \\n | \n | +| test.cpp:65:25:65:26 | \\r | \r | +| test.cpp:65:27:65:28 | \\t | \t | +| test.cpp:68:24:68:26 | abc | abc | +| test.cpp:69:24:69:25 | !a | !a | +| test.cpp:72:23:72:25 | foo | foo | +| test.cpp:72:28:72:30 | bar | bar | +| test.cpp:73:22:73:23 | fo | fo | +| test.cpp:73:25:73:25 | o | o | +| test.cpp:73:27:73:27 | b | b | +| test.cpp:73:29:73:30 | ar | ar | +| test.cpp:74:23:74:23 | a | a | +| test.cpp:74:25:74:25 | b | b | +| test.cpp:74:27:74:28 | cd | cd | +| test.cpp:74:30:74:30 | e | e | +| test.cpp:75:25:75:25 | : | : | +| test.cpp:75:28:75:29 | \\w | w | +| test.cpp:78:27:78:28 | \\w | w | +| test.cpp:79:28:79:28 | f | f | +| test.cpp:79:29:79:29 | o | o | +| test.cpp:82:24:82:24 | a | a | +| test.cpp:82:27:82:27 | b | b | +| test.cpp:83:30:83:30 | q | q | +| test.cpp:83:33:83:34 | \\s | s | +| test.cpp:89:24:89:24 | a | a | +| test.cpp:89:26:89:26 | f | f | +| test.cpp:98:25:98:25 | A | A | +| test.cpp:98:27:98:27 | F | F | +| test.cpp:98:37:98:37 | a | a | +| test.cpp:98:39:98:39 | f | f | +| test.cpp:106:21:106:26 | \\u{987 | \u0987 | diff --git a/cpp/ql/test/library-tests/regex/test.cpp b/cpp/ql/test/library-tests/regex/test.cpp new file mode 100644 index 00000000000..df580fb10eb --- /dev/null +++ b/cpp/ql/test/library-tests/regex/test.cpp @@ -0,0 +1,107 @@ +// Minimal stubs for std::regex surface — no #include of any external header. +// Provides just enough of the std:: regex API that the C++ extractor +// creates StringLiteral nodes for each regex pattern, using real qualified +// names so a future flow-config PR can identify them unchanged. +namespace std { + template + class basic_regex { + public: + basic_regex(const char *s) {} + basic_regex(const char *s, int flags) {} + basic_regex &assign(const char *s) { return *this; } + }; + typedef basic_regex regex; + + template + bool regex_match(const char *s, const basic_regex &re) { return false; } + + template + bool regex_search(const char *s, const basic_regex &re) { return false; } + + template + const char *regex_replace(const char *s, const basic_regex &re, + const char *fmt) { return s; } +} // namespace std + +void test() { + // Empty + std::regex r_empty(""); + + // Basic sequence + std::regex r_abc("abc"); + + // Repetition + std::regex r_rep1("a*b+c?d"); + std::regex r_rep2("a{4,8}"); + std::regex r_rep3("a{,8}"); + std::regex r_rep4("a{3,}"); + std::regex r_rep5("a{7}"); + + // Alternation + std::regex r_alt("foo|bar"); + + // Character classes + std::regex r_cc1("[abc]"); + std::regex r_cc2("[a-fA-F0-9_]"); + std::regex r_cc3("\\A[+-]?\\d+"); + std::regex r_cc4("[\\w]+"); + std::regex r_cc5("\\[\\][123]"); + std::regex r_cc6("[^A-Z]"); + std::regex r_cc7("[]]"); // MRI gives a warning, but accepts this as matching ']' + std::regex r_cc8("[^]]"); // MRI gives a warning, but accepts this as matching anything except ']' + std::regex r_cc9("[^-]"); + std::regex r_cc10("[|]"); + + // Nested character classes (BAD - not parsed correctly) + std::regex r_nested("[[a-f]A-F]"); + + // Meta-character classes + std::regex r_meta1(".*"); + std::regex r_meta1m(".*"); // /.*/m mode variant — mode flags are constructor args in C++ + std::regex r_meta2("\\w+\\W"); + std::regex r_meta3("\\s\\S"); + std::regex r_meta4("\\d\\D"); + std::regex r_meta5("\\h\\H"); + std::regex r_meta6("\\n\\r\\t"); + + // Anchors + std::regex r_anc1("\\Gabc"); + std::regex r_anc2("\\b!a\\B"); + + // Groups + std::regex r_grp1("(foo)*bar"); + std::regex r_grp2("fo(o|b)ar"); + std::regex r_grp3("(a|b|cd)e"); + std::regex r_grp4("(?::+)\\w"); // Non-capturing group matching colons + + // Named groups + std::regex r_ng1("(?\\w+)"); + std::regex r_ng2("(?'foo'fo+)"); // single-quote named-group form + + // Backreferences + std::regex r_bref1("(a+)b+\\1"); + std::regex r_bref2("(?q+)\\s+\\k+"); + + // Named character properties using the p-style syntax + std::regex r_prop1("\\p{Word}*"); + std::regex r_prop2("\\P{Digit}+"); + std::regex r_prop3("\\p{^Alnum}{2,3}"); + std::regex r_prop4("[a-f\\p{Digit}]+"); // Also valid inside character classes + + // Two separate character classes, each containing a single POSIX bracket expression + std::regex r_posix1("[[:alpha:]][[:digit:]]"); + + // A single character class containing two POSIX bracket expressions + std::regex r_posix2("[[:alpha:][:digit:]]"); + + // A single character class containing two ranges and one POSIX bracket expression + std::regex r_posix3("[A-F[:digit:]a-f]"); + + // *Not* a POSIX bracket expression; just a regular character class. + std::regex r_posix4("[:digit:]"); + + // Dropped: /#{A}bc/ — Ruby string interpolation, no C++ string-literal form. + + // unicode: \u{9879} in C++ (Ruby unicode escape syntax) + std::regex r_uni("\\u{9879}"); +}