mirror of
https://github.com/github/codeql.git
synced 2026-02-19 08:23:45 +01:00
Merge remote-tracking branch 'origin/main' into cfg_cleanup
This commit is contained in:
@@ -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
15
.devcontainer/Dockerfile
Normal 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
|
||||
39
.devcontainer/devcontainer.json
Normal file
39
.devcontainer/devcontainer.json
Normal 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
37
.devcontainer/post_attach.sh
Executable 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
4
.devcontainer/post_create.sh
Executable 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
2
Cargo.lock
generated
@@ -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
2
codeql
Submodule codeql updated: a1ccbcdaf1...6693c5bdd0
@@ -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"
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
52
ql/src/codeql_ruby/Diagnostics.qll
Normal file
52
ql/src/codeql_ruby/Diagnostics.qll
Normal 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" }
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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() }
|
||||
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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())
|
||||
)
|
||||
|
||||
173
ql/src/codeql_ruby/ast/internal/Synthesis.qll
Normal file
173
ql/src/codeql_ruby/ast/internal/Synthesis.qll
Normal 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())
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
32
ql/src/codeql_ruby/controlflow/internal/Cfg.qll
Normal file
32
ql/src/codeql_ruby/controlflow/internal/Cfg.qll
Normal 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()
|
||||
)
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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`. */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
420
ql/src/codeql_ruby/typetracking/TypeTracker.qll
Normal file
420
ql/src/codeql_ruby/typetracking/TypeTracker.qll
Normal 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() }
|
||||
}
|
||||
118
ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll
Normal file
118
ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll
Normal 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 }
|
||||
}
|
||||
18
ql/src/queries/diagnostics/ExtractionErrors.ql
Normal file
18
ql/src/queries/diagnostics/ExtractionErrors.ql
Normal 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()
|
||||
16
ql/src/queries/diagnostics/SuccessfullyExtractedFiles.ql
Normal file
16
ql/src/queries/diagnostics/SuccessfullyExtractedFiles.ql
Normal 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, ""
|
||||
26
ql/src/queries/security/cwe-732/WeakFilePermissions.qhelp
Normal file
26
ql/src/queries/security/cwe-732/WeakFilePermissions.qhelp
Normal 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>
|
||||
99
ql/src/queries/security/cwe-732/WeakFilePermissions.ql
Normal file
99
ql/src/queries/security/cwe-732/WeakFilePermissions.ql
Normal 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()
|
||||
15
ql/src/queries/summary/LinesOfCode.ql
Normal file
15
ql/src/queries/summary/LinesOfCode.ql
Normal 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())
|
||||
19
ql/src/queries/summary/LinesOfUserCode.ql
Normal file
19
ql/src/queries/summary/LinesOfUserCode.ql
Normal 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()
|
||||
)
|
||||
15
ql/src/queries/summary/NumberOfFilesExtractedWithErrors.ql
Normal file
15
ql/src/queries/summary/NumberOfFilesExtractedWithErrors.ql
Normal 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())
|
||||
)
|
||||
15
ql/src/queries/summary/NumberOfSuccessfullyExtractedFiles.ql
Normal file
15
ql/src/queries/summary/NumberOfSuccessfullyExtractedFiles.ql
Normal 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())
|
||||
)
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/**
|
||||
* @kind graph
|
||||
* @id rb/test/print-ast
|
||||
*/
|
||||
|
||||
import codeql_ruby.printAst
|
||||
|
||||
180
ql/test/library-tests/ast/AstDesugar.expected
Normal file
180
ql/test/library-tests/ast/AstDesugar.expected
Normal 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
|
||||
9
ql/test/library-tests/ast/AstDesugar.ql
Normal file
9
ql/test/library-tests/ast/AstDesugar.ql
Normal file
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* @kind graph
|
||||
*/
|
||||
|
||||
import codeql_ruby.printAst
|
||||
|
||||
class DesugarPrintAstConfiguration extends PrintAstConfiguration {
|
||||
override predicate shouldPrintNode(AstNode n) { isDesugared(n) }
|
||||
}
|
||||
@@ -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 | ...[...] |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
9
ql/test/library-tests/controlflow/graph/Cfg.ql
Normal file
9
ql/test/library-tests/controlflow/graph/Cfg.ql
Normal file
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* @kind graph
|
||||
*/
|
||||
|
||||
import codeql_ruby.controlflow.internal.Cfg
|
||||
|
||||
class MyRelevantCfgNode extends RelevantCfgNode {
|
||||
MyRelevantCfgNode() { exists(this) }
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
codeql_ruby/controlflow/internal/Cfg.ql
|
||||
22
ql/test/library-tests/controlflow/graph/desugar.rb
Normal file
22
ql/test/library-tests/controlflow/graph/desugar.rb
Normal 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
|
||||
@@ -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 | ... = ... |
|
||||
|
||||
@@ -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> |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
1
ql/test/query-tests/diagnostics/ExtractionErrors.qlref
Normal file
1
ql/test/query-tests/diagnostics/ExtractionErrors.qlref
Normal file
@@ -0,0 +1 @@
|
||||
queries/diagnostics/ExtractionErrors.ql
|
||||
@@ -0,0 +1 @@
|
||||
| 2 |
|
||||
@@ -0,0 +1 @@
|
||||
queries/summary/NumberOfFilesExtractedWithErrors.ql
|
||||
@@ -0,0 +1 @@
|
||||
| 2 |
|
||||
@@ -0,0 +1 @@
|
||||
queries/summary/NumberOfSuccessfullyExtractedFiles.ql
|
||||
@@ -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 | |
|
||||
@@ -0,0 +1 @@
|
||||
queries/diagnostics/SuccessfullyExtractedFiles.ql
|
||||
9
ql/test/query-tests/diagnostics/src/foo.rb
Normal file
9
ql/test/query-tests/diagnostics/src/foo.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
# comment
|
||||
|
||||
def hello
|
||||
p "hello world"
|
||||
end
|
||||
|
||||
# another one
|
||||
|
||||
hello
|
||||
5
ql/test/query-tests/diagnostics/src/not_ruby.rb
Executable file
5
ql/test/query-tests/diagnostics/src/not_ruby.rb
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This is a bash script
|
||||
export FOO="$(whereis ls)"
|
||||
exec "$FOO" "$(dirname "$0")"
|
||||
17
ql/test/query-tests/diagnostics/src/unsupported_feature.rb
Normal file
17
ql/test/query-tests/diagnostics/src/unsupported_feature.rb
Normal 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 "!" }
|
||||
9
ql/test/query-tests/diagnostics/src/vendor/cache/lib.rb
vendored
Normal file
9
ql/test/query-tests/diagnostics/src/vendor/cache/lib.rb
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
# comment
|
||||
|
||||
def hello
|
||||
p "hello lib"
|
||||
end
|
||||
|
||||
# another one
|
||||
|
||||
hello
|
||||
58
ql/test/query-tests/security/cwe-732/FilePermissions.rb
Normal file
58
ql/test/query-tests/security/cwe-732/FilePermissions.rb
Normal 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
|
||||
@@ -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 |
|
||||
@@ -0,0 +1 @@
|
||||
queries/security/cwe-732/WeakFilePermissions.ql
|
||||
1
ql/test/query-tests/summary/LinesOfCode.expected
Normal file
1
ql/test/query-tests/summary/LinesOfCode.expected
Normal file
@@ -0,0 +1 @@
|
||||
| 9 |
|
||||
1
ql/test/query-tests/summary/LinesOfCode.qlref
Normal file
1
ql/test/query-tests/summary/LinesOfCode.qlref
Normal file
@@ -0,0 +1 @@
|
||||
queries/summary/LinesOfCode.ql
|
||||
1
ql/test/query-tests/summary/LinesOfUserCode.expected
Normal file
1
ql/test/query-tests/summary/LinesOfUserCode.expected
Normal file
@@ -0,0 +1 @@
|
||||
| 5 |
|
||||
1
ql/test/query-tests/summary/LinesOfUserCode.qlref
Normal file
1
ql/test/query-tests/summary/LinesOfUserCode.qlref
Normal file
@@ -0,0 +1 @@
|
||||
queries/summary/LinesOfUserCode.ql
|
||||
11
ql/test/query-tests/summary/src/foo.rb
Normal file
11
ql/test/query-tests/summary/src/foo.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
# comment
|
||||
|
||||
def hello
|
||||
p "hello foo"
|
||||
end
|
||||
|
||||
# another one
|
||||
|
||||
hello
|
||||
|
||||
p "more code here"
|
||||
9
ql/test/query-tests/summary/src/vendor/cache/lib.rb
vendored
Normal file
9
ql/test/query-tests/summary/src/vendor/cache/lib.rb
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
# comment
|
||||
|
||||
def hello
|
||||
p "hello lib"
|
||||
end
|
||||
|
||||
# another one
|
||||
|
||||
hello
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
1250
upgrades/8725deeb2fa6627c45235f18b7c121c35498dac7/old.dbscheme
Normal file
1250
upgrades/8725deeb2fa6627c45235f18b7c121c35498dac7/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
1267
upgrades/8725deeb2fa6627c45235f18b7c121c35498dac7/ruby.dbscheme
Normal file
1267
upgrades/8725deeb2fa6627c45235f18b7c121c35498dac7/ruby.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Create an empty diagnostics table
|
||||
compatibility: backwards
|
||||
Reference in New Issue
Block a user