@@ -3,21 +3,14 @@ private import codeql.ruby.security.performance.RegExpTreeView as RETV
3
3
private import internal.AST
4
4
private import internal.Scope
5
5
private import internal.TreeSitter
6
+ private import codeql.ruby.controlflow.CfgNodes
6
7
7
8
/**
8
9
* A literal.
9
10
*
10
11
* This is the QL root class for all literals.
11
12
*/
12
- class Literal extends Expr , TLiteral {
13
- /**
14
- * Gets the source text for this literal, if this is a simple literal.
15
- *
16
- * For complex literals, such as arrays, hashes, and strings with
17
- * interpolations, this predicate has no result.
18
- */
19
- override string getValueText ( ) { none ( ) }
20
- }
13
+ class Literal extends Expr , TLiteral { }
21
14
22
15
/**
23
16
* A numeric literal, i.e. an integer, floating-point, rational, or complex
@@ -281,10 +274,10 @@ class StringComponent extends AstNode, TStringComponent {
281
274
* "foo#{ bar() } baz"
282
275
* ```
283
276
*/
284
- class StringTextComponent extends StringComponent , TStringTextComponent {
277
+ class StringTextComponent extends StringComponent , TStringTextComponentNonRegexp {
285
278
private Ruby:: Token g ;
286
279
287
- StringTextComponent ( ) { this = TStringTextComponent ( g ) }
280
+ StringTextComponent ( ) { this = TStringTextComponentNonRegexp ( g ) }
288
281
289
282
final override string toString ( ) { result = g .getValue ( ) }
290
283
@@ -296,10 +289,10 @@ class StringTextComponent extends StringComponent, TStringTextComponent {
296
289
/**
297
290
* An escape sequence component of a string or string-like literal.
298
291
*/
299
- class StringEscapeSequenceComponent extends StringComponent , TStringEscapeSequenceComponent {
292
+ class StringEscapeSequenceComponent extends StringComponent , TStringEscapeSequenceComponentNonRegexp {
300
293
private Ruby:: EscapeSequence g ;
301
294
302
- StringEscapeSequenceComponent ( ) { this = TStringEscapeSequenceComponent ( g ) }
295
+ StringEscapeSequenceComponent ( ) { this = TStringEscapeSequenceComponentNonRegexp ( g ) }
303
296
304
297
final override string toString ( ) { result = g .getValue ( ) }
305
298
@@ -312,10 +305,10 @@ class StringEscapeSequenceComponent extends StringComponent, TStringEscapeSequen
312
305
* An interpolation expression component of a string or string-like literal.
313
306
*/
314
307
class StringInterpolationComponent extends StringComponent , StmtSequence ,
315
- TStringInterpolationComponent {
308
+ TStringInterpolationComponentNonRegexp {
316
309
private Ruby:: Interpolation g ;
317
310
318
- StringInterpolationComponent ( ) { this = TStringInterpolationComponent ( g ) }
311
+ StringInterpolationComponent ( ) { this = TStringInterpolationComponentNonRegexp ( g ) }
319
312
320
313
final override string toString ( ) { result = "#{...}" }
321
314
@@ -326,6 +319,83 @@ class StringInterpolationComponent extends StringComponent, StmtSequence,
326
319
final override string getAPrimaryQlClass ( ) { result = "StringInterpolationComponent" }
327
320
}
328
321
322
+ private class TRegExpComponent =
323
+ TStringTextComponentRegexp or TStringEscapeSequenceComponentRegexp or
324
+ TStringInterpolationComponentRegexp ;
325
+
326
+ /**
327
+ * The base class for a component of a regular expression literal.
328
+ */
329
+ class RegExpComponent extends AstNode , TRegExpComponent {
330
+ /** Gets the source text for this regex component, if any. */
331
+ string getValueText ( ) { none ( ) }
332
+ }
333
+
334
+ /**
335
+ * A component of a regex literal that is simply text.
336
+ *
337
+ * For example, the following regex literals all contain `RegExpTextComponent`
338
+ * components whose `getValueText()` returns `"foo"`:
339
+ *
340
+ * ```rb
341
+ * 'foo'
342
+ * "#{ bar() }foo"
343
+ * "foo#{ bar() } baz"
344
+ * ```
345
+ */
346
+ class RegExpTextComponent extends RegExpComponent , TStringTextComponentRegexp {
347
+ private Ruby:: Token g ;
348
+
349
+ RegExpTextComponent ( ) { this = TStringTextComponentRegexp ( g ) }
350
+
351
+ final override string toString ( ) { result = g .getValue ( ) }
352
+
353
+ // Exclude components that are children of a free-spacing regex.
354
+ // We do this because `ParseRegExp.qll` cannot handle free-spacing regexes.
355
+ final override string getValueText ( ) {
356
+ not this .getParent ( ) .( RegExpLiteral ) .hasFreeSpacingFlag ( ) and result = g .getValue ( )
357
+ }
358
+
359
+ final override string getAPrimaryQlClass ( ) { result = "RegExpTextComponent" }
360
+ }
361
+
362
+ /**
363
+ * An escape sequence component of a regex literal.
364
+ */
365
+ class RegExpEscapeSequenceComponent extends RegExpComponent , TStringEscapeSequenceComponentRegexp {
366
+ private Ruby:: EscapeSequence g ;
367
+
368
+ RegExpEscapeSequenceComponent ( ) { this = TStringEscapeSequenceComponentRegexp ( g ) }
369
+
370
+ final override string toString ( ) { result = g .getValue ( ) }
371
+
372
+ // Exclude components that are children of a free-spacing regex.
373
+ // We do this because `ParseRegExp.qll` cannot handle free-spacing regexes.
374
+ final override string getValueText ( ) {
375
+ not this .getParent ( ) .( RegExpLiteral ) .hasFreeSpacingFlag ( ) and result = g .getValue ( )
376
+ }
377
+
378
+ final override string getAPrimaryQlClass ( ) { result = "RegExpEscapeSequenceComponent" }
379
+ }
380
+
381
+ /**
382
+ * An interpolation expression component of a regex literal.
383
+ */
384
+ class RegExpInterpolationComponent extends RegExpComponent , StmtSequence ,
385
+ TStringInterpolationComponentRegexp {
386
+ private Ruby:: Interpolation g ;
387
+
388
+ RegExpInterpolationComponent ( ) { this = TStringInterpolationComponentRegexp ( g ) }
389
+
390
+ final override string toString ( ) { result = "#{...}" }
391
+
392
+ final override Stmt getStmt ( int n ) { toGenerated ( result ) = g .getChild ( n ) }
393
+
394
+ final override string getValueText ( ) { none ( ) }
395
+
396
+ final override string getAPrimaryQlClass ( ) { result = "RegExpInterpolationComponent" }
397
+ }
398
+
329
399
/**
330
400
* A string, symbol, regexp, or subshell literal.
331
401
*/
@@ -410,17 +480,6 @@ class StringlikeLiteral extends Literal, TStringlikeLiteral {
410
480
result = ""
411
481
}
412
482
413
- override string getValueText ( ) {
414
- // 0 components should result in the empty string
415
- // if there are any interpolations, there should be no result
416
- // otherwise, concatenate all the components
417
- forall ( StringComponent c | c = this .getComponent ( _) |
418
- not c instanceof StringInterpolationComponent
419
- ) and
420
- result =
421
- concat ( StringComponent c , int i | c = this .getComponent ( i ) | c .getValueText ( ) order by i )
422
- }
423
-
424
483
override string toString ( ) {
425
484
exists ( string full , string summary |
426
485
full =
0 commit comments