Merge pull request #127 from github/aibaars/ast-2

Some more AST
This commit is contained in:
Arthur Baars
2021-02-12 18:40:24 +01:00
committed by GitHub
14 changed files with 267 additions and 73 deletions

View File

@@ -12,6 +12,18 @@ class Expr extends Stmt {
Expr() { this = range }
}
/**
* A reference to the current object. For example:
* - `self == other`
* - `self.method_name`
* - `def self.method_name ... end`
*/
class Self extends Expr, @token_self {
override Self::Range range;
final override string getAPrimaryQlClass() { result = "Self" }
}
/**
* A literal.
*

View File

@@ -27,6 +27,32 @@ class ModuleBase extends BodyStatement {
Module getModule(string name) { result = this.getAModule() and result.getName() = name }
}
/**
* A Ruby source file.
*
* ```rb
* def main
* puts "hello world!"
* end
* main
* ```
*/
class Toplevel extends ModuleBase, @program {
final override Toplevel::Range range;
final override string getAPrimaryQlClass() { result = "Toplevel" }
/**
* Gets the `n`th `BEGIN` block.
*/
final BeginBlock getBeginBlock(int n) { result = range.getBeginBlock(n) }
/**
* Gets a `BEGIN` block.
*/
final BeginBlock getABeginBlock() { result = getBeginBlock(_) }
}
/**
* A class definition.
*

View File

@@ -1,5 +1,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
@@ -25,6 +26,39 @@ class Stmt extends AstNode {
Callable getEnclosingCallable() { result = this.getCfgScope() }
}
/**
* An empty statement (`;`).
*/
class EmptyStmt extends Stmt, @token_empty_statement {
final override EmptyStmt::Range range;
final override string getAPrimaryQlClass() { result = "EmptyStmt" }
}
/**
* An `BEGIN` block.
* ```rb
* BEGIN { puts "starting ..." }
* ```
*/
class BeginBlock extends StmtSequence, @begin_block {
final override BeginBlock::Range range;
final override string getAPrimaryQlClass() { result = "BeginBlock" }
}
/**
* An `END` block.
* ```rb
* END { puts "shutting down" }
* ```
*/
class EndBlock extends StmtSequence, @end_block {
final override EndBlock::Range range;
final override string getAPrimaryQlClass() { result = "EndBlock" }
}
/**
* A statement that may return a value: `return`, `break` and `next`.
*
@@ -82,3 +116,27 @@ class NextStmt extends ReturningStmt, @next {
final override string getAPrimaryQlClass() { result = "NextStmt" }
}
/**
* A `redo` statement.
* ```rb
* redo
* ```
*/
class RedoStmt extends Stmt, @redo {
final override RedoStmt::Range range;
final override string getAPrimaryQlClass() { result = "RedoStmt" }
}
/**
* A `retry` statement.
* ```rb
* retry
* ```
*/
class RetryStmt extends Stmt, @retry {
final override RetryStmt::Range range;
final override string getAPrimaryQlClass() { result = "RetryStmt" }
}

View File

@@ -20,16 +20,10 @@ module AstNode {
// an AST node, for example we include the `in` keyword in `for` loops
// in the CFG, but not the AST
RemoveWhenFullCoverage() {
this instanceof Generated::Program
or
this = any(Generated::Method m).getName()
or
this = any(Generated::SingletonMethod m).getName()
or
this instanceof Generated::BeginBlock
or
this instanceof Generated::EndBlock
or
this = any(Generated::Call c).getMethod() and
not this instanceof Generated::ScopeResolution
or
@@ -47,16 +41,10 @@ module AstNode {
or
this instanceof Generated::BareString
or
this instanceof Generated::Self
or
this instanceof Generated::Float
or
this instanceof Generated::Superclass
or
this instanceof Generated::EmptyStatement
or
this instanceof Generated::Redo
or
this instanceof Generated::Hash
or
this instanceof Generated::Array

View File

@@ -6,6 +6,14 @@ module Expr {
abstract class Range extends Stmt::Range { }
}
module Self {
class Range extends Expr::Range, @token_self {
final override Generated::Self generated;
final override string toString() { result = "self" }
}
}
module Literal {
abstract class Range extends Expr::Range {
abstract string getValueText();
@@ -224,6 +232,16 @@ module ParenthesizedExpr {
}
}
module BeginBlock {
class Range extends StmtSequence::Range, @begin_block {
final override Generated::BeginBlock generated;
final override Stmt getStmt(int n) { result = generated.getChild(n) }
final override string toString() { result = "BEGIN { ... }" }
}
}
module ThenExpr {
class Range extends StmtSequence::Range, @then {
final override Generated::Then generated;

View File

@@ -7,6 +7,25 @@ module ModuleBase {
abstract class Range extends BodyStatement::Range { }
}
module Toplevel {
class Range extends ModuleBase::Range, @program {
final override Generated::Program generated;
Range() { generated.getLocation().getFile().getExtension() != "erb" }
final override Generated::AstNode getChild(int i) {
result = generated.getChild(i) and
not result instanceof Generated::BeginBlock
}
final StmtSequence getBeginBlock(int n) {
result = rank[n](int i, Generated::BeginBlock b | b = generated.getChild(i) | b order by i)
}
final override string toString() { result = generated.getLocation().getFile().getBaseName() }
}
}
module Class {
class Range extends ModuleBase::Range, ConstantWriteAccess::Range, @class {
final override Generated::Class generated;

View File

@@ -1,11 +1,30 @@
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.TreeSitter
module Stmt {
abstract class Range extends AstNode::Range { }
}
module EmptyStmt {
class Range extends Stmt::Range, @token_empty_statement {
final override Generated::EmptyStatement generated;
final override string toString() { result = ";" }
}
}
module EndBlock {
class Range extends StmtSequence::Range, @end_block {
final override Generated::EndBlock generated;
final override Stmt getStmt(int n) { result = generated.getChild(n) }
final override string toString() { result = "END { ... }" }
}
}
module ReturningStmt {
abstract class Range extends Stmt::Range {
abstract Generated::ArgumentList getArgumentList();
@@ -51,3 +70,19 @@ module NextStmt {
final override Generated::ArgumentList getArgumentList() { result = generated.getChild() }
}
}
module RedoStmt {
class Range extends Stmt::Range, @redo {
final override Generated::Redo generated;
final override string toString() { result = "redo" }
}
}
module RetryStmt {
class Range extends Stmt::Range, @retry {
final override Generated::Retry generated;
final override string toString() { result = "retry" }
}
}

View File

@@ -74,7 +74,6 @@ callsWithNoReceiverArgumentsOrBlock
| calls.rb:286:5:286:9 | call to super | super |
| calls.rb:287:5:287:11 | call to super | super |
| calls.rb:303:5:303:7 | call to foo | foo |
| calls.rb:304:5:304:14 | call to super | super |
| calls.rb:305:5:305:9 | call to super | super |
callsWithArguments
| calls.rb:14:1:14:11 | call to foo | foo | 0 | calls.rb:14:5:14:5 | 0 |
@@ -174,6 +173,7 @@ callsWithReceiver
| calls.rb:275:7:275:12 | call to bar | calls.rb:275:7:275:7 | X |
| calls.rb:279:11:279:16 | call to bar | calls.rb:279:11:279:11 | X |
| calls.rb:303:5:303:13 | call to super | calls.rb:303:5:303:7 | call to foo |
| calls.rb:304:5:304:14 | call to super | calls.rb:304:5:304:8 | self |
| calls.rb:305:5:305:15 | call to super | calls.rb:305:5:305:9 | call to super |
callsWithBlock
| calls.rb:17:1:17:17 | call to foo | calls.rb:17:5:17:17 | { ... } |

View File

@@ -301,7 +301,7 @@ end
class AnotherClass
def another_method
foo.super
self.super # TODO: this shows up as a call without a receiver, but that should be fixed once we handle `self` expressions
self.super
super.super # we expect the receiver to be a SuperCall, while the outer call should not (it's just a regular Call)
end
end
end

View File

@@ -1,4 +1,5 @@
moduleBases
| classes.rb:2:1:56:3 | classes.rb | Toplevel |
| classes.rb:3:1:4:3 | Foo | Class |
| classes.rb:7:1:8:3 | Bar | Class |
| classes.rb:11:1:12:3 | Baz | Class |
@@ -10,6 +11,7 @@ moduleBases
| classes.rb:41:1:52:3 | class << ... | Class |
| classes.rb:55:1:56:3 | MyClassInGlobalScope | Class |
| modules.rb:1:1:2:3 | Empty | Module |
| modules.rb:1:1:61:3 | modules.rb | Toplevel |
| modules.rb:4:1:24:3 | Foo | Module |
| modules.rb:5:3:14:5 | Bar | Module |
| modules.rb:6:5:7:7 | ClassInFooBar | Class |
@@ -20,7 +22,14 @@ moduleBases
| modules.rb:48:1:57:3 | Bar | Module |
| modules.rb:49:3:50:5 | ClassInAnotherDefinitionOfFooBar | Class |
| modules.rb:60:1:61:3 | MyModuleInGlobalScope | Module |
| toplevel.rb:1:1:5:23 | toplevel.rb | Toplevel |
moduleBaseClasses
| classes.rb:2:1:56:3 | classes.rb | classes.rb:3:1:4:3 | Foo |
| classes.rb:2:1:56:3 | classes.rb | classes.rb:7:1:8:3 | Bar |
| classes.rb:2:1:56:3 | classes.rb | classes.rb:11:1:12:3 | Baz |
| classes.rb:2:1:56:3 | classes.rb | classes.rb:16:1:17:3 | MyClass |
| classes.rb:2:1:56:3 | classes.rb | classes.rb:20:1:37:3 | Wibble |
| classes.rb:2:1:56:3 | classes.rb | classes.rb:55:1:56:3 | MyClassInGlobalScope |
| classes.rb:20:1:37:3 | Wibble | classes.rb:32:3:33:5 | ClassInWibble |
| modules.rb:4:1:24:3 | Foo | modules.rb:19:3:20:5 | ClassInFoo |
| modules.rb:5:3:14:5 | Bar | modules.rb:6:5:7:7 | ClassInFooBar |
@@ -38,5 +47,12 @@ moduleBaseMethods
| modules.rb:37:1:46:3 | Bar | modules.rb:41:3:42:5 | method_b |
| modules.rb:48:1:57:3 | Bar | modules.rb:52:3:53:5 | method_in_another_definition_of_foo_bar |
moduleBaseModules
| classes.rb:2:1:56:3 | classes.rb | classes.rb:15:1:15:20 | MyModule |
| classes.rb:20:1:37:3 | Wibble | classes.rb:35:3:36:5 | ModuleInWibble |
| modules.rb:1:1:61:3 | modules.rb | modules.rb:1:1:2:3 | Empty |
| modules.rb:1:1:61:3 | modules.rb | modules.rb:4:1:24:3 | Foo |
| modules.rb:1:1:61:3 | modules.rb | modules.rb:26:1:35:3 | Foo |
| modules.rb:1:1:61:3 | modules.rb | modules.rb:37:1:46:3 | Bar |
| modules.rb:1:1:61:3 | modules.rb | modules.rb:48:1:57:3 | Bar |
| modules.rb:1:1:61:3 | modules.rb | modules.rb:60:1:61:3 | MyModuleInGlobalScope |
| modules.rb:4:1:24:3 | Foo | modules.rb:5:3:14:5 | Bar |

View File

@@ -0,0 +1,8 @@
toplevel
| classes.rb:2:1:56:3 | classes.rb | Toplevel |
| modules.rb:1:1:61:3 | modules.rb | Toplevel |
| toplevel.rb:1:1:5:23 | toplevel.rb | Toplevel |
beginBlocks
| toplevel.rb:1:1:5:23 | toplevel.rb | 1 | toplevel.rb:5:1:5:22 | BEGIN { ... } |
endBlocks
| toplevel.rb:1:1:5:23 | toplevel.rb | toplevel.rb:3:1:3:18 | END { ... } |

View File

@@ -0,0 +1,9 @@
import ruby
query predicate toplevel(Toplevel m, string pClass) { pClass = m.getAPrimaryQlClass() }
query predicate beginBlocks(Toplevel m, int i, BeginBlock b) { b = m.getBeginBlock(i) }
query predicate endBlocks(Toplevel m, EndBlock b) {
b.getLocation().getFile() = m.getLocation().getFile()
}

View File

@@ -0,0 +1,5 @@
puts "world"
END { puts "!!!" }
BEGIN { puts "hello" }

View File

@@ -1,5 +1,5 @@
break_ensure.rb:
# 1| enter AstNode
# 1| enter break_ensure.rb
#-----| -> m1
# 1| enter m1
@@ -15,20 +15,20 @@ break_ensure.rb:
#-----| -> elements
case.rb:
# 1| enter AstNode
# 1| enter case.rb
#-----| -> if_in_case
# 1| enter if_in_case
#-----| -> case ...
cfg.rb:
# 1| enter AstNode
# 1| enter cfg.rb
#-----| -> bar
# 15| enter AstNode
# 15| enter BEGIN { ... }
#-----| -> puts
# 19| enter AstNode
# 19| enter END { ... }
#-----| -> puts
# 25| enter { ... }
@@ -65,7 +65,7 @@ cfg.rb:
#-----| -> x
exit.rb:
# 1| enter AstNode
# 1| enter exit.rb
#-----| -> m1
# 1| enter m1
@@ -75,14 +75,14 @@ exit.rb:
#-----| -> x
heredoc.rb:
# 1| enter AstNode
# 1| enter heredoc.rb
#-----| -> double_heredoc
# 1| enter double_heredoc
#-----| -> puts
ifs.rb:
# 1| enter AstNode
# 1| enter ifs.rb
#-----| -> m1
# 1| enter m1
@@ -107,7 +107,7 @@ ifs.rb:
#-----| -> true
loops.rb:
# 1| enter AstNode
# 1| enter loops.rb
#-----| -> m1
# 1| enter m1
@@ -123,7 +123,7 @@ loops.rb:
#-----| -> x
raise.rb:
# 1| enter AstNode
# 1| enter raise.rb
#-----| -> ExceptionA
# 7| enter m1
@@ -422,7 +422,7 @@ break_ensure.rb:
#-----| -> call to puts
# 44| m4
#-----| -> exit AstNode (normal)
#-----| -> exit break_ensure.rb (normal)
# 44| m4
#-----| -> m4
@@ -511,7 +511,7 @@ break_ensure.rb:
case.rb:
# 1| if_in_case
#-----| -> exit AstNode (normal)
#-----| -> exit case.rb (normal)
# 1| if_in_case
#-----| -> if_in_case
@@ -620,7 +620,7 @@ cfg.rb:
#-----| -> StringArray
# 12| call to puts
#-----| -> BeginBlock
#-----| -> BEGIN { ... }
# 12| puts
#-----| -> 4
@@ -628,11 +628,11 @@ cfg.rb:
# 12| 4
#-----| -> call to puts
# 15| BeginBlock
#-----| -> EndBlock
# 15| BEGIN { ... }
#-----| -> END { ... }
# 16| call to puts
#-----| -> exit AstNode (normal)
#-----| -> exit BEGIN { ... } (normal)
# 16| puts
#-----| -> hello
@@ -640,11 +640,11 @@ cfg.rb:
# 16| hello
#-----| -> call to puts
# 19| EndBlock
# 19| END { ... }
#-----| -> 41
# 20| call to puts
#-----| -> exit AstNode (normal)
#-----| -> exit END { ... } (normal)
# 20| puts
#-----| -> world
@@ -1973,7 +1973,7 @@ cfg.rb:
# 181| ... == ...
#-----| false -> if ...
#-----| true -> Redo
#-----| true -> redo
# 181| x
#-----| -> 5
@@ -1981,7 +1981,7 @@ cfg.rb:
# 181| 5
#-----| -> ... == ...
# 181| Redo
# 181| redo
#-----| redo -> x
# 182| call to puts
@@ -2039,7 +2039,7 @@ cfg.rb:
# 188| 42
# 191| call to run_block
#-----| -> exit AstNode (normal)
#-----| -> exit cfg.rb (normal)
# 191| run_block
#-----| -> { ... }
@@ -2101,7 +2101,7 @@ exit.rb:
#-----| -> call to puts
# 8| m2
#-----| -> exit AstNode (normal)
#-----| -> exit exit.rb (normal)
# 8| m2
#-----| -> m2
@@ -2142,7 +2142,7 @@ exit.rb:
heredoc.rb:
# 1| double_heredoc
#-----| -> exit AstNode (normal)
#-----| -> exit heredoc.rb (normal)
# 1| double_heredoc
#-----| -> double_heredoc
@@ -2519,7 +2519,7 @@ ifs.rb:
#-----| -> ... == ...
# 40| constant_condition
#-----| -> exit AstNode (normal)
#-----| -> exit ifs.rb (normal)
# 40| constant_condition
#-----| -> constant_condition
@@ -2651,7 +2651,7 @@ loops.rb:
# 16| ... > ...
#-----| false -> elsif ...
#-----| true -> Redo
#-----| true -> redo
# 16| x
#-----| -> 10
@@ -2659,7 +2659,7 @@ loops.rb:
# 16| 10
#-----| -> ... > ...
# 17| Redo
# 17| redo
#-----| redo -> puts
# 19| call to puts
@@ -2681,7 +2681,7 @@ loops.rb:
#-----| -> call to puts
# 24| m3
#-----| -> exit AstNode (normal)
#-----| -> exit loops.rb (normal)
# 24| m3
#-----| -> m3
@@ -3722,7 +3722,7 @@ raise.rb:
#-----| -> exit m13 (normal)
# 154| m14
#-----| -> exit AstNode (normal)
#-----| -> exit raise.rb (normal)
# 154| m14
#-----| -> m14
@@ -3768,7 +3768,7 @@ raise.rb:
#-----| -> call to nil?
break_ensure.rb:
# 1| exit AstNode
# 1| exit break_ensure.rb
# 1| exit m1
@@ -3779,16 +3779,16 @@ break_ensure.rb:
# 44| exit m4
case.rb:
# 1| exit AstNode
# 1| exit case.rb
# 1| exit if_in_case
cfg.rb:
# 1| exit AstNode
# 1| exit cfg.rb
# 15| exit AstNode
# 15| exit BEGIN { ... }
# 19| exit AstNode
# 19| exit END { ... }
# 25| exit { ... }
@@ -3811,19 +3811,19 @@ cfg.rb:
# 191| exit { ... }
exit.rb:
# 1| exit AstNode
# 1| exit exit.rb
# 1| exit m1
# 8| exit m2
heredoc.rb:
# 1| exit AstNode
# 1| exit heredoc.rb
# 1| exit double_heredoc
ifs.rb:
# 1| exit AstNode
# 1| exit ifs.rb
# 1| exit m1
@@ -3840,7 +3840,7 @@ ifs.rb:
# 40| exit constant_condition
loops.rb:
# 1| exit AstNode
# 1| exit loops.rb
# 1| exit m1
@@ -3851,7 +3851,7 @@ loops.rb:
# 25| exit do ... end
raise.rb:
# 1| exit AstNode
# 1| exit raise.rb
# 7| exit m1
@@ -3884,8 +3884,8 @@ raise.rb:
# 155| exit { ... }
break_ensure.rb:
# 1| exit AstNode (normal)
#-----| -> exit AstNode
# 1| exit break_ensure.rb (normal)
#-----| -> exit break_ensure.rb
# 1| exit m1 (normal)
#-----| -> exit m1
@@ -3900,21 +3900,21 @@ break_ensure.rb:
#-----| -> exit m4
case.rb:
# 1| exit AstNode (normal)
#-----| -> exit AstNode
# 1| exit case.rb (normal)
#-----| -> exit case.rb
# 1| exit if_in_case (normal)
#-----| -> exit if_in_case
cfg.rb:
# 1| exit AstNode (normal)
#-----| -> exit AstNode
# 1| exit cfg.rb (normal)
#-----| -> exit cfg.rb
# 15| exit AstNode (normal)
#-----| -> exit AstNode
# 15| exit BEGIN { ... } (normal)
#-----| -> exit BEGIN { ... }
# 19| exit AstNode (normal)
#-----| -> exit AstNode
# 19| exit END { ... } (normal)
#-----| -> exit END { ... }
# 25| exit { ... } (normal)
#-----| -> exit { ... }
@@ -3947,8 +3947,8 @@ cfg.rb:
#-----| -> exit { ... }
exit.rb:
# 1| exit AstNode (normal)
#-----| -> exit AstNode
# 1| exit exit.rb (normal)
#-----| -> exit exit.rb
# 1| exit m1 (abnormal)
#-----| -> exit m1
@@ -3963,15 +3963,15 @@ exit.rb:
#-----| -> exit m2
heredoc.rb:
# 1| exit AstNode (normal)
#-----| -> exit AstNode
# 1| exit heredoc.rb (normal)
#-----| -> exit heredoc.rb
# 1| exit double_heredoc (normal)
#-----| -> exit double_heredoc
ifs.rb:
# 1| exit AstNode (normal)
#-----| -> exit AstNode
# 1| exit ifs.rb (normal)
#-----| -> exit ifs.rb
# 1| exit m1 (normal)
#-----| -> exit m1
@@ -3995,8 +3995,8 @@ ifs.rb:
#-----| -> exit constant_condition
loops.rb:
# 1| exit AstNode (normal)
#-----| -> exit AstNode
# 1| exit loops.rb (normal)
#-----| -> exit loops.rb
# 1| exit m1 (normal)
#-----| -> exit m1
@@ -4011,8 +4011,8 @@ loops.rb:
#-----| -> exit do ... end
raise.rb:
# 1| exit AstNode (normal)
#-----| -> exit AstNode
# 1| exit raise.rb (normal)
#-----| -> exit raise.rb
# 7| exit m1 (abnormal)
#-----| -> exit m1