Skip to content

Commit b6d167e

Browse files
committed
Ruby: Split callable and its body into two AST nodes.
1 parent cb0fc78 commit b6d167e

12 files changed

Lines changed: 142 additions & 90 deletions

File tree

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ class StmtSequence extends Expr, TStmtSequence {
167167
*/
168168
class BodyStmt extends StmtSequence, TBodyStmt {
169169
final override Stmt getStmt(int n) {
170+
synthChild(this, n, result)
171+
or
170172
toGenerated(result) =
171173
rank[n + 1](Ruby::AstNode node, int i |
172174
node = getBodyStmtChild(this, i) and

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

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ private import internal.TreeSitter
88
private import internal.Method
99

1010
/** A callable. */
11-
class Callable extends StmtSequence, Expr, Scope, TCallable {
11+
class Callable extends Expr, Scope, TCallable {
1212
/** Gets the number of parameters of this callable. */
1313
final int getNumberOfParameters() { result = count(this.getAParameter()) }
1414

@@ -18,27 +18,25 @@ class Callable extends StmtSequence, Expr, Scope, TCallable {
1818
/** Gets the `n`th parameter of this callable. */
1919
Parameter getParameter(int n) { none() }
2020

21+
BodyStmt getBody() { none() }
22+
2123
override AstNode getAChild(string pred) {
2224
result = super.getAChild(pred)
2325
or
26+
pred = "getBody" and result = this.getBody()
27+
or
2428
pred = "getParameter" and result = this.getParameter(_)
2529
}
2630
}
2731

2832
/** A method. */
29-
class MethodBase extends Callable, BodyStmt, Scope, TMethodBase {
33+
class MethodBase extends Callable, Scope, TMethodBase {
3034
/** Gets the name of this method. */
3135
string getName() { none() }
3236

3337
/** Holds if the name of this method is `name`. */
3438
final predicate hasName(string name) { this.getName() = name }
3539

36-
override AstNode getAChild(string pred) {
37-
result = Callable.super.getAChild(pred)
38-
or
39-
result = BodyStmt.super.getAChild(pred)
40-
}
41-
4240
/**
4341
* Holds if this method is public.
4442
* Methods are public by default.
@@ -218,6 +216,10 @@ class Method extends MethodBase, TMethod {
218216
toGenerated(result) = g.getParameters().getChild(n)
219217
}
220218

219+
final override BodyStmt getBody() {
220+
toGenerated(result) = g.getBody() or synthChild(this, _, result)
221+
}
222+
221223
final override string toString() { result = this.getName() }
222224

223225
overlay[global]
@@ -280,6 +282,10 @@ class SingletonMethod extends MethodBase, TSingletonMethod {
280282
toGenerated(result) = g.getParameters().getChild(n)
281283
}
282284

285+
final override BodyStmt getBody() {
286+
toGenerated(result) = g.getBody() or synthChild(this, _, result)
287+
}
288+
283289
final override string toString() { result = this.getName() }
284290

285291
final override AstNode getAChild(string pred) {
@@ -321,7 +327,7 @@ class SingletonMethod extends MethodBase, TSingletonMethod {
321327
* -> (x) { x + 1 }
322328
* ```
323329
*/
324-
class Lambda extends Callable, BodyStmt, TLambda {
330+
class Lambda extends Callable, TLambda {
325331
private Ruby::Lambda g;
326332

327333
Lambda() { this = TLambda(g) }
@@ -332,13 +338,12 @@ class Lambda extends Callable, BodyStmt, TLambda {
332338
toGenerated(result) = g.getParameters().getChild(n)
333339
}
334340

335-
final override string toString() { result = "-> { ... }" }
336-
337-
final override AstNode getAChild(string pred) {
338-
result = Callable.super.getAChild(pred)
339-
or
340-
result = BodyStmt.super.getAChild(pred)
341+
final override BodyStmt getBody() {
342+
toGenerated(result) = g.getBody().(Ruby::DoBlock).getBody() or
343+
toGenerated(result) = g.getBody().(Ruby::Block).getBody()
341344
}
345+
346+
final override string toString() { result = "-> { ... }" }
342347
}
343348

344349
/** A block. */
@@ -355,15 +360,15 @@ class Block extends Callable, Scope, TBlock {
355360
*/
356361
LocalVariableWriteAccess getLocalVariable(int n) { none() }
357362

358-
override AstNode getAChild(string pred) {
363+
final override AstNode getAChild(string pred) {
359364
result = Callable.super.getAChild(pred)
360365
or
361366
pred = "getLocalVariable" and result = this.getLocalVariable(_)
362367
}
363368
}
364369

365370
/** A block enclosed within `do` and `end`. */
366-
class DoBlock extends Block, BodyStmt, TDoBlock {
371+
class DoBlock extends Block, TDoBlock {
367372
private Ruby::DoBlock g;
368373

369374
DoBlock() { this = TDoBlock(g) }
@@ -376,13 +381,9 @@ class DoBlock extends Block, BodyStmt, TDoBlock {
376381
toGenerated(result) = g.getParameters().getChild(n)
377382
}
378383

379-
final override string toString() { result = "do ... end" }
384+
final override BodyStmt getBody() { toGenerated(result) = g.getBody() }
380385

381-
final override AstNode getAChild(string pred) {
382-
result = Block.super.getAChild(pred)
383-
or
384-
result = BodyStmt.super.getAChild(pred)
385-
}
386+
final override string toString() { result = "do ... end" }
386387

387388
final override string getAPrimaryQlClass() { result = "DoBlock" }
388389
}

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

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,16 @@ private module Cached {
100100
} or
101101
TBlockArgument(Ruby::BlockArgument g) or
102102
TBlockParameter(Ruby::BlockParameter g) or
103+
TBodyStatement(Ruby::BodyStatement g) {
104+
any(Ruby::Method m).getBody() = g or
105+
any(Ruby::SingletonMethod m).getBody() = g or
106+
any(Ruby::DoBlock b).getBody() = g
107+
} or
108+
TBodyStmtSynth(Ast::AstNode parent, int i) { mkSynthChild(BodyStmtKind(), parent, i) } or
103109
TBooleanLiteralSynth(Ast::AstNode parent, int i, boolean value) {
104110
mkSynthChild(BooleanLiteralKind(value), parent, i)
105111
} or
112+
TBraceBlockBody(Ruby::BlockBody g) or
106113
TBraceBlockSynth(Ast::AstNode parent, int i) { mkSynthChild(BraceBlockKind(), parent, i) } or
107114
TBraceBlockReal(Ruby::Block g) { not g.getParent() instanceof Ruby::Lambda } or
108115
TBreakStmt(Ruby::Break g) or
@@ -362,23 +369,24 @@ private module Cached {
362369
TAssignMulExpr or TAssignRShiftExpr or TAssignSubExpr or TBareStringLiteral or
363370
TBareSymbolLiteral or TBeginBlock or TBeginExpr or TBitwiseAndExprReal or
364371
TBitwiseOrExprReal or TBitwiseXorExprReal or TBlockArgument or TBlockParameter or
365-
TBraceBlockReal or TBreakStmt or TCaseEqExpr or TCaseExpr or TCaseMatchReal or
366-
TCharacterLiteral or TClassDeclaration or TClassVariableAccessReal or TComplementExpr or
367-
TComplexLiteral or TDefinedExprReal or TDelimitedSymbolLiteral or
368-
TDestructuredLeftAssignment or TDestructuredParameter or TDivExprReal or TDo or TDoBlock or
369-
TElementReference or TElseReal or TElsif or TEmptyStmt or TEncoding or TEndBlock or
370-
TEnsure or TEqExpr or TExponentExprReal or TFalseLiteral or TFile or TFindPattern or
371-
TFloatLiteral or TForExpr or TForwardParameter or TForwardArgument or TGEExpr or TGTExpr or
372-
TGlobalVariableAccessReal or THashKeySymbolLiteral or THashLiteral or THashPattern or
373-
THashSplatExprReal or THashSplatNilParameter or THashSplatParameter or THereDoc or
374-
TIdentifierMethodCall or TIfReal or TIfModifierExpr or TInClauseReal or
375-
TInstanceVariableAccessReal or TIntegerLiteralReal or TKeywordParameter or TLEExpr or
376-
TLShiftExprReal or TLTExpr or TLambda or TLeftAssignmentList or TLine or
377-
TLocalVariableAccessReal or TLogicalAndExprReal or TLogicalOrExprReal or TMethod or
378-
TMatchPattern or TModuleDeclaration or TModuloExprReal or TMulExprReal or TNEExpr or
379-
TNextStmt or TNilLiteralReal or TNoRegExpMatchExpr or TNotExprReal or TOptionalParameter or
380-
TPairReal or TParenthesizedExpr or TParenthesizedPattern or TRShiftExprReal or
381-
TRangeLiteralReal or TRationalLiteral or TRedoStmt or TRegExpLiteral or TRegExpMatchExpr or
372+
TBodyStatement or TBraceBlockBody or TBraceBlockReal or TBreakStmt or TCaseEqExpr or
373+
TCaseExpr or TCaseMatchReal or TCharacterLiteral or TClassDeclaration or
374+
TClassVariableAccessReal or TComplementExpr or TComplexLiteral or TDefinedExprReal or
375+
TDelimitedSymbolLiteral or TDestructuredLeftAssignment or TDestructuredParameter or
376+
TDivExprReal or TDo or TDoBlock or TElementReference or TElseReal or TElsif or TEmptyStmt or
377+
TEncoding or TEndBlock or TEnsure or TEqExpr or TExponentExprReal or TFalseLiteral or
378+
TFile or TFindPattern or TFloatLiteral or TForExpr or TForwardParameter or
379+
TForwardArgument or TGEExpr or TGTExpr or TGlobalVariableAccessReal or
380+
THashKeySymbolLiteral or THashLiteral or THashPattern or THashSplatExprReal or
381+
THashSplatNilParameter or THashSplatParameter or THereDoc or TIdentifierMethodCall or
382+
TIfReal or TIfModifierExpr or TInClauseReal or TInstanceVariableAccessReal or
383+
TIntegerLiteralReal or TKeywordParameter or TLEExpr or TLShiftExprReal or TLTExpr or
384+
TLambda or TLeftAssignmentList or TLine or TLocalVariableAccessReal or
385+
TLogicalAndExprReal or TLogicalOrExprReal or TMethod or TMatchPattern or
386+
TModuleDeclaration or TModuloExprReal or TMulExprReal or TNEExpr or TNextStmt or
387+
TNilLiteralReal or TNoRegExpMatchExpr or TNotExprReal or TOptionalParameter or TPairReal or
388+
TParenthesizedExpr or TParenthesizedPattern or TRShiftExprReal or TRangeLiteralReal or
389+
TRationalLiteral or TRedoStmt or TRegExpLiteral or TRegExpMatchExpr or
382390
TRegularArrayLiteral or TRegularMethodCall or TRegularStringLiteral or TRegularSuperCall or
383391
TRescueClause or TRescueModifierExpr or TRetryStmt or TReturnStmt or
384392
TScopeResolutionConstantAccess or TSelfReal or TSimpleParameterReal or
@@ -393,13 +401,13 @@ private module Cached {
393401

394402
class TAstNodeSynth =
395403
TAddExprSynth or TAssignExprSynth or TBitwiseAndExprSynth or TBitwiseOrExprSynth or
396-
TBitwiseXorExprSynth or TBraceBlockSynth or TBooleanLiteralSynth or TCaseMatchSynth or
397-
TClassVariableAccessSynth or TConstantReadAccessSynth or TConstantWriteAccessSynth or
398-
TDivExprSynth or TElseSynth or TExponentExprSynth or TGlobalVariableAccessSynth or
399-
TIfSynth or TInClauseSynth or TInstanceVariableAccessSynth or TIntegerLiteralSynth or
400-
TLShiftExprSynth or TLocalVariableAccessSynth or TLogicalAndExprSynth or
401-
TLogicalOrExprSynth or TMethodCallSynth or TModuloExprSynth or TMulExprSynth or
402-
TNilLiteralSynth or TRShiftExprSynth or TRangeLiteralSynth or TSelfSynth or
404+
TBitwiseXorExprSynth or TBraceBlockSynth or TBodyStmtSynth or TBooleanLiteralSynth or
405+
TCaseMatchSynth or TClassVariableAccessSynth or TConstantReadAccessSynth or
406+
TConstantWriteAccessSynth or TDivExprSynth or TElseSynth or TExponentExprSynth or
407+
TGlobalVariableAccessSynth or TIfSynth or TInClauseSynth or TInstanceVariableAccessSynth or
408+
TIntegerLiteralSynth or TLShiftExprSynth or TLocalVariableAccessSynth or
409+
TLogicalAndExprSynth or TLogicalOrExprSynth or TMethodCallSynth or TModuloExprSynth or
410+
TMulExprSynth or TNilLiteralSynth or TRShiftExprSynth or TRangeLiteralSynth or TSelfSynth or
403411
TSimpleParameterSynth or TSplatExprSynth or THashSplatExprSynth or TStmtSequenceSynth or
404412
TSubExprSynth or TPairSynth or TSimpleSymbolLiteralSynth;
405413

@@ -439,6 +447,8 @@ private module Cached {
439447
n = TBitwiseXorExprReal(result) or
440448
n = TBlockArgument(result) or
441449
n = TBlockParameter(result) or
450+
n = TBodyStatement(result) or
451+
n = TBraceBlockBody(result) or
442452
n = TBraceBlockReal(result) or
443453
n = TBreakStmt(result) or
444454
n = TCaseEqExpr(result) or
@@ -584,6 +594,8 @@ private module Cached {
584594
or
585595
result = TBitwiseXorExprSynth(parent, i)
586596
or
597+
result = TBodyStmtSynth(parent, i)
598+
or
587599
result = TBooleanLiteralSynth(parent, i, _)
588600
or
589601
result = TBraceBlockSynth(parent, i)
@@ -757,9 +769,9 @@ class TElse = TElseReal or TElseSynth;
757769

758770
class TStmtSequence =
759771
TBeginBlock or TEndBlock or TThen or TElse or TDo or TEnsure or TStringInterpolationComponent or
760-
TBlock or TBodyStmt or TParenthesizedExpr or TStmtSequenceSynth;
772+
TBodyStmt or TParenthesizedExpr or TStmtSequenceSynth;
761773

762-
class TBodyStmt = TBeginExpr or TModuleBase or TMethod or TLambda or TDoBlock or TSingletonMethod;
774+
class TBodyStmt = TBeginExpr or TModuleBase or TBraceBlockBody or TBodyStatement or TBodyStmtSynth;
763775

764776
class TNilLiteral = TNilLiteralReal or TNilLiteralSynth;
765777

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

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -64,27 +64,31 @@ class Ensure extends StmtSequence, TEnsure {
6464

6565
// Not defined by dispatch, as it should not be exposed
6666
Ruby::AstNode getBodyStmtChild(TBodyStmt b, int i) {
67-
exists(Ruby::Method g, Ruby::AstNode body | b = TMethod(g) and body = g.getBody() |
68-
result = body.(Ruby::BodyStatement).getChild(i)
69-
or
70-
i = 0 and result = body and not body instanceof Ruby::BodyStatement
71-
)
72-
or
73-
exists(Ruby::SingletonMethod g, Ruby::AstNode body |
74-
b = TSingletonMethod(g) and body = g.getBody()
75-
|
76-
result = body.(Ruby::BodyStatement).getChild(i)
77-
or
78-
i = 0 and result = body and not body instanceof Ruby::BodyStatement
79-
)
80-
or
81-
exists(Ruby::Lambda g | b = TLambda(g) |
82-
result = g.getBody().(Ruby::DoBlock).getBody().getChild(i) or
83-
result = g.getBody().(Ruby::Block).getBody().getChild(i)
84-
)
67+
result = any(Ruby::BlockBody g | b = TBraceBlockBody(g)).getChild(i)
8568
or
86-
result = any(Ruby::DoBlock g | b = TDoBlock(g)).getBody().getChild(i)
69+
result = any(Ruby::BodyStatement g | b = TBodyStatement(g)).getChild(i)
8770
or
71+
// exists(Ruby::Method g, Ruby::AstNode body | b = TMethod(g) and body = g.getBody() |
72+
// result = body.(Ruby::BodyStatement).getChild(i)
73+
// or
74+
// i = 0 and result = body and not body instanceof Ruby::BodyStatement
75+
// )
76+
// or
77+
// exists(Ruby::SingletonMethod g, Ruby::AstNode body |
78+
// b = TSingletonMethod(g) and body = g.getBody()
79+
// |
80+
// result = body.(Ruby::BodyStatement).getChild(i)
81+
// or
82+
// i = 0 and result = body and not body instanceof Ruby::BodyStatement
83+
// )
84+
// or
85+
// exists(Ruby::Lambda g | b = TLambda(g) |
86+
// result = g.getBody().(Ruby::DoBlock).getBody().getChild(i) or
87+
// result = g.getBody().(Ruby::Block).getBody().getChild(i)
88+
// )
89+
// or
90+
// result = any(Ruby::DoBlock g | b = TDoBlock(g)).getBody().getChild(i)
91+
// or
8892
result = any(Ruby::Program g | b = TToplevel(g)).getChild(i) and
8993
not result instanceof Ruby::BeginBlock
9094
or

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class BraceBlockReal extends BraceBlock, TBraceBlockReal {
1818
toGenerated(result) = g.getParameters().getChild(n)
1919
}
2020

21-
final override Stmt getStmt(int i) { toGenerated(result) = g.getBody().getChild(i) }
21+
final override BodyStmt getBody() { toGenerated(result) = g.getBody() }
2222
}
2323

2424
/**
@@ -28,8 +28,5 @@ class BraceBlockReal extends BraceBlock, TBraceBlockReal {
2828
class BraceBlockSynth extends BraceBlock, TBraceBlockSynth {
2929
final override Parameter getParameter(int n) { synthChild(this, n, result) }
3030

31-
final override Stmt getStmt(int i) {
32-
i >= 0 and
33-
synthChild(this, i + this.getNumberOfParameters(), result)
34-
}
31+
final override BodyStmt getBody() { synthChild(this, _, result) }
3532
}

0 commit comments

Comments
 (0)