Add Scope.qll

This commit is contained in:
Arthur Baars
2021-03-09 09:46:42 +01:00
parent ce69c912fd
commit 00260db58f
10 changed files with 126 additions and 36 deletions

View File

@@ -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;
}

View File

@@ -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() }

View 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() }
}

View File

@@ -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() }
}

View File

@@ -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() }
}
}

View File

@@ -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 {

View 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
)
}