Skip to content

Commit c9fc43a

Browse files
committed
Ruby: Add matchesEmptyString to RegExpTerm
1 parent 9e0c82e commit c9fc43a

File tree

1 file changed

+46
-1
lines changed

1 file changed

+46
-1
lines changed

ruby/ql/lib/codeql/ruby/regexp/RegExpTreeView.qll

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,9 @@ class RegExpTerm extends RegExpParent {
268268

269269
/** Gets the primary QL class for this term. */
270270
override string getAPrimaryQlClass() { result = "RegExpTerm" }
271+
272+
/** Holds if this regular expression term can match the empty string. */
273+
predicate matchesEmptyString() { none() }
271274
}
272275

273276
/**
@@ -326,6 +329,8 @@ class RegExpStar extends InfiniteRepetitionQuantifier {
326329
RegExpStar() { this.getQualifier().charAt(0) = "*" }
327330

328331
override string getAPrimaryQlClass() { result = "RegExpStar" }
332+
333+
override predicate matchesEmptyString() { any() }
329334
}
330335

331336
/**
@@ -341,6 +346,8 @@ class RegExpPlus extends InfiniteRepetitionQuantifier {
341346
RegExpPlus() { this.getQualifier().charAt(0) = "+" }
342347

343348
override string getAPrimaryQlClass() { result = "RegExpPlus" }
349+
350+
override predicate matchesEmptyString() { this.getAChild().matchesEmptyString() }
344351
}
345352

346353
/**
@@ -356,6 +363,8 @@ class RegExpOpt extends RegExpQuantifier {
356363
RegExpOpt() { this.getQualifier().charAt(0) = "?" }
357364

358365
override string getAPrimaryQlClass() { result = "RegExpOpt" }
366+
367+
override predicate matchesEmptyString() { any() }
359368
}
360369

361370
/**
@@ -375,6 +384,8 @@ class RegExpRange extends RegExpQuantifier {
375384

376385
RegExpRange() { re.multiples(part_end, end, lower, upper) }
377386

387+
override string getAPrimaryQlClass() { result = "RegExpRange" }
388+
378389
/** Gets the string defining the upper bound of this range, if any. */
379390
string getUpper() { result = upper }
380391

@@ -393,7 +404,9 @@ class RegExpRange extends RegExpQuantifier {
393404
/** Gets the lower bound of the range. */
394405
int getLowerBound() { result = this.getLower().toInt() }
395406

396-
override string getAPrimaryQlClass() { result = "RegExpRange" }
407+
override predicate matchesEmptyString() {
408+
this.getAChild().matchesEmptyString() or this.getLowerBound() = 0
409+
}
397410
}
398411

399412
/**
@@ -440,6 +453,10 @@ class RegExpSequence extends RegExpTerm, TRegExpSequence {
440453
}
441454

442455
override string getAPrimaryQlClass() { result = "RegExpSequence" }
456+
457+
override predicate matchesEmptyString() {
458+
forall(RegExpTerm child | child = this.getAChild() | child.matchesEmptyString())
459+
}
443460
}
444461

445462
pragma[nomagic]
@@ -505,6 +522,8 @@ class RegExpAlt extends RegExpTerm, TRegExpAlt {
505522
override string getAMatchedString() { result = this.getAlternative().getAMatchedString() }
506523

507524
override string getAPrimaryQlClass() { result = "RegExpAlt" }
525+
526+
override predicate matchesEmptyString() { this.getAChild().matchesEmptyString() }
508527
}
509528

510529
class RegExpCharEscape = RegExpEscape;
@@ -579,6 +598,8 @@ class RegExpEscape extends RegExpNormalChar {
579598
*/
580599
class RegExpWordBoundary extends RegExpSpecialChar {
581600
RegExpWordBoundary() { this.getChar() = "\\b" }
601+
602+
override predicate matchesEmptyString() { none() }
582603
}
583604

584605
/**
@@ -607,6 +628,8 @@ class RegExpCharacterClassEscape extends RegExpEscape {
607628
override RegExpTerm getChild(int i) { none() }
608629

609630
override string getAPrimaryQlClass() { result = "RegExpCharacterClassEscape" }
631+
632+
override predicate matchesEmptyString() { none() }
610633
}
611634

612635
/**
@@ -663,6 +686,8 @@ class RegExpCharacterClass extends RegExpTerm, TRegExpCharacterClass {
663686
}
664687

665688
override string getAPrimaryQlClass() { result = "RegExpCharacterClass" }
689+
690+
override predicate matchesEmptyString() { none() }
666691
}
667692

668693
/**
@@ -702,6 +727,8 @@ class RegExpCharacterRange extends RegExpTerm, TRegExpCharacterRange {
702727
}
703728

704729
override string getAPrimaryQlClass() { result = "RegExpCharacterRange" }
730+
731+
override predicate matchesEmptyString() { none() }
705732
}
706733

707734
/**
@@ -773,6 +800,8 @@ class RegExpConstant extends RegExpTerm {
773800
override string getConstantValue() { result = this.getValue() }
774801

775802
override string getAPrimaryQlClass() { result = "RegExpConstant" }
803+
804+
override predicate matchesEmptyString() { none() }
776805
}
777806

778807
/**
@@ -820,6 +849,8 @@ class RegExpGroup extends RegExpTerm, TRegExpGroup {
820849
override string getAMatchedString() { result = this.getAChild().getAMatchedString() }
821850

822851
override string getAPrimaryQlClass() { result = "RegExpGroup" }
852+
853+
override predicate matchesEmptyString() { this.getAChild().matchesEmptyString() }
823854
}
824855

825856
/**
@@ -867,6 +898,8 @@ class RegExpDot extends RegExpSpecialChar {
867898
RegExpDot() { this.getChar() = "." }
868899

869900
override string getAPrimaryQlClass() { result = "RegExpDot" }
901+
902+
override predicate matchesEmptyString() { none() }
870903
}
871904

872905
/**
@@ -897,6 +930,8 @@ class RegExpDollar extends RegExpAnchor {
897930
RegExpDollar() { this.getChar() = ["$", "\\Z", "\\z"] }
898931

899932
override string getAPrimaryQlClass() { result = "RegExpDollar" }
933+
934+
override predicate matchesEmptyString() { any() }
900935
}
901936

902937
/**
@@ -912,6 +947,8 @@ class RegExpCaret extends RegExpAnchor {
912947
RegExpCaret() { this.getChar() = ["^", "\\A"] }
913948

914949
override string getAPrimaryQlClass() { result = "RegExpCaret" }
950+
951+
override predicate matchesEmptyString() { any() }
915952
}
916953

917954
/**
@@ -929,6 +966,8 @@ class RegExpZeroWidthMatch extends RegExpGroup {
929966
override RegExpTerm getChild(int i) { none() }
930967

931968
override string getAPrimaryQlClass() { result = "RegExpZeroWidthMatch" }
969+
970+
override predicate matchesEmptyString() { any() }
932971
}
933972

934973
/**
@@ -954,6 +993,8 @@ class RegExpSubPattern extends RegExpZeroWidthMatch {
954993
result.getEnd() = in_end
955994
)
956995
}
996+
997+
override predicate matchesEmptyString() { any() }
957998
}
958999

9591000
/**
@@ -981,6 +1022,8 @@ class RegExpPositiveLookahead extends RegExpLookahead {
9811022
RegExpPositiveLookahead() { re.positiveLookaheadAssertionGroup(start, end) }
9821023

9831024
override string getAPrimaryQlClass() { result = "RegExpPositiveLookahead" }
1025+
1026+
override predicate matchesEmptyString() { any() }
9841027
}
9851028

9861029
/**
@@ -1076,6 +1119,8 @@ class RegExpBackRef extends RegExpTerm, TRegExpBackRef {
10761119
override RegExpTerm getChild(int i) { none() }
10771120

10781121
override string getAPrimaryQlClass() { result = "RegExpBackRef" }
1122+
1123+
override predicate matchesEmptyString() { this.getGroup().matchesEmptyString() }
10791124
}
10801125

10811126
/**

0 commit comments

Comments
 (0)