mirror of
https://github.com/github/codeql.git
synced 2026-02-20 08:53:49 +01:00
Basic module resolution
This commit is contained in:
@@ -1,8 +1,39 @@
|
||||
private import codeql_ruby.AST
|
||||
private import codeql_ruby.ast.Constant
|
||||
private import internal.AST
|
||||
private import internal.Module
|
||||
private import internal.TreeSitter
|
||||
|
||||
/**
|
||||
* A representation of a run-time `module` or `class` value.
|
||||
*/
|
||||
class Module extends TConstant {
|
||||
Module() { this = TResolved(_, true) or this = TUnresolved(any(Namespace n)) }
|
||||
|
||||
string toString() {
|
||||
this = TResolved(result, _)
|
||||
or
|
||||
exists(Namespace n | this = TUnresolved(n) and result = "...::" + n.toString())
|
||||
}
|
||||
|
||||
Location getLocation() {
|
||||
exists(Namespace n | this = TUnresolved(n) and result = n.getLocation())
|
||||
or
|
||||
result =
|
||||
min(Namespace n, string qName, Location loc, int weight |
|
||||
this = TResolved(qName, _) and
|
||||
qName = constantDefinition(n) and
|
||||
loc = n.getLocation() and
|
||||
if exists(loc.getFile().getRelativePath()) then weight = 0 else weight = 1
|
||||
|
|
||||
loc
|
||||
order by
|
||||
weight, count(n.getAStmt()) desc, loc.getFile().getAbsolutePath(), loc.getStartLine(),
|
||||
loc.getStartColumn()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The base class for classes, singleton classes, and modules.
|
||||
*/
|
||||
@@ -24,6 +55,9 @@ class ModuleBase extends BodyStmt, Scope, TModuleBase {
|
||||
|
||||
/** Gets the module named `name` in this module/class, if any. */
|
||||
ModuleDefinition getModule(string name) { result = this.getAModule() and result.getName() = name }
|
||||
|
||||
/** Gets the representation of the run-time value of this module or class. */
|
||||
Module getModule() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,6 +96,8 @@ class Toplevel extends ModuleBase, TToplevel {
|
||||
pred = "getBeginBlock" and result = this.getBeginBlock(_)
|
||||
}
|
||||
|
||||
final override Module getModule() { result = TResolved("Object", true) }
|
||||
|
||||
final override string toString() { result = g.getLocation().getFile().getBaseName() }
|
||||
}
|
||||
|
||||
@@ -132,6 +168,12 @@ class Namespace extends ModuleBase, ConstantWriteAccess, TNamespace {
|
||||
*/
|
||||
override predicate hasGlobalScope() { none() }
|
||||
|
||||
final override Module getModule() {
|
||||
result = any(string qName | qName = constantDefinition(this) | TResolved(qName, true))
|
||||
or
|
||||
result = TUnresolved(this)
|
||||
}
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = ModuleBase.super.getAChild(pred) or
|
||||
result = ConstantWriteAccess.super.getAChild(pred)
|
||||
|
||||
106
ql/src/codeql_ruby/ast/internal/Module.qll
Normal file
106
ql/src/codeql_ruby/ast/internal/Module.qll
Normal file
@@ -0,0 +1,106 @@
|
||||
private import codeql.Locations
|
||||
private import codeql_ruby.ast.Constant
|
||||
private import codeql_ruby.ast.Module
|
||||
private import codeql_ruby.ast.Operation
|
||||
private import codeql_ruby.ast.Scope
|
||||
|
||||
// Names of built-in modules and classes
|
||||
private string builtin() { result = ["Object", "Kernel", "BasicObject", "Class", "Module"] }
|
||||
|
||||
newtype TConstant =
|
||||
TResolved(string qName, boolean isModule) {
|
||||
exists(ConstantWriteAccess n |
|
||||
qName = builtin() and isModule = true
|
||||
or
|
||||
qName = constantDefinition(n) and
|
||||
if n instanceof Namespace then isModule = true else isModule = false
|
||||
)
|
||||
} or
|
||||
TUnresolved(ConstantWriteAccess n) { not exists(constantDefinition(n)) }
|
||||
|
||||
private predicate isToplevel(ConstantAccess n) {
|
||||
not exists(n.getScopeExpr()) and
|
||||
(
|
||||
n.hasGlobalScope()
|
||||
or
|
||||
exists(Scope x | x.getADescendant() = n and x.getEnclosingModule() instanceof Toplevel)
|
||||
)
|
||||
}
|
||||
|
||||
private string constantDefinition0(ConstantWriteAccess n) { result = qualifiedNameForConstant0(n) }
|
||||
|
||||
/**
|
||||
* Resolve a scope expression
|
||||
*/
|
||||
private string resolveScopeExpr0(ConstantReadAccess n) {
|
||||
exists(string qname | qname = qualifiedNameForConstant0(n) |
|
||||
qname = builtin() and result = qname
|
||||
or
|
||||
not qname = builtin() and
|
||||
exists(ConstantWriteAccess def | qname = constantDefinition0(def) |
|
||||
result = qname and def instanceof Namespace
|
||||
or
|
||||
result = resolveScopeExpr0(def.getParent().(Assignment).getRightOperand())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
ModuleBase enclosing(ModuleBase m, int level) {
|
||||
result = m and level = 0
|
||||
or
|
||||
result = enclosing(m.getOuterScope().getEnclosingModule(), level - 1)
|
||||
}
|
||||
|
||||
private string resolveRelativeToEnclosing(ConstantAccess n, int i) {
|
||||
not isToplevel(n) and
|
||||
not exists(n.getScopeExpr()) and
|
||||
exists(Scope s, ModuleBase enclosing |
|
||||
n = s.getADescendant() and
|
||||
enclosing = enclosing(s.getEnclosingModule(), i) and
|
||||
(
|
||||
result = constantDefinition0(enclosing) + "::" + n.getName()
|
||||
or
|
||||
enclosing instanceof Toplevel and result = n.getName()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private string qualifiedNameForConstant0(ConstantAccess n) {
|
||||
isToplevel(n) and
|
||||
result = n.getName()
|
||||
or
|
||||
result = resolveRelativeToEnclosing(n, 0)
|
||||
or
|
||||
result = resolveScopeExpr0(n.getScopeExpr()) + "::" + n.getName()
|
||||
}
|
||||
|
||||
string constantDefinition(ConstantWriteAccess n) {
|
||||
result = constantDefinition0(n)
|
||||
or
|
||||
result = resolveScopeExpr(n.getScopeExpr()) + "::" + n.getName()
|
||||
}
|
||||
|
||||
private string resolveScopeExpr(ConstantReadAccess n) {
|
||||
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 = builtin() and result = qname
|
||||
or
|
||||
not qname = builtin() and
|
||||
exists(ConstantWriteAccess def | qname = constantDefinition0(def) |
|
||||
result = qname and def instanceof Namespace
|
||||
or
|
||||
result = resolveScopeExpr(def.getParent().(Assignment).getRightOperand())
|
||||
)
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user