Skip to content

Commit 7cfc696

Browse files
authored
Merge pull request github#7141 from hvitved/ruby/synthesis-realnode-recursion
Ruby: Eliminate unnecessary recursion through `RealNode`
2 parents f846915 + 9e8e2e2 commit 7cfc696

File tree

4 files changed

+100
-38
lines changed

4 files changed

+100
-38
lines changed

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

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ private module Cached {
167167
TLTExpr(Ruby::Binary g) { g instanceof @ruby_binary_langle } or
168168
TLambda(Ruby::Lambda g) or
169169
TLeftAssignmentList(Ruby::LeftAssignmentList g) or
170-
TLocalVariableAccessReal(Ruby::Identifier g, AST::LocalVariable v) {
170+
TLocalVariableAccessReal(Ruby::Identifier g, TLocalVariableReal v) {
171171
LocalVariableAccess::range(g, v)
172172
} or
173173
TLocalVariableAccessSynth(AST::AstNode parent, int i, AST::LocalVariable v) {
@@ -284,13 +284,55 @@ private module Cached {
284284
TWhileModifierExpr(Ruby::WhileModifier g) or
285285
TYieldCall(Ruby::Yield g)
286286

287+
class TAstNodeReal =
288+
TAddExprReal or TAliasStmt or TArgumentList or TAssignAddExpr or TAssignBitwiseAndExpr or
289+
TAssignBitwiseOrExpr or TAssignBitwiseXorExpr or TAssignDivExpr or TAssignExponentExpr or
290+
TAssignExprReal or TAssignLShiftExpr or TAssignLogicalAndExpr or TAssignLogicalOrExpr or
291+
TAssignModuloExpr or TAssignMulExpr or TAssignRShiftExpr or TAssignSubExpr or
292+
TBareStringLiteral or TBareSymbolLiteral or TBeginBlock or TBeginExpr or
293+
TBitwiseAndExprReal or TBitwiseOrExprReal or TBitwiseXorExprReal or TBlockArgument or
294+
TBlockParameter or TBraceBlock or TBreakStmt or TCaseEqExpr or TCaseExpr or
295+
TCharacterLiteral or TClassDeclaration or TClassVariableAccessReal or TComplementExpr or
296+
TComplexLiteral or TDefinedExpr or TDelimitedSymbolLiteral or TDestructuredLeftAssignment or
297+
TDivExprReal or TDo or TDoBlock or TElementReference or TElse or TElsif or TEmptyStmt or
298+
TEndBlock or TEnsure or TEqExpr or TExponentExprReal or TFalseLiteral or TFloatLiteral or
299+
TForExpr or TForIn or TForwardParameter or TForwardArgument or TGEExpr or TGTExpr or
300+
TGlobalVariableAccessReal or THashKeySymbolLiteral or THashLiteral or THashSplatExpr or
301+
THashSplatParameter or THereDoc or TIdentifierMethodCall or TIf or TIfModifierExpr or
302+
TInstanceVariableAccessReal or TIntegerLiteralReal or TKeywordParameter or TLEExpr or
303+
TLShiftExprReal or TLTExpr or TLambda or TLeftAssignmentList or TLocalVariableAccessReal or
304+
TLogicalAndExprReal or TLogicalOrExprReal or TMethod or TModuleDeclaration or
305+
TModuloExprReal or TMulExprReal or TNEExpr or TNextStmt or TNilLiteral or
306+
TNoRegExpMatchExpr or TNotExpr or TOptionalParameter or TPair or TParenthesizedExpr or
307+
TRShiftExprReal or TRangeLiteralReal or TRationalLiteral or TRedoStmt or TRegExpLiteral or
308+
TRegExpMatchExpr or TRegularArrayLiteral or TRegularMethodCall or TRegularStringLiteral or
309+
TRegularSuperCall or TRescueClause or TRescueModifierExpr or TRetryStmt or TReturnStmt or
310+
TScopeResolutionConstantAccess or TScopeResolutionMethodCall or TSelfReal or
311+
TSimpleParameter or TSimpleSymbolLiteral or TSingletonClass or TSingletonMethod or
312+
TSpaceshipExpr or TSplatExprReal or TSplatParameter or TStringArrayLiteral or
313+
TStringConcatenation or TStringEscapeSequenceComponent or TStringInterpolationComponent or
314+
TStringTextComponent or TSubExprReal or TSubshellLiteral or TSymbolArrayLiteral or
315+
TTernaryIfExpr or TThen or TTokenConstantAccess or TTokenMethodName or TTokenSuperCall or
316+
TToplevel or TTrueLiteral or TTuplePatternParameter or TUnaryMinusExpr or TUnaryPlusExpr or
317+
TUndefStmt or TUnlessExpr or TUnlessModifierExpr or TUntilExpr or TUntilModifierExpr or
318+
TWhenExpr or TWhileExpr or TWhileModifierExpr or TYieldCall;
319+
320+
class TAstNodeSynth =
321+
TAddExprSynth or TAssignExprSynth or TBitwiseAndExprSynth or TBitwiseOrExprSynth or
322+
TBitwiseXorExprSynth or TClassVariableAccessSynth or TConstantReadAccessSynth or
323+
TDivExprSynth or TExponentExprSynth or TGlobalVariableAccessSynth or
324+
TInstanceVariableAccessSynth or TIntegerLiteralSynth or TLShiftExprSynth or
325+
TLocalVariableAccessSynth or TLogicalAndExprSynth or TLogicalOrExprSynth or
326+
TMethodCallSynth or TModuloExprSynth or TMulExprSynth or TRShiftExprSynth or
327+
TRangeLiteralSynth or TSelfSynth or TSplatExprSynth or TStmtSequenceSynth or TSubExprSynth;
328+
287329
/**
288330
* Gets the underlying TreeSitter entity for a given AST node. This does not
289331
* include synthesized AST nodes, because they are not the primary AST node
290332
* for any given generated node.
291333
*/
292334
cached
293-
Ruby::AstNode toGenerated(AST::AstNode n) {
335+
Ruby::AstNode toGenerated(TAstNodeReal n) {
294336
n = TAddExprReal(result) or
295337
n = TAliasStmt(result) or
296338
n = TArgumentList(result) or
@@ -495,7 +537,9 @@ private module Cached {
495537
predicate synthChild(AST::AstNode parent, int i, AST::AstNode child) {
496538
child = getSynthChild(parent, i)
497539
or
498-
any(Synthesis s).child(parent, i, RealChild(child))
540+
any(Synthesis s).child(parent, i, RealChildRef(child))
541+
or
542+
any(Synthesis s).child(parent, i, SynthChildRef(child))
499543
}
500544

501545
/**
@@ -527,7 +571,7 @@ private module Cached {
527571

528572
import Cached
529573

530-
TAstNode fromGenerated(Ruby::AstNode n) { n = toGenerated(result) }
574+
TAstNodeReal fromGenerated(Ruby::AstNode n) { n = toGenerated(result) }
531575

532576
class TCall = TMethodCall or TYieldCall;
533577

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

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,25 @@ newtype SynthKind =
4646
*/
4747
newtype Child =
4848
SynthChild(SynthKind k) or
49-
RealChild(AstNode n)
49+
RealChildRef(TAstNodeReal n) or
50+
SynthChildRef(TAstNodeSynth n)
51+
52+
/**
53+
* The purpose of this inlined predicate is to split up child references into
54+
* those that are from real AST nodes (for which there will be no recursion
55+
* through `RealChildRef`), and those that are synthesized recursively
56+
* (for which there will be recursion through `SynthChildRef`).
57+
*
58+
* This performs much better than having a combined `ChildRef` that includes
59+
* both real and synthesized AST nodes, since the recursion happening in
60+
* `Synthesis::child/3` is non-linear.
61+
*/
62+
pragma[inline]
63+
private Child childRef(TAstNode n) {
64+
result = RealChildRef(n)
65+
or
66+
result = SynthChildRef(n)
67+
}
5068

5169
private newtype TSynthesis = MkSynthesis()
5270

@@ -125,7 +143,7 @@ private predicate assign(
125143
child = SynthChild(LocalVariableAccessSynthKind(v))
126144
or
127145
i = 1 and
128-
child = RealChild(value)
146+
child = childRef(value)
129147
)
130148
}
131149

@@ -218,10 +236,10 @@ private module SetterDesugar {
218236
exists(AstNode call | call = TMethodCallSynth(seq, 0, _, _, _) |
219237
parent = call and
220238
i = 0 and
221-
child = RealChild(sae.getReceiver())
239+
child = childRef(sae.getReceiver())
222240
or
223241
parent = call and
224-
child = RealChild(sae.getArgument(i - 1))
242+
child = childRef(sae.getArgument(i - 1))
225243
or
226244
exists(int valueIndex | valueIndex = sae.getNumberOfArguments() + 1 |
227245
parent = call and
@@ -234,7 +252,7 @@ private module SetterDesugar {
234252
child = SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(sae, 0)))
235253
or
236254
i = 1 and
237-
child = RealChild(sae.getRightOperand())
255+
child = childRef(sae.getRightOperand())
238256
)
239257
)
240258
)
@@ -357,7 +375,7 @@ private module AssignOperationDesugar {
357375
exists(AstNode assign | assign = TAssignExprSynth(vao, -1) |
358376
parent = assign and
359377
i = 0 and
360-
child = RealChild(vao.getLeftOperand())
378+
child = childRef(vao.getLeftOperand())
361379
or
362380
parent = assign and
363381
i = 1 and
@@ -369,7 +387,7 @@ private module AssignOperationDesugar {
369387
child = SynthChild(vao.getVariableAccessKind())
370388
or
371389
i = 1 and
372-
child = RealChild(vao.getRightOperand())
390+
child = childRef(vao.getRightOperand())
373391
)
374392
)
375393
)
@@ -477,7 +495,7 @@ private module AssignOperationDesugar {
477495
or
478496
parent = op and
479497
i = 1 and
480-
child = RealChild(sao.getRightOperand())
498+
child = childRef(sao.getRightOperand())
481499
)
482500
)
483501
or
@@ -648,7 +666,7 @@ private module CompoundAssignDesugar {
648666
or
649667
parent = TSplatExprSynth(assign, 1) and
650668
i = 0 and
651-
child = RealChild(tae.getRightOperand())
669+
child = childRef(tae.getRightOperand())
652670
)
653671
or
654672
exists(Pattern p, int j, int restIndex |
@@ -662,7 +680,7 @@ private module CompoundAssignDesugar {
662680
exists(AstNode assign | assign = TAssignExprSynth(seq, j + 1) |
663681
parent = assign and
664682
i = 0 and
665-
child = RealChild(p)
683+
child = childRef(p)
666684
or
667685
parent = assign and
668686
i = 1 and
@@ -767,7 +785,7 @@ private module ArrayLiteralDesugar {
767785
child = SynthChild(ConstantReadAccessKind("::Array"))
768786
or
769787
parent = mc and
770-
child = RealChild(al.getElement(i - 1))
788+
child = childRef(al.getElement(i - 1))
771789
)
772790
)
773791
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ abstract class VariableAccessImpl extends Expr, TVariableAccess {
495495
}
496496

497497
module LocalVariableAccess {
498-
predicate range(Ruby::Identifier id, LocalVariable v) {
498+
predicate range(Ruby::Identifier id, TLocalVariableReal v) {
499499
access(id, v) and
500500
(
501501
explicitWriteAccess(id, _)

ruby/ql/test/library-tests/controlflow/graph/Cfg.expected

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ break_ensure.rb:
4141
#-----| -> do ...
4242

4343
# 3| ... > ...
44-
#-----| raise -> for ... in ...
4544
#-----| true -> break
45+
#-----| raise -> for ... in ...
4646
#-----| false -> if ...
4747

4848
# 3| element
@@ -580,12 +580,12 @@ cfg.html.erb:
580580
# 12| self
581581
#-----| -> call to a
582582

583-
# 12| Pair
584-
#-----| -> call to link_to
585-
586583
# 12| :id
587584
#-----| -> "a"
588585

586+
# 12| Pair
587+
#-----| -> call to link_to
588+
589589
# 12| "a"
590590
#-----| -> Pair
591591

@@ -813,12 +813,12 @@ cfg.rb:
813813
# 23| 1
814814
#-----| -> ... + ...
815815

816-
# 25| 2
817-
#-----| -> { ... }
818-
819816
# 25| call to times
820817
#-----| -> self
821818

819+
# 25| 2
820+
#-----| -> { ... }
821+
822822
# 25| enter { ... }
823823
#-----| -> x
824824

@@ -1493,12 +1493,12 @@ cfg.rb:
14931493
# 97| "d"
14941494
#-----| -> Pair
14951495

1496-
# 97| Pair
1497-
#-----| -> {...}
1498-
14991496
# 97| :e
15001497
#-----| -> "f"
15011498

1499+
# 97| Pair
1500+
#-----| -> {...}
1501+
15021502
# 97| "f"
15031503
#-----| -> Pair
15041504

@@ -1619,12 +1619,12 @@ cfg.rb:
16191619
# 110| type
16201620
#-----| -> #{...}
16211621

1622-
# 113| ... if ...
1623-
#-----| -> C
1624-
16251622
# 113| call to puts
16261623
#-----| -> ... if ...
16271624

1625+
# 113| ... if ...
1626+
#-----| -> C
1627+
16281628
# 113| self
16291629
#-----| -> "hi"
16301630

@@ -1826,16 +1826,16 @@ cfg.rb:
18261826
# 134| EmptyModule
18271827
#-----| -> ... rescue ...
18281828

1829-
# 136| ... rescue ...
1830-
#-----| -> 1
1831-
18321829
# 136| ... / ...
18331830
#-----| raise -> self
18341831
#-----| -> __synth__0
18351832

18361833
# 136| 1
18371834
#-----| -> 0
18381835

1836+
# 136| ... rescue ...
1837+
#-----| -> 1
1838+
18391839
# 136| 0
18401840
#-----| -> ... / ...
18411841

@@ -2708,12 +2708,12 @@ desugar.rb:
27082708
# 18| __synth__2
27092709
#-----| -> __synth__3
27102710

2711-
# 18| ... + ...
2712-
#-----| -> ... = ...
2713-
27142711
# 18| call to baz
27152712
#-----| -> 3
27162713

2714+
# 18| ... + ...
2715+
#-----| -> ... = ...
2716+
27172717
# 18| x
27182718
#-----| -> call to baz
27192719

@@ -5076,12 +5076,12 @@ raise.rb:
50765076
# 155| elem
50775077
#-----| -> element
50785078

5079-
# 155| ... if ...
5080-
#-----| -> exit { ... } (normal)
5081-
50825079
# 155| call to raise
50835080
#-----| raise -> exit { ... } (abnormal)
50845081

5082+
# 155| ... if ...
5083+
#-----| -> exit { ... } (normal)
5084+
50855085
# 155| self
50865086
#-----| -> ""
50875087

0 commit comments

Comments
 (0)