Merge pull request #10705 from hvitved/ruby/singleton-overrides

Ruby: Take overrides into account for singleton methods defined on modules
This commit is contained in:
Tom Hvitved
2022-10-07 13:33:59 +02:00
committed by GitHub
7 changed files with 1045 additions and 1002 deletions

View File

@@ -389,7 +389,7 @@ private module Cached {
// ```
exists(DataFlow::Node sourceNode, Module m |
flowsToMethodCall(call, sourceNode, method) and
singletonMethodOnModule(result, method, m)
result = lookupSingletonMethod(m, method)
|
// ```rb
// def C.singleton; end # <- result
@@ -725,7 +725,10 @@ private predicate singletonMethodOnModule(MethodBase method, string name, Module
selfInModule(object.(SelfVariableReadAccess).getVariable(), m)
)
or
flowsToSingletonMethodObject(trackModuleAccess(m), method, name)
exists(DataFlow::LocalSourceNode sourceNode |
m = resolveConstantReadAccess(sourceNode.asExpr().getExpr()) and
flowsToSingletonMethodObject(sourceNode, method, name)
)
or
exists(Module other |
extendCallModule(m, other) and
@@ -733,6 +736,26 @@ private predicate singletonMethodOnModule(MethodBase method, string name, Module
)
}
/**
* Holds if `method` is a singleton method named `name`, defined on module
* `m`, or any transitive base class of `m`.
*/
pragma[nomagic]
private MethodBase lookupSingletonMethod(Module m, string name) {
singletonMethodOnModule(result, name, m)
or
// cannot be part of `singletonMethodOnModule` because it would introduce
// negative recursion below
exists(DataFlow::LocalSourceNode sourceNode |
sourceNode = trackModuleAccess(m) and
not m = resolveConstantReadAccess(sourceNode.asExpr().getExpr()) and
flowsToSingletonMethodObject(sourceNode, result, name)
)
or
not singletonMethodOnModule(_, name, m) and
result = lookupSingletonMethod(m.getSuperClass(), name)
}
/**
* Holds if `method` is a singleton method named `name`, defined on expression
* `object`, where `object` is not likely to resolve to a module: