mirror of
https://github.com/github/codeql.git
synced 2026-03-31 04:38:18 +02:00
Merge pull request #21511 from hvitved/ruby/empty-stats
Ruby: Use empty DB stats
This commit is contained in:
@@ -9,8 +9,12 @@ private import codeql.ruby.ast.internal.Scope
|
||||
private import codeql.ruby.controlflow.CfgNodes
|
||||
private import codeql.util.Numbers
|
||||
|
||||
bindingset[t]
|
||||
pragma[inline_late]
|
||||
private string getTokenValue(Ruby::Token t) { result = t.getValue() }
|
||||
|
||||
int parseInteger(Ruby::Integer i) {
|
||||
exists(string s | s = i.getValue().toLowerCase().replaceAll("_", "") |
|
||||
exists(string s | s = getTokenValue(i).toLowerCase().replaceAll("_", "") |
|
||||
s.charAt(0) != "0" and
|
||||
result = s.toInt()
|
||||
or
|
||||
@@ -38,7 +42,7 @@ class IntegerLiteralReal extends IntegerLiteralImpl, TIntegerLiteralReal {
|
||||
|
||||
final override int getValue() { result = parseInteger(g) }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
final override string toString() { result = getTokenValue(g) }
|
||||
}
|
||||
|
||||
class IntegerLiteralSynth extends IntegerLiteralImpl, TIntegerLiteralSynth {
|
||||
@@ -52,7 +56,7 @@ class IntegerLiteralSynth extends IntegerLiteralImpl, TIntegerLiteralSynth {
|
||||
}
|
||||
|
||||
// TODO: implement properly
|
||||
float parseFloat(Ruby::Float f) { result = f.getValue().toFloat() }
|
||||
float parseFloat(Ruby::Float f) { result = getTokenValue(f).toFloat() }
|
||||
|
||||
class FloatLiteralImpl extends Expr, TFloatLiteral {
|
||||
private Ruby::Float g;
|
||||
@@ -61,7 +65,7 @@ class FloatLiteralImpl extends Expr, TFloatLiteral {
|
||||
|
||||
final float getValue() { result = parseFloat(g) }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
final override string toString() { result = getTokenValue(g) }
|
||||
}
|
||||
|
||||
predicate isRationalValue(Ruby::Rational r, int numerator, int denominator) {
|
||||
@@ -71,8 +75,8 @@ predicate isRationalValue(Ruby::Rational r, int numerator, int denominator) {
|
||||
exists(Ruby::Float f, string regex, string before, string after |
|
||||
f = r.getChild() and
|
||||
regex = "([^.]*)\\.(.*)" and
|
||||
before = f.getValue().regexpCapture(regex, 1) and
|
||||
after = f.getValue().regexpCapture(regex, 2) and
|
||||
before = getTokenValue(f).regexpCapture(regex, 1) and
|
||||
after = getTokenValue(f).regexpCapture(regex, 2) and
|
||||
numerator = before.toInt() * denominator + after.toInt() and
|
||||
denominator = 10.pow(after.length())
|
||||
)
|
||||
@@ -87,14 +91,14 @@ class RationalLiteralImpl extends Expr, TRationalLiteral {
|
||||
isRationalValue(g, numerator, denominator)
|
||||
}
|
||||
|
||||
final override string toString() { result = g.getChild().(Ruby::Token).getValue() + "r" }
|
||||
final override string toString() { result = getTokenValue(g.getChild()) + "r" }
|
||||
}
|
||||
|
||||
float getComplexValue(Ruby::Complex c) {
|
||||
exists(int n, int d | isRationalValue(c.getChild(), n, d) and result = n.(float) / d.(float))
|
||||
or
|
||||
exists(string s |
|
||||
s = c.getChild().(Ruby::Token).getValue() and
|
||||
s = getTokenValue(c.getChild()) and
|
||||
result = s.prefix(s.length()).toFloat()
|
||||
)
|
||||
}
|
||||
@@ -109,8 +113,8 @@ class ComplexLiteralImpl extends Expr, TComplexLiteral {
|
||||
}
|
||||
|
||||
final override string toString() {
|
||||
result = g.getChild().(Ruby::Token).getValue() + "i" or
|
||||
result = g.getChild().(Ruby::Rational).getChild().(Ruby::Token).getValue() + "ri"
|
||||
result = getTokenValue(g.getChild()) + "i" or
|
||||
result = getTokenValue(g.getChild().(Ruby::Rational).getChild()) + "ri"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +141,7 @@ class TrueLiteral extends BooleanLiteralImpl, TTrueLiteral {
|
||||
|
||||
TrueLiteral() { this = TTrueLiteral(g) }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
final override string toString() { result = getTokenValue(g) }
|
||||
|
||||
final override boolean getValue() { result = true }
|
||||
}
|
||||
@@ -147,7 +151,7 @@ class FalseLiteral extends BooleanLiteralImpl, TFalseLiteral {
|
||||
|
||||
FalseLiteral() { this = TFalseLiteral(g) }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
final override string toString() { result = getTokenValue(g) }
|
||||
|
||||
final override boolean getValue() { result = false }
|
||||
}
|
||||
@@ -290,9 +294,9 @@ class RangeLiteralSynth extends RangeLiteralImpl, TRangeLiteralSynth {
|
||||
}
|
||||
|
||||
private string getMethodName(MethodName::Token t) {
|
||||
result = t.(Ruby::Token).getValue()
|
||||
result = getTokenValue(t)
|
||||
or
|
||||
result = t.(Ruby::Setter).getName().getValue() + "="
|
||||
result = getTokenValue(t.(Ruby::Setter).getName()) + "="
|
||||
}
|
||||
|
||||
class TokenMethodName extends Expr, TTokenMethodName {
|
||||
@@ -339,9 +343,9 @@ class StringTextComponentStringOrHeredocContent extends StringTextComponentImpl,
|
||||
|
||||
final override string getValue() { result = this.getUnescapedText() }
|
||||
|
||||
final override string getRawTextImpl() { result = g.getValue() }
|
||||
final override string getRawTextImpl() { result = getTokenValue(g) }
|
||||
|
||||
final private string getUnescapedText() { result = unescapeTextComponent(g.getValue()) }
|
||||
final private string getUnescapedText() { result = unescapeTextComponent(getTokenValue(g)) }
|
||||
}
|
||||
|
||||
private class StringTextComponentSimpleSymbol extends StringTextComponentImpl,
|
||||
@@ -352,7 +356,7 @@ private class StringTextComponentSimpleSymbol extends StringTextComponentImpl,
|
||||
StringTextComponentSimpleSymbol() { this = TStringTextComponentNonRegexpSimpleSymbol(g) }
|
||||
|
||||
// Tree-sitter gives us value text including the colon, which we skip.
|
||||
private string getSimpleSymbolValue() { result = g.getValue().suffix(1) }
|
||||
private string getSimpleSymbolValue() { result = getTokenValue(g).suffix(1) }
|
||||
|
||||
final override string getValue() { result = this.getSimpleSymbolValue() }
|
||||
|
||||
@@ -366,9 +370,9 @@ private class StringTextComponentHashKeySymbol extends StringTextComponentImpl,
|
||||
|
||||
StringTextComponentHashKeySymbol() { this = TStringTextComponentNonRegexpHashKeySymbol(g) }
|
||||
|
||||
final override string getValue() { result = g.getValue() }
|
||||
final override string getValue() { result = getTokenValue(g) }
|
||||
|
||||
final override string getRawTextImpl() { result = g.getValue() }
|
||||
final override string getRawTextImpl() { result = getTokenValue(g) }
|
||||
}
|
||||
|
||||
bindingset[escaped]
|
||||
@@ -438,9 +442,9 @@ class StringEscapeSequenceComponentImpl extends StringComponentImpl,
|
||||
|
||||
final override string getValue() { result = this.getUnescapedText() }
|
||||
|
||||
final string getRawTextImpl() { result = g.getValue() }
|
||||
final string getRawTextImpl() { result = getTokenValue(g) }
|
||||
|
||||
final private string getUnescapedText() { result = unescapeEscapeSequence(g.getValue()) }
|
||||
final private string getUnescapedText() { result = unescapeEscapeSequence(getTokenValue(g)) }
|
||||
|
||||
final override string toString() { result = this.getRawTextImpl() }
|
||||
}
|
||||
@@ -473,10 +477,10 @@ class RegExpTextComponentImpl extends RegExpComponentImpl, TStringTextComponentR
|
||||
// Exclude components that are children of a free-spacing regex.
|
||||
// We do this because `ParseRegExp.qll` cannot handle free-spacing regexes.
|
||||
not this.getParent().(RegExpLiteral).hasFreeSpacingFlag() and
|
||||
result = g.getValue()
|
||||
result = getTokenValue(g)
|
||||
}
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
final override string toString() { result = getTokenValue(g) }
|
||||
}
|
||||
|
||||
class RegExpEscapeSequenceComponentImpl extends RegExpComponentImpl,
|
||||
@@ -490,10 +494,10 @@ class RegExpEscapeSequenceComponentImpl extends RegExpComponentImpl,
|
||||
// Exclude components that are children of a free-spacing regex.
|
||||
// We do this because `ParseRegExp.qll` cannot handle free-spacing regexes.
|
||||
not this.getParent().(RegExpLiteral).hasFreeSpacingFlag() and
|
||||
result = g.getValue()
|
||||
result = getTokenValue(g)
|
||||
}
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
final override string toString() { result = getTokenValue(g) }
|
||||
}
|
||||
|
||||
class RegExpInterpolationComponentImpl extends RegExpComponentImpl,
|
||||
@@ -564,7 +568,7 @@ abstract class StringlikeLiteralImpl extends Expr, TStringlikeLiteral {
|
||||
concat(StringComponent c, int i, string s |
|
||||
c = this.getComponentImpl(i) and
|
||||
(
|
||||
s = toGenerated(c).(Ruby::Token).getValue()
|
||||
s = getTokenValue(toGenerated(c))
|
||||
or
|
||||
not toGenerated(c) instanceof Ruby::Token and
|
||||
s = "#{...}"
|
||||
@@ -635,7 +639,7 @@ class SimpleSymbolLiteralReal extends SimpleSymbolLiteralImpl, TSimpleSymbolLite
|
||||
|
||||
final override StringComponent getComponentImpl(int n) { n = 0 and toGenerated(result) = g }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
final override string toString() { result = getTokenValue(g) }
|
||||
}
|
||||
|
||||
class SimpleSymbolLiteralSynth extends SimpleSymbolLiteralImpl, TSimpleSymbolLiteralSynth,
|
||||
@@ -677,7 +681,7 @@ private class HashKeySymbolLiteral extends SymbolLiteralImpl, THashKeySymbolLite
|
||||
|
||||
final override StringComponent getComponentImpl(int n) { n = 0 and toGenerated(result) = g }
|
||||
|
||||
final override string toString() { result = ":" + g.getValue() }
|
||||
final override string toString() { result = ":" + getTokenValue(g) }
|
||||
}
|
||||
|
||||
class RegExpLiteralImpl extends StringlikeLiteralImpl, TRegExpLiteral {
|
||||
@@ -701,9 +705,9 @@ class CharacterLiteralImpl extends Expr, TCharacterLiteral {
|
||||
|
||||
CharacterLiteralImpl() { this = TCharacterLiteral(g) }
|
||||
|
||||
final string getValue() { result = g.getValue() }
|
||||
final string getValue() { result = getTokenValue(g) }
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
final override string toString() { result = getTokenValue(g) }
|
||||
}
|
||||
|
||||
class HereDocImpl extends StringlikeLiteralImpl, THereDoc {
|
||||
@@ -715,5 +719,5 @@ class HereDocImpl extends StringlikeLiteralImpl, THereDoc {
|
||||
toGenerated(result) = getHereDocBody(g).getChild(n)
|
||||
}
|
||||
|
||||
final override string toString() { result = g.getValue() }
|
||||
final override string toString() { result = getTokenValue(g) }
|
||||
}
|
||||
|
||||
@@ -639,7 +639,7 @@ private TMethodOrExpr lookupMethodOrConst(Module m, string name) {
|
||||
// For now, we restrict the scope of top-level declarations to their file.
|
||||
// This may remove some plausible targets, but also removes a lot of
|
||||
// implausible targets
|
||||
if getNode(result).getEnclosingModule() instanceof Toplevel
|
||||
then getNode(result).getFile() = m.getADeclaration().getFile()
|
||||
else any()
|
||||
forall(File file | file = getNode(result).getEnclosingModule().(Toplevel).getFile() |
|
||||
file = m.getADeclaration().getFile()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -149,11 +149,11 @@ cached
|
||||
private module Cached {
|
||||
/** Gets the enclosing scope of a node */
|
||||
cached
|
||||
Scope::Range scopeOf(Ruby::AstNode n) {
|
||||
Scope::Range scopeOfImpl(Ruby::AstNode n) {
|
||||
exists(Ruby::AstNode p | p = parentOf(n) |
|
||||
p = result
|
||||
or
|
||||
not p instanceof Scope::Range and result = scopeOf(p)
|
||||
not p instanceof Scope::Range and result = scopeOfImpl(p)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -163,16 +163,22 @@ private module Cached {
|
||||
* and synthesized scopes into account.
|
||||
*/
|
||||
cached
|
||||
Scope scopeOfInclSynth(AstNode n) {
|
||||
Scope scopeOfInclSynthImpl(AstNode n) {
|
||||
exists(AstNode p | p = parentOfInclSynth(n) |
|
||||
p = result
|
||||
or
|
||||
not p instanceof Scope and result = scopeOfInclSynth(p)
|
||||
not p instanceof Scope and result = scopeOfInclSynthImpl(p)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
bindingset[n]
|
||||
pragma[inline_late]
|
||||
Scope::Range scopeOf(Ruby::AstNode n) { result = Cached::scopeOfImpl(n) }
|
||||
|
||||
bindingset[n]
|
||||
pragma[inline_late]
|
||||
Scope scopeOfInclSynth(AstNode n) { result = Cached::scopeOfInclSynthImpl(n) }
|
||||
|
||||
abstract class ScopeImpl extends AstNode, TScopeType {
|
||||
final Scope getOuterScopeImpl() { result = scopeOfInclSynth(this) }
|
||||
|
||||
@@ -687,26 +687,30 @@ pragma[nomagic]
|
||||
private CfgScope getTargetInstance(DataFlowCall call, string method) {
|
||||
exists(boolean exact |
|
||||
result = lookupInstanceMethodCall(call, method, exact) and
|
||||
(
|
||||
if result.(Method).isPrivate()
|
||||
then
|
||||
call.asCall().getReceiver().getExpr() instanceof SelfVariableAccess and
|
||||
// For now, we restrict the scope of top-level declarations to their file.
|
||||
// This may remove some plausible targets, but also removes a lot of
|
||||
// implausible targets
|
||||
(
|
||||
isToplevelMethodInFile(result, call.asCall().getFile()) or
|
||||
not isToplevelMethodInFile(result, _)
|
||||
)
|
||||
else any()
|
||||
) and
|
||||
if result.(Method).isProtected()
|
||||
then
|
||||
result = lookupMethod(call.asCall().getExpr().getEnclosingModule().getModule(), method, exact)
|
||||
else any()
|
||||
(if result.(Method).isPrivate() then result = privateFilter(call) else any()) and
|
||||
if result.(Method).isProtected() then result = protectedFilter(call, method, exact) else any()
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[call, result]
|
||||
pragma[inline_late]
|
||||
private CfgScope privateFilter(DataFlowCall call) {
|
||||
call.asCall().getReceiver().getExpr() instanceof SelfVariableAccess and
|
||||
// For now, we restrict the scope of top-level declarations to their file.
|
||||
// This may remove some plausible targets, but also removes a lot of
|
||||
// implausible targets
|
||||
(
|
||||
isToplevelMethodInFile(result, call.asCall().getFile()) or
|
||||
not isToplevelMethodInFile(result, _)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[call, method, exact, result]
|
||||
pragma[inline_late]
|
||||
private CfgScope protectedFilter(DataFlowCall call, string method, boolean exact) {
|
||||
result = lookupMethod(call.asCall().getExpr().getEnclosingModule().getModule(), method, exact)
|
||||
}
|
||||
|
||||
private module TrackBlockInput implements CallGraphConstruction::Simple::InputSig {
|
||||
class State = Block;
|
||||
|
||||
|
||||
@@ -28,7 +28,13 @@ abstract class NodeImpl extends Node {
|
||||
DataFlowCallable getEnclosingCallable() { result = TCfgScope(this.getCfgScope()) }
|
||||
|
||||
/** Do not call: use `getEnclosingCallable()` instead. */
|
||||
abstract CfgScope getCfgScope();
|
||||
abstract CfgScope getCfgScopeImpl();
|
||||
|
||||
/** Do not call: use `getEnclosingCallable()` instead. */
|
||||
pragma[inline]
|
||||
final CfgScope getCfgScope() {
|
||||
pragma[only_bind_into](result) = pragma[only_bind_out](this).getCfgScopeImpl()
|
||||
}
|
||||
|
||||
/** Do not call: use `getLocation()` instead. */
|
||||
abstract Location getLocationImpl();
|
||||
@@ -38,7 +44,7 @@ abstract class NodeImpl extends Node {
|
||||
}
|
||||
|
||||
private class ExprNodeImpl extends ExprNode, NodeImpl {
|
||||
override CfgScope getCfgScope() { result = this.getExprNode().getExpr().getCfgScope() }
|
||||
override CfgScope getCfgScopeImpl() { result = this.getExprNode().getExpr().getCfgScope() }
|
||||
|
||||
override Location getLocationImpl() { result = this.getExprNode().getLocation() }
|
||||
|
||||
@@ -780,7 +786,7 @@ class SsaNode extends NodeImpl, TSsaNode {
|
||||
/** Holds if this node should be hidden from path explanations. */
|
||||
predicate isHidden() { any() }
|
||||
|
||||
override CfgScope getCfgScope() { result = node.getBasicBlock().getScope() }
|
||||
override CfgScope getCfgScopeImpl() { result = node.getBasicBlock().getScope() }
|
||||
|
||||
override Location getLocationImpl() { result = node.getLocation() }
|
||||
|
||||
@@ -827,7 +833,7 @@ class CapturedVariableNode extends NodeImpl, TCapturedVariableNode {
|
||||
/** Gets the captured variable represented by this node. */
|
||||
VariableCapture::CapturedVariable getVariable() { result = variable }
|
||||
|
||||
override CfgScope getCfgScope() { result = variable.getCallable() }
|
||||
override CfgScope getCfgScopeImpl() { result = variable.getCallable() }
|
||||
|
||||
override Location getLocationImpl() { result = variable.getLocation() }
|
||||
|
||||
@@ -849,7 +855,7 @@ class ReturningStatementNode extends NodeImpl, TReturningNode {
|
||||
/** Gets the expression corresponding to this node. */
|
||||
CfgNodes::ReturningCfgNode getReturningNode() { result = n }
|
||||
|
||||
override CfgScope getCfgScope() { result = n.getScope() }
|
||||
override CfgScope getCfgScopeImpl() { result = n.getScope() }
|
||||
|
||||
override Location getLocationImpl() { result = n.getLocation() }
|
||||
|
||||
@@ -867,7 +873,7 @@ class CaptureNode extends NodeImpl, TCaptureNode {
|
||||
|
||||
VariableCapture::Flow::SynthesizedCaptureNode getSynthesizedCaptureNode() { result = cn }
|
||||
|
||||
override CfgScope getCfgScope() { result = cn.getEnclosingCallable() }
|
||||
override CfgScope getCfgScopeImpl() { result = cn.getEnclosingCallable() }
|
||||
|
||||
override Location getLocationImpl() { result = cn.getLocation() }
|
||||
|
||||
@@ -935,7 +941,7 @@ private module ParameterNodes {
|
||||
)
|
||||
}
|
||||
|
||||
override CfgScope getCfgScope() { result = parameter.getCallable() }
|
||||
override CfgScope getCfgScopeImpl() { result = parameter.getCallable() }
|
||||
|
||||
override Location getLocationImpl() { result = parameter.getLocation() }
|
||||
|
||||
@@ -979,7 +985,7 @@ private module ParameterNodes {
|
||||
|
||||
final override SelfVariable getSelfVariable() { result.getDeclaringScope() = method }
|
||||
|
||||
override CfgScope getCfgScope() { result = method }
|
||||
override CfgScope getCfgScopeImpl() { result = method }
|
||||
|
||||
override Location getLocationImpl() { result = method.getLocation() }
|
||||
}
|
||||
@@ -1001,7 +1007,7 @@ private module ParameterNodes {
|
||||
|
||||
final override SelfVariable getSelfVariable() { result.getDeclaringScope() = t }
|
||||
|
||||
override CfgScope getCfgScope() { result = t }
|
||||
override CfgScope getCfgScopeImpl() { result = t }
|
||||
|
||||
override Location getLocationImpl() { result = t.getLocation() }
|
||||
}
|
||||
@@ -1028,7 +1034,7 @@ private module ParameterNodes {
|
||||
callable = c.asCfgScope() and pos.isLambdaSelf()
|
||||
}
|
||||
|
||||
override CfgScope getCfgScope() { result = callable }
|
||||
override CfgScope getCfgScopeImpl() { result = callable }
|
||||
|
||||
override Location getLocationImpl() { result = callable.getLocation() }
|
||||
|
||||
@@ -1071,7 +1077,7 @@ private module ParameterNodes {
|
||||
c.asCfgScope() = method and pos.isBlock()
|
||||
}
|
||||
|
||||
override CfgScope getCfgScope() { result = method }
|
||||
override CfgScope getCfgScopeImpl() { result = method }
|
||||
|
||||
override Location getLocationImpl() {
|
||||
result = this.getParameter().getLocation()
|
||||
@@ -1130,7 +1136,7 @@ private module ParameterNodes {
|
||||
c = callable and pos.isSynthHashSplat()
|
||||
}
|
||||
|
||||
final override CfgScope getCfgScope() { result = callable.asCfgScope() }
|
||||
final override CfgScope getCfgScopeImpl() { result = callable.asCfgScope() }
|
||||
|
||||
final override DataFlowCallable getEnclosingCallable() { result = callable }
|
||||
|
||||
@@ -1193,7 +1199,7 @@ private module ParameterNodes {
|
||||
)
|
||||
}
|
||||
|
||||
final override CfgScope getCfgScope() { result = callable.asCfgScope() }
|
||||
final override CfgScope getCfgScopeImpl() { result = callable.asCfgScope() }
|
||||
|
||||
final override DataFlowCallable getEnclosingCallable() { result = callable }
|
||||
|
||||
@@ -1240,7 +1246,7 @@ private module ParameterNodes {
|
||||
cs = getArrayContent(pos)
|
||||
}
|
||||
|
||||
final override CfgScope getCfgScope() { result = callable.asCfgScope() }
|
||||
final override CfgScope getCfgScopeImpl() { result = callable.asCfgScope() }
|
||||
|
||||
final override DataFlowCallable getEnclosingCallable() { result = callable }
|
||||
|
||||
@@ -1278,7 +1284,7 @@ class FlowSummaryNode extends NodeImpl, TFlowSummaryNode {
|
||||
result = this.getSummaryNode().getSummarizedCallable()
|
||||
}
|
||||
|
||||
override CfgScope getCfgScope() { none() }
|
||||
override CfgScope getCfgScopeImpl() { none() }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.asLibraryCallable() = this.getSummarizedCallable()
|
||||
@@ -1349,7 +1355,7 @@ module ArgumentNodes {
|
||||
this.sourceArgumentOf(call.asCall(), pos)
|
||||
}
|
||||
|
||||
override CfgScope getCfgScope() { result = yield.getScope() }
|
||||
override CfgScope getCfgScopeImpl() { result = yield.getScope() }
|
||||
|
||||
override Location getLocationImpl() { result = yield.getLocation() }
|
||||
}
|
||||
@@ -1379,7 +1385,7 @@ module ArgumentNodes {
|
||||
this.sourceArgumentOf(call.asCall(), pos)
|
||||
}
|
||||
|
||||
override CfgScope getCfgScope() { result = sup.getScope() }
|
||||
override CfgScope getCfgScopeImpl() { result = sup.getScope() }
|
||||
|
||||
override Location getLocationImpl() { result = sup.getLocation() }
|
||||
}
|
||||
@@ -1415,7 +1421,7 @@ module ArgumentNodes {
|
||||
this.sourceArgumentOf(call.asCall(), pos)
|
||||
}
|
||||
|
||||
final override CfgScope getCfgScope() { result = call_.getExpr().getCfgScope() }
|
||||
final override CfgScope getCfgScopeImpl() { result = call_.getExpr().getCfgScope() }
|
||||
|
||||
final override Location getLocationImpl() { result = call_.getLocation() }
|
||||
}
|
||||
@@ -1563,7 +1569,7 @@ module ArgumentNodes {
|
||||
)
|
||||
}
|
||||
|
||||
override CfgScope getCfgScope() { result = c.getExpr().getCfgScope() }
|
||||
override CfgScope getCfgScopeImpl() { result = c.getExpr().getCfgScope() }
|
||||
|
||||
override Location getLocationImpl() { result = c.getLocation() }
|
||||
|
||||
@@ -2037,16 +2043,21 @@ private predicate compatibleTypesNonSymRefl(DataFlowType t1, DataFlowType t2) {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate compatibleModuleTypes(TModuleDataFlowType t1, TModuleDataFlowType t2) {
|
||||
exists(Module m1, Module m2, Module m3 |
|
||||
t1 = TModuleDataFlowType(m1) and
|
||||
t2 = TModuleDataFlowType(m2)
|
||||
|
|
||||
private predicate compatibleModules(Module m1, Module m2) {
|
||||
exists(Module m3 |
|
||||
m3.getAnAncestor() = m1 and
|
||||
m3.getAnAncestor() = m2
|
||||
)
|
||||
}
|
||||
|
||||
private predicate compatibleModuleTypes(TModuleDataFlowType t1, TModuleDataFlowType t2) {
|
||||
exists(Module m1, Module m2 |
|
||||
compatibleModules(m1, m2) and
|
||||
t1 = TModuleDataFlowType(m1) and
|
||||
t2 = TModuleDataFlowType(m2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
|
||||
* a node of type `t1` to a node of type `t2`.
|
||||
@@ -2074,7 +2085,7 @@ private module PostUpdateNodes {
|
||||
|
||||
override ExprNode getPreUpdateNode() { e = result.getExprNode() }
|
||||
|
||||
override CfgScope getCfgScope() { result = e.getExpr().getCfgScope() }
|
||||
override CfgScope getCfgScopeImpl() { result = e.getExpr().getCfgScope() }
|
||||
|
||||
override Location getLocationImpl() { result = e.getLocation() }
|
||||
|
||||
|
||||
@@ -500,6 +500,7 @@ private module Persistence {
|
||||
class ActiveRecordAssociation extends DataFlow::CallNode {
|
||||
private ActiveRecordModelClass modelClass;
|
||||
|
||||
pragma[nomagic]
|
||||
ActiveRecordAssociation() {
|
||||
not exists(this.asExpr().getExpr().getEnclosingMethod()) and
|
||||
this.asExpr().getExpr().getEnclosingModule() = modelClass and
|
||||
@@ -583,6 +584,14 @@ private string pluralize(string input) {
|
||||
exists(string stem | stem + "s" = input) and result = input
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate activeRecordAssociationMethodCall(
|
||||
DataFlow::CallNode call, ActiveRecordAssociation assoc, string model
|
||||
) {
|
||||
call.getReceiver().(ActiveRecordInstance).getClass() = assoc.getSourceClass() and
|
||||
model = assoc.getTargetModelName()
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a method generated by an ActiveRecord association.
|
||||
* These yield ActiveRecord collection proxies, which act like collections but
|
||||
@@ -595,24 +604,21 @@ private class ActiveRecordAssociationMethodCall extends DataFlow::CallNode {
|
||||
ActiveRecordAssociation assoc;
|
||||
|
||||
ActiveRecordAssociationMethodCall() {
|
||||
exists(string model | model = assoc.getTargetModelName() |
|
||||
this.getReceiver().(ActiveRecordInstance).getClass() = assoc.getSourceClass() and
|
||||
exists(string model | activeRecordAssociationMethodCall(this, assoc, model) |
|
||||
assoc.isCollection() and
|
||||
(
|
||||
assoc.isCollection() and
|
||||
(
|
||||
this.getMethodName() = pluralize(model) + ["", "="]
|
||||
or
|
||||
this.getMethodName() = "<<"
|
||||
or
|
||||
this.getMethodName() = model + ["_ids", "_ids="]
|
||||
)
|
||||
this.getMethodName() = pluralize(model) + ["", "="]
|
||||
or
|
||||
assoc.isSingular() and
|
||||
(
|
||||
this.getMethodName() = model + ["", "="] or
|
||||
this.getMethodName() = ["build_", "reload_"] + model or
|
||||
this.getMethodName() = "create_" + model + ["!", ""]
|
||||
)
|
||||
this.getMethodName() = "<<"
|
||||
or
|
||||
this.getMethodName() = model + ["_ids", "_ids="]
|
||||
)
|
||||
or
|
||||
assoc.isSingular() and
|
||||
(
|
||||
this.getMethodName() = model + ["", "="] or
|
||||
this.getMethodName() = ["build_", "reload_"] + model or
|
||||
this.getMethodName() = "create_" + model + ["!", ""]
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -46,6 +46,10 @@ module Filters {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[m, name]
|
||||
pragma[inline_late]
|
||||
private Method lookupMethodInlineLate(Module m, string name) { result = lookupMethod(m, name) }
|
||||
|
||||
/**
|
||||
* A call to a class method that adds or removes a filter from the callback chain.
|
||||
* This class exists to encapsulate common behavior between calls that
|
||||
@@ -140,7 +144,8 @@ module Filters {
|
||||
*/
|
||||
Callable getAFilterCallable() {
|
||||
result =
|
||||
lookupMethod(this.getExpr().getEnclosingModule().getModule(), this.getFilterArgumentName())
|
||||
lookupMethodInlineLate(this.getExpr().getEnclosingModule().getModule(),
|
||||
this.getFilterArgumentName())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -943,6 +943,7 @@ module Routing {
|
||||
* Note: All-uppercase words like `CONSTANT` are not handled correctly.
|
||||
*/
|
||||
bindingset[base]
|
||||
pragma[inline_late]
|
||||
string underscore(string base) {
|
||||
base = "" and result = ""
|
||||
or
|
||||
|
||||
@@ -526,7 +526,7 @@ module Array {
|
||||
MethodCall mc;
|
||||
|
||||
bindingset[this]
|
||||
DeleteSummary() { mc.getMethodName() = "delete" }
|
||||
DeleteSummary() { pragma[only_bind_into](mc).getMethodName() = "delete" }
|
||||
|
||||
final override MethodCall getACallSimple() { result = mc }
|
||||
|
||||
@@ -790,7 +790,7 @@ module Array {
|
||||
MethodCall mc;
|
||||
|
||||
bindingset[this]
|
||||
FetchSummary() { mc.getMethodName() = "fetch" }
|
||||
FetchSummary() { pragma[only_bind_into](mc).getMethodName() = "fetch" }
|
||||
|
||||
override MethodCall getACallSimple() { result = mc }
|
||||
}
|
||||
|
||||
@@ -286,7 +286,7 @@ abstract private class FetchValuesSummary extends SummarizedCallable::Range {
|
||||
MethodCall mc;
|
||||
|
||||
bindingset[this]
|
||||
FetchValuesSummary() { mc.getMethodName() = "fetch_values" }
|
||||
FetchValuesSummary() { pragma[only_bind_into](mc).getMethodName() = "fetch_values" }
|
||||
|
||||
final override MethodCall getACallSimple() { result = mc }
|
||||
|
||||
@@ -390,7 +390,7 @@ abstract private class SliceSummary extends SummarizedCallable::Range {
|
||||
MethodCall mc;
|
||||
|
||||
bindingset[this]
|
||||
SliceSummary() { mc.getMethodName() = "slice" }
|
||||
SliceSummary() { pragma[only_bind_into](mc).getMethodName() = "slice" }
|
||||
|
||||
final override MethodCall getACallSimple() { result = mc }
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user