Also resolve constants with respect to the ancestors

of the enclosing module.
This commit is contained in:
Arthur Baars
2021-04-01 13:52:20 +02:00
parent f12e6ea8ea
commit 50b8b6b257

View File

@@ -1,5 +1,7 @@
private import codeql.Locations
private import codeql_ruby.ast.Call
private import codeql_ruby.ast.Constant
private import codeql_ruby.ast.Expr
private import codeql_ruby.ast.Module
private import codeql_ruby.ast.Operation
private import codeql_ruby.ast.Scope
@@ -7,6 +9,7 @@ private import codeql_ruby.ast.Scope
// Names of built-in modules and classes
private string builtin() { result = ["Object", "Kernel", "BasicObject", "Class", "Module"] }
cached
newtype TConstant =
TResolved(string qName, boolean isModule) {
exists(ConstantWriteAccess n |
@@ -62,11 +65,122 @@ private string resolveRelativeToEnclosing(ConstantAccess n, int i) {
exists(Scope s, ModuleBase enclosing |
n = s.getADescendant() and
enclosing = enclosing(s.getEnclosingModule(), i) and
(
result = scopeAppend(constantDefinition0(enclosing), n.getName())
result = scopeAppend(constantDefinition0(enclosing), n.getName()) and
(result = builtin() or result = constantDefinition0(_) or n instanceof ConstantWriteAccess)
)
}
private class IncludeOrPrependCall extends MethodCall {
IncludeOrPrependCall() { this.getMethodName() = ["include", "prepend"] }
string getAModule() { result = resolveScopeExpr0(this.getAnArgument()) }
string getTarget() {
result = resolveScopeExpr0(this.getReceiver())
or
exists(Scope s |
s.getADescendant() = this and
(
result = constantDefinition0(s.getEnclosingModule())
or
result = "Object" and s.getEnclosingModule() instanceof Toplevel
)
|
this.getReceiver() instanceof Self
or
enclosing instanceof Toplevel and result = n.getName()
not exists(this.getReceiver())
)
}
}
private string prepends(string qname) {
exists(IncludeOrPrependCall m |
m.getMethodName() = "prepend" and
qname = m.getTarget() and
result = m.getAModule()
)
}
private string includes(string qname) {
qname = "Object" and
result = "Kernel"
or
exists(IncludeOrPrependCall m |
m.getMethodName() = "include" and
qname = m.getTarget() and
result = m.getAModule()
)
}
private Expr superexpr(string qname) {
exists(ClassDefinition c | qname = constantDefinition0(c) and result = c.getSuperclassExpr())
}
private string superclass(string qname) {
qname = "Object" and result = "BasicObject"
or
result = resolveScopeExpr(superexpr(qname))
or
qname = constantDefinition0(_) and
not exists(superexpr(qname)) and
result = "Object" and
qname != "BasicObject"
}
private string ancestors(string qname) {
qname = [builtin(), constantDefinition0(any(Namespace x))] and
(
result = prepends(qname)
or
result = qname
or
result = includes(qname)
)
}
private string contains(string qname, string name) {
result = containsIgnoringSuper(qname, name)
or
not exists(containsIgnoringSuper(qname, name)) and
result = contains(superclass(qname), name)
}
private string qualifiedName(string container, string name) {
result = [builtin(), constantDefinition0(_)] and
(
container = result.regexpCapture("(.+)::([^:]+)", 1) and
name = result.regexpCapture("(.+)::([^:]+)", 2)
or
container = "Object" and name = result
)
}
private string containsIgnoringSuper(string qname, string name) {
result =
min(string n, string container, int i |
n = qualifiedName(container, name) and
(
container = ancestors*(prepends(qname)) and i = 0
or
container = qname and i = 1
or
container = ancestors*(includes(qname)) and i = 2
)
|
n order by i
)
}
private string resolveRelativeToAncestors(ConstantReadAccess n) {
not isToplevel(n) and
not exists(n.getScopeExpr()) and
exists(Scope s, ModuleBase enclosing |
n = s.getADescendant() and
enclosing = s.getEnclosingModule()
|
result = contains(constantDefinition(enclosing), n.getName())
or
enclosing instanceof Toplevel and result = contains("Object", n.getName())
)
}
@@ -86,23 +200,18 @@ string constantDefinition(ConstantWriteAccess n) {
}
private string resolveScopeExpr(ConstantReadAccess n) {
result = resolveScopeExpr0(n)
or
exists(string qname |
qname =
min(int i, string x |
(
x = qualifiedNameForConstant0(n) and i = 0
or
x = resolveRelativeToEnclosing(n, i)
) and
(x = builtin() or x = constantDefinition0(_))
|
x order by i
)
qname = min(int i, string x | x = resolveRelativeToEnclosing(n, i) | x order by i)
or
not exists(resolveRelativeToEnclosing(n, _)) and
qname = resolveRelativeToAncestors(n)
|
qname = builtin() and result = qname
or
not qname = builtin() and
exists(ConstantWriteAccess def | qname = constantDefinition0(def) |
exists(ConstantWriteAccess def | qname = constantDefinition(def) |
result = qname and def instanceof Namespace
or
result = resolveScopeExpr(def.getParent().(Assignment).getRightOperand())