Skip to content

Commit e7b0910

Browse files
committed
Ruby: Eliminate unnecessary recursion through RealNode
1 parent 3a8e2db commit e7b0910

File tree

3 files changed

+78
-16
lines changed

3 files changed

+78
-16
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, _)

0 commit comments

Comments
 (0)