mirror of
https://github.com/github/codeql.git
synced 2025-12-20 18:56:32 +01:00
Merge pull request #11461 from hvitved/ruby/unique-hash-splat-param
Ruby: At most one hash-splat `ParameterNode` per callable
This commit is contained in:
@@ -520,7 +520,8 @@ module Private {
|
|||||||
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
|
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
|
||||||
parameterReadState(c, _, pos)
|
parameterReadState(c, _, pos)
|
||||||
or
|
or
|
||||||
isParameterPostUpdate(_, c, pos)
|
// Same as `isParameterPostUpdate(_, c, pos)`, but can be used in a negative context
|
||||||
|
any(SummaryNodeState state).isOutputState(c, SummaryComponentStack::argument(pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate callbackOutput(
|
private predicate callbackOutput(
|
||||||
|
|||||||
@@ -520,7 +520,8 @@ module Private {
|
|||||||
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
|
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
|
||||||
parameterReadState(c, _, pos)
|
parameterReadState(c, _, pos)
|
||||||
or
|
or
|
||||||
isParameterPostUpdate(_, c, pos)
|
// Same as `isParameterPostUpdate(_, c, pos)`, but can be used in a negative context
|
||||||
|
any(SummaryNodeState state).isOutputState(c, SummaryComponentStack::argument(pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate callbackOutput(
|
private predicate callbackOutput(
|
||||||
|
|||||||
@@ -520,7 +520,8 @@ module Private {
|
|||||||
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
|
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
|
||||||
parameterReadState(c, _, pos)
|
parameterReadState(c, _, pos)
|
||||||
or
|
or
|
||||||
isParameterPostUpdate(_, c, pos)
|
// Same as `isParameterPostUpdate(_, c, pos)`, but can be used in a negative context
|
||||||
|
any(SummaryNodeState state).isOutputState(c, SummaryComponentStack::argument(pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate callbackOutput(
|
private predicate callbackOutput(
|
||||||
|
|||||||
@@ -520,7 +520,8 @@ module Private {
|
|||||||
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
|
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
|
||||||
parameterReadState(c, _, pos)
|
parameterReadState(c, _, pos)
|
||||||
or
|
or
|
||||||
isParameterPostUpdate(_, c, pos)
|
// Same as `isParameterPostUpdate(_, c, pos)`, but can be used in a negative context
|
||||||
|
any(SummaryNodeState state).isOutputState(c, SummaryComponentStack::argument(pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate callbackOutput(
|
private predicate callbackOutput(
|
||||||
|
|||||||
@@ -183,6 +183,18 @@ module LocalFlow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) {
|
predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) {
|
||||||
|
exists(DataFlowCallable c | nodeFrom = TSynthHashSplatParameterNode(c) |
|
||||||
|
exists(HashSplatParameter p |
|
||||||
|
p.getCallable() = c.asCallable() and
|
||||||
|
nodeTo = TNormalParameterNode(p)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(ParameterPosition pos |
|
||||||
|
nodeTo = TSummaryParameterNode(c.asLibraryCallable(), pos) and
|
||||||
|
pos.isHashSplat()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or
|
||||||
localSsaFlowStep(nodeFrom, nodeTo)
|
localSsaFlowStep(nodeFrom, nodeTo)
|
||||||
or
|
or
|
||||||
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::BlockArgumentCfgNode).getValue()
|
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::BlockArgumentCfgNode).getValue()
|
||||||
@@ -620,7 +632,9 @@ private module ParameterNodes {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
parameter = callable.getAParameter().(HashSplatParameter) and
|
parameter = callable.getAParameter().(HashSplatParameter) and
|
||||||
pos.isHashSplat()
|
pos.isHashSplat() and
|
||||||
|
// avoid overlap with `SynthHashSplatParameterNode`
|
||||||
|
not callable.getAParameter() instanceof KeywordParameter
|
||||||
or
|
or
|
||||||
parameter = callable.getParameter(0).(SplatParameter) and
|
parameter = callable.getParameter(0).(SplatParameter) and
|
||||||
pos.isSplatAll()
|
pos.isSplatAll()
|
||||||
@@ -772,7 +786,16 @@ private module ParameterNodes {
|
|||||||
override Parameter getParameter() { none() }
|
override Parameter getParameter() { none() }
|
||||||
|
|
||||||
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||||
sc = c.asLibraryCallable() and pos = pos_
|
sc = c.asLibraryCallable() and
|
||||||
|
pos = pos_ and
|
||||||
|
// avoid overlap with `SynthHashSplatParameterNode`
|
||||||
|
not (
|
||||||
|
pos.isHashSplat() and
|
||||||
|
exists(ParameterPosition keywordPos |
|
||||||
|
FlowSummaryImpl::Private::summaryParameterNodeRange(sc, keywordPos) and
|
||||||
|
keywordPos.isKeyword(_)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override CfgScope getCfgScope() { none() }
|
override CfgScope getCfgScope() { none() }
|
||||||
@@ -1174,11 +1197,11 @@ predicate clearsContent(Node n, ContentSet c) {
|
|||||||
// Filter out keyword arguments that are part of the method signature from
|
// Filter out keyword arguments that are part of the method signature from
|
||||||
// the hash-splat parameter
|
// the hash-splat parameter
|
||||||
exists(
|
exists(
|
||||||
DataFlowCallable callable, ParameterPosition hashSplatPos, ParameterNodeImpl keywordParam,
|
DataFlowCallable callable, HashSplatParameter hashSplatParam, ParameterNodeImpl keywordParam,
|
||||||
ParameterPosition keywordPos, string name
|
ParameterPosition keywordPos, string name
|
||||||
|
|
|
|
||||||
n.(ParameterNodes::NormalParameterNode).isParameterOf(callable, hashSplatPos) and
|
n = TNormalParameterNode(hashSplatParam) and
|
||||||
hashSplatPos.isHashSplat() and
|
callable.asCallable() = hashSplatParam.getCallable() and
|
||||||
keywordParam.isParameterOf(callable, keywordPos) and
|
keywordParam.isParameterOf(callable, keywordPos) and
|
||||||
keywordPos.isKeyword(name) and
|
keywordPos.isKeyword(name) and
|
||||||
c = getKeywordContent(name)
|
c = getKeywordContent(name)
|
||||||
|
|||||||
@@ -520,7 +520,8 @@ module Private {
|
|||||||
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
|
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
|
||||||
parameterReadState(c, _, pos)
|
parameterReadState(c, _, pos)
|
||||||
or
|
or
|
||||||
isParameterPostUpdate(_, c, pos)
|
// Same as `isParameterPostUpdate(_, c, pos)`, but can be used in a negative context
|
||||||
|
any(SummaryNodeState state).isOutputState(c, SummaryComponentStack::argument(pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate callbackOutput(
|
private predicate callbackOutput(
|
||||||
|
|||||||
@@ -520,7 +520,8 @@ module Private {
|
|||||||
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
|
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
|
||||||
parameterReadState(c, _, pos)
|
parameterReadState(c, _, pos)
|
||||||
or
|
or
|
||||||
isParameterPostUpdate(_, c, pos)
|
// Same as `isParameterPostUpdate(_, c, pos)`, but can be used in a negative context
|
||||||
|
any(SummaryNodeState state).isOutputState(c, SummaryComponentStack::argument(pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate callbackOutput(
|
private predicate callbackOutput(
|
||||||
|
|||||||
Reference in New Issue
Block a user