Skip to content

Commit 4354945

Browse files
committed
JS: Factor out recognition of RegExp flags
1 parent a3efcf6 commit 4354945

File tree

2 files changed

+46
-17
lines changed

2 files changed

+46
-17
lines changed

javascript/ql/src/semmle/javascript/Expr.qll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -454,16 +454,16 @@ class RegExpLiteral extends @regexpliteral, Literal, RegExpParent {
454454
string getFlags() { result = getValue().regexpCapture(".*/(\\w*)$", 1) }
455455

456456
/** Holds if this regular expression has an `m` flag. */
457-
predicate isMultiline() { getFlags().matches("%m%") }
457+
predicate isMultiline() { RegExp::isMultiline(getFlags()) }
458458

459459
/** Holds if this regular expression has a `g` flag. */
460-
predicate isGlobal() { getFlags().matches("%g%") }
460+
predicate isGlobal() { RegExp::isGlobal(getFlags()) }
461461

462462
/** Holds if this regular expression has an `i` flag. */
463-
predicate isIgnoreCase() { getFlags().matches("%i%") }
463+
predicate isIgnoreCase() { RegExp::isIgnoreCase(getFlags()) }
464464

465465
/** Holds if this regular expression has an `s` flag. */
466-
predicate isDotAll() { getFlags().matches("%s%") }
466+
predicate isDotAll() { RegExp::isDotAll(getFlags()) }
467467
}
468468

469469
/**

javascript/ql/src/semmle/javascript/Regexp.qll

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,7 @@ class RegExpTerm extends Locatable, @regexpterm {
113113
/**
114114
* Holds if this is the root term of a regular expression.
115115
*/
116-
predicate isRootTerm() {
117-
not getParent() instanceof RegExpTerm
118-
}
116+
predicate isRootTerm() { not getParent() instanceof RegExpTerm }
119117

120118
/**
121119
* Gets the outermost term of this regular expression.
@@ -130,19 +128,15 @@ class RegExpTerm extends Locatable, @regexpterm {
130128
/**
131129
* Holds if this term occurs as part of a regular expression literal.
132130
*/
133-
predicate isPartOfRegExpLiteral() {
134-
exists(getLiteral())
135-
}
131+
predicate isPartOfRegExpLiteral() { exists(getLiteral()) }
136132

137133
/**
138134
* Holds if this term occurs as part of a string literal.
139135
*
140136
* This predicate holds regardless of whether the string literal is actually
141137
* used as a regular expression. See `isUsedAsRegExp`.
142138
*/
143-
predicate isPartOfStringLiteral() {
144-
getRootTerm().getParent() instanceof StringLiteral
145-
}
139+
predicate isPartOfStringLiteral() { getRootTerm().getParent() instanceof StringLiteral }
146140

147141
/**
148142
* Holds if this term is part of a regular expression literal, or a string literal
@@ -344,8 +338,7 @@ class RegExpAnchor extends RegExpTerm, @regexp_anchor {
344338
* ^
345339
* ```
346340
*/
347-
class RegExpCaret extends RegExpAnchor, @regexp_caret {
348-
}
341+
class RegExpCaret extends RegExpAnchor, @regexp_caret { }
349342

350343
/**
351344
* A dollar assertion `$` matching the end of a line.
@@ -356,8 +349,7 @@ class RegExpCaret extends RegExpAnchor, @regexp_caret {
356349
* $
357350
* ```
358351
*/
359-
class RegExpDollar extends RegExpAnchor, @regexp_dollar {
360-
}
352+
class RegExpDollar extends RegExpAnchor, @regexp_dollar { }
361353

362354
/**
363355
* A word boundary assertion.
@@ -940,3 +932,40 @@ private class StringRegExpPatternSource extends RegExpPatternSource {
940932

941933
override RegExpTerm getRegExpTerm() { result = asExpr().(StringLiteral).asRegExp() }
942934
}
935+
936+
module RegExp {
937+
/** Gets the string `"?"` used to represent a regular expression whose flags are unknown. */
938+
string unknownFlag() { result = "?" }
939+
940+
/** Holds `flags` includes the `m` flag. */
941+
bindingset[flags]
942+
predicate isMultiline(string flags) { flags.matches("%m%") }
943+
944+
/** Holds `flags` includes the `g` flag. */
945+
bindingset[flags]
946+
predicate isGlobal(string flags) { flags.matches("%g%") }
947+
948+
/** Holds `flags` includes the `i` flag. */
949+
bindingset[flags]
950+
predicate isIgnoreCase(string flags) { flags.matches("%i%") }
951+
952+
/** Holds `flags` includes the `s` flag. */
953+
bindingset[flags]
954+
predicate isDotAll(string flags) { flags.matches("%s%") }
955+
956+
/** Holds `flags` includes the `m` flag or is the unknown flag `?`. */
957+
bindingset[flags]
958+
predicate maybeMultiline(string flags) { flags = unknownFlag() or isMultiline(flags) }
959+
960+
/** Holds `flags` includes the `g` flag or is the unknown flag `?`. */
961+
bindingset[flags]
962+
predicate maybeGlobal(string flags) { flags = unknownFlag() or isGlobal(flags) }
963+
964+
/** Holds `flags` includes the `i` flag or is the unknown flag `?`. */
965+
bindingset[flags]
966+
predicate maybeIgnoreCase(string flags) { flags = unknownFlag() or isIgnoreCase(flags) }
967+
968+
/** Holds `flags` includes the `s` flag or is the unknown flag `?`. */
969+
bindingset[flags]
970+
predicate maybeDotAll(string flags) { flags = unknownFlag() or isDotAll(flags) }
971+
}

0 commit comments

Comments
 (0)