mirror of
https://github.com/github/codeql.git
synced 2026-02-20 08:53:49 +01:00
Add Scope.qll
This commit is contained in:
@@ -9,6 +9,7 @@ import ast.Module
|
||||
import ast.Parameter
|
||||
import ast.Operation
|
||||
import ast.Pattern
|
||||
import ast.Scope
|
||||
import ast.Statement
|
||||
import ast.Variable
|
||||
private import ast.internal.AST
|
||||
|
||||
@@ -18,13 +18,18 @@ class Callable extends Expr, CfgScope {
|
||||
}
|
||||
|
||||
/** A method. */
|
||||
class Method extends Callable, BodyStatement, @method {
|
||||
final override Method::Range range;
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "Method" }
|
||||
class MethodBase extends Callable, BodyStatement, Scope {
|
||||
override MethodBase::Range range;
|
||||
|
||||
/** Gets the name of this method. */
|
||||
final string getName() { result = range.getName() }
|
||||
}
|
||||
|
||||
/** A normal method. */
|
||||
class Method extends MethodBase, @method {
|
||||
final override Method::Range range;
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "Method" }
|
||||
|
||||
/**
|
||||
* Holds if this is a setter method, as in the following example:
|
||||
@@ -40,16 +45,13 @@ class Method extends Callable, BodyStatement, @method {
|
||||
}
|
||||
|
||||
/** A singleton method. */
|
||||
class SingletonMethod extends Callable, BodyStatement, @singleton_method {
|
||||
class SingletonMethod extends MethodBase, @singleton_method {
|
||||
final override SingletonMethod::Range range;
|
||||
|
||||
final override string getAPrimaryQlClass() { result = "SingletonMethod" }
|
||||
|
||||
/** Gets the object of this singleton method. */
|
||||
final Expr getObject() { result = range.getObject() }
|
||||
|
||||
/** Gets the name of this method. */
|
||||
final string getName() { result = range.getName() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,7 +67,7 @@ class Lambda extends Callable, BodyStatement, @lambda {
|
||||
}
|
||||
|
||||
/** A block. */
|
||||
class Block extends Callable, StmtSequence {
|
||||
class Block extends Callable, StmtSequence, Scope {
|
||||
override Block::Range range;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,14 @@ private import internal.Module
|
||||
/**
|
||||
* The base class for classes, singleton classes, and modules.
|
||||
*/
|
||||
class ModuleBase extends BodyStatement {
|
||||
class ModuleBase extends BodyStatement, Scope {
|
||||
override ModuleBase::Range range;
|
||||
|
||||
/** Gets a method defined in this module/class. */
|
||||
Method getAMethod() { result = this.getAStmt() }
|
||||
MethodBase getAMethod() { result = this.getAStmt() }
|
||||
|
||||
/** Gets the method named `name` in this module/class, if any. */
|
||||
Method getMethod(string name) { result = this.getAMethod() and result.getName() = name }
|
||||
MethodBase getMethod(string name) { result = this.getAMethod() and result.getName() = name }
|
||||
|
||||
/** Gets a class defined in this module/class. */
|
||||
Class getAClass() { result = this.getAStmt() }
|
||||
|
||||
15
ql/src/codeql_ruby/ast/Scope.qll
Normal file
15
ql/src/codeql_ruby/ast/Scope.qll
Normal file
@@ -0,0 +1,15 @@
|
||||
private import codeql_ruby.AST
|
||||
private import internal.Scope
|
||||
|
||||
class Scope extends AstNode, Scope::ScopeType {
|
||||
override Scope::Range range;
|
||||
|
||||
AstNode getADescendant() { result = range.getADescendant() }
|
||||
|
||||
ModuleBase getEnclosingModule() { result = range.getEnclosingModule() }
|
||||
|
||||
MethodBase getEnclosingMethod() { result = range.getEnclosingMethod() }
|
||||
|
||||
/** Gets the scope in which this scope is nested, if any. */
|
||||
Scope getOuterScope() { result = range.getOuterScope() }
|
||||
}
|
||||
@@ -2,7 +2,6 @@ private import codeql_ruby.AST
|
||||
private import codeql_ruby.CFG
|
||||
private import internal.Expr
|
||||
private import internal.Statement
|
||||
private import internal.Variable
|
||||
private import codeql_ruby.controlflow.internal.ControlFlowGraphImpl
|
||||
|
||||
/**
|
||||
@@ -19,9 +18,6 @@ class Stmt extends AstNode {
|
||||
/** Gets the control-flow scope of this statement, if any. */
|
||||
CfgScope getCfgScope() { result = getCfgScope(this) }
|
||||
|
||||
/** Gets the variable scope that this statement belongs to. */
|
||||
VariableScope getVariableScope() { result = enclosingScope(this) }
|
||||
|
||||
/** Gets the enclosing callable, if any. */
|
||||
Callable getEnclosingCallable() { result = this.getCfgScope() }
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ private import codeql_ruby.AST
|
||||
private import codeql_ruby.ast.internal.AST
|
||||
private import codeql_ruby.ast.internal.Expr
|
||||
private import codeql_ruby.ast.internal.Parameter
|
||||
private import codeql_ruby.ast.internal.Scope
|
||||
private import TreeSitter
|
||||
|
||||
module Callable {
|
||||
@@ -14,13 +15,25 @@ module Callable {
|
||||
}
|
||||
}
|
||||
|
||||
module MethodBase {
|
||||
abstract class Range extends Callable::Range, BodyStatement::Range, Scope::Range {
|
||||
abstract string getName();
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
Callable::Range.super.child(label, child) or BodyStatement::Range.super.child(label, child)
|
||||
}
|
||||
|
||||
override string toString() { result = BodyStatement::Range.super.toString() }
|
||||
}
|
||||
}
|
||||
|
||||
module Method {
|
||||
class Range extends Callable::Range, BodyStatement::Range, @method {
|
||||
class Range extends MethodBase::Range, @method {
|
||||
final override Generated::Method generated;
|
||||
|
||||
override Parameter::Range getParameter(int n) { result = generated.getParameters().getChild(n) }
|
||||
|
||||
string getName() {
|
||||
override string getName() {
|
||||
result = generated.getName().(Generated::Token).getValue() or
|
||||
result = generated.getName().(Generated::Setter).getName().getValue() + "="
|
||||
}
|
||||
@@ -30,20 +43,16 @@ module Method {
|
||||
final override Generated::AstNode getChild(int i) { result = generated.getChild(i) }
|
||||
|
||||
final override string toString() { result = this.getName() }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
Callable::Range.super.child(label, child) or BodyStatement::Range.super.child(label, child)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module SingletonMethod {
|
||||
class Range extends Callable::Range, BodyStatement::Range, @singleton_method {
|
||||
class Range extends MethodBase::Range, @singleton_method {
|
||||
final override Generated::SingletonMethod generated;
|
||||
|
||||
override Parameter::Range getParameter(int n) { result = generated.getParameters().getChild(n) }
|
||||
|
||||
string getName() {
|
||||
override string getName() {
|
||||
result = generated.getName().(Generated::Token).getValue() or
|
||||
result = generated.getName().(SymbolLiteral).getValueText() or
|
||||
result = generated.getName().(Generated::Setter).getName().getValue() + "="
|
||||
@@ -56,9 +65,7 @@ module SingletonMethod {
|
||||
final override string toString() { result = this.getName() }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
Callable::Range.super.child(label, child)
|
||||
or
|
||||
BodyStatement::Range.super.child(label, child)
|
||||
MethodBase::Range.super.child(label, child)
|
||||
or
|
||||
label = "getObject" and child = getObject()
|
||||
}
|
||||
@@ -89,7 +96,7 @@ module Lambda {
|
||||
}
|
||||
|
||||
module Block {
|
||||
abstract class Range extends Callable::Range, StmtSequence::Range {
|
||||
abstract class Range extends Callable::Range, StmtSequence::Range, Scope::Range {
|
||||
Range() { not generated.getParent() instanceof Generated::Lambda }
|
||||
|
||||
override predicate child(string label, AstNode::Range child) {
|
||||
@@ -97,6 +104,8 @@ module Block {
|
||||
or
|
||||
StmtSequence::Range.super.child(label, child)
|
||||
}
|
||||
|
||||
override string toString() { result = StmtSequence::Range.super.toString() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,13 @@ private import codeql_ruby.AST
|
||||
private import codeql_ruby.ast.internal.AST
|
||||
private import codeql_ruby.ast.internal.Constant
|
||||
private import codeql_ruby.ast.internal.Expr
|
||||
private import codeql_ruby.ast.internal.Scope
|
||||
private import codeql_ruby.ast.internal.TreeSitter
|
||||
|
||||
module ModuleBase {
|
||||
abstract class Range extends BodyStatement::Range { }
|
||||
abstract class Range extends BodyStatement::Range, Scope::Range {
|
||||
override string toString() { result = BodyStatement::Range.super.toString() }
|
||||
}
|
||||
}
|
||||
|
||||
module Namespace {
|
||||
|
||||
63
ql/src/codeql_ruby/ast/internal/Scope.qll
Normal file
63
ql/src/codeql_ruby/ast/internal/Scope.qll
Normal file
@@ -0,0 +1,63 @@
|
||||
private import TreeSitter
|
||||
private import codeql_ruby.ast.internal.AST
|
||||
private import codeql_ruby.ast.internal.Module
|
||||
private import codeql_ruby.ast.internal.Method
|
||||
private import codeql_ruby.ast.internal.Statement
|
||||
|
||||
module Scope {
|
||||
class ScopeType = MethodLike or ModuleLike or BlockLike;
|
||||
|
||||
class BlockLike = @do_block or @lambda or @block or @end_block;
|
||||
|
||||
class ModuleLike = @program or @module or @class or @singleton_class;
|
||||
|
||||
class MethodLike = @method or @singleton_method;
|
||||
|
||||
class Range extends AstNode::Range, ScopeType {
|
||||
Range() { not exists(Generated::Lambda l | l.getBody() = this) }
|
||||
|
||||
Generated::AstNode getADescendant() { this = scopeOf(result) }
|
||||
|
||||
ModuleBase::Range getEnclosingModule() {
|
||||
result = this
|
||||
or
|
||||
not this instanceof ModuleBase::Range and result = this.getOuterScope().getEnclosingModule()
|
||||
}
|
||||
|
||||
MethodBase::Range getEnclosingMethod() {
|
||||
result = this
|
||||
or
|
||||
not this instanceof MethodBase::Range and
|
||||
not this instanceof ModuleBase::Range and
|
||||
result = this.getOuterScope().getEnclosingMethod()
|
||||
}
|
||||
|
||||
Scope::Range getOuterScope() { result = scopeOf(this) }
|
||||
|
||||
override string toString() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets the enclosing scope of a node */
|
||||
private Scope::Range scopeOf(Generated::AstNode n) {
|
||||
exists(Generated::AstNode p | p = parentOf(n) |
|
||||
p instanceof Scope::Range and result = p
|
||||
or
|
||||
not p instanceof Scope::Range and result = scopeOf(p)
|
||||
)
|
||||
}
|
||||
|
||||
private Generated::AstNode parentOf(Generated::AstNode n) {
|
||||
exists(Generated::AstNode parent | parent = n.getParent() |
|
||||
if
|
||||
n =
|
||||
[
|
||||
parent.(Generated::Module).getName(), parent.(Generated::Class).getName(),
|
||||
parent.(Generated::Class).getSuperclass(), parent.(Generated::SingletonClass).getValue(),
|
||||
parent.(Generated::Method).getName(), parent.(Generated::SingletonMethod).getName(),
|
||||
parent.(Generated::SingletonMethod).getObject()
|
||||
]
|
||||
then result = parent.getParent()
|
||||
else result = parent
|
||||
)
|
||||
}
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
private import codeql_ruby.ast.internal.AST as ASTInternal
|
||||
private import codeql_ruby.ast.internal.Control as Control
|
||||
private import codeql_ruby.ast.internal.Scope
|
||||
private import codeql_ruby.ast.internal.TreeSitter::Generated
|
||||
private import AstNodes
|
||||
private import codeql_ruby.ast.internal.Variable
|
||||
@@ -148,11 +149,6 @@ module CfgScope {
|
||||
}
|
||||
}
|
||||
|
||||
private AstNode parent(AstNode n) {
|
||||
result = parentOf(n) and
|
||||
not n instanceof CfgScope
|
||||
}
|
||||
|
||||
abstract private class ControlFlowTree extends AstNode {
|
||||
/**
|
||||
* Holds if `first` is the first element executed within this AST node.
|
||||
@@ -1263,11 +1259,16 @@ module Trees {
|
||||
}
|
||||
}
|
||||
|
||||
private Scope::Range parent(Scope::Range n) {
|
||||
result = n.getOuterScope() and
|
||||
not n instanceof CfgScope
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/** Gets the CFG scope of node `n`. */
|
||||
cached
|
||||
CfgScope getCfgScope(AstNode n) { result = unique(CfgScope scope | scope = parent*(parentOf(n))) }
|
||||
CfgScope getCfgScope(AstNode n) { result = parent*(any(Scope::Range x | x.getADescendant() = n)) }
|
||||
|
||||
private predicate isAbnormalExitType(SuccessorType t) {
|
||||
t instanceof RaiseSuccessor or t instanceof ExitSuccessor
|
||||
|
||||
@@ -6,7 +6,7 @@ private import CfgNodes::ExprNodes
|
||||
|
||||
/** Holds if `v` is uninitialized at index `i` in entry block `bb`. */
|
||||
predicate uninitializedWrite(EntryBasicBlock bb, int i, LocalVariable v) {
|
||||
v.getDeclaringScope().getScopeElement() = bb.getScope() and
|
||||
v.getDeclaringScope() = bb.getScope() and
|
||||
i = -1
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user