Add corpus cases: bare [:alpha:], mid-pattern a[🅱️]c, POSIX class as
range endpoint [[:alpha:]-z], malformed [[:alpha], leading literal ]
combined with a POSIX class []a[:alpha:]], three POSIX classes in one
class, additional names [[:xdigit:]] / [[:blank:]] / [[:cntrl:]] /
[[:graph:]], and the integration case combining all of the above.
The regenerated parse.expected reveals genuine mis-parses that this
commit deliberately records (fixes in Commit 6):
- unnested [:alpha:] and [🅱️] are treated as RegExpNamedCharacterProperty
even though POSIX brackets are only valid inside a character class,
- [[:alpha:]-z] emits a spurious [RegExpCharacterRange] ":]-z" instead
of a POSIX class + literal '-' + 'z'.
Bundle: github/codeql-action codeql-bundle-v2.26.1 (CodeQL CLI 2.26.1).
In ECMAScript std::regex, \0 matches NUL. The previous escapedCharacter
arms all rejected it: the final arm's `not exists(getChar(start+1).toInt())`
guard fails for "0", and the numbered-backref arm excludes 0. Add an
explicit \0 case (end=start+2) guarded so the following character is not
a digit, mirroring EcmaRegExp.escapedCharacter in PR #22200. Add corpus
case "a\\0b" to test.cpp; \0 now parses as RegExpEscape.
Bundle: github/codeql-action codeql-bundle-v2.26.1 (CodeQL CLI 2.26.1).
std::regex ECMAScript mode does not support \p{Name}; \p tokenizes as an
identity escape. Remove pStyleNamedCharacterProperty and its call sites;
namedCharacterProperty now covers only POSIX brackets ([:name:], [.x.],
[=x=]) and namedCharacterPropertyIsInverted keeps only the [[:^name:]]
case (fixing the offset from start+3 to start+2 for POSIX). Update
RegExpNamedCharacterProperty getName/isInverted docs to describe POSIX
brackets. Remove the four \p{...}/\P{...} corpus lines from test.cpp;
keep a plain [a-f\d]+ case for the class-with-escape shape.
Bundle: github/codeql-action codeql-bundle-v2.26.1 (CodeQL CLI 2.26.1).
Add new test cases to test.cpp exercising POSIX bracket expressions inside
character classes as supported by std::regex ECMAScript mode:
- Single POSIX classes: [[:alpha:]], [[:digit:]], [[:space:]], [[:upper:]],
[[:lower:]], [[:alnum:]], [[:print:]], [[:punct:]]
- Negated outer bracket: [^[:space:]]
- Mixed: regular char + POSIX class [a[:space:]]
- POSIX collating symbol [[.a.]]
- POSIX equivalence class [[=a=]]
- Mixed POSIX + range [[:alpha:]0-9]
The existing r_posix1-r_posix4 cases remain untouched. New cases use distinct
names (r_posix_alpha, r_posix_digit, etc.) to avoid redeclaration.
Generated .expected via codeql test run --learn (CodeQL 2.26.1); all 2 tests
pass. The expected output captures the CURRENT (pre-fix) tokenization — commit 7
will change these rows when correct POSIX nesting is implemented.
Content-only edits to test.cpp to remove Ruby-only syntax that has no
C++ ECMAScript equivalent:
1. Removed: "a{,8}" — Ruby-only "{,n}" no-lower-bound quantifier
(ECMAScript requires an explicit lower bound in {n,m})
2. Removed: second ".*" for /.*/m — mode flags in C++ are construction-site
arguments (e.g. std::regex::multiline), not part of the pattern string.
This mode variant was the exact same pattern string as r_meta1 so it
added no coverage.
3. Removed: "(?'foo'fo+)" — Ruby single-quote named-group form.
ECMAScript only supports the angle-bracket form (?<name>...).
Left in place for now (removed with the parser in commit 5):
\\A, \\z, \\G, \\h, \\H — Ruby-only anchor/escape classes.
The POSIX-bracket cases are kept through commit 7.
.expected regenerated by:
codeql test run --learn --search-path=. cpp/ql/test/library-tests/regex/
(CodeQL CLI 2.26.1)
All 2 tests passed.
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<CharT> constructor(const char*), constructor(const char*, int),
assign(const char*)
std::regex typedef for basic_regex<char>
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.