mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
347 lines
8.8 KiB
Plaintext
347 lines
8.8 KiB
Plaintext
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 TModule {
|
|
/** Gets a declaration of this module, if any. */
|
|
ModuleBase getADeclaration() { result.getModule() = this }
|
|
|
|
/** Gets the super class of this module, if any. */
|
|
Module getSuperClass() { result = getSuperClass(this) }
|
|
|
|
/** Gets a `prepend`ed module. */
|
|
Module getAPrependedModule() { result = getAPrependedModule(this) }
|
|
|
|
/** Gets an `include`d module. */
|
|
Module getAnIncludedModule() { result = getAnIncludedModule(this) }
|
|
|
|
/** Holds if this module is a class. */
|
|
pragma[noinline]
|
|
predicate isClass() { this.getADeclaration() instanceof ClassDeclaration }
|
|
|
|
/** Gets a textual representation of this module. */
|
|
string toString() {
|
|
this = TResolved(result)
|
|
or
|
|
exists(Namespace n | this = TUnresolved(n) and result = "...::" + n.toString())
|
|
}
|
|
|
|
/** Gets the location of this module. */
|
|
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 = namespaceDeclaration(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.
|
|
*/
|
|
class ModuleBase extends BodyStmt, Scope, TModuleBase {
|
|
/** Gets a method defined in this module/class. */
|
|
MethodBase getAMethod() { result = this.getAStmt() }
|
|
|
|
/** Gets the method named `name` in this module/class, if any. */
|
|
MethodBase getMethod(string name) { result = this.getAMethod() and result.getName() = name }
|
|
|
|
/** Gets a class defined in this module/class. */
|
|
ClassDeclaration getAClass() { result = this.getAStmt() }
|
|
|
|
/** Gets the class named `name` in this module/class, if any. */
|
|
ClassDeclaration getClass(string name) { result = this.getAClass() and result.getName() = name }
|
|
|
|
/** Gets a module defined in this module/class. */
|
|
ModuleDeclaration getAModule() { result = this.getAStmt() }
|
|
|
|
/** Gets the module named `name` in this module/class, if any. */
|
|
ModuleDeclaration 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() }
|
|
}
|
|
|
|
/**
|
|
* A Ruby source file.
|
|
*
|
|
* ```rb
|
|
* def main
|
|
* puts "hello world!"
|
|
* end
|
|
* main
|
|
* ```
|
|
*/
|
|
class Toplevel extends ModuleBase, TToplevel {
|
|
private Generated::Program g;
|
|
|
|
Toplevel() { this = TToplevel(g) }
|
|
|
|
final override string getAPrimaryQlClass() { result = "Toplevel" }
|
|
|
|
/**
|
|
* Gets the `n`th `BEGIN` block.
|
|
*/
|
|
final BeginBlock getBeginBlock(int n) {
|
|
toGenerated(result) =
|
|
rank[n + 1](int i, Generated::BeginBlock b | b = g.getChild(i) | b order by i)
|
|
}
|
|
|
|
/**
|
|
* Gets a `BEGIN` block.
|
|
*/
|
|
final BeginBlock getABeginBlock() { result = getBeginBlock(_) }
|
|
|
|
final override AstNode getAChild(string pred) {
|
|
result = super.getAChild(pred)
|
|
or
|
|
pred = "getBeginBlock" and result = this.getBeginBlock(_)
|
|
}
|
|
|
|
final override Module getModule() { result = TResolved("Object") }
|
|
|
|
final override string toString() { result = g.getLocation().getFile().getBaseName() }
|
|
}
|
|
|
|
/**
|
|
* A class or module definition.
|
|
*
|
|
* ```rb
|
|
* class Foo
|
|
* def bar
|
|
* end
|
|
* end
|
|
* module Bar
|
|
* class Baz
|
|
* end
|
|
* end
|
|
* ```
|
|
*/
|
|
class Namespace extends ModuleBase, ConstantWriteAccess, TNamespace {
|
|
override string getAPrimaryQlClass() { result = "Namespace" }
|
|
|
|
/**
|
|
* Gets the name of the module/class. In the following example, the result is
|
|
* `"Foo"`.
|
|
* ```rb
|
|
* class Foo
|
|
* end
|
|
* ```
|
|
*
|
|
* N.B. in the following example, where the module/class name uses the scope
|
|
* resolution operator, the result is the name being resolved, i.e. `"Bar"`.
|
|
* Use `getScopeExpr` to get the `Foo` for `Foo`.
|
|
* ```rb
|
|
* module Foo::Bar
|
|
* end
|
|
* ```
|
|
*/
|
|
override string getName() { none() }
|
|
|
|
/**
|
|
* Gets the scope expression used in the module/class name's scope resolution
|
|
* operation, if any.
|
|
*
|
|
* In the following example, the result is the `Expr` for `Foo`.
|
|
*
|
|
* ```rb
|
|
* module Foo::Bar
|
|
* end
|
|
* ```
|
|
*
|
|
* However, there is no result for the following example, since there is no
|
|
* scope resolution operation.
|
|
*
|
|
* ```rb
|
|
* module Baz
|
|
* end
|
|
* ```
|
|
*/
|
|
override Expr getScopeExpr() { none() }
|
|
|
|
/**
|
|
* Holds if the module/class name uses the scope resolution operator to access the
|
|
* global scope, as in this example:
|
|
*
|
|
* ```rb
|
|
* class ::Foo
|
|
* end
|
|
* ```
|
|
*/
|
|
override predicate hasGlobalScope() { none() }
|
|
|
|
final override Module getModule() {
|
|
result = any(string qName | qName = namespaceDeclaration(this) | TResolved(qName))
|
|
or
|
|
result = TUnresolved(this)
|
|
}
|
|
|
|
override AstNode getAChild(string pred) {
|
|
result = ModuleBase.super.getAChild(pred) or
|
|
result = ConstantWriteAccess.super.getAChild(pred)
|
|
}
|
|
|
|
final override string toString() { result = ConstantWriteAccess.super.toString() }
|
|
}
|
|
|
|
/**
|
|
* A class definition.
|
|
*
|
|
* ```rb
|
|
* class Foo
|
|
* def bar
|
|
* end
|
|
* end
|
|
* ```
|
|
*/
|
|
class ClassDeclaration extends Namespace, TClassDeclaration {
|
|
private Generated::Class g;
|
|
|
|
ClassDeclaration() { this = TClassDeclaration(g) }
|
|
|
|
final override string getAPrimaryQlClass() { result = "ClassDeclaration" }
|
|
|
|
/**
|
|
* Gets the `Expr` used as the superclass in the class definition, if any.
|
|
*
|
|
* In the following example, the result is a `ConstantReadAccess`.
|
|
* ```rb
|
|
* class Foo < Bar
|
|
* end
|
|
* ```
|
|
*
|
|
* In the following example, where the superclass is a call expression, the
|
|
* result is a `Call`.
|
|
* ```rb
|
|
* class C < foo()
|
|
* end
|
|
* ```
|
|
*/
|
|
final Expr getSuperclassExpr() { toGenerated(result) = g.getSuperclass().getChild() }
|
|
|
|
final override string getName() {
|
|
result = g.getName().(Generated::Token).getValue() or
|
|
result = g.getName().(Generated::ScopeResolution).getName().(Generated::Token).getValue()
|
|
}
|
|
|
|
final override Expr getScopeExpr() {
|
|
toGenerated(result) = g.getName().(Generated::ScopeResolution).getScope()
|
|
}
|
|
|
|
final override predicate hasGlobalScope() {
|
|
exists(Generated::ScopeResolution sr |
|
|
sr = g.getName() and
|
|
not exists(sr.getScope())
|
|
)
|
|
}
|
|
|
|
final override AstNode getAChild(string pred) {
|
|
result = super.getAChild(pred)
|
|
or
|
|
pred = "getSuperclassExpr" and result = this.getSuperclassExpr()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A definition of a singleton class on an object.
|
|
*
|
|
* ```rb
|
|
* class << foo
|
|
* def bar
|
|
* p 'bar'
|
|
* end
|
|
* end
|
|
* ```
|
|
*/
|
|
class SingletonClass extends ModuleBase, TSingletonClass {
|
|
private Generated::SingletonClass g;
|
|
|
|
SingletonClass() { this = TSingletonClass(g) }
|
|
|
|
final override string getAPrimaryQlClass() { result = "ClassDeclaration" }
|
|
|
|
/**
|
|
* Gets the expression resulting in the object on which the singleton class
|
|
* is defined. In the following example, the result is the `Expr` for `foo`:
|
|
*
|
|
* ```rb
|
|
* class << foo
|
|
* end
|
|
* ```
|
|
*/
|
|
final Expr getValue() { toGenerated(result) = g.getValue() }
|
|
|
|
final override string toString() { result = "class << ..." }
|
|
|
|
final override AstNode getAChild(string pred) {
|
|
result = super.getAChild(pred)
|
|
or
|
|
pred = "getValue" and result = this.getValue()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A module definition.
|
|
*
|
|
* ```rb
|
|
* module Foo
|
|
* class Bar
|
|
* end
|
|
* end
|
|
* ```
|
|
*
|
|
* N.B. this class represents a single instance of a module definition. In the
|
|
* following example, classes `Bar` and `Baz` are both defined in the module
|
|
* `Foo`, but in two syntactically distinct definitions, meaning that there
|
|
* will be two instances of `ModuleDeclaration` in the database.
|
|
*
|
|
* ```rb
|
|
* module Foo
|
|
* class Bar; end
|
|
* end
|
|
*
|
|
* module Foo
|
|
* class Baz; end
|
|
* end
|
|
* ```
|
|
*/
|
|
class ModuleDeclaration extends Namespace, TModuleDeclaration {
|
|
private Generated::Module g;
|
|
|
|
ModuleDeclaration() { this = TModuleDeclaration(g) }
|
|
|
|
final override string getAPrimaryQlClass() { result = "ModuleDeclaration" }
|
|
|
|
final override string getName() {
|
|
result = g.getName().(Generated::Token).getValue() or
|
|
result = g.getName().(Generated::ScopeResolution).getName().(Generated::Token).getValue()
|
|
}
|
|
|
|
final override Expr getScopeExpr() {
|
|
toGenerated(result) = g.getName().(Generated::ScopeResolution).getScope()
|
|
}
|
|
|
|
final override predicate hasGlobalScope() {
|
|
exists(Generated::ScopeResolution sr |
|
|
sr = g.getName() and
|
|
not exists(sr.getScope())
|
|
)
|
|
}
|
|
}
|