Skip to content

Commit abf3ce6

Browse files
committed
Ruby: expressions in pin operator ^
1 parent 00fb4d3 commit abf3ce6

File tree

10 files changed

+84
-26
lines changed

10 files changed

+84
-26
lines changed

ruby/ql/lib/codeql/ruby/ast/Pattern.qll

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ deprecated class TuplePattern extends Pattern, TTuplePattern {
8080

8181
private class TPatternNode =
8282
TArrayPattern or TFindPattern or THashPattern or TAlternativePattern or TAsPattern or
83-
TParenthesizedPattern or TVariableReferencePattern;
83+
TParenthesizedPattern or TExpressionReferencePattern or TVariableReferencePattern;
8484

8585
private class TPattern =
8686
TPatternNode or TLiteral or TLambda or TConstantAccess or TLocalVariableAccess or
@@ -404,29 +404,51 @@ class ParenthesizedPattern extends CasePattern, TParenthesizedPattern {
404404
}
405405

406406
/**
407-
* A variable reference in a pattern, i.e. `^x` in the following example:
407+
* A variable or value reference in a pattern, i.e. `^x`, and `^(2 * x)` in the following example:
408408
* ```rb
409409
* x = 10
410410
* case expr
411411
* in ^x then puts "ok"
412+
* in ^(2 * x) then puts "ok"
412413
* end
413414
* ```
414415
*/
415-
class VariableReferencePattern extends CasePattern, TVariableReferencePattern {
416-
private Ruby::VariableReferencePattern g;
416+
class ReferencePattern extends CasePattern, TReferencePattern {
417+
private Ruby::AstNode value;
417418

418-
VariableReferencePattern() { this = TVariableReferencePattern(g) }
419+
ReferencePattern() {
420+
value = any(Ruby::VariableReferencePattern g | this = TVariableReferencePattern(g)).getName()
421+
or
422+
value =
423+
any(Ruby::ExpressionReferencePattern g | this = TExpressionReferencePattern(g)).getValue()
424+
}
419425

420-
/** Gets the variable access corresponding to this variable reference pattern. */
421-
VariableReadAccess getVariableAccess() { toGenerated(result) = g.getName() }
426+
/** Gets the value this reference pattern matches against. */
427+
final Expr getValue() { toGenerated(result) = value }
422428

423-
final override string getAPrimaryQlClass() { result = "VariableReferencePattern" }
429+
final override string getAPrimaryQlClass() { result = "ReferencePattern" }
424430

425431
final override string toString() { result = "^..." }
426432

427-
final override AstNode getAChild(string pred) {
433+
override AstNode getAChild(string pred) {
428434
result = super.getAChild(pred)
429435
or
430-
pred = "getVariableAccess" and result = this.getVariableAccess()
436+
pred = "getValue" and result = this.getValue()
431437
}
432438
}
439+
440+
/**
441+
* DEPRECATED: Use `ReferencePattern` instead.
442+
*
443+
* A variable reference in a pattern, i.e. `^x` in the following example:
444+
* ```rb
445+
* x = 10
446+
* case expr
447+
* in ^x then puts "ok"
448+
* end
449+
* ```
450+
*/
451+
deprecated class VariableReferencePattern extends ReferencePattern, TVariableReferencePattern {
452+
/** Gets the variable access corresponding to this variable reference pattern. */
453+
final VariableReadAccess getVariableAccess() { result = this.getValue() }
454+
}

ruby/ql/lib/codeql/ruby/ast/internal/AST.qll

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,11 +320,14 @@ private module Cached {
320320
TUntilExpr(Ruby::Until g) or
321321
TUntilModifierExpr(Ruby::UntilModifier g) or
322322
TVariableReferencePattern(Ruby::VariableReferencePattern g) or
323+
TExpressionReferencePattern(Ruby::ExpressionReferencePattern g) or
323324
TWhenClause(Ruby::When g) or
324325
TWhileExpr(Ruby::While g) or
325326
TWhileModifierExpr(Ruby::WhileModifier g) or
326327
TYieldCall(Ruby::Yield g)
327328

329+
class TReferencePattern = TVariableReferencePattern or TExpressionReferencePattern;
330+
328331
class TAstNodeReal =
329332
TAddExprReal or TAliasStmt or TAlternativePattern or TArgumentList or TArrayPattern or
330333
TAsPattern or TAssignAddExpr or TAssignBitwiseAndExpr or TAssignBitwiseOrExpr or
@@ -359,7 +362,7 @@ private module Cached {
359362
TTernaryIfExpr or TThen or TTokenConstantAccess or TTokenMethodName or TTokenSuperCall or
360363
TToplevel or TTrueLiteral or TUnaryMinusExpr or TUnaryPlusExpr or TUndefStmt or
361364
TUnlessExpr or TUnlessModifierExpr or TUntilExpr or TUntilModifierExpr or
362-
TVariableReferencePattern or TWhenClause or TWhileExpr or TWhileModifierExpr or TYieldCall;
365+
TReferencePattern or TWhenClause or TWhileExpr or TWhileModifierExpr or TYieldCall;
363366

364367
class TAstNodeSynth =
365368
TAddExprSynth or TAssignExprSynth or TBitwiseAndExprSynth or TBitwiseOrExprSynth or
@@ -529,6 +532,7 @@ private module Cached {
529532
n = TUntilExpr(result) or
530533
n = TUntilModifierExpr(result) or
531534
n = TVariableReferencePattern(result) or
535+
n = TExpressionReferencePattern(result) or
532536
n = TWhenClause(result) or
533537
n = TWhileExpr(result) or
534538
n = TWhileModifierExpr(result) or

ruby/ql/lib/codeql/ruby/ast/internal/Variable.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,8 @@ private module Cached {
312312
i = any(Ruby::WhileModifier x).getCondition()
313313
or
314314
i = any(Ruby::WhileModifier x).getBody()
315+
or
316+
i = any(Ruby::ExpressionReferencePattern x).getValue()
315317
}
316318

317319
pragma[nomagic]

ruby/ql/lib/codeql/ruby/controlflow/internal/Completion.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ private predicate inMatchingContext(AstNode n) {
235235
or
236236
n instanceof CasePattern
237237
or
238-
n = any(VariableReferencePattern p).getVariableAccess()
238+
n = any(ReferencePattern p).getValue()
239239
or
240240
n.(Trees::DefaultValueParameterTree).hasDefaultValue()
241241
}

ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -731,8 +731,8 @@ module Trees {
731731
override ControlFlowTree getChildElement(int i) { result = this.getPattern() and i = 0 }
732732
}
733733

734-
private class VariableReferencePatternTree extends StandardPreOrderTree, VariableReferencePattern {
735-
override ControlFlowTree getChildElement(int i) { result = this.getVariableAccess() and i = 0 }
734+
private class ReferencePatternTree extends StandardPreOrderTree, ReferencePattern {
735+
override ControlFlowTree getChildElement(int i) { result = this.getValue() and i = 0 }
736736
}
737737

738738
private class InClauseTree extends PreOrderTree, InClause {

ruby/ql/test/library-tests/ast/Ast.expected

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -951,8 +951,8 @@ control/cases.rb:
951951
# 87| getBranch: [InClause] in ... then ...
952952
# 87| getPattern: [IntegerLiteral] 5
953953
# 88| getBranch: [InClause] in ... then ...
954-
# 88| getPattern: [VariableReferencePattern] ^...
955-
# 88| getVariableAccess: [LocalVariableAccess] foo
954+
# 88| getPattern: [ReferencePattern] ^...
955+
# 88| getValue: [LocalVariableAccess] foo
956956
# 89| getBranch: [InClause] in ... then ...
957957
# 89| getPattern: [StringLiteral] "string"
958958
# 89| getComponent: [StringTextComponent] string
@@ -1049,8 +1049,8 @@ control/cases.rb:
10491049
# 111| getBranch: [InClause] in ... then ...
10501050
# 111| getPattern: [AlternativePattern] ... | ...
10511051
# 111| getAlternative: [IntegerLiteral] 5
1052-
# 111| getAlternative: [VariableReferencePattern] ^...
1053-
# 111| getVariableAccess: [LocalVariableAccess] foo
1052+
# 111| getAlternative: [ReferencePattern] ^...
1053+
# 111| getValue: [LocalVariableAccess] foo
10541054
# 111| getAlternative: [StringLiteral] "string"
10551055
# 111| getComponent: [StringTextComponent] string
10561056
# 111| getAlternative: [LocalVariableAccess] var
@@ -1145,17 +1145,31 @@ control/cases.rb:
11451145
# 147| getValue: [MethodCall] call to expr
11461146
# 147| getReceiver: [Self, SelfVariableAccess] self
11471147
# 148| getBranch: [InClause] in ... then ...
1148-
# 148| getPattern: [VariableReferencePattern] ^...
1149-
# 148| getVariableAccess: [LocalVariableAccess] foo
1148+
# 148| getPattern: [ReferencePattern] ^...
1149+
# 148| getValue: [LocalVariableAccess] foo
11501150
# 149| getBranch: [InClause] in ... then ...
1151-
# 149| getPattern: [VariableReferencePattern] ^...
1152-
# 149| getVariableAccess: [GlobalVariableAccess] $foo
1151+
# 149| getPattern: [ReferencePattern] ^...
1152+
# 149| getValue: [GlobalVariableAccess] $foo
11531153
# 150| getBranch: [InClause] in ... then ...
1154-
# 150| getPattern: [VariableReferencePattern] ^...
1155-
# 150| getVariableAccess: [InstanceVariableAccess] @foo
1154+
# 150| getPattern: [ReferencePattern] ^...
1155+
# 150| getValue: [InstanceVariableAccess] @foo
11561156
# 151| getBranch: [InClause] in ... then ...
1157-
# 151| getPattern: [VariableReferencePattern] ^...
1158-
# 151| getVariableAccess: [ClassVariableAccess] @@foo
1157+
# 151| getPattern: [ReferencePattern] ^...
1158+
# 151| getValue: [ClassVariableAccess] @@foo
1159+
# 154| getStmt: [CaseExpr] case ...
1160+
# 154| getValue: [MethodCall] call to expr
1161+
# 154| getReceiver: [Self, SelfVariableAccess] self
1162+
# 155| getBranch: [InClause] in ... then ...
1163+
# 155| getPattern: [ReferencePattern] ^...
1164+
# 155| getValue: [LocalVariableAccess] foo
1165+
# 156| getBranch: [InClause] in ... then ...
1166+
# 156| getPattern: [ReferencePattern] ^...
1167+
# 156| getValue: [InstanceVariableAccess] @foo
1168+
# 157| getBranch: [InClause] in ... then ...
1169+
# 157| getPattern: [ReferencePattern] ^...
1170+
# 157| getValue: [AddExpr] ... + ...
1171+
# 157| getAnOperand/getLeftOperand/getReceiver: [IntegerLiteral] 1
1172+
# 157| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 1
11591173
modules/classes.rb:
11601174
# 2| [Toplevel] classes.rb
11611175
# 3| getStmt: [ClassDeclaration] Foo

ruby/ql/test/library-tests/ast/ValueText.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,10 @@
244244
| control/cases.rb:144:11:144:11 | :a | :a |
245245
| control/cases.rb:144:14:144:14 | 1 | 1 |
246246
| control/cases.rb:148:7:148:9 | foo | 42 |
247+
| control/cases.rb:155:8:155:10 | foo | 42 |
248+
| control/cases.rb:157:8:157:8 | 1 | 1 |
249+
| control/cases.rb:157:8:157:12 | ... + ... | 2 |
250+
| control/cases.rb:157:12:157:12 | 1 | 1 |
247251
| control/conditionals.rb:2:5:2:5 | 0 | 0 |
248252
| control/conditionals.rb:3:5:3:5 | 0 | 0 |
249253
| control/conditionals.rb:4:5:4:5 | 0 | 0 |

ruby/ql/test/library-tests/ast/control/CaseExpr.expected

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ caseValues
99
| cases.rb:128:1:133:3 | case ... | cases.rb:128:6:128:9 | call to expr |
1010
| cases.rb:137:1:145:3 | case ... | cases.rb:137:6:137:9 | call to expr |
1111
| cases.rb:147:1:152:3 | case ... | cases.rb:147:6:147:9 | call to expr |
12+
| cases.rb:154:1:158:3 | case ... | cases.rb:154:6:154:9 | call to expr |
1213
caseNoValues
1314
| cases.rb:18:1:22:3 | case ... |
1415
caseElseBranches
@@ -24,6 +25,7 @@ caseNoElseBranches
2425
| cases.rb:128:1:133:3 | case ... |
2526
| cases.rb:137:1:145:3 | case ... |
2627
| cases.rb:147:1:152:3 | case ... |
28+
| cases.rb:154:1:158:3 | case ... |
2729
caseWhenBranches
2830
| cases.rb:8:1:15:3 | case ... | cases.rb:9:1:10:7 | when ... | 0 | cases.rb:9:6:9:6 | b | cases.rb:9:7:10:7 | then ... |
2931
| cases.rb:8:1:15:3 | case ... | cases.rb:11:1:12:7 | when ... | 0 | cases.rb:11:6:11:6 | c | cases.rb:11:10:12:7 | then ... |
@@ -127,3 +129,6 @@ caseAllBranches
127129
| cases.rb:147:1:152:3 | case ... | 1 | cases.rb:149:3:149:11 | in ... then ... |
128130
| cases.rb:147:1:152:3 | case ... | 2 | cases.rb:150:3:150:11 | in ... then ... |
129131
| cases.rb:147:1:152:3 | case ... | 3 | cases.rb:151:3:151:12 | in ... then ... |
132+
| cases.rb:154:1:158:3 | case ... | 0 | cases.rb:155:3:155:12 | in ... then ... |
133+
| cases.rb:154:1:158:3 | case ... | 1 | cases.rb:156:3:156:13 | in ... then ... |
134+
| cases.rb:154:1:158:3 | case ... | 2 | cases.rb:157:3:157:14 | in ... then ... |

ruby/ql/test/library-tests/ast/control/ControlExpr.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
| cases.rb:128:1:133:3 | case ... | CaseExpr |
1010
| cases.rb:137:1:145:3 | case ... | CaseExpr |
1111
| cases.rb:147:1:152:3 | case ... | CaseExpr |
12+
| cases.rb:154:1:158:3 | case ... | CaseExpr |
1213
| conditionals.rb:10:1:12:3 | if ... | IfExpr |
1314
| conditionals.rb:15:1:19:3 | if ... | IfExpr |
1415
| conditionals.rb:22:1:30:3 | if ... | IfExpr |

ruby/ql/test/library-tests/ast/control/cases.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,10 @@
149149
in ^$foo;
150150
in ^@foo;
151151
in ^@@foo;
152+
end
153+
154+
case expr
155+
in ^(foo);
156+
in ^(@foo);
157+
in ^(1 + 1);
152158
end

0 commit comments

Comments
 (0)