Skip to content

Commit 56f8d5d

Browse files
authored
Merge pull request github#14229 from hvitved/ruby/splat-flow-performance
Ruby: Improve performance of flow through (hash) splats
2 parents f24abee + c570083 commit 56f8d5d

File tree

23 files changed

+5005
-4773
lines changed

23 files changed

+5005
-4773
lines changed

ruby/ql/lib/codeql/ruby/ApiGraphs.qll

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -886,8 +886,6 @@ module API {
886886
)
887887
or
888888
implicitCallEdge(pred, succ)
889-
or
890-
exists(DataFlow::HashLiteralNode splat | hashSplatEdge(splat, pred, succ))
891889
}
892890

893891
/**
@@ -986,29 +984,6 @@ module API {
986984
)
987985
}
988986

989-
pragma[nomagic]
990-
private DataFlow::Node getHashSplatArgument(DataFlow::HashLiteralNode literal) {
991-
result = DataFlowPrivate::TSynthHashSplatArgumentNode(literal.asExpr())
992-
}
993-
994-
/**
995-
* Holds if the epsilon edge `pred -> succ` should be generated to account for the members of a hash literal.
996-
*
997-
* This currently exists because hash literals are desugared to `Hash.[]` calls, whose summary relies on `WithContent`.
998-
* However, `contentEdge` does not currently generate edges for `WithContent` steps.
999-
*/
1000-
bindingset[literal]
1001-
pragma[inline_late]
1002-
private predicate hashSplatEdge(DataFlow::HashLiteralNode literal, ApiNode pred, ApiNode succ) {
1003-
exists(TypeTracker t |
1004-
pred = Impl::MkForwardNode(getALocalSourceStrict(getHashSplatArgument(literal)), t) and
1005-
succ = Impl::MkForwardNode(pragma[only_bind_out](literal), pragma[only_bind_out](t))
1006-
or
1007-
succ = Impl::MkBackwardNode(getALocalSourceStrict(getHashSplatArgument(literal)), t) and
1008-
pred = Impl::MkBackwardNode(pragma[only_bind_out](literal), pragma[only_bind_out](t))
1009-
)
1010-
}
1011-
1012987
pragma[nomagic]
1013988
private DataFlow::LocalSourceNode getAModuleReference(DataFlow::ModuleNode mod) {
1014989
result = mod.getAnImmediateReference()

ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,7 @@ private module Cached {
437437
FlowSummaryImplSpecific::ParsePositions::isParsedKeywordParameterPosition(_, name)
438438
} or
439439
THashSplatArgumentPosition() or
440+
TSynthHashSplatArgumentPosition() or
440441
TSplatArgumentPosition(int pos) { exists(Call c | c.getArgument(pos) instanceof SplatExpr) } or
441442
TSynthSplatArgumentPosition() or
442443
TAnyArgumentPosition() or
@@ -461,14 +462,10 @@ private module Cached {
461462
FlowSummaryImplSpecific::ParsePositions::isParsedKeywordArgumentPosition(_, name)
462463
} or
463464
THashSplatParameterPosition() or
464-
// To get flow from a hash-splat argument to a keyword parameter, we add a read-step
465-
// from a synthetic hash-splat parameter. We need this separate synthetic ParameterNode,
466-
// since we clear content of the normal hash-splat parameter for the names that
467-
// correspond to normal keyword parameters. Since we cannot re-use the same parameter
468-
// position for multiple parameter nodes in the same callable, we introduce this
469-
// synthetic parameter position.
470465
TSynthHashSplatParameterPosition() or
471466
TSplatParameterPosition(int pos) {
467+
pos = 0
468+
or
472469
exists(Parameter p | p.getPosition() = pos and p instanceof SplatParameter)
473470
} or
474471
TSynthSplatParameterPosition() or
@@ -1297,12 +1294,15 @@ class ParameterPosition extends TParameterPosition {
12971294
/** Holds if this position represents a hash-splat parameter. */
12981295
predicate isHashSplat() { this = THashSplatParameterPosition() }
12991296

1297+
/** Holds if this position represents a synthetic hash-splat parameter. */
13001298
predicate isSynthHashSplat() { this = TSynthHashSplatParameterPosition() }
13011299

1302-
predicate isSynthSplat() { this = TSynthSplatParameterPosition() }
1303-
1300+
/** Holds if this position represents a splat parameter at position `n`. */
13041301
predicate isSplat(int n) { this = TSplatParameterPosition(n) }
13051302

1303+
/** Holds if this position represents a synthetic splat parameter. */
1304+
predicate isSynthSplat() { this = TSynthSplatParameterPosition() }
1305+
13061306
/**
13071307
* Holds if this position represents any parameter, except `self` parameters. This
13081308
* includes both positional, named, and block parameters.
@@ -1334,9 +1334,9 @@ class ParameterPosition extends TParameterPosition {
13341334
or
13351335
this.isAnyNamed() and result = "any-named"
13361336
or
1337-
this.isSynthSplat() and result = "synthetic *"
1338-
or
13391337
exists(int pos | this.isSplat(pos) and result = "* (position " + pos + ")")
1338+
or
1339+
this.isSynthSplat() and result = "synthetic *"
13401340
}
13411341
}
13421342

@@ -1366,14 +1366,16 @@ class ArgumentPosition extends TArgumentPosition {
13661366
/** Holds if this position represents any positional parameter. */
13671367
predicate isAnyNamed() { this = TAnyKeywordArgumentPosition() }
13681368

1369-
/**
1370-
* Holds if this position represents a synthesized argument containing all keyword
1371-
* arguments wrapped in a hash.
1372-
*/
1369+
/** Holds if this position represents a hash-splat argument. */
13731370
predicate isHashSplat() { this = THashSplatArgumentPosition() }
13741371

1372+
/** Holds if this position represents a synthetic hash-splat argument. */
1373+
predicate isSynthHashSplat() { this = TSynthHashSplatArgumentPosition() }
1374+
1375+
/** Holds if this position represents a splat argument at position `n`. */
13751376
predicate isSplat(int n) { this = TSplatArgumentPosition(n) }
13761377

1378+
/** Holds if this position represents a synthetic splat argument. */
13771379
predicate isSynthSplat() { this = TSynthSplatArgumentPosition() }
13781380

13791381
/** Gets a textual representation of this position. */
@@ -1394,9 +1396,11 @@ class ArgumentPosition extends TArgumentPosition {
13941396
or
13951397
this.isHashSplat() and result = "**"
13961398
or
1397-
this.isSynthSplat() and result = "synthetic *"
1399+
this.isSynthHashSplat() and result = "synthetic **"
13981400
or
13991401
exists(int pos | this.isSplat(pos) and result = "* (position " + pos + ")")
1402+
or
1403+
this.isSynthSplat() and result = "synthetic *"
14001404
}
14011405
}
14021406

@@ -1429,17 +1433,21 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
14291433
or
14301434
exists(string name | ppos.isKeyword(name) and apos.isKeyword(name))
14311435
or
1432-
ppos.isHashSplat() and apos.isHashSplat()
1433-
or
1434-
ppos.isSynthHashSplat() and apos.isHashSplat()
1436+
(ppos.isHashSplat() or ppos.isSynthHashSplat()) and
1437+
(apos.isHashSplat() or apos.isSynthHashSplat())
14351438
or
1436-
ppos.isSplat(0) and apos.isSynthSplat()
1437-
or
1438-
ppos.isSynthSplat() and
1439-
(apos.isSynthSplat() or apos.isSplat(0))
1440-
or
1441-
// Exact splat match
1442-
exists(int n | apos.isSplat(n) and ppos.isSplat(n))
1439+
exists(int pos |
1440+
(
1441+
ppos.isSplat(pos)
1442+
or
1443+
ppos.isSynthSplat() and pos = 0
1444+
) and
1445+
(
1446+
apos.isSplat(pos)
1447+
or
1448+
apos.isSynthSplat() and pos = 0
1449+
)
1450+
)
14431451
or
14441452
ppos.isAny() and argumentPositionIsNotSelf(apos)
14451453
or

0 commit comments

Comments
 (0)