Merge remote-tracking branch 'origin/main' into cfg_cleanup

This commit is contained in:
Nick Rolfe
2021-05-17 16:26:28 +01:00
88 changed files with 9885 additions and 4219 deletions

View File

@@ -1,9 +1,10 @@
{
"provide": [
"ql/src/qlpack.yml",
"ql/consistency-queries/qlpack.yml",
"ql/test/qlpack.yml",
"ql/examples/qlpack.yml",
"upgrades/qlpack.yml",
"extractor-pack/codeql-extractor.yml"
]
}
}

15
.devcontainer/Dockerfile Normal file
View File

@@ -0,0 +1,15 @@
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.162.0/containers/rust/.devcontainer/base.Dockerfile
FROM mcr.microsoft.com/vscode/devcontainers/rust:0-1
RUN apt-key --keyring /usr/share/keyrings/githubcli-archive-keyring.gpg adv \
--keyserver keyserver.ubuntu.com --recv-key C99B11DEB97541F0 && \
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages $(lsb_release -cs) main" \
| tee /etc/apt/sources.list.d/github-cli2.list > /dev/null
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install --no-install-recommends gh
COPY post_create.sh /bin/post_create.sh
COPY post_attach.sh /bin/post_attach.sh

View File

@@ -0,0 +1,39 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.162.0/containers/rust
{
"name": "Rust",
"build": {
"dockerfile": "Dockerfile"
},
"runArgs": [
"--cap-add=SYS_PTRACE",
"--security-opt",
"seccomp=unconfined"
],
// Set *default* container specific settings.json values on container create.
"settings": {
"terminal.integrated.shell.linux": "/bin/bash",
"lldb.executable": "/usr/bin/lldb",
// VS Code don't watch files under ./target
"files.watcherExclude": {
"**/target/**": true
}
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"rust-lang.rust",
"bungcip.better-toml",
"vadimcn.vscode-lldb",
"mutantdino.resourcemonitor",
"ms-azuretools.vscode-docker",
"github.vscode-codeql"
],
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "rustc --version",
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode",
"postCreateCommand": [ "/bin/post_create.sh" ],
"postAttachCommand": [ "flock", "-E", "0", "-n", "/var/lock/post_attach.lock", "/bin/post_attach.sh" ]
}

37
.devcontainer/post_attach.sh Executable file
View File

@@ -0,0 +1,37 @@
#! /bin/bash
set -xe
echo "Check installed CodeQL version"
CURRENT_CODEQL_BIN=$(readlink -e /usr/local/bin/codeql || echo "")
LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | sort --version-sort | tail -1)
BASE_DIR=/home/vscode/codeql-binaries
mkdir -p "${BASE_DIR}"
LATEST_CODEQL_DIR="${BASE_DIR}/codeql-${LATEST}"
LATEST_CODEQL_BIN="${LATEST_CODEQL_DIR}/codeql/codeql"
if [ "${CURRENT_CODEQL_BIN}" != "${LATEST_CODEQL_BIN}" ]; then
echo "Installing CodeQL ${LATEST}"
TMPDIR=$(mktemp -d -p "$(dirname ${LATEST_CODEQL_DIR})")
gh release download --repo https://github.com/github/codeql-cli-binaries --pattern codeql-linux64.zip -D "${TMPDIR}" "$LATEST"
unzip -oq "${TMPDIR}/codeql-linux64.zip" -d "${TMPDIR}"
rm -f "${TMPDIR}/codeql-linux64.zip"
mv "${TMPDIR}" "${LATEST_CODEQL_DIR}"
test -x "${LATEST_CODEQL_BIN}" && sudo ln -sf "${LATEST_CODEQL_BIN}" /usr/local/bin/codeql
if [[ "${CURRENT_CODEQL_BIN}" =~ .*/codeql/codeql ]]; then
rm -rf "$(dirname $(dirname ${CURRENT_CODEQL_BIN}))"
fi
fi
echo "Build the Ruby extractor"
# clone the git dependencies using "git clone" because cargo's builtin git support is rather slow
REPO_DIR="${CARGO_HOME:-/home/vscode/.cargo}/git/db"
REPO_DIR_ERB="${REPO_DIR}/tree-sitter-embedded-template-4c796e3340c233b6"
REPO_DIR_RUBY="${REPO_DIR}/tree-sitter-ruby-666a40ce046f8e7a"
mkdir -p "${REPO_DIR}"
test -e "${REPO_DIR_ERB}" || git clone -q --bare https://github.com/tree-sitter/tree-sitter-embedded-template "${REPO_DIR_ERB}"
test -e "${REPO_DIR_RUBY}" || git clone -q --bare https://github.com/tree-sitter/tree-sitter-ruby.git "${REPO_DIR_RUBY}"
./create-extractor-pack.sh

4
.devcontainer/post_create.sh Executable file
View File

@@ -0,0 +1,4 @@
#! /bin/bash
mkdir -p /home/vscode/.config/codeql
echo '--search-path /workspaces/codeql-ruby' >> /home/vscode/.config/codeql/config

2
Cargo.lock generated
View File

@@ -590,7 +590,7 @@ dependencies = [
[[package]]
name = "tree-sitter-embedded-template"
version = "0.17.0"
source = "git+https://github.com/aibaars/tree-sitter-embedded-template?rev=d4aac29c08aa7c596633d00b5ec2dd2d247eafe4#d4aac29c08aa7c596633d00b5ec2dd2d247eafe4"
source = "git+https://github.com/tree-sitter/tree-sitter-embedded-template?rev=d4aac29c08aa7c596633d00b5ec2dd2d247eafe4#d4aac29c08aa7c596633d00b5ec2dd2d247eafe4"
dependencies = [
"cc",
"tree-sitter",

2
codeql

Submodule codeql updated: a1ccbcdaf1...6693c5bdd0

View File

@@ -10,7 +10,7 @@ edition = "2018"
flate2 = "1.0"
node-types = { path = "../node-types" }
tree-sitter = "0.17"
tree-sitter-embedded-template = { git = "https://github.com/aibaars/tree-sitter-embedded-template", rev = "d4aac29c08aa7c596633d00b5ec2dd2d247eafe4" }
tree-sitter-embedded-template = { git = "https://github.com/tree-sitter/tree-sitter-embedded-template", rev = "d4aac29c08aa7c596633d00b5ec2dd2d247eafe4" }
tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "32cd5a04adb4accb0c121f037ab59df3c3488228" }
clap = "2.33"
tracing = "0.1"

View File

@@ -305,22 +305,58 @@ struct Visitor<'a> {
}
impl Visitor<'_> {
fn record_parse_error(
&mut self,
error_message: String,
full_error_message: String,
loc: Label,
) {
error!("{}", full_error_message);
let id = self.trap_writer.fresh_id();
self.trap_writer.add_tuple(
"diagnostics",
vec![
Arg::Label(id),
Arg::Int(40), // severity 40 = error
Arg::String("parse_error".to_string()),
Arg::String(error_message),
Arg::String(full_error_message),
Arg::Label(loc),
],
);
}
fn record_parse_error_for_node(
&mut self,
error_message: String,
full_error_message: String,
node: Node,
) {
let (start_line, start_column, end_line, end_column) = location_for(&self.source, node);
let loc = self.trap_writer.location(
self.file_label,
start_line,
start_column,
end_line,
end_column,
);
self.record_parse_error(error_message, full_error_message, loc);
}
fn enter_node(&mut self, node: Node) -> bool {
if node.is_error() {
error!(
"{}:{}: parse error",
&self.path,
node.start_position().row + 1
);
return false;
}
if node.is_missing() {
error!(
"{}:{}: parse error: expecting '{}'",
if node.is_error() || node.is_missing() {
let error_message = if node.is_missing() {
format!("parse error: expecting '{}'", node.kind())
} else {
"parse error".to_string()
};
let full_error_message = format!(
"{}:{}: {}",
&self.path,
node.start_position().row + 1,
node.kind()
error_message
);
self.record_parse_error_for_node(error_message, full_error_message, node);
return false;
}
@@ -405,12 +441,15 @@ impl Visitor<'_> {
}
}
_ => {
error!(
"{}:{}: unknown table type: '{}'",
let error_message = format!("unknown table type: '{}'", node.kind());
let full_error_message = format!(
"{}:{}: {}",
&self.path,
node.start_position().row + 1,
node.kind()
error_message
);
self.record_parse_error(error_message, full_error_message, loc);
valid = false;
}
}
@@ -456,26 +495,36 @@ impl Visitor<'_> {
values.push(Arg::Label(child_node.label));
}
} else if field.name.is_some() {
error!(
"{}:{}: type mismatch for field {}::{} with type {:?} != {:?}",
&self.path,
node.start_position().row + 1,
let error_message = format!(
"type mismatch for field {}::{} with type {:?} != {:?}",
node.kind(),
child_node.field_name.unwrap_or("child"),
child_node.type_name,
field.type_info
)
);
let full_error_message = format!(
"{}:{}: {}",
&self.path,
node.start_position().row + 1,
error_message
);
self.record_parse_error_for_node(error_message, full_error_message, *node);
}
} else {
if child_node.field_name.is_some() || child_node.type_name.named {
error!(
"{}:{}: value for unknown field: {}::{} and type {:?}",
&self.path,
node.start_position().row + 1,
let error_message = format!(
"value for unknown field: {}::{} and type {:?}",
node.kind(),
&child_node.field_name.unwrap_or("child"),
&child_node.type_name
);
let full_error_message = format!(
"{}:{}: {}",
&self.path,
node.start_position().row + 1,
error_message
);
self.record_parse_error_for_node(error_message, full_error_message, *node);
}
}
}
@@ -489,10 +538,8 @@ impl Visitor<'_> {
args.push(child_values.first().unwrap().clone());
} else {
is_valid = false;
error!(
"{}:{}: {} for field: {}::{}",
&self.path,
node.start_position().row + 1,
let error_message = format!(
"{} for field: {}::{}",
if child_values.is_empty() {
"missing value"
} else {
@@ -500,7 +547,14 @@ impl Visitor<'_> {
},
node.kind(),
column_name
)
);
let full_error_message = format!(
"{}:{}: {}",
&self.path,
node.start_position().row + 1,
error_message
);
self.record_parse_error_for_node(error_message, full_error_message, *node);
}
}
Storage::Table {

View File

@@ -248,6 +248,11 @@ fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<dbscheme::Entry<
entries.push(dbscheme::Entry::Table(token_table));
entries.push(dbscheme::Entry::Case(token_case));
// Add the diagnostics table
let (diagnostics_case, diagnostics_table) = create_diagnostics();
entries.push(dbscheme::Entry::Table(diagnostics_table));
entries.push(dbscheme::Entry::Case(diagnostics_case));
// Create a union of all database types.
entries.push(dbscheme::Entry::Union(dbscheme::Union {
name: "ast_node",
@@ -590,6 +595,69 @@ fn create_source_location_prefix_table<'a>() -> dbscheme::Entry<'a> {
})
}
fn create_diagnostics<'a>() -> (dbscheme::Case<'a>, dbscheme::Table<'a>) {
let table = dbscheme::Table {
name: "diagnostics",
keysets: None,
columns: vec![
dbscheme::Column {
unique: true,
db_type: dbscheme::DbColumnType::Int,
name: "id",
ql_type: ql::Type::AtType("diagnostic"),
ql_type_is_ref: false,
},
dbscheme::Column {
unique: false,
db_type: dbscheme::DbColumnType::Int,
name: "severity",
ql_type: ql::Type::Int,
ql_type_is_ref: true,
},
dbscheme::Column {
unique: false,
db_type: dbscheme::DbColumnType::String,
name: "error_tag",
ql_type: ql::Type::String,
ql_type_is_ref: true,
},
dbscheme::Column {
unique: false,
db_type: dbscheme::DbColumnType::String,
name: "error_message",
ql_type: ql::Type::String,
ql_type_is_ref: true,
},
dbscheme::Column {
unique: false,
db_type: dbscheme::DbColumnType::String,
name: "full_error_message",
ql_type: ql::Type::String,
ql_type_is_ref: true,
},
dbscheme::Column {
unique: false,
db_type: dbscheme::DbColumnType::Int,
name: "location",
ql_type: ql::Type::AtType("location_default"),
ql_type_is_ref: true,
},
],
};
let severities: Vec<(usize, &str)> = vec![
(10, "diagnostic_debug"),
(20, "diagnostic_info"),
(30, "diagnostic_warning"),
(40, "diagnostic_error"),
];
let case = dbscheme::Case {
name: "diagnostic",
column: "severity",
branches: severities,
};
(case, table)
}
fn main() {
tracing_subscriber::fmt()
.with_target(false)

View File

@@ -15,6 +15,14 @@ query predicate missingParent(AstNode node, string cls) {
query predicate multipleParents(AstNode node, AstNode parent, string cls) {
parent = node.getParent() and
count(node.getParent()) > 1 and
cls = getAPrimaryQlClass(parent)
cls = getAPrimaryQlClass(parent) and
exists(AstNode one, AstNode two |
one = node.getParent() and
two = node.getParent() and
one != two
|
one.isSynthesized() and two.isSynthesized()
or
not one.isSynthesized() and not two.isSynthesized()
)
}

View File

@@ -190,4 +190,7 @@ class File extends Container, @file {
/** Gets the number of lines of comments in this file. */
int getNumberOfLinesOfComments() { result = count(int line | this.line(line, true)) }
/** Holds if this file was extracted from ordinary source code. */
predicate fromSource() { files(this, _, _, _, 1) }
}

View File

@@ -14,6 +14,7 @@ import ast.Statement
import ast.Variable
private import ast.internal.AST
private import ast.internal.Scope
private import ast.internal.Synthesis
/**
* A node in the abstract syntax tree. This class is the base class for all Ruby
@@ -56,7 +57,11 @@ class AstNode extends TAstNode {
final AstNode getAChild() { result = this.getAChild(_) }
/** Gets the parent of this `AstNode`, if this node is not a root node. */
final AstNode getParent() { result.getAChild() = this }
final AstNode getParent() {
result.getAChild() = this
or
result.getAChild().getDesugared() = this
}
/**
* Gets a child of this node, which can also be retrieved using a predicate
@@ -75,5 +80,25 @@ class AstNode extends TAstNode {
* foo(123)
* ```
*/
predicate isSynthesized() { this instanceof TImplicitSelf }
final predicate isSynthesized() { this = getSynthChild(_, _) }
/**
* Gets the desugared version of this AST node, if any.
*
* For example, the desugared version of
*
* ```rb
* x += y
* ```
*
* is
*
* ```rb
* x = x + y
* ```
*
* when `x` is a variable. Whenever an AST node can be desugared,
* then the desugared version is used in the control-flow graph.
*/
final AstNode getDesugared() { result = getSynthChild(this, -1) }
}

View File

@@ -0,0 +1,52 @@
private import codeql.Locations
/** A diagnostic emitted during extraction, such as a parse error */
class Diagnostic extends @diagnostic {
int severity;
string tag;
string message;
string fullMessage;
Location location;
Diagnostic() { diagnostics(this, severity, tag, message, fullMessage, location) }
/**
* Gets the numerical severity level associated with this diagnostic.
*/
int getSeverity() { result = severity }
/** Gets a string representation of the severity of this diagnostic. */
string getSeverityText() {
severity = 10 and result = "Debug"
or
severity = 20 and result = "Info"
or
severity = 30 and result = "Warning"
or
severity = 40 and result = "Error"
}
/** Gets the error code associated with this diagnostic, e.g. parse_error. */
string getTag() { result = tag }
/**
* Gets the error message text associated with this diagnostic.
*/
string getMessage() { result = message }
/**
* Gets the full error message text associated with this diagnostic.
*/
string getFullMessage() { result = fullMessage }
/** Gets the source location of this diagnostic. */
Location getLocation() { result = location }
/** Gets a textual representation of this diagnostic. */
string toString() { result = this.getMessage() }
}
/** A diagnostic relating to a particular error in extracting a file. */
class ExtractionError extends Diagnostic, @diagnostic_error {
ExtractionError() { this.getTag() = "parse_error" }
}

View File

@@ -137,7 +137,7 @@ private class IdentifierMethodCall extends MethodCall, TIdentifierMethodCall {
final override string getMethodName() { result = getMethodName(this, g.getValue()) }
final override Self getReceiver() { result = TImplicitSelf(g) }
final override Self getReceiver() { result = TSelfSynth(this, 0) }
}
private class ScopeResolutionMethodCall extends MethodCall, TScopeResolutionMethodCall {
@@ -162,12 +162,7 @@ private class RegularMethodCall extends MethodCall, TRegularMethodCall {
not exists(g.getReceiver()) and
toGenerated(result) = g.getMethod().(Generated::ScopeResolution).getScope()
or
// If there's no explicit receiver (or scope resolution that acts like a
// receiver), then the receiver is implicitly `self`. N.B. `::Foo()` is
// not valid Ruby.
not exists(g.getReceiver()) and
not exists(g.getMethod().(Generated::ScopeResolution).getScope()) and
result = TImplicitSelf(g)
result = TSelfSynth(this, 0)
}
final override string getMethodName() {

View File

@@ -79,6 +79,12 @@ class StmtSequence extends Expr, TStmtSequence {
override AstNode getAChild(string pred) { pred = "getStmt" and result = this.getStmt(_) }
}
private class StmtSequenceSynth extends StmtSequence, TStmtSequenceSynth {
final override Stmt getStmt(int n) { synthChild(this, n, result) }
final override string toString() { result = "..." }
}
private class Then extends StmtSequence, TThen {
private Generated::Then g;
@@ -210,11 +216,11 @@ class ParenthesizedExpr extends StmtSequence, TParenthesizedExpr {
ParenthesizedExpr() { this = TParenthesizedExpr(g) }
final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
final override string getAPrimaryQlClass() { result = "ParenthesizedExpr" }
final override string toString() { result = "( ... )" }
final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
}
/**

View File

@@ -47,6 +47,42 @@ class IntegerLiteral extends NumericLiteral, TIntegerLiteral {
final override string getValueText() { result = g.getValue() }
/** Gets the numerical value of this integer literal. */
final int getValue() {
exists(string s, string values, string str |
s = this.getValueText().toLowerCase() and
(
s.matches("0b%") and
values = "01" and
str = s.suffix(2)
or
s.matches("0x%") and
values = "0123456789abcdef" and
str = s.suffix(2)
or
s.charAt(0) = "0" and
not s.charAt(1) = ["b", "x", "o"] and
values = "01234567" and
str = s.suffix(1)
or
s.matches("0o%") and
values = "01234567" and
str = s.suffix(2)
or
s.charAt(0) != "0" and values = "0123456789" and str = s
)
|
result =
sum(int index, string c, int v, int exp |
c = str.replaceAll("_", "").charAt(index) and
v = values.indexOf(c.toLowerCase()) and
exp = str.replaceAll("_", "").length() - index - 1
|
v * values.length().pow(exp)
)
)
}
final override string toString() { result = this.getValueText() }
final override string getAPrimaryQlClass() { result = "IntegerLiteral" }

View File

@@ -101,12 +101,6 @@ class DefinedExpr extends UnaryOperation, TDefinedExpr {
/** A binary operation. */
class BinaryOperation extends Operation, TBinaryOperation {
private Generated::Binary g;
BinaryOperation() { g = toGenerated(this) }
final override string getOperator() { result = g.getOperator() }
final override Expr getAnOperand() {
result = this.getLeftOperand() or result = this.getRightOperand()
}
@@ -122,10 +116,28 @@ class BinaryOperation extends Operation, TBinaryOperation {
}
/** Gets the left operand of this binary operation. */
final Stmt getLeftOperand() { toGenerated(result) = g.getLeft() }
Stmt getLeftOperand() { none() }
/** Gets the right operand of this binary operation. */
final Stmt getRightOperand() { toGenerated(result) = g.getRight() }
Stmt getRightOperand() { none() }
}
private class BinaryOperationReal extends BinaryOperation {
private Generated::Binary g;
BinaryOperationReal() { g = toGenerated(this) }
final override string getOperator() { result = g.getOperator() }
final override Stmt getLeftOperand() { toGenerated(result) = g.getLeft() }
final override Stmt getRightOperand() { toGenerated(result) = g.getRight() }
}
abstract private class BinaryOperationSynth extends BinaryOperation {
final override Stmt getLeftOperand() { synthChild(this, 0, result) }
final override Stmt getRightOperand() { synthChild(this, 1, result) }
}
/**
@@ -143,6 +155,10 @@ class AddExpr extends BinaryArithmeticOperation, TAddExpr {
final override string getAPrimaryQlClass() { result = "AddExpr" }
}
private class AddExprSynth extends AddExpr, BinaryOperationSynth, TAddExprSynth {
final override string getOperator() { result = "+" }
}
/**
* A subtract expression.
* ```rb
@@ -153,6 +169,10 @@ class SubExpr extends BinaryArithmeticOperation, TSubExpr {
final override string getAPrimaryQlClass() { result = "SubExpr" }
}
private class SubExprSynth extends SubExpr, BinaryOperationSynth, TSubExprSynth {
final override string getOperator() { result = "-" }
}
/**
* A multiply expression.
* ```rb
@@ -163,6 +183,10 @@ class MulExpr extends BinaryArithmeticOperation, TMulExpr {
final override string getAPrimaryQlClass() { result = "MulExpr" }
}
private class MulExprSynth extends MulExpr, BinaryOperationSynth, TMulExprSynth {
final override string getOperator() { result = "*" }
}
/**
* A divide expression.
* ```rb
@@ -173,6 +197,10 @@ class DivExpr extends BinaryArithmeticOperation, TDivExpr {
final override string getAPrimaryQlClass() { result = "DivExpr" }
}
private class DivExprSynth extends DivExpr, BinaryOperationSynth, TDivExprSynth {
final override string getOperator() { result = "/" }
}
/**
* A modulo expression.
* ```rb
@@ -183,6 +211,10 @@ class ModuloExpr extends BinaryArithmeticOperation, TModuloExpr {
final override string getAPrimaryQlClass() { result = "ModuloExpr" }
}
private class ModuloExprSynth extends ModuloExpr, BinaryOperationSynth, TModuloExprSynth {
final override string getOperator() { result = "%" }
}
/**
* An exponent expression.
* ```rb
@@ -193,6 +225,10 @@ class ExponentExpr extends BinaryArithmeticOperation, TExponentExpr {
final override string getAPrimaryQlClass() { result = "ExponentExpr" }
}
private class ExponentExprSynth extends ExponentExpr, BinaryOperationSynth, TExponentExprSynth {
final override string getOperator() { result = "**" }
}
/**
* A binary logical operation.
*/
@@ -209,6 +245,10 @@ class LogicalAndExpr extends BinaryLogicalOperation, TLogicalAndExpr {
final override string getAPrimaryQlClass() { result = "LogicalAndExpr" }
}
private class LogicalAndExprSynth extends LogicalAndExpr, BinaryOperationSynth, TLogicalAndExprSynth {
final override string getOperator() { result = "&&" }
}
/**
* A logical OR operation, using either `or` or `||`.
* ```rb
@@ -220,6 +260,10 @@ class LogicalOrExpr extends BinaryLogicalOperation, TLogicalOrExpr {
final override string getAPrimaryQlClass() { result = "LogicalOrExpr" }
}
private class LogicalOrExprSynth extends LogicalOrExpr, BinaryOperationSynth, TLogicalOrExprSynth {
final override string getOperator() { result = "||" }
}
/**
* A binary bitwise operation.
*/
@@ -235,6 +279,10 @@ class LShiftExpr extends BinaryBitwiseOperation, TLShiftExpr {
final override string getAPrimaryQlClass() { result = "LShiftExpr" }
}
private class LShiftExprSynth extends LShiftExpr, BinaryOperationSynth, TLShiftExprSynth {
final override string getOperator() { result = "<<" }
}
/**
* A right-shift operation.
* ```rb
@@ -245,6 +293,10 @@ class RShiftExpr extends BinaryBitwiseOperation, TRShiftExpr {
final override string getAPrimaryQlClass() { result = "RShiftExpr" }
}
private class RShiftExprSynth extends RShiftExpr, BinaryOperationSynth, TRShiftExprSynth {
final override string getOperator() { result = ">>" }
}
/**
* A bitwise AND operation.
* ```rb
@@ -255,6 +307,10 @@ class BitwiseAndExpr extends BinaryBitwiseOperation, TBitwiseAndExpr {
final override string getAPrimaryQlClass() { result = "BitwiseAndExpr" }
}
private class BitwiseAndSynthExpr extends BitwiseAndExpr, BinaryOperationSynth, TBitwiseAndExprSynth {
final override string getOperator() { result = "&" }
}
/**
* A bitwise OR operation.
* ```rb
@@ -265,6 +321,10 @@ class BitwiseOrExpr extends BinaryBitwiseOperation, TBitwiseOrExpr {
final override string getAPrimaryQlClass() { result = "BitwiseOrExpr" }
}
private class BitwiseOrSynthExpr extends BitwiseOrExpr, BinaryOperationSynth, TBitwiseOrExprSynth {
final override string getOperator() { result = "|" }
}
/**
* An XOR (exclusive OR) operation.
* ```rb
@@ -275,6 +335,10 @@ class BitwiseXorExpr extends BinaryBitwiseOperation, TBitwiseXorExpr {
final override string getAPrimaryQlClass() { result = "BitwiseXorExpr" }
}
private class BitwiseXorSynthExpr extends BitwiseXorExpr, BinaryOperationSynth, TBitwiseXorExprSynth {
final override string getOperator() { result = "^" }
}
/**
* A comparison operation. That is, either an equality operation or a
* relational operation.
@@ -455,17 +519,25 @@ class Assignment extends Operation, TAssignment {
* ```
*/
class AssignExpr extends Assignment, TAssignExpr {
final override string getOperator() { result = "=" }
final override string getAPrimaryQlClass() { result = "AssignExpr" }
}
private class AssignExprReal extends AssignExpr, TAssignExprReal {
private Generated::Assignment g;
AssignExpr() { this = TAssignExpr(g) }
AssignExprReal() { this = TAssignExprReal(g) }
final override Pattern getLeftOperand() { toGenerated(result) = g.getLeft() }
final override Expr getRightOperand() { toGenerated(result) = g.getRight() }
}
final override string getOperator() { result = "=" }
private class AssignExprSynth extends AssignExpr, TAssignExprSynth {
final override Pattern getLeftOperand() { synthChild(this, 0, result) }
override string getAPrimaryQlClass() { result = "AssignExpr" }
final override Expr getRightOperand() { synthChild(this, 1, result) }
}
/**

View File

@@ -37,10 +37,7 @@ class TuplePatternParameter extends PatternParameter, TuplePattern, TTuplePatter
final override string getAPrimaryQlClass() { result = "TuplePatternParameter" }
override AstNode getAChild(string pred) {
result = PatternParameter.super.getAChild(pred) or
result = TuplePattern.super.getAChild(pred)
}
override AstNode getAChild(string pred) { result = TuplePattern.super.getAChild(pred) }
}
/** A named parameter. */
@@ -60,8 +57,6 @@ class NamedParameter extends Parameter, TNamedParameter {
final VariableAccess getDefiningAccess() { result = this.getVariable().getDefiningAccess() }
override AstNode getAChild(string pred) {
result = Parameter.super.getAChild(pred)
or
pred = "getDefiningAccess" and
result = this.getDefiningAccess()
}
@@ -75,7 +70,7 @@ class SimpleParameter extends NamedParameter, PatternParameter, VariablePattern,
final override string getName() { result = g.getValue() }
final override LocalVariable getVariable() { result = TLocalVariable(_, _, g) }
final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g) }
final override LocalVariable getAVariable() { result = this.getVariable() }
@@ -99,7 +94,7 @@ class BlockParameter extends NamedParameter, TBlockParameter {
final override string getName() { result = g.getName().getValue() }
final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) }
final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g.getName()) }
final override string toString() { result = "&" + this.getName() }
@@ -122,7 +117,7 @@ class HashSplatParameter extends NamedParameter, THashSplatParameter {
final override string getAPrimaryQlClass() { result = "HashSplatParameter" }
final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) }
final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g.getName()) }
final override string toString() { result = "**" + this.getName() }
@@ -147,7 +142,7 @@ class KeywordParameter extends NamedParameter, TKeywordParameter {
final override string getAPrimaryQlClass() { result = "KeywordParameter" }
final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) }
final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g.getName()) }
/**
* Gets the default value, i.e. the value assigned to the parameter when one
@@ -197,7 +192,7 @@ class OptionalParameter extends NamedParameter, TOptionalParameter {
*/
final Expr getDefaultValue() { toGenerated(result) = g.getValue() }
final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) }
final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g.getName()) }
final override string toString() { result = this.getName() }
@@ -227,7 +222,7 @@ class SplatParameter extends NamedParameter, TSplatParameter {
final override string getAPrimaryQlClass() { result = "SplatParameter" }
final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) }
final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g.getName()) }
final override string toString() { result = "*" + this.getName() }

View File

@@ -7,9 +7,13 @@ private import internal.Variable
/** A pattern. */
class Pattern extends AstNode {
Pattern() {
explicitAssignmentNode(toGenerated(this), _) or
implicitAssignmentNode(toGenerated(this)) or
explicitAssignmentNode(toGenerated(this), _)
or
implicitAssignmentNode(toGenerated(this))
or
implicitParameterAssignmentNode(toGenerated(this), _)
or
this = getSynthChild(any(AssignExpr ae), 0)
}
/** Gets a variable used in (or introduced by) this pattern. */

View File

@@ -8,21 +8,17 @@ private import internal.Variable
/** A variable declared in a scope. */
class Variable extends TVariable {
Variable::Range range;
Variable() { range = this }
/** Gets the name of this variable. */
final string getName() { result = range.getName() }
string getName() { none() }
/** Gets a textual representation of this variable. */
final string toString() { result = this.getName() }
/** Gets the location of this variable. */
final Location getLocation() { result = range.getLocation() }
Location getLocation() { none() }
/** Gets the scope this variable is declared in. */
final Scope getDeclaringScope() { toGenerated(result) = range.getDeclaringScope() }
Scope getDeclaringScope() { none() }
/** Gets an access to this variable. */
VariableAccess getAnAccess() { result.getVariable() = this }
@@ -30,12 +26,10 @@ class Variable extends TVariable {
/** A local variable. */
class LocalVariable extends Variable, TLocalVariable {
override LocalVariable::Range range;
final override LocalVariableAccess getAnAccess() { result.getVariable() = this }
override LocalVariableAccess getAnAccess() { none() }
/** Gets the access where this local variable is first introduced. */
VariableAccess getDefiningAccess() { result = range.getDefiningAccess() }
VariableAccess getDefiningAccess() { none() }
/**
* Holds if this variable is captured. For example in
@@ -55,14 +49,14 @@ class LocalVariable extends Variable, TLocalVariable {
}
/** A global variable. */
class GlobalVariable extends Variable, TGlobalVariable {
class GlobalVariable extends VariableReal, TGlobalVariable {
override GlobalVariable::Range range;
final override GlobalVariableAccess getAnAccess() { result.getVariable() = this }
}
/** An instance variable. */
class InstanceVariable extends Variable, TInstanceVariable {
class InstanceVariable extends VariableReal, TInstanceVariable {
override InstanceVariable::Range range;
/** Holds is this variable is a class instance variable. */
@@ -72,7 +66,7 @@ class InstanceVariable extends Variable, TInstanceVariable {
}
/** A class variable. */
class ClassVariable extends Variable, TClassVariable {
class ClassVariable extends VariableReal, TClassVariable {
override ClassVariable::Range range;
final override ClassVariableAccess getAnAccess() { result.getVariable() = this }
@@ -95,6 +89,8 @@ class VariableAccess extends Expr, TVariableAccess {
*/
predicate isExplicitWrite(AstNode assignment) {
explicitWriteAccess(toGenerated(this), toGenerated(assignment))
or
this = assignment.(AssignExpr).getLeftOperand()
}
/**
@@ -125,22 +121,12 @@ class VariableWriteAccess extends VariableAccess {
/** An access to a variable where the value is read. */
class VariableReadAccess extends VariableAccess {
VariableReadAccess() {
not this instanceof VariableWriteAccess
or
// `x` in `x += y` is considered both a read and a write
this = any(AssignOperation a).getLeftOperand()
}
VariableReadAccess() { not this instanceof VariableWriteAccess }
}
/** An access to a local variable. */
class LocalVariableAccess extends VariableAccess, TLocalVariableAccess {
private Generated::Identifier g;
private LocalVariable v;
LocalVariableAccess() { this = TLocalVariableAccess(g, v) }
final override LocalVariable getVariable() { result = v }
override LocalVariable getVariable() { none() }
final override string getAPrimaryQlClass() { result = "LocalVariableAccess" }
@@ -160,8 +146,6 @@ class LocalVariableAccess extends VariableAccess, TLocalVariableAccess {
* the access to `x` in the second `puts x` is not.
*/
final predicate isCapturedAccess() { isCapturedAccess(this) }
final override string toString() { result = g.getValue() }
}
/** An access to a local variable where the value is updated. */
@@ -172,16 +156,9 @@ class LocalVariableReadAccess extends LocalVariableAccess, VariableReadAccess {
/** An access to a global variable. */
class GlobalVariableAccess extends VariableAccess, TGlobalVariableAccess {
private Generated::GlobalVariable g;
private GlobalVariable v;
GlobalVariableAccess() { this = TGlobalVariableAccess(g, v) }
final override GlobalVariable getVariable() { result = v }
override GlobalVariable getVariable() { none() }
final override string getAPrimaryQlClass() { result = "GlobalVariableAccess" }
final override string toString() { result = g.getValue() }
}
/** An access to a global variable where the value is updated. */
@@ -192,28 +169,14 @@ class GlobalVariableReadAccess extends GlobalVariableAccess, VariableReadAccess
/** An access to an instance variable. */
class InstanceVariableAccess extends VariableAccess, TInstanceVariableAccess {
private Generated::InstanceVariable g;
private InstanceVariable v;
InstanceVariableAccess() { this = TInstanceVariableAccess(g, v) }
final override InstanceVariable getVariable() { result = v }
override InstanceVariable getVariable() { none() }
final override string getAPrimaryQlClass() { result = "InstanceVariableAccess" }
final override string toString() { result = g.getValue() }
}
/** An access to a class variable. */
class ClassVariableAccess extends VariableAccess, TClassVariableAccess {
private Generated::ClassVariable g;
private ClassVariable v;
ClassVariableAccess() { this = TClassVariableAccess(g, v) }
final override ClassVariable getVariable() { result = v }
override ClassVariable getVariable() { none() }
final override string getAPrimaryQlClass() { result = "ClassVariableAccess" }
final override string toString() { result = g.getValue() }
}

View File

@@ -3,6 +3,7 @@ private import TreeSitter
private import codeql_ruby.ast.internal.Parameter
private import codeql_ruby.ast.internal.Variable
private import codeql_ruby.AST as AST
private import Synthesis
module MethodName {
predicate range(Generated::UnderscoreMethodName g) {
@@ -16,11 +17,16 @@ module MethodName {
@token_identifier or @token_instance_variable or @token_operator;
}
private predicate mkSynthChild(SynthKind kind, AST::AstNode parent, int i) {
any(Synthesis s).child(parent, i, SynthChild(kind))
}
cached
private module Cached {
cached
newtype TAstNode =
TAddExpr(Generated::Binary g) { g instanceof @binary_plus } or
TAddExprReal(Generated::Binary g) { g instanceof @binary_plus } or
TAddExprSynth(AST::AstNode parent, int i) { mkSynthChild(AddExprKind(), parent, i) } or
TAliasStmt(Generated::Alias g) or
TArgumentList(Generated::AstNode g) {
(
@@ -50,7 +56,8 @@ private module Cached {
TAssignExponentExpr(Generated::OperatorAssignment g) {
g instanceof @operator_assignment_starstarequal
} or
TAssignExpr(Generated::Assignment g) or
TAssignExprReal(Generated::Assignment g) or
TAssignExprSynth(AST::AstNode parent, int i) { mkSynthChild(AssignExprKind(), parent, i) } or
TAssignLShiftExpr(Generated::OperatorAssignment g) {
g instanceof @operator_assignment_langlelangleequal
} or
@@ -72,9 +79,16 @@ private module Cached {
TBareSymbolLiteral(Generated::BareSymbol g) or
TBeginBlock(Generated::BeginBlock g) or
TBeginExpr(Generated::Begin g) or
TBitwiseAndExpr(Generated::Binary g) { g instanceof @binary_ampersand } or
TBitwiseOrExpr(Generated::Binary g) { g instanceof @binary_pipe } or
TBitwiseXorExpr(Generated::Binary g) { g instanceof @binary_caret } or
TBitwiseAndExprReal(Generated::Binary g) { g instanceof @binary_ampersand } or
TBitwiseAndExprSynth(AST::AstNode parent, int i) {
mkSynthChild(BitwiseAndExprKind(), parent, i)
} or
TBitwiseOrExprReal(Generated::Binary g) { g instanceof @binary_pipe } or
TBitwiseOrExprSynth(AST::AstNode parent, int i) { mkSynthChild(BitwiseOrExprKind(), parent, i) } or
TBitwiseXorExprReal(Generated::Binary g) { g instanceof @binary_caret } or
TBitwiseXorExprSynth(AST::AstNode parent, int i) {
mkSynthChild(BitwiseXorExprKind(), parent, i)
} or
TBlockArgument(Generated::BlockArgument g) or
TBlockParameter(Generated::BlockParameter g) or
TBraceBlock(Generated::Block g) { not g.getParent() instanceof Generated::Lambda } or
@@ -83,9 +97,12 @@ private module Cached {
TCaseExpr(Generated::Case g) or
TCharacterLiteral(Generated::Character g) or
TClassDeclaration(Generated::Class g) or
TClassVariableAccess(Generated::ClassVariable g, AST::ClassVariable v) {
TClassVariableAccessReal(Generated::ClassVariable g, AST::ClassVariable v) {
ClassVariableAccess::range(g, v)
} or
TClassVariableAccessSynth(AST::AstNode parent, int i, AST::ClassVariable v) {
mkSynthChild(ClassVariableAccessKind(v), parent, i)
} or
TComplementExpr(Generated::Unary g) { g instanceof @unary_tilde } or
TComplexLiteral(Generated::Complex g) or
TDefinedExpr(Generated::Unary g) { g instanceof @unary_definedquestion } or
@@ -93,7 +110,8 @@ private module Cached {
TDestructuredLeftAssignment(Generated::DestructuredLeftAssignment g) {
not strictcount(int i | exists(g.getParent().(Generated::LeftAssignmentList).getChild(i))) = 1
} or
TDivExpr(Generated::Binary g) { g instanceof @binary_slash } or
TDivExprReal(Generated::Binary g) { g instanceof @binary_slash } or
TDivExprSynth(AST::AstNode parent, int i) { mkSynthChild(DivExprKind(), parent, i) } or
TDo(Generated::Do g) or
TDoBlock(Generated::DoBlock g) { not g.getParent() instanceof Generated::Lambda } or
TElementReference(Generated::ElementReference g) or
@@ -103,17 +121,20 @@ private module Cached {
TEndBlock(Generated::EndBlock g) or
TEnsure(Generated::Ensure g) or
TEqExpr(Generated::Binary g) { g instanceof @binary_equalequal } or
TExplicitSelf(Generated::Self g) or
TExponentExpr(Generated::Binary g) { g instanceof @binary_starstar } or
TExponentExprReal(Generated::Binary g) { g instanceof @binary_starstar } or
TExponentExprSynth(AST::AstNode parent, int i) { mkSynthChild(ExponentExprKind(), parent, i) } or
TFalseLiteral(Generated::False g) or
TFloatLiteral(Generated::Float g) { not any(Generated::Rational r).getChild() = g } or
TForExpr(Generated::For g) or
TForIn(Generated::In g) or // TODO REMOVE
TGEExpr(Generated::Binary g) { g instanceof @binary_rangleequal } or
TGTExpr(Generated::Binary g) { g instanceof @binary_rangle } or
TGlobalVariableAccess(Generated::GlobalVariable g, AST::GlobalVariable v) {
TGlobalVariableAccessReal(Generated::GlobalVariable g, AST::GlobalVariable v) {
GlobalVariableAccess::range(g, v)
} or
TGlobalVariableAccessSynth(AST::AstNode parent, int i, AST::GlobalVariable v) {
mkSynthChild(GlobalVariableAccessKind(v), parent, i)
} or
THashKeySymbolLiteral(Generated::HashKeySymbol g) or
THashLiteral(Generated::Hash g) or
THashSplatArgument(Generated::HashSplatArgument g) or
@@ -122,34 +143,44 @@ private module Cached {
TIdentifierMethodCall(Generated::Identifier g) { isIdentifierMethodCall(g) } or
TIf(Generated::If g) or
TIfModifierExpr(Generated::IfModifier g) or
TImplicitSelf(Generated::AstNode g) {
isIdentifierMethodCall(g)
or
isRegularMethodCall(g) and
not exists(g.(Generated::Call).getReceiver()) and
not exists(g.(Generated::Call).getMethod().(Generated::ScopeResolution).getScope())
} or
TInstanceVariableAccess(Generated::InstanceVariable g, AST::InstanceVariable v) {
TInstanceVariableAccessReal(Generated::InstanceVariable g, AST::InstanceVariable v) {
InstanceVariableAccess::range(g, v)
} or
TInstanceVariableAccessSynth(AST::AstNode parent, int i, AST::InstanceVariable v) {
mkSynthChild(InstanceVariableAccessKind(v), parent, i)
} or
TIntegerLiteral(Generated::Integer g) { not any(Generated::Rational r).getChild() = g } or
TKeywordParameter(Generated::KeywordParameter g) or
TLEExpr(Generated::Binary g) { g instanceof @binary_langleequal } or
TLShiftExpr(Generated::Binary g) { g instanceof @binary_langlelangle } or
TLShiftExprReal(Generated::Binary g) { g instanceof @binary_langlelangle } or
TLShiftExprSynth(AST::AstNode parent, int i) { mkSynthChild(LShiftExprKind(), parent, i) } or
TLTExpr(Generated::Binary g) { g instanceof @binary_langle } or
TLambda(Generated::Lambda g) or
TLeftAssignmentList(Generated::LeftAssignmentList g) or
TLocalVariableAccess(Generated::Identifier g, AST::LocalVariable v) {
TLocalVariableAccessReal(Generated::Identifier g, AST::LocalVariable v) {
LocalVariableAccess::range(g, v)
} or
TLogicalAndExpr(Generated::Binary g) {
TLocalVariableAccessSynth(AST::AstNode parent, int i, AST::LocalVariable v) {
mkSynthChild(LocalVariableAccessRealKind(v), parent, i)
or
mkSynthChild(LocalVariableAccessSynthKind(v), parent, i)
} or
TLogicalAndExprReal(Generated::Binary g) {
g instanceof @binary_and or g instanceof @binary_ampersandampersand
} or
TLogicalOrExpr(Generated::Binary g) { g instanceof @binary_or or g instanceof @binary_pipepipe } or
TLogicalAndExprSynth(AST::AstNode parent, int i) {
mkSynthChild(LogicalAndExprKind(), parent, i)
} or
TLogicalOrExprReal(Generated::Binary g) {
g instanceof @binary_or or g instanceof @binary_pipepipe
} or
TLogicalOrExprSynth(AST::AstNode parent, int i) { mkSynthChild(LogicalOrExprKind(), parent, i) } or
TMethod(Generated::Method g) or
TModuleDeclaration(Generated::Module g) or
TModuloExpr(Generated::Binary g) { g instanceof @binary_percent } or
TMulExpr(Generated::Binary g) { g instanceof @binary_star } or
TModuloExprReal(Generated::Binary g) { g instanceof @binary_percent } or
TModuloExprSynth(AST::AstNode parent, int i) { mkSynthChild(ModuloExprKind(), parent, i) } or
TMulExprReal(Generated::Binary g) { g instanceof @binary_star } or
TMulExprSynth(AST::AstNode parent, int i) { mkSynthChild(MulExprKind(), parent, i) } or
TNEExpr(Generated::Binary g) { g instanceof @binary_bangequal } or
TNextStmt(Generated::Next g) or
TNilLiteral(Generated::Nil g) or
@@ -158,7 +189,8 @@ private module Cached {
TOptionalParameter(Generated::OptionalParameter g) or
TPair(Generated::Pair g) or
TParenthesizedExpr(Generated::ParenthesizedStatements g) or
TRShiftExpr(Generated::Binary g) { g instanceof @binary_ranglerangle } or
TRShiftExprReal(Generated::Binary g) { g instanceof @binary_ranglerangle } or
TRShiftExprSynth(AST::AstNode parent, int i) { mkSynthChild(RShiftExprKind(), parent, i) } or
TRangeLiteral(Generated::Range g) or
TRationalLiteral(Generated::Rational g) or
TRedoStmt(Generated::Redo g) or
@@ -187,6 +219,8 @@ private module Cached {
i = g.getName() and
not exists(Generated::Call c | c.getMethod() = g)
} or
TSelfReal(Generated::Self g) or
TSelfSynth(AST::AstNode parent, int i) { mkSynthChild(SelfKind(), parent, i) } or
TSimpleParameter(Generated::Identifier g) { g instanceof Parameter::Range } or
TSimpleSymbolLiteral(Generated::SimpleSymbol g) or
TSingletonClass(Generated::SingletonClass g) or
@@ -194,6 +228,7 @@ private module Cached {
TSpaceshipExpr(Generated::Binary g) { g instanceof @binary_langleequalrangle } or
TSplatArgument(Generated::SplatArgument g) or
TSplatParameter(Generated::SplatParameter g) or
TStmtSequenceSynth(AST::AstNode parent, int i) { mkSynthChild(StmtSequenceKind(), parent, i) } or
TStringArrayLiteral(Generated::StringArray g) or
TStringConcatenation(Generated::ChainedString g) or
TStringEscapeSequenceComponent(Generated::EscapeSequence g) or
@@ -201,7 +236,8 @@ private module Cached {
TStringTextComponent(Generated::Token g) {
g instanceof Generated::StringContent or g instanceof Generated::HeredocContent
} or
TSubExpr(Generated::Binary g) { g instanceof @binary_minus } or
TSubExprReal(Generated::Binary g) { g instanceof @binary_minus } or
TSubExprSynth(AST::AstNode parent, int i) { mkSynthChild(SubExprKind(), parent, i) } or
TSubshellLiteral(Generated::Subshell g) or
TSymbolArrayLiteral(Generated::SymbolArray g) or
TTernaryIfExpr(Generated::Conditional g) or
@@ -245,7 +281,7 @@ private module Cached {
*/
cached
Generated::AstNode toGenerated(AST::AstNode n) {
n = TAddExpr(result) or
n = TAddExprReal(result) or
n = TAliasStmt(result) or
n = TArgumentList(result) or
n = TAssignAddExpr(result) or
@@ -254,7 +290,7 @@ private module Cached {
n = TAssignBitwiseXorExpr(result) or
n = TAssignDivExpr(result) or
n = TAssignExponentExpr(result) or
n = TAssignExpr(result) or
n = TAssignExprReal(result) or
n = TAssignLShiftExpr(result) or
n = TAssignLogicalAndExpr(result) or
n = TAssignLogicalOrExpr(result) or
@@ -266,9 +302,9 @@ private module Cached {
n = TBareSymbolLiteral(result) or
n = TBeginBlock(result) or
n = TBeginExpr(result) or
n = TBitwiseAndExpr(result) or
n = TBitwiseOrExpr(result) or
n = TBitwiseXorExpr(result) or
n = TBitwiseAndExprReal(result) or
n = TBitwiseOrExprReal(result) or
n = TBitwiseXorExprReal(result) or
n = TBlockArgument(result) or
n = TBlockParameter(result) or
n = TBraceBlock(result) or
@@ -277,13 +313,13 @@ private module Cached {
n = TCaseExpr(result) or
n = TCharacterLiteral(result) or
n = TClassDeclaration(result) or
n = TClassVariableAccess(result, _) or
n = TClassVariableAccessReal(result, _) or
n = TComplementExpr(result) or
n = TComplexLiteral(result) or
n = TDefinedExpr(result) or
n = TDelimitedSymbolLiteral(result) or
n = TDestructuredLeftAssignment(result) or
n = TDivExpr(result) or
n = TDivExprReal(result) or
n = TDo(result) or
n = TDoBlock(result) or
n = TElementReference(result) or
@@ -293,15 +329,14 @@ private module Cached {
n = TEndBlock(result) or
n = TEnsure(result) or
n = TEqExpr(result) or
n = TExplicitSelf(result) or
n = TExponentExpr(result) or
n = TExponentExprReal(result) or
n = TFalseLiteral(result) or
n = TFloatLiteral(result) or
n = TForExpr(result) or
n = TForIn(result) or // TODO REMOVE
n = TGEExpr(result) or
n = TGTExpr(result) or
n = TGlobalVariableAccess(result, _) or
n = TGlobalVariableAccessReal(result, _) or
n = THashKeySymbolLiteral(result) or
n = THashLiteral(result) or
n = THashSplatArgument(result) or
@@ -310,21 +345,21 @@ private module Cached {
n = TIdentifierMethodCall(result) or
n = TIf(result) or
n = TIfModifierExpr(result) or
n = TInstanceVariableAccess(result, _) or
n = TInstanceVariableAccessReal(result, _) or
n = TIntegerLiteral(result) or
n = TKeywordParameter(result) or
n = TLEExpr(result) or
n = TLShiftExpr(result) or
n = TLShiftExprReal(result) or
n = TLTExpr(result) or
n = TLambda(result) or
n = TLeftAssignmentList(result) or
n = TLocalVariableAccess(result, _) or
n = TLogicalAndExpr(result) or
n = TLogicalOrExpr(result) or
n = TLocalVariableAccessReal(result, _) or
n = TLogicalAndExprReal(result) or
n = TLogicalOrExprReal(result) or
n = TMethod(result) or
n = TModuleDeclaration(result) or
n = TModuloExpr(result) or
n = TMulExpr(result) or
n = TModuloExprReal(result) or
n = TMulExprReal(result) or
n = TNEExpr(result) or
n = TNextStmt(result) or
n = TNilLiteral(result) or
@@ -333,7 +368,7 @@ private module Cached {
n = TOptionalParameter(result) or
n = TPair(result) or
n = TParenthesizedExpr(result) or
n = TRShiftExpr(result) or
n = TRShiftExprReal(result) or
n = TRangeLiteral(result) or
n = TRationalLiteral(result) or
n = TRedoStmt(result) or
@@ -349,6 +384,7 @@ private module Cached {
n = TReturnStmt(result) or
n = TScopeResolutionConstantAccess(result, _) or
n = TScopeResolutionMethodCall(result, _) or
n = TSelfReal(result) or
n = TSimpleParameter(result) or
n = TSimpleSymbolLiteral(result) or
n = TSingletonClass(result) or
@@ -361,7 +397,7 @@ private module Cached {
n = TStringEscapeSequenceComponent(result) or
n = TStringInterpolationComponent(result) or
n = TStringTextComponent(result) or
n = TSubExpr(result) or
n = TSubExprReal(result) or
n = TSubshellLiteral(result) or
n = TSymbolArrayLiteral(result) or
n = TTernaryIfExpr(result) or
@@ -385,14 +421,105 @@ private module Cached {
n = TYieldCall(result)
}
/** Gets the `i`th synthesized child of `parent`. */
cached
AST::AstNode getSynthChild(AST::AstNode parent, int i) {
exists(SynthKind kind | mkSynthChild(kind, parent, i) |
kind = AddExprKind() and
result = TAddExprSynth(parent, i)
or
kind = AssignExprKind() and
result = TAssignExprSynth(parent, i)
or
kind = BitwiseAndExprKind() and
result = TBitwiseAndExprSynth(parent, i)
or
kind = BitwiseOrExprKind() and
result = TBitwiseOrExprSynth(parent, i)
or
kind = BitwiseXorExprKind() and
result = TBitwiseXorExprSynth(parent, i)
or
exists(AST::ClassVariable v |
kind = ClassVariableAccessKind(v) and
result = TClassVariableAccessSynth(parent, i, v)
)
or
kind = DivExprKind() and
result = TDivExprSynth(parent, i)
or
kind = ExponentExprKind() and
result = TExponentExprSynth(parent, i)
or
exists(AST::GlobalVariable v |
kind = GlobalVariableAccessKind(v) and
result = TGlobalVariableAccessSynth(parent, i, v)
)
or
exists(AST::InstanceVariable v |
kind = InstanceVariableAccessKind(v) and
result = TInstanceVariableAccessSynth(parent, i, v)
)
or
kind = LShiftExprKind() and
result = TLShiftExprSynth(parent, i)
or
exists(AST::LocalVariable v | result = TLocalVariableAccessSynth(parent, i, v) |
kind = LocalVariableAccessRealKind(v)
or
kind = LocalVariableAccessSynthKind(v)
)
or
kind = LogicalAndExprKind() and
result = TLogicalAndExprSynth(parent, i)
or
kind = LogicalOrExprKind() and
result = TLogicalOrExprSynth(parent, i)
or
kind = ModuloExprKind() and
result = TModuloExprSynth(parent, i)
or
kind = MulExprKind() and
result = TMulExprSynth(parent, i)
or
kind = RShiftExprKind() and
result = TRShiftExprSynth(parent, i)
or
kind = SelfKind() and
result = TSelfSynth(parent, i)
or
kind = StmtSequenceKind() and
result = TStmtSequenceSynth(parent, i)
or
kind = SubExprKind() and
result = TSubExprSynth(parent, i)
)
}
/**
* Holds if the `i`th child of `parent` is `child`. Either `parent` or
* `child` (or both) is a synthesized node.
*/
cached
predicate synthChild(AST::AstNode parent, int i, AST::AstNode child) {
child = getSynthChild(parent, i)
or
any(Synthesis s).child(parent, i, RealChild(child))
}
/**
* Like `toGenerated`, but also returns generated nodes for synthesized AST
* nodes.
*/
cached
Generated::AstNode toGeneratedInclSynth(AST::AstNode n) {
result = toGenerated(n) or
n = TImplicitSelf(result)
result = toGenerated(n)
or
not exists(toGenerated(n)) and
exists(AST::AstNode parent |
synthChild(parent, _, n) and
result = toGeneratedInclSynth(parent)
)
}
}
@@ -421,7 +548,7 @@ class TConditionalLoop = TWhileExpr or TUntilExpr or TWhileModifierExpr or TUnti
class TLoop = TConditionalLoop or TForExpr;
class TSelf = TExplicitSelf or TImplicitSelf;
class TSelf = TSelfReal or TSelfSynth;
class TExpr =
TSelf or TArgumentList or TRescueClause or TRescueModifierExpr or TPair or TStringConcatenation or
@@ -431,7 +558,7 @@ class TExpr =
class TStmtSequence =
TBeginBlock or TEndBlock or TThen or TElse or TDo or TEnsure or TStringInterpolationComponent or
TBlock or TBodyStmt or TParenthesizedExpr;
TBlock or TBodyStmt or TParenthesizedExpr or TStmtSequenceSynth;
class TBodyStmt = TBeginExpr or TModuleBase or TMethod or TLambda or TDoBlock or TSingletonMethod;
@@ -485,17 +612,45 @@ class TBinaryOperation =
class TBinaryArithmeticOperation =
TAddExpr or TSubExpr or TMulExpr or TDivExpr or TModuloExpr or TExponentExpr;
class TAddExpr = TAddExprReal or TAddExprSynth;
class TSubExpr = TSubExprReal or TSubExprSynth;
class TMulExpr = TMulExprReal or TMulExprSynth;
class TDivExpr = TDivExprReal or TDivExprSynth;
class TModuloExpr = TModuloExprReal or TModuloExprSynth;
class TExponentExpr = TExponentExprReal or TExponentExprSynth;
class TBinaryLogicalOperation = TLogicalAndExpr or TLogicalOrExpr;
class TLogicalAndExpr = TLogicalAndExprReal or TLogicalAndExprSynth;
class TLogicalOrExpr = TLogicalOrExprReal or TLogicalOrExprSynth;
class TBinaryBitwiseOperation =
TLShiftExpr or TRShiftExpr or TBitwiseAndExpr or TBitwiseOrExpr or TBitwiseXorExpr;
class TLShiftExpr = TLShiftExprReal or TLShiftExprSynth;
class TRShiftExpr = TRShiftExprReal or TRShiftExprSynth;
class TBitwiseAndExpr = TBitwiseAndExprReal or TBitwiseAndExprSynth;
class TBitwiseOrExpr = TBitwiseOrExprReal or TBitwiseOrExprSynth;
class TBitwiseXorExpr = TBitwiseXorExprReal or TBitwiseXorExprSynth;
class TComparisonOperation = TEqualityOperation or TRelationalOperation;
class TEqualityOperation = TEqExpr or TNEExpr or TCaseEqExpr;
class TRelationalOperation = TGTExpr or TGEExpr or TLTExpr or TLEExpr;
class TAssignExpr = TAssignExprReal or TAssignExprSynth;
class TAssignment = TAssignExpr or TAssignOperation;
class TAssignOperation =
@@ -531,3 +686,11 @@ class TTuplePattern = TTuplePatternParameter or TDestructuredLeftAssignment or T
class TVariableAccess =
TLocalVariableAccess or TGlobalVariableAccess or TInstanceVariableAccess or TClassVariableAccess;
class TLocalVariableAccess = TLocalVariableAccessReal or TLocalVariableAccessSynth;
class TGlobalVariableAccess = TGlobalVariableAccessReal or TGlobalVariableAccessSynth;
class TInstanceVariableAccess = TInstanceVariableAccessReal or TInstanceVariableAccessSynth;
class TClassVariableAccess = TClassVariableAccessReal or TClassVariableAccessSynth;

View File

@@ -67,7 +67,7 @@ private module Cached {
m = resolveScopeExpr(c.getReceiver())
or
m = enclosingModule(c).getModule() and
c.receiverIsSelf()
c.getReceiver() instanceof Self
) and
result = resolveScopeExpr(c.getAnArgument())
)
@@ -81,7 +81,7 @@ private module Cached {
m = resolveScopeExpr(c.getReceiver())
or
m = enclosingModule(c).getModule() and
c.receiverIsSelf()
c.getReceiver() instanceof Self
) and
result = resolveScopeExpr(c.getAnArgument())
)

View File

@@ -0,0 +1,173 @@
/** Provides predicates for synthesizing AST nodes. */
private import AST
private import TreeSitter
private import codeql_ruby.ast.internal.Parameter
private import codeql_ruby.ast.internal.Variable
private import codeql_ruby.AST
/** A synthesized AST node kind. */
newtype SynthKind =
AddExprKind() or
AssignExprKind() or
BitwiseAndExprKind() or
BitwiseOrExprKind() or
BitwiseXorExprKind() or
ClassVariableAccessKind(ClassVariable v) or
DivExprKind() or
ExponentExprKind() or
GlobalVariableAccessKind(GlobalVariable v) or
InstanceVariableAccessKind(InstanceVariable v) or
LShiftExprKind() or
LocalVariableAccessRealKind(LocalVariableReal v) or
LocalVariableAccessSynthKind(TLocalVariableSynth v) or
LogicalAndExprKind() or
LogicalOrExprKind() or
ModuloExprKind() or
MulExprKind() or
StmtSequenceKind() or
RShiftExprKind() or
SelfKind() or
SubExprKind()
/**
* An AST child.
*
* Either a new synthesized node or a reference to an existing node.
*/
newtype Child =
SynthChild(SynthKind k) or
RealChild(AstNode n)
private newtype TSynthesis = MkSynthesis()
/** A class used for synthesizing AST nodes. */
class Synthesis extends TSynthesis {
/**
* Holds if a node should be synthesized as the `i`th child of `parent`, or if
* a non-synthesized node should be the `i`th child of synthesized node `parent`.
*
* `i = -1` is used to represent that the synthesized node is a desugared version
* of its parent.
*/
predicate child(AstNode parent, int i, Child child) { none() }
/**
* Holds if a local variable, identified by `i`, should be synthesized for AST
* node `n`.
*/
predicate localVariable(AstNode n, int i) { none() }
/**
* Holds if `n` should be excluded from `ControlFlowTree` in the CFG construction.
*/
predicate excludeFromControlFlowTree(AstNode n) { none() }
final string toString() { none() }
}
private module ImplicitSelfSynthesis {
private class IdentifierMethodCallSelfSynthesis extends Synthesis {
final override predicate child(AstNode parent, int i, Child child) {
child = SynthChild(SelfKind()) and
parent = TIdentifierMethodCall(_) and
i = 0
}
}
private class RegularMethodCallSelfSynthesis extends Synthesis {
final override predicate child(AstNode parent, int i, Child child) {
child = SynthChild(SelfKind()) and
i = 0 and
exists(Generated::AstNode g |
parent = TRegularMethodCall(g) and
// If there's no explicit receiver (or scope resolution that acts like a
// receiver), then the receiver is implicitly `self`. N.B. `::Foo()` is
// not valid Ruby.
not exists(g.(Generated::Call).getReceiver()) and
not exists(g.(Generated::Call).getMethod().(Generated::ScopeResolution).getScope())
)
}
}
}
private module AssignOperationDesugar {
/**
* Gets the operator kind to synthesize for operator assignment `ao`.
*/
private SynthKind getKind(AssignOperation ao) {
ao instanceof AssignAddExpr and result = AddExprKind()
or
ao instanceof AssignSubExpr and result = SubExprKind()
or
ao instanceof AssignMulExpr and result = MulExprKind()
or
ao instanceof AssignDivExpr and result = DivExprKind()
or
ao instanceof AssignModuloExpr and result = ModuloExprKind()
or
ao instanceof AssignExponentExpr and result = ExponentExprKind()
or
ao instanceof AssignLogicalAndExpr and result = LogicalAndExprKind()
or
ao instanceof AssignLogicalOrExpr and result = LogicalOrExprKind()
or
ao instanceof AssignLShiftExpr and result = LShiftExprKind()
or
ao instanceof AssignRShiftExpr and result = RShiftExprKind()
or
ao instanceof AssignBitwiseAndExpr and result = BitwiseAndExprKind()
or
ao instanceof AssignBitwiseOrExpr and result = BitwiseOrExprKind()
or
ao instanceof AssignBitwiseXorExpr and result = BitwiseXorExprKind()
}
/**
* ```rb
* x += y
* ```
*
* desguars to
*
* ```rb
* x = x + y
* ```
*
* when `x` is a variable.
*/
private class VariableAssignOperationSynthesis extends Synthesis {
final override predicate child(AstNode parent, int i, Child child) {
exists(AssignOperation ao, VariableReal v |
v = ao.getLeftOperand().(VariableAccessReal).getVariableReal()
|
parent = ao and
i = -1 and
child = SynthChild(AssignExprKind())
or
exists(AstNode assign | assign = getSynthChild(ao, -1) |
parent = assign and
i = 0 and
child = RealChild(ao.getLeftOperand())
or
parent = assign and
i = 1 and
child = SynthChild(getKind(ao))
or
parent = getSynthChild(assign, 1) and
(
i = 0 and
child =
SynthChild([
LocalVariableAccessRealKind(v).(SynthKind), InstanceVariableAccessKind(v),
ClassVariableAccessKind(v), GlobalVariableAccessKind(v)
])
or
i = 1 and
child = RealChild(ao.getRightOperand())
)
)
)
}
}
}

View File

@@ -4,6 +4,7 @@ private import codeql_ruby.AST
private import codeql_ruby.ast.internal.AST
private import codeql_ruby.ast.internal.Parameter
private import codeql_ruby.ast.internal.Scope
private import codeql_ruby.ast.internal.Synthesis
/**
* Holds if `n` is in the left-hand-side of an explicit assignment `assignment`.
@@ -128,7 +129,7 @@ private module Cached {
other order by other.getLocation().getStartLine(), other.getLocation().getStartColumn()
)
} or
TLocalVariable(Scope::Range scope, string name, Generated::Identifier i) {
TLocalVariableReal(Scope::Range scope, string name, Generated::Identifier i) {
scopeDefinesParameterVariable(scope, name, i)
or
i =
@@ -139,7 +140,8 @@ private module Cached {
) and
not scopeDefinesParameterVariable(scope, name, _) and
not inherits(scope, name, _)
}
} or
TLocalVariableSynth(AstNode n, int i) { any(Synthesis s).localVariable(n, i) }
// Db types that can be vcalls
private class VcallToken =
@@ -288,7 +290,7 @@ private module Cached {
}
cached
predicate access(Generated::Identifier access, Variable::Range variable) {
predicate access(Generated::Identifier access, VariableReal::Range variable) {
exists(string name |
variable.getName() = name and
name = access.getValue()
@@ -372,8 +374,10 @@ private predicate inherits(Scope::Range scope, string name, Scope::Range outer)
)
}
module Variable {
class Range extends TVariable {
class TVariableReal = TGlobalVariable or TClassVariable or TInstanceVariable or TLocalVariableReal;
module VariableReal {
class Range extends TVariableReal {
abstract string getName();
string toString() { result = this.getName() }
@@ -384,13 +388,15 @@ module Variable {
}
}
class TLocalVariable = TLocalVariableReal or TLocalVariableSynth;
module LocalVariable {
class Range extends Variable::Range, TLocalVariable {
class Range extends VariableReal::Range, TLocalVariableReal {
private Scope::Range scope;
private string name;
private Generated::Identifier i;
Range() { this = TLocalVariable(scope, name, i) }
Range() { this = TLocalVariableReal(scope, name, i) }
final override string getName() { result = name }
@@ -402,8 +408,41 @@ module LocalVariable {
}
}
class VariableReal extends Variable, TVariableReal {
VariableReal::Range range;
VariableReal() { range = this }
final override string getName() { result = range.getName() }
final override Location getLocation() { result = range.getLocation() }
final override Scope getDeclaringScope() { toGenerated(result) = range.getDeclaringScope() }
}
class LocalVariableReal extends VariableReal, LocalVariable, TLocalVariableReal {
override LocalVariable::Range range;
final override LocalVariableAccessReal getAnAccess() { result.getVariable() = this }
final override VariableAccess getDefiningAccess() { result = range.getDefiningAccess() }
}
class LocalVariableSynth extends LocalVariable, TLocalVariableSynth {
private AstNode n;
private int i;
LocalVariableSynth() { this = TLocalVariableSynth(n, i) }
final override string getName() { result = "__synth__" + i }
final override Location getLocation() { result = n.getLocation() }
final override Scope getDeclaringScope() { none() } // not relevant for synthesized variables
}
module GlobalVariable {
class Range extends Variable::Range, TGlobalVariable {
class Range extends VariableReal::Range, TGlobalVariable {
private string name;
Range() { this = TGlobalVariable(name) }
@@ -417,7 +456,7 @@ module GlobalVariable {
}
module InstanceVariable {
class Range extends Variable::Range, TInstanceVariable {
class Range extends VariableReal::Range, TInstanceVariable {
private ModuleBase::Range scope;
private boolean instance;
private string name;
@@ -436,7 +475,7 @@ module InstanceVariable {
}
module ClassVariable {
class Range extends Variable::Range, TClassVariable {
class Range extends VariableReal::Range, TClassVariable {
private ModuleBase::Range scope;
private string name;
private Generated::AstNode decl;
@@ -464,16 +503,126 @@ module LocalVariableAccess {
}
}
class TVariableAccessReal =
TLocalVariableAccessReal or TGlobalVariableAccess or TInstanceVariableAccess or
TClassVariableAccess;
abstract class VariableAccessReal extends VariableAccess, TVariableAccessReal {
/**
* Same as `getVariable()`, but restricted to non-synthesized variable accesses.
*
* The sole purpose of this predicate is to make AST synthesis monotonic.
*/
abstract VariableReal getVariableReal();
}
private class LocalVariableAccessReal extends VariableAccessReal, LocalVariableAccess,
TLocalVariableAccessReal {
private Generated::Identifier g;
private LocalVariable v;
LocalVariableAccessReal() { this = TLocalVariableAccessReal(g, v) }
final override LocalVariable getVariable() { result = v }
final override LocalVariableReal getVariableReal() { result = v }
final override string toString() { result = g.getValue() }
}
private class LocalVariableAccessSynth extends LocalVariableAccess, TLocalVariableAccessSynth {
private LocalVariable v;
LocalVariableAccessSynth() { this = TLocalVariableAccessSynth(_, _, v) }
final override LocalVariable getVariable() { result = v }
final override string toString() { result = v.getName() }
}
module GlobalVariableAccess {
predicate range(Generated::GlobalVariable n, GlobalVariable v) { n.getValue() = v.getName() }
}
private class GlobalVariableAccessReal extends VariableAccessReal, GlobalVariableAccess,
TGlobalVariableAccessReal {
private Generated::GlobalVariable g;
private GlobalVariable v;
GlobalVariableAccessReal() { this = TGlobalVariableAccessReal(g, v) }
final override GlobalVariable getVariable() { result = v }
final override GlobalVariable getVariableReal() { result = v }
final override string toString() { result = g.getValue() }
}
private class GlobalVariableAccessSynth extends GlobalVariableAccess, TGlobalVariableAccessSynth {
private GlobalVariable v;
GlobalVariableAccessSynth() { this = TGlobalVariableAccessSynth(_, _, v) }
final override GlobalVariable getVariable() { result = v }
final override string toString() { result = v.getName() }
}
module InstanceVariableAccess {
predicate range(Generated::InstanceVariable n, InstanceVariable v) {
instanceVariableAccess(n, v)
}
}
private class InstanceVariableAccessReal extends VariableAccessReal, InstanceVariableAccess,
TInstanceVariableAccessReal {
private Generated::InstanceVariable g;
private InstanceVariable v;
InstanceVariableAccessReal() { this = TInstanceVariableAccessReal(g, v) }
final override InstanceVariable getVariable() { result = v }
final override InstanceVariable getVariableReal() { result = v }
final override string toString() { result = g.getValue() }
}
private class InstanceVariableAccessSynth extends InstanceVariableAccess,
TInstanceVariableAccessSynth {
private InstanceVariable v;
InstanceVariableAccessSynth() { this = TInstanceVariableAccessSynth(_, _, v) }
final override InstanceVariable getVariable() { result = v }
final override string toString() { result = v.getName() }
}
module ClassVariableAccess {
predicate range(Generated::ClassVariable n, ClassVariable v) { classVariableAccess(n, v) }
}
private class ClassVariableAccessReal extends VariableAccessReal, ClassVariableAccess,
TClassVariableAccessReal {
private Generated::ClassVariable g;
private ClassVariable v;
ClassVariableAccessReal() { this = TClassVariableAccessReal(g, v) }
final override ClassVariable getVariable() { result = v }
final override ClassVariable getVariableReal() { result = v }
final override string toString() { result = g.getValue() }
}
private class ClassVariableAccessSynth extends ClassVariableAccess, TClassVariableAccessSynth {
private ClassVariable v;
ClassVariableAccessSynth() { this = TClassVariableAccessSynth(_, _, v) }
final override ClassVariable getVariable() { result = v }
final override string toString() { result = v.getName() }
}

View File

@@ -159,6 +159,13 @@ abstract private class ExprChildMapping extends Expr {
)
}
private Expr desugar(Expr n) {
result = n.getDesugared()
or
not exists(n.getDesugared()) and
result = n
}
/**
* Holds if there is a control-flow path from `cfn` to `cfnChild`, where `cfn`
* is a control-flow node for this expression, and `cfnChild` is a control-flow
@@ -171,13 +178,13 @@ abstract private class ExprChildMapping extends Expr {
exists(BasicBlock bb |
this.reachesBasicBlockBase(child, cfn, bb) and
cfnChild = bb.getANode() and
cfnChild = child.getAControlFlowNode()
cfnChild = desugar(child).getAControlFlowNode()
)
or
exists(BasicBlock bb |
this.reachesBasicBlockRec(child, cfn, bb) and
cfnChild = bb.getANode() and
cfnChild = child.getAControlFlowNode()
cfnChild = desugar(child).getAControlFlowNode()
)
}
}
@@ -247,6 +254,11 @@ module ExprNodes {
override predicate relevantChild(Expr e) { e = this.getValue() or e = this.getBranch(_) }
}
/** A control-flow node that wraps a `MethodCall` AST expression. */
class MethodCallCfgNode extends CallCfgNode {
MethodCallCfgNode() { this.getExpr() instanceof MethodCall }
}
/** A control-flow node that wraps a `CaseExpr` AST expression. */
class CaseExprCfgNode extends ExprCfgNode {
override CaseExprChildMapping e;

View File

@@ -1,28 +0,0 @@
/**
* @kind graph
* @id rb/test/cfg
*/
import codeql_ruby.CFG
query predicate nodes(CfgNode n, string attr, string val) {
attr = "semmle.order" and
val =
any(int i |
n =
rank[i](CfgNode p |
|
p
order by
p.getLocation().getFile().getBaseName(), p.getLocation().getFile().getAbsolutePath(),
p.getLocation().getStartLine(), p.getLocation().getStartColumn()
)
).toString()
}
query predicate edges(CfgNode pred, CfgNode succ, string attr, string val) {
exists(SuccessorType t | succ = pred.getASuccessor(t) |
attr = "semmle.label" and
if t instanceof SuccessorTypes::NormalSuccessor then val = "" else val = t.toString()
)
}

View File

@@ -0,0 +1,32 @@
/**
* Import this module into a `.ql` file of `@kind graph` to render a CFG. The
* graph is restricted to nodes from `RelevantCfgNode`.
*/
private import codeql.Locations
import codeql_ruby.CFG
abstract class RelevantCfgNode extends CfgNode { }
query predicate nodes(RelevantCfgNode n, string attr, string val) {
attr = "semmle.order" and
val =
any(int i |
n =
rank[i](RelevantCfgNode p, Location l |
l = p.getLocation()
|
p
order by
l.getFile().getBaseName(), l.getFile().getAbsolutePath(), l.getStartLine(),
l.getStartColumn()
)
).toString()
}
query predicate edges(RelevantCfgNode pred, RelevantCfgNode succ, string attr, string val) {
exists(SuccessorType t | succ = pred.getASuccessor(t) |
attr = "semmle.label" and
if t instanceof SuccessorTypes::NormalSuccessor then val = "" else val = t.toString()
)
}

View File

@@ -35,6 +35,7 @@ private import codeql_ruby.AST
private import codeql_ruby.ast.internal.AST as ASTInternal
private import codeql_ruby.ast.internal.Scope
private import codeql_ruby.ast.Scope
private import codeql_ruby.ast.internal.Synthesis
private import codeql_ruby.ast.internal.TreeSitter
private import codeql_ruby.ast.internal.Variable
private import codeql_ruby.controlflow.ControlFlowGraph
@@ -85,6 +86,8 @@ module CfgScope {
}
abstract private class ControlFlowTree extends AstNode {
ControlFlowTree() { not any(Synthesis s).excludeFromControlFlowTree(this) }
/**
* Holds if `first` is the first element executed within this AST node.
*/
@@ -284,6 +287,8 @@ module Trees {
}
private class AssignOperationTree extends StandardPostOrderTree, AssignOperation {
AssignOperationTree() { not this.getLeftOperand() instanceof VariableAccess }
final override ControlFlowTree getChildNode(int i) {
result = this.getLeftOperand() and i = 0
or
@@ -725,6 +730,22 @@ module Trees {
}
}
private class DesugaredTree extends ControlFlowTree {
ControlFlowTree desugared;
DesugaredTree() { desugared = this.getDesugared() }
final override predicate propagatesAbnormal(AstNode child) {
desugared.propagatesAbnormal(child)
}
final override predicate first(AstNode first) { desugared.first(first) }
final override predicate last(AstNode last, Completion c) { desugared.last(last, c) }
final override predicate succ(AstNode pred, AstNode succ, Completion c) { none() }
}
private class DoBlockTree extends BodyStmtTree, DoBlock {
/** Gets the `i`th child in the body of this block. */
final override AstNode getBodyChild(int i, boolean rescuable) {

View File

@@ -40,6 +40,12 @@ class DataFlowCallable = CfgScope;
class DataFlowCall extends CfgNodes::ExprNodes::CallCfgNode {
DataFlowCallable getEnclosingCallable() { result = this.getScope() }
DataFlowCallable getTarget() {
// TODO: this is a placeholder that finds a method with the same name, iff it's uniquely named.
result =
unique(DataFlowCallable c | c.(Method).getName() = this.getNode().(MethodCall).getMethodName())
}
}
/** Gets a viable run-time target for the call `call`. */

View File

@@ -2133,11 +2133,8 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
exists(Cc cc0 |
cc = pragma[only_bind_into](cc0) and
localFlowEntry(node, config) and
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
)
localFlowEntry(node, config) and
result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
}
private predicate localStep(
@@ -3132,7 +3129,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
sc = mid.getSummaryCtx() and
localCC = getLocalCallContext(cc, getNodeEnclosingCallable(midnode)) and
localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, _, conf, localCC) and

View File

@@ -2,6 +2,7 @@ private import ruby
private import DataFlowDispatch
private import DataFlowPrivate
private import codeql_ruby.CFG
private import codeql_ruby.typetracking.TypeTracker
/**
* An element, viewed as a node in a data flow graph. Either an expression
@@ -73,6 +74,37 @@ class ParameterNode extends Node, TParameterNode {
predicate isParameterOf(Callable c, int i) { p = c.getParameter(i) }
}
/**
* A data-flow node that is a source of local flow.
*/
class LocalSourceNode extends Node {
LocalSourceNode() { not simpleLocalFlowStep+(any(ExprNode n), this) }
/** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */
pragma[inline]
predicate flowsTo(Node nodeTo) { hasLocalSource(nodeTo, this) }
/**
* Gets a node that this node may flow to using one heap and/or interprocedural step.
*
* See `TypeTracker` for more details about how to use this.
*/
pragma[inline]
LocalSourceNode track(TypeTracker t2, TypeTracker t) { t = t2.step(this, result) }
}
predicate hasLocalSource(Node sink, Node source) {
// Declaring `source` to be a `SourceNode` currently causes a redundant check in the
// recursive case, so instead we check it explicitly here.
source = sink and
source instanceof LocalSourceNode
or
exists(Node mid |
hasLocalSource(mid, source) and
simpleLocalFlowStep(mid, sink)
)
}
/** Gets a node corresponding to expression `e`. */
ExprNode exprNode(CfgNodes::ExprCfgNode e) { result.getExprNode() = e }

View File

@@ -1,5 +1,5 @@
/**
* Provides a language-independant implementation of static single assignment
* Provides a language-independent implementation of static single assignment
* (SSA) form.
*/
@@ -316,15 +316,23 @@ private module SsaDefReaches {
)
}
/**
* Holds if the reference to `def` at index `i` in basic block `bb` is the
* last reference to `v` inside `bb`.
*/
pragma[noinline]
predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) {
ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v)
}
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v) {
exists(ssaDefRank(def, v, bb, _, _))
}
pragma[noinline]
private BasicBlock getAMaybeLiveSuccessor(Definition def, BasicBlock bb) {
result = getABasicBlockSuccessor(bb) and
not defOccursInBlock(_, bb, def.getSourceVariable()) and
ssaDefReachesEndOfBlock(bb, def, _)
private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) {
ssaDefReachesEndOfBlock(bb, def, _) and
not defOccursInBlock(_, bb, def.getSourceVariable())
}
/**
@@ -337,7 +345,11 @@ private module SsaDefReaches {
defOccursInBlock(def, bb1, _) and
bb2 = getABasicBlockSuccessor(bb1)
or
exists(BasicBlock mid | varBlockReaches(def, bb1, mid) | bb2 = getAMaybeLiveSuccessor(def, mid))
exists(BasicBlock mid |
varBlockReaches(def, bb1, mid) and
ssaDefReachesThroughBlock(def, mid) and
bb2 = getABasicBlockSuccessor(mid)
)
}
/**
@@ -348,24 +360,16 @@ private module SsaDefReaches {
*/
predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) {
varBlockReaches(def, bb1, bb2) and
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1 and
variableRead(bb2, i2, _, _)
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1
}
}
private import SsaDefReaches
pragma[noinline]
private predicate ssaDefReachesEndOfBlockRec(BasicBlock bb, Definition def, SourceVariable v) {
exists(BasicBlock idom | ssaDefReachesEndOfBlock(idom, def, v) |
// The construction of SSA form ensures that each read of a variable is
// dominated by its definition. An SSA definition therefore reaches a
// control flow node if it is the _closest_ SSA definition that dominates
// the node. If two definitions dominate a node then one must dominate the
// other, so therefore the definition of _closest_ is given by the dominator
// tree. Thus, reaching definitions can be calculated in terms of dominance.
idom = getImmediateBasicBlockDominator(bb)
)
pragma[nomagic]
predicate liveThrough(BasicBlock bb, SourceVariable v) {
liveAtExit(bb, v) and
not ssaRef(bb, _, v, SsaDef())
}
/**
@@ -382,9 +386,14 @@ predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable
liveAtExit(bb, v)
)
or
ssaDefReachesEndOfBlockRec(bb, def, v) and
liveAtExit(bb, v) and
not ssaRef(bb, _, v, SsaDef())
// The construction of SSA form ensures that each read of a variable is
// dominated by its definition. An SSA definition therefore reaches a
// control flow node if it is the _closest_ SSA definition that dominates
// the node. If two definitions dominate a node then one must dominate the
// other, so therefore the definition of _closest_ is given by the dominator
// tree. Thus, reaching definitions can be calculated in terms of dominance.
ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and
liveThrough(bb, pragma[only_bind_into](v))
}
/**
@@ -433,15 +442,22 @@ predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2
bb2 = bb1
)
or
exists(SourceVariable v | ssaDefRank(def, v, bb1, i1, _) = maxSsaRefRank(bb1, v)) and
lastSsaRef(def, _, bb1, i1) and
defAdjacentRead(def, bb1, bb2, i2)
}
pragma[noinline]
private predicate adjacentDefRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v
) {
adjacentDefRead(def, bb1, i1, bb2, i2) and
v = def.getSourceVariable()
}
private predicate adjacentDefReachesRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
) {
adjacentDefRead(def, bb1, i1, bb2, i2) and
exists(SourceVariable v | v = def.getSourceVariable() |
exists(SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) |
ssaRef(bb1, i1, v, SsaDef())
or
variableRead(bb1, i1, v, true)
@@ -474,17 +490,19 @@ predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, Ba
*/
pragma[nomagic]
predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) {
exists(int rnk, SourceVariable v, int j | rnk = ssaDefRank(def, v, bb, i, _) |
exists(SourceVariable v |
// Next reference to `v` inside `bb` is a write
next.definesAt(v, bb, j) and
rnk + 1 = ssaRefRank(bb, j, v, SsaDef())
exists(int rnk, int j |
rnk = ssaDefRank(def, v, bb, i, _) and
next.definesAt(v, bb, j) and
rnk + 1 = ssaRefRank(bb, j, v, SsaDef())
)
or
// Can reach a write using one or more steps
rnk = maxSsaRefRank(bb, v) and
lastSsaRef(def, v, bb, i) and
exists(BasicBlock bb2 |
varBlockReaches(def, bb, bb2) and
next.definesAt(v, bb2, j) and
1 = ssaRefRank(bb2, j, v, SsaDef())
1 = ssaDefRank(next, v, bb2, _, SsaDef())
)
)
}
@@ -538,7 +556,8 @@ pragma[nomagic]
predicate lastRef(Definition def, BasicBlock bb, int i) {
lastRefRedef(def, bb, i, _)
or
exists(SourceVariable v | ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v) |
lastSsaRef(def, _, bb, i) and
(
// Can reach exit directly
bb instanceof ExitBasicBlock
or

View File

@@ -8,6 +8,13 @@
import AST
/** Holds if `n` appears in the desugaring of some other node. */
predicate isDesugared(AstNode n) {
n = any(AstNode sugar).getDesugared()
or
isDesugared(n.getParent())
}
/**
* The query can extend this class to control which nodes are printed.
*/
@@ -17,7 +24,19 @@ class PrintAstConfiguration extends string {
/**
* Holds if the given node should be printed.
*/
predicate shouldPrintNode(AstNode n) { any() }
predicate shouldPrintNode(AstNode n) {
not isDesugared(n)
or
not n.isSynthesized()
or
n.isSynthesized() and
not n = any(AstNode sugar).getDesugared() and
exists(AstNode parent |
parent = n.getParent() and
not parent.isSynthesized() and
not n = parent.getDesugared()
)
}
}
/**
@@ -32,12 +51,11 @@ class PrintAstNode extends AstNode {
result =
any(int i |
this =
rank[i](AstNode p |
|
p
order by
p.getLocation().getFile().getBaseName(), p.getLocation().getFile().getAbsolutePath(),
p.getLocation().getStartLine(), p.getLocation().getStartColumn()
rank[i](AstNode p, Location l, File f |
l = p.getLocation() and
f = l.getFile()
|
p order by f.getBaseName(), f.getAbsolutePath(), l.getStartLine(), l.getStartColumn()
)
).toString()
}
@@ -75,10 +93,10 @@ query predicate nodes(PrintAstNode node, string key, string value) {
query predicate edges(PrintAstNode source, PrintAstNode target, string key, string value) {
source.shouldPrint() and
target.shouldPrint() and
target = source.getAChild() and
target = source.getChild(_) and
(
key = "semmle.label" and
value = concat(string name | source.getChild(name) = target | name, "/")
value = strictconcat(string name | source.getChild(name) = target | name, "/")
or
key = "semmle.order" and
value = target.getProperty("semmle.order")

View File

@@ -0,0 +1,420 @@
/** Step Summaries and Type Tracking */
private import TypeTrackerSpecific
/**
* Any string that may appear as the name of a piece of content. This will usually include things like:
* - Attribute names (in Python)
* - Property names (in JavaScript)
*
* In general, this can also be used to model things like stores to specific list indices. To ensure
* correctness, it is important that
*
* - different types of content do not have overlapping names, and
* - the empty string `""` is not a valid piece of content, as it is used to indicate the absence of
* content instead.
*/
class ContentName extends string {
ContentName() { this = getPossibleContentName() }
}
/** Either a content name, or the empty string (representing no content). */
class OptionalContentName extends string {
OptionalContentName() { this instanceof ContentName or this = "" }
}
/**
* A description of a step on an inter-procedural data flow path.
*/
private newtype TStepSummary =
LevelStep() or
CallStep() or
ReturnStep() or
StoreStep(ContentName content) or
LoadStep(ContentName content)
/**
* INTERNAL: Use `TypeTracker` or `TypeBackTracker` instead.
*
* A description of a step on an inter-procedural data flow path.
*/
class StepSummary extends TStepSummary {
/** Gets a textual representation of this step summary. */
string toString() {
this instanceof LevelStep and result = "level"
or
this instanceof CallStep and result = "call"
or
this instanceof ReturnStep and result = "return"
or
exists(string content | this = StoreStep(content) | result = "store " + content)
or
exists(string content | this = LoadStep(content) | result = "load " + content)
}
}
/** Provides predicates for updating step summaries (`StepSummary`s). */
module StepSummary {
/**
* Gets the summary that corresponds to having taken a forwards
* heap and/or inter-procedural step from `nodeFrom` to `nodeTo`.
*/
cached
predicate step(LocalSourceNode nodeFrom, LocalSourceNode nodeTo, StepSummary summary) {
exists(Node mid | nodeFrom.flowsTo(mid) and smallstep(mid, nodeTo, summary))
}
/**
* Gets the summary that corresponds to having taken a forwards
* local, heap and/or inter-procedural step from `nodeFrom` to `nodeTo`.
*
* Unlike `StepSummary::step`, this predicate does not compress
* type-preserving steps.
*/
predicate smallstep(Node nodeFrom, LocalSourceNode nodeTo, StepSummary summary) {
jumpStep(nodeFrom, nodeTo) and
summary = LevelStep()
or
callStep(nodeFrom, nodeTo) and summary = CallStep()
or
returnStep(nodeFrom, nodeTo) and
summary = ReturnStep()
or
exists(string content |
localSourceStoreStep(nodeFrom, nodeTo, content) and
summary = StoreStep(content)
or
basicLoadStep(nodeFrom, nodeTo, content) and summary = LoadStep(content)
)
}
/**
* Holds if `nodeFrom` is being written to the `content` content of the object in `nodeTo`.
*
* Note that `nodeTo` will always be a local source node that flows to the place where the content
* is written in `basicStoreStep`. This may lead to the flow of information going "back in time"
* from the point of view of the execution of the program.
*
* For instance, if we interpret attribute writes in Python as writing to content with the same
* name as the attribute and consider the following snippet
*
* ```python
* def foo(y):
* x = Foo()
* bar(x)
* x.attr = y
* baz(x)
*
* def bar(x):
* z = x.attr
* ```
* for the attribute write `x.attr = y`, we will have `content` being the literal string `"attr"`,
* `nodeFrom` will be `y`, and `nodeTo` will be the object `Foo()` created on the first line of the
* function. This means we will track the fact that `x.attr` can have the type of `y` into the
* assignment to `z` inside `bar`, even though this attribute write happens _after_ `bar` is called.
*/
predicate localSourceStoreStep(Node nodeFrom, LocalSourceNode nodeTo, string content) {
exists(Node obj | nodeTo.flowsTo(obj) and basicStoreStep(nodeFrom, obj, content))
}
}
private newtype TTypeTracker = MkTypeTracker(Boolean hasCall, OptionalContentName content)
/**
* Summary of the steps needed to track a value to a given dataflow node.
*
* This can be used to track objects that implement a certain API in order to
* recognize calls to that API. Note that type-tracking does not by itself provide a
* source/sink relation, that is, it may determine that a node has a given type,
* but it won't determine where that type came from.
*
* It is recommended that all uses of this type are written in the following form,
* for tracking some type `myType`:
* ```ql
* DataFlow::LocalSourceNode myType(DataFlow::TypeTracker t) {
* t.start() and
* result = < source of myType >
* or
* exists (DataFlow::TypeTracker t2 |
* result = myType(t2).track(t2, t)
* )
* }
*
* DataFlow::Node myType() { myType(DataFlow::TypeTracker::end()).flowsTo(result) }
* ```
*
* Instead of `result = myType(t2).track(t2, t)`, you can also use the equivalent
* `t = t2.step(myType(t2), result)`. If you additionally want to track individual
* intra-procedural steps, use `t = t2.smallstep(myCallback(t2), result)`.
*/
class TypeTracker extends TTypeTracker {
Boolean hasCall;
OptionalContentName content;
TypeTracker() { this = MkTypeTracker(hasCall, content) }
/** Gets the summary resulting from appending `step` to this type-tracking summary. */
cached
TypeTracker append(StepSummary step) {
step = LevelStep() and result = this
or
step = CallStep() and result = MkTypeTracker(true, content)
or
step = ReturnStep() and hasCall = false and result = this
or
step = LoadStep(content) and result = MkTypeTracker(hasCall, "")
or
exists(string p | step = StoreStep(p) and content = "" and result = MkTypeTracker(hasCall, p))
}
/** Gets a textual representation of this summary. */
string toString() {
exists(string withCall, string withContent |
(if hasCall = true then withCall = "with" else withCall = "without") and
(if content != "" then withContent = " with content " + content else withContent = "") and
result = "type tracker " + withCall + " call steps" + withContent
)
}
/**
* Holds if this is the starting point of type tracking.
*/
predicate start() { hasCall = false and content = "" }
/**
* Holds if this is the starting point of type tracking, and the value starts in the content named `contentName`.
* The type tracking only ends after the content has been loaded.
*/
predicate startInContent(ContentName contentName) { hasCall = false and content = contentName }
/**
* Holds if this is the starting point of type tracking
* when tracking a parameter into a call, but not out of it.
*/
predicate call() { hasCall = true and content = "" }
/**
* Holds if this is the end point of type tracking.
*/
predicate end() { content = "" }
/**
* INTERNAL. DO NOT USE.
*
* Holds if this type has been tracked into a call.
*/
boolean hasCall() { result = hasCall }
/**
* INTERNAL. DO NOT USE.
*
* Gets the content associated with this type tracker.
*/
string getContent() { result = content }
/**
* Gets a type tracker that starts where this one has left off to allow continued
* tracking.
*
* This predicate is only defined if the type is not associated to a piece of content.
*/
TypeTracker continue() { content = "" and result = this }
/**
* Gets the summary that corresponds to having taken a forwards
* heap and/or inter-procedural step from `nodeFrom` to `nodeTo`.
*/
pragma[inline]
TypeTracker step(LocalSourceNode nodeFrom, LocalSourceNode nodeTo) {
exists(StepSummary summary |
StepSummary::step(nodeFrom, pragma[only_bind_out](nodeTo), pragma[only_bind_into](summary)) and
result = this.append(pragma[only_bind_into](summary))
)
}
/**
* Gets the summary that corresponds to having taken a forwards
* local, heap and/or inter-procedural step from `nodeFrom` to `nodeTo`.
*
* Unlike `TypeTracker::step`, this predicate exposes all edges
* in the flow graph, and not just the edges between `Node`s.
* It may therefore be less performant.
*
* Type tracking predicates using small steps typically take the following form:
* ```ql
* DataFlow::Node myType(DataFlow::TypeTracker t) {
* t.start() and
* result = < source of myType >
* or
* exists (DataFlow::TypeTracker t2 |
* t = t2.smallstep(myType(t2), result)
* )
* }
*
* DataFlow::Node myType() {
* result = myType(DataFlow::TypeTracker::end())
* }
* ```
*/
pragma[inline]
TypeTracker smallstep(Node nodeFrom, Node nodeTo) {
exists(StepSummary summary |
StepSummary::smallstep(nodeFrom, nodeTo, summary) and
result = this.append(summary)
)
or
simpleLocalFlowStep(nodeFrom, nodeTo) and
result = this
}
}
/** Provides predicates for implementing custom `TypeTracker`s. */
module TypeTracker {
/**
* Gets a valid end point of type tracking.
*/
TypeTracker end() { result.end() }
}
private newtype TTypeBackTracker = MkTypeBackTracker(Boolean hasReturn, OptionalContentName content)
/**
* Summary of the steps needed to back-track a use of a value to a given dataflow node.
*
* This can for example be used to track callbacks that are passed to a certain API,
* so we can model specific parameters of that callback as having a certain type.
*
* Note that type back-tracking does not provide a source/sink relation, that is,
* it may determine that a node will be used in an API call somewhere, but it won't
* determine exactly where that use was, or the path that led to the use.
*
* It is recommended that all uses of this type are written in the following form,
* for back-tracking some callback type `myCallback`:
*
* ```ql
* DataFlow::LocalSourceNode myCallback(DataFlow::TypeBackTracker t) {
* t.start() and
* result = (< some API call >).getArgument(< n >).getALocalSource()
* or
* exists (DataFlow::TypeBackTracker t2 |
* result = myCallback(t2).backtrack(t2, t)
* )
* }
*
* DataFlow::LocalSourceNode myCallback() { result = myCallback(DataFlow::TypeBackTracker::end()) }
* ```
*
* Instead of `result = myCallback(t2).backtrack(t2, t)`, you can also use the equivalent
* `t2 = t.step(result, myCallback(t2))`. If you additionally want to track individual
* intra-procedural steps, use `t2 = t.smallstep(result, myCallback(t2))`.
*/
class TypeBackTracker extends TTypeBackTracker {
Boolean hasReturn;
string content;
TypeBackTracker() { this = MkTypeBackTracker(hasReturn, content) }
/** Gets the summary resulting from prepending `step` to this type-tracking summary. */
TypeBackTracker prepend(StepSummary step) {
step = LevelStep() and result = this
or
step = CallStep() and hasReturn = false and result = this
or
step = ReturnStep() and result = MkTypeBackTracker(true, content)
or
exists(string p |
step = LoadStep(p) and content = "" and result = MkTypeBackTracker(hasReturn, p)
)
or
step = StoreStep(content) and result = MkTypeBackTracker(hasReturn, "")
}
/** Gets a textual representation of this summary. */
string toString() {
exists(string withReturn, string withContent |
(if hasReturn = true then withReturn = "with" else withReturn = "without") and
(if content != "" then withContent = " with content " + content else withContent = "") and
result = "type back-tracker " + withReturn + " return steps" + withContent
)
}
/**
* Holds if this is the starting point of type tracking.
*/
predicate start() { hasReturn = false and content = "" }
/**
* Holds if this is the end point of type tracking.
*/
predicate end() { content = "" }
/**
* INTERNAL. DO NOT USE.
*
* Holds if this type has been back-tracked into a call through return edge.
*/
boolean hasReturn() { result = hasReturn }
/**
* Gets a type tracker that starts where this one has left off to allow continued
* tracking.
*
* This predicate is only defined if the type has not been tracked into a piece of content.
*/
TypeBackTracker continue() { content = "" and result = this }
/**
* Gets the summary that corresponds to having taken a backwards
* heap and/or inter-procedural step from `nodeTo` to `nodeFrom`.
*/
pragma[inline]
TypeBackTracker step(LocalSourceNode nodeFrom, LocalSourceNode nodeTo) {
exists(StepSummary summary |
StepSummary::step(pragma[only_bind_out](nodeFrom), nodeTo, pragma[only_bind_into](summary)) and
this = result.prepend(pragma[only_bind_into](summary))
)
}
/**
* Gets the summary that corresponds to having taken a backwards
* local, heap and/or inter-procedural step from `nodeTo` to `nodeFrom`.
*
* Unlike `TypeBackTracker::step`, this predicate exposes all edges
* in the flowgraph, and not just the edges between
* `LocalSourceNode`s. It may therefore be less performant.
*
* Type tracking predicates using small steps typically take the following form:
* ```ql
* DataFlow::Node myType(DataFlow::TypeBackTracker t) {
* t.start() and
* result = < some API call >.getArgument(< n >)
* or
* exists (DataFlow::TypeBackTracker t2 |
* t = t2.smallstep(result, myType(t2))
* )
* }
*
* DataFlow::Node myType() {
* result = myType(DataFlow::TypeBackTracker::end())
* }
* ```
*/
pragma[inline]
TypeBackTracker smallstep(Node nodeFrom, Node nodeTo) {
exists(StepSummary summary |
StepSummary::smallstep(nodeFrom, nodeTo, summary) and
this = result.prepend(summary)
)
or
simpleLocalFlowStep(nodeFrom, nodeTo) and
this = result
}
}
/** Provides predicates for implementing custom `TypeBackTracker`s. */
module TypeBackTracker {
/**
* Gets a valid end point of type back-tracking.
*/
TypeBackTracker end() { result.end() }
}

View File

@@ -0,0 +1,118 @@
private import codeql_ruby.AST as AST
private import codeql_ruby.dataflow.internal.DataFlowPublic as DataFlowPublic
private import codeql_ruby.dataflow.internal.DataFlowPrivate as DataFlowPrivate
private import codeql_ruby.dataflow.internal.DataFlowDispatch as DataFlowDispatch
private import codeql_ruby.controlflow.CfgNodes
class Node = DataFlowPublic::Node;
class LocalSourceNode = DataFlowPublic::LocalSourceNode;
predicate simpleLocalFlowStep = DataFlowPrivate::simpleLocalFlowStep/2;
predicate jumpStep = DataFlowPrivate::jumpStep/2;
/**
* Gets the name of a possible piece of content. This will usually include things like
*
* - Attribute names (in Python)
* - Property names (in JavaScript)
*/
string getPossibleContentName() { result = getSetterCallAttributeName(_) }
/** Holds if `nodeFrom` steps to `nodeTo` by being passed as a parameter in a call. */
predicate callStep(
DataFlowPrivate::ArgumentNode nodeFrom, DataFlowPrivate::ExplicitParameterNode nodeTo
) {
exists(DataFlowDispatch::DataFlowCall call, DataFlowDispatch::DataFlowCallable callable, int i |
call.getTarget() = callable and
nodeFrom.argumentOf(call, i) and
nodeTo.isParameterOf(callable, i)
)
}
/** Holds if `nodeFrom` steps to `nodeTo` by being returned from a call. */
predicate returnStep(DataFlowPrivate::ReturnNode nodeFrom, Node nodeTo) {
exists(DataFlowDispatch::DataFlowCall call |
nodeFrom.getEnclosingCallable() = call.getTarget() and
nodeTo.asExpr().getNode() = call.getNode()
)
}
/**
* Holds if `nodeFrom` is being written to the `content` content of the object
* in `nodeTo`.
*
* Note that the choice of `nodeTo` does not have to make sense
* "chronologically". All we care about is whether the `content` content of
* `nodeTo` can have a specific type, and the assumption is that if a specific
* type appears here, then any access of that particular content can yield
* something of that particular type.
*
* Thus, in an example such as
*
* ```rb
* def foo(y)
* x = Foo.new
* bar(x)
* x.content = y
* baz(x)
* end
*
* def bar(x)
* z = x.content
* end
* ```
* for the content write `x.content = y`, we will have `content` being the
* literal string `"content"`, `nodeFrom` will be `y`, and `nodeTo` will be the
* `Foo` object created on the first line of the function. This means we will
* track the fact that `x.content` can have the type of `y` into the assignment
* to `z` inside `bar`, even though this content write happens _after_ `bar` is
* called.
*/
predicate basicStoreStep(Node nodeFrom, LocalSourceNode nodeTo, string content) {
// TODO: support SetterMethodCall inside TuplePattern
exists(ExprNodes::AssignmentCfgNode assignment, ExprNodes::MethodCallCfgNode call |
assignment.getLhs() = call and
content = getSetterCallAttributeName(call.getExpr()) and
nodeTo.(DataFlowPublic::ExprNode).getExprNode() = call.getReceiver() and
call.getExpr() instanceof AST::SetterMethodCall and
assignment.getRhs() = nodeFrom.(DataFlowPublic::ExprNode).getExprNode()
)
}
/**
* Returns the name of the attribute being set by the setter method call, i.e.
* the name of the setter method without the trailing `=`. In the following
* example, the result is `"bar"`.
*
* ```rb
* foo.bar = 1
* ```
*/
private string getSetterCallAttributeName(AST::SetterMethodCall call) {
// TODO: this should be exposed in `SetterMethodCall`
not call instanceof AST::ElementReference and
exists(string setterName |
setterName = call.getMethodName() and result = setterName.prefix(setterName.length() - 1)
)
}
/**
* Holds if `nodeTo` is the result of accessing the `content` content of `nodeFrom`.
*/
predicate basicLoadStep(Node nodeFrom, Node nodeTo, string content) {
exists(ExprNodes::MethodCallCfgNode call |
call.getExpr().getNumberOfArguments() = 0 and
content = call.getExpr().(AST::MethodCall).getMethodName() and
nodeFrom.asExpr() = call.getReceiver() and
nodeTo.asExpr() = call
)
}
/**
* A utility class that is equivalent to `boolean` but does not require type joining.
*/
class Boolean extends boolean {
Boolean() { this = true or this = false }
}

View File

@@ -0,0 +1,18 @@
/**
* @name Extraction errors
* @description List all extraction errors for files in the source code directory.
* @kind diagnostic
* @id rb/diagnostics/extraction-errors
*/
import ruby
import codeql_ruby.Diagnostics
/** Gets the SARIF severity to associate an error. */
int getSeverity() { result = 2 }
from ExtractionError error, File f
where
f = error.getLocation().getFile() and
exists(f.getRelativePath())
select error, "Extraction failed in " + f + " with error " + error.getMessage(), getSeverity()

View File

@@ -0,0 +1,16 @@
/**
* @name Successfully extracted files
* @description Lists all files in the source code directory that were extracted
* without encountering an error in the file.
* @kind diagnostic
* @id rb/diagnostics/successfully-extracted-files
*/
import ruby
import codeql_ruby.Diagnostics
from File f
where
not exists(ExtractionError e | e.getLocation().getFile() = f) and
exists(f.getRelativePath())
select f, ""

View File

@@ -0,0 +1,26 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<p>
When creating a file, POSIX systems allow permissions to be specified
for owner, group and others separately. Permissions should be kept as
strict as possible, preventing access to the files contents by other users.
</p>
</overview>
<recommendation>
<p>
Restrict the file permissions of files to prevent any but the owner being able to read or write to that file
</p>
</recommendation>
<references>
<li>
Wikipedia:
<a href="https://en.wikipedia.org/wiki/File_system_permissions">File system permissions</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,99 @@
/**
* @name Overly permissive file permissions
* @description Allowing files to be readable or writable by users other than the owner may allow sensitive information to be accessed.
* @kind path-problem
* @problem.severity warning
* @id rb/overly-permissive-file
* @tags external/cwe/cwe-732
* security
* @precision low
*/
import ruby
import codeql_ruby.DataFlow
import DataFlow::PathGraph
private import codeql_ruby.dataflow.SSA
// TODO: account for flows through tuple assignments
/** An expression referencing the File or FileUtils module */
class FileModuleAccess extends Expr {
FileModuleAccess() {
this.(ConstantAccess).getName() = "File"
or
this.(ConstantAccess).getName() = "FileUtils"
or
exists(FileModuleAccess fma, Ssa::WriteDefinition def |
def.getARead() = this.getAControlFlowNode() and
def.getWriteAccess().getParent().(Assignment).getRightOperand() = fma
)
}
}
bindingset[p]
int world_permission(int p) { result = p.bitAnd(7) }
// 70 oct = 56 dec
bindingset[p]
int group_permission(int p) { result = p.bitAnd(56) }
bindingset[p]
string access(int p) {
p.bitAnd(2) != 0 and result = "writable"
or
p.bitAnd(4) != 0 and result = "readable"
}
/** An expression specifing a file permission that allows group/others read or write access */
class PermissivePermissionsExpr extends Expr {
// TODO: non-literal expressions?
PermissivePermissionsExpr() {
exists(int perm, string acc |
perm = this.(IntegerLiteral).getValue() and
(acc = access(world_permission(perm)) or acc = access(group_permission(perm)))
)
or
// adding/setting read or write permissions for all/group/other
this.(StringLiteral).getValueText().regexpMatch(".*[ago][^-=+]*[+=][xXst]*[rw].*")
}
}
/** A call to a method of File or FileUtils that may modify file permissions */
class PermissionSettingMethodCall extends MethodCall {
private string methodName;
private Expr permArg;
PermissionSettingMethodCall() {
this.getReceiver() instanceof FileModuleAccess and
this.getMethodName() = methodName and
(
methodName in ["chmod", "chmod_R", "lchmod"] and permArg = this.getArgument(0)
or
methodName = "mkfifo" and permArg = this.getArgument(1)
or
methodName in ["new", "open"] and permArg = this.getArgument(2)
or
methodName in ["install", "makedirs", "mkdir", "mkdir_p", "mkpath"] and
permArg = this.getKeywordArgument("mode")
// TODO: defaults for optional args? This may depend on the umask
)
}
Expr getPermissionArgument() { result = permArg }
}
class PermissivePermissionsConfig extends DataFlow::Configuration {
PermissivePermissionsConfig() { this = "PermissivePermissionsConfig" }
override predicate isSource(DataFlow::Node source) {
exists(PermissivePermissionsExpr ppe | source.asExpr().getExpr() = ppe)
}
override predicate isSink(DataFlow::Node sink) {
exists(PermissionSettingMethodCall c | sink.asExpr().getExpr() = c.getPermissionArgument())
}
}
from DataFlow::PathNode source, DataFlow::PathNode sink, PermissivePermissionsConfig conf
where conf.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "Overly permissive mask sets file to $@.", source.getNode(),
source.getNode().toString()

View File

@@ -0,0 +1,15 @@
/**
* @id rb/summary/lines-of-code
* @name Total lines of Ruby code in the database
* @description The total number of lines of Ruby code from the source code
* directory, including external libraries and auto-generated files. This is a
* useful metric of the size of a database. This query counts the lines of
* code, excluding whitespace or comments.
* @kind metric
* @tags summary
* lines-of-code
*/
import ruby
select sum(File f | exists(f.getRelativePath()) | f.getNumberOfLinesOfCode())

View File

@@ -0,0 +1,19 @@
/**
* @id rb/summary/lines-of-user-code
* @name Total Lines of user written Ruby code in the database
* @description The total number of lines of Ruby code from the source code
* directory, excluding external library and auto-generated files. This
* query counts the lines of code, excluding whitespace or comments.
* @kind metric
* @tags summary
*/
import ruby
select sum(File f |
f.fromSource() and
exists(f.getRelativePath()) and
not f.getAbsolutePath().matches("%/vendor/%")
|
f.getNumberOfLinesOfCode()
)

View File

@@ -0,0 +1,15 @@
/**
* @id rb/summary/number-of-files-extracted-with-errors
* @name Total number of files that were extracted with errors
* @description The total number of Ruby code files that we extracted, but where
* at least one extraction error occurred in the process.
* @kind metric
* @tags summary
*/
import ruby
import codeql_ruby.Diagnostics
select count(File f |
exists(ExtractionError e | e.getLocation().getFile() = f) and exists(f.getRelativePath())
)

View File

@@ -0,0 +1,15 @@
/**
* @id rb/summary/number-of-successfully-extracted-files
* @name Total number of files that were extracted without error
* @description The total number of Ruby code files that we extracted without
* encountering any extraction errors
* @kind metric
* @tags summary
*/
import ruby
import codeql_ruby.Diagnostics
select count(File f |
not exists(ExtractionError e | e.getLocation().getFile() = f) and exists(f.getRelativePath())
)

View File

@@ -1237,6 +1237,23 @@ case @token.kind of
;
diagnostics(
unique int id: @diagnostic,
int severity: int ref,
string error_tag: string ref,
string error_message: string ref,
string full_error_message: string ref,
int location: @location_default ref
);
case @diagnostic.severity of
10 = @diagnostic_debug
| 20 = @diagnostic_info
| 30 = @diagnostic_warning
| 40 = @diagnostic_error
;
@ast_node = @alias | @argument_list | @array | @assignment | @bare_string | @bare_symbol | @begin | @begin_block | @binary | @block | @block_argument | @block_parameter | @block_parameters | @break | @call | @case__ | @chained_string | @class | @conditional | @delimited_symbol | @destructured_left_assignment | @destructured_parameter | @do | @do_block | @element_reference | @else | @elsif | @end_block | @ensure | @exception_variable | @exceptions | @for | @hash | @hash_splat_argument | @hash_splat_parameter | @heredoc_body | @if | @if_modifier | @in | @interpolation | @keyword_parameter | @lambda | @lambda_parameters | @left_assignment_list | @method | @method_parameters | @module | @next | @operator_assignment | @optional_parameter | @pair | @parenthesized_statements | @pattern | @program | @range | @rational | @redo | @regex | @rescue | @rescue_modifier | @rest_assignment | @retry | @return | @right_assignment_list | @scope_resolution | @setter | @singleton_class | @singleton_method | @splat_argument | @splat_parameter | @string__ | @string_array | @subshell | @superclass | @symbol_array | @then | @token | @unary | @undef | @unless | @unless_modifier | @until | @until_modifier | @when | @while | @while_modifier | @yield
@ast_node_parent = @ast_node | @file

File diff suppressed because it is too large Load Diff

View File

@@ -567,6 +567,21 @@ calls/calls.rb:
# 319| getReceiver: [Self] self
# 319| getArgument: [IntegerLiteral] 0
# 319| getAnOperand/getRightOperand: [IntegerLiteral] 1
# 320| getStmt: [AssignMulExpr] ... *= ...
# 320| getAnOperand/getLeftOperand: [ElementReference, SetterMethodCall] ...[...]
# 320| getReceiver: [MethodCall] call to bar
# 320| getReceiver: [MethodCall] call to foo
# 320| getReceiver: [Self] self
# 320| getArgument: [IntegerLiteral] 0
# 320| getArgument: [MethodCall] call to baz
# 320| getReceiver: [MethodCall] call to foo
# 320| getReceiver: [Self] self
# 320| getArgument: [AddExpr] ... + ...
# 320| getAnOperand/getLeftOperand: [MethodCall] call to boo
# 320| getReceiver: [MethodCall] call to foo
# 320| getReceiver: [Self] self
# 320| getAnOperand/getRightOperand: [IntegerLiteral] 1
# 320| getAnOperand/getRightOperand: [IntegerLiteral] 2
control/cases.rb:
# 1| [Toplevel] cases.rb
# 2| getStmt: [AssignExpr] ... = ...
@@ -1718,6 +1733,25 @@ operations/operations.rb:
# 84| getStmt: [AssignBitwiseXorExpr] ... ^= ...
# 84| getAnOperand/getLeftOperand: [LocalVariableAccess] baz
# 84| getAnOperand/getRightOperand: [LocalVariableAccess] qux
# 86| getStmt: [ClassDeclaration] X
# 87| getStmt: [AssignExpr] ... = ...
# 87| getAnOperand/getLeftOperand: [InstanceVariableAccess] @x
# 87| getAnOperand/getRightOperand: [IntegerLiteral] 1
# 88| getStmt: [AssignAddExpr] ... += ...
# 88| getAnOperand/getLeftOperand: [InstanceVariableAccess] @x
# 88| getAnOperand/getRightOperand: [IntegerLiteral] 2
# 90| getStmt: [AssignExpr] ... = ...
# 90| getAnOperand/getLeftOperand: [ClassVariableAccess] @@y
# 90| getAnOperand/getRightOperand: [IntegerLiteral] 3
# 91| getStmt: [AssignDivExpr] ... /= ...
# 91| getAnOperand/getLeftOperand: [ClassVariableAccess] @@y
# 91| getAnOperand/getRightOperand: [IntegerLiteral] 4
# 94| getStmt: [AssignExpr] ... = ...
# 94| getAnOperand/getLeftOperand: [GlobalVariableAccess] $global_var
# 94| getAnOperand/getRightOperand: [IntegerLiteral] 5
# 95| getStmt: [AssignMulExpr] ... *= ...
# 95| getAnOperand/getLeftOperand: [GlobalVariableAccess] $global_var
# 95| getAnOperand/getRightOperand: [IntegerLiteral] 6
params/params.rb:
# 1| [Toplevel] params.rb
# 4| getStmt: [Method] identifier_method_params

View File

@@ -1,6 +1,5 @@
/**
* @kind graph
* @id rb/test/print-ast
*/
import codeql_ruby.printAst

View File

@@ -0,0 +1,180 @@
calls/calls.rb:
# 66| [AssignExpr] ... = ...
# 66| getAnOperand/getLeftOperand: [LocalVariableAccess] var1
# 66| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 66| getAnOperand/getLeftOperand: [LocalVariableAccess] var1
# 66| getAnOperand/getRightOperand: [MethodCall] call to bar
# 66| getReceiver: [Self] self
# 67| [AssignExpr] ... = ...
# 67| getAnOperand/getLeftOperand: [LocalVariableAccess] var1
# 67| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 67| getAnOperand/getLeftOperand: [LocalVariableAccess] var1
# 67| getAnOperand/getRightOperand: [MethodCall] call to bar
# 67| getReceiver: [ConstantReadAccess] X
control/loops.rb:
# 10| [AssignExpr] ... = ...
# 10| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
# 10| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 10| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
# 10| getAnOperand/getRightOperand: [LocalVariableAccess] n
# 17| [AssignExpr] ... = ...
# 17| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
# 17| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 17| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
# 17| getAnOperand/getRightOperand: [LocalVariableAccess] n
# 18| [AssignExpr] ... = ...
# 18| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
# 18| getAnOperand/getRightOperand: [SubExpr] ... - ...
# 18| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
# 18| getAnOperand/getRightOperand: [LocalVariableAccess] n
# 23| [AssignExpr] ... = ...
# 23| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
# 23| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 23| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
# 23| getAnOperand/getRightOperand: [LocalVariableAccess] value
# 24| [AssignExpr] ... = ...
# 24| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
# 24| getAnOperand/getRightOperand: [MulExpr] ... * ...
# 24| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
# 24| getAnOperand/getRightOperand: [LocalVariableAccess] value
# 29| [AssignExpr] ... = ...
# 29| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
# 29| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 29| getAnOperand/getLeftOperand: [LocalVariableAccess] sum
# 29| getAnOperand/getRightOperand: [LocalVariableAccess] value
# 30| [AssignExpr] ... = ...
# 30| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
# 30| getAnOperand/getRightOperand: [DivExpr] ... / ...
# 30| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
# 30| getAnOperand/getRightOperand: [LocalVariableAccess] value
# 36| [AssignExpr] ... = ...
# 36| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 36| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 36| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 36| getAnOperand/getRightOperand: [IntegerLiteral] 1
# 37| [AssignExpr] ... = ...
# 37| getAnOperand/getLeftOperand: [LocalVariableAccess] z
# 37| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 37| getAnOperand/getLeftOperand: [LocalVariableAccess] z
# 37| getAnOperand/getRightOperand: [IntegerLiteral] 1
# 43| [AssignExpr] ... = ...
# 43| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 43| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 43| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 43| getAnOperand/getRightOperand: [IntegerLiteral] 1
# 44| [AssignExpr] ... = ...
# 44| getAnOperand/getLeftOperand: [LocalVariableAccess] z
# 44| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 44| getAnOperand/getLeftOperand: [LocalVariableAccess] z
# 44| getAnOperand/getRightOperand: [IntegerLiteral] 2
# 48| [AssignExpr] ... = ...
# 48| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 48| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 48| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 48| getAnOperand/getRightOperand: [IntegerLiteral] 1
# 52| [AssignExpr] ... = ...
# 52| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 52| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 52| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 52| getAnOperand/getRightOperand: [IntegerLiteral] 1
# 53| [AssignExpr] ... = ...
# 53| getAnOperand/getLeftOperand: [LocalVariableAccess] z
# 53| getAnOperand/getRightOperand: [SubExpr] ... - ...
# 53| getAnOperand/getLeftOperand: [LocalVariableAccess] z
# 53| getAnOperand/getRightOperand: [IntegerLiteral] 1
# 58| [AssignExpr] ... = ...
# 58| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 58| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 58| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 58| getAnOperand/getRightOperand: [IntegerLiteral] 1
# 59| [AssignExpr] ... = ...
# 59| getAnOperand/getLeftOperand: [LocalVariableAccess] z
# 59| getAnOperand/getRightOperand: [SubExpr] ... - ...
# 59| getAnOperand/getLeftOperand: [LocalVariableAccess] z
# 59| getAnOperand/getRightOperand: [IntegerLiteral] 4
# 63| [AssignExpr] ... = ...
# 63| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 63| getAnOperand/getRightOperand: [SubExpr] ... - ...
# 63| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 63| getAnOperand/getRightOperand: [IntegerLiteral] 1
operations/operations.rb:
# 68| [AssignExpr] ... = ...
# 68| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 68| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 68| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 68| getAnOperand/getRightOperand: [IntegerLiteral] 128
# 69| [AssignExpr] ... = ...
# 69| getAnOperand/getLeftOperand: [LocalVariableAccess] y
# 69| getAnOperand/getRightOperand: [SubExpr] ... - ...
# 69| getAnOperand/getLeftOperand: [LocalVariableAccess] y
# 69| getAnOperand/getRightOperand: [IntegerLiteral] 32
# 70| [AssignExpr] ... = ...
# 70| getAnOperand/getLeftOperand: [LocalVariableAccess] a
# 70| getAnOperand/getRightOperand: [MulExpr] ... * ...
# 70| getAnOperand/getLeftOperand: [LocalVariableAccess] a
# 70| getAnOperand/getRightOperand: [IntegerLiteral] 12
# 71| [AssignExpr] ... = ...
# 71| getAnOperand/getLeftOperand: [LocalVariableAccess] b
# 71| getAnOperand/getRightOperand: [DivExpr] ... / ...
# 71| getAnOperand/getLeftOperand: [LocalVariableAccess] b
# 71| getAnOperand/getRightOperand: [IntegerLiteral] 4
# 72| [AssignExpr] ... = ...
# 72| getAnOperand/getLeftOperand: [LocalVariableAccess] z
# 72| getAnOperand/getRightOperand: [ModuloExpr] ... % ...
# 72| getAnOperand/getLeftOperand: [LocalVariableAccess] z
# 72| getAnOperand/getRightOperand: [IntegerLiteral] 2
# 73| [AssignExpr] ... = ...
# 73| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
# 73| getAnOperand/getRightOperand: [ExponentExpr] ... ** ...
# 73| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
# 73| getAnOperand/getRightOperand: [LocalVariableAccess] bar
# 76| [AssignExpr] ... = ...
# 76| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 76| getAnOperand/getRightOperand: [LogicalAndExpr] ... && ...
# 76| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 76| getAnOperand/getRightOperand: [LocalVariableAccess] y
# 77| [AssignExpr] ... = ...
# 77| getAnOperand/getLeftOperand: [LocalVariableAccess] a
# 77| getAnOperand/getRightOperand: [LogicalOrExpr] ... || ...
# 77| getAnOperand/getLeftOperand: [LocalVariableAccess] a
# 77| getAnOperand/getRightOperand: [LocalVariableAccess] b
# 80| [AssignExpr] ... = ...
# 80| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 80| getAnOperand/getRightOperand: [LShiftExpr] ... << ...
# 80| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 80| getAnOperand/getRightOperand: [IntegerLiteral] 2
# 81| [AssignExpr] ... = ...
# 81| getAnOperand/getLeftOperand: [LocalVariableAccess] y
# 81| getAnOperand/getRightOperand: [RShiftExpr] ... >> ...
# 81| getAnOperand/getLeftOperand: [LocalVariableAccess] y
# 81| getAnOperand/getRightOperand: [IntegerLiteral] 3
# 82| [AssignExpr] ... = ...
# 82| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
# 82| getAnOperand/getRightOperand: [BitwiseAndExpr] ... & ...
# 82| getAnOperand/getLeftOperand: [LocalVariableAccess] foo
# 82| getAnOperand/getRightOperand: [LocalVariableAccess] mask
# 83| [AssignExpr] ... = ...
# 83| getAnOperand/getLeftOperand: [LocalVariableAccess] bar
# 83| getAnOperand/getRightOperand: [BitwiseOrExpr] ... | ...
# 83| getAnOperand/getLeftOperand: [LocalVariableAccess] bar
# 83| getAnOperand/getRightOperand: [IntegerLiteral] 0x01
# 84| [AssignExpr] ... = ...
# 84| getAnOperand/getLeftOperand: [LocalVariableAccess] baz
# 84| getAnOperand/getRightOperand: [BitwiseXorExpr] ... ^ ...
# 84| getAnOperand/getLeftOperand: [LocalVariableAccess] baz
# 84| getAnOperand/getRightOperand: [LocalVariableAccess] qux
# 88| [AssignExpr] ... = ...
# 88| getAnOperand/getLeftOperand: [InstanceVariableAccess] @x
# 88| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 88| getAnOperand/getLeftOperand: [InstanceVariableAccess] @x
# 88| getAnOperand/getRightOperand: [IntegerLiteral] 2
# 91| [AssignExpr] ... = ...
# 91| getAnOperand/getLeftOperand: [ClassVariableAccess] @@y
# 91| getAnOperand/getRightOperand: [DivExpr] ... / ...
# 91| getAnOperand/getLeftOperand: [ClassVariableAccess] @@y
# 91| getAnOperand/getRightOperand: [IntegerLiteral] 4
# 95| [AssignExpr] ... = ...
# 95| getAnOperand/getLeftOperand: [GlobalVariableAccess] $global_var
# 95| getAnOperand/getRightOperand: [MulExpr] ... * ...
# 95| getAnOperand/getLeftOperand: [GlobalVariableAccess] $global_var
# 95| getAnOperand/getRightOperand: [IntegerLiteral] 6

View File

@@ -0,0 +1,9 @@
/**
* @kind graph
*/
import codeql_ruby.printAst
class DesugarPrintAstConfiguration extends PrintAstConfiguration {
override predicate shouldPrintNode(AstNode n) { isDesugared(n) }
}

View File

@@ -36,6 +36,12 @@ callsWithArguments
| calls.rb:317:5:317:10 | ...[...] | []= | 0 | calls.rb:317:9:317:9 | 5 |
| calls.rb:319:1:319:6 | ...[...] | [] | 0 | calls.rb:319:5:319:5 | 0 |
| calls.rb:319:1:319:6 | ...[...] | []= | 0 | calls.rb:319:5:319:5 | 0 |
| calls.rb:320:1:320:32 | ...[...] | [] | 0 | calls.rb:320:9:320:9 | 0 |
| calls.rb:320:1:320:32 | ...[...] | [] | 1 | calls.rb:320:12:320:18 | call to baz |
| calls.rb:320:1:320:32 | ...[...] | [] | 2 | calls.rb:320:21:320:31 | ... + ... |
| calls.rb:320:1:320:32 | ...[...] | []= | 0 | calls.rb:320:9:320:9 | 0 |
| calls.rb:320:1:320:32 | ...[...] | []= | 1 | calls.rb:320:12:320:18 | call to baz |
| calls.rb:320:1:320:32 | ...[...] | []= | 2 | calls.rb:320:21:320:31 | ... + ... |
callsWithReceiver
| calls.rb:2:1:2:5 | call to foo | calls.rb:2:1:2:5 | self |
| calls.rb:5:1:5:10 | call to bar | calls.rb:5:1:5:3 | Foo |
@@ -216,6 +222,13 @@ callsWithReceiver
| calls.rb:318:1:318:10 | call to count/count= | calls.rb:318:1:318:4 | self |
| calls.rb:319:1:319:3 | call to foo | calls.rb:319:1:319:3 | self |
| calls.rb:319:1:319:6 | ...[...] | calls.rb:319:1:319:3 | call to foo |
| calls.rb:320:1:320:3 | call to foo | calls.rb:320:1:320:3 | self |
| calls.rb:320:1:320:7 | call to bar | calls.rb:320:1:320:3 | call to foo |
| calls.rb:320:1:320:32 | ...[...] | calls.rb:320:1:320:7 | call to bar |
| calls.rb:320:12:320:14 | call to foo | calls.rb:320:12:320:14 | self |
| calls.rb:320:12:320:18 | call to baz | calls.rb:320:12:320:14 | call to foo |
| calls.rb:320:21:320:23 | call to foo | calls.rb:320:21:320:23 | self |
| calls.rb:320:21:320:27 | call to boo | calls.rb:320:21:320:23 | call to foo |
callsWithBlock
| calls.rb:17:1:17:17 | call to foo | calls.rb:17:5:17:17 | { ... } |
| calls.rb:20:1:22:3 | call to foo | calls.rb:20:5:22:3 | do ... end |
@@ -262,3 +275,4 @@ setterCalls
| calls.rb:317:5:317:10 | ...[...] |
| calls.rb:318:1:318:10 | call to count/count= |
| calls.rb:319:1:319:6 | ...[...] |
| calls.rb:320:1:320:32 | ...[...] |

View File

@@ -317,3 +317,4 @@ self.foo, *self.bar, foo[4] = [1, 2, 3, 4]
a, *foo[5] = [1, 2, 3]
self.count += 1
foo[0] += 1
foo.bar[0, foo.baz, foo.boo + 1] *= 2

View File

@@ -18,18 +18,40 @@ assignments
| operations.rb:19:1:19:5 | ... = ... | = | operations.rb:19:1:19:1 | y | operations.rb:19:5:19:5 | 0 | AssignExpr |
| operations.rb:20:1:20:5 | ... = ... | = | operations.rb:20:1:20:1 | z | operations.rb:20:5:20:5 | 0 | AssignExpr |
| operations.rb:68:1:68:8 | ... += ... | += | operations.rb:68:1:68:1 | x | operations.rb:68:6:68:8 | 128 | AssignAddExpr |
| operations.rb:68:1:68:8 | ... = ... | = | operations.rb:68:1:68:1 | x | operations.rb:68:1:68:8 | ... + ... | AssignExpr |
| operations.rb:69:1:69:7 | ... -= ... | -= | operations.rb:69:1:69:1 | y | operations.rb:69:6:69:7 | 32 | AssignSubExpr |
| operations.rb:69:1:69:7 | ... = ... | = | operations.rb:69:1:69:1 | y | operations.rb:69:1:69:7 | ... - ... | AssignExpr |
| operations.rb:70:1:70:7 | ... *= ... | *= | operations.rb:70:1:70:1 | a | operations.rb:70:6:70:7 | 12 | AssignMulExpr |
| operations.rb:70:1:70:7 | ... = ... | = | operations.rb:70:1:70:1 | a | operations.rb:70:1:70:7 | ... * ... | AssignExpr |
| operations.rb:71:1:71:6 | ... /= ... | /= | operations.rb:71:1:71:1 | b | operations.rb:71:6:71:6 | 4 | AssignDivExpr |
| operations.rb:71:1:71:6 | ... = ... | = | operations.rb:71:1:71:1 | b | operations.rb:71:1:71:6 | ... / ... | AssignExpr |
| operations.rb:72:1:72:6 | ... %= ... | %= | operations.rb:72:1:72:1 | z | operations.rb:72:6:72:6 | 2 | AssignModuloExpr |
| operations.rb:72:1:72:6 | ... = ... | = | operations.rb:72:1:72:1 | z | operations.rb:72:1:72:6 | ... % ... | AssignExpr |
| operations.rb:73:1:73:11 | ... **= ... | **= | operations.rb:73:1:73:3 | foo | operations.rb:73:9:73:11 | bar | AssignExponentExpr |
| operations.rb:73:1:73:11 | ... = ... | = | operations.rb:73:1:73:3 | foo | operations.rb:73:1:73:11 | ... ** ... | AssignExpr |
| operations.rb:76:2:76:8 | ... &&= ... | &&= | operations.rb:76:2:76:2 | x | operations.rb:76:8:76:8 | y | AssignLogicalAndExpr |
| operations.rb:76:2:76:8 | ... = ... | = | operations.rb:76:2:76:2 | x | operations.rb:76:2:76:8 | ... && ... | AssignExpr |
| operations.rb:77:2:77:8 | ... = ... | = | operations.rb:77:2:77:2 | a | operations.rb:77:2:77:8 | ... \|\| ... | AssignExpr |
| operations.rb:77:2:77:8 | ... \|\|= ... | \|\|= | operations.rb:77:2:77:2 | a | operations.rb:77:8:77:8 | b | AssignLogicalOrExpr |
| operations.rb:80:2:80:8 | ... <<= ... | <<= | operations.rb:80:2:80:2 | x | operations.rb:80:8:80:8 | 2 | AssignLShiftExpr |
| operations.rb:80:2:80:8 | ... = ... | = | operations.rb:80:2:80:2 | x | operations.rb:80:2:80:8 | ... << ... | AssignExpr |
| operations.rb:81:2:81:8 | ... = ... | = | operations.rb:81:2:81:2 | y | operations.rb:81:2:81:8 | ... >> ... | AssignExpr |
| operations.rb:81:2:81:8 | ... >>= ... | >>= | operations.rb:81:2:81:2 | y | operations.rb:81:8:81:8 | 3 | AssignRShiftExpr |
| operations.rb:82:2:82:12 | ... &= ... | &= | operations.rb:82:2:82:4 | foo | operations.rb:82:9:82:12 | mask | AssignBitwiseAndExpr |
| operations.rb:82:2:82:12 | ... = ... | = | operations.rb:82:2:82:4 | foo | operations.rb:82:2:82:12 | ... & ... | AssignExpr |
| operations.rb:83:2:83:12 | ... = ... | = | operations.rb:83:2:83:4 | bar | operations.rb:83:2:83:12 | ... \| ... | AssignExpr |
| operations.rb:83:2:83:12 | ... \|= ... | \|= | operations.rb:83:2:83:4 | bar | operations.rb:83:9:83:12 | 0x01 | AssignBitwiseOrExpr |
| operations.rb:84:2:84:11 | ... = ... | = | operations.rb:84:2:84:4 | baz | operations.rb:84:2:84:11 | ... ^ ... | AssignExpr |
| operations.rb:84:2:84:11 | ... ^= ... | ^= | operations.rb:84:2:84:4 | baz | operations.rb:84:9:84:11 | qux | AssignBitwiseXorExpr |
| operations.rb:87:3:87:8 | ... = ... | = | operations.rb:87:3:87:4 | @x | operations.rb:87:8:87:8 | 1 | AssignExpr |
| operations.rb:88:3:88:9 | ... += ... | += | operations.rb:88:3:88:4 | @x | operations.rb:88:9:88:9 | 2 | AssignAddExpr |
| operations.rb:88:3:88:9 | ... = ... | = | operations.rb:88:3:88:4 | @x | operations.rb:88:3:88:9 | ... + ... | AssignExpr |
| operations.rb:90:3:90:9 | ... = ... | = | operations.rb:90:3:90:5 | @@y | operations.rb:90:9:90:9 | 3 | AssignExpr |
| operations.rb:91:3:91:10 | ... /= ... | /= | operations.rb:91:3:91:5 | @@y | operations.rb:91:10:91:10 | 4 | AssignDivExpr |
| operations.rb:91:3:91:10 | ... = ... | = | operations.rb:91:3:91:5 | @@y | operations.rb:91:3:91:10 | ... / ... | AssignExpr |
| operations.rb:94:1:94:15 | ... = ... | = | operations.rb:94:1:94:11 | $global_var | operations.rb:94:15:94:15 | 5 | AssignExpr |
| operations.rb:95:1:95:16 | ... *= ... | *= | operations.rb:95:1:95:11 | $global_var | operations.rb:95:16:95:16 | 6 | AssignMulExpr |
| operations.rb:95:1:95:16 | ... = ... | = | operations.rb:95:1:95:11 | $global_var | operations.rb:95:1:95:16 | ... * ... | AssignExpr |
assignOperations
| operations.rb:68:1:68:8 | ... += ... | += | operations.rb:68:1:68:1 | x | operations.rb:68:6:68:8 | 128 | AssignAddExpr |
| operations.rb:69:1:69:7 | ... -= ... | -= | operations.rb:69:1:69:1 | y | operations.rb:69:6:69:7 | 32 | AssignSubExpr |
@@ -44,6 +66,9 @@ assignOperations
| operations.rb:82:2:82:12 | ... &= ... | &= | operations.rb:82:2:82:4 | foo | operations.rb:82:9:82:12 | mask | AssignBitwiseAndExpr |
| operations.rb:83:2:83:12 | ... \|= ... | \|= | operations.rb:83:2:83:4 | bar | operations.rb:83:9:83:12 | 0x01 | AssignBitwiseOrExpr |
| operations.rb:84:2:84:11 | ... ^= ... | ^= | operations.rb:84:2:84:4 | baz | operations.rb:84:9:84:11 | qux | AssignBitwiseXorExpr |
| operations.rb:88:3:88:9 | ... += ... | += | operations.rb:88:3:88:4 | @x | operations.rb:88:9:88:9 | 2 | AssignAddExpr |
| operations.rb:91:3:91:10 | ... /= ... | /= | operations.rb:91:3:91:5 | @@y | operations.rb:91:10:91:10 | 4 | AssignDivExpr |
| operations.rb:95:1:95:16 | ... *= ... | *= | operations.rb:95:1:95:11 | $global_var | operations.rb:95:16:95:16 | 6 | AssignMulExpr |
assignArithmeticOperations
| operations.rb:68:1:68:8 | ... += ... | += | operations.rb:68:1:68:1 | x | operations.rb:68:6:68:8 | 128 | AssignAddExpr |
| operations.rb:69:1:69:7 | ... -= ... | -= | operations.rb:69:1:69:1 | y | operations.rb:69:6:69:7 | 32 | AssignSubExpr |
@@ -51,6 +76,9 @@ assignArithmeticOperations
| operations.rb:71:1:71:6 | ... /= ... | /= | operations.rb:71:1:71:1 | b | operations.rb:71:6:71:6 | 4 | AssignDivExpr |
| operations.rb:72:1:72:6 | ... %= ... | %= | operations.rb:72:1:72:1 | z | operations.rb:72:6:72:6 | 2 | AssignModuloExpr |
| operations.rb:73:1:73:11 | ... **= ... | **= | operations.rb:73:1:73:3 | foo | operations.rb:73:9:73:11 | bar | AssignExponentExpr |
| operations.rb:88:3:88:9 | ... += ... | += | operations.rb:88:3:88:4 | @x | operations.rb:88:9:88:9 | 2 | AssignAddExpr |
| operations.rb:91:3:91:10 | ... /= ... | /= | operations.rb:91:3:91:5 | @@y | operations.rb:91:10:91:10 | 4 | AssignDivExpr |
| operations.rb:95:1:95:16 | ... *= ... | *= | operations.rb:95:1:95:11 | $global_var | operations.rb:95:16:95:16 | 6 | AssignMulExpr |
assignLogicalOperations
| operations.rb:76:2:76:8 | ... &&= ... | &&= | operations.rb:76:2:76:2 | x | operations.rb:76:8:76:8 | y | AssignLogicalAndExpr |
| operations.rb:77:2:77:8 | ... \|\|= ... | \|\|= | operations.rb:77:2:77:2 | a | operations.rb:77:8:77:8 | b | AssignLogicalOrExpr |

View File

@@ -24,6 +24,22 @@ binaryOperations
| operations.rb:63:1:63:7 | ... <=> ... | <=> | operations.rb:63:1:63:1 | a | operations.rb:63:7:63:7 | b | SpaceshipExpr |
| operations.rb:64:1:64:15 | ... =~ ... | =~ | operations.rb:64:1:64:4 | name | operations.rb:64:9:64:15 | /foo.*/ | RegexMatchExpr |
| operations.rb:65:1:65:17 | ... !~ ... | !~ | operations.rb:65:1:65:6 | handle | operations.rb:65:11:65:17 | /.*bar/ | NoRegexMatchExpr |
| operations.rb:68:1:68:8 | ... + ... | + | operations.rb:68:1:68:8 | x | operations.rb:68:6:68:8 | 128 | AddExpr |
| operations.rb:69:1:69:7 | ... - ... | - | operations.rb:69:1:69:7 | y | operations.rb:69:6:69:7 | 32 | SubExpr |
| operations.rb:70:1:70:7 | ... * ... | * | operations.rb:70:1:70:7 | a | operations.rb:70:6:70:7 | 12 | MulExpr |
| operations.rb:71:1:71:6 | ... / ... | / | operations.rb:71:1:71:6 | b | operations.rb:71:6:71:6 | 4 | DivExpr |
| operations.rb:72:1:72:6 | ... % ... | % | operations.rb:72:1:72:6 | z | operations.rb:72:6:72:6 | 2 | ModuloExpr |
| operations.rb:73:1:73:11 | ... ** ... | ** | operations.rb:73:1:73:11 | foo | operations.rb:73:9:73:11 | bar | ExponentExpr |
| operations.rb:76:2:76:8 | ... && ... | && | operations.rb:76:2:76:8 | x | operations.rb:76:8:76:8 | y | LogicalAndExpr |
| operations.rb:77:2:77:8 | ... \|\| ... | \|\| | operations.rb:77:2:77:8 | a | operations.rb:77:8:77:8 | b | LogicalOrExpr |
| operations.rb:80:2:80:8 | ... << ... | << | operations.rb:80:2:80:8 | x | operations.rb:80:8:80:8 | 2 | LShiftExpr |
| operations.rb:81:2:81:8 | ... >> ... | >> | operations.rb:81:2:81:8 | y | operations.rb:81:8:81:8 | 3 | RShiftExpr |
| operations.rb:82:2:82:12 | ... & ... | & | operations.rb:82:2:82:12 | foo | operations.rb:82:9:82:12 | mask | BitwiseAndExpr |
| operations.rb:83:2:83:12 | ... \| ... | \| | operations.rb:83:2:83:12 | bar | operations.rb:83:9:83:12 | 0x01 | BitwiseOrExpr |
| operations.rb:84:2:84:11 | ... ^ ... | ^ | operations.rb:84:2:84:11 | baz | operations.rb:84:9:84:11 | qux | BitwiseXorExpr |
| operations.rb:88:3:88:9 | ... + ... | + | operations.rb:88:3:88:9 | @x | operations.rb:88:9:88:9 | 2 | AddExpr |
| operations.rb:91:3:91:10 | ... / ... | / | operations.rb:91:3:91:10 | @@y | operations.rb:91:10:91:10 | 4 | DivExpr |
| operations.rb:95:1:95:16 | ... * ... | * | operations.rb:95:1:95:16 | $global_var | operations.rb:95:16:95:16 | 6 | MulExpr |
binaryArithmeticOperations
| operations.rb:31:1:31:7 | ... + ... | + | operations.rb:31:1:31:1 | w | operations.rb:31:5:31:7 | 234 | AddExpr |
| operations.rb:32:1:32:6 | ... - ... | - | operations.rb:32:1:32:1 | x | operations.rb:32:5:32:6 | 17 | SubExpr |
@@ -31,17 +47,33 @@ binaryArithmeticOperations
| operations.rb:34:1:34:5 | ... / ... | / | operations.rb:34:1:34:1 | z | operations.rb:34:5:34:5 | 2 | DivExpr |
| operations.rb:35:1:35:7 | ... % ... | % | operations.rb:35:1:35:3 | num | operations.rb:35:7:35:7 | 2 | ModuloExpr |
| operations.rb:36:1:36:13 | ... ** ... | ** | operations.rb:36:1:36:4 | base | operations.rb:36:9:36:13 | power | ExponentExpr |
| operations.rb:68:1:68:8 | ... + ... | + | operations.rb:68:1:68:8 | x | operations.rb:68:6:68:8 | 128 | AddExpr |
| operations.rb:69:1:69:7 | ... - ... | - | operations.rb:69:1:69:7 | y | operations.rb:69:6:69:7 | 32 | SubExpr |
| operations.rb:70:1:70:7 | ... * ... | * | operations.rb:70:1:70:7 | a | operations.rb:70:6:70:7 | 12 | MulExpr |
| operations.rb:71:1:71:6 | ... / ... | / | operations.rb:71:1:71:6 | b | operations.rb:71:6:71:6 | 4 | DivExpr |
| operations.rb:72:1:72:6 | ... % ... | % | operations.rb:72:1:72:6 | z | operations.rb:72:6:72:6 | 2 | ModuloExpr |
| operations.rb:73:1:73:11 | ... ** ... | ** | operations.rb:73:1:73:11 | foo | operations.rb:73:9:73:11 | bar | ExponentExpr |
| operations.rb:88:3:88:9 | ... + ... | + | operations.rb:88:3:88:9 | @x | operations.rb:88:9:88:9 | 2 | AddExpr |
| operations.rb:91:3:91:10 | ... / ... | / | operations.rb:91:3:91:10 | @@y | operations.rb:91:10:91:10 | 4 | DivExpr |
| operations.rb:95:1:95:16 | ... * ... | * | operations.rb:95:1:95:16 | $global_var | operations.rb:95:16:95:16 | 6 | MulExpr |
binaryLogicalOperations
| operations.rb:39:1:39:10 | ... && ... | && | operations.rb:39:1:39:3 | foo | operations.rb:39:8:39:10 | bar | LogicalAndExpr |
| operations.rb:40:1:40:11 | ... and ... | and | operations.rb:40:1:40:3 | baz | operations.rb:40:9:40:11 | qux | LogicalAndExpr |
| operations.rb:41:1:41:6 | ... or ... | or | operations.rb:41:1:41:1 | a | operations.rb:41:6:41:6 | b | LogicalOrExpr |
| operations.rb:42:1:42:6 | ... \|\| ... | \|\| | operations.rb:42:1:42:1 | x | operations.rb:42:6:42:6 | y | LogicalOrExpr |
| operations.rb:76:2:76:8 | ... && ... | && | operations.rb:76:2:76:8 | x | operations.rb:76:8:76:8 | y | LogicalAndExpr |
| operations.rb:77:2:77:8 | ... \|\| ... | \|\| | operations.rb:77:2:77:8 | a | operations.rb:77:8:77:8 | b | LogicalOrExpr |
binaryBitwiseOperations
| operations.rb:45:1:45:6 | ... << ... | << | operations.rb:45:1:45:1 | x | operations.rb:45:6:45:6 | 3 | LShiftExpr |
| operations.rb:46:1:46:7 | ... >> ... | >> | operations.rb:46:1:46:1 | y | operations.rb:46:6:46:7 | 16 | RShiftExpr |
| operations.rb:47:1:47:10 | ... & ... | & | operations.rb:47:1:47:3 | foo | operations.rb:47:7:47:10 | 0xff | BitwiseAndExpr |
| operations.rb:48:1:48:10 | ... \| ... | \| | operations.rb:48:1:48:3 | bar | operations.rb:48:7:48:10 | 0x02 | BitwiseOrExpr |
| operations.rb:49:1:49:9 | ... ^ ... | ^ | operations.rb:49:1:49:3 | baz | operations.rb:49:7:49:9 | qux | BitwiseXorExpr |
| operations.rb:80:2:80:8 | ... << ... | << | operations.rb:80:2:80:8 | x | operations.rb:80:8:80:8 | 2 | LShiftExpr |
| operations.rb:81:2:81:8 | ... >> ... | >> | operations.rb:81:2:81:8 | y | operations.rb:81:8:81:8 | 3 | RShiftExpr |
| operations.rb:82:2:82:12 | ... & ... | & | operations.rb:82:2:82:12 | foo | operations.rb:82:9:82:12 | mask | BitwiseAndExpr |
| operations.rb:83:2:83:12 | ... \| ... | \| | operations.rb:83:2:83:12 | bar | operations.rb:83:9:83:12 | 0x01 | BitwiseOrExpr |
| operations.rb:84:2:84:11 | ... ^ ... | ^ | operations.rb:84:2:84:11 | baz | operations.rb:84:9:84:11 | qux | BitwiseXorExpr |
comparisonOperations
| operations.rb:52:1:52:6 | ... == ... | == | operations.rb:52:1:52:1 | x | operations.rb:52:6:52:6 | y | EqExpr |
| operations.rb:53:1:53:8 | ... != ... | != | operations.rb:53:1:53:1 | a | operations.rb:53:6:53:8 | 123 | NEExpr |

View File

@@ -90,29 +90,105 @@
| operations.rb:64:1:64:15 | ... =~ ... | =~ | operations.rb:64:9:64:15 | /foo.*/ | RegexMatchExpr |
| operations.rb:65:1:65:17 | ... !~ ... | !~ | operations.rb:65:1:65:6 | handle | NoRegexMatchExpr |
| operations.rb:65:1:65:17 | ... !~ ... | !~ | operations.rb:65:11:65:17 | /.*bar/ | NoRegexMatchExpr |
| operations.rb:68:1:68:8 | ... + ... | + | operations.rb:68:1:68:8 | x | AddExpr |
| operations.rb:68:1:68:8 | ... + ... | + | operations.rb:68:6:68:8 | 128 | AddExpr |
| operations.rb:68:1:68:8 | ... += ... | += | operations.rb:68:1:68:1 | x | AssignAddExpr |
| operations.rb:68:1:68:8 | ... += ... | += | operations.rb:68:6:68:8 | 128 | AssignAddExpr |
| operations.rb:68:1:68:8 | ... = ... | = | operations.rb:68:1:68:1 | x | AssignExpr |
| operations.rb:68:1:68:8 | ... = ... | = | operations.rb:68:1:68:8 | ... + ... | AssignExpr |
| operations.rb:69:1:69:7 | ... - ... | - | operations.rb:69:1:69:7 | y | SubExpr |
| operations.rb:69:1:69:7 | ... - ... | - | operations.rb:69:6:69:7 | 32 | SubExpr |
| operations.rb:69:1:69:7 | ... -= ... | -= | operations.rb:69:1:69:1 | y | AssignSubExpr |
| operations.rb:69:1:69:7 | ... -= ... | -= | operations.rb:69:6:69:7 | 32 | AssignSubExpr |
| operations.rb:69:1:69:7 | ... = ... | = | operations.rb:69:1:69:1 | y | AssignExpr |
| operations.rb:69:1:69:7 | ... = ... | = | operations.rb:69:1:69:7 | ... - ... | AssignExpr |
| operations.rb:70:1:70:7 | ... * ... | * | operations.rb:70:1:70:7 | a | MulExpr |
| operations.rb:70:1:70:7 | ... * ... | * | operations.rb:70:6:70:7 | 12 | MulExpr |
| operations.rb:70:1:70:7 | ... *= ... | *= | operations.rb:70:1:70:1 | a | AssignMulExpr |
| operations.rb:70:1:70:7 | ... *= ... | *= | operations.rb:70:6:70:7 | 12 | AssignMulExpr |
| operations.rb:70:1:70:7 | ... = ... | = | operations.rb:70:1:70:1 | a | AssignExpr |
| operations.rb:70:1:70:7 | ... = ... | = | operations.rb:70:1:70:7 | ... * ... | AssignExpr |
| operations.rb:71:1:71:6 | ... / ... | / | operations.rb:71:1:71:6 | b | DivExpr |
| operations.rb:71:1:71:6 | ... / ... | / | operations.rb:71:6:71:6 | 4 | DivExpr |
| operations.rb:71:1:71:6 | ... /= ... | /= | operations.rb:71:1:71:1 | b | AssignDivExpr |
| operations.rb:71:1:71:6 | ... /= ... | /= | operations.rb:71:6:71:6 | 4 | AssignDivExpr |
| operations.rb:71:1:71:6 | ... = ... | = | operations.rb:71:1:71:1 | b | AssignExpr |
| operations.rb:71:1:71:6 | ... = ... | = | operations.rb:71:1:71:6 | ... / ... | AssignExpr |
| operations.rb:72:1:72:6 | ... % ... | % | operations.rb:72:1:72:6 | z | ModuloExpr |
| operations.rb:72:1:72:6 | ... % ... | % | operations.rb:72:6:72:6 | 2 | ModuloExpr |
| operations.rb:72:1:72:6 | ... %= ... | %= | operations.rb:72:1:72:1 | z | AssignModuloExpr |
| operations.rb:72:1:72:6 | ... %= ... | %= | operations.rb:72:6:72:6 | 2 | AssignModuloExpr |
| operations.rb:72:1:72:6 | ... = ... | = | operations.rb:72:1:72:1 | z | AssignExpr |
| operations.rb:72:1:72:6 | ... = ... | = | operations.rb:72:1:72:6 | ... % ... | AssignExpr |
| operations.rb:73:1:73:11 | ... ** ... | ** | operations.rb:73:1:73:11 | foo | ExponentExpr |
| operations.rb:73:1:73:11 | ... ** ... | ** | operations.rb:73:9:73:11 | bar | ExponentExpr |
| operations.rb:73:1:73:11 | ... **= ... | **= | operations.rb:73:1:73:3 | foo | AssignExponentExpr |
| operations.rb:73:1:73:11 | ... **= ... | **= | operations.rb:73:9:73:11 | bar | AssignExponentExpr |
| operations.rb:73:1:73:11 | ... = ... | = | operations.rb:73:1:73:3 | foo | AssignExpr |
| operations.rb:73:1:73:11 | ... = ... | = | operations.rb:73:1:73:11 | ... ** ... | AssignExpr |
| operations.rb:76:2:76:8 | ... && ... | && | operations.rb:76:2:76:8 | x | LogicalAndExpr |
| operations.rb:76:2:76:8 | ... && ... | && | operations.rb:76:8:76:8 | y | LogicalAndExpr |
| operations.rb:76:2:76:8 | ... &&= ... | &&= | operations.rb:76:2:76:2 | x | AssignLogicalAndExpr |
| operations.rb:76:2:76:8 | ... &&= ... | &&= | operations.rb:76:8:76:8 | y | AssignLogicalAndExpr |
| operations.rb:76:2:76:8 | ... = ... | = | operations.rb:76:2:76:2 | x | AssignExpr |
| operations.rb:76:2:76:8 | ... = ... | = | operations.rb:76:2:76:8 | ... && ... | AssignExpr |
| operations.rb:77:2:77:8 | ... = ... | = | operations.rb:77:2:77:2 | a | AssignExpr |
| operations.rb:77:2:77:8 | ... = ... | = | operations.rb:77:2:77:8 | ... \|\| ... | AssignExpr |
| operations.rb:77:2:77:8 | ... \|\| ... | \|\| | operations.rb:77:2:77:8 | a | LogicalOrExpr |
| operations.rb:77:2:77:8 | ... \|\| ... | \|\| | operations.rb:77:8:77:8 | b | LogicalOrExpr |
| operations.rb:77:2:77:8 | ... \|\|= ... | \|\|= | operations.rb:77:2:77:2 | a | AssignLogicalOrExpr |
| operations.rb:77:2:77:8 | ... \|\|= ... | \|\|= | operations.rb:77:8:77:8 | b | AssignLogicalOrExpr |
| operations.rb:80:2:80:8 | ... << ... | << | operations.rb:80:2:80:8 | x | LShiftExpr |
| operations.rb:80:2:80:8 | ... << ... | << | operations.rb:80:8:80:8 | 2 | LShiftExpr |
| operations.rb:80:2:80:8 | ... <<= ... | <<= | operations.rb:80:2:80:2 | x | AssignLShiftExpr |
| operations.rb:80:2:80:8 | ... <<= ... | <<= | operations.rb:80:8:80:8 | 2 | AssignLShiftExpr |
| operations.rb:80:2:80:8 | ... = ... | = | operations.rb:80:2:80:2 | x | AssignExpr |
| operations.rb:80:2:80:8 | ... = ... | = | operations.rb:80:2:80:8 | ... << ... | AssignExpr |
| operations.rb:81:2:81:8 | ... = ... | = | operations.rb:81:2:81:2 | y | AssignExpr |
| operations.rb:81:2:81:8 | ... = ... | = | operations.rb:81:2:81:8 | ... >> ... | AssignExpr |
| operations.rb:81:2:81:8 | ... >> ... | >> | operations.rb:81:2:81:8 | y | RShiftExpr |
| operations.rb:81:2:81:8 | ... >> ... | >> | operations.rb:81:8:81:8 | 3 | RShiftExpr |
| operations.rb:81:2:81:8 | ... >>= ... | >>= | operations.rb:81:2:81:2 | y | AssignRShiftExpr |
| operations.rb:81:2:81:8 | ... >>= ... | >>= | operations.rb:81:8:81:8 | 3 | AssignRShiftExpr |
| operations.rb:82:2:82:12 | ... & ... | & | operations.rb:82:2:82:12 | foo | BitwiseAndExpr |
| operations.rb:82:2:82:12 | ... & ... | & | operations.rb:82:9:82:12 | mask | BitwiseAndExpr |
| operations.rb:82:2:82:12 | ... &= ... | &= | operations.rb:82:2:82:4 | foo | AssignBitwiseAndExpr |
| operations.rb:82:2:82:12 | ... &= ... | &= | operations.rb:82:9:82:12 | mask | AssignBitwiseAndExpr |
| operations.rb:82:2:82:12 | ... = ... | = | operations.rb:82:2:82:4 | foo | AssignExpr |
| operations.rb:82:2:82:12 | ... = ... | = | operations.rb:82:2:82:12 | ... & ... | AssignExpr |
| operations.rb:83:2:83:12 | ... = ... | = | operations.rb:83:2:83:4 | bar | AssignExpr |
| operations.rb:83:2:83:12 | ... = ... | = | operations.rb:83:2:83:12 | ... \| ... | AssignExpr |
| operations.rb:83:2:83:12 | ... \| ... | \| | operations.rb:83:2:83:12 | bar | BitwiseOrExpr |
| operations.rb:83:2:83:12 | ... \| ... | \| | operations.rb:83:9:83:12 | 0x01 | BitwiseOrExpr |
| operations.rb:83:2:83:12 | ... \|= ... | \|= | operations.rb:83:2:83:4 | bar | AssignBitwiseOrExpr |
| operations.rb:83:2:83:12 | ... \|= ... | \|= | operations.rb:83:9:83:12 | 0x01 | AssignBitwiseOrExpr |
| operations.rb:84:2:84:11 | ... = ... | = | operations.rb:84:2:84:4 | baz | AssignExpr |
| operations.rb:84:2:84:11 | ... = ... | = | operations.rb:84:2:84:11 | ... ^ ... | AssignExpr |
| operations.rb:84:2:84:11 | ... ^ ... | ^ | operations.rb:84:2:84:11 | baz | BitwiseXorExpr |
| operations.rb:84:2:84:11 | ... ^ ... | ^ | operations.rb:84:9:84:11 | qux | BitwiseXorExpr |
| operations.rb:84:2:84:11 | ... ^= ... | ^= | operations.rb:84:2:84:4 | baz | AssignBitwiseXorExpr |
| operations.rb:84:2:84:11 | ... ^= ... | ^= | operations.rb:84:9:84:11 | qux | AssignBitwiseXorExpr |
| operations.rb:87:3:87:8 | ... = ... | = | operations.rb:87:3:87:4 | @x | AssignExpr |
| operations.rb:87:3:87:8 | ... = ... | = | operations.rb:87:8:87:8 | 1 | AssignExpr |
| operations.rb:88:3:88:9 | ... + ... | + | operations.rb:88:3:88:9 | @x | AddExpr |
| operations.rb:88:3:88:9 | ... + ... | + | operations.rb:88:9:88:9 | 2 | AddExpr |
| operations.rb:88:3:88:9 | ... += ... | += | operations.rb:88:3:88:4 | @x | AssignAddExpr |
| operations.rb:88:3:88:9 | ... += ... | += | operations.rb:88:9:88:9 | 2 | AssignAddExpr |
| operations.rb:88:3:88:9 | ... = ... | = | operations.rb:88:3:88:4 | @x | AssignExpr |
| operations.rb:88:3:88:9 | ... = ... | = | operations.rb:88:3:88:9 | ... + ... | AssignExpr |
| operations.rb:90:3:90:9 | ... = ... | = | operations.rb:90:3:90:5 | @@y | AssignExpr |
| operations.rb:90:3:90:9 | ... = ... | = | operations.rb:90:9:90:9 | 3 | AssignExpr |
| operations.rb:91:3:91:10 | ... / ... | / | operations.rb:91:3:91:10 | @@y | DivExpr |
| operations.rb:91:3:91:10 | ... / ... | / | operations.rb:91:10:91:10 | 4 | DivExpr |
| operations.rb:91:3:91:10 | ... /= ... | /= | operations.rb:91:3:91:5 | @@y | AssignDivExpr |
| operations.rb:91:3:91:10 | ... /= ... | /= | operations.rb:91:10:91:10 | 4 | AssignDivExpr |
| operations.rb:91:3:91:10 | ... = ... | = | operations.rb:91:3:91:5 | @@y | AssignExpr |
| operations.rb:91:3:91:10 | ... = ... | = | operations.rb:91:3:91:10 | ... / ... | AssignExpr |
| operations.rb:94:1:94:15 | ... = ... | = | operations.rb:94:1:94:11 | $global_var | AssignExpr |
| operations.rb:94:1:94:15 | ... = ... | = | operations.rb:94:15:94:15 | 5 | AssignExpr |
| operations.rb:95:1:95:16 | ... * ... | * | operations.rb:95:1:95:16 | $global_var | MulExpr |
| operations.rb:95:1:95:16 | ... * ... | * | operations.rb:95:16:95:16 | 6 | MulExpr |
| operations.rb:95:1:95:16 | ... *= ... | *= | operations.rb:95:1:95:11 | $global_var | AssignMulExpr |
| operations.rb:95:1:95:16 | ... *= ... | *= | operations.rb:95:16:95:16 | 6 | AssignMulExpr |
| operations.rb:95:1:95:16 | ... = ... | = | operations.rb:95:1:95:11 | $global_var | AssignExpr |
| operations.rb:95:1:95:16 | ... = ... | = | operations.rb:95:1:95:16 | ... * ... | AssignExpr |

View File

@@ -81,4 +81,15 @@ foo **= bar
y >>= 3
foo &= mask
bar |= 0x01
baz ^= qux
baz ^= qux
class X
@x = 1
@x += 2
@@y = 3
@@y /= 4
end
$global_var = 5
$global_var *= 6

View File

@@ -660,12 +660,12 @@ cfg.rb:
# 35| false
#-----| false -> if ...
# 39| self
#-----| -> 42
# 39| call to puts
#-----| -> case ...
# 39| self
#-----| -> 42
# 39| 42
#-----| -> call to puts
@@ -765,8 +765,8 @@ cfg.rb:
#-----| -> b
# 49| ... == ...
#-----| true -> self
#-----| false -> b
#-----| true -> self
# 49| b
#-----| -> 0
@@ -775,8 +775,8 @@ cfg.rb:
#-----| -> ... == ...
# 49| ... > ...
#-----| true -> self
#-----| false -> chained
#-----| true -> self
# 49| b
#-----| -> 1
@@ -1414,14 +1414,20 @@ cfg.rb:
# 124| 2
#-----| -> ... = ...
# 125| ... += ...
# 125| some
#-----| -> some
# 125| ... = ...
#-----| -> last
# 125| ... + ...
#-----| -> ... = ...
# 125| some
#-----| -> 10
# 125| 10
#-----| -> ... += ...
#-----| -> ... + ...
# 126| ... = ...
#-----| -> range
@@ -1514,8 +1520,8 @@ cfg.rb:
#-----| -> ... rescue ...
# 136| ... / ...
#-----| raise -> self
#-----| -> init
#-----| raise -> self
# 136| 1
#-----| -> 0
@@ -1850,14 +1856,20 @@ cfg.rb:
# 176| do ...
#-----| -> x
# 176| ... += ...
# 176| x
#-----| -> x
# 176| ... = ...
#-----| -> self
# 176| ... + ...
#-----| -> ... = ...
# 176| x
#-----| -> 10
# 176| 10
#-----| -> ... += ...
#-----| -> ... + ...
# 176| call to puts
#-----| -> do ...
@@ -1892,14 +1904,20 @@ cfg.rb:
# 179| "hello"
#-----| -> call to puts
# 179| ... += ...
# 179| i
#-----| -> i
# 179| ... = ...
#-----| -> ( ... )
# 179| ... + ...
#-----| -> ... = ...
# 179| i
#-----| -> 1
# 179| 1
#-----| -> ... += ...
#-----| -> ... + ...
# 179| ... == ...
#-----| true -> ... until ...
@@ -1936,14 +1954,20 @@ cfg.rb:
# 182| do ...
#-----| -> x
# 183| ... += ...
# 183| x
#-----| -> x
# 183| ... = ...
#-----| -> x
# 183| ... + ...
#-----| -> ... = ...
# 183| x
#-----| -> 1
# 183| 1
#-----| -> ... += ...
#-----| -> ... + ...
# 184| if ...
#-----| -> self
@@ -1985,14 +2009,20 @@ cfg.rb:
# 188| "hello"
#-----| -> call to puts
# 188| ... -= ...
# 188| i
#-----| -> i
# 188| ... = ...
#-----| -> ( ... )
# 188| ... - ...
#-----| -> ... = ...
# 188| i
#-----| -> 1
# 188| 1
#-----| -> ... -= ...
#-----| -> ... - ...
# 188| ... != ...
#-----| false -> ... while ...
@@ -2050,6 +2080,201 @@ cfg.rb:
# 194| x
#-----| -> call to puts
desugar.rb:
# 1| enter m1
#-----| -> x
# 1| enter desugar.rb
#-----| -> m1
# 1| m1
#-----| -> m2
# 1| exit m1
# 1| exit desugar.rb
# 1| exit m1 (normal)
#-----| -> exit m1
# 1| exit desugar.rb (normal)
#-----| -> exit desugar.rb
# 1| x
#-----| -> x
# 2| x
#-----| -> x
# 2| ... = ...
#-----| -> exit m1 (normal)
# 2| ... + ...
#-----| -> ... = ...
# 2| x
#-----| -> 1
# 2| 1
#-----| -> ... + ...
# 5| enter m2
#-----| -> x
# 5| m2
#-----| -> m3
# 5| exit m2
# 5| exit m2 (normal)
#-----| -> exit m2
# 5| x
#-----| -> x
# 6| ... += ...
#-----| -> exit m2 (normal)
# 6| call to count/count=
#-----| -> 1
# 6| call to foo
#-----| -> call to count/count=
# 6| x
#-----| -> call to foo
# 6| 1
#-----| -> ... += ...
# 9| enter m3
#-----| -> x
# 9| m3
#-----| -> @x
# 9| exit m3
# 9| exit m3 (normal)
#-----| -> exit m3
# 9| x
#-----| -> y
# 9| y
#-----| -> x
# 10| ... += ...
#-----| -> exit m3 (normal)
# 10| ...[...]
#-----| -> 1
# 10| call to foo
#-----| -> 0
# 10| x
#-----| -> call to foo
# 10| 0
#-----| -> y
# 10| call to bar
#-----| -> x
# 10| y
#-----| -> call to bar
# 10| ... + ...
#-----| -> ...[...]
# 10| call to baz
#-----| -> 3
# 10| x
#-----| -> call to baz
# 10| 3
#-----| -> ... + ...
# 10| 1
#-----| -> ... += ...
# 13| X
#-----| -> $global_var
# 14| ... = ...
#-----| -> @x
# 14| @x
#-----| -> 1
# 14| 1
#-----| -> ... = ...
# 15| @x
#-----| -> @x
# 15| ... = ...
#-----| -> @@y
# 15| ... + ...
#-----| -> ... = ...
# 15| @x
#-----| -> 2
# 15| 2
#-----| -> ... + ...
# 17| ... = ...
#-----| -> @@y
# 17| @@y
#-----| -> 3
# 17| 3
#-----| -> ... = ...
# 18| @@y
#-----| -> @@y
# 18| ... = ...
#-----| -> X
# 18| ... / ...
#-----| -> ... = ...
# 18| @@y
#-----| -> 4
# 18| 4
#-----| -> ... / ...
# 21| ... = ...
#-----| -> $global_var
# 21| $global_var
#-----| -> 5
# 21| 5
#-----| -> ... = ...
# 22| $global_var
#-----| -> $global_var
# 22| ... = ...
#-----| -> exit desugar.rb (normal)
# 22| ... * ...
#-----| -> ... = ...
# 22| $global_var
#-----| -> 6
# 22| 6
#-----| -> ... * ...
exit.rb:
# 1| enter m1
#-----| -> x
@@ -2214,8 +2439,8 @@ ifs.rb:
#-----| -> exit m1 (normal)
# 2| ... > ...
#-----| true -> self
#-----| false -> x
#-----| true -> self
# 2| x
#-----| -> 2
@@ -2726,14 +2951,20 @@ loops.rb:
# 3| x
#-----| -> call to puts
# 4| ... -= ...
# 4| x
#-----| -> x
# 4| ... = ...
#-----| -> do ...
# 4| ... - ...
#-----| -> ... = ...
# 4| x
#-----| -> 1
# 4| 1
#-----| -> ... -= ...
#-----| -> ... - ...
# 8| enter m2
#-----| -> x
@@ -2774,14 +3005,20 @@ loops.rb:
# 10| x
#-----| -> call to puts
# 11| ... -= ...
# 11| x
#-----| -> x
# 11| ... = ...
#-----| -> x
# 11| ... - ...
#-----| -> ... = ...
# 11| x
#-----| -> 1
# 11| 1
#-----| -> ... -= ...
#-----| -> ... - ...
# 12| if ...
#-----| -> self
@@ -3302,8 +3539,8 @@ raise.rb:
#-----| -> self
# 69| ... > ...
#-----| true -> self
#-----| false -> x
#-----| true -> self
# 69| x
#-----| -> 2
@@ -3414,8 +3651,8 @@ raise.rb:
#-----| -> self
# 82| ... > ...
#-----| true -> self
#-----| false -> x
#-----| true -> self
# 82| x
#-----| -> 2
@@ -3541,8 +3778,8 @@ raise.rb:
#-----| -> self
# 97| ... > ...
#-----| true -> self
#-----| false -> x
#-----| true -> self
# 97| x
#-----| -> 2

View File

@@ -0,0 +1,9 @@
/**
* @kind graph
*/
import codeql_ruby.controlflow.internal.Cfg
class MyRelevantCfgNode extends RelevantCfgNode {
MyRelevantCfgNode() { exists(this) }
}

View File

@@ -1 +0,0 @@
codeql_ruby/controlflow/internal/Cfg.ql

View File

@@ -0,0 +1,22 @@
def m1 x
x += 1
end
def m2 x
x.foo.count += 1
end
def m3 x, y
x.foo[0, y.bar, x.baz + 3] += 1
end
class X
@x = 1
@x += 2
@@y = 3
@@y /= 4
end
$global_var = 5
$global_var *= 6

View File

@@ -14,9 +14,10 @@
| local_dataflow.rb:5:7:5:13 | ( ... ) | local_dataflow.rb:5:3:5:13 | ... = ... |
| local_dataflow.rb:5:8:5:12 | ... = ... | local_dataflow.rb:5:7:5:13 | ( ... ) |
| local_dataflow.rb:5:12:5:12 | a | local_dataflow.rb:5:8:5:12 | ... = ... |
| local_dataflow.rb:5:12:5:12 | a | local_dataflow.rb:6:8:6:8 | a |
| local_dataflow.rb:5:12:5:12 | a | local_dataflow.rb:6:8:6:13 | a |
| local_dataflow.rb:6:7:6:14 | ( ... ) | local_dataflow.rb:6:3:6:14 | ... = ... |
| local_dataflow.rb:6:8:6:13 | ... += ... | local_dataflow.rb:6:7:6:14 | ( ... ) |
| local_dataflow.rb:6:8:6:13 | ... + ... | local_dataflow.rb:6:8:6:13 | ... = ... |
| local_dataflow.rb:6:8:6:13 | ... = ... | local_dataflow.rb:6:7:6:14 | ( ... ) |
| local_dataflow.rb:9:1:9:15 | ... = ... | local_dataflow.rb:10:14:10:18 | array |
| local_dataflow.rb:9:9:9:15 | [...] | local_dataflow.rb:9:1:9:15 | ... = ... |
| local_dataflow.rb:9:9:9:15 | [...] | local_dataflow.rb:9:1:9:15 | ... = ... |

View File

@@ -42,7 +42,7 @@ definition
| scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a |
| scopes.rb:7:1:7:5 | ... = ... | scopes.rb:7:1:7:1 | a |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a |
| scopes.rb:11:4:11:9 | ... += ... | scopes.rb:7:1:7:1 | a |
| scopes.rb:11:4:11:9 | ... = ... | scopes.rb:7:1:7:1 | a |
| scopes.rb:13:4:13:32 | ... = ... | scopes.rb:7:1:7:1 | a |
| scopes.rb:13:4:13:32 | ... = ... | scopes.rb:13:7:13:7 | b |
| scopes.rb:13:4:13:32 | ... = ... | scopes.rb:13:11:13:11 | c |
@@ -55,7 +55,7 @@ definition
| ssa.rb:10:5:10:9 | ... = ... | ssa.rb:2:3:2:3 | i |
| ssa.rb:18:8:18:8 | x | ssa.rb:18:8:18:8 | x |
| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x |
| ssa.rb:21:5:21:10 | ... -= ... | ssa.rb:18:8:18:8 | x |
| ssa.rb:21:5:21:10 | ... = ... | ssa.rb:18:8:18:8 | x |
| ssa.rb:25:1:30:3 | <uninitialized> | ssa.rb:26:7:26:10 | elem |
| ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements |
| ssa.rb:26:7:26:10 | elem | ssa.rb:26:7:26:10 | elem |
@@ -72,13 +72,13 @@ definition
| ssa.rb:53:8:53:10 | foo | ssa.rb:53:8:53:10 | foo |
| ssa.rb:54:3:54:11 | ... = ... | ssa.rb:54:3:54:3 | x |
| ssa.rb:59:3:59:8 | ... = ... | ssa.rb:59:3:59:3 | x |
| ssa.rb:60:3:60:9 | ... += ... | ssa.rb:59:3:59:3 | x |
| ssa.rb:60:3:60:9 | ... = ... | ssa.rb:59:3:59:3 | x |
| ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a |
| ssa.rb:65:3:65:15 | ... = ... | ssa.rb:65:3:65:10 | captured |
| ssa.rb:66:3:70:5 | call to times | ssa.rb:65:3:65:10 | captured |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured |
| ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a |
| ssa.rb:69:5:69:17 | ... += ... | ssa.rb:65:3:65:10 | captured |
| ssa.rb:69:5:69:17 | ... = ... | ssa.rb:65:3:65:10 | captured |
| ssa.rb:75:3:75:14 | ... = ... | ssa.rb:75:3:75:10 | captured |
| ssa.rb:76:7:78:5 | <captured> | ssa.rb:75:3:75:10 | captured |
| ssa.rb:82:3:82:14 | ... = ... | ssa.rb:82:3:82:10 | captured |
@@ -124,8 +124,8 @@ read
| scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a |
| scopes.rb:7:1:7:5 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:8:6:8:6 | a |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:4 | a |
| scopes.rb:11:4:11:9 | ... += ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:9 | a |
| scopes.rb:11:4:11:9 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a |
| scopes.rb:13:4:13:32 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:14:9:14:9 | a |
| scopes.rb:13:4:13:32 | ... = ... | scopes.rb:13:7:13:7 | b | scopes.rb:15:9:15:9 | b |
| scopes.rb:13:4:13:32 | ... = ... | scopes.rb:13:11:13:11 | c | scopes.rb:16:9:16:9 | c |
@@ -145,7 +145,7 @@ read
| ssa.rb:10:5:10:9 | ... = ... | ssa.rb:2:3:2:3 | i | ssa.rb:12:10:12:10 | i |
| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:19:9:19:9 | x |
| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:20:10:20:10 | x |
| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:21:5:21:5 | x |
| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:21:5:21:10 | x |
| ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:26:15:26:22 | elements |
| ssa.rb:26:7:26:10 | elem | ssa.rb:26:7:26:10 | elem | ssa.rb:27:10:27:13 | elem |
| ssa.rb:26:12:26:22 | phi | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem |
@@ -156,12 +156,12 @@ read
| ssa.rb:50:3:50:8 | phi | ssa.rb:49:14:49:14 | y | ssa.rb:50:8:50:8 | y |
| ssa.rb:53:8:53:10 | foo | ssa.rb:53:8:53:10 | foo | ssa.rb:54:7:54:9 | foo |
| ssa.rb:54:3:54:11 | ... = ... | ssa.rb:54:3:54:3 | x | ssa.rb:55:8:55:8 | x |
| ssa.rb:59:3:59:8 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:60:3:60:3 | x |
| ssa.rb:60:3:60:9 | ... += ... | ssa.rb:59:3:59:3 | x | ssa.rb:61:8:61:8 | x |
| ssa.rb:59:3:59:8 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:60:3:60:9 | x |
| ssa.rb:60:3:60:9 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:61:8:61:8 | x |
| ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | ssa.rb:66:3:66:3 | a |
| ssa.rb:66:3:70:5 | call to times | ssa.rb:65:3:65:10 | captured | ssa.rb:71:8:71:15 | captured |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured | ssa.rb:69:5:69:12 | captured |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured | ssa.rb:69:5:69:17 | captured |
| ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a | ssa.rb:67:10:67:10 | a |
| ssa.rb:76:7:78:5 | <captured> | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured |
| ssa.rb:84:10:86:8 | <captured> | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured |
@@ -204,7 +204,7 @@ firstRead
| scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a |
| scopes.rb:7:1:7:5 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:8:6:8:6 | a |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a |
| scopes.rb:11:4:11:9 | ... += ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a |
| scopes.rb:11:4:11:9 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a |
| scopes.rb:13:4:13:32 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:14:9:14:9 | a |
| scopes.rb:13:4:13:32 | ... = ... | scopes.rb:13:7:13:7 | b | scopes.rb:15:9:15:9 | b |
| scopes.rb:13:4:13:32 | ... = ... | scopes.rb:13:11:13:11 | c | scopes.rb:16:9:16:9 | c |
@@ -226,8 +226,8 @@ firstRead
| ssa.rb:50:3:50:8 | phi | ssa.rb:49:14:49:14 | y | ssa.rb:50:8:50:8 | y |
| ssa.rb:53:8:53:10 | foo | ssa.rb:53:8:53:10 | foo | ssa.rb:54:7:54:9 | foo |
| ssa.rb:54:3:54:11 | ... = ... | ssa.rb:54:3:54:3 | x | ssa.rb:55:8:55:8 | x |
| ssa.rb:59:3:59:8 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:60:3:60:3 | x |
| ssa.rb:60:3:60:9 | ... += ... | ssa.rb:59:3:59:3 | x | ssa.rb:61:8:61:8 | x |
| ssa.rb:59:3:59:8 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:60:3:60:9 | x |
| ssa.rb:60:3:60:9 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:61:8:61:8 | x |
| ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | ssa.rb:66:3:66:3 | a |
| ssa.rb:66:3:70:5 | call to times | ssa.rb:65:3:65:10 | captured | ssa.rb:71:8:71:15 | captured |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured |
@@ -272,8 +272,8 @@ lastRead
| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:55:9:55:9 | x |
| scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a |
| scopes.rb:7:1:7:5 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:8:6:8:6 | a |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:4 | a |
| scopes.rb:11:4:11:9 | ... += ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:9 | a |
| scopes.rb:11:4:11:9 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a |
| scopes.rb:13:4:13:32 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:14:9:14:9 | a |
| scopes.rb:13:4:13:32 | ... = ... | scopes.rb:13:7:13:7 | b | scopes.rb:15:9:15:9 | b |
| scopes.rb:13:4:13:32 | ... = ... | scopes.rb:13:11:13:11 | c | scopes.rb:16:9:16:9 | c |
@@ -285,7 +285,7 @@ lastRead
| ssa.rb:6:5:6:9 | ... = ... | ssa.rb:2:3:2:3 | i | ssa.rb:8:10:8:10 | i |
| ssa.rb:10:5:10:9 | ... = ... | ssa.rb:2:3:2:3 | i | ssa.rb:12:10:12:10 | i |
| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:19:9:19:9 | x |
| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:21:5:21:5 | x |
| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:21:5:21:10 | x |
| ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:26:15:26:22 | elements |
| ssa.rb:26:7:26:10 | elem | ssa.rb:26:7:26:10 | elem | ssa.rb:27:10:27:13 | elem |
| ssa.rb:26:12:26:22 | phi | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem |
@@ -296,11 +296,11 @@ lastRead
| ssa.rb:50:3:50:8 | phi | ssa.rb:49:14:49:14 | y | ssa.rb:50:8:50:8 | y |
| ssa.rb:53:8:53:10 | foo | ssa.rb:53:8:53:10 | foo | ssa.rb:54:7:54:9 | foo |
| ssa.rb:54:3:54:11 | ... = ... | ssa.rb:54:3:54:3 | x | ssa.rb:55:8:55:8 | x |
| ssa.rb:59:3:59:8 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:60:3:60:3 | x |
| ssa.rb:60:3:60:9 | ... += ... | ssa.rb:59:3:59:3 | x | ssa.rb:61:8:61:8 | x |
| ssa.rb:59:3:59:8 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:60:3:60:9 | x |
| ssa.rb:60:3:60:9 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:61:8:61:8 | x |
| ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | ssa.rb:66:3:66:3 | a |
| ssa.rb:66:3:70:5 | call to times | ssa.rb:65:3:65:10 | captured | ssa.rb:71:8:71:15 | captured |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured | ssa.rb:69:5:69:12 | captured |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured | ssa.rb:69:5:69:17 | captured |
| ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a | ssa.rb:67:10:67:10 | a |
| ssa.rb:76:7:78:5 | <captured> | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured |
| ssa.rb:84:10:86:8 | <captured> | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured |
@@ -308,7 +308,7 @@ adjacentReads
| nested_scopes.rb:13:11:13:15 | ... = ... | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:14:16:14:16 | a | nested_scopes.rb:15:11:15:11 | a |
| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas | parameters.rb:11:14:11:19 | pizzas |
| parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:40:25:43 | name | parameters.rb:26:8:26:11 | name |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | scopes.rb:11:4:11:4 | a |
| scopes.rb:9:9:18:3 | <captured> | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | scopes.rb:11:4:11:9 | a |
| scopes.rb:27:1:27:5 | ... = ... | scopes.rb:27:1:27:1 | x | scopes.rb:28:8:28:8 | x | scopes.rb:31:10:31:10 | x |
| scopes.rb:27:1:27:5 | ... = ... | scopes.rb:27:1:27:1 | x | scopes.rb:31:10:31:10 | x | scopes.rb:34:7:34:7 | x |
| scopes.rb:27:1:27:5 | ... = ... | scopes.rb:27:1:27:1 | x | scopes.rb:34:7:34:7 | x | scopes.rb:34:14:34:14 | x |
@@ -317,8 +317,8 @@ adjacentReads
| ssa.rb:6:5:6:9 | ... = ... | ssa.rb:2:3:2:3 | i | ssa.rb:7:10:7:10 | i | ssa.rb:8:10:8:10 | i |
| ssa.rb:10:5:10:9 | ... = ... | ssa.rb:2:3:2:3 | i | ssa.rb:11:10:11:10 | i | ssa.rb:12:10:12:10 | i |
| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:19:9:19:9 | x | ssa.rb:20:10:20:10 | x |
| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:20:10:20:10 | x | ssa.rb:21:5:21:5 | x |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured | ssa.rb:69:5:69:12 | captured |
| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:20:10:20:10 | x | ssa.rb:21:5:21:10 | x |
| ssa.rb:66:11:70:5 | <captured> | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured | ssa.rb:69:5:69:17 | captured |
phi
| parameters.rb:37:3:37:18 | phi | parameters.rb:35:16:35:16 | b | parameters.rb:35:1:38:3 | <uninitialized> |
| parameters.rb:37:3:37:18 | phi | parameters.rb:35:16:35:16 | b | parameters.rb:35:16:35:20 | ... = ... |
@@ -329,7 +329,7 @@ phi
| ssa.rb:5:3:13:5 | phi | ssa.rb:2:3:2:3 | i | ssa.rb:6:5:6:9 | ... = ... |
| ssa.rb:5:3:13:5 | phi | ssa.rb:2:3:2:3 | i | ssa.rb:10:5:10:9 | ... = ... |
| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:18:8:18:8 | x |
| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:21:5:21:10 | ... -= ... |
| ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:21:5:21:10 | ... = ... |
| ssa.rb:26:12:26:22 | phi | ssa.rb:26:7:26:10 | elem | ssa.rb:25:1:30:3 | <uninitialized> |
| ssa.rb:26:12:26:22 | phi | ssa.rb:26:7:26:10 | elem | ssa.rb:26:7:26:10 | elem |
| ssa.rb:45:3:45:12 | phi | ssa.rb:45:3:45:3 | x | ssa.rb:44:1:47:3 | <uninitialized> |

View File

@@ -103,6 +103,7 @@ variableAccess
| scopes.rb:9:14:9:14 | x | scopes.rb:9:14:9:14 | x | scopes.rb:9:9:18:3 | do ... end |
| scopes.rb:10:9:10:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | scopes.rb |
| scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | scopes.rb |
| scopes.rb:11:4:11:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | scopes.rb |
| scopes.rb:12:9:12:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | scopes.rb |
| scopes.rb:13:4:13:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:40:1 | scopes.rb |
| scopes.rb:13:7:13:7 | b | scopes.rb:13:7:13:7 | b | scopes.rb:9:9:18:3 | do ... end |
@@ -139,6 +140,7 @@ variableAccess
| ssa.rb:19:9:19:9 | x | ssa.rb:18:8:18:8 | x | ssa.rb:18:1:23:3 | m1 |
| ssa.rb:20:10:20:10 | x | ssa.rb:18:8:18:8 | x | ssa.rb:18:1:23:3 | m1 |
| ssa.rb:21:5:21:5 | x | ssa.rb:18:8:18:8 | x | ssa.rb:18:1:23:3 | m1 |
| ssa.rb:21:5:21:10 | x | ssa.rb:18:8:18:8 | x | ssa.rb:18:1:23:3 | m1 |
| ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:25:1:30:3 | m2 |
| ssa.rb:26:7:26:10 | elem | ssa.rb:26:7:26:10 | elem | ssa.rb:25:1:30:3 | m2 |
| ssa.rb:26:15:26:22 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:25:1:30:3 | m2 |
@@ -161,6 +163,7 @@ variableAccess
| ssa.rb:55:8:55:8 | x | ssa.rb:54:3:54:3 | x | ssa.rb:53:1:56:3 | m7 |
| ssa.rb:59:3:59:3 | x | ssa.rb:59:3:59:3 | x | ssa.rb:58:1:62:3 | m8 |
| ssa.rb:60:3:60:3 | x | ssa.rb:59:3:59:3 | x | ssa.rb:58:1:62:3 | m8 |
| ssa.rb:60:3:60:9 | x | ssa.rb:59:3:59:3 | x | ssa.rb:58:1:62:3 | m8 |
| ssa.rb:61:8:61:8 | x | ssa.rb:59:3:59:3 | x | ssa.rb:58:1:62:3 | m8 |
| ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | ssa.rb:64:1:72:3 | m9 |
| ssa.rb:65:3:65:10 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:64:1:72:3 | m9 |
@@ -169,6 +172,7 @@ variableAccess
| ssa.rb:67:10:67:10 | a | ssa.rb:66:15:66:15 | a | ssa.rb:66:11:70:5 | do ... end |
| ssa.rb:68:10:68:17 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:64:1:72:3 | m9 |
| ssa.rb:69:5:69:12 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:64:1:72:3 | m9 |
| ssa.rb:69:5:69:17 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:64:1:72:3 | m9 |
| ssa.rb:71:8:71:15 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:64:1:72:3 | m9 |
| ssa.rb:75:3:75:10 | captured | ssa.rb:75:3:75:10 | captured | ssa.rb:74:1:79:3 | m10 |
| ssa.rb:77:15:77:22 | captured | ssa.rb:75:3:75:10 | captured | ssa.rb:74:1:79:3 | m10 |
@@ -205,6 +209,7 @@ explicitWrite
| scopes.rb:4:4:4:4 | a | scopes.rb:4:4:4:8 | ... = ... |
| scopes.rb:7:1:7:1 | a | scopes.rb:7:1:7:5 | ... = ... |
| scopes.rb:11:4:11:4 | a | scopes.rb:11:4:11:9 | ... += ... |
| scopes.rb:11:4:11:4 | a | scopes.rb:11:4:11:9 | ... = ... |
| scopes.rb:13:4:13:4 | a | scopes.rb:13:4:13:32 | ... = ... |
| scopes.rb:13:7:13:7 | b | scopes.rb:13:4:13:32 | ... = ... |
| scopes.rb:13:11:13:11 | c | scopes.rb:13:4:13:32 | ... = ... |
@@ -220,14 +225,17 @@ explicitWrite
| ssa.rb:6:5:6:5 | i | ssa.rb:6:5:6:9 | ... = ... |
| ssa.rb:10:5:10:5 | i | ssa.rb:10:5:10:9 | ... = ... |
| ssa.rb:21:5:21:5 | x | ssa.rb:21:5:21:10 | ... -= ... |
| ssa.rb:21:5:21:5 | x | ssa.rb:21:5:21:10 | ... = ... |
| ssa.rb:40:3:40:4 | m3 | ssa.rb:40:3:40:9 | ... = ... |
| ssa.rb:45:3:45:3 | x | ssa.rb:45:3:45:7 | ... = ... |
| ssa.rb:49:14:49:14 | y | ssa.rb:49:14:49:19 | ... = ... |
| ssa.rb:54:3:54:3 | x | ssa.rb:54:3:54:11 | ... = ... |
| ssa.rb:59:3:59:3 | x | ssa.rb:59:3:59:8 | ... = ... |
| ssa.rb:60:3:60:3 | x | ssa.rb:60:3:60:9 | ... += ... |
| ssa.rb:60:3:60:3 | x | ssa.rb:60:3:60:9 | ... = ... |
| ssa.rb:65:3:65:10 | captured | ssa.rb:65:3:65:15 | ... = ... |
| ssa.rb:69:5:69:12 | captured | ssa.rb:69:5:69:17 | ... += ... |
| ssa.rb:69:5:69:12 | captured | ssa.rb:69:5:69:17 | ... = ... |
| ssa.rb:75:3:75:10 | captured | ssa.rb:75:3:75:14 | ... = ... |
| ssa.rb:82:3:82:10 | captured | ssa.rb:82:3:82:14 | ... = ... |
implicitWrite
@@ -316,7 +324,7 @@ readAccess
| scopes.rb:5:9:5:9 | a |
| scopes.rb:8:6:8:6 | a |
| scopes.rb:10:9:10:9 | a |
| scopes.rb:11:4:11:4 | a |
| scopes.rb:11:4:11:9 | a |
| scopes.rb:12:9:12:9 | a |
| scopes.rb:14:9:14:9 | a |
| scopes.rb:15:9:15:9 | b |
@@ -338,7 +346,7 @@ readAccess
| ssa.rb:15:8:15:8 | i |
| ssa.rb:19:9:19:9 | x |
| ssa.rb:20:10:20:10 | x |
| ssa.rb:21:5:21:5 | x |
| ssa.rb:21:5:21:10 | x |
| ssa.rb:26:15:26:22 | elements |
| ssa.rb:27:10:27:13 | elem |
| ssa.rb:29:8:29:11 | elem |
@@ -349,12 +357,12 @@ readAccess
| ssa.rb:50:8:50:8 | y |
| ssa.rb:54:7:54:9 | foo |
| ssa.rb:55:8:55:8 | x |
| ssa.rb:60:3:60:3 | x |
| ssa.rb:60:3:60:9 | x |
| ssa.rb:61:8:61:8 | x |
| ssa.rb:66:3:66:3 | a |
| ssa.rb:67:10:67:10 | a |
| ssa.rb:68:10:68:17 | captured |
| ssa.rb:69:5:69:12 | captured |
| ssa.rb:69:5:69:17 | captured |
| ssa.rb:71:8:71:15 | captured |
| ssa.rb:77:15:77:22 | captured |
| ssa.rb:85:15:85:22 | captured |

View File

@@ -0,0 +1,5 @@
| src/not_ruby.rb:5:25:5:26 | parse error | Extraction failed in src/not_ruby.rb with error parse error | 2 |
| src/unsupported_feature.rb:2:18:2:20 | parse error | Extraction failed in src/unsupported_feature.rb with error parse error | 2 |
| src/unsupported_feature.rb:3:13:3:15 | parse error | Extraction failed in src/unsupported_feature.rb with error parse error | 2 |
| src/unsupported_feature.rb:6:15:6:17 | parse error | Extraction failed in src/unsupported_feature.rb with error parse error | 2 |
| src/unsupported_feature.rb:7:20:7:22 | parse error | Extraction failed in src/unsupported_feature.rb with error parse error | 2 |

View File

@@ -0,0 +1 @@
queries/diagnostics/ExtractionErrors.ql

View File

@@ -0,0 +1 @@
queries/summary/NumberOfFilesExtractedWithErrors.ql

View File

@@ -0,0 +1 @@
queries/summary/NumberOfSuccessfullyExtractedFiles.ql

View File

@@ -0,0 +1,2 @@
| src/foo.rb:0:0:0:0 | src/foo.rb | |
| src/vendor/cache/lib.rb:0:0:0:0 | src/vendor/cache/lib.rb | |

View File

@@ -0,0 +1 @@
queries/diagnostics/SuccessfullyExtractedFiles.ql

View File

@@ -0,0 +1,9 @@
# comment
def hello
p "hello world"
end
# another one
hello

View File

@@ -0,0 +1,5 @@
#!/bin/bash
# This is a bash script
export FOO="$(whereis ls)"
exec "$FOO" "$(dirname "$0")"

View File

@@ -0,0 +1,17 @@
class Foo
def initialize(...)
do_init(...)
end
def do_init(...)
really_do_init(...)
end
def really_do_init(bar, baz:, &block)
puts bar
puts baz
block.call
end
end
Foo.new("hello", baz: "world") { || puts "!" }

View File

@@ -0,0 +1,9 @@
# comment
def hello
p "hello lib"
end
# another one
hello

View File

@@ -0,0 +1,58 @@
require "fileutils"
def run_chmod_1(filename)
FileUtils.chmod 0222, filename
FileUtils.chmod 0622, filename
FileUtils.chmod 0755, filename
FileUtils.chmod 0777, filename
end
module DummyModule
def chmod(mode, list, options = {} )
list
end
end
def run_chmod_2(filename)
foo = FileUtils
bar = foo
baz = Dummy
# "safe"
baz.chmod 0755, filename
baz = bar
# unsafe
baz.chmod 0755, filename
end
def run_chmod_3(filename)
# TODO: we currently miss this
foo = FileUtils
bar, baz = foo, 7
bar.chmod 0755, filename
end
def run_chmod_4(filename)
# safe permissions
FileUtils.chmod 0700, filename
FileUtils.chmod 0711, filename
FileUtils.chmod 0701, filename
FileUtils.chmod 0710, filename
end
def run_chmod_5(filename)
perm = 0777
FileUtils.chmod perm, filename
perm2 = perm
FileUtils.chmod perm2, filename
perm = "u=wrx,g=rwx,o=x"
perm2 = perm
FileUtils.chmod perm2, filename
FileUtils.chmod "u=rwx,o+r", filename
FileUtils.chmod "u=rwx,go-r", filename
FileUtils.chmod "a+rw", filename
end
def run_chmod_R(filename)
File.chmod_R 0755, filename
end

View File

@@ -0,0 +1,30 @@
edges
| FilePermissions.rb:43:10:43:13 | 0777 : | FilePermissions.rb:44:19:44:22 | perm |
| FilePermissions.rb:43:10:43:13 | 0777 : | FilePermissions.rb:46:19:46:23 | perm2 |
| FilePermissions.rb:48:10:48:26 | "u=wrx,g=rwx,o=x" : | FilePermissions.rb:50:19:50:23 | perm2 |
nodes
| FilePermissions.rb:4:19:4:22 | 0222 | semmle.label | 0222 |
| FilePermissions.rb:5:19:5:22 | 0622 | semmle.label | 0622 |
| FilePermissions.rb:6:19:6:22 | 0755 | semmle.label | 0755 |
| FilePermissions.rb:7:19:7:22 | 0777 | semmle.label | 0777 |
| FilePermissions.rb:24:13:24:16 | 0755 | semmle.label | 0755 |
| FilePermissions.rb:43:10:43:13 | 0777 : | semmle.label | 0777 : |
| FilePermissions.rb:44:19:44:22 | perm | semmle.label | perm |
| FilePermissions.rb:46:19:46:23 | perm2 | semmle.label | perm2 |
| FilePermissions.rb:48:10:48:26 | "u=wrx,g=rwx,o=x" : | semmle.label | "u=wrx,g=rwx,o=x" : |
| FilePermissions.rb:50:19:50:23 | perm2 | semmle.label | perm2 |
| FilePermissions.rb:51:19:51:29 | "u=rwx,o+r" | semmle.label | "u=rwx,o+r" |
| FilePermissions.rb:53:19:53:24 | "a+rw" | semmle.label | "a+rw" |
| FilePermissions.rb:57:16:57:19 | 0755 | semmle.label | 0755 |
#select
| FilePermissions.rb:4:19:4:22 | 0222 | FilePermissions.rb:4:19:4:22 | 0222 | FilePermissions.rb:4:19:4:22 | 0222 | Overly permissive mask sets file to $@. | FilePermissions.rb:4:19:4:22 | 0222 | 0222 |
| FilePermissions.rb:5:19:5:22 | 0622 | FilePermissions.rb:5:19:5:22 | 0622 | FilePermissions.rb:5:19:5:22 | 0622 | Overly permissive mask sets file to $@. | FilePermissions.rb:5:19:5:22 | 0622 | 0622 |
| FilePermissions.rb:6:19:6:22 | 0755 | FilePermissions.rb:6:19:6:22 | 0755 | FilePermissions.rb:6:19:6:22 | 0755 | Overly permissive mask sets file to $@. | FilePermissions.rb:6:19:6:22 | 0755 | 0755 |
| FilePermissions.rb:7:19:7:22 | 0777 | FilePermissions.rb:7:19:7:22 | 0777 | FilePermissions.rb:7:19:7:22 | 0777 | Overly permissive mask sets file to $@. | FilePermissions.rb:7:19:7:22 | 0777 | 0777 |
| FilePermissions.rb:24:13:24:16 | 0755 | FilePermissions.rb:24:13:24:16 | 0755 | FilePermissions.rb:24:13:24:16 | 0755 | Overly permissive mask sets file to $@. | FilePermissions.rb:24:13:24:16 | 0755 | 0755 |
| FilePermissions.rb:44:19:44:22 | perm | FilePermissions.rb:43:10:43:13 | 0777 : | FilePermissions.rb:44:19:44:22 | perm | Overly permissive mask sets file to $@. | FilePermissions.rb:43:10:43:13 | 0777 | 0777 |
| FilePermissions.rb:46:19:46:23 | perm2 | FilePermissions.rb:43:10:43:13 | 0777 : | FilePermissions.rb:46:19:46:23 | perm2 | Overly permissive mask sets file to $@. | FilePermissions.rb:43:10:43:13 | 0777 | 0777 |
| FilePermissions.rb:50:19:50:23 | perm2 | FilePermissions.rb:48:10:48:26 | "u=wrx,g=rwx,o=x" : | FilePermissions.rb:50:19:50:23 | perm2 | Overly permissive mask sets file to $@. | FilePermissions.rb:48:10:48:26 | "u=wrx,g=rwx,o=x" | "u=wrx,g=rwx,o=x" |
| FilePermissions.rb:51:19:51:29 | "u=rwx,o+r" | FilePermissions.rb:51:19:51:29 | "u=rwx,o+r" | FilePermissions.rb:51:19:51:29 | "u=rwx,o+r" | Overly permissive mask sets file to $@. | FilePermissions.rb:51:19:51:29 | "u=rwx,o+r" | "u=rwx,o+r" |
| FilePermissions.rb:53:19:53:24 | "a+rw" | FilePermissions.rb:53:19:53:24 | "a+rw" | FilePermissions.rb:53:19:53:24 | "a+rw" | Overly permissive mask sets file to $@. | FilePermissions.rb:53:19:53:24 | "a+rw" | "a+rw" |
| FilePermissions.rb:57:16:57:19 | 0755 | FilePermissions.rb:57:16:57:19 | 0755 | FilePermissions.rb:57:16:57:19 | 0755 | Overly permissive mask sets file to $@. | FilePermissions.rb:57:16:57:19 | 0755 | 0755 |

View File

@@ -0,0 +1 @@
queries/security/cwe-732/WeakFilePermissions.ql

View File

@@ -0,0 +1 @@
| 9 |

View File

@@ -0,0 +1 @@
queries/summary/LinesOfCode.ql

View File

@@ -0,0 +1 @@
| 5 |

View File

@@ -0,0 +1 @@
queries/summary/LinesOfUserCode.ql

View File

@@ -0,0 +1,11 @@
# comment
def hello
p "hello foo"
end
# another one
hello
p "more code here"

View File

@@ -0,0 +1,9 @@
# comment
def hello
p "hello lib"
end
# another one
hello

View File

@@ -10,5 +10,9 @@
"DataFlow": [
"codeql/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll",
"ql/src/codeql_ruby/dataflow/internal/DataFlowImpl.qll"
],
"TypeTracker": [
"codeql/python/ql/src/experimental/typetracking/TypeTracker.qll",
"ql/src/codeql_ruby/typetracking/TypeTracker.qll"
]
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Create an empty diagnostics table
compatibility: backwards