diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9cf9474f24d..875f0a2e5c7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,12 +28,17 @@ jobs: run: cargo build --release - name: Generate dbscheme if: ${{ matrix.os == 'ubuntu-latest' }} - run: target/release/generator + run: target/release/ruby-generator - uses: actions/upload-artifact@v2 if: ${{ matrix.os == 'ubuntu-latest' }} with: name: ruby.dbscheme path: ruby.dbscheme + - uses: actions/upload-artifact@v2 + if: ${{ matrix.os == 'ubuntu-latest' }} + with: + name: ruby_ast.qll + path: ruby_ast.qll - uses: actions/upload-artifact@v2 with: name: extractor-${{ matrix.os }} diff --git a/Cargo.lock b/Cargo.lock index dcee32f598f..61c02ba2aa2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,16 +96,6 @@ dependencies = [ "vec_map", ] -[[package]] -name = "generator" -version = "0.1.0" -dependencies = [ - "node-types", - "tracing", - "tracing-subscriber", - "tree-sitter-ruby", -] - [[package]] name = "generator" version = "0.6.23" @@ -142,9 +132,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" +checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" [[package]] name = "log" @@ -162,7 +152,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0e8460f2f2121162705187214720353c517b97bdfb3494c0b1e33d83ebe4bed" dependencies = [ "cfg-if", - "generator 0.6.23", + "generator", "scoped-tls", "serde", "serde_json", @@ -274,6 +264,16 @@ dependencies = [ "tree-sitter-ruby", ] +[[package]] +name = "ruby-generator" +version = "0.1.0" +dependencies = [ + "node-types", + "tracing", + "tracing-subscriber", + "tree-sitter-ruby", +] + [[package]] name = "rustc_version" version = "0.2.3" @@ -365,9 +365,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "syn" -version = "1.0.46" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad5de3220ea04da322618ded2c42233d02baca219d6f160a3e9c87cda16c942" +checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac" dependencies = [ "proc-macro2", "quote", diff --git a/README.md b/README.md index efd22e31736..ee7cc63e1b3 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,22 @@ # Ruby analysis support for CodeQL -Under development. \ No newline at end of file +Under development. + +## Building the tools from source + +[Install Rust](https://www.rust-lang.org/tools/install), then run: + +```bash +cargo build --release +``` + +## Generating the database schema and QL library + +The generated `ruby.dbscheme` and `ruby_ast.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 ruby_ast.qll +``` diff --git a/extractor/src/extractor.rs b/extractor/src/extractor.rs index 7aae963d139..60d995ceed2 100644 --- a/extractor/src/extractor.rs +++ b/extractor/src/extractor.rs @@ -225,10 +225,7 @@ impl Visitor<'_> { "too many values" }, node.kind(), - match field.name.as_ref() { - Some(x) => x, - None => "child", - } + &field.get_name() ) } } @@ -237,10 +234,7 @@ impl Visitor<'_> { self.trap_output.push(TrapEntry::ChildOf( node_type_name(&field.parent.kind, field.parent.named), parent_id, - match &field.name { - Some(name) => name.to_owned(), - None => "child".to_owned(), - }, + field.get_name(), Index(index), *child_id, )); diff --git a/generator/Cargo.toml b/generator/Cargo.toml index 32ef3ac4a03..0615ffeab3d 100644 --- a/generator/Cargo.toml +++ b/generator/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "generator" +name = "ruby-generator" version = "0.1.0" authors = ["GitHub"] edition = "2018" diff --git a/generator/src/dbscheme.rs b/generator/src/dbscheme.rs index fc5d5e1eda9..88b06400418 100644 --- a/generator/src/dbscheme.rs +++ b/generator/src/dbscheme.rs @@ -1,3 +1,4 @@ +use crate::ql; use std::fmt; /// Represents a distinct entry in the database schema. @@ -27,7 +28,7 @@ pub struct Column { pub db_type: DbColumnType, pub name: String, pub unique: bool, - pub ql_type: QlColumnType, + pub ql_type: ql::Type, pub ql_type_is_ref: bool, } @@ -37,18 +38,6 @@ pub enum DbColumnType { String, } -// The QL type of a column. -pub enum QlColumnType { - /// Primitive `int` type. - Int, - - /// Primitive `string` type. - String, - - /// A custom type, defined elsewhere by a table or union. - Custom(String), -} - impl fmt::Display for Table { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if let Some(keyset) = &self.keysets { @@ -76,12 +65,7 @@ impl fmt::Display for Table { DbColumnType::String => "string", } )?; - write!(f, "{}: ", column.name)?; - match &column.ql_type { - QlColumnType::Int => write!(f, "int")?, - QlColumnType::String => write!(f, "string")?, - QlColumnType::Custom(name) => write!(f, "@{}", name)?, - } + write!(f, "{}: {}", column.name, column.ql_type)?; if column.ql_type_is_ref { write!(f, " ref")?; } diff --git a/generator/src/language.rs b/generator/src/language.rs index c98c089a800..4e2f985a21c 100644 --- a/generator/src/language.rs +++ b/generator/src/language.rs @@ -4,4 +4,5 @@ pub struct Language { pub name: String, pub node_types: &'static str, pub dbscheme_path: PathBuf, + pub ql_library_path: PathBuf, } diff --git a/generator/src/main.rs b/generator/src/main.rs index 3861a6cd665..cb7d7457ae8 100644 --- a/generator/src/main.rs +++ b/generator/src/main.rs @@ -1,8 +1,9 @@ mod dbscheme; mod language; +mod ql; +mod ql_gen; use language::Language; -use node_types; use std::collections::BTreeSet as Set; use std::fs::File; use std::io::LineWriter; @@ -27,13 +28,10 @@ fn make_field_type( // type to represent them. let field_union_name = format!("{}_{}_type", parent_name, field_name); let field_union_name = node_types::escape_name(&field_union_name); - let mut members: Vec = Vec::new(); - for field_type in types { - members.push(node_types::escape_name(&node_types::node_type_name( - &field_type.kind, - field_type.named, - ))); - } + let members: Vec = types + .iter() + .map(|t| node_types::escape_name(&node_types::node_type_name(&t.kind, t.named))) + .collect(); entries.push(dbscheme::Entry::Union(dbscheme::Union { name: field_union_name.clone(), members, @@ -49,10 +47,7 @@ fn add_field( field: &node_types::Field, entries: &mut Vec, ) { - let field_name = match &field.name { - None => "child".to_owned(), - Some(x) => x.to_owned(), - }; + let field_name = field.get_name(); let parent_name = node_types::node_type_name(&field.parent.kind, field.parent.named); match field.storage { node_types::Storage::Table { .. } => { @@ -67,9 +62,7 @@ fn add_field( unique: false, db_type: dbscheme::DbColumnType::Int, name: node_types::escape_name(&parent_name), - ql_type: dbscheme::QlColumnType::Custom(node_types::escape_name( - &parent_name, - )), + ql_type: ql::Type::AtType(node_types::escape_name(&parent_name)), ql_type_is_ref: true, }, // Then an index column. @@ -77,7 +70,7 @@ fn add_field( unique: false, db_type: dbscheme::DbColumnType::Int, name: "index".to_string(), - ql_type: dbscheme::QlColumnType::Int, + ql_type: ql::Type::Int, ql_type_is_ref: true, }, // And then the field @@ -85,7 +78,7 @@ fn add_field( unique: true, db_type: dbscheme::DbColumnType::Int, name: node_types::escape_name(&field_type), - ql_type: dbscheme::QlColumnType::Custom(field_type), + ql_type: ql::Type::AtType(field_type), ql_type_is_ref: true, }, ], @@ -106,7 +99,7 @@ fn add_field( unique: false, db_type: dbscheme::DbColumnType::Int, name: node_types::escape_name(&field_name), - ql_type: dbscheme::QlColumnType::Custom(field_type), + ql_type: ql::Type::AtType(field_type), ql_type_is_ref: true, }); } @@ -115,7 +108,10 @@ fn add_field( /// Converts the given tree-sitter node types into CodeQL dbscheme entries. fn convert_nodes(nodes: &Vec) -> Vec { - let mut entries: Vec = Vec::new(); + let mut entries: Vec = vec![ + create_location_table(), + create_source_location_prefix_table(), + ]; let mut top_members: Vec = Vec::new(); for node in nodes { @@ -150,7 +146,7 @@ fn convert_nodes(nodes: &Vec) -> Vec { db_type: dbscheme::DbColumnType::Int, name: "id".to_string(), unique: true, - ql_type: dbscheme::QlColumnType::Custom(node_types::escape_name(&name)), + ql_type: ql::Type::AtType(node_types::escape_name(&name)), ql_type_is_ref: false, }], keysets: None, @@ -170,7 +166,7 @@ fn convert_nodes(nodes: &Vec) -> Vec { unique: false, db_type: dbscheme::DbColumnType::String, name: "text".to_string(), - ql_type: dbscheme::QlColumnType::String, + ql_type: ql::Type::String, ql_type_is_ref: true, }); } @@ -180,7 +176,7 @@ fn convert_nodes(nodes: &Vec) -> Vec { unique: false, db_type: dbscheme::DbColumnType::Int, name: "loc".to_string(), - ql_type: dbscheme::QlColumnType::Custom("location".to_string()), + ql_type: ql::Type::AtType("location".to_string()), ql_type_is_ref: true, }); @@ -200,7 +196,8 @@ fn convert_nodes(nodes: &Vec) -> Vec { fn write_dbscheme(language: &Language, entries: &[dbscheme::Entry]) -> std::io::Result<()> { info!( - "Writing to '{}'", + "Writing database schema for {} to '{}'", + &language.name, match language.dbscheme_path.to_str() { None => "", Some(p) => p, @@ -211,7 +208,7 @@ fn write_dbscheme(language: &Language, entries: &[dbscheme::Entry]) -> std::io:: dbscheme::write(&language.name, &mut file, &entries) } -fn create_location_entry() -> dbscheme::Entry { +fn create_location_table() -> dbscheme::Entry { dbscheme::Entry::Table(dbscheme::Table { name: "location".to_string(), keysets: None, @@ -220,49 +217,49 @@ fn create_location_entry() -> dbscheme::Entry { unique: true, db_type: dbscheme::DbColumnType::Int, name: "id".to_string(), - ql_type: dbscheme::QlColumnType::Custom("location".to_string()), + ql_type: ql::Type::AtType("location".to_string()), ql_type_is_ref: false, }, dbscheme::Column { unique: false, db_type: dbscheme::DbColumnType::String, name: "file_path".to_string(), - ql_type: dbscheme::QlColumnType::String, + ql_type: ql::Type::String, ql_type_is_ref: true, }, dbscheme::Column { unique: false, db_type: dbscheme::DbColumnType::Int, name: "start_line".to_string(), - ql_type: dbscheme::QlColumnType::Int, + ql_type: ql::Type::Int, ql_type_is_ref: true, }, dbscheme::Column { unique: false, db_type: dbscheme::DbColumnType::Int, name: "start_column".to_string(), - ql_type: dbscheme::QlColumnType::Int, + ql_type: ql::Type::Int, ql_type_is_ref: true, }, dbscheme::Column { unique: false, db_type: dbscheme::DbColumnType::Int, name: "end_line".to_string(), - ql_type: dbscheme::QlColumnType::Int, + ql_type: ql::Type::Int, ql_type_is_ref: true, }, dbscheme::Column { unique: false, db_type: dbscheme::DbColumnType::Int, name: "end_column".to_string(), - ql_type: dbscheme::QlColumnType::Int, + ql_type: ql::Type::Int, ql_type_is_ref: true, }, ], }) } -fn create_source_location_prefix_entry() -> dbscheme::Entry { +fn create_source_location_prefix_table() -> dbscheme::Entry { dbscheme::Entry::Table(dbscheme::Table { name: "sourceLocationPrefix".to_string(), keysets: None, @@ -270,7 +267,7 @@ fn create_source_location_prefix_entry() -> dbscheme::Entry { unique: false, db_type: dbscheme::DbColumnType::String, name: "prefix".to_string(), - ql_type: dbscheme::QlColumnType::String, + ql_type: ql::Type::String, ql_type_is_ref: true, }], }) @@ -290,6 +287,7 @@ fn main() { name: "Ruby".to_string(), node_types: tree_sitter_ruby::NODE_TYPES, dbscheme_path: PathBuf::from("ruby.dbscheme"), + ql_library_path: PathBuf::from("ruby_ast.qll"), }; match node_types::read_node_types_str(&ruby.node_types) { Err(e) => { @@ -297,15 +295,18 @@ fn main() { std::process::exit(1); } Ok(nodes) => { - let mut dbscheme_entries = convert_nodes(&nodes); - dbscheme_entries.push(create_location_entry()); - dbscheme_entries.push(create_source_location_prefix_entry()); - match write_dbscheme(&ruby, &dbscheme_entries) { - Err(e) => { - error!("Failed to write dbscheme: {}", e); - std::process::exit(2); - } - Ok(()) => {} + let dbscheme_entries = convert_nodes(&nodes); + + if let Err(e) = write_dbscheme(&ruby, &dbscheme_entries) { + error!("Failed to write dbscheme: {}", e); + std::process::exit(2); + } + + let classes = ql_gen::convert_nodes(&nodes); + + if let Err(e) = ql_gen::write(&ruby, &classes) { + println!("Failed to write QL library: {}", e); + std::process::exit(3); } } } diff --git a/generator/src/ql.rs b/generator/src/ql.rs new file mode 100644 index 00000000000..d422cde9f3a --- /dev/null +++ b/generator/src/ql.rs @@ -0,0 +1,180 @@ +use std::fmt; + +pub struct Class { + pub name: String, + pub is_abstract: bool, + pub supertypes: Vec, + pub characteristic_predicate: Option, + pub predicates: Vec, +} + +impl fmt::Display for Class { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.is_abstract { + write!(f, "abstract ")?; + } + write!(f, "class {} extends ", &self.name)?; + for (index, supertype) in self.supertypes.iter().enumerate() { + if index > 0 { + write!(f, ", ")?; + } + write!(f, "{}", supertype)?; + } + write!(f, " {{ \n")?; + + if let Some(charpred) = &self.characteristic_predicate { + write!( + f, + " {}\n", + Predicate { + name: self.name.clone(), + overridden: false, + return_type: None, + formal_parameters: vec![], + body: charpred.clone(), + } + )?; + } + + for predicate in &self.predicates { + write!(f, " {}\n", predicate)?; + } + + write!(f, "}}")?; + + Ok(()) + } +} + +// The QL type of a column. +#[derive(Clone)] +pub enum Type { + /// Primitive `int` type. + Int, + + /// Primitive `string` type. + String, + + /// A user-defined type. + Normal(String), + + /// A database type that will need to be referred to with an `@` prefix. + AtType(String), +} + +impl fmt::Display for Type { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Type::Int => write!(f, "int"), + Type::String => write!(f, "string"), + Type::Normal(name) => write!(f, "{}", name), + Type::AtType(name) => write!(f, "@{}", name), + } + } +} + +#[derive(Clone)] +pub enum Expression { + Var(String), + String(String), + Pred(String, Vec), + Or(Vec), + Equals(Box, Box), +} + +impl fmt::Display for Expression { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Expression::Var(x) => write!(f, "{}", x), + Expression::String(s) => write!(f, "\"{}\"", s), + Expression::Pred(n, args) => { + write!(f, "{}(", n)?; + for (index, arg) in args.iter().enumerate() { + if index > 0 { + write!(f, ", ")?; + } + write!(f, "{}", arg)?; + } + write!(f, ")") + } + Expression::Or(disjuncts) => { + if disjuncts.is_empty() { + write!(f, "none()") + } else { + for (index, disjunct) in disjuncts.iter().enumerate() { + if index > 0 { + write!(f, " or ")?; + } + write!(f, "{}", disjunct)?; + } + Ok(()) + } + } + Expression::Equals(a, b) => write!(f, "{} = {}", a, b), + } + } +} + +#[derive(Clone)] +pub struct Predicate { + pub name: String, + pub overridden: bool, + pub return_type: Option, + pub formal_parameters: Vec, + pub body: Expression, +} + +impl fmt::Display for Predicate { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.overridden { + write!(f, "override ")?; + } + match &self.return_type { + None => write!(f, "predicate ")?, + Some(return_type) => write!(f, "{} ", return_type)?, + } + write!(f, "{}(", self.name)?; + for (index, param) in self.formal_parameters.iter().enumerate() { + if index > 0 { + write!(f, ", ")?; + } + write!(f, "{}", param)?; + } + write!(f, ") {{ {} }}", self.body)?; + + Ok(()) + } +} + +#[derive(Clone)] +pub struct FormalParameter { + pub name: String, + pub param_type: Type, +} + +impl fmt::Display for FormalParameter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} {}", self.param_type, self.name) + } +} + +/// Generates a QL library by writing the given `classes` to the `file`. +pub fn write( + language_name: &str, + file: &mut dyn std::io::Write, + classes: &[Class], +) -> std::io::Result<()> { + write!(file, "/*\n")?; + write!(file, " * CodeQL library for {}\n", language_name)?; + write!( + file, + " * Automatically generated from the tree-sitter grammar; do not edit\n" + )?; + write!(file, " */\n\n")?; + + for class in classes { + write!(file, "{}\n\n", &class)?; + } + + Ok(()) +} diff --git a/generator/src/ql_gen.rs b/generator/src/ql_gen.rs new file mode 100644 index 00000000000..f400052e90d --- /dev/null +++ b/generator/src/ql_gen.rs @@ -0,0 +1,533 @@ +use crate::language::Language; +use crate::ql; +use std::collections::{BTreeSet, HashMap}; +use std::fs::File; +use std::io::LineWriter; + +type SupertypeMap = HashMap>; + +/// Writes the QL AST library for the given library. +/// +/// # Arguments +/// +/// `language` - the language for which we're generating a library +/// `classes` - the list of classes to write. +pub fn write(language: &Language, classes: &[ql::Class]) -> std::io::Result<()> { + println!( + "Writing QL library for {} to '{}'", + &language.name, + match language.ql_library_path.to_str() { + None => "", + Some(p) => p, + } + ); + let file = File::create(&language.ql_library_path)?; + let mut file = LineWriter::new(file); + ql::write(&language.name, &mut file, &classes) +} + +/// Creates a map from QL class names to their supertypes. +fn create_supertype_map(nodes: &[node_types::Entry]) -> SupertypeMap { + let mut map = SupertypeMap::new(); + for node in nodes { + match &node { + node_types::Entry::Union { + type_name, + members: n_members, + } => { + let supertype_class_name = dbscheme_name_to_class_name(&node_types::escape_name( + &node_types::node_type_name(&type_name.kind, type_name.named), + )); + for n_member in n_members { + let subtype_class_name = dbscheme_name_to_class_name(&node_types::escape_name( + &node_types::node_type_name(&n_member.kind, n_member.named), + )); + map.entry(subtype_class_name) + .or_insert_with(|| BTreeSet::new()) + .insert(supertype_class_name.clone()); + } + } + node_types::Entry::Table { type_name, fields } => { + let node_name = node_types::node_type_name(&type_name.kind, type_name.named); + for field in fields { + if field.types.len() != 1 { + // This field can have one of several types. Since we create an ad-hoc + // QL union type to represent them, the class wrapping that union type + // will be a supertype of all its members. + let field_union_name = format!("{}_{}_type", &node_name, &field.get_name()); + let field_union_name = node_types::escape_name(&field_union_name); + let supertype_name = dbscheme_name_to_class_name(&field_union_name); + for field_type in &field.types { + let member_name = + node_types::node_type_name(&field_type.kind, field_type.named); + let member_class_name = + dbscheme_name_to_class_name(&node_types::escape_name(&member_name)); + map.entry(member_class_name) + .or_insert_with(|| BTreeSet::new()) + .insert(supertype_name.clone()); + } + } + } + } + } + } + + map +} + +fn get_base_classes(name: &str, supertype_map: &SupertypeMap) -> Vec { + let mut base_classes: Vec = vec![ql::Type::Normal("Top".to_owned())]; + + if let Some(supertypes) = supertype_map.get(name) { + base_classes.extend( + supertypes + .into_iter() + .map(|st| ql::Type::Normal(st.clone())), + ); + } + + base_classes +} + +/// Creates the hard-coded `Top` class that acts as a supertype of all classes we +/// generate. +fn create_top_class() -> ql::Class { + let to_string = create_none_predicate("toString", false, Some(ql::Type::String), vec![]); + let get_location = create_none_predicate( + "getLocation", + false, + Some(ql::Type::Normal("Location".to_owned())), + vec![], + ); + let get_a_field_or_child = create_none_predicate( + "getAFieldOrChild", + false, + Some(ql::Type::Normal("Top".to_owned())), + vec![], + ); + ql::Class { + name: "Top".to_owned(), + is_abstract: false, + supertypes: vec![ql::Type::AtType("top".to_owned())], + characteristic_predicate: None, + predicates: vec![to_string, get_location, get_a_field_or_child], + } +} + +/// Creates a predicate whose body is `none()`. +fn create_none_predicate( + name: &str, + overridden: bool, + return_type: Option, + formal_parameters: Vec, +) -> ql::Predicate { + ql::Predicate { + name: name.to_owned(), + overridden, + return_type, + formal_parameters, + body: ql::Expression::Pred("none".to_owned(), vec![]), + } +} + +/// Creates the special `Location` class to wrap the location table. +fn create_location_class() -> ql::Class { + let to_string = ql::Predicate { + name: "toString".to_owned(), + overridden: false, + return_type: Some(ql::Type::String), + formal_parameters: vec![], + body: ql::Expression::Equals( + Box::new(ql::Expression::Var("result".to_owned())), + Box::new(ql::Expression::String("Location".to_owned())), + ), + }; + let has_location_info = ql::Predicate { + name: "hasLocationInfo".to_owned(), + overridden: false, + return_type: None, + formal_parameters: vec![ + ql::FormalParameter { + name: "filePath".to_owned(), + param_type: ql::Type::String, + }, + ql::FormalParameter { + name: "startLine".to_owned(), + param_type: ql::Type::Int, + }, + ql::FormalParameter { + name: "startColumn".to_owned(), + param_type: ql::Type::Int, + }, + ql::FormalParameter { + name: "endLine".to_owned(), + param_type: ql::Type::Int, + }, + ql::FormalParameter { + name: "endColumn".to_owned(), + param_type: ql::Type::Int, + }, + ], + body: ql::Expression::Pred( + "location".to_owned(), + vec![ + ql::Expression::Var("this".to_owned()), + ql::Expression::Var("filePath".to_owned()), + ql::Expression::Var("startLine".to_owned()), + ql::Expression::Var("startColumn".to_owned()), + ql::Expression::Var("endLine".to_owned()), + ql::Expression::Var("endColumn".to_owned()), + ], + ), + }; + ql::Class { + name: "Location".to_owned(), + supertypes: vec![ql::Type::AtType("location".to_owned())], + is_abstract: false, + characteristic_predicate: None, + predicates: vec![to_string, has_location_info], + } +} + +/// Given the name of the parent node, and its field information, returns the +/// name of the field's type. This may be an ad-hoc union of all the possible +/// types the field can take, in which case we create a new class and push it to +/// `classes`. +fn create_field_class( + parent_name: &str, + field: &node_types::Field, + classes: &mut Vec, + supertype_map: &SupertypeMap, +) -> String { + if field.types.len() == 1 { + // This field can only have a single type. + let t = field.types.iter().next().unwrap(); + node_types::escape_name(&node_types::node_type_name(&t.kind, t.named)) + } else { + // This field can have one of several types. The dbscheme contains a + // union type, so we create a QL class to wrap that. + let field_union_name = format!("{}_{}_type", parent_name, &field.get_name()); + let field_union_name = node_types::escape_name(&field_union_name); + let class_name = dbscheme_name_to_class_name(&field_union_name); + classes.push(ql::Class { + name: class_name.clone(), + is_abstract: false, + supertypes: [ + vec![ql::Type::AtType(field_union_name.clone())], + get_base_classes(&class_name, &supertype_map), + ] + .concat(), + characteristic_predicate: None, + predicates: vec![], + }); + field_union_name + } +} + +/// Given a valid dbscheme name (i.e. in snake case), produces the equivalent QL +/// name (i.e. in CamelCase). For example, "foo_bar_baz" becomes "FooBarBaz". +fn dbscheme_name_to_class_name(dbscheme_name: &str) -> String { + fn to_title_case(word: &str) -> String { + let mut first = true; + let mut result = String::new(); + for c in word.chars() { + if first { + first = false; + result.push(c.to_ascii_uppercase()); + } else { + result.push(c); + } + } + result + } + dbscheme_name + .split('_') + .map(|word| to_title_case(word)) + .collect::>() + .join("") +} + +/// Creates a `toString` predicate that returns the given text. +fn create_to_string_predicate(text: &str) -> ql::Predicate { + ql::Predicate { + name: "toString".to_owned(), + overridden: true, + return_type: Some(ql::Type::String), + formal_parameters: vec![], + body: ql::Expression::Equals( + Box::new(ql::Expression::Var("result".to_owned())), + Box::new(ql::Expression::String(text.to_owned())), + ), + } +} + +/// Creates the `getLocation` predicate. +/// +/// # Arguments +/// +/// `def_table` - the name of the table that defines the entity and its location. +/// `arity` - the total number of columns in the table +fn create_get_location_predicate(def_table: &str, arity: usize) -> ql::Predicate { + ql::Predicate { + name: "getLocation".to_owned(), + overridden: true, + return_type: Some(ql::Type::Normal("Location".to_owned())), + formal_parameters: vec![], + // body of the form: foo_bar_def(_, _, ..., result) + body: ql::Expression::Pred( + def_table.to_owned(), + [ + vec![ql::Expression::Var("this".to_owned())], + vec![ql::Expression::Var("_".to_owned()); arity - 2], + vec![ql::Expression::Var("result".to_owned())], + ] + .concat(), + ), + } +} + +/// Creates the `getText` predicate for a leaf node. +/// +/// # Arguments +/// +/// `def_table` - the name of the table that defines the entity and its text. +fn create_get_text_predicate(def_table: &str) -> ql::Predicate { + ql::Predicate { + name: "getText".to_owned(), + overridden: false, + return_type: Some(ql::Type::String), + formal_parameters: vec![], + body: ql::Expression::Pred( + def_table.to_owned(), + vec![ + ql::Expression::Var("this".to_owned()), + ql::Expression::Var("result".to_owned()), + ql::Expression::Var("_".to_owned()), + ], + ), + } +} + +/// Returns an expression to get a field that's defined as a column in the parent's table. +/// +/// # Arguments +/// +/// * `table_name` - the name of parent's defining table +/// * `column_index` - the index in that table that defines the field +/// * `arity` - the total number of columns in the table +fn create_get_field_expr_for_column_storage( + table_name: &str, + column_index: usize, + arity: usize, +) -> ql::Expression { + let num_underscores_before = column_index - 1; + let num_underscores_after = arity - 2 - num_underscores_before; + ql::Expression::Pred( + table_name.to_owned(), + [ + vec![ql::Expression::Var("this".to_owned())], + vec![ql::Expression::Var("_".to_owned()); num_underscores_before], + vec![ql::Expression::Var("result".to_owned())], + vec![ql::Expression::Var("_".to_owned()); num_underscores_after], + ] + .concat(), + ) +} + +/// Returns an expression to get the field with the given index from its +/// auxiliary table. The index name can be "_" so the expression will hold for +/// all indices. +fn create_get_field_expr_for_table_storage( + table_name: &str, + index_var_name: &str, +) -> ql::Expression { + ql::Expression::Pred( + table_name.to_owned(), + vec![ + ql::Expression::Var("this".to_owned()), + ql::Expression::Var(index_var_name.to_owned()), + ql::Expression::Var("result".to_owned()), + ], + ) +} + +/// Creates a pair consisting of a predicate to get the given field, and an +/// expression that will get the same field. When the field can occur multiple +/// times, the predicate will take an index argument, while the expression will +/// use the "don't care" expression to hold for all occurrences. +/// +/// # Arguments +/// +/// `main_table_name` - the name of the defining table for the parent node +/// `main_table_arity` - the number of columns in the main table +/// `main_table_column_index` - a mutable reference to a column index indicating +/// where the field is in the main table. If this is used (i.e. the field has +/// column storage), then the index is incremented. +/// `parent_name` - the name of the parent node +/// `field` - the field whose getters we are creating +/// `field_type` - the db name of the field's type (possibly being a union we created) +fn create_field_getters( + main_table_name: &str, + main_table_arity: usize, + main_table_column_index: &mut usize, + parent_name: &str, + field: &node_types::Field, + field_type: &str, +) -> (ql::Predicate, ql::Expression) { + match &field.storage { + node_types::Storage::Column => { + let result = ( + ql::Predicate { + name: format!( + "get{}", + dbscheme_name_to_class_name(&node_types::escape_name(&field.get_name())) + ), + overridden: false, + return_type: Some(ql::Type::Normal(dbscheme_name_to_class_name(field_type))), + formal_parameters: vec![], + body: create_get_field_expr_for_column_storage( + &main_table_name, + *main_table_column_index, + main_table_arity, + ), + }, + create_get_field_expr_for_column_storage( + &main_table_name, + *main_table_column_index, + main_table_arity, + ), + ); + *main_table_column_index += 1; + result + } + node_types::Storage::Table => { + let field_table_name = format!("{}_{}", parent_name, &field.get_name()); + ( + ql::Predicate { + name: format!( + "get{}", + dbscheme_name_to_class_name(&node_types::escape_name(&field.get_name())) + ), + overridden: false, + return_type: Some(ql::Type::Normal(dbscheme_name_to_class_name(field_type))), + formal_parameters: vec![ql::FormalParameter { + name: "i".to_owned(), + param_type: ql::Type::Int, + }], + body: create_get_field_expr_for_table_storage(&field_table_name, "i"), + }, + create_get_field_expr_for_table_storage(&field_table_name, "_"), + ) + } + } +} + +/// Converts the given node types into CodeQL classes wrapping the dbscheme. +pub fn convert_nodes(nodes: &Vec) -> Vec { + let supertype_map = create_supertype_map(nodes); + let mut classes: Vec = vec![create_location_class(), create_top_class()]; + + for node in nodes { + match &node { + node_types::Entry::Union { + type_name, + members: _, + } => { + // It's a tree-sitter supertype node, so we're wrapping a dbscheme + // union type. + let union_name = node_types::escape_name(&node_types::node_type_name( + &type_name.kind, + type_name.named, + )); + let class_name = dbscheme_name_to_class_name(&union_name); + classes.push(ql::Class { + name: class_name.clone(), + is_abstract: false, + supertypes: [ + vec![ql::Type::AtType(union_name)], + get_base_classes(&class_name, &supertype_map), + ] + .concat(), + characteristic_predicate: None, + predicates: vec![], + }); + } + node_types::Entry::Table { type_name, fields } => { + // Count how many columns there will be in the main table. + // There will be: + // - one for the id + // - one for the location + // - one for each field that's stored as a column + // - if there are no fields, one for the text column. + let main_table_arity = 2 + if fields.is_empty() { + 1 + } else { + fields + .iter() + .filter(|&f| matches!(f.storage, node_types::Storage::Column)) + .count() + }; + + let name = node_types::node_type_name(&type_name.kind, type_name.named); + let dbscheme_name = node_types::escape_name(&name); + let ql_type = ql::Type::AtType(dbscheme_name.clone()); + let main_table_name = node_types::escape_name(&(format!("{}_def", name))); + let main_class_name = dbscheme_name_to_class_name(&dbscheme_name); + let mut main_class = ql::Class { + name: main_class_name.clone(), + is_abstract: false, + supertypes: [ + vec![ql_type], + get_base_classes(&main_class_name, &supertype_map), + ] + .concat(), + characteristic_predicate: None, + predicates: vec![ + create_to_string_predicate(&main_class_name), + create_get_location_predicate(&main_table_name, main_table_arity), + ], + }; + + if fields.is_empty() { + main_class + .predicates + .push(create_get_text_predicate(&main_table_name)); + } else { + let mut main_table_column_index: usize = 1; + let mut get_child_exprs: Vec = Vec::new(); + + // Iterate through the fields, creating: + // - classes to wrap union types if fields need them, + // - predicates to access the fields, + // - the QL expressions to access the fields that will be part of getAFieldOrChild. + for field in fields { + let field_type = + create_field_class(&name, field, &mut classes, &supertype_map); + let (get_pred, get_child_expr) = create_field_getters( + &main_table_name, + main_table_arity, + &mut main_table_column_index, + &name, + field, + &field_type, + ); + main_class.predicates.push(get_pred); + get_child_exprs.push(get_child_expr); + } + + main_class.predicates.push(ql::Predicate { + name: "getAFieldOrChild".to_owned(), + overridden: true, + return_type: Some(ql::Type::Normal("Top".to_owned())), + formal_parameters: vec![], + body: ql::Expression::Or(get_child_exprs), + }); + } + + classes.push(main_class); + } + } + } + + classes +} diff --git a/node-types/src/lib.rs b/node-types/src/lib.rs index 37daed4c397..d7b4128018d 100644 --- a/node-types/src/lib.rs +++ b/node-types/src/lib.rs @@ -33,6 +33,15 @@ pub struct Field { pub storage: Storage, } +impl Field { + pub fn get_name(&self) -> String { + match &self.name { + Some(name) => name.clone(), + None => "child".to_owned(), + } + } +} + #[derive(Debug)] pub enum Storage { /// the field is stored as a column in the parent table diff --git a/ruby.dbscheme b/ruby.dbscheme index 9e0864eafdf..6e65059c6b5 100644 --- a/ruby.dbscheme +++ b/ruby.dbscheme @@ -1,6 +1,19 @@ // CodeQL database schema for Ruby // Automatically generated from the tree-sitter grammar; do not edit +location( + unique int id: @location, + string file_path: string ref, + int start_line: int ref, + int start_column: int ref, + int end_line: int ref, + int end_column: int ref +); + +sourceLocationPrefix( + string prefix: string ref +); + @underscore_arg = @underscore_primary | @assignment | @binary | @conditional | @operator_assignment | @range | @unary @underscore_lhs = @underscore_variable | @call | @element_reference | @false | @method_call | @nil | @scope_resolution | @true @@ -1849,16 +1862,3 @@ tilde_unnamed_def( @top = @alias | @argument_list | @array | @assignment | @bare_string | @bare_symbol | @begin | @begin_block | @binary | @block | @block_argument | @block_parameter | @block_parameters | @break | @call | @case__ | @chained_string | @class | @conditional | @destructured_left_assignment | @destructured_parameter | @do | @do_block | @element_reference | @else | @elsif | @empty_statement | @end_block | @ensure | @exception_variable | @exceptions | @for | @hash | @hash_splat_argument | @hash_splat_parameter | @if | @if_modifier | @in | @interpolation | @keyword_parameter | @lambda | @lambda_parameters | @left_assignment_list | @method | @method_call | @method_parameters | @module | @next | @operator | @operator_assignment | @optional_parameter | @pair | @parenthesized_statements | @pattern | @program | @range | @rational | @redo | @regex | @rescue | @rescue_modifier | @rest_assignment | @retry | @return | @right_assignment_list | @scope_resolution | @setter | @singleton_class | @singleton_method | @splat_argument | @splat_parameter | @string__ | @string_array | @subshell | @superclass | @symbol | @symbol_array | @then | @unary | @undef | @unless | @unless_modifier | @until | @until_modifier | @when | @while | @while_modifier | @yield | @bang_unnamed | @bangequal_unnamed | @bangtilde_unnamed | @dquote_unnamed | @hashlbrace_unnamed | @percent_unnamed | @percentequal_unnamed | @percentilparen_unnamed | @percentwlparen_unnamed | @ampersand_unnamed | @ampersandampersand_unnamed | @ampersandampersandequal_unnamed | @ampersanddot_unnamed | @ampersandequal_unnamed | @lparen_unnamed | @rparen_unnamed | @star_unnamed | @starstar_unnamed | @starstarequal_unnamed | @starequal_unnamed | @plus_unnamed | @plusequal_unnamed | @plusat_unnamed | @comma_unnamed | @minus_unnamed | @minusequal_unnamed | @minusrangle_unnamed | @minusat_unnamed | @dot_unnamed | @dotdot_unnamed | @dotdotdot_unnamed | @slash_unnamed | @slashequal_unnamed | @colon_unnamed | @colondquote_unnamed | @coloncolon_unnamed | @semicolon_unnamed | @langle_unnamed | @langlelangle_unnamed | @langlelangleequal_unnamed | @langleequal_unnamed | @langleequalrangle_unnamed | @equal_unnamed | @equalequal_unnamed | @equalequalequal_unnamed | @equalrangle_unnamed | @equaltilde_unnamed | @rangle_unnamed | @rangleequal_unnamed | @ranglerangle_unnamed | @ranglerangleequal_unnamed | @question_unnamed | @b_e_g_i_n__unnamed | @e_n_d__unnamed | @lbracket_unnamed | @lbracketrbracket_unnamed | @lbracketrbracketequal_unnamed | @rbracket_unnamed | @caret_unnamed | @caretequal_unnamed | @underscore__e_n_d____unnamed | @backtick_unnamed | @alias_unnamed | @and_unnamed | @begin_unnamed | @break_unnamed | @case_unnamed | @character | @class_unnamed | @class_variable | @complex | @constant | @def_unnamed | @definedquestion_unnamed | @do_unnamed | @else_unnamed | @elsif_unnamed | @end_unnamed | @ensure_unnamed | @escape_sequence | @false | @float__ | @for_unnamed | @global_variable | @heredoc_beginning | @heredoc_end | @identifier | @if_unnamed | @in_unnamed | @instance_variable | @integer | @module_unnamed | @next_unnamed | @nil | @not_unnamed | @or_unnamed | @r_unnamed | @redo_unnamed | @rescue_unnamed | @retry_unnamed | @return_unnamed | @self | @super | @then_unnamed | @true | @undef_unnamed | @uninterpreted | @unless_unnamed | @until_unnamed | @when_unnamed | @while_unnamed | @yield_unnamed | @lbrace_unnamed | @pipe_unnamed | @pipeequal_unnamed | @pipepipe_unnamed | @pipepipeequal_unnamed | @rbrace_unnamed | @tilde_unnamed -location( - unique int id: @location, - string file_path: string ref, - int start_line: int ref, - int start_column: int ref, - int end_line: int ref, - int end_column: int ref -); - -sourceLocationPrefix( - string prefix: string ref -); - diff --git a/ruby_ast.qll b/ruby_ast.qll new file mode 100644 index 00000000000..6961412bf08 --- /dev/null +++ b/ruby_ast.qll @@ -0,0 +1,2207 @@ +/* + * CodeQL library for Ruby + * Automatically generated from the tree-sitter grammar; do not edit + */ + +class Location extends @location { + string toString() { result = "Location" } + + predicate hasLocationInfo( + string filePath, int startLine, int startColumn, int endLine, int endColumn + ) { + location(this, filePath, startLine, startColumn, endLine, endColumn) + } +} + +class Top extends @top { + string toString() { none() } + + Location getLocation() { none() } + + Top getAFieldOrChild() { none() } +} + +class UnderscoreArg extends @underscore_arg, Top, ArgumentListChildType, ArrayChildType, + AssignmentRightType, BinaryLeftType, BinaryRightType, ElementReferenceChildType, + ExceptionsChildType, IfModifierConditionType, OperatorAssignmentRightType, PairKeyType, + PatternChildType, RescueModifierHandlerType, RightAssignmentListChildType, + SingletonMethodObjectType, SuperclassChildType, UnaryChildType, UnderscoreStatement, + UnlessModifierConditionType, UntilModifierConditionType, WhileModifierConditionType { } + +class UnderscoreLhs extends @underscore_lhs, Top, AssignmentLeftType, + DestructuredLeftAssignmentChildType, ForPatternType, LeftAssignmentListChildType, + UnderscorePrimary { } + +class UnderscoreMethodName extends @underscore_method_name, Top { } + +class UnderscorePrimary extends @underscore_primary, Top, CallReceiverType, UnderscoreArg { } + +class UnderscoreStatement extends @underscore_statement, Top, BeginBlockChildType, BeginChildType, + BlockChildType, ClassChildType, DoBlockChildType, DoChildType, ElseChildType, EndBlockChildType, + EnsureChildType, MethodChildType, ModuleChildType, ParenthesizedStatementsChildType, + ProgramChildType, SingletonClassChildType, SingletonMethodChildType, ThenChildType { } + +class UnderscoreVariable extends @underscore_variable, Top, MethodCallMethodType, + SingletonMethodObjectType, UnderscoreLhs { } + +class Alias extends @alias, Top, UnderscoreStatement { + override string toString() { result = "Alias" } + + override Location getLocation() { alias_def(this, _, _, result) } + + UnderscoreMethodName getAlias() { alias_def(this, result, _, _) } + + UnderscoreMethodName getName() { alias_def(this, _, result, _) } + + override Top getAFieldOrChild() { alias_def(this, result, _, _) or alias_def(this, _, result, _) } +} + +class ArgumentListChildType extends @argument_list_child_type, Top { } + +class ArgumentList extends @argument_list, Top, CallMethodType { + override string toString() { result = "ArgumentList" } + + override Location getLocation() { argument_list_def(this, result) } + + ArgumentListChildType getChild(int i) { argument_list_child(this, i, result) } + + override Top getAFieldOrChild() { argument_list_child(this, _, result) } +} + +class ArrayChildType extends @array_child_type, Top { } + +class Array extends @array, Top, UnderscorePrimary { + override string toString() { result = "Array" } + + override Location getLocation() { array_def(this, result) } + + ArrayChildType getChild(int i) { array_child(this, i, result) } + + override Top getAFieldOrChild() { array_child(this, _, result) } +} + +class AssignmentLeftType extends @assignment_left_type, Top { } + +class AssignmentRightType extends @assignment_right_type, Top { } + +class Assignment extends @assignment, Top, UnderscoreArg, UnderscoreStatement { + override string toString() { result = "Assignment" } + + override Location getLocation() { assignment_def(this, _, _, result) } + + AssignmentLeftType getLeft() { assignment_def(this, result, _, _) } + + AssignmentRightType getRight() { assignment_def(this, _, result, _) } + + override Top getAFieldOrChild() { + assignment_def(this, result, _, _) or assignment_def(this, _, result, _) + } +} + +class BareStringChildType extends @bare_string_child_type, Top { } + +class BareString extends @bare_string, Top { + override string toString() { result = "BareString" } + + override Location getLocation() { bare_string_def(this, result) } + + BareStringChildType getChild(int i) { bare_string_child(this, i, result) } + + override Top getAFieldOrChild() { bare_string_child(this, _, result) } +} + +class BareSymbolChildType extends @bare_symbol_child_type, Top { } + +class BareSymbol extends @bare_symbol, Top { + override string toString() { result = "BareSymbol" } + + override Location getLocation() { bare_symbol_def(this, result) } + + BareSymbolChildType getChild(int i) { bare_symbol_child(this, i, result) } + + override Top getAFieldOrChild() { bare_symbol_child(this, _, result) } +} + +class BeginChildType extends @begin_child_type, Top { } + +class Begin extends @begin, Top, UnderscorePrimary { + override string toString() { result = "Begin" } + + override Location getLocation() { begin_def(this, result) } + + BeginChildType getChild(int i) { begin_child(this, i, result) } + + override Top getAFieldOrChild() { begin_child(this, _, result) } +} + +class BeginBlockChildType extends @begin_block_child_type, Top { } + +class BeginBlock extends @begin_block, Top, UnderscoreStatement { + override string toString() { result = "BeginBlock" } + + override Location getLocation() { begin_block_def(this, result) } + + BeginBlockChildType getChild(int i) { begin_block_child(this, i, result) } + + override Top getAFieldOrChild() { begin_block_child(this, _, result) } +} + +class BinaryLeftType extends @binary_left_type, Top { } + +class BinaryOperatorType extends @binary_operator_type, Top { } + +class BinaryRightType extends @binary_right_type, Top { } + +class Binary extends @binary, Top, UnderscoreArg, UnderscoreStatement { + override string toString() { result = "Binary" } + + override Location getLocation() { binary_def(this, _, _, _, result) } + + BinaryLeftType getLeft() { binary_def(this, result, _, _, _) } + + BinaryOperatorType getOperator() { binary_def(this, _, result, _, _) } + + BinaryRightType getRight() { binary_def(this, _, _, result, _) } + + override Top getAFieldOrChild() { + binary_def(this, result, _, _, _) or + binary_def(this, _, result, _, _) or + binary_def(this, _, _, result, _) + } +} + +class BlockChildType extends @block_child_type, Top { } + +class Block extends @block, Top, LambdaBodyType, MethodCallBlockType { + override string toString() { result = "Block" } + + override Location getLocation() { block_def(this, result) } + + BlockChildType getChild(int i) { block_child(this, i, result) } + + override Top getAFieldOrChild() { block_child(this, _, result) } +} + +class BlockArgument extends @block_argument, Top, ArgumentListChildType, ArrayChildType, + ElementReferenceChildType { + override string toString() { result = "BlockArgument" } + + override Location getLocation() { block_argument_def(this, _, result) } + + UnderscoreArg getChild() { block_argument_def(this, result, _) } + + override Top getAFieldOrChild() { block_argument_def(this, result, _) } +} + +class BlockParameter extends @block_parameter, Top, BlockParametersChildType, + DestructuredParameterChildType, LambdaParametersChildType, MethodParametersChildType { + override string toString() { result = "BlockParameter" } + + override Location getLocation() { block_parameter_def(this, _, result) } + + Identifier getName() { block_parameter_def(this, result, _) } + + override Top getAFieldOrChild() { block_parameter_def(this, result, _) } +} + +class BlockParametersChildType extends @block_parameters_child_type, Top { } + +class BlockParameters extends @block_parameters, Top, BlockChildType, DoBlockChildType { + override string toString() { result = "BlockParameters" } + + override Location getLocation() { block_parameters_def(this, result) } + + BlockParametersChildType getChild(int i) { block_parameters_child(this, i, result) } + + override Top getAFieldOrChild() { block_parameters_child(this, _, result) } +} + +class Break extends @break, Top, ArgumentListChildType, ArrayChildType, AssignmentRightType, + BinaryLeftType, BinaryRightType, ElementReferenceChildType, IfModifierConditionType, + OperatorAssignmentRightType, RescueModifierHandlerType, SuperclassChildType, UnaryChildType, + UnderscorePrimary, UnderscoreStatement, UnlessModifierConditionType, UntilModifierConditionType, + WhileModifierConditionType { + override string toString() { result = "Break" } + + override Location getLocation() { break_def(this, result) } + + ArgumentList getChild(int i) { break_child(this, i, result) } + + override Top getAFieldOrChild() { break_child(this, _, result) } +} + +class CallMethodType extends @call_method_type, Top { } + +class CallReceiverType extends @call_receiver_type, Top { } + +class Call extends @call, Top, ArgumentListChildType, ArrayChildType, AssignmentRightType, + BinaryLeftType, BinaryRightType, ElementReferenceChildType, IfModifierConditionType, + MethodCallMethodType, OperatorAssignmentRightType, RescueModifierHandlerType, SuperclassChildType, + UnaryChildType, UnderscoreLhs, UnderscoreStatement, UnlessModifierConditionType, + UntilModifierConditionType, WhileModifierConditionType { + override string toString() { result = "Call" } + + override Location getLocation() { call_def(this, _, _, result) } + + CallMethodType getMethod() { call_def(this, result, _, _) } + + CallReceiverType getReceiver() { call_def(this, _, result, _) } + + override Top getAFieldOrChild() { call_def(this, result, _, _) or call_def(this, _, result, _) } +} + +class CaseChildType extends @case_child_type, Top { } + +class Case extends @case__, Top, UnderscorePrimary { + override string toString() { result = "Case" } + + override Location getLocation() { case_def(this, result) } + + UnderscoreStatement getValue(int i) { case_value(this, i, result) } + + CaseChildType getChild(int i) { case_child(this, i, result) } + + override Top getAFieldOrChild() { case_value(this, _, result) or case_child(this, _, result) } +} + +class ChainedString extends @chained_string, Top, UnderscorePrimary { + override string toString() { result = "ChainedString" } + + override Location getLocation() { chained_string_def(this, result) } + + String getChild(int i) { chained_string_child(this, i, result) } + + override Top getAFieldOrChild() { chained_string_child(this, _, result) } +} + +class ClassNameType extends @class_name_type, Top { } + +class ClassChildType extends @class_child_type, Top { } + +class Class extends @class, Top, UnderscorePrimary { + override string toString() { result = "Class" } + + override Location getLocation() { class_def(this, _, result) } + + ClassNameType getName() { class_def(this, result, _) } + + ClassChildType getChild(int i) { class_child(this, i, result) } + + override Top getAFieldOrChild() { class_def(this, result, _) or class_child(this, _, result) } +} + +class Conditional extends @conditional, Top, UnderscoreArg { + override string toString() { 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 Top getAFieldOrChild() { + conditional_def(this, result, _, _, _) or + conditional_def(this, _, result, _, _) or + conditional_def(this, _, _, result, _) + } +} + +class DestructuredLeftAssignmentChildType extends @destructured_left_assignment_child_type, Top { } + +class DestructuredLeftAssignment extends @destructured_left_assignment, Top, + DestructuredLeftAssignmentChildType, ForPatternType, LeftAssignmentListChildType { + override string toString() { result = "DestructuredLeftAssignment" } + + override Location getLocation() { destructured_left_assignment_def(this, result) } + + DestructuredLeftAssignmentChildType getChild(int i) { + destructured_left_assignment_child(this, i, result) + } + + override Top getAFieldOrChild() { destructured_left_assignment_child(this, _, result) } +} + +class DestructuredParameterChildType extends @destructured_parameter_child_type, Top { } + +class DestructuredParameter extends @destructured_parameter, Top, BlockParametersChildType, + DestructuredParameterChildType, LambdaParametersChildType, MethodParametersChildType { + override string toString() { result = "DestructuredParameter" } + + override Location getLocation() { destructured_parameter_def(this, result) } + + DestructuredParameterChildType getChild(int i) { destructured_parameter_child(this, i, result) } + + override Top getAFieldOrChild() { destructured_parameter_child(this, _, result) } +} + +class DoChildType extends @do_child_type, Top { } + +class Do extends @do, Top { + override string toString() { result = "Do" } + + override Location getLocation() { do_def(this, result) } + + DoChildType getChild(int i) { do_child(this, i, result) } + + override Top getAFieldOrChild() { do_child(this, _, result) } +} + +class DoBlockChildType extends @do_block_child_type, Top { } + +class DoBlock extends @do_block, Top, LambdaBodyType, MethodCallBlockType { + override string toString() { result = "DoBlock" } + + override Location getLocation() { do_block_def(this, result) } + + DoBlockChildType getChild(int i) { do_block_child(this, i, result) } + + override Top getAFieldOrChild() { do_block_child(this, _, result) } +} + +class ElementReferenceChildType extends @element_reference_child_type, Top { } + +class ElementReference extends @element_reference, Top, UnderscoreLhs { + override string toString() { result = "ElementReference" } + + override Location getLocation() { element_reference_def(this, _, result) } + + UnderscorePrimary getObject() { element_reference_def(this, result, _) } + + ElementReferenceChildType getChild(int i) { element_reference_child(this, i, result) } + + override Top getAFieldOrChild() { + element_reference_def(this, result, _) or element_reference_child(this, _, result) + } +} + +class ElseChildType extends @else_child_type, Top { } + +class Else extends @else, Top, BeginChildType, CaseChildType, ClassChildType, DoBlockChildType, + ElsifAlternativeType, IfAlternativeType, MethodChildType, ModuleChildType, + SingletonClassChildType, SingletonMethodChildType, UnlessAlternativeType { + override string toString() { result = "Else" } + + override Location getLocation() { else_def(this, result) } + + SemicolonUnnamed getCondition(int i) { else_condition(this, i, result) } + + ElseChildType getChild(int i) { else_child(this, i, result) } + + override Top getAFieldOrChild() { else_condition(this, _, result) or else_child(this, _, result) } +} + +class ElsifAlternativeType extends @elsif_alternative_type, Top { } + +class Elsif extends @elsif, Top, ElsifAlternativeType, IfAlternativeType, UnlessAlternativeType { + override string toString() { result = "Elsif" } + + override Location getLocation() { elsif_def(this, _, result) } + + ElsifAlternativeType getAlternative(int i) { elsif_alternative(this, i, result) } + + UnderscoreStatement getCondition() { elsif_def(this, result, _) } + + Then getConsequence(int i) { elsif_consequence(this, i, result) } + + override Top getAFieldOrChild() { + elsif_alternative(this, _, result) or + elsif_def(this, result, _) or + elsif_consequence(this, _, result) + } +} + +class EmptyStatement extends @empty_statement, Top, BeginBlockChildType, BeginChildType, + BlockChildType, ClassChildType, DoBlockChildType, DoChildType, ElseChildType, EndBlockChildType, + EnsureChildType, MethodChildType, ModuleChildType, ParenthesizedStatementsChildType, + ProgramChildType, SingletonClassChildType, SingletonMethodChildType, ThenChildType { + override string toString() { result = "EmptyStatement" } + + override Location getLocation() { empty_statement_def(this, _, result) } + + string getText() { empty_statement_def(this, result, _) } +} + +class EndBlockChildType extends @end_block_child_type, Top { } + +class EndBlock extends @end_block, Top, UnderscoreStatement { + override string toString() { result = "EndBlock" } + + override Location getLocation() { end_block_def(this, result) } + + EndBlockChildType getChild(int i) { end_block_child(this, i, result) } + + override Top getAFieldOrChild() { end_block_child(this, _, result) } +} + +class EnsureChildType extends @ensure_child_type, Top { } + +class Ensure extends @ensure, Top, BeginChildType, ClassChildType, DoBlockChildType, + MethodChildType, ModuleChildType, SingletonClassChildType, SingletonMethodChildType { + override string toString() { result = "Ensure" } + + override Location getLocation() { ensure_def(this, result) } + + EnsureChildType getChild(int i) { ensure_child(this, i, result) } + + override Top getAFieldOrChild() { ensure_child(this, _, result) } +} + +class ExceptionVariable extends @exception_variable, Top { + override string toString() { result = "ExceptionVariable" } + + override Location getLocation() { exception_variable_def(this, _, result) } + + UnderscoreLhs getChild() { exception_variable_def(this, result, _) } + + override Top getAFieldOrChild() { exception_variable_def(this, result, _) } +} + +class ExceptionsChildType extends @exceptions_child_type, Top { } + +class Exceptions extends @exceptions, Top { + override string toString() { result = "Exceptions" } + + override Location getLocation() { exceptions_def(this, result) } + + ExceptionsChildType getChild(int i) { exceptions_child(this, i, result) } + + override Top getAFieldOrChild() { exceptions_child(this, _, result) } +} + +class ForPatternType extends @for_pattern_type, Top { } + +class For extends @for, Top, UnderscorePrimary { + override string toString() { result = "For" } + + override Location getLocation() { for_def(this, _, _, result) } + + Do getBody() { for_def(this, result, _, _) } + + ForPatternType getPattern(int i) { for_pattern(this, i, result) } + + In getValue() { for_def(this, _, result, _) } + + override Top getAFieldOrChild() { + for_def(this, result, _, _) or for_pattern(this, _, result) or for_def(this, _, result, _) + } +} + +class HashChildType extends @hash_child_type, Top { } + +class Hash extends @hash, Top, UnderscorePrimary { + override string toString() { result = "Hash" } + + override Location getLocation() { hash_def(this, result) } + + HashChildType getChild(int i) { hash_child(this, i, result) } + + override Top getAFieldOrChild() { hash_child(this, _, result) } +} + +class HashSplatArgument extends @hash_splat_argument, Top, ArgumentListChildType, ArrayChildType, + ElementReferenceChildType, HashChildType { + override string toString() { result = "HashSplatArgument" } + + override Location getLocation() { hash_splat_argument_def(this, _, result) } + + UnderscoreArg getChild() { hash_splat_argument_def(this, result, _) } + + override Top getAFieldOrChild() { hash_splat_argument_def(this, result, _) } +} + +class HashSplatParameter extends @hash_splat_parameter, Top, BlockParametersChildType, + DestructuredParameterChildType, LambdaParametersChildType, MethodParametersChildType { + override string toString() { result = "HashSplatParameter" } + + override Location getLocation() { hash_splat_parameter_def(this, result) } + + Identifier getName(int i) { hash_splat_parameter_name(this, i, result) } + + override Top getAFieldOrChild() { hash_splat_parameter_name(this, _, result) } +} + +class IfAlternativeType extends @if_alternative_type, Top { } + +class If extends @if, Top, UnderscorePrimary { + override string toString() { result = "If" } + + override Location getLocation() { if_def(this, _, result) } + + IfAlternativeType getAlternative(int i) { if_alternative(this, i, result) } + + UnderscoreStatement getCondition() { if_def(this, result, _) } + + Then getConsequence(int i) { if_consequence(this, i, result) } + + override Top getAFieldOrChild() { + if_alternative(this, _, result) or if_def(this, result, _) or if_consequence(this, _, result) + } +} + +class IfModifierConditionType extends @if_modifier_condition_type, Top { } + +class IfModifier extends @if_modifier, Top, UnderscoreStatement { + override string toString() { result = "IfModifier" } + + override Location getLocation() { if_modifier_def(this, _, _, result) } + + UnderscoreStatement getBody() { if_modifier_def(this, result, _, _) } + + IfModifierConditionType getCondition() { if_modifier_def(this, _, result, _) } + + override Top getAFieldOrChild() { + if_modifier_def(this, result, _, _) or if_modifier_def(this, _, result, _) + } +} + +class In extends @in, Top { + override string toString() { result = "In" } + + override Location getLocation() { in_def(this, _, result) } + + UnderscoreArg getChild() { in_def(this, result, _) } + + override Top getAFieldOrChild() { in_def(this, result, _) } +} + +class Interpolation extends @interpolation, Top, BareStringChildType, BareSymbolChildType, + RegexChildType, StringChildType, SubshellChildType, SymbolChildType { + override string toString() { result = "Interpolation" } + + override Location getLocation() { interpolation_def(this, _, result) } + + UnderscoreStatement getChild() { interpolation_def(this, result, _) } + + override Top getAFieldOrChild() { interpolation_def(this, result, _) } +} + +class KeywordParameter extends @keyword_parameter, Top, BlockParametersChildType, + DestructuredParameterChildType, LambdaParametersChildType, MethodParametersChildType { + override string toString() { result = "KeywordParameter" } + + override Location getLocation() { keyword_parameter_def(this, _, result) } + + Identifier getName() { keyword_parameter_def(this, result, _) } + + UnderscoreArg getValue(int i) { keyword_parameter_value(this, i, result) } + + override Top getAFieldOrChild() { + keyword_parameter_def(this, result, _) or keyword_parameter_value(this, _, result) + } +} + +class LambdaBodyType extends @lambda_body_type, Top { } + +class Lambda extends @lambda, Top, UnderscorePrimary { + override string toString() { result = "Lambda" } + + override Location getLocation() { lambda_def(this, _, result) } + + LambdaBodyType getBody() { lambda_def(this, result, _) } + + LambdaParameters getParameters(int i) { lambda_parameters(this, i, result) } + + override Top getAFieldOrChild() { + lambda_def(this, result, _) or lambda_parameters(this, _, result) + } +} + +class LambdaParametersChildType extends @lambda_parameters_child_type, Top { } + +class LambdaParameters extends @lambda_parameters, Top { + override string toString() { result = "LambdaParameters" } + + override Location getLocation() { lambda_parameters_def(this, result) } + + LambdaParametersChildType getChild(int i) { lambda_parameters_child(this, i, result) } + + override Top getAFieldOrChild() { lambda_parameters_child(this, _, result) } +} + +class LeftAssignmentListChildType extends @left_assignment_list_child_type, Top { } + +class LeftAssignmentList extends @left_assignment_list, Top, AssignmentLeftType { + override string toString() { result = "LeftAssignmentList" } + + override Location getLocation() { left_assignment_list_def(this, result) } + + LeftAssignmentListChildType getChild(int i) { left_assignment_list_child(this, i, result) } + + override Top getAFieldOrChild() { left_assignment_list_child(this, _, result) } +} + +class MethodChildType extends @method_child_type, Top { } + +class Method extends @method, Top, UnderscorePrimary { + override string toString() { result = "Method" } + + override Location getLocation() { method_def(this, _, result) } + + UnderscoreMethodName getName() { method_def(this, result, _) } + + MethodParameters getParameters(int i) { method_parameters(this, i, result) } + + MethodChildType getChild(int i) { method_child(this, i, result) } + + override Top getAFieldOrChild() { + method_def(this, result, _) or + method_parameters(this, _, result) or + method_child(this, _, result) + } +} + +class MethodCallBlockType extends @method_call_block_type, Top { } + +class MethodCallMethodType extends @method_call_method_type, Top { } + +class MethodCall extends @method_call, Top, ArgumentListChildType, ArrayChildType, + AssignmentRightType, BinaryLeftType, BinaryRightType, CallReceiverType, ElementReferenceChildType, + IfModifierConditionType, OperatorAssignmentRightType, RescueModifierHandlerType, + SuperclassChildType, UnaryChildType, UnderscoreLhs, UnderscoreStatement, + UnlessModifierConditionType, UntilModifierConditionType, WhileModifierConditionType { + override string toString() { result = "MethodCall" } + + override Location getLocation() { method_call_def(this, _, result) } + + ArgumentList getArguments(int i) { method_call_arguments(this, i, result) } + + MethodCallBlockType getBlock(int i) { method_call_block(this, i, result) } + + MethodCallMethodType getMethod() { method_call_def(this, result, _) } + + override Top getAFieldOrChild() { + method_call_arguments(this, _, result) or + method_call_block(this, _, result) or + method_call_def(this, result, _) + } +} + +class MethodParametersChildType extends @method_parameters_child_type, Top { } + +class MethodParameters extends @method_parameters, Top { + override string toString() { result = "MethodParameters" } + + override Location getLocation() { method_parameters_def(this, result) } + + MethodParametersChildType getChild(int i) { method_parameters_child(this, i, result) } + + override Top getAFieldOrChild() { method_parameters_child(this, _, result) } +} + +class ModuleNameType extends @module_name_type, Top { } + +class ModuleChildType extends @module_child_type, Top { } + +class Module extends @module, Top, UnderscorePrimary { + override string toString() { result = "Module" } + + override Location getLocation() { module_def(this, _, result) } + + ModuleNameType getName() { module_def(this, result, _) } + + ModuleChildType getChild(int i) { module_child(this, i, result) } + + override Top getAFieldOrChild() { module_def(this, result, _) or module_child(this, _, result) } +} + +class Next extends @next, Top, ArgumentListChildType, ArrayChildType, AssignmentRightType, + BinaryLeftType, BinaryRightType, ElementReferenceChildType, IfModifierConditionType, + OperatorAssignmentRightType, RescueModifierHandlerType, SuperclassChildType, UnaryChildType, + UnderscorePrimary, UnderscoreStatement, UnlessModifierConditionType, UntilModifierConditionType, + WhileModifierConditionType { + override string toString() { result = "Next" } + + override Location getLocation() { next_def(this, result) } + + ArgumentList getChild(int i) { next_child(this, i, result) } + + override Top getAFieldOrChild() { next_child(this, _, result) } +} + +class Operator extends @operator, Top, CallMethodType, UnderscoreMethodName { + override string toString() { result = "Operator" } + + override Location getLocation() { operator_def(this, _, result) } + + string getText() { operator_def(this, result, _) } +} + +class OperatorAssignmentRightType extends @operator_assignment_right_type, Top { } + +class OperatorAssignment extends @operator_assignment, Top, UnderscoreArg, UnderscoreStatement { + override string toString() { result = "OperatorAssignment" } + + override Location getLocation() { operator_assignment_def(this, _, _, result) } + + UnderscoreLhs getLeft() { operator_assignment_def(this, result, _, _) } + + OperatorAssignmentRightType getRight() { operator_assignment_def(this, _, result, _) } + + override Top getAFieldOrChild() { + operator_assignment_def(this, result, _, _) or operator_assignment_def(this, _, result, _) + } +} + +class OptionalParameter extends @optional_parameter, Top, BlockParametersChildType, + DestructuredParameterChildType, LambdaParametersChildType, MethodParametersChildType { + override string toString() { 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 Top getAFieldOrChild() { + optional_parameter_def(this, result, _, _) or optional_parameter_def(this, _, result, _) + } +} + +class PairKeyType extends @pair_key_type, Top { } + +class Pair extends @pair, Top, ArgumentListChildType, ArrayChildType, ElementReferenceChildType, + HashChildType { + override string toString() { result = "Pair" } + + override Location getLocation() { pair_def(this, _, _, result) } + + PairKeyType getKey() { pair_def(this, result, _, _) } + + UnderscoreArg getValue() { pair_def(this, _, result, _) } + + override Top getAFieldOrChild() { pair_def(this, result, _, _) or pair_def(this, _, result, _) } +} + +class ParenthesizedStatementsChildType extends @parenthesized_statements_child_type, Top { } + +class ParenthesizedStatements extends @parenthesized_statements, Top, UnaryChildType, + UnderscorePrimary { + override string toString() { result = "ParenthesizedStatements" } + + override Location getLocation() { parenthesized_statements_def(this, result) } + + ParenthesizedStatementsChildType getChild(int i) { + parenthesized_statements_child(this, i, result) + } + + override Top getAFieldOrChild() { parenthesized_statements_child(this, _, result) } +} + +class PatternChildType extends @pattern_child_type, Top { } + +class Pattern extends @pattern, Top, WhenPatternType { + override string toString() { result = "Pattern" } + + override Location getLocation() { pattern_def(this, _, result) } + + PatternChildType getChild() { pattern_def(this, result, _) } + + override Top getAFieldOrChild() { pattern_def(this, result, _) } +} + +class ProgramChildType extends @program_child_type, Top { } + +class Program extends @program, Top { + override string toString() { result = "Program" } + + override Location getLocation() { program_def(this, result) } + + ProgramChildType getChild(int i) { program_child(this, i, result) } + + override Top getAFieldOrChild() { program_child(this, _, result) } +} + +class Range extends @range, Top, UnderscoreArg { + override string toString() { result = "Range" } + + override Location getLocation() { range_def(this, result) } + + UnderscoreArg getChild(int i) { range_child(this, i, result) } + + override Top getAFieldOrChild() { range_child(this, _, result) } +} + +class Rational extends @rational, Top, UnderscorePrimary { + override string toString() { result = "Rational" } + + override Location getLocation() { rational_def(this, _, result) } + + Integer getChild() { rational_def(this, result, _) } + + override Top getAFieldOrChild() { rational_def(this, result, _) } +} + +class Redo extends @redo, Top, UnderscorePrimary { + override string toString() { result = "Redo" } + + override Location getLocation() { redo_def(this, result) } + + ArgumentList getChild(int i) { redo_child(this, i, result) } + + override Top getAFieldOrChild() { redo_child(this, _, result) } +} + +class RegexChildType extends @regex_child_type, Top { } + +class Regex extends @regex, Top, UnderscorePrimary { + override string toString() { result = "Regex" } + + override Location getLocation() { regex_def(this, result) } + + RegexChildType getChild(int i) { regex_child(this, i, result) } + + override Top getAFieldOrChild() { regex_child(this, _, result) } +} + +class Rescue extends @rescue, Top, BeginChildType, ClassChildType, DoBlockChildType, + MethodChildType, ModuleChildType, SingletonClassChildType, SingletonMethodChildType { + override string toString() { result = "Rescue" } + + override Location getLocation() { rescue_def(this, result) } + + Then getBody(int i) { rescue_body(this, i, result) } + + Exceptions getExceptions(int i) { rescue_exceptions(this, i, result) } + + ExceptionVariable getVariable(int i) { rescue_variable(this, i, result) } + + override Top getAFieldOrChild() { + rescue_body(this, _, result) or + rescue_exceptions(this, _, result) or + rescue_variable(this, _, result) + } +} + +class RescueModifierHandlerType extends @rescue_modifier_handler_type, Top { } + +class RescueModifier extends @rescue_modifier, Top, UnderscoreStatement { + override string toString() { result = "RescueModifier" } + + override Location getLocation() { rescue_modifier_def(this, _, _, result) } + + UnderscoreStatement getBody() { rescue_modifier_def(this, result, _, _) } + + RescueModifierHandlerType getHandler() { rescue_modifier_def(this, _, result, _) } + + override Top getAFieldOrChild() { + rescue_modifier_def(this, result, _, _) or rescue_modifier_def(this, _, result, _) + } +} + +class RestAssignment extends @rest_assignment, Top, DestructuredLeftAssignmentChildType, + ForPatternType, LeftAssignmentListChildType { + override string toString() { result = "RestAssignment" } + + override Location getLocation() { rest_assignment_def(this, result) } + + UnderscoreLhs getChild(int i) { rest_assignment_child(this, i, result) } + + override Top getAFieldOrChild() { rest_assignment_child(this, _, result) } +} + +class Retry extends @retry, Top, UnderscorePrimary { + override string toString() { result = "Retry" } + + override Location getLocation() { retry_def(this, result) } + + ArgumentList getChild(int i) { retry_child(this, i, result) } + + override Top getAFieldOrChild() { retry_child(this, _, result) } +} + +class Return extends @return, Top, ArgumentListChildType, ArrayChildType, AssignmentRightType, + BinaryLeftType, BinaryRightType, ElementReferenceChildType, IfModifierConditionType, + OperatorAssignmentRightType, RescueModifierHandlerType, SuperclassChildType, UnaryChildType, + UnderscorePrimary, UnderscoreStatement, UnlessModifierConditionType, UntilModifierConditionType, + WhileModifierConditionType { + override string toString() { result = "Return" } + + override Location getLocation() { return_def(this, result) } + + ArgumentList getChild(int i) { return_child(this, i, result) } + + override Top getAFieldOrChild() { return_child(this, _, result) } +} + +class RightAssignmentListChildType extends @right_assignment_list_child_type, Top { } + +class RightAssignmentList extends @right_assignment_list, Top, AssignmentRightType { + override string toString() { result = "RightAssignmentList" } + + override Location getLocation() { right_assignment_list_def(this, result) } + + RightAssignmentListChildType getChild(int i) { right_assignment_list_child(this, i, result) } + + override Top getAFieldOrChild() { right_assignment_list_child(this, _, result) } +} + +class ScopeResolutionNameType extends @scope_resolution_name_type, Top { } + +class ScopeResolution extends @scope_resolution, Top, ClassNameType, MethodCallMethodType, + ModuleNameType, UnderscoreLhs { + override string toString() { result = "ScopeResolution" } + + override Location getLocation() { scope_resolution_def(this, _, result) } + + ScopeResolutionNameType getName() { scope_resolution_def(this, result, _) } + + UnderscorePrimary getScope(int i) { scope_resolution_scope(this, i, result) } + + override Top getAFieldOrChild() { + scope_resolution_def(this, result, _) or scope_resolution_scope(this, _, result) + } +} + +class Setter extends @setter, Top, UnderscoreMethodName { + override string toString() { result = "Setter" } + + override Location getLocation() { setter_def(this, _, result) } + + Identifier getChild() { setter_def(this, result, _) } + + override Top getAFieldOrChild() { setter_def(this, result, _) } +} + +class SingletonClassChildType extends @singleton_class_child_type, Top { } + +class SingletonClass extends @singleton_class, Top, UnderscorePrimary { + override string toString() { result = "SingletonClass" } + + override Location getLocation() { singleton_class_def(this, _, result) } + + UnderscoreArg getValue() { singleton_class_def(this, result, _) } + + SingletonClassChildType getChild(int i) { singleton_class_child(this, i, result) } + + override Top getAFieldOrChild() { + singleton_class_def(this, result, _) or singleton_class_child(this, _, result) + } +} + +class SingletonMethodObjectType extends @singleton_method_object_type, Top { } + +class SingletonMethodChildType extends @singleton_method_child_type, Top { } + +class SingletonMethod extends @singleton_method, Top, UnderscorePrimary { + override string toString() { result = "SingletonMethod" } + + override Location getLocation() { singleton_method_def(this, _, _, result) } + + UnderscoreMethodName getName() { singleton_method_def(this, result, _, _) } + + SingletonMethodObjectType getObject() { singleton_method_def(this, _, result, _) } + + MethodParameters getParameters(int i) { singleton_method_parameters(this, i, result) } + + SingletonMethodChildType getChild(int i) { singleton_method_child(this, i, result) } + + override Top 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, Top, ArgumentListChildType, ArrayChildType, + AssignmentRightType, ElementReferenceChildType, ExceptionsChildType, PatternChildType, + RightAssignmentListChildType { + override string toString() { result = "SplatArgument" } + + override Location getLocation() { splat_argument_def(this, _, result) } + + UnderscoreArg getChild() { splat_argument_def(this, result, _) } + + override Top getAFieldOrChild() { splat_argument_def(this, result, _) } +} + +class SplatParameter extends @splat_parameter, Top, BlockParametersChildType, + DestructuredParameterChildType, LambdaParametersChildType, MethodParametersChildType { + override string toString() { result = "SplatParameter" } + + override Location getLocation() { splat_parameter_def(this, result) } + + Identifier getName(int i) { splat_parameter_name(this, i, result) } + + override Top getAFieldOrChild() { splat_parameter_name(this, _, result) } +} + +class StringChildType extends @string_child_type, Top { } + +class String extends @string__, Top, PairKeyType, UnderscorePrimary { + override string toString() { result = "String" } + + override Location getLocation() { string_def(this, result) } + + StringChildType getChild(int i) { string_child(this, i, result) } + + override Top getAFieldOrChild() { string_child(this, _, result) } +} + +class StringArray extends @string_array, Top, UnderscorePrimary { + override string toString() { result = "StringArray" } + + override Location getLocation() { string_array_def(this, result) } + + BareString getChild(int i) { string_array_child(this, i, result) } + + override Top getAFieldOrChild() { string_array_child(this, _, result) } +} + +class SubshellChildType extends @subshell_child_type, Top { } + +class Subshell extends @subshell, Top, UnderscorePrimary { + override string toString() { result = "Subshell" } + + override Location getLocation() { subshell_def(this, result) } + + SubshellChildType getChild(int i) { subshell_child(this, i, result) } + + override Top getAFieldOrChild() { subshell_child(this, _, result) } +} + +class SuperclassChildType extends @superclass_child_type, Top { } + +class Superclass extends @superclass, Top, ClassChildType { + override string toString() { result = "Superclass" } + + override Location getLocation() { superclass_def(this, _, result) } + + SuperclassChildType getChild() { superclass_def(this, result, _) } + + override Top getAFieldOrChild() { superclass_def(this, result, _) } +} + +class SymbolChildType extends @symbol_child_type, Top { } + +class Symbol extends @symbol, Top, PairKeyType, UnderscoreMethodName, UnderscorePrimary { + override string toString() { result = "Symbol" } + + override Location getLocation() { symbol_def(this, result) } + + SymbolChildType getChild(int i) { symbol_child(this, i, result) } + + override Top getAFieldOrChild() { symbol_child(this, _, result) } +} + +class SymbolArray extends @symbol_array, Top, UnderscorePrimary { + override string toString() { result = "SymbolArray" } + + override Location getLocation() { symbol_array_def(this, result) } + + BareSymbol getChild(int i) { symbol_array_child(this, i, result) } + + override Top getAFieldOrChild() { symbol_array_child(this, _, result) } +} + +class ThenChildType extends @then_child_type, Top { } + +class Then extends @then, Top { + override string toString() { result = "Then" } + + override Location getLocation() { then_def(this, result) } + + ThenChildType getChild(int i) { then_child(this, i, result) } + + override Top getAFieldOrChild() { then_child(this, _, result) } +} + +class UnaryChildType extends @unary_child_type, Top { } + +class Unary extends @unary, Top, UnderscoreArg, UnderscorePrimary, UnderscoreStatement { + override string toString() { result = "Unary" } + + override Location getLocation() { unary_def(this, _, result) } + + UnaryChildType getChild() { unary_def(this, result, _) } + + override Top getAFieldOrChild() { unary_def(this, result, _) } +} + +class Undef extends @undef, Top, UnderscoreStatement { + override string toString() { result = "Undef" } + + override Location getLocation() { undef_def(this, result) } + + UnderscoreMethodName getChild(int i) { undef_child(this, i, result) } + + override Top getAFieldOrChild() { undef_child(this, _, result) } +} + +class UnlessAlternativeType extends @unless_alternative_type, Top { } + +class Unless extends @unless, Top, UnderscorePrimary { + override string toString() { result = "Unless" } + + override Location getLocation() { unless_def(this, _, result) } + + UnlessAlternativeType getAlternative(int i) { unless_alternative(this, i, result) } + + UnderscoreStatement getCondition() { unless_def(this, result, _) } + + Then getConsequence(int i) { unless_consequence(this, i, result) } + + override Top getAFieldOrChild() { + unless_alternative(this, _, result) or + unless_def(this, result, _) or + unless_consequence(this, _, result) + } +} + +class UnlessModifierConditionType extends @unless_modifier_condition_type, Top { } + +class UnlessModifier extends @unless_modifier, Top, UnderscoreStatement { + override string toString() { result = "UnlessModifier" } + + override Location getLocation() { unless_modifier_def(this, _, _, result) } + + UnderscoreStatement getBody() { unless_modifier_def(this, result, _, _) } + + UnlessModifierConditionType getCondition() { unless_modifier_def(this, _, result, _) } + + override Top getAFieldOrChild() { + unless_modifier_def(this, result, _, _) or unless_modifier_def(this, _, result, _) + } +} + +class Until extends @until, Top, UnderscorePrimary { + override string toString() { result = "Until" } + + override Location getLocation() { until_def(this, _, _, result) } + + Do getBody() { until_def(this, result, _, _) } + + UnderscoreStatement getCondition() { until_def(this, _, result, _) } + + override Top getAFieldOrChild() { until_def(this, result, _, _) or until_def(this, _, result, _) } +} + +class UntilModifierConditionType extends @until_modifier_condition_type, Top { } + +class UntilModifier extends @until_modifier, Top, UnderscoreStatement { + override string toString() { result = "UntilModifier" } + + override Location getLocation() { until_modifier_def(this, _, _, result) } + + UnderscoreStatement getBody() { until_modifier_def(this, result, _, _) } + + UntilModifierConditionType getCondition() { until_modifier_def(this, _, result, _) } + + override Top getAFieldOrChild() { + until_modifier_def(this, result, _, _) or until_modifier_def(this, _, result, _) + } +} + +class WhenPatternType extends @when_pattern_type, Top { } + +class When extends @when, Top, CaseChildType { + override string toString() { result = "When" } + + override Location getLocation() { when_def(this, result) } + + Then getBody(int i) { when_body(this, i, result) } + + WhenPatternType getPattern(int i) { when_pattern(this, i, result) } + + override Top getAFieldOrChild() { when_body(this, _, result) or when_pattern(this, _, result) } +} + +class While extends @while, Top, UnderscorePrimary { + override string toString() { result = "While" } + + override Location getLocation() { while_def(this, _, _, result) } + + Do getBody() { while_def(this, result, _, _) } + + UnderscoreStatement getCondition() { while_def(this, _, result, _) } + + override Top getAFieldOrChild() { while_def(this, result, _, _) or while_def(this, _, result, _) } +} + +class WhileModifierConditionType extends @while_modifier_condition_type, Top { } + +class WhileModifier extends @while_modifier, Top, UnderscoreStatement { + override string toString() { result = "WhileModifier" } + + override Location getLocation() { while_modifier_def(this, _, _, result) } + + UnderscoreStatement getBody() { while_modifier_def(this, result, _, _) } + + WhileModifierConditionType getCondition() { while_modifier_def(this, _, result, _) } + + override Top getAFieldOrChild() { + while_modifier_def(this, result, _, _) or while_modifier_def(this, _, result, _) + } +} + +class Yield extends @yield, Top, ArgumentListChildType, ArrayChildType, AssignmentRightType, + BinaryLeftType, BinaryRightType, ElementReferenceChildType, IfModifierConditionType, + OperatorAssignmentRightType, RescueModifierHandlerType, SuperclassChildType, UnaryChildType, + UnderscorePrimary, UnderscoreStatement, UnlessModifierConditionType, UntilModifierConditionType, + WhileModifierConditionType { + override string toString() { result = "Yield" } + + override Location getLocation() { yield_def(this, result) } + + ArgumentList getChild(int i) { yield_child(this, i, result) } + + override Top getAFieldOrChild() { yield_child(this, _, result) } +} + +class BangUnnamed extends @bang_unnamed, Top { + override string toString() { result = "BangUnnamed" } + + override Location getLocation() { bang_unnamed_def(this, _, result) } + + string getText() { bang_unnamed_def(this, result, _) } +} + +class BangequalUnnamed extends @bangequal_unnamed, Top, BinaryOperatorType { + override string toString() { result = "BangequalUnnamed" } + + override Location getLocation() { bangequal_unnamed_def(this, _, result) } + + string getText() { bangequal_unnamed_def(this, result, _) } +} + +class BangtildeUnnamed extends @bangtilde_unnamed, Top, BinaryOperatorType { + override string toString() { result = "BangtildeUnnamed" } + + override Location getLocation() { bangtilde_unnamed_def(this, _, result) } + + string getText() { bangtilde_unnamed_def(this, result, _) } +} + +class DquoteUnnamed extends @dquote_unnamed, Top { + override string toString() { result = "DquoteUnnamed" } + + override Location getLocation() { dquote_unnamed_def(this, _, result) } + + string getText() { dquote_unnamed_def(this, result, _) } +} + +class HashlbraceUnnamed extends @hashlbrace_unnamed, Top { + override string toString() { result = "HashlbraceUnnamed" } + + override Location getLocation() { hashlbrace_unnamed_def(this, _, result) } + + string getText() { hashlbrace_unnamed_def(this, result, _) } +} + +class PercentUnnamed extends @percent_unnamed, Top, BinaryOperatorType { + override string toString() { result = "PercentUnnamed" } + + override Location getLocation() { percent_unnamed_def(this, _, result) } + + string getText() { percent_unnamed_def(this, result, _) } +} + +class PercentequalUnnamed extends @percentequal_unnamed, Top { + override string toString() { result = "PercentequalUnnamed" } + + override Location getLocation() { percentequal_unnamed_def(this, _, result) } + + string getText() { percentequal_unnamed_def(this, result, _) } +} + +class PercentilparenUnnamed extends @percentilparen_unnamed, Top { + override string toString() { result = "PercentilparenUnnamed" } + + override Location getLocation() { percentilparen_unnamed_def(this, _, result) } + + string getText() { percentilparen_unnamed_def(this, result, _) } +} + +class PercentwlparenUnnamed extends @percentwlparen_unnamed, Top { + override string toString() { result = "PercentwlparenUnnamed" } + + override Location getLocation() { percentwlparen_unnamed_def(this, _, result) } + + string getText() { percentwlparen_unnamed_def(this, result, _) } +} + +class AmpersandUnnamed extends @ampersand_unnamed, Top, BinaryOperatorType { + override string toString() { result = "AmpersandUnnamed" } + + override Location getLocation() { ampersand_unnamed_def(this, _, result) } + + string getText() { ampersand_unnamed_def(this, result, _) } +} + +class AmpersandampersandUnnamed extends @ampersandampersand_unnamed, Top, BinaryOperatorType { + override string toString() { result = "AmpersandampersandUnnamed" } + + override Location getLocation() { ampersandampersand_unnamed_def(this, _, result) } + + string getText() { ampersandampersand_unnamed_def(this, result, _) } +} + +class AmpersandampersandequalUnnamed extends @ampersandampersandequal_unnamed, Top { + override string toString() { result = "AmpersandampersandequalUnnamed" } + + override Location getLocation() { ampersandampersandequal_unnamed_def(this, _, result) } + + string getText() { ampersandampersandequal_unnamed_def(this, result, _) } +} + +class AmpersanddotUnnamed extends @ampersanddot_unnamed, Top { + override string toString() { result = "AmpersanddotUnnamed" } + + override Location getLocation() { ampersanddot_unnamed_def(this, _, result) } + + string getText() { ampersanddot_unnamed_def(this, result, _) } +} + +class AmpersandequalUnnamed extends @ampersandequal_unnamed, Top { + override string toString() { result = "AmpersandequalUnnamed" } + + override Location getLocation() { ampersandequal_unnamed_def(this, _, result) } + + string getText() { ampersandequal_unnamed_def(this, result, _) } +} + +class LparenUnnamed extends @lparen_unnamed, Top { + override string toString() { result = "LparenUnnamed" } + + override Location getLocation() { lparen_unnamed_def(this, _, result) } + + string getText() { lparen_unnamed_def(this, result, _) } +} + +class RparenUnnamed extends @rparen_unnamed, Top { + override string toString() { result = "RparenUnnamed" } + + override Location getLocation() { rparen_unnamed_def(this, _, result) } + + string getText() { rparen_unnamed_def(this, result, _) } +} + +class StarUnnamed extends @star_unnamed, Top, BinaryOperatorType { + override string toString() { result = "StarUnnamed" } + + override Location getLocation() { star_unnamed_def(this, _, result) } + + string getText() { star_unnamed_def(this, result, _) } +} + +class StarstarUnnamed extends @starstar_unnamed, Top, BinaryOperatorType { + override string toString() { result = "StarstarUnnamed" } + + override Location getLocation() { starstar_unnamed_def(this, _, result) } + + string getText() { starstar_unnamed_def(this, result, _) } +} + +class StarstarequalUnnamed extends @starstarequal_unnamed, Top { + override string toString() { result = "StarstarequalUnnamed" } + + override Location getLocation() { starstarequal_unnamed_def(this, _, result) } + + string getText() { starstarequal_unnamed_def(this, result, _) } +} + +class StarequalUnnamed extends @starequal_unnamed, Top { + override string toString() { result = "StarequalUnnamed" } + + override Location getLocation() { starequal_unnamed_def(this, _, result) } + + string getText() { starequal_unnamed_def(this, result, _) } +} + +class PlusUnnamed extends @plus_unnamed, Top, BinaryOperatorType { + override string toString() { result = "PlusUnnamed" } + + override Location getLocation() { plus_unnamed_def(this, _, result) } + + string getText() { plus_unnamed_def(this, result, _) } +} + +class PlusequalUnnamed extends @plusequal_unnamed, Top { + override string toString() { result = "PlusequalUnnamed" } + + override Location getLocation() { plusequal_unnamed_def(this, _, result) } + + string getText() { plusequal_unnamed_def(this, result, _) } +} + +class PlusatUnnamed extends @plusat_unnamed, Top { + override string toString() { result = "PlusatUnnamed" } + + override Location getLocation() { plusat_unnamed_def(this, _, result) } + + string getText() { plusat_unnamed_def(this, result, _) } +} + +class CommaUnnamed extends @comma_unnamed, Top, WhenPatternType { + override string toString() { result = "CommaUnnamed" } + + override Location getLocation() { comma_unnamed_def(this, _, result) } + + string getText() { comma_unnamed_def(this, result, _) } +} + +class MinusUnnamed extends @minus_unnamed, Top, BinaryOperatorType { + override string toString() { result = "MinusUnnamed" } + + override Location getLocation() { minus_unnamed_def(this, _, result) } + + string getText() { minus_unnamed_def(this, result, _) } +} + +class MinusequalUnnamed extends @minusequal_unnamed, Top { + override string toString() { result = "MinusequalUnnamed" } + + override Location getLocation() { minusequal_unnamed_def(this, _, result) } + + string getText() { minusequal_unnamed_def(this, result, _) } +} + +class MinusrangleUnnamed extends @minusrangle_unnamed, Top { + override string toString() { result = "MinusrangleUnnamed" } + + override Location getLocation() { minusrangle_unnamed_def(this, _, result) } + + string getText() { minusrangle_unnamed_def(this, result, _) } +} + +class MinusatUnnamed extends @minusat_unnamed, Top { + override string toString() { result = "MinusatUnnamed" } + + override Location getLocation() { minusat_unnamed_def(this, _, result) } + + string getText() { minusat_unnamed_def(this, result, _) } +} + +class DotUnnamed extends @dot_unnamed, Top { + override string toString() { result = "DotUnnamed" } + + override Location getLocation() { dot_unnamed_def(this, _, result) } + + string getText() { dot_unnamed_def(this, result, _) } +} + +class DotdotUnnamed extends @dotdot_unnamed, Top { + override string toString() { result = "DotdotUnnamed" } + + override Location getLocation() { dotdot_unnamed_def(this, _, result) } + + string getText() { dotdot_unnamed_def(this, result, _) } +} + +class DotdotdotUnnamed extends @dotdotdot_unnamed, Top { + override string toString() { result = "DotdotdotUnnamed" } + + override Location getLocation() { dotdotdot_unnamed_def(this, _, result) } + + string getText() { dotdotdot_unnamed_def(this, result, _) } +} + +class SlashUnnamed extends @slash_unnamed, Top, BinaryOperatorType { + override string toString() { result = "SlashUnnamed" } + + override Location getLocation() { slash_unnamed_def(this, _, result) } + + string getText() { slash_unnamed_def(this, result, _) } +} + +class SlashequalUnnamed extends @slashequal_unnamed, Top { + override string toString() { result = "SlashequalUnnamed" } + + override Location getLocation() { slashequal_unnamed_def(this, _, result) } + + string getText() { slashequal_unnamed_def(this, result, _) } +} + +class ColonUnnamed extends @colon_unnamed, Top { + override string toString() { result = "ColonUnnamed" } + + override Location getLocation() { colon_unnamed_def(this, _, result) } + + string getText() { colon_unnamed_def(this, result, _) } +} + +class ColondquoteUnnamed extends @colondquote_unnamed, Top { + override string toString() { result = "ColondquoteUnnamed" } + + override Location getLocation() { colondquote_unnamed_def(this, _, result) } + + string getText() { colondquote_unnamed_def(this, result, _) } +} + +class ColoncolonUnnamed extends @coloncolon_unnamed, Top { + override string toString() { result = "ColoncolonUnnamed" } + + override Location getLocation() { coloncolon_unnamed_def(this, _, result) } + + string getText() { coloncolon_unnamed_def(this, result, _) } +} + +class SemicolonUnnamed extends @semicolon_unnamed, Top { + override string toString() { result = "SemicolonUnnamed" } + + override Location getLocation() { semicolon_unnamed_def(this, _, result) } + + string getText() { semicolon_unnamed_def(this, result, _) } +} + +class LangleUnnamed extends @langle_unnamed, Top, BinaryOperatorType { + override string toString() { result = "LangleUnnamed" } + + override Location getLocation() { langle_unnamed_def(this, _, result) } + + string getText() { langle_unnamed_def(this, result, _) } +} + +class LanglelangleUnnamed extends @langlelangle_unnamed, Top, BinaryOperatorType { + override string toString() { result = "LanglelangleUnnamed" } + + override Location getLocation() { langlelangle_unnamed_def(this, _, result) } + + string getText() { langlelangle_unnamed_def(this, result, _) } +} + +class LanglelangleequalUnnamed extends @langlelangleequal_unnamed, Top { + override string toString() { result = "LanglelangleequalUnnamed" } + + override Location getLocation() { langlelangleequal_unnamed_def(this, _, result) } + + string getText() { langlelangleequal_unnamed_def(this, result, _) } +} + +class LangleequalUnnamed extends @langleequal_unnamed, Top, BinaryOperatorType { + override string toString() { result = "LangleequalUnnamed" } + + override Location getLocation() { langleequal_unnamed_def(this, _, result) } + + string getText() { langleequal_unnamed_def(this, result, _) } +} + +class LangleequalrangleUnnamed extends @langleequalrangle_unnamed, Top, BinaryOperatorType { + override string toString() { result = "LangleequalrangleUnnamed" } + + override Location getLocation() { langleequalrangle_unnamed_def(this, _, result) } + + string getText() { langleequalrangle_unnamed_def(this, result, _) } +} + +class EqualUnnamed extends @equal_unnamed, Top { + override string toString() { result = "EqualUnnamed" } + + override Location getLocation() { equal_unnamed_def(this, _, result) } + + string getText() { equal_unnamed_def(this, result, _) } +} + +class EqualequalUnnamed extends @equalequal_unnamed, Top, BinaryOperatorType { + override string toString() { result = "EqualequalUnnamed" } + + override Location getLocation() { equalequal_unnamed_def(this, _, result) } + + string getText() { equalequal_unnamed_def(this, result, _) } +} + +class EqualequalequalUnnamed extends @equalequalequal_unnamed, Top, BinaryOperatorType { + override string toString() { result = "EqualequalequalUnnamed" } + + override Location getLocation() { equalequalequal_unnamed_def(this, _, result) } + + string getText() { equalequalequal_unnamed_def(this, result, _) } +} + +class EqualrangleUnnamed extends @equalrangle_unnamed, Top { + override string toString() { result = "EqualrangleUnnamed" } + + override Location getLocation() { equalrangle_unnamed_def(this, _, result) } + + string getText() { equalrangle_unnamed_def(this, result, _) } +} + +class EqualtildeUnnamed extends @equaltilde_unnamed, Top, BinaryOperatorType { + override string toString() { result = "EqualtildeUnnamed" } + + override Location getLocation() { equaltilde_unnamed_def(this, _, result) } + + string getText() { equaltilde_unnamed_def(this, result, _) } +} + +class RangleUnnamed extends @rangle_unnamed, Top, BinaryOperatorType { + override string toString() { result = "RangleUnnamed" } + + override Location getLocation() { rangle_unnamed_def(this, _, result) } + + string getText() { rangle_unnamed_def(this, result, _) } +} + +class RangleequalUnnamed extends @rangleequal_unnamed, Top, BinaryOperatorType { + override string toString() { result = "RangleequalUnnamed" } + + override Location getLocation() { rangleequal_unnamed_def(this, _, result) } + + string getText() { rangleequal_unnamed_def(this, result, _) } +} + +class RanglerangleUnnamed extends @ranglerangle_unnamed, Top, BinaryOperatorType { + override string toString() { result = "RanglerangleUnnamed" } + + override Location getLocation() { ranglerangle_unnamed_def(this, _, result) } + + string getText() { ranglerangle_unnamed_def(this, result, _) } +} + +class RanglerangleequalUnnamed extends @ranglerangleequal_unnamed, Top { + override string toString() { result = "RanglerangleequalUnnamed" } + + override Location getLocation() { ranglerangleequal_unnamed_def(this, _, result) } + + string getText() { ranglerangleequal_unnamed_def(this, result, _) } +} + +class QuestionUnnamed extends @question_unnamed, Top { + override string toString() { result = "QuestionUnnamed" } + + override Location getLocation() { question_unnamed_def(this, _, result) } + + string getText() { question_unnamed_def(this, result, _) } +} + +class BEGINUnnamed extends @b_e_g_i_n__unnamed, Top { + override string toString() { result = "BEGINUnnamed" } + + override Location getLocation() { b_e_g_i_n__unnamed_def(this, _, result) } + + string getText() { b_e_g_i_n__unnamed_def(this, result, _) } +} + +class ENDUnnamed extends @e_n_d__unnamed, Top { + override string toString() { result = "ENDUnnamed" } + + override Location getLocation() { e_n_d__unnamed_def(this, _, result) } + + string getText() { e_n_d__unnamed_def(this, result, _) } +} + +class LbracketUnnamed extends @lbracket_unnamed, Top { + override string toString() { result = "LbracketUnnamed" } + + override Location getLocation() { lbracket_unnamed_def(this, _, result) } + + string getText() { lbracket_unnamed_def(this, result, _) } +} + +class LbracketrbracketUnnamed extends @lbracketrbracket_unnamed, Top { + override string toString() { result = "LbracketrbracketUnnamed" } + + override Location getLocation() { lbracketrbracket_unnamed_def(this, _, result) } + + string getText() { lbracketrbracket_unnamed_def(this, result, _) } +} + +class LbracketrbracketequalUnnamed extends @lbracketrbracketequal_unnamed, Top { + override string toString() { result = "LbracketrbracketequalUnnamed" } + + override Location getLocation() { lbracketrbracketequal_unnamed_def(this, _, result) } + + string getText() { lbracketrbracketequal_unnamed_def(this, result, _) } +} + +class RbracketUnnamed extends @rbracket_unnamed, Top { + override string toString() { result = "RbracketUnnamed" } + + override Location getLocation() { rbracket_unnamed_def(this, _, result) } + + string getText() { rbracket_unnamed_def(this, result, _) } +} + +class CaretUnnamed extends @caret_unnamed, Top, BinaryOperatorType { + override string toString() { result = "CaretUnnamed" } + + override Location getLocation() { caret_unnamed_def(this, _, result) } + + string getText() { caret_unnamed_def(this, result, _) } +} + +class CaretequalUnnamed extends @caretequal_unnamed, Top { + override string toString() { result = "CaretequalUnnamed" } + + override Location getLocation() { caretequal_unnamed_def(this, _, result) } + + string getText() { caretequal_unnamed_def(this, result, _) } +} + +class UnderscoreENDUnnamed extends @underscore__e_n_d____unnamed, Top { + override string toString() { result = "UnderscoreENDUnnamed" } + + override Location getLocation() { underscore__e_n_d____unnamed_def(this, _, result) } + + string getText() { underscore__e_n_d____unnamed_def(this, result, _) } +} + +class BacktickUnnamed extends @backtick_unnamed, Top { + override string toString() { result = "BacktickUnnamed" } + + override Location getLocation() { backtick_unnamed_def(this, _, result) } + + string getText() { backtick_unnamed_def(this, result, _) } +} + +class AliasUnnamed extends @alias_unnamed, Top { + override string toString() { result = "AliasUnnamed" } + + override Location getLocation() { alias_unnamed_def(this, _, result) } + + string getText() { alias_unnamed_def(this, result, _) } +} + +class AndUnnamed extends @and_unnamed, Top, BinaryOperatorType { + override string toString() { result = "AndUnnamed" } + + override Location getLocation() { and_unnamed_def(this, _, result) } + + string getText() { and_unnamed_def(this, result, _) } +} + +class BeginUnnamed extends @begin_unnamed, Top { + override string toString() { result = "BeginUnnamed" } + + override Location getLocation() { begin_unnamed_def(this, _, result) } + + string getText() { begin_unnamed_def(this, result, _) } +} + +class BreakUnnamed extends @break_unnamed, Top { + override string toString() { result = "BreakUnnamed" } + + override Location getLocation() { break_unnamed_def(this, _, result) } + + string getText() { break_unnamed_def(this, result, _) } +} + +class CaseUnnamed extends @case_unnamed, Top { + override string toString() { result = "CaseUnnamed" } + + override Location getLocation() { case_unnamed_def(this, _, result) } + + string getText() { case_unnamed_def(this, result, _) } +} + +class Character extends @character, Top, UnderscorePrimary { + override string toString() { result = "Character" } + + override Location getLocation() { character_def(this, _, result) } + + string getText() { character_def(this, result, _) } +} + +class ClassUnnamed extends @class_unnamed, Top { + override string toString() { result = "ClassUnnamed" } + + override Location getLocation() { class_unnamed_def(this, _, result) } + + string getText() { class_unnamed_def(this, result, _) } +} + +class ClassVariable extends @class_variable, Top, UnderscoreMethodName, UnderscoreVariable { + override string toString() { result = "ClassVariable" } + + override Location getLocation() { class_variable_def(this, _, result) } + + string getText() { class_variable_def(this, result, _) } +} + +class Complex extends @complex, Top, UnderscorePrimary { + override string toString() { result = "Complex" } + + override Location getLocation() { complex_def(this, _, result) } + + string getText() { complex_def(this, result, _) } +} + +class Constant extends @constant, Top, CallMethodType, ClassNameType, ModuleNameType, + ScopeResolutionNameType, UnderscoreMethodName, UnderscoreVariable { + override string toString() { result = "Constant" } + + override Location getLocation() { constant_def(this, _, result) } + + string getText() { constant_def(this, result, _) } +} + +class DefUnnamed extends @def_unnamed, Top { + override string toString() { result = "DefUnnamed" } + + override Location getLocation() { def_unnamed_def(this, _, result) } + + string getText() { def_unnamed_def(this, result, _) } +} + +class DefinedquestionUnnamed extends @definedquestion_unnamed, Top { + override string toString() { result = "DefinedquestionUnnamed" } + + override Location getLocation() { definedquestion_unnamed_def(this, _, result) } + + string getText() { definedquestion_unnamed_def(this, result, _) } +} + +class DoUnnamed extends @do_unnamed, Top { + override string toString() { result = "DoUnnamed" } + + override Location getLocation() { do_unnamed_def(this, _, result) } + + string getText() { do_unnamed_def(this, result, _) } +} + +class ElseUnnamed extends @else_unnamed, Top { + override string toString() { result = "ElseUnnamed" } + + override Location getLocation() { else_unnamed_def(this, _, result) } + + string getText() { else_unnamed_def(this, result, _) } +} + +class ElsifUnnamed extends @elsif_unnamed, Top { + override string toString() { result = "ElsifUnnamed" } + + override Location getLocation() { elsif_unnamed_def(this, _, result) } + + string getText() { elsif_unnamed_def(this, result, _) } +} + +class EndUnnamed extends @end_unnamed, Top { + override string toString() { result = "EndUnnamed" } + + override Location getLocation() { end_unnamed_def(this, _, result) } + + string getText() { end_unnamed_def(this, result, _) } +} + +class EnsureUnnamed extends @ensure_unnamed, Top { + override string toString() { result = "EnsureUnnamed" } + + override Location getLocation() { ensure_unnamed_def(this, _, result) } + + string getText() { ensure_unnamed_def(this, result, _) } +} + +class EscapeSequence extends @escape_sequence, Top, BareStringChildType, BareSymbolChildType, + RegexChildType, StringChildType, SubshellChildType, SymbolChildType { + override string toString() { result = "EscapeSequence" } + + override Location getLocation() { escape_sequence_def(this, _, result) } + + string getText() { escape_sequence_def(this, result, _) } +} + +class False extends @false, Top, UnderscoreLhs { + override string toString() { result = "False" } + + override Location getLocation() { false_def(this, _, result) } + + string getText() { false_def(this, result, _) } +} + +class Float extends @float__, Top, UnaryChildType, UnderscorePrimary { + override string toString() { result = "Float" } + + override Location getLocation() { float_def(this, _, result) } + + string getText() { float_def(this, result, _) } +} + +class ForUnnamed extends @for_unnamed, Top { + override string toString() { result = "ForUnnamed" } + + override Location getLocation() { for_unnamed_def(this, _, result) } + + string getText() { for_unnamed_def(this, result, _) } +} + +class GlobalVariable extends @global_variable, Top, UnderscoreMethodName, UnderscoreVariable { + override string toString() { result = "GlobalVariable" } + + override Location getLocation() { global_variable_def(this, _, result) } + + string getText() { global_variable_def(this, result, _) } +} + +class HeredocBeginning extends @heredoc_beginning, Top, UnderscorePrimary { + override string toString() { result = "HeredocBeginning" } + + override Location getLocation() { heredoc_beginning_def(this, _, result) } + + string getText() { heredoc_beginning_def(this, result, _) } +} + +class HeredocEnd extends @heredoc_end, Top { + override string toString() { result = "HeredocEnd" } + + override Location getLocation() { heredoc_end_def(this, _, result) } + + string getText() { heredoc_end_def(this, result, _) } +} + +class Identifier extends @identifier, Top, BlockParametersChildType, CallMethodType, + DestructuredParameterChildType, LambdaParametersChildType, MethodParametersChildType, + ScopeResolutionNameType, UnderscoreMethodName, UnderscoreVariable { + override string toString() { result = "Identifier" } + + override Location getLocation() { identifier_def(this, _, result) } + + string getText() { identifier_def(this, result, _) } +} + +class IfUnnamed extends @if_unnamed, Top { + override string toString() { result = "IfUnnamed" } + + override Location getLocation() { if_unnamed_def(this, _, result) } + + string getText() { if_unnamed_def(this, result, _) } +} + +class InUnnamed extends @in_unnamed, Top { + override string toString() { result = "InUnnamed" } + + override Location getLocation() { in_unnamed_def(this, _, result) } + + string getText() { in_unnamed_def(this, result, _) } +} + +class InstanceVariable extends @instance_variable, Top, UnderscoreMethodName, UnderscoreVariable { + override string toString() { result = "InstanceVariable" } + + override Location getLocation() { instance_variable_def(this, _, result) } + + string getText() { instance_variable_def(this, result, _) } +} + +class Integer extends @integer, Top, UnaryChildType, UnderscorePrimary { + override string toString() { result = "Integer" } + + override Location getLocation() { integer_def(this, _, result) } + + string getText() { integer_def(this, result, _) } +} + +class ModuleUnnamed extends @module_unnamed, Top { + override string toString() { result = "ModuleUnnamed" } + + override Location getLocation() { module_unnamed_def(this, _, result) } + + string getText() { module_unnamed_def(this, result, _) } +} + +class NextUnnamed extends @next_unnamed, Top { + override string toString() { result = "NextUnnamed" } + + override Location getLocation() { next_unnamed_def(this, _, result) } + + string getText() { next_unnamed_def(this, result, _) } +} + +class Nil extends @nil, Top, UnderscoreLhs { + override string toString() { result = "Nil" } + + override Location getLocation() { nil_def(this, _, result) } + + string getText() { nil_def(this, result, _) } +} + +class NotUnnamed extends @not_unnamed, Top { + override string toString() { result = "NotUnnamed" } + + override Location getLocation() { not_unnamed_def(this, _, result) } + + string getText() { not_unnamed_def(this, result, _) } +} + +class OrUnnamed extends @or_unnamed, Top, BinaryOperatorType { + override string toString() { result = "OrUnnamed" } + + override Location getLocation() { or_unnamed_def(this, _, result) } + + string getText() { or_unnamed_def(this, result, _) } +} + +class RUnnamed extends @r_unnamed, Top { + override string toString() { result = "RUnnamed" } + + override Location getLocation() { r_unnamed_def(this, _, result) } + + string getText() { r_unnamed_def(this, result, _) } +} + +class RedoUnnamed extends @redo_unnamed, Top { + override string toString() { result = "RedoUnnamed" } + + override Location getLocation() { redo_unnamed_def(this, _, result) } + + string getText() { redo_unnamed_def(this, result, _) } +} + +class RescueUnnamed extends @rescue_unnamed, Top { + override string toString() { result = "RescueUnnamed" } + + override Location getLocation() { rescue_unnamed_def(this, _, result) } + + string getText() { rescue_unnamed_def(this, result, _) } +} + +class RetryUnnamed extends @retry_unnamed, Top { + override string toString() { result = "RetryUnnamed" } + + override Location getLocation() { retry_unnamed_def(this, _, result) } + + string getText() { retry_unnamed_def(this, result, _) } +} + +class ReturnUnnamed extends @return_unnamed, Top { + override string toString() { result = "ReturnUnnamed" } + + override Location getLocation() { return_unnamed_def(this, _, result) } + + string getText() { return_unnamed_def(this, result, _) } +} + +class Self extends @self, Top, UnderscoreVariable { + override string toString() { result = "Self" } + + override Location getLocation() { self_def(this, _, result) } + + string getText() { self_def(this, result, _) } +} + +class Super extends @super, Top, UnderscoreVariable { + override string toString() { result = "Super" } + + override Location getLocation() { super_def(this, _, result) } + + string getText() { super_def(this, result, _) } +} + +class ThenUnnamed extends @then_unnamed, Top { + override string toString() { result = "ThenUnnamed" } + + override Location getLocation() { then_unnamed_def(this, _, result) } + + string getText() { then_unnamed_def(this, result, _) } +} + +class True extends @true, Top, UnderscoreLhs { + override string toString() { result = "True" } + + override Location getLocation() { true_def(this, _, result) } + + string getText() { true_def(this, result, _) } +} + +class UndefUnnamed extends @undef_unnamed, Top { + override string toString() { result = "UndefUnnamed" } + + override Location getLocation() { undef_unnamed_def(this, _, result) } + + string getText() { undef_unnamed_def(this, result, _) } +} + +class Uninterpreted extends @uninterpreted, Top, ProgramChildType { + override string toString() { result = "Uninterpreted" } + + override Location getLocation() { uninterpreted_def(this, _, result) } + + string getText() { uninterpreted_def(this, result, _) } +} + +class UnlessUnnamed extends @unless_unnamed, Top { + override string toString() { result = "UnlessUnnamed" } + + override Location getLocation() { unless_unnamed_def(this, _, result) } + + string getText() { unless_unnamed_def(this, result, _) } +} + +class UntilUnnamed extends @until_unnamed, Top { + override string toString() { result = "UntilUnnamed" } + + override Location getLocation() { until_unnamed_def(this, _, result) } + + string getText() { until_unnamed_def(this, result, _) } +} + +class WhenUnnamed extends @when_unnamed, Top { + override string toString() { result = "WhenUnnamed" } + + override Location getLocation() { when_unnamed_def(this, _, result) } + + string getText() { when_unnamed_def(this, result, _) } +} + +class WhileUnnamed extends @while_unnamed, Top { + override string toString() { result = "WhileUnnamed" } + + override Location getLocation() { while_unnamed_def(this, _, result) } + + string getText() { while_unnamed_def(this, result, _) } +} + +class YieldUnnamed extends @yield_unnamed, Top { + override string toString() { result = "YieldUnnamed" } + + override Location getLocation() { yield_unnamed_def(this, _, result) } + + string getText() { yield_unnamed_def(this, result, _) } +} + +class LbraceUnnamed extends @lbrace_unnamed, Top { + override string toString() { result = "LbraceUnnamed" } + + override Location getLocation() { lbrace_unnamed_def(this, _, result) } + + string getText() { lbrace_unnamed_def(this, result, _) } +} + +class PipeUnnamed extends @pipe_unnamed, Top, BinaryOperatorType { + override string toString() { result = "PipeUnnamed" } + + override Location getLocation() { pipe_unnamed_def(this, _, result) } + + string getText() { pipe_unnamed_def(this, result, _) } +} + +class PipeequalUnnamed extends @pipeequal_unnamed, Top { + override string toString() { result = "PipeequalUnnamed" } + + override Location getLocation() { pipeequal_unnamed_def(this, _, result) } + + string getText() { pipeequal_unnamed_def(this, result, _) } +} + +class PipepipeUnnamed extends @pipepipe_unnamed, Top, BinaryOperatorType { + override string toString() { result = "PipepipeUnnamed" } + + override Location getLocation() { pipepipe_unnamed_def(this, _, result) } + + string getText() { pipepipe_unnamed_def(this, result, _) } +} + +class PipepipeequalUnnamed extends @pipepipeequal_unnamed, Top { + override string toString() { result = "PipepipeequalUnnamed" } + + override Location getLocation() { pipepipeequal_unnamed_def(this, _, result) } + + string getText() { pipepipeequal_unnamed_def(this, result, _) } +} + +class RbraceUnnamed extends @rbrace_unnamed, Top { + override string toString() { result = "RbraceUnnamed" } + + override Location getLocation() { rbrace_unnamed_def(this, _, result) } + + string getText() { rbrace_unnamed_def(this, result, _) } +} + +class TildeUnnamed extends @tilde_unnamed, Top { + override string toString() { result = "TildeUnnamed" } + + override Location getLocation() { tilde_unnamed_def(this, _, result) } + + string getText() { tilde_unnamed_def(this, result, _) } +}