@@ -268,6 +268,9 @@ class RegExpTerm extends RegExpParent {
268
268
269
269
/** Gets the primary QL class for this term. */
270
270
override string getAPrimaryQlClass ( ) { result = "RegExpTerm" }
271
+
272
+ /** Holds if this regular expression term can match the empty string. */
273
+ predicate matchesEmptyString ( ) { none ( ) }
271
274
}
272
275
273
276
/**
@@ -326,6 +329,8 @@ class RegExpStar extends InfiniteRepetitionQuantifier {
326
329
RegExpStar ( ) { this .getQualifier ( ) .charAt ( 0 ) = "*" }
327
330
328
331
override string getAPrimaryQlClass ( ) { result = "RegExpStar" }
332
+
333
+ override predicate matchesEmptyString ( ) { any ( ) }
329
334
}
330
335
331
336
/**
@@ -341,6 +346,8 @@ class RegExpPlus extends InfiniteRepetitionQuantifier {
341
346
RegExpPlus ( ) { this .getQualifier ( ) .charAt ( 0 ) = "+" }
342
347
343
348
override string getAPrimaryQlClass ( ) { result = "RegExpPlus" }
349
+
350
+ override predicate matchesEmptyString ( ) { this .getAChild ( ) .matchesEmptyString ( ) }
344
351
}
345
352
346
353
/**
@@ -356,6 +363,8 @@ class RegExpOpt extends RegExpQuantifier {
356
363
RegExpOpt ( ) { this .getQualifier ( ) .charAt ( 0 ) = "?" }
357
364
358
365
override string getAPrimaryQlClass ( ) { result = "RegExpOpt" }
366
+
367
+ override predicate matchesEmptyString ( ) { any ( ) }
359
368
}
360
369
361
370
/**
@@ -375,6 +384,8 @@ class RegExpRange extends RegExpQuantifier {
375
384
376
385
RegExpRange ( ) { re .multiples ( part_end , end , lower , upper ) }
377
386
387
+ override string getAPrimaryQlClass ( ) { result = "RegExpRange" }
388
+
378
389
/** Gets the string defining the upper bound of this range, if any. */
379
390
string getUpper ( ) { result = upper }
380
391
@@ -393,7 +404,9 @@ class RegExpRange extends RegExpQuantifier {
393
404
/** Gets the lower bound of the range. */
394
405
int getLowerBound ( ) { result = this .getLower ( ) .toInt ( ) }
395
406
396
- override string getAPrimaryQlClass ( ) { result = "RegExpRange" }
407
+ override predicate matchesEmptyString ( ) {
408
+ this .getAChild ( ) .matchesEmptyString ( ) or this .getLowerBound ( ) = 0
409
+ }
397
410
}
398
411
399
412
/**
@@ -440,6 +453,10 @@ class RegExpSequence extends RegExpTerm, TRegExpSequence {
440
453
}
441
454
442
455
override string getAPrimaryQlClass ( ) { result = "RegExpSequence" }
456
+
457
+ override predicate matchesEmptyString ( ) {
458
+ forall ( RegExpTerm child | child = this .getAChild ( ) | child .matchesEmptyString ( ) )
459
+ }
443
460
}
444
461
445
462
pragma [ nomagic]
@@ -505,6 +522,8 @@ class RegExpAlt extends RegExpTerm, TRegExpAlt {
505
522
override string getAMatchedString ( ) { result = this .getAlternative ( ) .getAMatchedString ( ) }
506
523
507
524
override string getAPrimaryQlClass ( ) { result = "RegExpAlt" }
525
+
526
+ override predicate matchesEmptyString ( ) { this .getAChild ( ) .matchesEmptyString ( ) }
508
527
}
509
528
510
529
class RegExpCharEscape = RegExpEscape ;
@@ -579,6 +598,8 @@ class RegExpEscape extends RegExpNormalChar {
579
598
*/
580
599
class RegExpWordBoundary extends RegExpSpecialChar {
581
600
RegExpWordBoundary ( ) { this .getChar ( ) = "\\b" }
601
+
602
+ override predicate matchesEmptyString ( ) { none ( ) }
582
603
}
583
604
584
605
/**
@@ -607,6 +628,8 @@ class RegExpCharacterClassEscape extends RegExpEscape {
607
628
override RegExpTerm getChild ( int i ) { none ( ) }
608
629
609
630
override string getAPrimaryQlClass ( ) { result = "RegExpCharacterClassEscape" }
631
+
632
+ override predicate matchesEmptyString ( ) { none ( ) }
610
633
}
611
634
612
635
/**
@@ -663,6 +686,8 @@ class RegExpCharacterClass extends RegExpTerm, TRegExpCharacterClass {
663
686
}
664
687
665
688
override string getAPrimaryQlClass ( ) { result = "RegExpCharacterClass" }
689
+
690
+ override predicate matchesEmptyString ( ) { none ( ) }
666
691
}
667
692
668
693
/**
@@ -702,6 +727,8 @@ class RegExpCharacterRange extends RegExpTerm, TRegExpCharacterRange {
702
727
}
703
728
704
729
override string getAPrimaryQlClass ( ) { result = "RegExpCharacterRange" }
730
+
731
+ override predicate matchesEmptyString ( ) { none ( ) }
705
732
}
706
733
707
734
/**
@@ -773,6 +800,8 @@ class RegExpConstant extends RegExpTerm {
773
800
override string getConstantValue ( ) { result = this .getValue ( ) }
774
801
775
802
override string getAPrimaryQlClass ( ) { result = "RegExpConstant" }
803
+
804
+ override predicate matchesEmptyString ( ) { none ( ) }
776
805
}
777
806
778
807
/**
@@ -820,6 +849,8 @@ class RegExpGroup extends RegExpTerm, TRegExpGroup {
820
849
override string getAMatchedString ( ) { result = this .getAChild ( ) .getAMatchedString ( ) }
821
850
822
851
override string getAPrimaryQlClass ( ) { result = "RegExpGroup" }
852
+
853
+ override predicate matchesEmptyString ( ) { this .getAChild ( ) .matchesEmptyString ( ) }
823
854
}
824
855
825
856
/**
@@ -867,6 +898,8 @@ class RegExpDot extends RegExpSpecialChar {
867
898
RegExpDot ( ) { this .getChar ( ) = "." }
868
899
869
900
override string getAPrimaryQlClass ( ) { result = "RegExpDot" }
901
+
902
+ override predicate matchesEmptyString ( ) { none ( ) }
870
903
}
871
904
872
905
/**
@@ -897,6 +930,8 @@ class RegExpDollar extends RegExpAnchor {
897
930
RegExpDollar ( ) { this .getChar ( ) = [ "$" , "\\Z" , "\\z" ] }
898
931
899
932
override string getAPrimaryQlClass ( ) { result = "RegExpDollar" }
933
+
934
+ override predicate matchesEmptyString ( ) { any ( ) }
900
935
}
901
936
902
937
/**
@@ -912,6 +947,8 @@ class RegExpCaret extends RegExpAnchor {
912
947
RegExpCaret ( ) { this .getChar ( ) = [ "^" , "\\A" ] }
913
948
914
949
override string getAPrimaryQlClass ( ) { result = "RegExpCaret" }
950
+
951
+ override predicate matchesEmptyString ( ) { any ( ) }
915
952
}
916
953
917
954
/**
@@ -929,6 +966,8 @@ class RegExpZeroWidthMatch extends RegExpGroup {
929
966
override RegExpTerm getChild ( int i ) { none ( ) }
930
967
931
968
override string getAPrimaryQlClass ( ) { result = "RegExpZeroWidthMatch" }
969
+
970
+ override predicate matchesEmptyString ( ) { any ( ) }
932
971
}
933
972
934
973
/**
@@ -954,6 +993,8 @@ class RegExpSubPattern extends RegExpZeroWidthMatch {
954
993
result .getEnd ( ) = in_end
955
994
)
956
995
}
996
+
997
+ override predicate matchesEmptyString ( ) { any ( ) }
957
998
}
958
999
959
1000
/**
@@ -981,6 +1022,8 @@ class RegExpPositiveLookahead extends RegExpLookahead {
981
1022
RegExpPositiveLookahead ( ) { re .positiveLookaheadAssertionGroup ( start , end ) }
982
1023
983
1024
override string getAPrimaryQlClass ( ) { result = "RegExpPositiveLookahead" }
1025
+
1026
+ override predicate matchesEmptyString ( ) { any ( ) }
984
1027
}
985
1028
986
1029
/**
@@ -1076,6 +1119,8 @@ class RegExpBackRef extends RegExpTerm, TRegExpBackRef {
1076
1119
override RegExpTerm getChild ( int i ) { none ( ) }
1077
1120
1078
1121
override string getAPrimaryQlClass ( ) { result = "RegExpBackRef" }
1122
+
1123
+ override predicate matchesEmptyString ( ) { this .getGroup ( ) .matchesEmptyString ( ) }
1079
1124
}
1080
1125
1081
1126
/**
0 commit comments