From c598dc6b5c891ef46e69f1c0d142fa51da26b61b Mon Sep 17 00:00:00 2001 From: Nick Rolfe Date: Wed, 25 Nov 2020 17:53:13 +0000 Subject: [PATCH 1/8] Initial work on user-facing AST library --- .github/workflows/build.yml | 4 +- Cargo.lock | 14 +- README.md | 4 +- create-extractor-pack.ps1 | 2 +- create-extractor-pack.sh | 2 +- extractor/Cargo.toml | 2 +- generator/Cargo.toml | 2 +- generator/src/main.rs | 2 +- generator/src/ql.rs | 2 + ql/src/codeql_ruby/AST.qll | 40 + ql/src/codeql_ruby/Generated.qll | 1540 +++++++++++++++++ ql/src/codeql_ruby/Method.qll | 119 ++ ql/src/codeql_ruby/Parameter.qll | 182 ++ ql/src/codeql_ruby/ast.qll | 1530 ---------------- .../codeql_ruby/controlflow/BasicBlocks.qll | 2 +- .../controlflow/ControlFlowGraph.qll | 2 +- .../controlflow/internal/AstNodes.qll | 2 +- .../controlflow/internal/Completion.qll | 2 +- .../controlflow/internal/Consistency.qll | 2 +- .../internal/ControlFlowGraphImpl.qll | 2 +- .../controlflow/internal/NonReturning.qll | 2 +- .../controlflow/internal/Splitting.qll | 2 +- ql/src/codeql_ruby/printAst.qll | 12 +- ql/src/printAst.ql | 3 +- ql/src/ruby.dbscheme | 16 +- ql/src/ruby.qll | 1 + .../library-tests/ast/params/params.expected | 139 ++ ql/test/library-tests/ast/params/params.ql | 46 + ql/test/library-tests/ast/params/params.rb | 70 + 29 files changed, 2184 insertions(+), 1564 deletions(-) create mode 100644 ql/src/codeql_ruby/AST.qll create mode 100644 ql/src/codeql_ruby/Generated.qll create mode 100644 ql/src/codeql_ruby/Method.qll create mode 100644 ql/src/codeql_ruby/Parameter.qll delete mode 100644 ql/src/codeql_ruby/ast.qll create mode 100644 ql/src/ruby.qll create mode 100644 ql/test/library-tests/ast/params/params.expected create mode 100644 ql/test/library-tests/ast/params/params.ql create mode 100644 ql/test/library-tests/ast/params/params.rb diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index aa3be0f87568..38b4e81bd726 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -46,8 +46,8 @@ jobs: - uses: actions/upload-artifact@v2 if: ${{ matrix.os == 'ubuntu-latest' }} with: - name: ruby_ast.qll - path: ql/src/codeql_ruby/ast.qll + name: Generated.qll + path: ql/src/codeql_ruby/Generated.qll - uses: actions/upload-artifact@v2 with: name: extractor-${{ matrix.os }} diff --git a/Cargo.lock b/Cargo.lock index 8088308da067..c1901813418e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,9 +64,9 @@ checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" [[package]] name = "cc" -version = "1.0.62" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40" +checksum = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15" [[package]] name = "cfg-if" @@ -397,9 +397,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" +checksum = "7acad6f34eb9e8a259d3283d1e8c1d34d7415943d4895f65cc73813c7396fc85" [[package]] name = "strsim" @@ -409,9 +409,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "syn" -version = "1.0.48" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac" +checksum = "443b4178719c5a851e1bde36ce12da21d74a0e60b4d982ec3385a933c812f0f6" dependencies = [ "proc-macro2", "quote", @@ -535,7 +535,7 @@ dependencies = [ [[package]] name = "tree-sitter-ruby" version = "0.17.0" -source = "git+https://github.com/tree-sitter/tree-sitter-ruby.git?rev=93632008c63e0577413bbedf120fb92a96397785#93632008c63e0577413bbedf120fb92a96397785" +source = "git+https://github.com/nickrolfe/tree-sitter-ruby.git?branch=refinements#cf76d2c60dac54259912f0c3c4d5c73e78304ace" dependencies = [ "cc", "tree-sitter", diff --git a/README.md b/README.md index 3875a966f0f5..1be806ecb762 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ cargo build --release ## Generating the database schema and QL library -The generated `ql/src/ruby.dbscheme` and `ql/src/codeql_ruby/ast.qll` files are included in the repository, but they can be re-generated as follows: +The generated `ql/src/ruby.dbscheme` and `ql/src/codeql_ruby/Generated.qll` files are included in the repository, but they can be re-generated as follows: ```bash # Run the generator cargo run --release -p ruby-generator # Then auto-format the QL library -codeql query format -i ql/src/codeql_ruby/ast.qll +codeql query format -i ql/src/codeql_ruby/Generated.qll ``` ## Building a CodeQL database for a Ruby program diff --git a/create-extractor-pack.ps1 b/create-extractor-pack.ps1 index 42ac4cee6511..f5b5c506dd2d 100644 --- a/create-extractor-pack.ps1 +++ b/create-extractor-pack.ps1 @@ -1,7 +1,7 @@ cargo build --release cargo run --release -p ruby-generator -codeql query format -i ql\src\codeql_ruby\ast.qll +codeql query format -i ql\src\codeql_ruby\Generated.qll rm -Recurse -Force extractor-pack mkdir extractor-pack | Out-Null diff --git a/create-extractor-pack.sh b/create-extractor-pack.sh index 0e9533c277bb..98a7fcd4f656 100755 --- a/create-extractor-pack.sh +++ b/create-extractor-pack.sh @@ -13,7 +13,7 @@ fi cargo build --release cargo run --release -p ruby-generator -codeql query format -i ql/src/codeql_ruby/ast.qll +codeql query format -i ql/src/codeql_ruby/Generated.qll rm -rf extractor-pack mkdir -p extractor-pack diff --git a/extractor/Cargo.toml b/extractor/Cargo.toml index e2277decc99e..e46a097b8321 100644 --- a/extractor/Cargo.toml +++ b/extractor/Cargo.toml @@ -10,7 +10,7 @@ edition = "2018" flate2 = "1.0" node-types = { path = "../node-types" } tree-sitter = "0.17" -tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "93632008c63e0577413bbedf120fb92a96397785" } +tree-sitter-ruby = { git = "https://github.com/nickrolfe/tree-sitter-ruby.git", branch = "refinements" } clap = "2.33" tracing = "0.1" tracing-subscriber = { version = "0.2", features = ["env-filter"] } diff --git a/generator/Cargo.toml b/generator/Cargo.toml index 5d1943b35fba..02415182811a 100644 --- a/generator/Cargo.toml +++ b/generator/Cargo.toml @@ -10,4 +10,4 @@ edition = "2018" node-types = { path = "../node-types" } tracing = "0.1" tracing-subscriber = { version = "0.2", features = ["env-filter"] } -tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "93632008c63e0577413bbedf120fb92a96397785" } +tree-sitter-ruby = { git = "https://github.com/nickrolfe/tree-sitter-ruby.git", branch = "refinements" } diff --git a/generator/src/main.rs b/generator/src/main.rs index 9c68a4788af5..330eef50ce92 100644 --- a/generator/src/main.rs +++ b/generator/src/main.rs @@ -574,7 +574,7 @@ fn main() { name: "Ruby".to_owned(), node_types: tree_sitter_ruby::NODE_TYPES, dbscheme_path: PathBuf::from("ql/src/ruby.dbscheme"), - ql_library_path: PathBuf::from("ql/src/codeql_ruby/ast.qll"), + ql_library_path: PathBuf::from("ql/src/codeql_ruby/Generated.qll"), }; match node_types::read_node_types_str(&ruby.node_types) { Err(e) => { diff --git a/generator/src/ql.rs b/generator/src/ql.rs index 29381cd581c8..f7b6a9b07f39 100644 --- a/generator/src/ql.rs +++ b/generator/src/ql.rs @@ -214,10 +214,12 @@ pub fn write<'a>( " * Automatically generated from the tree-sitter grammar; do not edit\n" )?; write!(file, " */\n\n")?; + write!(file, "module Generated {{\n")?; for element in elements { write!(file, "{}\n\n", &element)?; } + write!(file, "}}")?; Ok(()) } diff --git a/ql/src/codeql_ruby/AST.qll b/ql/src/codeql_ruby/AST.qll new file mode 100644 index 000000000000..d9f0bfb47a9f --- /dev/null +++ b/ql/src/codeql_ruby/AST.qll @@ -0,0 +1,40 @@ +import codeql_ruby.Method +import codeql_ruby.Parameter +private import codeql_ruby.Generated + +class Location = Generated::Location; + +/** + * A node in the abstract syntax tree. This class is the base class for all Ruby + * program elements. + */ +class AstNode extends @ast_node { + /** + * Gets the name of a primary CodeQL class to which this node belongs. + * + * This predicate always has a result. If no primary class can be + * determined, the result is `"???"`. If multiple primary classes match, + * this predicate can have multiple results. + */ + string describeQlClass() { result = "???" } + + /** Gets a textual representation of this node. */ + string toString() { result = "AstNode" } + + /** Gets the location if this node. */ + Location getLocation() { result = this.(Generated::AstNode).getLocation() } +} + +/** + * Models program elements for destructured patterns. + */ +abstract class Pattern extends AstNode { + /** Gets the number of elements in this pattern. */ + abstract int getNumberOfElements(); + + /** Gets the nth element in this pattern. */ + abstract AstNode getElement(int n); + + /** Gets an element in this pattern. */ + AstNode getAnElement() { result = this.getElement(_) } +} diff --git a/ql/src/codeql_ruby/Generated.qll b/ql/src/codeql_ruby/Generated.qll new file mode 100644 index 000000000000..8c97c3854bd4 --- /dev/null +++ b/ql/src/codeql_ruby/Generated.qll @@ -0,0 +1,1540 @@ +/* + * CodeQL library for Ruby + * Automatically generated from the tree-sitter grammar; do not edit + */ + +module Generated { + import codeql.files.FileSystem + import codeql.Locations + + class AstNode extends @ast_node { + string toString() { result = this.describeQlClass() } + + Location getLocation() { none() } + + AstNode getParent() { none() } + + int getParentIndex() { none() } + + AstNode getAFieldOrChild() { none() } + + string describeQlClass() { result = "???" } + } + + class Token extends @token, AstNode { + override AstNode getParent() { tokeninfo(this, result, _, _, _, _, _, _) } + + override int getParentIndex() { tokeninfo(this, _, result, _, _, _, _, _) } + + string getValue() { tokeninfo(this, _, _, _, _, _, result, _) } + + override Location getLocation() { tokeninfo(this, _, _, _, _, _, _, result) } + + override string toString() { result = getValue() } + + override string describeQlClass() { result = "Token" } + } + + class ReservedWord extends @reserved_word, Token { + override string describeQlClass() { result = "ReservedWord" } + } + + class UnderscoreArg extends @underscore_arg, AstNode { } + + class UnderscoreLhs extends @underscore_lhs, AstNode { } + + class UnderscoreMethodName extends @underscore_method_name, AstNode { } + + class UnderscorePrimary extends @underscore_primary, AstNode { } + + class UnderscoreStatement extends @underscore_statement, AstNode { } + + class UnderscoreVariable extends @underscore_variable, AstNode { } + + class Alias extends @alias, AstNode { + override string describeQlClass() { result = "Alias" } + + override Location getLocation() { alias_def(this, _, _, _, _, result) } + + UnderscoreMethodName getAlias() { alias_def(this, _, _, result, _, _) } + + UnderscoreMethodName getName() { alias_def(this, _, _, _, result, _) } + + override AstNode getParent() { alias_def(this, result, _, _, _, _) } + + override int getParentIndex() { alias_def(this, _, result, _, _, _) } + + override AstNode getAFieldOrChild() { + alias_def(this, _, _, result, _, _) or alias_def(this, _, _, _, result, _) + } + } + + class ArgumentList extends @argument_list, AstNode { + override string describeQlClass() { result = "ArgumentList" } + + override Location getLocation() { argument_list_def(this, _, _, result) } + + AstNode getChild(int i) { argument_list_child(this, i, result) } + + override AstNode getParent() { argument_list_def(this, result, _, _) } + + override int getParentIndex() { argument_list_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { argument_list_child(this, _, result) } + } + + class Array extends @array, AstNode { + override string describeQlClass() { result = "Array" } + + override Location getLocation() { array_def(this, _, _, result) } + + AstNode getChild(int i) { array_child(this, i, result) } + + override AstNode getParent() { array_def(this, result, _, _) } + + override int getParentIndex() { array_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { array_child(this, _, result) } + } + + class Assignment extends @assignment, AstNode { + override string describeQlClass() { result = "Assignment" } + + override Location getLocation() { assignment_def(this, _, _, _, _, result) } + + AstNode getLeft() { assignment_def(this, _, _, result, _, _) } + + AstNode getRight() { assignment_def(this, _, _, _, result, _) } + + override AstNode getParent() { assignment_def(this, result, _, _, _, _) } + + override int getParentIndex() { assignment_def(this, _, result, _, _, _) } + + override AstNode getAFieldOrChild() { + assignment_def(this, _, _, result, _, _) or assignment_def(this, _, _, _, result, _) + } + } + + class BareString extends @bare_string, AstNode { + override string describeQlClass() { result = "BareString" } + + override Location getLocation() { bare_string_def(this, _, _, result) } + + AstNode getChild(int i) { bare_string_child(this, i, result) } + + override AstNode getParent() { bare_string_def(this, result, _, _) } + + override int getParentIndex() { bare_string_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { bare_string_child(this, _, result) } + } + + class BareSymbol extends @bare_symbol, AstNode { + override string describeQlClass() { result = "BareSymbol" } + + override Location getLocation() { bare_symbol_def(this, _, _, result) } + + AstNode getChild(int i) { bare_symbol_child(this, i, result) } + + override AstNode getParent() { bare_symbol_def(this, result, _, _) } + + override int getParentIndex() { bare_symbol_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { bare_symbol_child(this, _, result) } + } + + class Begin extends @begin, AstNode { + override string describeQlClass() { result = "Begin" } + + override Location getLocation() { begin_def(this, _, _, result) } + + AstNode getChild(int i) { begin_child(this, i, result) } + + override AstNode getParent() { begin_def(this, result, _, _) } + + override int getParentIndex() { begin_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { begin_child(this, _, result) } + } + + class BeginBlock extends @begin_block, AstNode { + override string describeQlClass() { result = "BeginBlock" } + + override Location getLocation() { begin_block_def(this, _, _, result) } + + AstNode getChild(int i) { begin_block_child(this, i, result) } + + override AstNode getParent() { begin_block_def(this, result, _, _) } + + override int getParentIndex() { begin_block_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { begin_block_child(this, _, result) } + } + + class Binary extends @binary, AstNode { + override string describeQlClass() { result = "Binary" } + + override Location getLocation() { binary_def(this, _, _, _, _, _, result) } + + AstNode getLeft() { binary_def(this, _, _, result, _, _, _) } + + AstNode getOperator() { binary_def(this, _, _, _, result, _, _) } + + AstNode getRight() { binary_def(this, _, _, _, _, result, _) } + + override AstNode getParent() { binary_def(this, result, _, _, _, _, _) } + + override int getParentIndex() { binary_def(this, _, result, _, _, _, _) } + + override AstNode getAFieldOrChild() { + binary_def(this, _, _, result, _, _, _) or + binary_def(this, _, _, _, result, _, _) or + binary_def(this, _, _, _, _, result, _) + } + } + + class Block extends @block, AstNode { + override string describeQlClass() { result = "Block" } + + override Location getLocation() { block_def(this, _, _, result) } + + BlockParameters getParameters() { block_parameters(this, result) } + + AstNode getChild(int i) { block_child(this, i, result) } + + override AstNode getParent() { block_def(this, result, _, _) } + + override int getParentIndex() { block_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { + block_parameters(this, result) or block_child(this, _, result) + } + } + + class BlockArgument extends @block_argument, AstNode { + override string describeQlClass() { result = "BlockArgument" } + + override Location getLocation() { block_argument_def(this, _, _, _, result) } + + UnderscoreArg getChild() { block_argument_def(this, _, _, result, _) } + + override AstNode getParent() { block_argument_def(this, result, _, _, _) } + + override int getParentIndex() { block_argument_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { block_argument_def(this, _, _, result, _) } + } + + class BlockParameter extends @block_parameter, AstNode { + override string describeQlClass() { result = "BlockParameter" } + + override Location getLocation() { block_parameter_def(this, _, _, _, result) } + + Identifier getName() { block_parameter_def(this, _, _, result, _) } + + override AstNode getParent() { block_parameter_def(this, result, _, _, _) } + + override int getParentIndex() { block_parameter_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { block_parameter_def(this, _, _, result, _) } + } + + class BlockParameters extends @block_parameters, AstNode { + override string describeQlClass() { result = "BlockParameters" } + + override Location getLocation() { block_parameters_def(this, _, _, result) } + + AstNode getChild(int i) { block_parameters_child(this, i, result) } + + override AstNode getParent() { block_parameters_def(this, result, _, _) } + + override int getParentIndex() { block_parameters_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { block_parameters_child(this, _, result) } + } + + class Break extends @break, AstNode { + override string describeQlClass() { result = "Break" } + + override Location getLocation() { break_def(this, _, _, result) } + + ArgumentList getChild() { break_child(this, result) } + + override AstNode getParent() { break_def(this, result, _, _) } + + override int getParentIndex() { break_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { break_child(this, result) } + } + + class Call extends @call, AstNode { + override string describeQlClass() { result = "Call" } + + override Location getLocation() { call_def(this, _, _, _, _, result) } + + AstNode getMethod() { call_def(this, _, _, result, _, _) } + + AstNode getReceiver() { call_def(this, _, _, _, result, _) } + + override AstNode getParent() { call_def(this, result, _, _, _, _) } + + override int getParentIndex() { call_def(this, _, result, _, _, _) } + + override AstNode getAFieldOrChild() { + call_def(this, _, _, result, _, _) or call_def(this, _, _, _, result, _) + } + } + + class Case extends @case__, AstNode { + override string describeQlClass() { result = "Case" } + + override Location getLocation() { case_def(this, _, _, result) } + + UnderscoreStatement getValue() { case_value(this, result) } + + AstNode getChild(int i) { case_child(this, i, result) } + + override AstNode getParent() { case_def(this, result, _, _) } + + override int getParentIndex() { case_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { case_value(this, result) or case_child(this, _, result) } + } + + class ChainedString extends @chained_string, AstNode { + override string describeQlClass() { result = "ChainedString" } + + override Location getLocation() { chained_string_def(this, _, _, result) } + + String getChild(int i) { chained_string_child(this, i, result) } + + override AstNode getParent() { chained_string_def(this, result, _, _) } + + override int getParentIndex() { chained_string_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { chained_string_child(this, _, result) } + } + + class Character extends @token_character, Token { + override string describeQlClass() { result = "Character" } + } + + class Class extends @class, AstNode { + override string describeQlClass() { result = "Class" } + + override Location getLocation() { class_def(this, _, _, _, result) } + + AstNode getName() { class_def(this, _, _, result, _) } + + AstNode getChild(int i) { class_child(this, i, result) } + + override AstNode getParent() { class_def(this, result, _, _, _) } + + override int getParentIndex() { class_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { + class_def(this, _, _, result, _) or class_child(this, _, result) + } + } + + class ClassVariable extends @token_class_variable, Token { + override string describeQlClass() { result = "ClassVariable" } + } + + class Comment extends @token_comment, Token { + override string describeQlClass() { result = "Comment" } + } + + class Complex extends @token_complex, Token { + override string describeQlClass() { result = "Complex" } + } + + class Conditional extends @conditional, AstNode { + override string describeQlClass() { result = "Conditional" } + + override Location getLocation() { conditional_def(this, _, _, _, _, _, result) } + + UnderscoreArg getAlternative() { conditional_def(this, _, _, result, _, _, _) } + + UnderscoreArg getCondition() { conditional_def(this, _, _, _, result, _, _) } + + UnderscoreArg getConsequence() { conditional_def(this, _, _, _, _, result, _) } + + override AstNode getParent() { conditional_def(this, result, _, _, _, _, _) } + + override int getParentIndex() { conditional_def(this, _, result, _, _, _, _) } + + override AstNode getAFieldOrChild() { + conditional_def(this, _, _, result, _, _, _) or + conditional_def(this, _, _, _, result, _, _) or + conditional_def(this, _, _, _, _, result, _) + } + } + + class Constant extends @token_constant, Token { + override string describeQlClass() { result = "Constant" } + } + + class DestructuredLeftAssignment extends @destructured_left_assignment, AstNode { + override string describeQlClass() { result = "DestructuredLeftAssignment" } + + override Location getLocation() { destructured_left_assignment_def(this, _, _, result) } + + AstNode getChild(int i) { destructured_left_assignment_child(this, i, result) } + + override AstNode getParent() { destructured_left_assignment_def(this, result, _, _) } + + override int getParentIndex() { destructured_left_assignment_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { destructured_left_assignment_child(this, _, result) } + } + + class DestructuredParameter extends @destructured_parameter, AstNode { + override string describeQlClass() { result = "DestructuredParameter" } + + override Location getLocation() { destructured_parameter_def(this, _, _, result) } + + AstNode getChild(int i) { destructured_parameter_child(this, i, result) } + + override AstNode getParent() { destructured_parameter_def(this, result, _, _) } + + override int getParentIndex() { destructured_parameter_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { destructured_parameter_child(this, _, result) } + } + + class Do extends @do, AstNode { + override string describeQlClass() { result = "Do" } + + override Location getLocation() { do_def(this, _, _, result) } + + AstNode getChild(int i) { do_child(this, i, result) } + + override AstNode getParent() { do_def(this, result, _, _) } + + override int getParentIndex() { do_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { do_child(this, _, result) } + } + + class DoBlock extends @do_block, AstNode { + override string describeQlClass() { result = "DoBlock" } + + override Location getLocation() { do_block_def(this, _, _, result) } + + BlockParameters getParameters() { do_block_parameters(this, result) } + + AstNode getChild(int i) { do_block_child(this, i, result) } + + override AstNode getParent() { do_block_def(this, result, _, _) } + + override int getParentIndex() { do_block_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { + do_block_parameters(this, result) or do_block_child(this, _, result) + } + } + + class ElementReference extends @element_reference, AstNode { + override string describeQlClass() { result = "ElementReference" } + + override Location getLocation() { element_reference_def(this, _, _, _, result) } + + UnderscorePrimary getObject() { element_reference_def(this, _, _, result, _) } + + AstNode getChild(int i) { element_reference_child(this, i, result) } + + override AstNode getParent() { element_reference_def(this, result, _, _, _) } + + override int getParentIndex() { element_reference_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { + element_reference_def(this, _, _, result, _) or element_reference_child(this, _, result) + } + } + + class Else extends @else, AstNode { + override string describeQlClass() { result = "Else" } + + override Location getLocation() { else_def(this, _, _, result) } + + AstNode getChild(int i) { else_child(this, i, result) } + + override AstNode getParent() { else_def(this, result, _, _) } + + override int getParentIndex() { else_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { else_child(this, _, result) } + } + + class Elsif extends @elsif, AstNode { + override string describeQlClass() { result = "Elsif" } + + override Location getLocation() { elsif_def(this, _, _, _, result) } + + AstNode getAlternative() { elsif_alternative(this, result) } + + UnderscoreStatement getCondition() { elsif_def(this, _, _, result, _) } + + Then getConsequence() { elsif_consequence(this, result) } + + override AstNode getParent() { elsif_def(this, result, _, _, _) } + + override int getParentIndex() { elsif_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { + elsif_alternative(this, result) or + elsif_def(this, _, _, result, _) or + elsif_consequence(this, result) + } + } + + class EmptyStatement extends @token_empty_statement, Token { + override string describeQlClass() { result = "EmptyStatement" } + } + + class EndBlock extends @end_block, AstNode { + override string describeQlClass() { result = "EndBlock" } + + override Location getLocation() { end_block_def(this, _, _, result) } + + AstNode getChild(int i) { end_block_child(this, i, result) } + + override AstNode getParent() { end_block_def(this, result, _, _) } + + override int getParentIndex() { end_block_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { end_block_child(this, _, result) } + } + + class Ensure extends @ensure, AstNode { + override string describeQlClass() { result = "Ensure" } + + override Location getLocation() { ensure_def(this, _, _, result) } + + AstNode getChild(int i) { ensure_child(this, i, result) } + + override AstNode getParent() { ensure_def(this, result, _, _) } + + override int getParentIndex() { ensure_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { ensure_child(this, _, result) } + } + + class EscapeSequence extends @token_escape_sequence, Token { + override string describeQlClass() { result = "EscapeSequence" } + } + + class ExceptionVariable extends @exception_variable, AstNode { + override string describeQlClass() { result = "ExceptionVariable" } + + override Location getLocation() { exception_variable_def(this, _, _, _, result) } + + UnderscoreLhs getChild() { exception_variable_def(this, _, _, result, _) } + + override AstNode getParent() { exception_variable_def(this, result, _, _, _) } + + override int getParentIndex() { exception_variable_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { exception_variable_def(this, _, _, result, _) } + } + + class Exceptions extends @exceptions, AstNode { + override string describeQlClass() { result = "Exceptions" } + + override Location getLocation() { exceptions_def(this, _, _, result) } + + AstNode getChild(int i) { exceptions_child(this, i, result) } + + override AstNode getParent() { exceptions_def(this, result, _, _) } + + override int getParentIndex() { exceptions_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { exceptions_child(this, _, result) } + } + + class False extends @token_false, Token { + override string describeQlClass() { result = "False" } + } + + class Float extends @token_float, Token { + override string describeQlClass() { result = "Float" } + } + + class For extends @for, AstNode { + override string describeQlClass() { result = "For" } + + override Location getLocation() { for_def(this, _, _, _, _, result) } + + Do getBody() { for_def(this, _, _, result, _, _) } + + AstNode getPattern(int i) { for_pattern(this, i, result) } + + In getValue() { for_def(this, _, _, _, result, _) } + + override AstNode getParent() { for_def(this, result, _, _, _, _) } + + override int getParentIndex() { for_def(this, _, result, _, _, _) } + + override AstNode getAFieldOrChild() { + for_def(this, _, _, result, _, _) or + for_pattern(this, _, result) or + for_def(this, _, _, _, result, _) + } + } + + class GlobalVariable extends @token_global_variable, Token { + override string describeQlClass() { result = "GlobalVariable" } + } + + class Hash extends @hash, AstNode { + override string describeQlClass() { result = "Hash" } + + override Location getLocation() { hash_def(this, _, _, result) } + + AstNode getChild(int i) { hash_child(this, i, result) } + + override AstNode getParent() { hash_def(this, result, _, _) } + + override int getParentIndex() { hash_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { hash_child(this, _, result) } + } + + class HashSplatArgument extends @hash_splat_argument, AstNode { + override string describeQlClass() { result = "HashSplatArgument" } + + override Location getLocation() { hash_splat_argument_def(this, _, _, _, result) } + + UnderscoreArg getChild() { hash_splat_argument_def(this, _, _, result, _) } + + override AstNode getParent() { hash_splat_argument_def(this, result, _, _, _) } + + override int getParentIndex() { hash_splat_argument_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { hash_splat_argument_def(this, _, _, result, _) } + } + + class HashSplatParameter extends @hash_splat_parameter, AstNode { + override string describeQlClass() { result = "HashSplatParameter" } + + override Location getLocation() { hash_splat_parameter_def(this, _, _, result) } + + Identifier getName() { hash_splat_parameter_name(this, result) } + + override AstNode getParent() { hash_splat_parameter_def(this, result, _, _) } + + override int getParentIndex() { hash_splat_parameter_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { hash_splat_parameter_name(this, result) } + } + + class HeredocBeginning extends @token_heredoc_beginning, Token { + override string describeQlClass() { result = "HeredocBeginning" } + } + + class HeredocBody extends @heredoc_body, AstNode { + override string describeQlClass() { result = "HeredocBody" } + + override Location getLocation() { heredoc_body_def(this, _, _, result) } + + AstNode getChild(int i) { heredoc_body_child(this, i, result) } + + override AstNode getParent() { heredoc_body_def(this, result, _, _) } + + override int getParentIndex() { heredoc_body_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { heredoc_body_child(this, _, result) } + } + + class HeredocContent extends @token_heredoc_content, Token { + override string describeQlClass() { result = "HeredocContent" } + } + + class HeredocEnd extends @token_heredoc_end, Token { + override string describeQlClass() { result = "HeredocEnd" } + } + + class Identifier extends @token_identifier, Token { + override string describeQlClass() { result = "Identifier" } + } + + class If extends @if, AstNode { + override string describeQlClass() { result = "If" } + + override Location getLocation() { if_def(this, _, _, _, result) } + + AstNode getAlternative() { if_alternative(this, result) } + + UnderscoreStatement getCondition() { if_def(this, _, _, result, _) } + + Then getConsequence() { if_consequence(this, result) } + + override AstNode getParent() { if_def(this, result, _, _, _) } + + override int getParentIndex() { if_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { + if_alternative(this, result) or if_def(this, _, _, result, _) or if_consequence(this, result) + } + } + + class IfModifier extends @if_modifier, AstNode { + override string describeQlClass() { result = "IfModifier" } + + override Location getLocation() { if_modifier_def(this, _, _, _, _, result) } + + UnderscoreStatement getBody() { if_modifier_def(this, _, _, result, _, _) } + + AstNode getCondition() { if_modifier_def(this, _, _, _, result, _) } + + override AstNode getParent() { if_modifier_def(this, result, _, _, _, _) } + + override int getParentIndex() { if_modifier_def(this, _, result, _, _, _) } + + override AstNode getAFieldOrChild() { + if_modifier_def(this, _, _, result, _, _) or if_modifier_def(this, _, _, _, result, _) + } + } + + class In extends @in, AstNode { + override string describeQlClass() { result = "In" } + + override Location getLocation() { in_def(this, _, _, _, result) } + + UnderscoreArg getChild() { in_def(this, _, _, result, _) } + + override AstNode getParent() { in_def(this, result, _, _, _) } + + override int getParentIndex() { in_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { in_def(this, _, _, result, _) } + } + + class InstanceVariable extends @token_instance_variable, Token { + override string describeQlClass() { result = "InstanceVariable" } + } + + class Integer extends @token_integer, Token { + override string describeQlClass() { result = "Integer" } + } + + class Interpolation extends @interpolation, AstNode { + override string describeQlClass() { result = "Interpolation" } + + override Location getLocation() { interpolation_def(this, _, _, _, result) } + + UnderscoreStatement getChild() { interpolation_def(this, _, _, result, _) } + + override AstNode getParent() { interpolation_def(this, result, _, _, _) } + + override int getParentIndex() { interpolation_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { interpolation_def(this, _, _, result, _) } + } + + class KeywordParameter extends @keyword_parameter, AstNode { + override string describeQlClass() { result = "KeywordParameter" } + + override Location getLocation() { keyword_parameter_def(this, _, _, _, result) } + + Identifier getName() { keyword_parameter_def(this, _, _, result, _) } + + UnderscoreArg getValue() { keyword_parameter_value(this, result) } + + override AstNode getParent() { keyword_parameter_def(this, result, _, _, _) } + + override int getParentIndex() { keyword_parameter_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { + keyword_parameter_def(this, _, _, result, _) or keyword_parameter_value(this, result) + } + } + + class Lambda extends @lambda, AstNode { + override string describeQlClass() { result = "Lambda" } + + override Location getLocation() { lambda_def(this, _, _, _, result) } + + AstNode getBody() { lambda_def(this, _, _, result, _) } + + LambdaParameters getParameters() { lambda_parameters(this, result) } + + override AstNode getParent() { lambda_def(this, result, _, _, _) } + + override int getParentIndex() { lambda_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { + lambda_def(this, _, _, result, _) or lambda_parameters(this, result) + } + } + + class LambdaParameters extends @lambda_parameters, AstNode { + override string describeQlClass() { result = "LambdaParameters" } + + override Location getLocation() { lambda_parameters_def(this, _, _, result) } + + AstNode getChild(int i) { lambda_parameters_child(this, i, result) } + + override AstNode getParent() { lambda_parameters_def(this, result, _, _) } + + override int getParentIndex() { lambda_parameters_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { lambda_parameters_child(this, _, result) } + } + + class LeftAssignmentList extends @left_assignment_list, AstNode { + override string describeQlClass() { result = "LeftAssignmentList" } + + override Location getLocation() { left_assignment_list_def(this, _, _, result) } + + AstNode getChild(int i) { left_assignment_list_child(this, i, result) } + + override AstNode getParent() { left_assignment_list_def(this, result, _, _) } + + override int getParentIndex() { left_assignment_list_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { left_assignment_list_child(this, _, result) } + } + + class Method extends @method, AstNode { + override string describeQlClass() { result = "Method" } + + override Location getLocation() { method_def(this, _, _, _, result) } + + UnderscoreMethodName getName() { method_def(this, _, _, result, _) } + + MethodParameters getParameters() { method_parameters(this, result) } + + AstNode getChild(int i) { method_child(this, i, result) } + + override AstNode getParent() { method_def(this, result, _, _, _) } + + override int getParentIndex() { method_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { + method_def(this, _, _, result, _) or + method_parameters(this, result) or + method_child(this, _, result) + } + } + + class MethodCall extends @method_call, AstNode { + override string describeQlClass() { result = "MethodCall" } + + override Location getLocation() { method_call_def(this, _, _, _, result) } + + ArgumentList getArguments() { method_call_arguments(this, result) } + + AstNode getBlock() { method_call_block(this, result) } + + AstNode getMethod() { method_call_def(this, _, _, result, _) } + + override AstNode getParent() { method_call_def(this, result, _, _, _) } + + override int getParentIndex() { method_call_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { + method_call_arguments(this, result) or + method_call_block(this, result) or + method_call_def(this, _, _, result, _) + } + } + + class MethodParameters extends @method_parameters, AstNode { + override string describeQlClass() { result = "MethodParameters" } + + override Location getLocation() { method_parameters_def(this, _, _, result) } + + AstNode getChild(int i) { method_parameters_child(this, i, result) } + + override AstNode getParent() { method_parameters_def(this, result, _, _) } + + override int getParentIndex() { method_parameters_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { method_parameters_child(this, _, result) } + } + + class Module extends @module, AstNode { + override string describeQlClass() { result = "Module" } + + override Location getLocation() { module_def(this, _, _, _, result) } + + AstNode getName() { module_def(this, _, _, result, _) } + + AstNode getChild(int i) { module_child(this, i, result) } + + override AstNode getParent() { module_def(this, result, _, _, _) } + + override int getParentIndex() { module_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { + module_def(this, _, _, result, _) or module_child(this, _, result) + } + } + + class Next extends @next, AstNode { + override string describeQlClass() { result = "Next" } + + override Location getLocation() { next_def(this, _, _, result) } + + ArgumentList getChild() { next_child(this, result) } + + override AstNode getParent() { next_def(this, result, _, _) } + + override int getParentIndex() { next_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { next_child(this, result) } + } + + class Nil extends @token_nil, Token { + override string describeQlClass() { result = "Nil" } + } + + class Operator extends @token_operator, Token { + override string describeQlClass() { result = "Operator" } + } + + class OperatorAssignment extends @operator_assignment, AstNode { + override string describeQlClass() { result = "OperatorAssignment" } + + override Location getLocation() { operator_assignment_def(this, _, _, _, _, result) } + + UnderscoreLhs getLeft() { operator_assignment_def(this, _, _, result, _, _) } + + AstNode getRight() { operator_assignment_def(this, _, _, _, result, _) } + + override AstNode getParent() { operator_assignment_def(this, result, _, _, _, _) } + + override int getParentIndex() { operator_assignment_def(this, _, result, _, _, _) } + + override AstNode getAFieldOrChild() { + operator_assignment_def(this, _, _, result, _, _) or + operator_assignment_def(this, _, _, _, result, _) + } + } + + class OptionalParameter extends @optional_parameter, AstNode { + override string describeQlClass() { result = "OptionalParameter" } + + override Location getLocation() { optional_parameter_def(this, _, _, _, _, result) } + + Identifier getName() { optional_parameter_def(this, _, _, result, _, _) } + + UnderscoreArg getValue() { optional_parameter_def(this, _, _, _, result, _) } + + override AstNode getParent() { optional_parameter_def(this, result, _, _, _, _) } + + override int getParentIndex() { optional_parameter_def(this, _, result, _, _, _) } + + override AstNode getAFieldOrChild() { + optional_parameter_def(this, _, _, result, _, _) or + optional_parameter_def(this, _, _, _, result, _) + } + } + + class Pair extends @pair, AstNode { + override string describeQlClass() { result = "Pair" } + + override Location getLocation() { pair_def(this, _, _, _, _, result) } + + AstNode getKey() { pair_def(this, _, _, result, _, _) } + + UnderscoreArg getValue() { pair_def(this, _, _, _, result, _) } + + override AstNode getParent() { pair_def(this, result, _, _, _, _) } + + override int getParentIndex() { pair_def(this, _, result, _, _, _) } + + override AstNode getAFieldOrChild() { + pair_def(this, _, _, result, _, _) or pair_def(this, _, _, _, result, _) + } + } + + class ParenthesizedStatements extends @parenthesized_statements, AstNode { + override string describeQlClass() { result = "ParenthesizedStatements" } + + override Location getLocation() { parenthesized_statements_def(this, _, _, result) } + + AstNode getChild(int i) { parenthesized_statements_child(this, i, result) } + + override AstNode getParent() { parenthesized_statements_def(this, result, _, _) } + + override int getParentIndex() { parenthesized_statements_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { parenthesized_statements_child(this, _, result) } + } + + class Pattern extends @pattern, AstNode { + override string describeQlClass() { result = "Pattern" } + + override Location getLocation() { pattern_def(this, _, _, _, result) } + + AstNode getChild() { pattern_def(this, _, _, result, _) } + + override AstNode getParent() { pattern_def(this, result, _, _, _) } + + override int getParentIndex() { pattern_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { pattern_def(this, _, _, result, _) } + } + + class Program extends @program, AstNode { + override string describeQlClass() { result = "Program" } + + override Location getLocation() { program_def(this, _, _, result) } + + AstNode getChild(int i) { program_child(this, i, result) } + + override AstNode getParent() { program_def(this, result, _, _) } + + override int getParentIndex() { program_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { program_child(this, _, result) } + } + + class Range extends @range, AstNode { + override string describeQlClass() { result = "Range" } + + override Location getLocation() { range_def(this, _, _, result) } + + UnderscoreArg getChild(int i) { range_child(this, i, result) } + + override AstNode getParent() { range_def(this, result, _, _) } + + override int getParentIndex() { range_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { range_child(this, _, result) } + } + + class Rational extends @rational, AstNode { + override string describeQlClass() { result = "Rational" } + + override Location getLocation() { rational_def(this, _, _, _, result) } + + Integer getChild() { rational_def(this, _, _, result, _) } + + override AstNode getParent() { rational_def(this, result, _, _, _) } + + override int getParentIndex() { rational_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { rational_def(this, _, _, result, _) } + } + + class Redo extends @redo, AstNode { + override string describeQlClass() { result = "Redo" } + + override Location getLocation() { redo_def(this, _, _, result) } + + ArgumentList getChild() { redo_child(this, result) } + + override AstNode getParent() { redo_def(this, result, _, _) } + + override int getParentIndex() { redo_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { redo_child(this, result) } + } + + class Regex extends @regex, AstNode { + override string describeQlClass() { result = "Regex" } + + override Location getLocation() { regex_def(this, _, _, result) } + + AstNode getChild(int i) { regex_child(this, i, result) } + + override AstNode getParent() { regex_def(this, result, _, _) } + + override int getParentIndex() { regex_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { regex_child(this, _, result) } + } + + class Rescue extends @rescue, AstNode { + override string describeQlClass() { result = "Rescue" } + + override Location getLocation() { rescue_def(this, _, _, result) } + + Then getBody() { rescue_body(this, result) } + + Exceptions getExceptions() { rescue_exceptions(this, result) } + + ExceptionVariable getVariable() { rescue_variable(this, result) } + + override AstNode getParent() { rescue_def(this, result, _, _) } + + override int getParentIndex() { rescue_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { + rescue_body(this, result) or rescue_exceptions(this, result) or rescue_variable(this, result) + } + } + + class RescueModifier extends @rescue_modifier, AstNode { + override string describeQlClass() { result = "RescueModifier" } + + override Location getLocation() { rescue_modifier_def(this, _, _, _, _, result) } + + UnderscoreStatement getBody() { rescue_modifier_def(this, _, _, result, _, _) } + + AstNode getHandler() { rescue_modifier_def(this, _, _, _, result, _) } + + override AstNode getParent() { rescue_modifier_def(this, result, _, _, _, _) } + + override int getParentIndex() { rescue_modifier_def(this, _, result, _, _, _) } + + override AstNode getAFieldOrChild() { + rescue_modifier_def(this, _, _, result, _, _) or rescue_modifier_def(this, _, _, _, result, _) + } + } + + class RestAssignment extends @rest_assignment, AstNode { + override string describeQlClass() { result = "RestAssignment" } + + override Location getLocation() { rest_assignment_def(this, _, _, result) } + + UnderscoreLhs getChild() { rest_assignment_child(this, result) } + + override AstNode getParent() { rest_assignment_def(this, result, _, _) } + + override int getParentIndex() { rest_assignment_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { rest_assignment_child(this, result) } + } + + class Retry extends @retry, AstNode { + override string describeQlClass() { result = "Retry" } + + override Location getLocation() { retry_def(this, _, _, result) } + + ArgumentList getChild() { retry_child(this, result) } + + override AstNode getParent() { retry_def(this, result, _, _) } + + override int getParentIndex() { retry_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { retry_child(this, result) } + } + + class Return extends @return, AstNode { + override string describeQlClass() { result = "Return" } + + override Location getLocation() { return_def(this, _, _, result) } + + ArgumentList getChild() { return_child(this, result) } + + override AstNode getParent() { return_def(this, result, _, _) } + + override int getParentIndex() { return_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { return_child(this, result) } + } + + class RightAssignmentList extends @right_assignment_list, AstNode { + override string describeQlClass() { result = "RightAssignmentList" } + + override Location getLocation() { right_assignment_list_def(this, _, _, result) } + + AstNode getChild(int i) { right_assignment_list_child(this, i, result) } + + override AstNode getParent() { right_assignment_list_def(this, result, _, _) } + + override int getParentIndex() { right_assignment_list_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { right_assignment_list_child(this, _, result) } + } + + class ScopeResolution extends @scope_resolution, AstNode { + override string describeQlClass() { result = "ScopeResolution" } + + override Location getLocation() { scope_resolution_def(this, _, _, _, result) } + + AstNode getName() { scope_resolution_def(this, _, _, result, _) } + + UnderscorePrimary getScope() { scope_resolution_scope(this, result) } + + override AstNode getParent() { scope_resolution_def(this, result, _, _, _) } + + override int getParentIndex() { scope_resolution_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { + scope_resolution_def(this, _, _, result, _) or scope_resolution_scope(this, result) + } + } + + class Self extends @token_self, Token { + override string describeQlClass() { result = "Self" } + } + + class Setter extends @setter, AstNode { + override string describeQlClass() { result = "Setter" } + + override Location getLocation() { setter_def(this, _, _, _, result) } + + Identifier getName() { setter_def(this, _, _, result, _) } + + override AstNode getParent() { setter_def(this, result, _, _, _) } + + override int getParentIndex() { setter_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { setter_def(this, _, _, result, _) } + } + + class SingletonClass extends @singleton_class, AstNode { + override string describeQlClass() { result = "SingletonClass" } + + override Location getLocation() { singleton_class_def(this, _, _, _, result) } + + UnderscoreArg getValue() { singleton_class_def(this, _, _, result, _) } + + AstNode getChild(int i) { singleton_class_child(this, i, result) } + + override AstNode getParent() { singleton_class_def(this, result, _, _, _) } + + override int getParentIndex() { singleton_class_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { + singleton_class_def(this, _, _, result, _) or singleton_class_child(this, _, result) + } + } + + class SingletonMethod extends @singleton_method, AstNode { + override string describeQlClass() { result = "SingletonMethod" } + + override Location getLocation() { singleton_method_def(this, _, _, _, _, result) } + + UnderscoreMethodName getName() { singleton_method_def(this, _, _, result, _, _) } + + AstNode getObject() { singleton_method_def(this, _, _, _, result, _) } + + MethodParameters getParameters() { singleton_method_parameters(this, result) } + + AstNode getChild(int i) { singleton_method_child(this, i, result) } + + override AstNode getParent() { singleton_method_def(this, result, _, _, _, _) } + + override int getParentIndex() { singleton_method_def(this, _, result, _, _, _) } + + override AstNode getAFieldOrChild() { + singleton_method_def(this, _, _, result, _, _) or + singleton_method_def(this, _, _, _, result, _) or + singleton_method_parameters(this, result) or + singleton_method_child(this, _, result) + } + } + + class SplatArgument extends @splat_argument, AstNode { + override string describeQlClass() { result = "SplatArgument" } + + override Location getLocation() { splat_argument_def(this, _, _, _, result) } + + UnderscoreArg getChild() { splat_argument_def(this, _, _, result, _) } + + override AstNode getParent() { splat_argument_def(this, result, _, _, _) } + + override int getParentIndex() { splat_argument_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { splat_argument_def(this, _, _, result, _) } + } + + class SplatParameter extends @splat_parameter, AstNode { + override string describeQlClass() { result = "SplatParameter" } + + override Location getLocation() { splat_parameter_def(this, _, _, result) } + + Identifier getName() { splat_parameter_name(this, result) } + + override AstNode getParent() { splat_parameter_def(this, result, _, _) } + + override int getParentIndex() { splat_parameter_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { splat_parameter_name(this, result) } + } + + class String extends @string__, AstNode { + override string describeQlClass() { result = "String" } + + override Location getLocation() { string_def(this, _, _, result) } + + AstNode getChild(int i) { string_child(this, i, result) } + + override AstNode getParent() { string_def(this, result, _, _) } + + override int getParentIndex() { string_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { string_child(this, _, result) } + } + + class StringArray extends @string_array, AstNode { + override string describeQlClass() { result = "StringArray" } + + override Location getLocation() { string_array_def(this, _, _, result) } + + BareString getChild(int i) { string_array_child(this, i, result) } + + override AstNode getParent() { string_array_def(this, result, _, _) } + + override int getParentIndex() { string_array_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { string_array_child(this, _, result) } + } + + class StringContent extends @token_string_content, Token { + override string describeQlClass() { result = "StringContent" } + } + + class Subshell extends @subshell, AstNode { + override string describeQlClass() { result = "Subshell" } + + override Location getLocation() { subshell_def(this, _, _, result) } + + AstNode getChild(int i) { subshell_child(this, i, result) } + + override AstNode getParent() { subshell_def(this, result, _, _) } + + override int getParentIndex() { subshell_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { subshell_child(this, _, result) } + } + + class Super extends @token_super, Token { + override string describeQlClass() { result = "Super" } + } + + class Superclass extends @superclass, AstNode { + override string describeQlClass() { result = "Superclass" } + + override Location getLocation() { superclass_def(this, _, _, _, result) } + + AstNode getChild() { superclass_def(this, _, _, result, _) } + + override AstNode getParent() { superclass_def(this, result, _, _, _) } + + override int getParentIndex() { superclass_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { superclass_def(this, _, _, result, _) } + } + + class Symbol extends @symbol, AstNode { + override string describeQlClass() { result = "Symbol" } + + override Location getLocation() { symbol_def(this, _, _, result) } + + AstNode getChild(int i) { symbol_child(this, i, result) } + + override AstNode getParent() { symbol_def(this, result, _, _) } + + override int getParentIndex() { symbol_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { symbol_child(this, _, result) } + } + + class SymbolArray extends @symbol_array, AstNode { + override string describeQlClass() { result = "SymbolArray" } + + override Location getLocation() { symbol_array_def(this, _, _, result) } + + BareSymbol getChild(int i) { symbol_array_child(this, i, result) } + + override AstNode getParent() { symbol_array_def(this, result, _, _) } + + override int getParentIndex() { symbol_array_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { symbol_array_child(this, _, result) } + } + + class Then extends @then, AstNode { + override string describeQlClass() { result = "Then" } + + override Location getLocation() { then_def(this, _, _, result) } + + AstNode getChild(int i) { then_child(this, i, result) } + + override AstNode getParent() { then_def(this, result, _, _) } + + override int getParentIndex() { then_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { then_child(this, _, result) } + } + + class True extends @token_true, Token { + override string describeQlClass() { result = "True" } + } + + class Unary extends @unary, AstNode { + override string describeQlClass() { result = "Unary" } + + override Location getLocation() { unary_def(this, _, _, _, _, result) } + + AstNode getOperand() { unary_def(this, _, _, result, _, _) } + + AstNode getOperator() { unary_def(this, _, _, _, result, _) } + + override AstNode getParent() { unary_def(this, result, _, _, _, _) } + + override int getParentIndex() { unary_def(this, _, result, _, _, _) } + + override AstNode getAFieldOrChild() { + unary_def(this, _, _, result, _, _) or unary_def(this, _, _, _, result, _) + } + } + + class Undef extends @undef, AstNode { + override string describeQlClass() { result = "Undef" } + + override Location getLocation() { undef_def(this, _, _, result) } + + UnderscoreMethodName getChild(int i) { undef_child(this, i, result) } + + override AstNode getParent() { undef_def(this, result, _, _) } + + override int getParentIndex() { undef_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { undef_child(this, _, result) } + } + + class Uninterpreted extends @token_uninterpreted, Token { + override string describeQlClass() { result = "Uninterpreted" } + } + + class Unless extends @unless, AstNode { + override string describeQlClass() { result = "Unless" } + + override Location getLocation() { unless_def(this, _, _, _, result) } + + AstNode getAlternative() { unless_alternative(this, result) } + + UnderscoreStatement getCondition() { unless_def(this, _, _, result, _) } + + Then getConsequence() { unless_consequence(this, result) } + + override AstNode getParent() { unless_def(this, result, _, _, _) } + + override int getParentIndex() { unless_def(this, _, result, _, _) } + + override AstNode getAFieldOrChild() { + unless_alternative(this, result) or + unless_def(this, _, _, result, _) or + unless_consequence(this, result) + } + } + + class UnlessModifier extends @unless_modifier, AstNode { + override string describeQlClass() { result = "UnlessModifier" } + + override Location getLocation() { unless_modifier_def(this, _, _, _, _, result) } + + UnderscoreStatement getBody() { unless_modifier_def(this, _, _, result, _, _) } + + AstNode getCondition() { unless_modifier_def(this, _, _, _, result, _) } + + override AstNode getParent() { unless_modifier_def(this, result, _, _, _, _) } + + override int getParentIndex() { unless_modifier_def(this, _, result, _, _, _) } + + override AstNode getAFieldOrChild() { + unless_modifier_def(this, _, _, result, _, _) or unless_modifier_def(this, _, _, _, result, _) + } + } + + class Until extends @until, AstNode { + override string describeQlClass() { result = "Until" } + + override Location getLocation() { until_def(this, _, _, _, _, result) } + + Do getBody() { until_def(this, _, _, result, _, _) } + + UnderscoreStatement getCondition() { until_def(this, _, _, _, result, _) } + + override AstNode getParent() { until_def(this, result, _, _, _, _) } + + override int getParentIndex() { until_def(this, _, result, _, _, _) } + + override AstNode getAFieldOrChild() { + until_def(this, _, _, result, _, _) or until_def(this, _, _, _, result, _) + } + } + + class UntilModifier extends @until_modifier, AstNode { + override string describeQlClass() { result = "UntilModifier" } + + override Location getLocation() { until_modifier_def(this, _, _, _, _, result) } + + UnderscoreStatement getBody() { until_modifier_def(this, _, _, result, _, _) } + + AstNode getCondition() { until_modifier_def(this, _, _, _, result, _) } + + override AstNode getParent() { until_modifier_def(this, result, _, _, _, _) } + + override int getParentIndex() { until_modifier_def(this, _, result, _, _, _) } + + override AstNode getAFieldOrChild() { + until_modifier_def(this, _, _, result, _, _) or until_modifier_def(this, _, _, _, result, _) + } + } + + class When extends @when, AstNode { + override string describeQlClass() { result = "When" } + + override Location getLocation() { when_def(this, _, _, result) } + + Then getBody() { when_body(this, result) } + + AstNode getPattern(int i) { when_pattern(this, i, result) } + + override AstNode getParent() { when_def(this, result, _, _) } + + override int getParentIndex() { when_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { when_body(this, result) or when_pattern(this, _, result) } + } + + class While extends @while, AstNode { + override string describeQlClass() { result = "While" } + + override Location getLocation() { while_def(this, _, _, _, _, result) } + + Do getBody() { while_def(this, _, _, result, _, _) } + + UnderscoreStatement getCondition() { while_def(this, _, _, _, result, _) } + + override AstNode getParent() { while_def(this, result, _, _, _, _) } + + override int getParentIndex() { while_def(this, _, result, _, _, _) } + + override AstNode getAFieldOrChild() { + while_def(this, _, _, result, _, _) or while_def(this, _, _, _, result, _) + } + } + + class WhileModifier extends @while_modifier, AstNode { + override string describeQlClass() { result = "WhileModifier" } + + override Location getLocation() { while_modifier_def(this, _, _, _, _, result) } + + UnderscoreStatement getBody() { while_modifier_def(this, _, _, result, _, _) } + + AstNode getCondition() { while_modifier_def(this, _, _, _, result, _) } + + override AstNode getParent() { while_modifier_def(this, result, _, _, _, _) } + + override int getParentIndex() { while_modifier_def(this, _, result, _, _, _) } + + override AstNode getAFieldOrChild() { + while_modifier_def(this, _, _, result, _, _) or while_modifier_def(this, _, _, _, result, _) + } + } + + class Yield extends @yield, AstNode { + override string describeQlClass() { result = "Yield" } + + override Location getLocation() { yield_def(this, _, _, result) } + + ArgumentList getChild() { yield_child(this, result) } + + override AstNode getParent() { yield_def(this, result, _, _) } + + override int getParentIndex() { yield_def(this, _, result, _) } + + override AstNode getAFieldOrChild() { yield_child(this, result) } + } +} diff --git a/ql/src/codeql_ruby/Method.qll b/ql/src/codeql_ruby/Method.qll new file mode 100644 index 000000000000..6aa5e61c027f --- /dev/null +++ b/ql/src/codeql_ruby/Method.qll @@ -0,0 +1,119 @@ +import codeql_ruby.AST +private import codeql_ruby.Generated + +/** A Ruby method. */ +class Method extends @method, AstNode { + Generated::Method generated; + + Method() { generated = this } + + override string describeQlClass() { result = "Method" } + + override string toString() { result = this.getName() } + + /** Gets the name of the method. */ + string getName() { + result = generated.getName().(Generated::Token).getValue() or + // TODO: use hand-written Symbol class + result = generated.getName().(Generated::Symbol).toString() or + result = generated.getName().(Generated::Setter).getName().getValue() + "=" + } + + /** + * Holds if this is a setter method, as in the following example: + * ``` + * class Person + * def name=(n) + * @name = n + * end + * end + * ``` + */ + predicate isSetter() { generated.getName() instanceof Generated::Setter } + + /** Gets the number of parameters of this method. */ + int getNumberOfParameters() { result = count(this.getAParameter()) } + + /** Gets a parameter of this method. */ + Parameter getAParameter() { result = this.getParameter(_) } + + /** Gets the nth parameter of this method. */ + Parameter getParameter(int n) { result = generated.getParameters().getChild(n) } +} + +/** + * A Ruby lambda (anonymous method). For example: + * ``` + * -> (x) { x + 1 } + * ``` + */ +class Lambda extends @lambda, AstNode { + Generated::Lambda generated; + + Lambda() { generated = this } + + override string describeQlClass() { result = "Lambda" } + + override string toString() { result = "-> { ... }" } + + /** Gets the number of parameters of this lambda. */ + int getNumberOfParameters() { result = count(this.getAParameter()) } + + /** Gets a parameter of this lambda. */ + Parameter getAParameter() { result = this.getParameter(_) } + + /** Gets the nth parameter of this lambda. */ + Parameter getParameter(int n) { result = generated.getParameters().getChild(n) } +} + +/** A Ruby block. */ +abstract class Block extends AstNode { + /** Gets the number of parameters of this block. */ + abstract int getNumberOfParameters(); + + /** Gets the nth parameter of this block. */ + abstract Parameter getParameter(int n); + + /** Gets a parameter of this block. */ + Parameter getAParameter() { result = this.getParameter(_) } + // TODO: body/statements +} + +/** A Ruby block enclosed within `do` and `end`. */ +class DoBlock extends @do_block, Block { + Generated::DoBlock generated; + + DoBlock() { generated = this } + + override string describeQlClass() { result = "DoBlock" } + + override string toString() { result = "| ... |" } + + /** Gets the number of parameters of this block. */ + override int getNumberOfParameters() { result = count(this.getAParameter()) } + + /** Gets the nth parameter of this block. */ + override Parameter getParameter(int n) { result = generated.getParameters().getChild(n) } +} + +/** + * A Ruby block defined using curly braces, e.g. in the following code: + * ``` + * names.each { |name| puts name } + * ``` + */ +class BraceBlock extends @block, Block { + Generated::Block generated; + + BraceBlock() { generated = this } + + override string describeQlClass() { result = "BraceBlock" } + + override string toString() { result = "{ ... }" } + + /** Gets the number of parameters of this block. */ + override int getNumberOfParameters() { result = count(this.getAParameter()) } + + /** Gets the nth parameter of this block. */ + override Parameter getParameter(int n) { result = generated.getParameters().getChild(n) } +} diff --git a/ql/src/codeql_ruby/Parameter.qll b/ql/src/codeql_ruby/Parameter.qll new file mode 100644 index 000000000000..0f6cb8fa419b --- /dev/null +++ b/ql/src/codeql_ruby/Parameter.qll @@ -0,0 +1,182 @@ +import codeql_ruby.AST +private import codeql_ruby.Generated + +/** + * A parameter to a block, lambda, or method. + */ +abstract class Parameter extends AstNode { + /** + * Gets the position of this parameter in the parent block, lambda, or + * method's parameter list. + */ + int getPosition() { + exists(Method m | m.getParameter(result) = this) or + exists(Block b | b.getParameter(result) = this) or + exists(Lambda l | l.getParameter(result) = this) + } +} + +/** + * A parameter that is a block. For example, `&bar` in the following code: + * ``` + * def foo(&bar) + * bar.call if block_given? + * end + * ``` + */ +class BlockParameter extends @block_parameter, Parameter { + Generated::BlockParameter generated; + + BlockParameter() { generated = this } + + override string describeQlClass() { result = "BlockParameter" } + + override string toString() { result = "&" + this.getName() } + + /** Gets the name of the parameter. */ + string getName() { result = generated.getName().getValue() } +} + +/** + * A parameter that is destructured. For example, the parameter `(a, b)` in the + * following code: + * ``` + * pairs.each do |(a, b)| + * puts a + b + * end + * ``` + */ +class PatternParameter extends @destructured_parameter, Parameter, Pattern { + Generated::DestructuredParameter generated; + + PatternParameter() { generated = this } + + override string describeQlClass() { result = "PatternParameter" } + + override string toString() { result = "(..., ...)" } + + /** + * Gets the number of parameters of this destructuring. + */ + override int getNumberOfElements() { result = count(this.getElement(_)) } + + /** + * Gets the nth parameter of this pattern. + */ + override AstNode getElement(int n) { result = generated.getChild(n) } +} + +/** + * A hash-splat (or double-splat) parameter. For example, `**options` in the + * following code: + * ``` + * def foo(bar, **options) + * ... + * end + * ``` + */ +class HashSplatParameter extends @hash_splat_parameter, Parameter { + Generated::HashSplatParameter generated; + + HashSplatParameter() { generated = this } + + override string describeQlClass() { result = "HashSplatParameter" } + + override string toString() { result = "**" + this.getName() } + + /** Gets the name of the parameter. */ + string getName() { result = generated.getName().getValue() } +} + +/** + * TODO + */ +class KeywordParameter extends @keyword_parameter, Parameter { + Generated::KeywordParameter generated; + + KeywordParameter() { generated = this } + + override string describeQlClass() { result = "KeywordParameter" } + + /** Gets the name of the parameter. */ + string getName() { result = generated.getName().getValue() } + + /** + * Gets the default value, i.e. the value assigned to the parameter when one + * is not provided by the caller. If the parameter is mandatory and does not + * have a default value, this predicate has no result. + * TODO: better return type (Expr?) + */ + AstNode getDefaultValue() { result = generated.getValue() } + + override string toString() { result = this.getName() } +} + +/** + * An optional parameter. For example, the parameter `name` in the following + * code: + * ``` + * def say_hello(name = 'Anon') + * puts "hello #{name}" + * end + * ``` + */ +class OptionalParameter extends @optional_parameter, Parameter { + Generated::OptionalParameter generated; + + OptionalParameter() { generated = this } + + override string describeQlClass() { result = "OptionalParameter" } + + override string toString() { result = this.getName() } + + /** Gets the name of the parameter. */ + string getName() { result = generated.getName().getValue() } + + /** + * Gets the default value, i.e. the value assigned to the parameter when one + * is not provided by the caller. + * TODO: better return type (Expr?) + */ + AstNode getDefaultValue() { result = generated.getValue() } +} + +/** + * A splat parameter. For example, `*values` in the following code: + * ``` + * def foo(bar, *values) + * ... + * end + * ``` + */ +class SplatParameter extends @splat_parameter, Parameter { + Generated::SplatParameter generated; + + SplatParameter() { generated = this } + + override string describeQlClass() { result = "SplatParameter" } + + override string toString() { result = this.getName() } + + /** Gets the name of the parameter. */ + string getName() { result = generated.getName().getValue() } +} + +/** + * An identifier that is a parameter in a block, lambda, or method. + */ +class IdentifierParameter extends @token_identifier, Parameter { + IdentifierParameter() { + block_parameters_child(_, _, this) or + destructured_parameter_child(_, _, this) or + lambda_parameters_child(_, _, this) or + method_parameters_child(_, _, this) + } + + override string describeQlClass() { result = "IdentifierParameter" } + + override string toString() { result = this.getName() } + + /** Gets the name of the parameter. */ + string getName() { result = this.(Generated::Identifier).getValue() } +} diff --git a/ql/src/codeql_ruby/ast.qll b/ql/src/codeql_ruby/ast.qll deleted file mode 100644 index 7933f90c81e2..000000000000 --- a/ql/src/codeql_ruby/ast.qll +++ /dev/null @@ -1,1530 +0,0 @@ -/* - * CodeQL library for Ruby - * Automatically generated from the tree-sitter grammar; do not edit - */ - -import codeql.files.FileSystem -import codeql.Locations - -class AstNode extends @ast_node { - string toString() { result = this.describeQlClass() } - - Location getLocation() { none() } - - AstNode getParent() { none() } - - int getParentIndex() { none() } - - AstNode getAFieldOrChild() { none() } - - string describeQlClass() { result = "???" } -} - -class Token extends @token, AstNode { - override AstNode getParent() { tokeninfo(this, result, _, _, _, _, _, _) } - - override int getParentIndex() { tokeninfo(this, _, result, _, _, _, _, _) } - - string getValue() { tokeninfo(this, _, _, _, _, _, result, _) } - - override Location getLocation() { tokeninfo(this, _, _, _, _, _, _, result) } - - override string toString() { result = getValue() } - - override string describeQlClass() { result = "Token" } -} - -class ReservedWord extends @reserved_word, Token { - override string describeQlClass() { result = "ReservedWord" } -} - -class UnderscoreArg extends @underscore_arg, AstNode { } - -class UnderscoreLhs extends @underscore_lhs, AstNode { } - -class UnderscoreMethodName extends @underscore_method_name, AstNode { } - -class UnderscorePrimary extends @underscore_primary, AstNode { } - -class UnderscoreStatement extends @underscore_statement, AstNode { } - -class UnderscoreVariable extends @underscore_variable, AstNode { } - -class Alias extends @alias, AstNode { - override string describeQlClass() { result = "Alias" } - - override Location getLocation() { alias_def(this, _, _, _, _, result) } - - UnderscoreMethodName getAlias() { alias_def(this, _, _, result, _, _) } - - UnderscoreMethodName getName() { alias_def(this, _, _, _, result, _) } - - override AstNode getParent() { alias_def(this, result, _, _, _, _) } - - override int getParentIndex() { alias_def(this, _, result, _, _, _) } - - override AstNode getAFieldOrChild() { - alias_def(this, _, _, result, _, _) or alias_def(this, _, _, _, result, _) - } -} - -class ArgumentList extends @argument_list, AstNode { - override string describeQlClass() { result = "ArgumentList" } - - override Location getLocation() { argument_list_def(this, _, _, result) } - - AstNode getChild(int i) { argument_list_child(this, i, result) } - - override AstNode getParent() { argument_list_def(this, result, _, _) } - - override int getParentIndex() { argument_list_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { argument_list_child(this, _, result) } -} - -class Array extends @array, AstNode { - override string describeQlClass() { result = "Array" } - - override Location getLocation() { array_def(this, _, _, result) } - - AstNode getChild(int i) { array_child(this, i, result) } - - override AstNode getParent() { array_def(this, result, _, _) } - - override int getParentIndex() { array_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { array_child(this, _, result) } -} - -class Assignment extends @assignment, AstNode { - override string describeQlClass() { result = "Assignment" } - - override Location getLocation() { assignment_def(this, _, _, _, _, result) } - - AstNode getLeft() { assignment_def(this, _, _, result, _, _) } - - AstNode getRight() { assignment_def(this, _, _, _, result, _) } - - override AstNode getParent() { assignment_def(this, result, _, _, _, _) } - - override int getParentIndex() { assignment_def(this, _, result, _, _, _) } - - override AstNode getAFieldOrChild() { - assignment_def(this, _, _, result, _, _) or assignment_def(this, _, _, _, result, _) - } -} - -class BareString extends @bare_string, AstNode { - override string describeQlClass() { result = "BareString" } - - override Location getLocation() { bare_string_def(this, _, _, result) } - - AstNode getChild(int i) { bare_string_child(this, i, result) } - - override AstNode getParent() { bare_string_def(this, result, _, _) } - - override int getParentIndex() { bare_string_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { bare_string_child(this, _, result) } -} - -class BareSymbol extends @bare_symbol, AstNode { - override string describeQlClass() { result = "BareSymbol" } - - override Location getLocation() { bare_symbol_def(this, _, _, result) } - - AstNode getChild(int i) { bare_symbol_child(this, i, result) } - - override AstNode getParent() { bare_symbol_def(this, result, _, _) } - - override int getParentIndex() { bare_symbol_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { bare_symbol_child(this, _, result) } -} - -class Begin extends @begin, AstNode { - override string describeQlClass() { result = "Begin" } - - override Location getLocation() { begin_def(this, _, _, result) } - - AstNode getChild(int i) { begin_child(this, i, result) } - - override AstNode getParent() { begin_def(this, result, _, _) } - - override int getParentIndex() { begin_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { begin_child(this, _, result) } -} - -class BeginBlock extends @begin_block, AstNode { - override string describeQlClass() { result = "BeginBlock" } - - override Location getLocation() { begin_block_def(this, _, _, result) } - - AstNode getChild(int i) { begin_block_child(this, i, result) } - - override AstNode getParent() { begin_block_def(this, result, _, _) } - - override int getParentIndex() { begin_block_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { begin_block_child(this, _, result) } -} - -class Binary extends @binary, AstNode { - override string describeQlClass() { result = "Binary" } - - override Location getLocation() { binary_def(this, _, _, _, _, _, result) } - - AstNode getLeft() { binary_def(this, _, _, result, _, _, _) } - - AstNode getOperator() { binary_def(this, _, _, _, result, _, _) } - - AstNode getRight() { binary_def(this, _, _, _, _, result, _) } - - override AstNode getParent() { binary_def(this, result, _, _, _, _, _) } - - override int getParentIndex() { binary_def(this, _, result, _, _, _, _) } - - override AstNode getAFieldOrChild() { - binary_def(this, _, _, result, _, _, _) or - binary_def(this, _, _, _, result, _, _) or - binary_def(this, _, _, _, _, result, _) - } -} - -class Block extends @block, AstNode { - override string describeQlClass() { result = "Block" } - - override Location getLocation() { block_def(this, _, _, result) } - - AstNode getChild(int i) { block_child(this, i, result) } - - override AstNode getParent() { block_def(this, result, _, _) } - - override int getParentIndex() { block_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { block_child(this, _, result) } -} - -class BlockArgument extends @block_argument, AstNode { - override string describeQlClass() { result = "BlockArgument" } - - override Location getLocation() { block_argument_def(this, _, _, _, result) } - - UnderscoreArg getChild() { block_argument_def(this, _, _, result, _) } - - override AstNode getParent() { block_argument_def(this, result, _, _, _) } - - override int getParentIndex() { block_argument_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { block_argument_def(this, _, _, result, _) } -} - -class BlockParameter extends @block_parameter, AstNode { - override string describeQlClass() { result = "BlockParameter" } - - override Location getLocation() { block_parameter_def(this, _, _, _, result) } - - Identifier getName() { block_parameter_def(this, _, _, result, _) } - - override AstNode getParent() { block_parameter_def(this, result, _, _, _) } - - override int getParentIndex() { block_parameter_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { block_parameter_def(this, _, _, result, _) } -} - -class BlockParameters extends @block_parameters, AstNode { - override string describeQlClass() { result = "BlockParameters" } - - override Location getLocation() { block_parameters_def(this, _, _, result) } - - AstNode getChild(int i) { block_parameters_child(this, i, result) } - - override AstNode getParent() { block_parameters_def(this, result, _, _) } - - override int getParentIndex() { block_parameters_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { block_parameters_child(this, _, result) } -} - -class Break extends @break, AstNode { - override string describeQlClass() { result = "Break" } - - override Location getLocation() { break_def(this, _, _, result) } - - ArgumentList getChild() { break_child(this, result) } - - override AstNode getParent() { break_def(this, result, _, _) } - - override int getParentIndex() { break_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { break_child(this, result) } -} - -class Call extends @call, AstNode { - override string describeQlClass() { result = "Call" } - - override Location getLocation() { call_def(this, _, _, _, _, result) } - - AstNode getMethod() { call_def(this, _, _, result, _, _) } - - AstNode getReceiver() { call_def(this, _, _, _, result, _) } - - override AstNode getParent() { call_def(this, result, _, _, _, _) } - - override int getParentIndex() { call_def(this, _, result, _, _, _) } - - override AstNode getAFieldOrChild() { - call_def(this, _, _, result, _, _) or call_def(this, _, _, _, result, _) - } -} - -class Case extends @case__, AstNode { - override string describeQlClass() { result = "Case" } - - override Location getLocation() { case_def(this, _, _, result) } - - UnderscoreStatement getValue() { case_value(this, result) } - - AstNode getChild(int i) { case_child(this, i, result) } - - override AstNode getParent() { case_def(this, result, _, _) } - - override int getParentIndex() { case_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { case_value(this, result) or case_child(this, _, result) } -} - -class ChainedString extends @chained_string, AstNode { - override string describeQlClass() { result = "ChainedString" } - - override Location getLocation() { chained_string_def(this, _, _, result) } - - String getChild(int i) { chained_string_child(this, i, result) } - - override AstNode getParent() { chained_string_def(this, result, _, _) } - - override int getParentIndex() { chained_string_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { chained_string_child(this, _, result) } -} - -class Character extends @token_character, Token { - override string describeQlClass() { result = "Character" } -} - -class Class extends @class, AstNode { - override string describeQlClass() { result = "Class" } - - override Location getLocation() { class_def(this, _, _, _, result) } - - AstNode getName() { class_def(this, _, _, result, _) } - - AstNode getChild(int i) { class_child(this, i, result) } - - override AstNode getParent() { class_def(this, result, _, _, _) } - - override int getParentIndex() { class_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { - class_def(this, _, _, result, _) or class_child(this, _, result) - } -} - -class ClassVariable extends @token_class_variable, Token { - override string describeQlClass() { result = "ClassVariable" } -} - -class Comment extends @token_comment, Token { - override string describeQlClass() { result = "Comment" } -} - -class Complex extends @token_complex, Token { - override string describeQlClass() { result = "Complex" } -} - -class Conditional extends @conditional, AstNode { - override string describeQlClass() { result = "Conditional" } - - override Location getLocation() { conditional_def(this, _, _, _, _, _, result) } - - UnderscoreArg getAlternative() { conditional_def(this, _, _, result, _, _, _) } - - UnderscoreArg getCondition() { conditional_def(this, _, _, _, result, _, _) } - - UnderscoreArg getConsequence() { conditional_def(this, _, _, _, _, result, _) } - - override AstNode getParent() { conditional_def(this, result, _, _, _, _, _) } - - override int getParentIndex() { conditional_def(this, _, result, _, _, _, _) } - - override AstNode getAFieldOrChild() { - conditional_def(this, _, _, result, _, _, _) or - conditional_def(this, _, _, _, result, _, _) or - conditional_def(this, _, _, _, _, result, _) - } -} - -class Constant extends @token_constant, Token { - override string describeQlClass() { result = "Constant" } -} - -class DestructuredLeftAssignment extends @destructured_left_assignment, AstNode { - override string describeQlClass() { result = "DestructuredLeftAssignment" } - - override Location getLocation() { destructured_left_assignment_def(this, _, _, result) } - - AstNode getChild(int i) { destructured_left_assignment_child(this, i, result) } - - override AstNode getParent() { destructured_left_assignment_def(this, result, _, _) } - - override int getParentIndex() { destructured_left_assignment_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { destructured_left_assignment_child(this, _, result) } -} - -class DestructuredParameter extends @destructured_parameter, AstNode { - override string describeQlClass() { result = "DestructuredParameter" } - - override Location getLocation() { destructured_parameter_def(this, _, _, result) } - - AstNode getChild(int i) { destructured_parameter_child(this, i, result) } - - override AstNode getParent() { destructured_parameter_def(this, result, _, _) } - - override int getParentIndex() { destructured_parameter_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { destructured_parameter_child(this, _, result) } -} - -class Do extends @do, AstNode { - override string describeQlClass() { result = "Do" } - - override Location getLocation() { do_def(this, _, _, result) } - - AstNode getChild(int i) { do_child(this, i, result) } - - override AstNode getParent() { do_def(this, result, _, _) } - - override int getParentIndex() { do_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { do_child(this, _, result) } -} - -class DoBlock extends @do_block, AstNode { - override string describeQlClass() { result = "DoBlock" } - - override Location getLocation() { do_block_def(this, _, _, result) } - - AstNode getChild(int i) { do_block_child(this, i, result) } - - override AstNode getParent() { do_block_def(this, result, _, _) } - - override int getParentIndex() { do_block_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { do_block_child(this, _, result) } -} - -class ElementReference extends @element_reference, AstNode { - override string describeQlClass() { result = "ElementReference" } - - override Location getLocation() { element_reference_def(this, _, _, _, result) } - - UnderscorePrimary getObject() { element_reference_def(this, _, _, result, _) } - - AstNode getChild(int i) { element_reference_child(this, i, result) } - - override AstNode getParent() { element_reference_def(this, result, _, _, _) } - - override int getParentIndex() { element_reference_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { - element_reference_def(this, _, _, result, _) or element_reference_child(this, _, result) - } -} - -class Else extends @else, AstNode { - override string describeQlClass() { result = "Else" } - - override Location getLocation() { else_def(this, _, _, result) } - - AstNode getChild(int i) { else_child(this, i, result) } - - override AstNode getParent() { else_def(this, result, _, _) } - - override int getParentIndex() { else_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { else_child(this, _, result) } -} - -class Elsif extends @elsif, AstNode { - override string describeQlClass() { result = "Elsif" } - - override Location getLocation() { elsif_def(this, _, _, _, result) } - - AstNode getAlternative() { elsif_alternative(this, result) } - - UnderscoreStatement getCondition() { elsif_def(this, _, _, result, _) } - - Then getConsequence() { elsif_consequence(this, result) } - - override AstNode getParent() { elsif_def(this, result, _, _, _) } - - override int getParentIndex() { elsif_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { - elsif_alternative(this, result) or - elsif_def(this, _, _, result, _) or - elsif_consequence(this, result) - } -} - -class EmptyStatement extends @token_empty_statement, Token { - override string describeQlClass() { result = "EmptyStatement" } -} - -class EndBlock extends @end_block, AstNode { - override string describeQlClass() { result = "EndBlock" } - - override Location getLocation() { end_block_def(this, _, _, result) } - - AstNode getChild(int i) { end_block_child(this, i, result) } - - override AstNode getParent() { end_block_def(this, result, _, _) } - - override int getParentIndex() { end_block_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { end_block_child(this, _, result) } -} - -class Ensure extends @ensure, AstNode { - override string describeQlClass() { result = "Ensure" } - - override Location getLocation() { ensure_def(this, _, _, result) } - - AstNode getChild(int i) { ensure_child(this, i, result) } - - override AstNode getParent() { ensure_def(this, result, _, _) } - - override int getParentIndex() { ensure_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { ensure_child(this, _, result) } -} - -class EscapeSequence extends @token_escape_sequence, Token { - override string describeQlClass() { result = "EscapeSequence" } -} - -class ExceptionVariable extends @exception_variable, AstNode { - override string describeQlClass() { result = "ExceptionVariable" } - - override Location getLocation() { exception_variable_def(this, _, _, _, result) } - - UnderscoreLhs getChild() { exception_variable_def(this, _, _, result, _) } - - override AstNode getParent() { exception_variable_def(this, result, _, _, _) } - - override int getParentIndex() { exception_variable_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { exception_variable_def(this, _, _, result, _) } -} - -class Exceptions extends @exceptions, AstNode { - override string describeQlClass() { result = "Exceptions" } - - override Location getLocation() { exceptions_def(this, _, _, result) } - - AstNode getChild(int i) { exceptions_child(this, i, result) } - - override AstNode getParent() { exceptions_def(this, result, _, _) } - - override int getParentIndex() { exceptions_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { exceptions_child(this, _, result) } -} - -class False extends @token_false, Token { - override string describeQlClass() { result = "False" } -} - -class Float extends @token_float, Token { - override string describeQlClass() { result = "Float" } -} - -class For extends @for, AstNode { - override string describeQlClass() { result = "For" } - - override Location getLocation() { for_def(this, _, _, _, _, result) } - - Do getBody() { for_def(this, _, _, result, _, _) } - - AstNode getPattern(int i) { for_pattern(this, i, result) } - - In getValue() { for_def(this, _, _, _, result, _) } - - override AstNode getParent() { for_def(this, result, _, _, _, _) } - - override int getParentIndex() { for_def(this, _, result, _, _, _) } - - override AstNode getAFieldOrChild() { - for_def(this, _, _, result, _, _) or - for_pattern(this, _, result) or - for_def(this, _, _, _, result, _) - } -} - -class GlobalVariable extends @token_global_variable, Token { - override string describeQlClass() { result = "GlobalVariable" } -} - -class Hash extends @hash, AstNode { - override string describeQlClass() { result = "Hash" } - - override Location getLocation() { hash_def(this, _, _, result) } - - AstNode getChild(int i) { hash_child(this, i, result) } - - override AstNode getParent() { hash_def(this, result, _, _) } - - override int getParentIndex() { hash_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { hash_child(this, _, result) } -} - -class HashSplatArgument extends @hash_splat_argument, AstNode { - override string describeQlClass() { result = "HashSplatArgument" } - - override Location getLocation() { hash_splat_argument_def(this, _, _, _, result) } - - UnderscoreArg getChild() { hash_splat_argument_def(this, _, _, result, _) } - - override AstNode getParent() { hash_splat_argument_def(this, result, _, _, _) } - - override int getParentIndex() { hash_splat_argument_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { hash_splat_argument_def(this, _, _, result, _) } -} - -class HashSplatParameter extends @hash_splat_parameter, AstNode { - override string describeQlClass() { result = "HashSplatParameter" } - - override Location getLocation() { hash_splat_parameter_def(this, _, _, result) } - - Identifier getName() { hash_splat_parameter_name(this, result) } - - override AstNode getParent() { hash_splat_parameter_def(this, result, _, _) } - - override int getParentIndex() { hash_splat_parameter_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { hash_splat_parameter_name(this, result) } -} - -class HeredocBeginning extends @token_heredoc_beginning, Token { - override string describeQlClass() { result = "HeredocBeginning" } -} - -class HeredocBody extends @heredoc_body, AstNode { - override string describeQlClass() { result = "HeredocBody" } - - override Location getLocation() { heredoc_body_def(this, _, _, result) } - - AstNode getChild(int i) { heredoc_body_child(this, i, result) } - - override AstNode getParent() { heredoc_body_def(this, result, _, _) } - - override int getParentIndex() { heredoc_body_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { heredoc_body_child(this, _, result) } -} - -class HeredocContent extends @token_heredoc_content, Token { - override string describeQlClass() { result = "HeredocContent" } -} - -class HeredocEnd extends @token_heredoc_end, Token { - override string describeQlClass() { result = "HeredocEnd" } -} - -class Identifier extends @token_identifier, Token { - override string describeQlClass() { result = "Identifier" } -} - -class If extends @if, AstNode { - override string describeQlClass() { result = "If" } - - override Location getLocation() { if_def(this, _, _, _, result) } - - AstNode getAlternative() { if_alternative(this, result) } - - UnderscoreStatement getCondition() { if_def(this, _, _, result, _) } - - Then getConsequence() { if_consequence(this, result) } - - override AstNode getParent() { if_def(this, result, _, _, _) } - - override int getParentIndex() { if_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { - if_alternative(this, result) or if_def(this, _, _, result, _) or if_consequence(this, result) - } -} - -class IfModifier extends @if_modifier, AstNode { - override string describeQlClass() { result = "IfModifier" } - - override Location getLocation() { if_modifier_def(this, _, _, _, _, result) } - - UnderscoreStatement getBody() { if_modifier_def(this, _, _, result, _, _) } - - AstNode getCondition() { if_modifier_def(this, _, _, _, result, _) } - - override AstNode getParent() { if_modifier_def(this, result, _, _, _, _) } - - override int getParentIndex() { if_modifier_def(this, _, result, _, _, _) } - - override AstNode getAFieldOrChild() { - if_modifier_def(this, _, _, result, _, _) or if_modifier_def(this, _, _, _, result, _) - } -} - -class In extends @in, AstNode { - override string describeQlClass() { result = "In" } - - override Location getLocation() { in_def(this, _, _, _, result) } - - UnderscoreArg getChild() { in_def(this, _, _, result, _) } - - override AstNode getParent() { in_def(this, result, _, _, _) } - - override int getParentIndex() { in_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { in_def(this, _, _, result, _) } -} - -class InstanceVariable extends @token_instance_variable, Token { - override string describeQlClass() { result = "InstanceVariable" } -} - -class Integer extends @token_integer, Token { - override string describeQlClass() { result = "Integer" } -} - -class Interpolation extends @interpolation, AstNode { - override string describeQlClass() { result = "Interpolation" } - - override Location getLocation() { interpolation_def(this, _, _, _, result) } - - UnderscoreStatement getChild() { interpolation_def(this, _, _, result, _) } - - override AstNode getParent() { interpolation_def(this, result, _, _, _) } - - override int getParentIndex() { interpolation_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { interpolation_def(this, _, _, result, _) } -} - -class KeywordParameter extends @keyword_parameter, AstNode { - override string describeQlClass() { result = "KeywordParameter" } - - override Location getLocation() { keyword_parameter_def(this, _, _, _, result) } - - Identifier getName() { keyword_parameter_def(this, _, _, result, _) } - - UnderscoreArg getValue() { keyword_parameter_value(this, result) } - - override AstNode getParent() { keyword_parameter_def(this, result, _, _, _) } - - override int getParentIndex() { keyword_parameter_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { - keyword_parameter_def(this, _, _, result, _) or keyword_parameter_value(this, result) - } -} - -class Lambda extends @lambda, AstNode { - override string describeQlClass() { result = "Lambda" } - - override Location getLocation() { lambda_def(this, _, _, _, result) } - - AstNode getBody() { lambda_def(this, _, _, result, _) } - - LambdaParameters getParameters() { lambda_parameters(this, result) } - - override AstNode getParent() { lambda_def(this, result, _, _, _) } - - override int getParentIndex() { lambda_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { - lambda_def(this, _, _, result, _) or lambda_parameters(this, result) - } -} - -class LambdaParameters extends @lambda_parameters, AstNode { - override string describeQlClass() { result = "LambdaParameters" } - - override Location getLocation() { lambda_parameters_def(this, _, _, result) } - - AstNode getChild(int i) { lambda_parameters_child(this, i, result) } - - override AstNode getParent() { lambda_parameters_def(this, result, _, _) } - - override int getParentIndex() { lambda_parameters_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { lambda_parameters_child(this, _, result) } -} - -class LeftAssignmentList extends @left_assignment_list, AstNode { - override string describeQlClass() { result = "LeftAssignmentList" } - - override Location getLocation() { left_assignment_list_def(this, _, _, result) } - - AstNode getChild(int i) { left_assignment_list_child(this, i, result) } - - override AstNode getParent() { left_assignment_list_def(this, result, _, _) } - - override int getParentIndex() { left_assignment_list_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { left_assignment_list_child(this, _, result) } -} - -class Method extends @method, AstNode { - override string describeQlClass() { result = "Method" } - - override Location getLocation() { method_def(this, _, _, _, result) } - - UnderscoreMethodName getName() { method_def(this, _, _, result, _) } - - MethodParameters getParameters() { method_parameters(this, result) } - - AstNode getChild(int i) { method_child(this, i, result) } - - override AstNode getParent() { method_def(this, result, _, _, _) } - - override int getParentIndex() { method_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { - method_def(this, _, _, result, _) or - method_parameters(this, result) or - method_child(this, _, result) - } -} - -class MethodCall extends @method_call, AstNode { - override string describeQlClass() { result = "MethodCall" } - - override Location getLocation() { method_call_def(this, _, _, _, result) } - - ArgumentList getArguments() { method_call_arguments(this, result) } - - AstNode getBlock() { method_call_block(this, result) } - - AstNode getMethod() { method_call_def(this, _, _, result, _) } - - override AstNode getParent() { method_call_def(this, result, _, _, _) } - - override int getParentIndex() { method_call_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { - method_call_arguments(this, result) or - method_call_block(this, result) or - method_call_def(this, _, _, result, _) - } -} - -class MethodParameters extends @method_parameters, AstNode { - override string describeQlClass() { result = "MethodParameters" } - - override Location getLocation() { method_parameters_def(this, _, _, result) } - - AstNode getChild(int i) { method_parameters_child(this, i, result) } - - override AstNode getParent() { method_parameters_def(this, result, _, _) } - - override int getParentIndex() { method_parameters_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { method_parameters_child(this, _, result) } -} - -class Module extends @module, AstNode { - override string describeQlClass() { result = "Module" } - - override Location getLocation() { module_def(this, _, _, _, result) } - - AstNode getName() { module_def(this, _, _, result, _) } - - AstNode getChild(int i) { module_child(this, i, result) } - - override AstNode getParent() { module_def(this, result, _, _, _) } - - override int getParentIndex() { module_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { - module_def(this, _, _, result, _) or module_child(this, _, result) - } -} - -class Next extends @next, AstNode { - override string describeQlClass() { result = "Next" } - - override Location getLocation() { next_def(this, _, _, result) } - - ArgumentList getChild() { next_child(this, result) } - - override AstNode getParent() { next_def(this, result, _, _) } - - override int getParentIndex() { next_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { next_child(this, result) } -} - -class Nil extends @token_nil, Token { - override string describeQlClass() { result = "Nil" } -} - -class Operator extends @token_operator, Token { - override string describeQlClass() { result = "Operator" } -} - -class OperatorAssignment extends @operator_assignment, AstNode { - override string describeQlClass() { result = "OperatorAssignment" } - - override Location getLocation() { operator_assignment_def(this, _, _, _, _, result) } - - UnderscoreLhs getLeft() { operator_assignment_def(this, _, _, result, _, _) } - - AstNode getRight() { operator_assignment_def(this, _, _, _, result, _) } - - override AstNode getParent() { operator_assignment_def(this, result, _, _, _, _) } - - override int getParentIndex() { operator_assignment_def(this, _, result, _, _, _) } - - override AstNode getAFieldOrChild() { - operator_assignment_def(this, _, _, result, _, _) or - operator_assignment_def(this, _, _, _, result, _) - } -} - -class OptionalParameter extends @optional_parameter, AstNode { - override string describeQlClass() { result = "OptionalParameter" } - - override Location getLocation() { optional_parameter_def(this, _, _, _, _, result) } - - Identifier getName() { optional_parameter_def(this, _, _, result, _, _) } - - UnderscoreArg getValue() { optional_parameter_def(this, _, _, _, result, _) } - - override AstNode getParent() { optional_parameter_def(this, result, _, _, _, _) } - - override int getParentIndex() { optional_parameter_def(this, _, result, _, _, _) } - - override AstNode getAFieldOrChild() { - optional_parameter_def(this, _, _, result, _, _) or - optional_parameter_def(this, _, _, _, result, _) - } -} - -class Pair extends @pair, AstNode { - override string describeQlClass() { result = "Pair" } - - override Location getLocation() { pair_def(this, _, _, _, _, result) } - - AstNode getKey() { pair_def(this, _, _, result, _, _) } - - UnderscoreArg getValue() { pair_def(this, _, _, _, result, _) } - - override AstNode getParent() { pair_def(this, result, _, _, _, _) } - - override int getParentIndex() { pair_def(this, _, result, _, _, _) } - - override AstNode getAFieldOrChild() { - pair_def(this, _, _, result, _, _) or pair_def(this, _, _, _, result, _) - } -} - -class ParenthesizedStatements extends @parenthesized_statements, AstNode { - override string describeQlClass() { result = "ParenthesizedStatements" } - - override Location getLocation() { parenthesized_statements_def(this, _, _, result) } - - AstNode getChild(int i) { parenthesized_statements_child(this, i, result) } - - override AstNode getParent() { parenthesized_statements_def(this, result, _, _) } - - override int getParentIndex() { parenthesized_statements_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { parenthesized_statements_child(this, _, result) } -} - -class Pattern extends @pattern, AstNode { - override string describeQlClass() { result = "Pattern" } - - override Location getLocation() { pattern_def(this, _, _, _, result) } - - AstNode getChild() { pattern_def(this, _, _, result, _) } - - override AstNode getParent() { pattern_def(this, result, _, _, _) } - - override int getParentIndex() { pattern_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { pattern_def(this, _, _, result, _) } -} - -class Program extends @program, AstNode { - override string describeQlClass() { result = "Program" } - - override Location getLocation() { program_def(this, _, _, result) } - - AstNode getChild(int i) { program_child(this, i, result) } - - override AstNode getParent() { program_def(this, result, _, _) } - - override int getParentIndex() { program_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { program_child(this, _, result) } -} - -class Range extends @range, AstNode { - override string describeQlClass() { result = "Range" } - - override Location getLocation() { range_def(this, _, _, result) } - - UnderscoreArg getChild(int i) { range_child(this, i, result) } - - override AstNode getParent() { range_def(this, result, _, _) } - - override int getParentIndex() { range_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { range_child(this, _, result) } -} - -class Rational extends @rational, AstNode { - override string describeQlClass() { result = "Rational" } - - override Location getLocation() { rational_def(this, _, _, _, result) } - - Integer getChild() { rational_def(this, _, _, result, _) } - - override AstNode getParent() { rational_def(this, result, _, _, _) } - - override int getParentIndex() { rational_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { rational_def(this, _, _, result, _) } -} - -class Redo extends @redo, AstNode { - override string describeQlClass() { result = "Redo" } - - override Location getLocation() { redo_def(this, _, _, result) } - - ArgumentList getChild() { redo_child(this, result) } - - override AstNode getParent() { redo_def(this, result, _, _) } - - override int getParentIndex() { redo_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { redo_child(this, result) } -} - -class Regex extends @regex, AstNode { - override string describeQlClass() { result = "Regex" } - - override Location getLocation() { regex_def(this, _, _, result) } - - AstNode getChild(int i) { regex_child(this, i, result) } - - override AstNode getParent() { regex_def(this, result, _, _) } - - override int getParentIndex() { regex_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { regex_child(this, _, result) } -} - -class Rescue extends @rescue, AstNode { - override string describeQlClass() { result = "Rescue" } - - override Location getLocation() { rescue_def(this, _, _, result) } - - Then getBody() { rescue_body(this, result) } - - Exceptions getExceptions() { rescue_exceptions(this, result) } - - ExceptionVariable getVariable() { rescue_variable(this, result) } - - override AstNode getParent() { rescue_def(this, result, _, _) } - - override int getParentIndex() { rescue_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { - rescue_body(this, result) or rescue_exceptions(this, result) or rescue_variable(this, result) - } -} - -class RescueModifier extends @rescue_modifier, AstNode { - override string describeQlClass() { result = "RescueModifier" } - - override Location getLocation() { rescue_modifier_def(this, _, _, _, _, result) } - - UnderscoreStatement getBody() { rescue_modifier_def(this, _, _, result, _, _) } - - AstNode getHandler() { rescue_modifier_def(this, _, _, _, result, _) } - - override AstNode getParent() { rescue_modifier_def(this, result, _, _, _, _) } - - override int getParentIndex() { rescue_modifier_def(this, _, result, _, _, _) } - - override AstNode getAFieldOrChild() { - rescue_modifier_def(this, _, _, result, _, _) or rescue_modifier_def(this, _, _, _, result, _) - } -} - -class RestAssignment extends @rest_assignment, AstNode { - override string describeQlClass() { result = "RestAssignment" } - - override Location getLocation() { rest_assignment_def(this, _, _, result) } - - UnderscoreLhs getChild() { rest_assignment_child(this, result) } - - override AstNode getParent() { rest_assignment_def(this, result, _, _) } - - override int getParentIndex() { rest_assignment_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { rest_assignment_child(this, result) } -} - -class Retry extends @retry, AstNode { - override string describeQlClass() { result = "Retry" } - - override Location getLocation() { retry_def(this, _, _, result) } - - ArgumentList getChild() { retry_child(this, result) } - - override AstNode getParent() { retry_def(this, result, _, _) } - - override int getParentIndex() { retry_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { retry_child(this, result) } -} - -class Return extends @return, AstNode { - override string describeQlClass() { result = "Return" } - - override Location getLocation() { return_def(this, _, _, result) } - - ArgumentList getChild() { return_child(this, result) } - - override AstNode getParent() { return_def(this, result, _, _) } - - override int getParentIndex() { return_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { return_child(this, result) } -} - -class RightAssignmentList extends @right_assignment_list, AstNode { - override string describeQlClass() { result = "RightAssignmentList" } - - override Location getLocation() { right_assignment_list_def(this, _, _, result) } - - AstNode getChild(int i) { right_assignment_list_child(this, i, result) } - - override AstNode getParent() { right_assignment_list_def(this, result, _, _) } - - override int getParentIndex() { right_assignment_list_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { right_assignment_list_child(this, _, result) } -} - -class ScopeResolution extends @scope_resolution, AstNode { - override string describeQlClass() { result = "ScopeResolution" } - - override Location getLocation() { scope_resolution_def(this, _, _, _, result) } - - AstNode getName() { scope_resolution_def(this, _, _, result, _) } - - UnderscorePrimary getScope() { scope_resolution_scope(this, result) } - - override AstNode getParent() { scope_resolution_def(this, result, _, _, _) } - - override int getParentIndex() { scope_resolution_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { - scope_resolution_def(this, _, _, result, _) or scope_resolution_scope(this, result) - } -} - -class Self extends @token_self, Token { - override string describeQlClass() { result = "Self" } -} - -class Setter extends @setter, AstNode { - override string describeQlClass() { result = "Setter" } - - override Location getLocation() { setter_def(this, _, _, _, result) } - - Identifier getChild() { setter_def(this, _, _, result, _) } - - override AstNode getParent() { setter_def(this, result, _, _, _) } - - override int getParentIndex() { setter_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { setter_def(this, _, _, result, _) } -} - -class SingletonClass extends @singleton_class, AstNode { - override string describeQlClass() { result = "SingletonClass" } - - override Location getLocation() { singleton_class_def(this, _, _, _, result) } - - UnderscoreArg getValue() { singleton_class_def(this, _, _, result, _) } - - AstNode getChild(int i) { singleton_class_child(this, i, result) } - - override AstNode getParent() { singleton_class_def(this, result, _, _, _) } - - override int getParentIndex() { singleton_class_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { - singleton_class_def(this, _, _, result, _) or singleton_class_child(this, _, result) - } -} - -class SingletonMethod extends @singleton_method, AstNode { - override string describeQlClass() { result = "SingletonMethod" } - - override Location getLocation() { singleton_method_def(this, _, _, _, _, result) } - - UnderscoreMethodName getName() { singleton_method_def(this, _, _, result, _, _) } - - AstNode getObject() { singleton_method_def(this, _, _, _, result, _) } - - MethodParameters getParameters() { singleton_method_parameters(this, result) } - - AstNode getChild(int i) { singleton_method_child(this, i, result) } - - override AstNode getParent() { singleton_method_def(this, result, _, _, _, _) } - - override int getParentIndex() { singleton_method_def(this, _, result, _, _, _) } - - override AstNode getAFieldOrChild() { - singleton_method_def(this, _, _, result, _, _) or - singleton_method_def(this, _, _, _, result, _) or - singleton_method_parameters(this, result) or - singleton_method_child(this, _, result) - } -} - -class SplatArgument extends @splat_argument, AstNode { - override string describeQlClass() { result = "SplatArgument" } - - override Location getLocation() { splat_argument_def(this, _, _, _, result) } - - UnderscoreArg getChild() { splat_argument_def(this, _, _, result, _) } - - override AstNode getParent() { splat_argument_def(this, result, _, _, _) } - - override int getParentIndex() { splat_argument_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { splat_argument_def(this, _, _, result, _) } -} - -class SplatParameter extends @splat_parameter, AstNode { - override string describeQlClass() { result = "SplatParameter" } - - override Location getLocation() { splat_parameter_def(this, _, _, result) } - - Identifier getName() { splat_parameter_name(this, result) } - - override AstNode getParent() { splat_parameter_def(this, result, _, _) } - - override int getParentIndex() { splat_parameter_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { splat_parameter_name(this, result) } -} - -class String extends @string__, AstNode { - override string describeQlClass() { result = "String" } - - override Location getLocation() { string_def(this, _, _, result) } - - AstNode getChild(int i) { string_child(this, i, result) } - - override AstNode getParent() { string_def(this, result, _, _) } - - override int getParentIndex() { string_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { string_child(this, _, result) } -} - -class StringArray extends @string_array, AstNode { - override string describeQlClass() { result = "StringArray" } - - override Location getLocation() { string_array_def(this, _, _, result) } - - BareString getChild(int i) { string_array_child(this, i, result) } - - override AstNode getParent() { string_array_def(this, result, _, _) } - - override int getParentIndex() { string_array_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { string_array_child(this, _, result) } -} - -class StringContent extends @token_string_content, Token { - override string describeQlClass() { result = "StringContent" } -} - -class Subshell extends @subshell, AstNode { - override string describeQlClass() { result = "Subshell" } - - override Location getLocation() { subshell_def(this, _, _, result) } - - AstNode getChild(int i) { subshell_child(this, i, result) } - - override AstNode getParent() { subshell_def(this, result, _, _) } - - override int getParentIndex() { subshell_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { subshell_child(this, _, result) } -} - -class Super extends @token_super, Token { - override string describeQlClass() { result = "Super" } -} - -class Superclass extends @superclass, AstNode { - override string describeQlClass() { result = "Superclass" } - - override Location getLocation() { superclass_def(this, _, _, _, result) } - - AstNode getChild() { superclass_def(this, _, _, result, _) } - - override AstNode getParent() { superclass_def(this, result, _, _, _) } - - override int getParentIndex() { superclass_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { superclass_def(this, _, _, result, _) } -} - -class Symbol extends @symbol, AstNode { - override string describeQlClass() { result = "Symbol" } - - override Location getLocation() { symbol_def(this, _, _, result) } - - AstNode getChild(int i) { symbol_child(this, i, result) } - - override AstNode getParent() { symbol_def(this, result, _, _) } - - override int getParentIndex() { symbol_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { symbol_child(this, _, result) } -} - -class SymbolArray extends @symbol_array, AstNode { - override string describeQlClass() { result = "SymbolArray" } - - override Location getLocation() { symbol_array_def(this, _, _, result) } - - BareSymbol getChild(int i) { symbol_array_child(this, i, result) } - - override AstNode getParent() { symbol_array_def(this, result, _, _) } - - override int getParentIndex() { symbol_array_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { symbol_array_child(this, _, result) } -} - -class Then extends @then, AstNode { - override string describeQlClass() { result = "Then" } - - override Location getLocation() { then_def(this, _, _, result) } - - AstNode getChild(int i) { then_child(this, i, result) } - - override AstNode getParent() { then_def(this, result, _, _) } - - override int getParentIndex() { then_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { then_child(this, _, result) } -} - -class True extends @token_true, Token { - override string describeQlClass() { result = "True" } -} - -class Unary extends @unary, AstNode { - override string describeQlClass() { result = "Unary" } - - override Location getLocation() { unary_def(this, _, _, _, _, result) } - - AstNode getOperand() { unary_def(this, _, _, result, _, _) } - - AstNode getOperator() { unary_def(this, _, _, _, result, _) } - - override AstNode getParent() { unary_def(this, result, _, _, _, _) } - - override int getParentIndex() { unary_def(this, _, result, _, _, _) } - - override AstNode getAFieldOrChild() { - unary_def(this, _, _, result, _, _) or unary_def(this, _, _, _, result, _) - } -} - -class Undef extends @undef, AstNode { - override string describeQlClass() { result = "Undef" } - - override Location getLocation() { undef_def(this, _, _, result) } - - UnderscoreMethodName getChild(int i) { undef_child(this, i, result) } - - override AstNode getParent() { undef_def(this, result, _, _) } - - override int getParentIndex() { undef_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { undef_child(this, _, result) } -} - -class Uninterpreted extends @token_uninterpreted, Token { - override string describeQlClass() { result = "Uninterpreted" } -} - -class Unless extends @unless, AstNode { - override string describeQlClass() { result = "Unless" } - - override Location getLocation() { unless_def(this, _, _, _, result) } - - AstNode getAlternative() { unless_alternative(this, result) } - - UnderscoreStatement getCondition() { unless_def(this, _, _, result, _) } - - Then getConsequence() { unless_consequence(this, result) } - - override AstNode getParent() { unless_def(this, result, _, _, _) } - - override int getParentIndex() { unless_def(this, _, result, _, _) } - - override AstNode getAFieldOrChild() { - unless_alternative(this, result) or - unless_def(this, _, _, result, _) or - unless_consequence(this, result) - } -} - -class UnlessModifier extends @unless_modifier, AstNode { - override string describeQlClass() { result = "UnlessModifier" } - - override Location getLocation() { unless_modifier_def(this, _, _, _, _, result) } - - UnderscoreStatement getBody() { unless_modifier_def(this, _, _, result, _, _) } - - AstNode getCondition() { unless_modifier_def(this, _, _, _, result, _) } - - override AstNode getParent() { unless_modifier_def(this, result, _, _, _, _) } - - override int getParentIndex() { unless_modifier_def(this, _, result, _, _, _) } - - override AstNode getAFieldOrChild() { - unless_modifier_def(this, _, _, result, _, _) or unless_modifier_def(this, _, _, _, result, _) - } -} - -class Until extends @until, AstNode { - override string describeQlClass() { result = "Until" } - - override Location getLocation() { until_def(this, _, _, _, _, result) } - - Do getBody() { until_def(this, _, _, result, _, _) } - - UnderscoreStatement getCondition() { until_def(this, _, _, _, result, _) } - - override AstNode getParent() { until_def(this, result, _, _, _, _) } - - override int getParentIndex() { until_def(this, _, result, _, _, _) } - - override AstNode getAFieldOrChild() { - until_def(this, _, _, result, _, _) or until_def(this, _, _, _, result, _) - } -} - -class UntilModifier extends @until_modifier, AstNode { - override string describeQlClass() { result = "UntilModifier" } - - override Location getLocation() { until_modifier_def(this, _, _, _, _, result) } - - UnderscoreStatement getBody() { until_modifier_def(this, _, _, result, _, _) } - - AstNode getCondition() { until_modifier_def(this, _, _, _, result, _) } - - override AstNode getParent() { until_modifier_def(this, result, _, _, _, _) } - - override int getParentIndex() { until_modifier_def(this, _, result, _, _, _) } - - override AstNode getAFieldOrChild() { - until_modifier_def(this, _, _, result, _, _) or until_modifier_def(this, _, _, _, result, _) - } -} - -class When extends @when, AstNode { - override string describeQlClass() { result = "When" } - - override Location getLocation() { when_def(this, _, _, result) } - - Then getBody() { when_body(this, result) } - - AstNode getPattern(int i) { when_pattern(this, i, result) } - - override AstNode getParent() { when_def(this, result, _, _) } - - override int getParentIndex() { when_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { when_body(this, result) or when_pattern(this, _, result) } -} - -class While extends @while, AstNode { - override string describeQlClass() { result = "While" } - - override Location getLocation() { while_def(this, _, _, _, _, result) } - - Do getBody() { while_def(this, _, _, result, _, _) } - - UnderscoreStatement getCondition() { while_def(this, _, _, _, result, _) } - - override AstNode getParent() { while_def(this, result, _, _, _, _) } - - override int getParentIndex() { while_def(this, _, result, _, _, _) } - - override AstNode getAFieldOrChild() { - while_def(this, _, _, result, _, _) or while_def(this, _, _, _, result, _) - } -} - -class WhileModifier extends @while_modifier, AstNode { - override string describeQlClass() { result = "WhileModifier" } - - override Location getLocation() { while_modifier_def(this, _, _, _, _, result) } - - UnderscoreStatement getBody() { while_modifier_def(this, _, _, result, _, _) } - - AstNode getCondition() { while_modifier_def(this, _, _, _, result, _) } - - override AstNode getParent() { while_modifier_def(this, result, _, _, _, _) } - - override int getParentIndex() { while_modifier_def(this, _, result, _, _, _) } - - override AstNode getAFieldOrChild() { - while_modifier_def(this, _, _, result, _, _) or while_modifier_def(this, _, _, _, result, _) - } -} - -class Yield extends @yield, AstNode { - override string describeQlClass() { result = "Yield" } - - override Location getLocation() { yield_def(this, _, _, result) } - - ArgumentList getChild() { yield_child(this, result) } - - override AstNode getParent() { yield_def(this, result, _, _) } - - override int getParentIndex() { yield_def(this, _, result, _) } - - override AstNode getAFieldOrChild() { yield_child(this, result) } -} diff --git a/ql/src/codeql_ruby/controlflow/BasicBlocks.qll b/ql/src/codeql_ruby/controlflow/BasicBlocks.qll index 5f320a554eaa..0fcbe5411cd5 100644 --- a/ql/src/codeql_ruby/controlflow/BasicBlocks.qll +++ b/ql/src/codeql_ruby/controlflow/BasicBlocks.qll @@ -1,6 +1,6 @@ /** Provides classes representing basic blocks. */ -private import codeql_ruby.ast +private import codeql_ruby.Generated::Generated private import codeql_ruby.controlflow.ControlFlowGraph private import internal.ControlFlowGraphImpl private import SuccessorTypes diff --git a/ql/src/codeql_ruby/controlflow/ControlFlowGraph.qll b/ql/src/codeql_ruby/controlflow/ControlFlowGraph.qll index 75674fb10e5d..660777f5eb7b 100644 --- a/ql/src/codeql_ruby/controlflow/ControlFlowGraph.qll +++ b/ql/src/codeql_ruby/controlflow/ControlFlowGraph.qll @@ -1,6 +1,6 @@ /** Provides classes representing the control flow graph. */ -private import codeql_ruby.ast +private import codeql_ruby.Generated::Generated private import codeql_ruby.controlflow.BasicBlocks private import SuccessorTypes private import internal.ControlFlowGraphImpl diff --git a/ql/src/codeql_ruby/controlflow/internal/AstNodes.qll b/ql/src/codeql_ruby/controlflow/internal/AstNodes.qll index 2562fc88e29b..d941e4b9acdc 100644 --- a/ql/src/codeql_ruby/controlflow/internal/AstNodes.qll +++ b/ql/src/codeql_ruby/controlflow/internal/AstNodes.qll @@ -3,7 +3,7 @@ * will likely be part of the hand-written user-facing AST layer. */ -private import codeql_ruby.ast +private import codeql_ruby.Generated::Generated class LogicalNotAstNode extends Unary { AstNode operand; diff --git a/ql/src/codeql_ruby/controlflow/internal/Completion.qll b/ql/src/codeql_ruby/controlflow/internal/Completion.qll index 4ca358c04978..f0a82b0077e4 100644 --- a/ql/src/codeql_ruby/controlflow/internal/Completion.qll +++ b/ql/src/codeql_ruby/controlflow/internal/Completion.qll @@ -4,7 +4,7 @@ * A completion represents how a statement or expression terminates. */ -private import codeql_ruby.ast +private import codeql_ruby.Generated::Generated private import codeql_ruby.controlflow.ControlFlowGraph private import AstNodes private import NonReturning diff --git a/ql/src/codeql_ruby/controlflow/internal/Consistency.qll b/ql/src/codeql_ruby/controlflow/internal/Consistency.qll index 1488d32a6a58..8e48975d412b 100644 --- a/ql/src/codeql_ruby/controlflow/internal/Consistency.qll +++ b/ql/src/codeql_ruby/controlflow/internal/Consistency.qll @@ -1,4 +1,4 @@ -private import codeql_ruby.ast +private import codeql_ruby.Generated::Generated private import codeql_ruby.controlflow.ControlFlowGraph private import Completion private import Splitting diff --git a/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll b/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll index 1fd3ac8ec728..dbca2e553a09 100644 --- a/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll +++ b/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll @@ -31,7 +31,7 @@ * caught up by its surrounding loop and turned into a `NormalCompletion`. */ -private import codeql_ruby.ast +private import codeql_ruby.Generated::Generated private import AstNodes private import codeql_ruby.controlflow.ControlFlowGraph private import Completion diff --git a/ql/src/codeql_ruby/controlflow/internal/NonReturning.qll b/ql/src/codeql_ruby/controlflow/internal/NonReturning.qll index 119a1e85ac51..f19c16e8975c 100644 --- a/ql/src/codeql_ruby/controlflow/internal/NonReturning.qll +++ b/ql/src/codeql_ruby/controlflow/internal/NonReturning.qll @@ -1,6 +1,6 @@ /** Provides a simple analysis for identifying calls that will not return. */ -private import codeql_ruby.ast +private import codeql_ruby.Generated::Generated private import Completion /** A call that definitely does not return (conservative analysis). */ diff --git a/ql/src/codeql_ruby/controlflow/internal/Splitting.qll b/ql/src/codeql_ruby/controlflow/internal/Splitting.qll index 4edb360ececd..baa4e1753e79 100644 --- a/ql/src/codeql_ruby/controlflow/internal/Splitting.qll +++ b/ql/src/codeql_ruby/controlflow/internal/Splitting.qll @@ -2,7 +2,7 @@ * Provides classes and predicates relevant for splitting the control flow graph. */ -private import codeql_ruby.ast +private import codeql_ruby.Generated::Generated private import AstNodes private import Completion private import ControlFlowGraphImpl diff --git a/ql/src/codeql_ruby/printAst.qll b/ql/src/codeql_ruby/printAst.qll index 287e8d906374..7b8c70b1eddc 100644 --- a/ql/src/codeql_ruby/printAst.qll +++ b/ql/src/codeql_ruby/printAst.qll @@ -6,7 +6,7 @@ * to hold for only the AST nodes you wish to view. */ -import codeql_ruby.ast +import codeql_ruby.Generated /** * The query can extend this class to control which nodes are printed. @@ -17,13 +17,13 @@ class PrintAstConfiguration extends string { /** * Holds if the given node should be printed. */ - predicate shouldPrintNode(AstNode n) { any() } + predicate shouldPrintNode(Generated::AstNode n) { any() } } /** * A node in the output tree. */ -class PrintAstNode extends AstNode { +class PrintAstNode extends Generated::AstNode { string getProperty(string key) { key = "semmle.label" and result = "[" + this.describeQlClass() + "] " + this.toString() @@ -36,15 +36,15 @@ class PrintAstNode extends AstNode { */ predicate shouldPrint() { ( - not this instanceof Token + not this instanceof Generated::Token or - exists(AstNode parent | parent.getAFieldOrChild() = this) + exists(Generated::AstNode parent | parent.getAFieldOrChild() = this) ) and shouldPrintNode(this) } } -private predicate shouldPrintNode(AstNode n) { +private predicate shouldPrintNode(Generated::AstNode n) { exists(PrintAstConfiguration config | config.shouldPrintNode(n)) } diff --git a/ql/src/printAst.ql b/ql/src/printAst.ql index e02a35d2163c..92898a25228f 100644 --- a/ql/src/printAst.ql +++ b/ql/src/printAst.ql @@ -8,6 +8,7 @@ */ import codeql_ruby.printAst +import codeql.files.FileSystem /** * The source file to generate an AST from. @@ -36,7 +37,7 @@ File getFileBySourceArchiveName(string name) { * Overrides the configuration to print only nodes in the selected source file. */ class Cfg extends PrintAstConfiguration { - override predicate shouldPrintNode(AstNode n) { + override predicate shouldPrintNode(Generated::AstNode n) { n.getLocation().getFile() = getFileBySourceArchiveName(selectedSourceFile()) } } diff --git a/ql/src/ruby.dbscheme b/ql/src/ruby.dbscheme index dcd9a75400e1..25830bc58ec0 100644 --- a/ql/src/ruby.dbscheme +++ b/ql/src/ruby.dbscheme @@ -201,7 +201,12 @@ binary_def( int loc: @location ref ); -@block_child_type = @block_parameters | @token_empty_statement | @underscore_statement +block_parameters( + unique int block: @block ref, + unique int block_parameters: @block_parameters ref +); + +@block_child_type = @token_empty_statement | @underscore_statement #keyset[block, index] block_child( @@ -399,7 +404,12 @@ do_def( int loc: @location ref ); -@do_block_child_type = @block_parameters | @else | @ensure | @rescue | @token_empty_statement | @underscore_statement +do_block_parameters( + unique int do_block: @do_block ref, + unique int block_parameters: @block_parameters ref +); + +@do_block_child_type = @else | @ensure | @rescue | @token_empty_statement | @underscore_statement #keyset[do_block, index] do_block_child( @@ -1063,7 +1073,7 @@ setter_def( unique int id: @setter, int parent: @ast_node_parent ref, int parent_index: int ref, - int child: @token_identifier ref, + int name: @token_identifier ref, int loc: @location ref ); diff --git a/ql/src/ruby.qll b/ql/src/ruby.qll new file mode 100644 index 000000000000..61099c3f2e9c --- /dev/null +++ b/ql/src/ruby.qll @@ -0,0 +1 @@ +import codeql_ruby.AST diff --git a/ql/test/library-tests/ast/params/params.expected b/ql/test/library-tests/ast/params/params.expected new file mode 100644 index 000000000000..c3fde5ca2d09 --- /dev/null +++ b/ql/test/library-tests/ast/params/params.expected @@ -0,0 +1,139 @@ +idParams +| params.rb:4:30:4:32 | foo | foo | +| params.rb:4:35:4:37 | bar | bar | +| params.rb:4:40:4:42 | baz | baz | +| params.rb:9:15:9:17 | key | key | +| params.rb:9:20:9:24 | value | value | +| params.rb:14:11:14:13 | foo | foo | +| params.rb:14:16:14:18 | bar | bar | +| params.rb:17:32:17:32 | a | a | +| params.rb:17:35:17:35 | b | b | +| params.rb:17:38:17:38 | c | c | +| params.rb:22:16:22:16 | a | a | +| params.rb:22:19:22:19 | b | b | +| params.rb:25:24:25:28 | first | first | +| params.rb:25:31:25:36 | second | second | +| params.rb:25:41:25:45 | third | third | +| params.rb:25:48:25:53 | fourth | fourth | +| params.rb:30:23:30:28 | wibble | wibble | +| params.rb:34:16:34:18 | val | val | +| params.rb:38:26:38:26 | x | x | +| params.rb:41:32:41:32 | x | x | +| params.rb:53:34:53:34 | x | x | +| params.rb:58:33:58:36 | val1 | val1 | +| params.rb:65:29:65:32 | name | name | +| params.rb:70:35:70:35 | a | a | +blockParams +| params.rb:46:28:46:33 | &block | block | +| params.rb:62:29:62:34 | &block | block | +patternParams +| params.rb:17:31:17:39 | (..., ...) | params.rb:17:32:17:32 | a | 0 | +| params.rb:17:31:17:39 | (..., ...) | params.rb:17:35:17:35 | b | 1 | +| params.rb:17:31:17:39 | (..., ...) | params.rb:17:38:17:38 | c | 2 | +| params.rb:22:15:22:20 | (..., ...) | params.rb:22:16:22:16 | a | 0 | +| params.rb:22:15:22:20 | (..., ...) | params.rb:22:19:22:19 | b | 1 | +| params.rb:25:23:25:37 | (..., ...) | params.rb:25:24:25:28 | first | 0 | +| params.rb:25:23:25:37 | (..., ...) | params.rb:25:31:25:36 | second | 1 | +| params.rb:25:40:25:54 | (..., ...) | params.rb:25:41:25:45 | third | 0 | +| params.rb:25:40:25:54 | (..., ...) | params.rb:25:48:25:53 | fourth | 1 | +splatParams +| params.rb:30:31:30:36 | splat | splat | +| params.rb:34:21:34:26 | splat | splat | +| params.rb:38:29:38:33 | blah | blah | +hashSplatParams +| params.rb:30:39:30:52 | **double_splat | double_splat | +| params.rb:34:29:34:42 | **double_splat | double_splat | +| params.rb:38:36:38:43 | **wibble | wibble | +keywordParams +| params.rb:41:35:41:38 | foo | foo | (none) | +| params.rb:41:41:41:46 | bar | bar | AstNode | +| params.rb:49:28:49:30 | xx | xx | (none) | +| params.rb:49:33:49:39 | yy | yy | AstNode | +| params.rb:53:37:53:38 | y | y | (none) | +| params.rb:53:41:53:44 | z | z | AstNode | +optionalParams +| params.rb:58:39:58:46 | val2 | val2 | params.rb:58:46:58:46 | AstNode | +| params.rb:58:49:58:58 | val3 | val3 | params.rb:58:56:58:58 | AstNode | +| params.rb:65:35:65:42 | age | age | params.rb:65:41:65:42 | AstNode | +| params.rb:70:38:70:45 | b | b | params.rb:70:42:70:45 | AstNode | +| params.rb:70:48:70:53 | c | c | params.rb:70:52:70:53 | AstNode | +paramsInMethods +| params.rb:4:1:5:3 | identifier_method_params | 0 | params.rb:4:30:4:32 | foo | IdentifierParameter | +| params.rb:4:1:5:3 | identifier_method_params | 1 | params.rb:4:35:4:37 | bar | IdentifierParameter | +| params.rb:4:1:5:3 | identifier_method_params | 2 | params.rb:4:40:4:42 | baz | IdentifierParameter | +| params.rb:17:1:18:3 | destructured_method_param | 0 | params.rb:17:31:17:39 | (..., ...) | PatternParameter | +| params.rb:30:1:31:3 | method_with_splat | 0 | params.rb:30:23:30:28 | wibble | IdentifierParameter | +| params.rb:30:1:31:3 | method_with_splat | 1 | params.rb:30:31:30:36 | splat | SplatParameter | +| params.rb:30:1:31:3 | method_with_splat | 2 | params.rb:30:39:30:52 | **double_splat | HashSplatParameter | +| params.rb:41:1:43:3 | method_with_keyword_params | 0 | params.rb:41:32:41:32 | x | IdentifierParameter | +| params.rb:41:1:43:3 | method_with_keyword_params | 1 | params.rb:41:35:41:38 | foo | KeywordParameter | +| params.rb:41:1:43:3 | method_with_keyword_params | 2 | params.rb:41:41:41:46 | bar | KeywordParameter | +| params.rb:46:1:48:3 | use_block_with_keyword | 0 | params.rb:46:28:46:33 | &block | BlockParameter | +| params.rb:58:1:59:3 | method_with_optional_params | 0 | params.rb:58:33:58:36 | val1 | IdentifierParameter | +| params.rb:58:1:59:3 | method_with_optional_params | 1 | params.rb:58:39:58:46 | val2 | OptionalParameter | +| params.rb:58:1:59:3 | method_with_optional_params | 2 | params.rb:58:49:58:58 | val3 | OptionalParameter | +| params.rb:62:1:64:3 | use_block_with_optional | 0 | params.rb:62:29:62:34 | &block | BlockParameter | +paramsInBlocks +| params.rb:9:11:11:3 | \| ... \| | 0 | params.rb:9:15:9:17 | key | IdentifierParameter | +| params.rb:9:11:11:3 | \| ... \| | 1 | params.rb:9:20:9:24 | value | IdentifierParameter | +| params.rb:22:12:22:32 | { ... } | 0 | params.rb:22:15:22:20 | (..., ...) | PatternParameter | +| params.rb:34:12:35:3 | \| ... \| | 0 | params.rb:34:16:34:18 | val | IdentifierParameter | +| params.rb:34:12:35:3 | \| ... \| | 1 | params.rb:34:21:34:26 | splat | SplatParameter | +| params.rb:34:12:35:3 | \| ... \| | 2 | params.rb:34:29:34:42 | **double_splat | HashSplatParameter | +| params.rb:49:24:51:3 | \| ... \| | 0 | params.rb:49:28:49:30 | xx | KeywordParameter | +| params.rb:49:24:51:3 | \| ... \| | 1 | params.rb:49:33:49:39 | yy | KeywordParameter | +| params.rb:65:25:67:3 | \| ... \| | 0 | params.rb:65:29:65:32 | name | IdentifierParameter | +| params.rb:65:25:67:3 | \| ... \| | 1 | params.rb:65:35:65:42 | age | OptionalParameter | +paramsInLambdas +| params.rb:14:7:14:33 | -> { ... } | 0 | params.rb:14:11:14:13 | foo | IdentifierParameter | +| params.rb:14:7:14:33 | -> { ... } | 1 | params.rb:14:16:14:18 | bar | IdentifierParameter | +| params.rb:25:19:27:1 | -> { ... } | 0 | params.rb:25:23:25:37 | (..., ...) | PatternParameter | +| params.rb:25:19:27:1 | -> { ... } | 1 | params.rb:25:40:25:54 | (..., ...) | PatternParameter | +| params.rb:38:22:38:47 | -> { ... } | 0 | params.rb:38:26:38:26 | x | IdentifierParameter | +| params.rb:38:22:38:47 | -> { ... } | 1 | params.rb:38:29:38:33 | blah | SplatParameter | +| params.rb:38:22:38:47 | -> { ... } | 2 | params.rb:38:36:38:43 | **wibble | HashSplatParameter | +| params.rb:53:30:55:1 | -> { ... } | 0 | params.rb:53:34:53:34 | x | IdentifierParameter | +| params.rb:53:30:55:1 | -> { ... } | 1 | params.rb:53:37:53:38 | y | KeywordParameter | +| params.rb:53:30:55:1 | -> { ... } | 2 | params.rb:53:41:53:44 | z | KeywordParameter | +| params.rb:70:31:70:64 | -> { ... } | 0 | params.rb:70:35:70:35 | a | IdentifierParameter | +| params.rb:70:31:70:64 | -> { ... } | 1 | params.rb:70:38:70:45 | b | OptionalParameter | +| params.rb:70:31:70:64 | -> { ... } | 2 | params.rb:70:48:70:53 | c | OptionalParameter | +#select +| params.rb:4:30:4:32 | foo | 0 | IdentifierParameter | +| params.rb:4:35:4:37 | bar | 1 | IdentifierParameter | +| params.rb:4:40:4:42 | baz | 2 | IdentifierParameter | +| params.rb:9:15:9:17 | key | 0 | IdentifierParameter | +| params.rb:9:20:9:24 | value | 1 | IdentifierParameter | +| params.rb:14:11:14:13 | foo | 0 | IdentifierParameter | +| params.rb:14:16:14:18 | bar | 1 | IdentifierParameter | +| params.rb:17:31:17:39 | (..., ...) | 0 | PatternParameter | +| params.rb:22:15:22:20 | (..., ...) | 0 | PatternParameter | +| params.rb:25:23:25:37 | (..., ...) | 0 | PatternParameter | +| params.rb:25:40:25:54 | (..., ...) | 1 | PatternParameter | +| params.rb:30:23:30:28 | wibble | 0 | IdentifierParameter | +| params.rb:30:31:30:36 | splat | 1 | SplatParameter | +| params.rb:30:39:30:52 | **double_splat | 2 | HashSplatParameter | +| params.rb:34:16:34:18 | val | 0 | IdentifierParameter | +| params.rb:34:21:34:26 | splat | 1 | SplatParameter | +| params.rb:34:29:34:42 | **double_splat | 2 | HashSplatParameter | +| params.rb:38:26:38:26 | x | 0 | IdentifierParameter | +| params.rb:38:29:38:33 | blah | 1 | SplatParameter | +| params.rb:38:36:38:43 | **wibble | 2 | HashSplatParameter | +| params.rb:41:32:41:32 | x | 0 | IdentifierParameter | +| params.rb:41:35:41:38 | foo | 1 | KeywordParameter | +| params.rb:41:41:41:46 | bar | 2 | KeywordParameter | +| params.rb:46:28:46:33 | &block | 0 | BlockParameter | +| params.rb:49:28:49:30 | xx | 0 | KeywordParameter | +| params.rb:49:33:49:39 | yy | 1 | KeywordParameter | +| params.rb:53:34:53:34 | x | 0 | IdentifierParameter | +| params.rb:53:37:53:38 | y | 1 | KeywordParameter | +| params.rb:53:41:53:44 | z | 2 | KeywordParameter | +| params.rb:58:33:58:36 | val1 | 0 | IdentifierParameter | +| params.rb:58:39:58:46 | val2 | 1 | OptionalParameter | +| params.rb:58:49:58:58 | val3 | 2 | OptionalParameter | +| params.rb:62:29:62:34 | &block | 0 | BlockParameter | +| params.rb:65:29:65:32 | name | 0 | IdentifierParameter | +| params.rb:65:35:65:42 | age | 1 | OptionalParameter | +| params.rb:70:35:70:35 | a | 0 | IdentifierParameter | +| params.rb:70:38:70:45 | b | 1 | OptionalParameter | +| params.rb:70:48:70:53 | c | 2 | OptionalParameter | diff --git a/ql/test/library-tests/ast/params/params.ql b/ql/test/library-tests/ast/params/params.ql new file mode 100644 index 000000000000..c17f921d3f2d --- /dev/null +++ b/ql/test/library-tests/ast/params/params.ql @@ -0,0 +1,46 @@ +import ruby + +//////////////////////////////////////////////////////////////////////////////// +// Query predicates for various types of parameter +query predicate idParams(IdentifierParameter ip, string name) { name = ip.getName() } + +query predicate blockParams(BlockParameter bp, string name) { name = bp.getName() } + +query predicate patternParams(PatternParameter pp, Parameter child, int childIndex) { + pp.getElement(childIndex) = child +} + +query predicate splatParams(SplatParameter sp, string name) { name = sp.getName() } + +query predicate hashSplatParams(HashSplatParameter hsp, string name) { name = hsp.getName() } + +query predicate keywordParams(KeywordParameter kp, string name, string defaultValueStr) { + name = kp.getName() and + if exists(kp.getDefaultValue()) + then defaultValueStr = kp.getDefaultValue().toString() + else defaultValueStr = "(none)" +} + +query predicate optionalParams(OptionalParameter op, string name, AstNode defaultValue) { + name = op.getName() and + defaultValue = op.getDefaultValue() +} + +//////////////////////////////////////////////////////////////////////////////// +// Query predicates for various contexts of parameters +query predicate paramsInMethods(Method m, int i, Parameter p, string pClass) { + p = m.getParameter(i) and pClass = p.describeQlClass() +} + +query predicate paramsInBlocks(Block b, int i, Parameter p, string pClass) { + p = b.getParameter(i) and pClass = p.describeQlClass() +} + +query predicate paramsInLambdas(Lambda l, int i, Parameter p, string pClass) { + p = l.getParameter(i) and pClass = p.describeQlClass() +} + +//////////////////////////////////////////////////////////////////////////////// +// General query selecting all parameters +from Parameter p +select p, p.getPosition(), p.describeQlClass() diff --git a/ql/test/library-tests/ast/params/params.rb b/ql/test/library-tests/ast/params/params.rb new file mode 100644 index 000000000000..5946b265c84c --- /dev/null +++ b/ql/test/library-tests/ast/params/params.rb @@ -0,0 +1,70 @@ +# Tests for the different kinds and contexts of parameters. + +# Method containing identifier parameters +def identifier_method_params(foo, bar, baz) +end + +# Block containing identifier parameters +hash = {} +hash.each do |key, value| + puts "#{key} -> #{value}" +end + +# Lambda containing identifier parameters +sum = -> (foo, bar) { foo + bar } + +# Method containing destructured parameters +def destructured_method_param((a, b, c)) +end + +# Block containing destructured parameters +array = [] +array.each { |(a, b)| puts a+b } + +# Lambda containing destructured parameters +sum_four_values = -> ((first, second), (third, fourth)) { + first + second + third + fourth +} + +# Method containing splat and hash-splat params +def method_with_splat(wibble, *splat, **double_splat) +end + +# Block with splat and hash-splat parameter +array.each do |val, *splat, **double_splat| +end + +# Lambda with splat and hash-splat +lambda_with_splats = -> (x, *blah, **wibble) {} + +# Method containing keyword parameters +def method_with_keyword_params(x, foo:, bar: 7) + x + foo + bar +end + +# Block with keyword parameters +def use_block_with_keyword(&block) + puts(block.call bar: 2, foo: 3) +end +use_block_with_keyword do |xx:, yy: 100| + xx + yy +end + +lambda_with_keyword_params = -> (x, y:, z: 3) { + x + y + z +} + +# Method containing optional parameters +def method_with_optional_params(val1, val2 = 0, val3 = 100) +end + +# Block containing optional parameter +def use_block_with_optional(&block) + block.call 'Zeus' +end +use_block_with_optional do |name, age = 99| + puts "#{name} is #{age} years old" +end + +# Lambda containing optional parameters +lambda_with_optional_params = -> (a, b = 1000, c = 20) { a+b+c } \ No newline at end of file From 399170fd58e085a770fe831e2f9770a6b16258ef Mon Sep 17 00:00:00 2001 From: Nick Rolfe Date: Thu, 26 Nov 2020 15:33:50 +0000 Subject: [PATCH 2/8] Add getParent(Index) to user-facing AstNode --- ql/src/codeql_ruby/AST.qll | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/ql/src/codeql_ruby/AST.qll b/ql/src/codeql_ruby/AST.qll index d9f0bfb47a9f..89ccae6c3ebd 100644 --- a/ql/src/codeql_ruby/AST.qll +++ b/ql/src/codeql_ruby/AST.qll @@ -1,14 +1,17 @@ +import codeql.Locations import codeql_ruby.Method import codeql_ruby.Parameter private import codeql_ruby.Generated -class Location = Generated::Location; - /** * A node in the abstract syntax tree. This class is the base class for all Ruby * program elements. */ class AstNode extends @ast_node { + Generated::AstNode generated; + + AstNode() { generated = this } + /** * Gets the name of a primary CodeQL class to which this node belongs. * @@ -22,7 +25,18 @@ class AstNode extends @ast_node { string toString() { result = "AstNode" } /** Gets the location if this node. */ - Location getLocation() { result = this.(Generated::AstNode).getLocation() } + Location getLocation() { result = generated.getLocation() } + + /** + * Gets the parent of this node in the abstract syntax tree, if it has one. + */ + AstNode getParent() { result = generated.getParent() } + + /** + * Gets the index (position) of this node in the parent node's list of + * children. + */ + int getParentIndex() { result = generated.getParentIndex() } } /** From 38b401f04fcd448598e3dde1dfbbd05face650ad Mon Sep 17 00:00:00 2001 From: Nick Rolfe Date: Thu, 26 Nov 2020 16:04:46 +0000 Subject: [PATCH 3/8] Fix import --- ql/src/codeql_ruby/Variables.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ql/src/codeql_ruby/Variables.qll b/ql/src/codeql_ruby/Variables.qll index ee1d6aa9751f..186837aa1331 100644 --- a/ql/src/codeql_ruby/Variables.qll +++ b/ql/src/codeql_ruby/Variables.qll @@ -1,6 +1,6 @@ /** Provides classes for modeling program variables. */ -private import ast +private import Generated::Generated private import codeql.Locations private AstNode parent(AstNode n) { From 00f3daabfe8a00a0ec528727036624be61bd3917 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 27 Nov 2020 14:39:20 +0100 Subject: [PATCH 4/8] Rename `Variables.qll` to `Variable.qll` --- ql/consistency-queries/VariablesConsistency.ql | 2 +- ql/src/codeql_ruby/{Variables.qll => Variable.qll} | 0 ql/test/library-tests/variables/parameter.ql | 2 +- ql/test/library-tests/variables/varaccess.ql | 2 +- ql/test/library-tests/variables/variable.ql | 2 +- ql/test/library-tests/variables/varscopes.ql | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) rename ql/src/codeql_ruby/{Variables.qll => Variable.qll} (100%) diff --git a/ql/consistency-queries/VariablesConsistency.ql b/ql/consistency-queries/VariablesConsistency.ql index 6ef6598f89b3..c510fcc8c936 100644 --- a/ql/consistency-queries/VariablesConsistency.ql +++ b/ql/consistency-queries/VariablesConsistency.ql @@ -1,4 +1,4 @@ -import codeql_ruby.Variables +import codeql_ruby.Variable query predicate ambiguousVariable(VariableAccess access, Variable variable) { access.getVariable() = variable and diff --git a/ql/src/codeql_ruby/Variables.qll b/ql/src/codeql_ruby/Variable.qll similarity index 100% rename from ql/src/codeql_ruby/Variables.qll rename to ql/src/codeql_ruby/Variable.qll diff --git a/ql/test/library-tests/variables/parameter.ql b/ql/test/library-tests/variables/parameter.ql index 0c7eec562082..dc75c0cf846b 100644 --- a/ql/test/library-tests/variables/parameter.ql +++ b/ql/test/library-tests/variables/parameter.ql @@ -1,4 +1,4 @@ -import codeql_ruby.Variables +import codeql_ruby.Variable query predicate parameter(Parameter p, Variable v) { p.getAnAccess().getVariable() = v } diff --git a/ql/test/library-tests/variables/varaccess.ql b/ql/test/library-tests/variables/varaccess.ql index 6d428bdf4e6e..e3fc8f9b11f8 100644 --- a/ql/test/library-tests/variables/varaccess.ql +++ b/ql/test/library-tests/variables/varaccess.ql @@ -1,4 +1,4 @@ -import codeql_ruby.Variables +import codeql_ruby.Variable query predicate variableAccess(VariableAccess access, Variable variable, VariableScope scope) { variable = access.getVariable() and diff --git a/ql/test/library-tests/variables/variable.ql b/ql/test/library-tests/variables/variable.ql index 13f7a0f0efad..abb7292eeab0 100644 --- a/ql/test/library-tests/variables/variable.ql +++ b/ql/test/library-tests/variables/variable.ql @@ -1,4 +1,4 @@ -import codeql_ruby.Variables +import codeql_ruby.Variable query predicate variable(Variable v) { any() } diff --git a/ql/test/library-tests/variables/varscopes.ql b/ql/test/library-tests/variables/varscopes.ql index fcc13759b3c6..a7f64cfcdcff 100644 --- a/ql/test/library-tests/variables/varscopes.ql +++ b/ql/test/library-tests/variables/varscopes.ql @@ -1,3 +1,3 @@ -import codeql_ruby.Variables +import codeql_ruby.Variable select any(VariableScope x) From 59d45de11894d4df5c102844c2798d3097484d56 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 27 Nov 2020 14:45:15 +0100 Subject: [PATCH 5/8] Move AST files into `ast` folder --- ql/consistency-queries/VariablesConsistency.ql | 2 +- ql/src/codeql_ruby/AST.qll | 4 ++-- ql/src/codeql_ruby/{ => ast}/Method.qll | 0 ql/src/codeql_ruby/{ => ast}/Parameter.qll | 0 ql/src/codeql_ruby/{ => ast}/Variable.qll | 2 +- ql/test/library-tests/variables/parameter.ql | 2 +- ql/test/library-tests/variables/varaccess.ql | 2 +- ql/test/library-tests/variables/variable.ql | 2 +- ql/test/library-tests/variables/varscopes.ql | 2 +- 9 files changed, 8 insertions(+), 8 deletions(-) rename ql/src/codeql_ruby/{ => ast}/Method.qll (100%) rename ql/src/codeql_ruby/{ => ast}/Parameter.qll (100%) rename ql/src/codeql_ruby/{ => ast}/Variable.qll (99%) diff --git a/ql/consistency-queries/VariablesConsistency.ql b/ql/consistency-queries/VariablesConsistency.ql index c510fcc8c936..acbf5c8a05ae 100644 --- a/ql/consistency-queries/VariablesConsistency.ql +++ b/ql/consistency-queries/VariablesConsistency.ql @@ -1,4 +1,4 @@ -import codeql_ruby.Variable +import codeql_ruby.ast.Variable query predicate ambiguousVariable(VariableAccess access, Variable variable) { access.getVariable() = variable and diff --git a/ql/src/codeql_ruby/AST.qll b/ql/src/codeql_ruby/AST.qll index 89ccae6c3ebd..0171cf2bfa28 100644 --- a/ql/src/codeql_ruby/AST.qll +++ b/ql/src/codeql_ruby/AST.qll @@ -1,6 +1,6 @@ import codeql.Locations -import codeql_ruby.Method -import codeql_ruby.Parameter +import codeql_ruby.ast.Method +import codeql_ruby.ast.Parameter private import codeql_ruby.Generated /** diff --git a/ql/src/codeql_ruby/Method.qll b/ql/src/codeql_ruby/ast/Method.qll similarity index 100% rename from ql/src/codeql_ruby/Method.qll rename to ql/src/codeql_ruby/ast/Method.qll diff --git a/ql/src/codeql_ruby/Parameter.qll b/ql/src/codeql_ruby/ast/Parameter.qll similarity index 100% rename from ql/src/codeql_ruby/Parameter.qll rename to ql/src/codeql_ruby/ast/Parameter.qll diff --git a/ql/src/codeql_ruby/Variable.qll b/ql/src/codeql_ruby/ast/Variable.qll similarity index 99% rename from ql/src/codeql_ruby/Variable.qll rename to ql/src/codeql_ruby/ast/Variable.qll index 186837aa1331..50eb92532d82 100644 --- a/ql/src/codeql_ruby/Variable.qll +++ b/ql/src/codeql_ruby/ast/Variable.qll @@ -1,6 +1,6 @@ /** Provides classes for modeling program variables. */ -private import Generated::Generated +private import codeql_ruby.Generated::Generated private import codeql.Locations private AstNode parent(AstNode n) { diff --git a/ql/test/library-tests/variables/parameter.ql b/ql/test/library-tests/variables/parameter.ql index dc75c0cf846b..254abfc2daec 100644 --- a/ql/test/library-tests/variables/parameter.ql +++ b/ql/test/library-tests/variables/parameter.ql @@ -1,4 +1,4 @@ -import codeql_ruby.Variable +import codeql_ruby.ast.Variable query predicate parameter(Parameter p, Variable v) { p.getAnAccess().getVariable() = v } diff --git a/ql/test/library-tests/variables/varaccess.ql b/ql/test/library-tests/variables/varaccess.ql index e3fc8f9b11f8..2c62bc563a30 100644 --- a/ql/test/library-tests/variables/varaccess.ql +++ b/ql/test/library-tests/variables/varaccess.ql @@ -1,4 +1,4 @@ -import codeql_ruby.Variable +import codeql_ruby.ast.Variable query predicate variableAccess(VariableAccess access, Variable variable, VariableScope scope) { variable = access.getVariable() and diff --git a/ql/test/library-tests/variables/variable.ql b/ql/test/library-tests/variables/variable.ql index abb7292eeab0..e63cb8ffeb19 100644 --- a/ql/test/library-tests/variables/variable.ql +++ b/ql/test/library-tests/variables/variable.ql @@ -1,4 +1,4 @@ -import codeql_ruby.Variable +import codeql_ruby.ast.Variable query predicate variable(Variable v) { any() } diff --git a/ql/test/library-tests/variables/varscopes.ql b/ql/test/library-tests/variables/varscopes.ql index a7f64cfcdcff..e0272ce17af0 100644 --- a/ql/test/library-tests/variables/varscopes.ql +++ b/ql/test/library-tests/variables/varscopes.ql @@ -1,3 +1,3 @@ -import codeql_ruby.Variable +import codeql_ruby.ast.Variable select any(VariableScope x) From 58baa33a3f82f9174670f123e0593be7466d0909 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 27 Nov 2020 15:12:29 +0100 Subject: [PATCH 6/8] Various changes to user-facing library - Remove `abstract` classes from public API. - Align `Variable.qll` with rest of library. - Introduce `Callable` class. - Make `Pattern` class cover everything that can be on the LHS of an assignment and in a pattern (except special parameters such as `**param`). --- ql/src/codeql_ruby/AST.qll | 27 +- ql/src/codeql_ruby/ast/Method.qll | 108 ++++---- ql/src/codeql_ruby/ast/Parameter.qll | 171 ++++++------ ql/src/codeql_ruby/ast/Pattern.qll | 40 +++ ql/src/codeql_ruby/ast/Variable.qll | 249 +++++------------- ql/src/codeql_ruby/ast/internal/Method.qll | 42 +++ ql/src/codeql_ruby/ast/internal/Pattern.qll | 65 +++++ ql/src/codeql_ruby/ast/internal/Variable.qll | 130 +++++++++ .../library-tests/ast/params/params.expected | 104 ++++---- ql/test/library-tests/ast/params/params.ql | 6 +- .../variables/parameter.expected | 36 +-- ql/test/library-tests/variables/parameter.ql | 4 +- ql/test/library-tests/variables/scopes.rb | 5 + .../variables/varaccess.expected | 141 +--------- ql/test/library-tests/variables/varaccess.ql | 13 - .../library-tests/variables/variable.expected | 46 +--- ql/test/library-tests/variables/variable.ql | 4 - .../variables/varscopes.expected | 4 +- 18 files changed, 570 insertions(+), 625 deletions(-) create mode 100644 ql/src/codeql_ruby/ast/Pattern.qll create mode 100644 ql/src/codeql_ruby/ast/internal/Method.qll create mode 100644 ql/src/codeql_ruby/ast/internal/Pattern.qll create mode 100644 ql/src/codeql_ruby/ast/internal/Variable.qll diff --git a/ql/src/codeql_ruby/AST.qll b/ql/src/codeql_ruby/AST.qll index 0171cf2bfa28..1e47ac4b82e8 100644 --- a/ql/src/codeql_ruby/AST.qll +++ b/ql/src/codeql_ruby/AST.qll @@ -1,6 +1,8 @@ import codeql.Locations import codeql_ruby.ast.Method import codeql_ruby.ast.Parameter +import codeql_ruby.ast.Pattern +import codeql_ruby.ast.Variable private import codeql_ruby.Generated /** @@ -26,29 +28,4 @@ class AstNode extends @ast_node { /** Gets the location if this node. */ Location getLocation() { result = generated.getLocation() } - - /** - * Gets the parent of this node in the abstract syntax tree, if it has one. - */ - AstNode getParent() { result = generated.getParent() } - - /** - * Gets the index (position) of this node in the parent node's list of - * children. - */ - int getParentIndex() { result = generated.getParentIndex() } -} - -/** - * Models program elements for destructured patterns. - */ -abstract class Pattern extends AstNode { - /** Gets the number of elements in this pattern. */ - abstract int getNumberOfElements(); - - /** Gets the nth element in this pattern. */ - abstract AstNode getElement(int n); - - /** Gets an element in this pattern. */ - AstNode getAnElement() { result = this.getElement(_) } } diff --git a/ql/src/codeql_ruby/ast/Method.qll b/ql/src/codeql_ruby/ast/Method.qll index 6aa5e61c027f..80849be07d7a 100644 --- a/ql/src/codeql_ruby/ast/Method.qll +++ b/ql/src/codeql_ruby/ast/Method.qll @@ -1,17 +1,30 @@ import codeql_ruby.AST private import codeql_ruby.Generated +private import internal.Method -/** A Ruby method. */ -class Method extends @method, AstNode { - Generated::Method generated; +/** A callable. */ +class Callable extends AstNode { + Callable() { this instanceof CallableRange } - Method() { generated = this } + /** Gets the number of parameters of this callable. */ + final int getNumberOfParameters() { result = count(this.getAParameter()) } + + /** Gets a parameter of this callable. */ + final Parameter getAParameter() { result = this.getParameter(_) } + + /** Gets the nth parameter of this callable. */ + final Parameter getParameter(int n) { result = this.(CallableRange).getParameter(n) } +} + +/** A method. */ +class Method extends Callable, @method { + final override Generated::Method generated; override string describeQlClass() { result = "Method" } override string toString() { result = this.getName() } - /** Gets the name of the method. */ + /** Gets the name of this method. */ string getName() { result = generated.getName().(Generated::Token).getValue() or // TODO: use hand-written Symbol class @@ -21,7 +34,7 @@ class Method extends @method, AstNode { /** * Holds if this is a setter method, as in the following example: - * ``` + * ```rb * class Person * def name=(n) * @name = n @@ -30,90 +43,63 @@ class Method extends @method, AstNode { * ``` */ predicate isSetter() { generated.getName() instanceof Generated::Setter } +} + +/** A singleton method. */ +class SingletonMethod extends Callable, @singleton_method { + final override Generated::SingletonMethod generated; - /** Gets the number of parameters of this method. */ - int getNumberOfParameters() { result = count(this.getAParameter()) } + override string describeQlClass() { result = "SingletonMethod" } - /** Gets a parameter of this method. */ - Parameter getAParameter() { result = this.getParameter(_) } + override string toString() { result = this.getName() } - /** Gets the nth parameter of this method. */ - Parameter getParameter(int n) { result = generated.getParameters().getChild(n) } + /** Gets the name of this method. */ + string getName() { + result = generated.getName().(Generated::Token).getValue() or + // TODO: use hand-written Symbol class + result = generated.getName().(Generated::Symbol).toString() or + result = generated.getName().(Generated::Setter).getName().getValue() + "=" + } } /** - * A Ruby lambda (anonymous method). For example: - * ``` + * A lambda (anonymous method). For example: + * ```rb * -> (x) { x + 1 } * ``` */ -class Lambda extends @lambda, AstNode { - Generated::Lambda generated; - - Lambda() { generated = this } +class Lambda extends Callable, @lambda { + final override Generated::Lambda generated; override string describeQlClass() { result = "Lambda" } override string toString() { result = "-> { ... }" } - - /** Gets the number of parameters of this lambda. */ - int getNumberOfParameters() { result = count(this.getAParameter()) } - - /** Gets a parameter of this lambda. */ - Parameter getAParameter() { result = this.getParameter(_) } - - /** Gets the nth parameter of this lambda. */ - Parameter getParameter(int n) { result = generated.getParameters().getChild(n) } } -/** A Ruby block. */ -abstract class Block extends AstNode { - /** Gets the number of parameters of this block. */ - abstract int getNumberOfParameters(); - - /** Gets the nth parameter of this block. */ - abstract Parameter getParameter(int n); - - /** Gets a parameter of this block. */ - Parameter getAParameter() { result = this.getParameter(_) } - // TODO: body/statements +/** A block. */ +class Block extends AstNode, Callable { + Block() { this instanceof BlockRange } } -/** A Ruby block enclosed within `do` and `end`. */ -class DoBlock extends @do_block, Block { - Generated::DoBlock generated; - - DoBlock() { generated = this } +/** A block enclosed within `do` and `end`. */ +class DoBlock extends Block, @do_block { + final override Generated::DoBlock generated; override string describeQlClass() { result = "DoBlock" } override string toString() { result = "| ... |" } - - /** Gets the number of parameters of this block. */ - override int getNumberOfParameters() { result = count(this.getAParameter()) } - - /** Gets the nth parameter of this block. */ - override Parameter getParameter(int n) { result = generated.getParameters().getChild(n) } } /** - * A Ruby block defined using curly braces, e.g. in the following code: - * ``` + * A block defined using curly braces, e.g. in the following code: + * ```rb * names.each { |name| puts name } * ``` */ -class BraceBlock extends @block, Block { - Generated::Block generated; - - BraceBlock() { generated = this } +class BraceBlock extends Block, @block { + final override Generated::Block generated; override string describeQlClass() { result = "BraceBlock" } override string toString() { result = "{ ... }" } - - /** Gets the number of parameters of this block. */ - override int getNumberOfParameters() { result = count(this.getAParameter()) } - - /** Gets the nth parameter of this block. */ - override Parameter getParameter(int n) { result = generated.getParameters().getChild(n) } } diff --git a/ql/src/codeql_ruby/ast/Parameter.qll b/ql/src/codeql_ruby/ast/Parameter.qll index 0f6cb8fa419b..f870a62d7f39 100644 --- a/ql/src/codeql_ruby/ast/Parameter.qll +++ b/ql/src/codeql_ruby/ast/Parameter.qll @@ -1,105 +1,123 @@ import codeql_ruby.AST private import codeql_ruby.Generated - -/** - * A parameter to a block, lambda, or method. - */ -abstract class Parameter extends AstNode { - /** - * Gets the position of this parameter in the parent block, lambda, or - * method's parameter list. - */ - int getPosition() { - exists(Method m | m.getParameter(result) = this) or - exists(Block b | b.getParameter(result) = this) or - exists(Lambda l | l.getParameter(result) = this) +private import Variable +private import Pattern +private import internal.Variable + +/** A parameter. */ +class Parameter extends AstNode { + private int pos; + + Parameter() { + this = any(Generated::BlockParameters bp).getChild(pos) + or + this = any(Generated::MethodParameters mp).getChild(pos) + or + this = any(Generated::LambdaParameters lp).getChild(pos) } + + /** Gets the callable that this parameter belongs to. */ + Callable getCallable() { result.getAParameter() = this } + + /** Gets the zero-based position of this parameter. */ + int getPosition() { result = pos } } /** - * A parameter that is a block. For example, `&bar` in the following code: - * ``` - * def foo(&bar) - * bar.call if block_given? - * end - * ``` + * A parameter defined using a pattern. + * + * This includes both simple parameters and tuple parameters. */ -class BlockParameter extends @block_parameter, Parameter { - Generated::BlockParameter generated; +class PatternParameter extends Parameter, Pattern { + override string toString() { result = Pattern.super.toString() } - BlockParameter() { generated = this } + override Location getLocation() { result = Pattern.super.getLocation() } +} - override string describeQlClass() { result = "BlockParameter" } +/** A parameter defined using a tuple pattern. */ +class TuplePatternParameter extends PatternParameter, TuplePattern { + override string toString() { result = TuplePattern.super.toString() } - override string toString() { result = "&" + this.getName() } + override string describeQlClass() { result = "TuplePatternParameter" } +} + +/** A named parameter. */ +class NamedParameter extends Parameter { + NamedParameter() { not this instanceof TuplePattern } + + /** Gets the name of this parameter. */ + string getName() { none() } + + /** Gets the variable introduced by this parameter. */ + Variable getVariable() { none() } + + /** Gets an access to this parameter. */ + final VariableAccess getAnAccess() { result = this.getVariable().getAnAccess() } +} + +/** A simple (normal) parameter. */ +class SimpleParameter extends NamedParameter, PatternParameter, VariablePattern { + override string getName() { result = VariablePattern.super.getName() } + + final override Variable getVariable() { result = TLocalVariable(_, _, this) } + + override string describeQlClass() { result = "SimpleParameter" } - /** Gets the name of the parameter. */ - string getName() { result = generated.getName().getValue() } + override string toString() { result = this.getName() } } /** - * A parameter that is destructured. For example, the parameter `(a, b)` in the - * following code: - * ``` - * pairs.each do |(a, b)| - * puts a + b + * A parameter that is a block. For example, `&bar` in the following code: + * ```rb + * def foo(&bar) + * bar.call if block_given? * end * ``` */ -class PatternParameter extends @destructured_parameter, Parameter, Pattern { - Generated::DestructuredParameter generated; - - PatternParameter() { generated = this } +class BlockParameter extends @block_parameter, NamedParameter { + override Generated::BlockParameter generated; - override string describeQlClass() { result = "PatternParameter" } + final override Variable getVariable() { result = TLocalVariable(_, _, generated.getName()) } - override string toString() { result = "(..., ...)" } + override string describeQlClass() { result = "BlockParameter" } - /** - * Gets the number of parameters of this destructuring. - */ - override int getNumberOfElements() { result = count(this.getElement(_)) } + override string toString() { result = "&" + this.getName() } - /** - * Gets the nth parameter of this pattern. - */ - override AstNode getElement(int n) { result = generated.getChild(n) } + override string getName() { result = generated.getName().getValue() } } /** * A hash-splat (or double-splat) parameter. For example, `**options` in the * following code: - * ``` + * ```rb * def foo(bar, **options) * ... * end * ``` */ -class HashSplatParameter extends @hash_splat_parameter, Parameter { - Generated::HashSplatParameter generated; +class HashSplatParameter extends @hash_splat_parameter, NamedParameter { + override Generated::HashSplatParameter generated; - HashSplatParameter() { generated = this } + final override Variable getVariable() { result = TLocalVariable(_, _, generated.getName()) } override string describeQlClass() { result = "HashSplatParameter" } override string toString() { result = "**" + this.getName() } - /** Gets the name of the parameter. */ - string getName() { result = generated.getName().getValue() } + override string getName() { result = generated.getName().getValue() } } /** * TODO */ -class KeywordParameter extends @keyword_parameter, Parameter { - Generated::KeywordParameter generated; +class KeywordParameter extends @keyword_parameter, NamedParameter { + override Generated::KeywordParameter generated; - KeywordParameter() { generated = this } + final override Variable getVariable() { result = TLocalVariable(_, _, generated.getName()) } override string describeQlClass() { result = "KeywordParameter" } - /** Gets the name of the parameter. */ - string getName() { result = generated.getName().getValue() } + override string getName() { result = generated.getName().getValue() } /** * Gets the default value, i.e. the value assigned to the parameter when one @@ -115,23 +133,22 @@ class KeywordParameter extends @keyword_parameter, Parameter { /** * An optional parameter. For example, the parameter `name` in the following * code: - * ``` + * ```rb * def say_hello(name = 'Anon') * puts "hello #{name}" * end * ``` */ -class OptionalParameter extends @optional_parameter, Parameter { - Generated::OptionalParameter generated; +class OptionalParameter extends @optional_parameter, NamedParameter { + override Generated::OptionalParameter generated; - OptionalParameter() { generated = this } + final override Variable getVariable() { result = TLocalVariable(_, _, generated.getName()) } override string describeQlClass() { result = "OptionalParameter" } override string toString() { result = this.getName() } - /** Gets the name of the parameter. */ - string getName() { result = generated.getName().getValue() } + override string getName() { result = generated.getName().getValue() } /** * Gets the default value, i.e. the value assigned to the parameter when one @@ -143,40 +160,20 @@ class OptionalParameter extends @optional_parameter, Parameter { /** * A splat parameter. For example, `*values` in the following code: - * ``` + * ```rb * def foo(bar, *values) * ... * end * ``` */ -class SplatParameter extends @splat_parameter, Parameter { - Generated::SplatParameter generated; +class SplatParameter extends @splat_parameter, NamedParameter { + override Generated::SplatParameter generated; - SplatParameter() { generated = this } + final override Variable getVariable() { result = TLocalVariable(_, _, generated.getName()) } override string describeQlClass() { result = "SplatParameter" } override string toString() { result = this.getName() } - /** Gets the name of the parameter. */ - string getName() { result = generated.getName().getValue() } -} - -/** - * An identifier that is a parameter in a block, lambda, or method. - */ -class IdentifierParameter extends @token_identifier, Parameter { - IdentifierParameter() { - block_parameters_child(_, _, this) or - destructured_parameter_child(_, _, this) or - lambda_parameters_child(_, _, this) or - method_parameters_child(_, _, this) - } - - override string describeQlClass() { result = "IdentifierParameter" } - - override string toString() { result = this.getName() } - - /** Gets the name of the parameter. */ - string getName() { result = this.(Generated::Identifier).getValue() } + override string getName() { result = generated.getName().getValue() } } diff --git a/ql/src/codeql_ruby/ast/Pattern.qll b/ql/src/codeql_ruby/ast/Pattern.qll new file mode 100644 index 000000000000..a6464e6be669 --- /dev/null +++ b/ql/src/codeql_ruby/ast/Pattern.qll @@ -0,0 +1,40 @@ +import codeql_ruby.AST +private import codeql_ruby.Generated +private import codeql.Locations +private import internal.Pattern +private import Variable + +/** A pattern. */ +class Pattern extends AstNode { + Pattern() { this instanceof PatternRange } +} + +/** A simple variable pattern. */ +class VariablePattern extends Pattern { + override Generated::Identifier generated; + + /** Gets the name of the variable used in this pattern. */ + string getName() { result = generated.getValue() } + + /** Gets the variable used in this pattern. */ + Variable getVariable() { this = result.getAnAccess() } + + override string toString() { result = this.getName() } +} + +/** + * A tuple pattern. + * + * This includes both tuple patterns in parameters and assignments. + */ +class TuplePattern extends Pattern { + TuplePattern() { this instanceof TuplePatternRange } + + /** Gets the `i`th pattern in this tuple pattern. */ + final Pattern getElement(int i) { result = this.(TuplePatternRange).getElement(i) } + + /** Gets a sub pattern in this tuple pattern. */ + final Pattern getAnElement() { result = this.getElement(_) } + + override string toString() { result = "(..., ...)" } +} diff --git a/ql/src/codeql_ruby/ast/Variable.qll b/ql/src/codeql_ruby/ast/Variable.qll index 50eb92532d82..9a3acce53da7 100644 --- a/ql/src/codeql_ruby/ast/Variable.qll +++ b/ql/src/codeql_ruby/ast/Variable.qll @@ -1,140 +1,9 @@ /** Provides classes for modeling program variables. */ -private import codeql_ruby.Generated::Generated +import codeql_ruby.AST +private import codeql_ruby.Generated private import codeql.Locations - -private AstNode parent(AstNode n) { - result = n.getParent() and - not n = any(VariableScope s).getScopeElement() -} - -/** Gets the enclosing scope for `node`. */ -private VariableScope enclosingScope(AstNode node) { - result.getScopeElement() = parent*(node.getParent()) -} - -/** A parameter. */ -class Parameter extends AstNode { - private int position; - private VariableScope scope; - - Parameter() { - this = - scope.(BlockScope).getScopeElement().getAFieldOrChild().(BlockParameters).getChild(position) - or - this = - scope.(MethodScope).getScopeElement().getAFieldOrChild().(MethodParameters).getChild(position) - } - - /** Gets the (zero-based) position of this parameter. */ - final int getPosition() { result = position } - - /** Gets the scope this parameter is declared in. */ - final VariableScope getDeclaringScope() { result = scope } - - /** Gets an access to this parameter. */ - final ParameterAccess getAnAccess() { result.getParameter() = this } -} - -private Identifier parameterIdentifier(Parameter p) { - result = p or - result = p.(SplatParameter).getName() or - result = p.(HashSplatParameter).getName() or - result = p.(BlockParameter).getName() or - result = p.(OptionalParameter).getName() or - result = p.(KeywordParameter).getName() or - result = destructuredIdentifier(p.(DestructuredParameter)) -} - -private Identifier destructuredIdentifier(AstNode node) { - result = node or - result = destructuredIdentifier(node.(DestructuredParameter).getAFieldOrChild()) -} - -/** Holds if `scope` defines `name` in its parameter declaration. */ -private predicate scopeDefinesParameter(VariableScope scope, string name, Location location) { - location = - min(Parameter p, Identifier i | - scope = p.getDeclaringScope() and - i = parameterIdentifier(p) and - name = i.getValue() - | - i.getLocation() as loc order by loc.getStartLine(), loc.getStartColumn() - ) -} - -/** Holds if `var` is assigned in `scope`. */ -private predicate scopeAssigns(VariableScope scope, Identifier var) { - var in [any(Assignment assign).getLeft(), any(OperatorAssignment assign).getLeft()] and - scope = enclosingScope(var) -} - -/** Holds if location `one` starts strictly before location `two` */ -pragma[inline] -predicate strictlyBefore(Location one, Location two) { - one.getStartLine() < two.getStartLine() - or - one.getStartLine() = two.getStartLine() and one.getStartColumn() < two.getStartColumn() -} - -/** Holds if block scope `scope` inherits `var` from an outer scope `outer`. */ -private predicate blockScopeInherits(BlockScope scope, string var, VariableScope outer) { - not scopeDefinesParameter(scope, var, _) and - ( - outer = scope.getOuterScope() and - ( - scopeDefinesParameter(outer, var, _) - or - exists(Identifier i | i.getValue() = var | - scopeAssigns(outer, i) and - strictlyBefore(i.getLocation(), scope.getLocation()) - ) - ) - or - blockScopeInherits(scope.getOuterScope(), var, outer) - ) -} - -cached -private module Cached { - cached - newtype TScope = - TTopLevelScope(Program node) or - TModuleScope(Module node) or - TClassScope(AstNode cls) { cls instanceof Class or cls instanceof SingletonClass } or - TMethodScope(AstNode method) { method instanceof Method or method instanceof SingletonMethod } or - TBlockScope(AstNode block) { block instanceof Block or block instanceof DoBlock } - - cached - newtype TVariable = - TLocalVariable(VariableScope scope, string name, Location location) { - scopeDefinesParameter(scope, name, location) - or - not scopeDefinesParameter(scope, name, _) and - not blockScopeInherits(scope, name, _) and - location = - min(Location loc, Identifier other | - loc = other.getLocation() and name = other.getValue() and scopeAssigns(scope, other) - | - loc order by loc.getStartLine(), loc.getStartColumn() - ) - } - - cached - predicate access(Identifier access, Variable variable) { - exists(string name | name = access.getValue() | - variable = enclosingScope(access).getVariable(name) and - not strictlyBefore(access.getLocation(), variable.getLocation()) - or - exists(VariableScope declScope | - variable = declScope.getVariable(name) and - blockScopeInherits(enclosingScope(access), name, declScope) - ) - ) - } -} - -private import Cached +private import internal.Variable /** A scope in which variables can be declared. */ class VariableScope extends TScope { @@ -157,6 +26,47 @@ class VariableScope extends TScope { } } +/** A top-level scope. */ +class TopLevelScope extends VariableScope, TTopLevelScope { + final override string toString() { result = "top-level scope" } + + final override AstNode getScopeElement() { TTopLevelScope(result) = this } +} + +/** A module scope. */ +class ModuleScope extends VariableScope, TModuleScope { + final override string toString() { result = "module scope" } + + final override AstNode getScopeElement() { TModuleScope(result) = this } +} + +/** A class scope. */ +class ClassScope extends VariableScope, TClassScope { + final override string toString() { result = "class scope" } + + final override AstNode getScopeElement() { TClassScope(result) = this } +} + +/** A callable scope. */ +class CallableScope extends VariableScope, TCallableScope { + private Callable c; + + CallableScope() { this = TCallableScope(c) } + + final override string toString() { + (c instanceof Method or c instanceof SingletonMethod) and + result = "method scope" + or + c instanceof Lambda and + result = "lambda scope" + or + c instanceof Block and + result = "block scope" + } + + final override Callable getScopeElement() { TCallableScope(result) = this } +} + /** A variable declared in a scope. */ class Variable extends TVariable { /** Gets the name of this variable. */ @@ -179,78 +89,37 @@ class Variable extends TVariable { class LocalVariable extends Variable { private VariableScope scope; private string name; - private Location location; + private Generated::Identifier i; - LocalVariable() { this = TLocalVariable(scope, name, location) } + LocalVariable() { this = TLocalVariable(scope, name, i) } final override string getName() { result = name } - final override Location getLocation() { result = location } + final override Location getLocation() { result = i.getLocation() } final override VariableScope getDeclaringScope() { result = scope } + + final override LocalVariableAccess getAnAccess() { result.getVariable() = this } } -/** An identifier that refers to a variable. */ -class VariableAccess extends Identifier { +/** An access to a variable. */ +class VariableAccess extends AstNode, @token_identifier { + override Generated::Identifier generated; Variable variable; VariableAccess() { access(this, variable) } - /** - * Gets the variable this identifier refers to. - */ + /** Gets the variable this identifier refers to. */ Variable getVariable() { result = variable } -} - -/** An identifier that refers to a parameter. */ -class ParameterAccess extends VariableAccess { - Parameter parameter; - - ParameterAccess() { - exists(Identifier i | - i = parameterIdentifier(parameter) and - variable.getDeclaringScope() = parameter.getDeclaringScope() and - variable.getLocation() = i.getLocation() - ) - } - - final Parameter getParameter() { result = parameter } -} - -/** A top-level scope. */ -class TopLevelScope extends VariableScope, TTopLevelScope { - final override string toString() { result = "top-level scope" } - - final override AstNode getScopeElement() { TTopLevelScope(result) = this } -} - -/** A module scope. */ -class ModuleScope extends VariableScope, TModuleScope { - final override string toString() { result = "module scope" } - - final override Module getScopeElement() { TModuleScope(result) = this } -} - -/** A class scope. */ -class ClassScope extends VariableScope, TClassScope { - final override string toString() { result = "class scope" } - - final override AstNode getScopeElement() { TClassScope(result) = this } -} - -/** A method scope. */ -class MethodScope extends VariableScope, TMethodScope { - final override string toString() { result = "method scope" } - final override AstNode getScopeElement() { TMethodScope(result) = this } + override string toString() { result = variable.getName() } } -/** A block scope. */ -class BlockScope extends VariableScope, TBlockScope { - final override string toString() { result = "block scope" } +/** An access to a local variable. */ +class LocalVariableAccess extends VariableAccess { + override LocalVariable variable; - final override AstNode getScopeElement() { TBlockScope(result) = this } + override LocalVariable getVariable() { result = variable } - /** Gets the scope in which this scope is nested, if any. */ - final VariableScope getOuterScope() { result = enclosingScope(this.getScopeElement()) } + override string toString() { result = variable.getName() } } diff --git a/ql/src/codeql_ruby/ast/internal/Method.qll b/ql/src/codeql_ruby/ast/internal/Method.qll new file mode 100644 index 000000000000..b2519a8e3d08 --- /dev/null +++ b/ql/src/codeql_ruby/ast/internal/Method.qll @@ -0,0 +1,42 @@ +import codeql_ruby.AST +private import codeql_ruby.Generated + +abstract class CallableRange extends AstNode { + abstract Parameter getParameter(int n); +} + +private class MethodRange extends CallableRange, @method { + final override Generated::Method generated; + + override Parameter getParameter(int n) { result = generated.getParameters().getChild(n) } +} + +private class SingletonMethodRange extends CallableRange, @singleton_method { + final override Generated::SingletonMethod generated; + + override Parameter getParameter(int n) { result = generated.getParameters().getChild(n) } +} + +private class LambdaRange extends CallableRange, @lambda { + final override Generated::Lambda generated; + + final override Parameter getParameter(int n) { result = generated.getParameters().getChild(n) } +} + +abstract class BlockRange extends CallableRange { + Generated::BlockParameters params; + + final override Parameter getParameter(int n) { result = params.getChild(n) } +} + +private class DoBlockRange extends BlockRange, @do_block { + final override Generated::DoBlock generated; + + DoBlockRange() { params = generated.getParameters() } +} + +private class BraceBlockRange extends BlockRange, @block { + final override Generated::Block generated; + + BraceBlockRange() { params = generated.getParameters() } +} diff --git a/ql/src/codeql_ruby/ast/internal/Pattern.qll b/ql/src/codeql_ruby/ast/internal/Pattern.qll new file mode 100644 index 000000000000..35ebc7c69d5d --- /dev/null +++ b/ql/src/codeql_ruby/ast/internal/Pattern.qll @@ -0,0 +1,65 @@ +import codeql_ruby.AST +private import codeql_ruby.Generated +private import codeql.Locations + +private predicate tuplePatternNode(Generated::AstNode n, boolean parameter) { + n instanceof Generated::DestructuredParameter and + parameter = true + or + n instanceof Generated::DestructuredLeftAssignment and + parameter = false + or + n instanceof Generated::LeftAssignmentList and + parameter = false + or + tuplePatternNode(n.getParent(), parameter) +} + +private predicate patternNode(Generated::AstNode n, boolean parameter) { + tuplePatternNode(n, parameter) + or + parameter = true and + n = any(Callable c).getAParameter() + or + parameter = false and + n in [ + any(Generated::Assignment assign).getLeft(), + any(Generated::OperatorAssignment assign).getLeft() + ] +} + +/** + * Holds if a variable is assigned at `i`. `parameter` indicates whether it is + * an implicit parameter assignment. + */ +predicate assignment(Generated::Identifier i, boolean parameter) { patternNode(i, parameter) } + +abstract class PatternRange extends AstNode { + PatternRange() { patternNode(this, _) } +} + +private class VariablePatternRange extends PatternRange { + override Generated::Identifier generated; +} + +abstract class TuplePatternRange extends PatternRange { + abstract Pattern getElement(int i); +} + +private class ParameterTuplePatternRange extends TuplePatternRange { + override Generated::DestructuredParameter generated; + + override Pattern getElement(int i) { result = generated.getChild(i) } +} + +private class AssignmentTuplePatternRange extends TuplePatternRange { + override Generated::DestructuredLeftAssignment generated; + + override Pattern getElement(int i) { result = generated.getChild(i) } +} + +private class AssignmentListPatternRange extends TuplePatternRange { + override Generated::LeftAssignmentList generated; + + override Pattern getElement(int i) { result = generated.getChild(i) } +} diff --git a/ql/src/codeql_ruby/ast/internal/Variable.qll b/ql/src/codeql_ruby/ast/internal/Variable.qll new file mode 100644 index 000000000000..8cbda5c70b86 --- /dev/null +++ b/ql/src/codeql_ruby/ast/internal/Variable.qll @@ -0,0 +1,130 @@ +import codeql_ruby.AST +private import codeql_ruby.Generated +private import codeql.Locations +private import Pattern + +private Generated::AstNode parent(Generated::AstNode n) { + result = n.getParent() and + not n = any(VariableScope s).getScopeElement() +} + +/** Gets the enclosing scope for `node`. */ +private VariableScope enclosingScope(Generated::AstNode node) { + result.getScopeElement() = parent*(node.getParent()) +} + +/** Holds if `scope` defines `name` in its parameter declaration at `i`. */ +private predicate scopeDefinesParameterVariable( + CallableScope scope, string name, Generated::Identifier i +) { + assignment(i, true) and + scope = enclosingScope(i) and + name = i.getValue() + or + exists(Parameter p | + p = scope.getScopeElement().getAParameter() and + name = p.(NamedParameter).getName() + | + i = p.(Generated::BlockParameter).getName() or + i = p.(Generated::HashSplatParameter).getName() or + i = p.(Generated::KeywordParameter).getName() or + i = p.(Generated::OptionalParameter).getName() or + i = p.(Generated::SplatParameter).getName() + ) +} + +/** Holds if `name` is assigned in `scope` at `i`. */ +private predicate scopeAssigns(VariableScope scope, string name, Generated::Identifier i) { + assignment(i, false) and + name = i.getValue() and + scope = enclosingScope(i) +} + +/** Holds if location `one` starts strictly before location `two` */ +pragma[inline] +private predicate strictlyBefore(Location one, Location two) { + one.getStartLine() < two.getStartLine() + or + one.getStartLine() = two.getStartLine() and one.getStartColumn() < two.getStartColumn() +} + +/** A scope that may capture outer local variables. */ +private class CapturingScope extends CallableScope { + CapturingScope() { + exists(Callable c | c = this.getScopeElement() | + c instanceof Block + or + c instanceof DoBlock + or + c instanceof Lambda // TODO: Check if this is actually the case + ) + } + + /** Gets the scope in which this scope is nested, if any. */ + private VariableScope getOuterScope() { result = enclosingScope(this.getScopeElement()) } + + /** Holds if this scope inherits `name` from an outer scope `outer`. */ + predicate inherits(string name, VariableScope outer) { + not scopeDefinesParameterVariable(this, name, _) and + ( + outer = this.getOuterScope() and + ( + scopeDefinesParameterVariable(outer, name, _) + or + exists(Generated::Identifier i | + scopeAssigns(outer, name, i) and + strictlyBefore(i.getLocation(), this.getLocation()) + ) + ) + or + this.getOuterScope().(CapturingScope).inherits(name, outer) + ) + } +} + +cached +private module Cached { + cached + newtype TScope = + TTopLevelScope(Generated::Program node) or + TModuleScope(Generated::Module node) or + TClassScope(AstNode cls) { + cls instanceof Generated::Class or cls instanceof Generated::SingletonClass + } or + TCallableScope(Callable c) + + cached + newtype TVariable = + TLocalVariable(VariableScope scope, string name, Generated::Identifier i) { + scopeDefinesParameterVariable(scope, name, i) + or + scopeAssigns(scope, name, i) and + i = + min(Generated::Identifier other | + scopeAssigns(scope, name, other) + | + other order by other.getLocation().getStartLine(), other.getLocation().getStartColumn() + ) and + not scopeDefinesParameterVariable(scope, name, _) and + not scope.(CapturingScope).inherits(name, _) + } + + cached + predicate access(Generated::Identifier access, Variable variable) { + exists(string name | + name = access.getValue() and + // Do not generate an access at the defining location + not variable = TLocalVariable(_, name, access) + | + variable = enclosingScope(access).getVariable(name) and + not strictlyBefore(access.getLocation(), variable.getLocation()) + or + exists(VariableScope declScope | + variable = declScope.getVariable(name) and + enclosingScope(access).(CapturingScope).inherits(name, declScope) + ) + ) + } +} + +import Cached diff --git a/ql/test/library-tests/ast/params/params.expected b/ql/test/library-tests/ast/params/params.expected index c3fde5ca2d09..5f3ac3db14ca 100644 --- a/ql/test/library-tests/ast/params/params.expected +++ b/ql/test/library-tests/ast/params/params.expected @@ -6,23 +6,33 @@ idParams | params.rb:9:20:9:24 | value | value | | params.rb:14:11:14:13 | foo | foo | | params.rb:14:16:14:18 | bar | bar | -| params.rb:17:32:17:32 | a | a | -| params.rb:17:35:17:35 | b | b | -| params.rb:17:38:17:38 | c | c | -| params.rb:22:16:22:16 | a | a | -| params.rb:22:19:22:19 | b | b | -| params.rb:25:24:25:28 | first | first | -| params.rb:25:31:25:36 | second | second | -| params.rb:25:41:25:45 | third | third | -| params.rb:25:48:25:53 | fourth | fourth | | params.rb:30:23:30:28 | wibble | wibble | +| params.rb:30:31:30:36 | splat | splat | +| params.rb:30:39:30:52 | **double_splat | double_splat | | params.rb:34:16:34:18 | val | val | +| params.rb:34:21:34:26 | splat | splat | +| params.rb:34:29:34:42 | **double_splat | double_splat | | params.rb:38:26:38:26 | x | x | +| params.rb:38:29:38:33 | blah | blah | +| params.rb:38:36:38:43 | **wibble | wibble | | params.rb:41:32:41:32 | x | x | +| params.rb:41:35:41:38 | foo | foo | +| params.rb:41:41:41:46 | bar | bar | +| params.rb:46:28:46:33 | &block | block | +| params.rb:49:28:49:30 | xx | xx | +| params.rb:49:33:49:39 | yy | yy | | params.rb:53:34:53:34 | x | x | +| params.rb:53:37:53:38 | y | y | +| params.rb:53:41:53:44 | z | z | | params.rb:58:33:58:36 | val1 | val1 | +| params.rb:58:39:58:46 | val2 | val2 | +| params.rb:58:49:58:58 | val3 | val3 | +| params.rb:62:29:62:34 | &block | block | | params.rb:65:29:65:32 | name | name | +| params.rb:65:35:65:42 | age | age | | params.rb:70:35:70:35 | a | a | +| params.rb:70:38:70:45 | b | b | +| params.rb:70:48:70:53 | c | c | blockParams | params.rb:46:28:46:33 | &block | block | | params.rb:62:29:62:34 | &block | block | @@ -58,82 +68,82 @@ optionalParams | params.rb:70:38:70:45 | b | b | params.rb:70:42:70:45 | AstNode | | params.rb:70:48:70:53 | c | c | params.rb:70:52:70:53 | AstNode | paramsInMethods -| params.rb:4:1:5:3 | identifier_method_params | 0 | params.rb:4:30:4:32 | foo | IdentifierParameter | -| params.rb:4:1:5:3 | identifier_method_params | 1 | params.rb:4:35:4:37 | bar | IdentifierParameter | -| params.rb:4:1:5:3 | identifier_method_params | 2 | params.rb:4:40:4:42 | baz | IdentifierParameter | -| params.rb:17:1:18:3 | destructured_method_param | 0 | params.rb:17:31:17:39 | (..., ...) | PatternParameter | -| params.rb:30:1:31:3 | method_with_splat | 0 | params.rb:30:23:30:28 | wibble | IdentifierParameter | +| params.rb:4:1:5:3 | identifier_method_params | 0 | params.rb:4:30:4:32 | foo | SimpleParameter | +| params.rb:4:1:5:3 | identifier_method_params | 1 | params.rb:4:35:4:37 | bar | SimpleParameter | +| params.rb:4:1:5:3 | identifier_method_params | 2 | params.rb:4:40:4:42 | baz | SimpleParameter | +| params.rb:17:1:18:3 | destructured_method_param | 0 | params.rb:17:31:17:39 | (..., ...) | TuplePatternParameter | +| params.rb:30:1:31:3 | method_with_splat | 0 | params.rb:30:23:30:28 | wibble | SimpleParameter | | params.rb:30:1:31:3 | method_with_splat | 1 | params.rb:30:31:30:36 | splat | SplatParameter | | params.rb:30:1:31:3 | method_with_splat | 2 | params.rb:30:39:30:52 | **double_splat | HashSplatParameter | -| params.rb:41:1:43:3 | method_with_keyword_params | 0 | params.rb:41:32:41:32 | x | IdentifierParameter | +| params.rb:41:1:43:3 | method_with_keyword_params | 0 | params.rb:41:32:41:32 | x | SimpleParameter | | params.rb:41:1:43:3 | method_with_keyword_params | 1 | params.rb:41:35:41:38 | foo | KeywordParameter | | params.rb:41:1:43:3 | method_with_keyword_params | 2 | params.rb:41:41:41:46 | bar | KeywordParameter | | params.rb:46:1:48:3 | use_block_with_keyword | 0 | params.rb:46:28:46:33 | &block | BlockParameter | -| params.rb:58:1:59:3 | method_with_optional_params | 0 | params.rb:58:33:58:36 | val1 | IdentifierParameter | +| params.rb:58:1:59:3 | method_with_optional_params | 0 | params.rb:58:33:58:36 | val1 | SimpleParameter | | params.rb:58:1:59:3 | method_with_optional_params | 1 | params.rb:58:39:58:46 | val2 | OptionalParameter | | params.rb:58:1:59:3 | method_with_optional_params | 2 | params.rb:58:49:58:58 | val3 | OptionalParameter | | params.rb:62:1:64:3 | use_block_with_optional | 0 | params.rb:62:29:62:34 | &block | BlockParameter | paramsInBlocks -| params.rb:9:11:11:3 | \| ... \| | 0 | params.rb:9:15:9:17 | key | IdentifierParameter | -| params.rb:9:11:11:3 | \| ... \| | 1 | params.rb:9:20:9:24 | value | IdentifierParameter | -| params.rb:22:12:22:32 | { ... } | 0 | params.rb:22:15:22:20 | (..., ...) | PatternParameter | -| params.rb:34:12:35:3 | \| ... \| | 0 | params.rb:34:16:34:18 | val | IdentifierParameter | +| params.rb:9:11:11:3 | \| ... \| | 0 | params.rb:9:15:9:17 | key | SimpleParameter | +| params.rb:9:11:11:3 | \| ... \| | 1 | params.rb:9:20:9:24 | value | SimpleParameter | +| params.rb:22:12:22:32 | { ... } | 0 | params.rb:22:15:22:20 | (..., ...) | TuplePatternParameter | +| params.rb:34:12:35:3 | \| ... \| | 0 | params.rb:34:16:34:18 | val | SimpleParameter | | params.rb:34:12:35:3 | \| ... \| | 1 | params.rb:34:21:34:26 | splat | SplatParameter | | params.rb:34:12:35:3 | \| ... \| | 2 | params.rb:34:29:34:42 | **double_splat | HashSplatParameter | | params.rb:49:24:51:3 | \| ... \| | 0 | params.rb:49:28:49:30 | xx | KeywordParameter | | params.rb:49:24:51:3 | \| ... \| | 1 | params.rb:49:33:49:39 | yy | KeywordParameter | -| params.rb:65:25:67:3 | \| ... \| | 0 | params.rb:65:29:65:32 | name | IdentifierParameter | +| params.rb:65:25:67:3 | \| ... \| | 0 | params.rb:65:29:65:32 | name | SimpleParameter | | params.rb:65:25:67:3 | \| ... \| | 1 | params.rb:65:35:65:42 | age | OptionalParameter | paramsInLambdas -| params.rb:14:7:14:33 | -> { ... } | 0 | params.rb:14:11:14:13 | foo | IdentifierParameter | -| params.rb:14:7:14:33 | -> { ... } | 1 | params.rb:14:16:14:18 | bar | IdentifierParameter | -| params.rb:25:19:27:1 | -> { ... } | 0 | params.rb:25:23:25:37 | (..., ...) | PatternParameter | -| params.rb:25:19:27:1 | -> { ... } | 1 | params.rb:25:40:25:54 | (..., ...) | PatternParameter | -| params.rb:38:22:38:47 | -> { ... } | 0 | params.rb:38:26:38:26 | x | IdentifierParameter | +| params.rb:14:7:14:33 | -> { ... } | 0 | params.rb:14:11:14:13 | foo | SimpleParameter | +| params.rb:14:7:14:33 | -> { ... } | 1 | params.rb:14:16:14:18 | bar | SimpleParameter | +| params.rb:25:19:27:1 | -> { ... } | 0 | params.rb:25:23:25:37 | (..., ...) | TuplePatternParameter | +| params.rb:25:19:27:1 | -> { ... } | 1 | params.rb:25:40:25:54 | (..., ...) | TuplePatternParameter | +| params.rb:38:22:38:47 | -> { ... } | 0 | params.rb:38:26:38:26 | x | SimpleParameter | | params.rb:38:22:38:47 | -> { ... } | 1 | params.rb:38:29:38:33 | blah | SplatParameter | | params.rb:38:22:38:47 | -> { ... } | 2 | params.rb:38:36:38:43 | **wibble | HashSplatParameter | -| params.rb:53:30:55:1 | -> { ... } | 0 | params.rb:53:34:53:34 | x | IdentifierParameter | +| params.rb:53:30:55:1 | -> { ... } | 0 | params.rb:53:34:53:34 | x | SimpleParameter | | params.rb:53:30:55:1 | -> { ... } | 1 | params.rb:53:37:53:38 | y | KeywordParameter | | params.rb:53:30:55:1 | -> { ... } | 2 | params.rb:53:41:53:44 | z | KeywordParameter | -| params.rb:70:31:70:64 | -> { ... } | 0 | params.rb:70:35:70:35 | a | IdentifierParameter | +| params.rb:70:31:70:64 | -> { ... } | 0 | params.rb:70:35:70:35 | a | SimpleParameter | | params.rb:70:31:70:64 | -> { ... } | 1 | params.rb:70:38:70:45 | b | OptionalParameter | | params.rb:70:31:70:64 | -> { ... } | 2 | params.rb:70:48:70:53 | c | OptionalParameter | #select -| params.rb:4:30:4:32 | foo | 0 | IdentifierParameter | -| params.rb:4:35:4:37 | bar | 1 | IdentifierParameter | -| params.rb:4:40:4:42 | baz | 2 | IdentifierParameter | -| params.rb:9:15:9:17 | key | 0 | IdentifierParameter | -| params.rb:9:20:9:24 | value | 1 | IdentifierParameter | -| params.rb:14:11:14:13 | foo | 0 | IdentifierParameter | -| params.rb:14:16:14:18 | bar | 1 | IdentifierParameter | -| params.rb:17:31:17:39 | (..., ...) | 0 | PatternParameter | -| params.rb:22:15:22:20 | (..., ...) | 0 | PatternParameter | -| params.rb:25:23:25:37 | (..., ...) | 0 | PatternParameter | -| params.rb:25:40:25:54 | (..., ...) | 1 | PatternParameter | -| params.rb:30:23:30:28 | wibble | 0 | IdentifierParameter | +| params.rb:4:30:4:32 | foo | 0 | SimpleParameter | +| params.rb:4:35:4:37 | bar | 1 | SimpleParameter | +| params.rb:4:40:4:42 | baz | 2 | SimpleParameter | +| params.rb:9:15:9:17 | key | 0 | SimpleParameter | +| params.rb:9:20:9:24 | value | 1 | SimpleParameter | +| params.rb:14:11:14:13 | foo | 0 | SimpleParameter | +| params.rb:14:16:14:18 | bar | 1 | SimpleParameter | +| params.rb:17:31:17:39 | (..., ...) | 0 | TuplePatternParameter | +| params.rb:22:15:22:20 | (..., ...) | 0 | TuplePatternParameter | +| params.rb:25:23:25:37 | (..., ...) | 0 | TuplePatternParameter | +| params.rb:25:40:25:54 | (..., ...) | 1 | TuplePatternParameter | +| params.rb:30:23:30:28 | wibble | 0 | SimpleParameter | | params.rb:30:31:30:36 | splat | 1 | SplatParameter | | params.rb:30:39:30:52 | **double_splat | 2 | HashSplatParameter | -| params.rb:34:16:34:18 | val | 0 | IdentifierParameter | +| params.rb:34:16:34:18 | val | 0 | SimpleParameter | | params.rb:34:21:34:26 | splat | 1 | SplatParameter | | params.rb:34:29:34:42 | **double_splat | 2 | HashSplatParameter | -| params.rb:38:26:38:26 | x | 0 | IdentifierParameter | +| params.rb:38:26:38:26 | x | 0 | SimpleParameter | | params.rb:38:29:38:33 | blah | 1 | SplatParameter | | params.rb:38:36:38:43 | **wibble | 2 | HashSplatParameter | -| params.rb:41:32:41:32 | x | 0 | IdentifierParameter | +| params.rb:41:32:41:32 | x | 0 | SimpleParameter | | params.rb:41:35:41:38 | foo | 1 | KeywordParameter | | params.rb:41:41:41:46 | bar | 2 | KeywordParameter | | params.rb:46:28:46:33 | &block | 0 | BlockParameter | | params.rb:49:28:49:30 | xx | 0 | KeywordParameter | | params.rb:49:33:49:39 | yy | 1 | KeywordParameter | -| params.rb:53:34:53:34 | x | 0 | IdentifierParameter | +| params.rb:53:34:53:34 | x | 0 | SimpleParameter | | params.rb:53:37:53:38 | y | 1 | KeywordParameter | | params.rb:53:41:53:44 | z | 2 | KeywordParameter | -| params.rb:58:33:58:36 | val1 | 0 | IdentifierParameter | +| params.rb:58:33:58:36 | val1 | 0 | SimpleParameter | | params.rb:58:39:58:46 | val2 | 1 | OptionalParameter | | params.rb:58:49:58:58 | val3 | 2 | OptionalParameter | | params.rb:62:29:62:34 | &block | 0 | BlockParameter | -| params.rb:65:29:65:32 | name | 0 | IdentifierParameter | +| params.rb:65:29:65:32 | name | 0 | SimpleParameter | | params.rb:65:35:65:42 | age | 1 | OptionalParameter | -| params.rb:70:35:70:35 | a | 0 | IdentifierParameter | +| params.rb:70:35:70:35 | a | 0 | SimpleParameter | | params.rb:70:38:70:45 | b | 1 | OptionalParameter | | params.rb:70:48:70:53 | c | 2 | OptionalParameter | diff --git a/ql/test/library-tests/ast/params/params.ql b/ql/test/library-tests/ast/params/params.ql index c17f921d3f2d..0ae480f01007 100644 --- a/ql/test/library-tests/ast/params/params.ql +++ b/ql/test/library-tests/ast/params/params.ql @@ -2,12 +2,12 @@ import ruby //////////////////////////////////////////////////////////////////////////////// // Query predicates for various types of parameter -query predicate idParams(IdentifierParameter ip, string name) { name = ip.getName() } +query predicate idParams(NamedParameter np, string name) { name = np.getName() } query predicate blockParams(BlockParameter bp, string name) { name = bp.getName() } -query predicate patternParams(PatternParameter pp, Parameter child, int childIndex) { - pp.getElement(childIndex) = child +query predicate patternParams(TuplePatternParameter tpp, Pattern child, int childIndex) { + tpp.getElement(childIndex) = child } query predicate splatParams(SplatParameter sp, string name) { name = sp.getName() } diff --git a/ql/test/library-tests/variables/parameter.expected b/ql/test/library-tests/variables/parameter.expected index 1e3167d187dc..1a881a81b788 100644 --- a/ql/test/library-tests/variables/parameter.expected +++ b/ql/test/library-tests/variables/parameter.expected @@ -1,29 +1,29 @@ parameter | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:23:15:23 | a | -| nested_scopes.rb:16:26:16:26 | x | nested_scopes.rb:16:26:16:26 | x | | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:29:16:29 | a | -| nested_scopes.rb:18:26:18:26 | x | nested_scopes.rb:18:26:18:26 | x | | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:21:22:21 | a | | parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | | parameters.rb:1:18:1:18 | y | parameters.rb:1:18:1:18 | y | | parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | -| parameters.rb:7:25:7:31 | SplatParameter | parameters.rb:7:26:7:31 | pizzas | -| parameters.rb:15:15:15:19 | HashSplatParameter | parameters.rb:15:17:15:19 | map | +| parameters.rb:7:25:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | +| parameters.rb:15:15:15:19 | **map | parameters.rb:15:17:15:19 | map | | parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | | parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | -| parameters.rb:21:16:21:21 | BlockParameter | parameters.rb:21:17:21:21 | block | -| parameters.rb:25:15:25:30 | OptionalParameter | parameters.rb:25:15:25:18 | name | -| parameters.rb:25:33:25:50 | OptionalParameter | parameters.rb:25:33:25:36 | size | -| parameters.rb:30:15:30:20 | KeywordParameter | parameters.rb:30:15:30:19 | first | -| parameters.rb:30:24:30:33 | KeywordParameter | parameters.rb:30:24:30:29 | middle | -| parameters.rb:30:36:30:40 | KeywordParameter | parameters.rb:30:36:30:39 | last | -| parameters.rb:35:11:35:21 | OptionalParameter | parameters.rb:35:11:35:11 | a | -| parameters.rb:40:12:40:19 | KeywordParameter | parameters.rb:40:12:40:12 | d | +| parameters.rb:21:16:21:21 | &block | parameters.rb:21:17:21:21 | block | +| parameters.rb:25:15:25:30 | name | parameters.rb:25:15:25:18 | name | +| parameters.rb:25:33:25:50 | size | parameters.rb:25:33:25:36 | size | +| parameters.rb:30:15:30:20 | first | parameters.rb:30:15:30:19 | first | +| parameters.rb:30:24:30:33 | middle | parameters.rb:30:24:30:29 | middle | +| parameters.rb:30:36:30:40 | last | parameters.rb:30:36:30:39 | last | +| parameters.rb:35:11:35:21 | a | parameters.rb:35:11:35:11 | a | +| parameters.rb:40:12:40:19 | d | parameters.rb:40:12:40:12 | d | | parameters.rb:45:20:45:20 | _ | parameters.rb:45:20:45:20 | _ | -| parameters.rb:49:12:49:16 | DestructuredParameter | parameters.rb:49:13:49:13 | a | -| parameters.rb:49:12:49:16 | DestructuredParameter | parameters.rb:49:15:49:15 | b | -| parameters.rb:54:14:54:24 | OptionalParameter | parameters.rb:54:14:54:14 | y | -| scopes.rb:2:14:2:14 | x | scopes.rb:2:14:2:14 | x | -| scopes.rb:9:14:9:14 | x | scopes.rb:9:14:9:14 | x | +| parameters.rb:45:20:45:20 | _ | parameters.rb:45:22:45:22 | _ | +| parameters.rb:45:22:45:22 | _ | parameters.rb:45:20:45:20 | _ | +| parameters.rb:45:22:45:22 | _ | parameters.rb:45:22:45:22 | _ | +| parameters.rb:54:14:54:24 | y | parameters.rb:54:14:54:14 | y | parameterNoAcess -| parameters.rb:45:22:45:22 | _ | +| nested_scopes.rb:16:26:16:26 | x | +| nested_scopes.rb:18:26:18:26 | x | +| scopes.rb:2:14:2:14 | x | +| scopes.rb:9:14:9:14 | x | diff --git a/ql/test/library-tests/variables/parameter.ql b/ql/test/library-tests/variables/parameter.ql index 254abfc2daec..5826fca9e290 100644 --- a/ql/test/library-tests/variables/parameter.ql +++ b/ql/test/library-tests/variables/parameter.ql @@ -1,5 +1,5 @@ import codeql_ruby.ast.Variable -query predicate parameter(Parameter p, Variable v) { p.getAnAccess().getVariable() = v } +query predicate parameter(NamedParameter p, Variable v) { p.getAnAccess().getVariable() = v } -query predicate parameterNoAcess(Parameter p) { not exists(p.getAnAccess()) } +query predicate parameterNoAcess(NamedParameter p) { not exists(p.getAnAccess()) } diff --git a/ql/test/library-tests/variables/scopes.rb b/ql/test/library-tests/variables/scopes.rb index 9ecbad96c5cd..1219acef8ccd 100644 --- a/ql/test/library-tests/variables/scopes.rb +++ b/ql/test/library-tests/variables/scopes.rb @@ -10,4 +10,9 @@ def a ; "x" end puts a # local variable from top-level a = 3 puts a # local variable from top-level + a, b, (c, d) = [4, 5, [6, 7]] + puts a # local variable from top-level + puts b # new local variable + puts c # new local variable + puts d # new local variable end \ No newline at end of file diff --git a/ql/test/library-tests/variables/varaccess.expected b/ql/test/library-tests/variables/varaccess.expected index afb0bdab854f..3b076a124e2e 100644 --- a/ql/test/library-tests/variables/varaccess.expected +++ b/ql/test/library-tests/variables/varaccess.expected @@ -1,173 +1,52 @@ -variableAccess -| nested_scopes.rb:5:3:5:3 | a | nested_scopes.rb:5:3:5:3 | a | nested_scopes.rb:4:1:39:3 | class scope | -| nested_scopes.rb:7:5:7:5 | a | nested_scopes.rb:7:5:7:5 | a | nested_scopes.rb:6:3:37:5 | module scope | -| nested_scopes.rb:9:7:9:7 | a | nested_scopes.rb:9:7:9:7 | a | nested_scopes.rb:8:5:35:7 | module scope | -| nested_scopes.rb:11:9:11:9 | a | nested_scopes.rb:11:9:11:9 | a | nested_scopes.rb:10:7:26:9 | class scope | -| nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:12:9:21:11 | method scope | | nested_scopes.rb:14:16:14:16 | a | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:12:9:21:11 | method scope | | nested_scopes.rb:15:11:15:11 | a | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:12:9:21:11 | method scope | -| nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:19:20:13 | block scope | | nested_scopes.rb:16:13:16:13 | a | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:19:20:13 | block scope | -| nested_scopes.rb:16:26:16:26 | x | nested_scopes.rb:16:26:16:26 | x | nested_scopes.rb:16:21:19:15 | block scope | -| nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:21:19:15 | block scope | | nested_scopes.rb:17:15:17:15 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:21:19:15 | block scope | | nested_scopes.rb:18:15:18:15 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:21:19:15 | block scope | -| nested_scopes.rb:18:26:18:26 | x | nested_scopes.rb:18:26:18:26 | x | nested_scopes.rb:18:23:18:36 | block scope | | nested_scopes.rb:18:34:18:34 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:21:19:15 | block scope | -| nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:9:24:11 | method scope | | nested_scopes.rb:23:16:23:16 | a | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:9:24:11 | method scope | | nested_scopes.rb:25:14:25:14 | a | nested_scopes.rb:11:9:11:9 | a | nested_scopes.rb:10:7:26:9 | class scope | -| nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:30:7:33:9 | class scope | | nested_scopes.rb:32:16:32:16 | a | nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:30:7:33:9 | class scope | | nested_scopes.rb:34:12:34:12 | a | nested_scopes.rb:9:7:9:7 | a | nested_scopes.rb:8:5:35:7 | module scope | | nested_scopes.rb:36:10:36:10 | a | nested_scopes.rb:7:5:7:5 | a | nested_scopes.rb:6:3:37:5 | module scope | | nested_scopes.rb:38:8:38:8 | a | nested_scopes.rb:5:3:5:3 | a | nested_scopes.rb:4:1:39:3 | class scope | -| nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:1:1:42:1 | top-level scope | | nested_scopes.rb:41:1:41:1 | d | nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:1:1:42:1 | top-level scope | -| parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | parameters.rb:1:9:5:3 | block scope | -| parameters.rb:1:18:1:18 | y | parameters.rb:1:18:1:18 | y | parameters.rb:1:9:5:3 | block scope | | parameters.rb:2:4:2:4 | y | parameters.rb:1:18:1:18 | y | parameters.rb:1:9:5:3 | block scope | | parameters.rb:3:9:3:9 | x | parameters.rb:1:14:1:14 | x | parameters.rb:1:9:5:3 | block scope | | parameters.rb:4:9:4:9 | y | parameters.rb:1:18:1:18 | y | parameters.rb:1:9:5:3 | block scope | -| parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:7:1:13:3 | method scope | -| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:1:13:3 | method scope | | parameters.rb:8:6:8:11 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:1:13:3 | method scope | | parameters.rb:9:25:9:30 | client | parameters.rb:7:17:7:22 | client | parameters.rb:7:1:13:3 | method scope | | parameters.rb:11:14:11:19 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:1:13:3 | method scope | | parameters.rb:11:41:11:46 | client | parameters.rb:7:17:7:22 | client | parameters.rb:7:1:13:3 | method scope | -| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | parameters.rb:15:1:19:3 | method scope | | parameters.rb:16:3:16:5 | map | parameters.rb:15:17:15:19 | map | parameters.rb:15:1:19:3 | method scope | -| parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | parameters.rb:16:12:18:5 | block scope | -| parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | parameters.rb:16:12:18:5 | block scope | | parameters.rb:17:13:17:15 | key | parameters.rb:16:16:16:18 | key | parameters.rb:16:12:18:5 | block scope | | parameters.rb:17:22:17:26 | value | parameters.rb:16:21:16:25 | value | parameters.rb:16:12:18:5 | block scope | -| parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | parameters.rb:21:1:23:3 | method scope | | parameters.rb:22:3:22:7 | block | parameters.rb:21:17:21:21 | block | parameters.rb:21:1:23:3 | method scope | -| parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:1:28:3 | method scope | -| parameters.rb:25:33:25:36 | size | parameters.rb:25:33:25:36 | size | parameters.rb:25:1:28:3 | method scope | | parameters.rb:25:40:25:43 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:1:28:3 | method scope | | parameters.rb:26:8:26:11 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:1:28:3 | method scope | | parameters.rb:27:8:27:11 | size | parameters.rb:25:33:25:36 | size | parameters.rb:25:1:28:3 | method scope | -| parameters.rb:30:15:30:19 | first | parameters.rb:30:15:30:19 | first | parameters.rb:30:1:32:3 | method scope | -| parameters.rb:30:24:30:29 | middle | parameters.rb:30:24:30:29 | middle | parameters.rb:30:1:32:3 | method scope | -| parameters.rb:30:36:30:39 | last | parameters.rb:30:36:30:39 | last | parameters.rb:30:1:32:3 | method scope | | parameters.rb:31:11:31:15 | first | parameters.rb:30:15:30:19 | first | parameters.rb:30:1:32:3 | method scope | | parameters.rb:31:20:31:25 | middle | parameters.rb:30:24:30:29 | middle | parameters.rb:30:1:32:3 | method scope | | parameters.rb:31:30:31:33 | last | parameters.rb:30:36:30:39 | last | parameters.rb:30:1:32:3 | method scope | -| parameters.rb:34:1:34:1 | b | parameters.rb:34:1:34:1 | b | parameters.rb:1:1:58:1 | top-level scope | -| parameters.rb:35:11:35:11 | a | parameters.rb:35:11:35:11 | a | parameters.rb:35:1:38:3 | method scope | -| parameters.rb:35:16:35:16 | b | parameters.rb:35:16:35:16 | b | parameters.rb:35:1:38:3 | method scope | | parameters.rb:37:11:37:11 | a | parameters.rb:35:11:35:11 | a | parameters.rb:35:1:38:3 | method scope | | parameters.rb:37:16:37:16 | b | parameters.rb:35:16:35:16 | b | parameters.rb:35:1:38:3 | method scope | -| parameters.rb:40:12:40:12 | d | parameters.rb:40:12:40:12 | d | parameters.rb:40:1:43:3 | method scope | -| parameters.rb:40:15:40:15 | e | parameters.rb:40:15:40:15 | e | parameters.rb:40:1:43:3 | method scope | | parameters.rb:42:11:42:11 | d | parameters.rb:40:12:40:12 | d | parameters.rb:40:1:43:3 | method scope | | parameters.rb:42:16:42:16 | e | parameters.rb:40:15:40:15 | e | parameters.rb:40:1:43:3 | method scope | -| parameters.rb:45:20:45:20 | _ | parameters.rb:45:20:45:20 | _ | parameters.rb:45:1:47:3 | method scope | | parameters.rb:45:22:45:22 | _ | parameters.rb:45:20:45:20 | _ | parameters.rb:45:1:47:3 | method scope | | parameters.rb:46:8:46:8 | _ | parameters.rb:45:20:45:20 | _ | parameters.rb:45:1:47:3 | method scope | -| parameters.rb:49:13:49:13 | a | parameters.rb:49:13:49:13 | a | parameters.rb:49:1:51:3 | method scope | -| parameters.rb:49:15:49:15 | b | parameters.rb:49:15:49:15 | b | parameters.rb:49:1:51:3 | method scope | +| parameters.rb:46:8:46:8 | _ | parameters.rb:45:22:45:22 | _ | parameters.rb:45:1:47:3 | method scope | | parameters.rb:50:11:50:11 | a | parameters.rb:49:13:49:13 | a | parameters.rb:49:1:51:3 | method scope | | parameters.rb:50:16:50:16 | b | parameters.rb:49:15:49:15 | b | parameters.rb:49:1:51:3 | method scope | -| parameters.rb:53:1:53:1 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:58:1 | top-level scope | -| parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y | parameters.rb:54:9:57:3 | block scope | | parameters.rb:54:19:54:19 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:58:1 | top-level scope | | parameters.rb:55:9:55:9 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:58:1 | top-level scope | | parameters.rb:56:9:56:9 | y | parameters.rb:54:14:54:14 | y | parameters.rb:54:9:57:3 | block scope | -| scopes.rb:2:14:2:14 | x | scopes.rb:2:14:2:14 | x | scopes.rb:2:9:6:3 | block scope | -| scopes.rb:4:4:4:4 | a | scopes.rb:4:4:4:4 | a | scopes.rb:2:9:6:3 | block scope | | scopes.rb:5:9:5:9 | a | scopes.rb:4:4:4:4 | a | scopes.rb:2:9:6:3 | block scope | -| scopes.rb:7:1:7:1 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:13:3 | top-level scope | -| scopes.rb:8:6:8:6 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:13:3 | top-level scope | -| scopes.rb:9:14:9:14 | x | scopes.rb:9:14:9:14 | x | scopes.rb:9:9:13:3 | block scope | -| scopes.rb:10:9:10:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:13:3 | top-level scope | -| scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:13:3 | top-level scope | -| scopes.rb:12:9:12:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:13:3 | top-level scope | -parameterAccess -| nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:19:20:13 | block scope | -| nested_scopes.rb:16:13:16:13 | a | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:19:20:13 | block scope | -| nested_scopes.rb:16:26:16:26 | x | nested_scopes.rb:16:26:16:26 | x | nested_scopes.rb:16:21:19:15 | block scope | -| nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:21:19:15 | block scope | -| nested_scopes.rb:17:15:17:15 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:21:19:15 | block scope | -| nested_scopes.rb:18:15:18:15 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:21:19:15 | block scope | -| nested_scopes.rb:18:26:18:26 | x | nested_scopes.rb:18:26:18:26 | x | nested_scopes.rb:18:23:18:36 | block scope | -| nested_scopes.rb:18:34:18:34 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:21:19:15 | block scope | -| nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:9:24:11 | method scope | -| nested_scopes.rb:23:16:23:16 | a | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:9:24:11 | method scope | -| parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | parameters.rb:1:9:5:3 | block scope | -| parameters.rb:1:18:1:18 | y | parameters.rb:1:18:1:18 | y | parameters.rb:1:9:5:3 | block scope | -| parameters.rb:2:4:2:4 | y | parameters.rb:1:18:1:18 | y | parameters.rb:1:9:5:3 | block scope | -| parameters.rb:3:9:3:9 | x | parameters.rb:1:14:1:14 | x | parameters.rb:1:9:5:3 | block scope | -| parameters.rb:4:9:4:9 | y | parameters.rb:1:18:1:18 | y | parameters.rb:1:9:5:3 | block scope | -| parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:7:1:13:3 | method scope | -| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:1:13:3 | method scope | -| parameters.rb:8:6:8:11 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:1:13:3 | method scope | -| parameters.rb:9:25:9:30 | client | parameters.rb:7:17:7:22 | client | parameters.rb:7:1:13:3 | method scope | -| parameters.rb:11:14:11:19 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:1:13:3 | method scope | -| parameters.rb:11:41:11:46 | client | parameters.rb:7:17:7:22 | client | parameters.rb:7:1:13:3 | method scope | -| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | parameters.rb:15:1:19:3 | method scope | -| parameters.rb:16:3:16:5 | map | parameters.rb:15:17:15:19 | map | parameters.rb:15:1:19:3 | method scope | -| parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | parameters.rb:16:12:18:5 | block scope | -| parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | parameters.rb:16:12:18:5 | block scope | -| parameters.rb:17:13:17:15 | key | parameters.rb:16:16:16:18 | key | parameters.rb:16:12:18:5 | block scope | -| parameters.rb:17:22:17:26 | value | parameters.rb:16:21:16:25 | value | parameters.rb:16:12:18:5 | block scope | -| parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | parameters.rb:21:1:23:3 | method scope | -| parameters.rb:22:3:22:7 | block | parameters.rb:21:17:21:21 | block | parameters.rb:21:1:23:3 | method scope | -| parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:1:28:3 | method scope | -| parameters.rb:25:33:25:36 | size | parameters.rb:25:33:25:36 | size | parameters.rb:25:1:28:3 | method scope | -| parameters.rb:25:40:25:43 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:1:28:3 | method scope | -| parameters.rb:26:8:26:11 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:1:28:3 | method scope | -| parameters.rb:27:8:27:11 | size | parameters.rb:25:33:25:36 | size | parameters.rb:25:1:28:3 | method scope | -| parameters.rb:30:15:30:19 | first | parameters.rb:30:15:30:19 | first | parameters.rb:30:1:32:3 | method scope | -| parameters.rb:30:24:30:29 | middle | parameters.rb:30:24:30:29 | middle | parameters.rb:30:1:32:3 | method scope | -| parameters.rb:30:36:30:39 | last | parameters.rb:30:36:30:39 | last | parameters.rb:30:1:32:3 | method scope | -| parameters.rb:31:11:31:15 | first | parameters.rb:30:15:30:19 | first | parameters.rb:30:1:32:3 | method scope | -| parameters.rb:31:20:31:25 | middle | parameters.rb:30:24:30:29 | middle | parameters.rb:30:1:32:3 | method scope | -| parameters.rb:31:30:31:33 | last | parameters.rb:30:36:30:39 | last | parameters.rb:30:1:32:3 | method scope | -| parameters.rb:35:11:35:11 | a | parameters.rb:35:11:35:11 | a | parameters.rb:35:1:38:3 | method scope | -| parameters.rb:37:11:37:11 | a | parameters.rb:35:11:35:11 | a | parameters.rb:35:1:38:3 | method scope | -| parameters.rb:40:12:40:12 | d | parameters.rb:40:12:40:12 | d | parameters.rb:40:1:43:3 | method scope | -| parameters.rb:42:11:42:11 | d | parameters.rb:40:12:40:12 | d | parameters.rb:40:1:43:3 | method scope | -| parameters.rb:45:20:45:20 | _ | parameters.rb:45:20:45:20 | _ | parameters.rb:45:1:47:3 | method scope | -| parameters.rb:45:22:45:22 | _ | parameters.rb:45:20:45:20 | _ | parameters.rb:45:1:47:3 | method scope | -| parameters.rb:46:8:46:8 | _ | parameters.rb:45:20:45:20 | _ | parameters.rb:45:1:47:3 | method scope | -| parameters.rb:49:13:49:13 | a | parameters.rb:49:13:49:13 | a | parameters.rb:49:1:51:3 | method scope | -| parameters.rb:49:15:49:15 | b | parameters.rb:49:15:49:15 | b | parameters.rb:49:1:51:3 | method scope | -| parameters.rb:50:11:50:11 | a | parameters.rb:49:13:49:13 | a | parameters.rb:49:1:51:3 | method scope | -| parameters.rb:50:16:50:16 | b | parameters.rb:49:15:49:15 | b | parameters.rb:49:1:51:3 | method scope | -| parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y | parameters.rb:54:9:57:3 | block scope | -| parameters.rb:56:9:56:9 | y | parameters.rb:54:14:54:14 | y | parameters.rb:54:9:57:3 | block scope | -| scopes.rb:2:14:2:14 | x | scopes.rb:2:14:2:14 | x | scopes.rb:2:9:6:3 | block scope | -| scopes.rb:9:14:9:14 | x | scopes.rb:9:14:9:14 | x | scopes.rb:9:9:13:3 | block scope | -localVariableAccess -| nested_scopes.rb:5:3:5:3 | a | nested_scopes.rb:5:3:5:3 | a | nested_scopes.rb:4:1:39:3 | class scope | -| nested_scopes.rb:7:5:7:5 | a | nested_scopes.rb:7:5:7:5 | a | nested_scopes.rb:6:3:37:5 | module scope | -| nested_scopes.rb:9:7:9:7 | a | nested_scopes.rb:9:7:9:7 | a | nested_scopes.rb:8:5:35:7 | module scope | -| nested_scopes.rb:11:9:11:9 | a | nested_scopes.rb:11:9:11:9 | a | nested_scopes.rb:10:7:26:9 | class scope | -| nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:12:9:21:11 | method scope | -| nested_scopes.rb:14:16:14:16 | a | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:12:9:21:11 | method scope | -| nested_scopes.rb:15:11:15:11 | a | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:12:9:21:11 | method scope | -| nested_scopes.rb:25:14:25:14 | a | nested_scopes.rb:11:9:11:9 | a | nested_scopes.rb:10:7:26:9 | class scope | -| nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:30:7:33:9 | class scope | -| nested_scopes.rb:32:16:32:16 | a | nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:30:7:33:9 | class scope | -| nested_scopes.rb:34:12:34:12 | a | nested_scopes.rb:9:7:9:7 | a | nested_scopes.rb:8:5:35:7 | module scope | -| nested_scopes.rb:36:10:36:10 | a | nested_scopes.rb:7:5:7:5 | a | nested_scopes.rb:6:3:37:5 | module scope | -| nested_scopes.rb:38:8:38:8 | a | nested_scopes.rb:5:3:5:3 | a | nested_scopes.rb:4:1:39:3 | class scope | -| nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:1:1:42:1 | top-level scope | -| nested_scopes.rb:41:1:41:1 | d | nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:1:1:42:1 | top-level scope | -| parameters.rb:34:1:34:1 | b | parameters.rb:34:1:34:1 | b | parameters.rb:1:1:58:1 | top-level scope | -| parameters.rb:35:16:35:16 | b | parameters.rb:35:16:35:16 | b | parameters.rb:35:1:38:3 | method scope | -| parameters.rb:37:16:37:16 | b | parameters.rb:35:16:35:16 | b | parameters.rb:35:1:38:3 | method scope | -| parameters.rb:40:15:40:15 | e | parameters.rb:40:15:40:15 | e | parameters.rb:40:1:43:3 | method scope | -| parameters.rb:42:16:42:16 | e | parameters.rb:40:15:40:15 | e | parameters.rb:40:1:43:3 | method scope | -| parameters.rb:53:1:53:1 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:58:1 | top-level scope | -| parameters.rb:54:19:54:19 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:58:1 | top-level scope | -| parameters.rb:55:9:55:9 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:58:1 | top-level scope | -| scopes.rb:4:4:4:4 | a | scopes.rb:4:4:4:4 | a | scopes.rb:2:9:6:3 | block scope | -| scopes.rb:5:9:5:9 | a | scopes.rb:4:4:4:4 | a | scopes.rb:2:9:6:3 | block scope | -| scopes.rb:7:1:7:1 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:13:3 | top-level scope | -| scopes.rb:8:6:8:6 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:13:3 | top-level scope | -| scopes.rb:10:9:10:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:13:3 | top-level scope | -| scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:13:3 | top-level scope | -| scopes.rb:12:9:12:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:13:3 | top-level scope | +| scopes.rb:8:6:8:6 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:18:3 | top-level scope | +| scopes.rb:10:9:10:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:18:3 | top-level scope | +| scopes.rb:11:4:11:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:18:3 | top-level scope | +| scopes.rb:12:9:12:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:18:3 | top-level scope | +| scopes.rb:13:4:13:4 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:18:3 | top-level scope | +| scopes.rb:14:9:14:9 | a | scopes.rb:7:1:7:1 | a | scopes.rb:1:1:18:3 | top-level scope | +| scopes.rb:15:9:15:9 | b | scopes.rb:13:7:13:7 | b | scopes.rb:9:9:18:3 | block scope | +| scopes.rb:16:9:16:9 | c | scopes.rb:13:11:13:11 | c | scopes.rb:9:9:18:3 | block scope | +| scopes.rb:17:9:17:9 | d | scopes.rb:13:14:13:14 | d | scopes.rb:9:9:18:3 | block scope | diff --git a/ql/test/library-tests/variables/varaccess.ql b/ql/test/library-tests/variables/varaccess.ql index 2c62bc563a30..112829104615 100644 --- a/ql/test/library-tests/variables/varaccess.ql +++ b/ql/test/library-tests/variables/varaccess.ql @@ -4,16 +4,3 @@ query predicate variableAccess(VariableAccess access, Variable variable, Variabl variable = access.getVariable() and scope = variable.getDeclaringScope() } - -query predicate parameterAccess(ParameterAccess access, LocalVariable variable, VariableScope scope) { - variable = access.getVariable() and - scope = variable.getDeclaringScope() -} - -query predicate localVariableAccess( - VariableAccess access, LocalVariable variable, VariableScope scope -) { - not access instanceof ParameterAccess and - variable = access.getVariable() and - scope = variable.getDeclaringScope() -} diff --git a/ql/test/library-tests/variables/variable.expected b/ql/test/library-tests/variables/variable.expected index a9b283555f7a..711969685657 100644 --- a/ql/test/library-tests/variables/variable.expected +++ b/ql/test/library-tests/variables/variable.expected @@ -1,4 +1,3 @@ -variable | nested_scopes.rb:5:3:5:3 | a | | nested_scopes.rb:7:5:7:5 | a | | nested_scopes.rb:9:7:9:7 | a | @@ -30,6 +29,7 @@ variable | parameters.rb:40:12:40:12 | d | | parameters.rb:40:15:40:15 | e | | parameters.rb:45:20:45:20 | _ | +| parameters.rb:45:22:45:22 | _ | | parameters.rb:49:13:49:13 | a | | parameters.rb:49:15:49:15 | b | | parameters.rb:53:1:53:1 | x | @@ -38,44 +38,6 @@ variable | scopes.rb:4:4:4:4 | a | | scopes.rb:7:1:7:1 | a | | scopes.rb:9:14:9:14 | x | -parameter -| nested_scopes.rb:15:23:15:23 | a | -| nested_scopes.rb:16:26:16:26 | x | -| nested_scopes.rb:16:29:16:29 | a | -| nested_scopes.rb:18:26:18:26 | x | -| nested_scopes.rb:22:21:22:21 | a | -| parameters.rb:1:14:1:14 | x | -| parameters.rb:1:18:1:18 | y | -| parameters.rb:7:17:7:22 | client | -| parameters.rb:7:26:7:31 | pizzas | -| parameters.rb:15:17:15:19 | map | -| parameters.rb:16:16:16:18 | key | -| parameters.rb:16:21:16:25 | value | -| parameters.rb:21:17:21:21 | block | -| parameters.rb:25:15:25:18 | name | -| parameters.rb:25:33:25:36 | size | -| parameters.rb:30:15:30:19 | first | -| parameters.rb:30:24:30:29 | middle | -| parameters.rb:30:36:30:39 | last | -| parameters.rb:35:11:35:11 | a | -| parameters.rb:40:12:40:12 | d | -| parameters.rb:45:20:45:20 | _ | -| parameters.rb:49:13:49:13 | a | -| parameters.rb:49:15:49:15 | b | -| parameters.rb:54:14:54:14 | y | -| scopes.rb:2:14:2:14 | x | -| scopes.rb:9:14:9:14 | x | -localVariable -| nested_scopes.rb:5:3:5:3 | a | -| nested_scopes.rb:7:5:7:5 | a | -| nested_scopes.rb:9:7:9:7 | a | -| nested_scopes.rb:11:9:11:9 | a | -| nested_scopes.rb:13:11:13:11 | a | -| nested_scopes.rb:31:11:31:11 | a | -| nested_scopes.rb:40:1:40:1 | d | -| parameters.rb:34:1:34:1 | b | -| parameters.rb:35:16:35:16 | b | -| parameters.rb:40:15:40:15 | e | -| parameters.rb:53:1:53:1 | x | -| scopes.rb:4:4:4:4 | a | -| scopes.rb:7:1:7:1 | a | +| scopes.rb:13:7:13:7 | b | +| scopes.rb:13:11:13:11 | c | +| scopes.rb:13:14:13:14 | d | diff --git a/ql/test/library-tests/variables/variable.ql b/ql/test/library-tests/variables/variable.ql index e63cb8ffeb19..32812d7d856f 100644 --- a/ql/test/library-tests/variables/variable.ql +++ b/ql/test/library-tests/variables/variable.ql @@ -1,7 +1,3 @@ import codeql_ruby.ast.Variable query predicate variable(Variable v) { any() } - -query predicate parameter(LocalVariable v) { v.getAnAccess() instanceof ParameterAccess } - -query predicate localVariable(LocalVariable v) { not v.getAnAccess() instanceof ParameterAccess } diff --git a/ql/test/library-tests/variables/varscopes.expected b/ql/test/library-tests/variables/varscopes.expected index 7a09f5981832..70c2d9283cf8 100644 --- a/ql/test/library-tests/variables/varscopes.expected +++ b/ql/test/library-tests/variables/varscopes.expected @@ -25,6 +25,6 @@ | parameters.rb:49:1:51:3 | method scope | | parameters.rb:54:9:57:3 | block scope | | scopes.rb:1:1:1:15 | method scope | -| scopes.rb:1:1:13:3 | top-level scope | +| scopes.rb:1:1:18:3 | top-level scope | | scopes.rb:2:9:6:3 | block scope | -| scopes.rb:9:9:13:3 | block scope | +| scopes.rb:9:9:18:3 | block scope | From c0dd89122c576354cf2374afb23c32e3295550b9 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Sat, 28 Nov 2020 19:23:08 +0100 Subject: [PATCH 7/8] Handle parameters with overlapping names --- ql/src/codeql_ruby/ast/internal/Variable.qll | 18 +++++++++++++++--- .../library-tests/variables/parameter.expected | 4 +--- .../library-tests/variables/varaccess.expected | 1 - .../library-tests/variables/variable.expected | 1 - 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/ql/src/codeql_ruby/ast/internal/Variable.qll b/ql/src/codeql_ruby/ast/internal/Variable.qll index 8cbda5c70b86..c0975cdad291 100644 --- a/ql/src/codeql_ruby/ast/internal/Variable.qll +++ b/ql/src/codeql_ruby/ast/internal/Variable.qll @@ -13,13 +13,25 @@ private VariableScope enclosingScope(Generated::AstNode node) { result.getScopeElement() = parent*(node.getParent()) } +private predicate parameterAssignment(CallableScope scope, string name, Generated::Identifier i) { + assignment(i, true) and + scope = enclosingScope(i) and + name = i.getValue() +} + /** Holds if `scope` defines `name` in its parameter declaration at `i`. */ private predicate scopeDefinesParameterVariable( CallableScope scope, string name, Generated::Identifier i ) { - assignment(i, true) and - scope = enclosingScope(i) and - name = i.getValue() + parameterAssignment(scope, name, i) and + // In case of overlapping parameter names (e.g. `_`), only the first + // parameter will give rise to a variable + i = + min(Generated::Identifier other | + parameterAssignment(scope, name, other) + | + other order by other.getLocation().getStartLine(), other.getLocation().getStartColumn() + ) or exists(Parameter p | p = scope.getScopeElement().getAParameter() and diff --git a/ql/test/library-tests/variables/parameter.expected b/ql/test/library-tests/variables/parameter.expected index 1a881a81b788..938423399317 100644 --- a/ql/test/library-tests/variables/parameter.expected +++ b/ql/test/library-tests/variables/parameter.expected @@ -18,12 +18,10 @@ parameter | parameters.rb:35:11:35:21 | a | parameters.rb:35:11:35:11 | a | | parameters.rb:40:12:40:19 | d | parameters.rb:40:12:40:12 | d | | parameters.rb:45:20:45:20 | _ | parameters.rb:45:20:45:20 | _ | -| parameters.rb:45:20:45:20 | _ | parameters.rb:45:22:45:22 | _ | -| parameters.rb:45:22:45:22 | _ | parameters.rb:45:20:45:20 | _ | -| parameters.rb:45:22:45:22 | _ | parameters.rb:45:22:45:22 | _ | | parameters.rb:54:14:54:24 | y | parameters.rb:54:14:54:14 | y | parameterNoAcess | nested_scopes.rb:16:26:16:26 | x | | nested_scopes.rb:18:26:18:26 | x | +| parameters.rb:45:22:45:22 | _ | | scopes.rb:2:14:2:14 | x | | scopes.rb:9:14:9:14 | x | diff --git a/ql/test/library-tests/variables/varaccess.expected b/ql/test/library-tests/variables/varaccess.expected index 3b076a124e2e..eda09d402faa 100644 --- a/ql/test/library-tests/variables/varaccess.expected +++ b/ql/test/library-tests/variables/varaccess.expected @@ -34,7 +34,6 @@ | parameters.rb:42:16:42:16 | e | parameters.rb:40:15:40:15 | e | parameters.rb:40:1:43:3 | method scope | | parameters.rb:45:22:45:22 | _ | parameters.rb:45:20:45:20 | _ | parameters.rb:45:1:47:3 | method scope | | parameters.rb:46:8:46:8 | _ | parameters.rb:45:20:45:20 | _ | parameters.rb:45:1:47:3 | method scope | -| parameters.rb:46:8:46:8 | _ | parameters.rb:45:22:45:22 | _ | parameters.rb:45:1:47:3 | method scope | | parameters.rb:50:11:50:11 | a | parameters.rb:49:13:49:13 | a | parameters.rb:49:1:51:3 | method scope | | parameters.rb:50:16:50:16 | b | parameters.rb:49:15:49:15 | b | parameters.rb:49:1:51:3 | method scope | | parameters.rb:54:19:54:19 | x | parameters.rb:53:1:53:1 | x | parameters.rb:1:1:58:1 | top-level scope | diff --git a/ql/test/library-tests/variables/variable.expected b/ql/test/library-tests/variables/variable.expected index 711969685657..143f5d2639a8 100644 --- a/ql/test/library-tests/variables/variable.expected +++ b/ql/test/library-tests/variables/variable.expected @@ -29,7 +29,6 @@ | parameters.rb:40:12:40:12 | d | | parameters.rb:40:15:40:15 | e | | parameters.rb:45:20:45:20 | _ | -| parameters.rb:45:22:45:22 | _ | | parameters.rb:49:13:49:13 | a | | parameters.rb:49:15:49:15 | b | | parameters.rb:53:1:53:1 | x | From baf29ae56b6a59dfc8838f177f339ff92cb684a2 Mon Sep 17 00:00:00 2001 From: Nick Rolfe Date: Mon, 30 Nov 2020 13:42:02 +0000 Subject: [PATCH 8/8] Add qldoc comment and isOptional predicate to KeywordParameter --- ql/src/codeql_ruby/ast/Parameter.qll | 16 +++++++++++++++- ql/test/library-tests/ast/params/params.ql | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/ql/src/codeql_ruby/ast/Parameter.qll b/ql/src/codeql_ruby/ast/Parameter.qll index f870a62d7f39..af7748d504ad 100644 --- a/ql/src/codeql_ruby/ast/Parameter.qll +++ b/ql/src/codeql_ruby/ast/Parameter.qll @@ -108,7 +108,15 @@ class HashSplatParameter extends @hash_splat_parameter, NamedParameter { } /** - * TODO + * A keyword parameter, including a default value if the parameter is optional. + * For example, in the following example, `foo` is a keyword parameter with a + * default value of `0`, and `bar` is a mandatory keyword parameter with no + * default value mandatory parameter). + * ```rb + * def f(foo: 0, bar:) + * foo * 10 + bar + * end + * ``` */ class KeywordParameter extends @keyword_parameter, NamedParameter { override Generated::KeywordParameter generated; @@ -127,6 +135,12 @@ class KeywordParameter extends @keyword_parameter, NamedParameter { */ AstNode getDefaultValue() { result = generated.getValue() } + /** + * Holds if the parameter is optional. That is, there is a default value that + * is used when the caller omits this parameter. + */ + predicate isOptional() { exists(this.getDefaultValue()) } + override string toString() { result = this.getName() } } diff --git a/ql/test/library-tests/ast/params/params.ql b/ql/test/library-tests/ast/params/params.ql index 0ae480f01007..77394ff3a4c9 100644 --- a/ql/test/library-tests/ast/params/params.ql +++ b/ql/test/library-tests/ast/params/params.ql @@ -16,7 +16,7 @@ query predicate hashSplatParams(HashSplatParameter hsp, string name) { name = hs query predicate keywordParams(KeywordParameter kp, string name, string defaultValueStr) { name = kp.getName() and - if exists(kp.getDefaultValue()) + if kp.isOptional() then defaultValueStr = kp.getDefaultValue().toString() else defaultValueStr = "(none)" }