@@ -479,7 +479,7 @@ abstract class RegexString extends StringLiteral {
479479 private predicate flagGroupStartNoModes ( int start , int end ) {
480480 this .isGroupStart ( start ) and
481481 this .getChar ( start + 1 ) = "?" and
482- this .getChar ( start + 2 ) in [ "i " , "m" , "s" , "u" , "x" , "U" ] and
482+ this .getChar ( start + 2 ) in [ "-" , "i" , "d ", "m" , "s" , "u" , "x" , "U" ] and
483483 end = start + 2
484484 }
485485
@@ -491,15 +491,18 @@ abstract class RegexString extends StringLiteral {
491491 this .flagGroupStartNoModes ( start , pos )
492492 or
493493 this .modeCharacter ( start , pos - 1 ) and
494- this .getChar ( pos ) in [ "i " , "m" , "s" , "u" , "x" , "U" ]
494+ this .getChar ( pos ) in [ "-" , "i" , "d ", "m" , "s" , "u" , "x" , "U" ]
495495 }
496496
497497 /**
498498 * Holds if a parse mode group is between `start` and `end`.
499499 */
500500 private predicate flagGroupStart ( int start , int end ) {
501501 this .flagGroupStartNoModes ( start , _) and
502- end = max ( int i | this .modeCharacter ( start , i ) | i + 1 )
502+ // Check if this is a capturing group with flags, and therefore the `:` should be excluded
503+ exists ( int maybeEnd | maybeEnd = max ( int i | this .modeCharacter ( start , i ) | i + 1 ) |
504+ if this .getChar ( maybeEnd ) = ":" then end = maybeEnd + 1 else end = maybeEnd
505+ )
503506 }
504507
505508 /**
@@ -510,9 +513,15 @@ abstract class RegexString extends StringLiteral {
510513 * ```
511514 */
512515 private predicate flag ( string c ) {
513- exists ( int pos |
514- this .modeCharacter ( _, pos ) and
515- this .getChar ( pos ) = c
516+ exists ( int start , int pos |
517+ this .modeCharacter ( start , pos ) and
518+ this .getChar ( pos ) = c and
519+ // Ignore if flag is disabled; use `<=` to also exclude `-` itself
520+ // This does not properly handle the (contrived) case where a flag is both enabled and
521+ // disabled, e.g. `(?i-i)a+`, in which case the flag seems to acts as if it was disabled
522+ not exists ( int minusPos |
523+ this .modeCharacter ( start , minusPos ) and this .getChar ( minusPos ) = "-" and minusPos <= pos
524+ )
516525 )
517526 }
518527
@@ -524,6 +533,8 @@ abstract class RegexString extends StringLiteral {
524533 exists ( string c | this .flag ( c ) |
525534 c = "i" and result = "IGNORECASE"
526535 or
536+ c = "d" and result = "UNIXLINES"
537+ or
527538 c = "m" and result = "MULTILINE"
528539 or
529540 c = "s" and result = "DOTALL"
@@ -930,13 +941,13 @@ class Regex extends RegexString {
930941
931942 /**
932943 * Gets a mode (if any) of this regular expression. Can be any of:
933- * DEBUG
934- * IGNORECASE
935- * MULTILINE
936- * DOTALL
937- * UNICODE
938- * VERBOSE
939- * UNICODECLASS
944+ * - IGNORECASE
945+ * - UNIXLINES
946+ * - MULTILINE
947+ * - DOTALL
948+ * - UNICODE
949+ * - VERBOSE
950+ * - UNICODECLASS
940951 */
941952 string getAMode ( ) {
942953 result != "None" and
@@ -946,7 +957,7 @@ class Regex extends RegexString {
946957 }
947958
948959 /**
949- * Holds if this regex is used to match against a full string,
960+ * Holds if this regex is used to match against a full string,
950961 * as though it was implicitly surrounded by ^ and $.
951962 */
952963 predicate matchesFullString ( ) { matches_full_string = true }
0 commit comments