@@ -24,9 +24,9 @@ abstract class RegExp extends Expr {
2424 predicate isIgnoreCase ( ) { this .getAMode ( ) = "IGNORECASE" }
2525
2626 /**
27- * Gets the flags for this `RegExp`, or the empty string if it has no flags.
27+ * Gets a string repreenting the flags for this `RegExp`, or the empty string if it has no flags.
2828 */
29- string getFlags ( ) { result = concat ( string mode | mode = this .getAMode ( ) | mode , " | " ) }
29+ string getFlags ( ) { result = concat ( string mode | mode = this .getAMode ( ) | mode , " | " ) }
3030
3131 /**
3232 * Helper predicate for `charSetStart(int start, int end)`.
@@ -275,27 +275,34 @@ abstract class RegExp extends Expr {
275275 private predicate isGroupStart ( int i ) { this .nonEscapedCharAt ( i ) = "(" and not this .inCharSet ( i ) }
276276
277277 /**
278- * Holds if `start` and `end` are the range of the mode prefix substring (if any) of this
279- * regular expression, and `c` is a mode prefix character specified in it. For example
280- * in the following regular expression, `start` is `0`, `end` is `3` and `c` is `i`.
278+ * Holds if a parse mode prefix starts between `start` and `end`. For example:
281279 * ```
282- * (?i)one|two
280+ * (?i)
283281 * ```
284282 */
285- private predicate flagGroupStart ( int start , int end , string c ) {
286- // TODO: I believe this fails with multiple mode specifiers such as (?is) at the moment.
283+ private predicate flagGroupStart ( int start , int end ) {
287284 this .isGroupStart ( start ) and
288285 this .getChar ( start + 1 ) = "?" and
289- end = start + 3 and
290- c = this .getChar ( start + 2 ) and
291- c in [ "i" , "m" , "s" , "u" , "x" , "U" ]
286+ end = start + 2
287+ }
288+
289+ /**
290+ * Holds if a parse mode prefix group is between `start` and `end`, and includes the
291+ * mode flag `c`.
292+ */
293+ private predicate flagGroup ( int start , int end , string c ) {
294+ exists ( int inStart , int inEnd |
295+ this .flagGroupStart ( start , inStart ) and
296+ this .groupContents ( start , end , inStart , inEnd ) and
297+ this .getChar ( [ inStart .. inEnd - 1 ] ) = c
298+ )
292299 }
293300
294301 /**
295302 * Gets a mode of this regular expression string if it is defined by a mode prefix.
296303 */
297304 string getModeFromPrefix ( ) {
298- exists ( string c | this .flagGroupStart ( _, _, c ) |
305+ exists ( string c | this .flagGroup ( _, _, c ) |
299306 // TODO: are these correct in Swift?
300307 c = "i" and result = "IGNORECASE"
301308 or
@@ -322,10 +329,13 @@ abstract class RegExp extends Expr {
322329 * UNICODECLASS
323330 */
324331 string getAMode ( ) {
325- /* TODO
326- result != "None" and
327- usedAsRegex(this, result, _)
328- or*/
332+ /*
333+ * TODO
334+ * result != "None" and
335+ * usedAsRegex(this, result, _)
336+ * or
337+ */
338+
329339 result = this .getModeFromPrefix ( )
330340 }
331341
@@ -709,7 +719,7 @@ abstract class RegExp extends Expr {
709719 or
710720 this .simpleGroupStart ( start , end )
711721 or
712- this .flagGroupStart ( start , end , _ )
722+ this .flagGroupStart ( start , end )
713723 }
714724
715725 /** Matches the start of a non-capturing group, e.g. `(?:` */
0 commit comments