private import codeql_ruby.AST private import internal.Expr /** * An expression. * * This is the root QL class for all expressions. */ class Expr extends Stmt { override Expr::Range range; Expr() { this = range } } /** * A literal. * * This is the QL root class for all literals. */ class Literal extends Expr { override Literal::Range range; /** Gets the source text for this literal, if it is constant. */ final string getValueText() { result = range.getValueText() } } /** * An integer literal. * ```rb * x = 123 * y = 0xff * ``` */ class IntegerLiteral extends Literal, @token_integer { final override IntegerLiteral::Range range; final override string getAPrimaryQlClass() { result = "IntegerLiteral" } } /** A `nil` literal. */ class NilLiteral extends Literal, @token_nil { final override NilLiteral::Range range; final override string getAPrimaryQlClass() { result = "NilLiteral" } } /** * A Boolean literal. * ```rb * true * false * TRUE * FALSE * ``` */ class BooleanLiteral extends Literal, BooleanLiteral::DbUnion { final override BooleanLiteral::Range range; final override string getAPrimaryQlClass() { result = "BooleanLiteral" } /** Holds if the Boolean literal is `true` or `TRUE`. */ predicate isTrue() { range.isTrue() } /** Holds if the Boolean literal is `false` or `FALSE`. */ predicate isFalse() { range.isFalse() } } // TODO: expand this. It's a minimal placeholder so we can test `=~` and `!~`. class RegexLiteral extends Literal, @regex { final override RegexLiteral::Range range; final override string getAPrimaryQlClass() { result = "RegexLiteral" } } /** * A string literal. * ```rb * 'hello' * "hello, #{name}" * ``` * TODO: expand this minimal placeholder. */ class StringLiteral extends Literal, @string__ { final override StringLiteral::Range range; final override string getAPrimaryQlClass() { result = "StringLiteral" } } /** * A symbol literal. * ```rb * :foo * :"foo bar" * :"foo bar #{baz}" * ``` * TODO: expand this minimal placeholder. */ class SymbolLiteral extends Literal { final override SymbolLiteral::Range range; final override string getAPrimaryQlClass() { result = "SymbolLiteral" } } /** A sequence of expressions. */ class StmtSequence extends Expr { override StmtSequence::Range range; override string getAPrimaryQlClass() { result = "StmtSequence" } /** Gets the `n`th statement in this sequence. */ final Stmt getStmt(int n) { result = range.getStmt(n) } /** Gets a statement in this sequence. */ final Stmt getAStmt() { result = this.getStmt(_) } /** Gets the last expression in this sequence, if any. */ final Expr getLastExpr() { result = this.getStmt(this.getNumberOfStatements() - 1) } /** Gets the number of statements in this sequence. */ final int getNumberOfStatements() { result = count(this.getAStmt()) } /** Holds if this sequence has no statements. */ final predicate isEmpty() { this.getNumberOfStatements() = 0 } } /** * A sequence of statements representing the body of a method, class, module, * or do-block. That is, any body that may also include rescue/ensure/else * statements. */ class BodyStatement extends StmtSequence { override BodyStatement::Range range; /** Gets the `else` block in this block, if any. */ final StmtSequence getElse() { result = range.getElse() } /** Gets the `ensure` block in this block, if any. */ final StmtSequence getEnsure() { result = range.getEnsure() } final predicate hasEnsure() { exists(this.getEnsure()) } } /** * A parenthesized expression sequence, typically containing a single expression: * ```rb * (x + 1) * ``` * However, they can also contain multiple expressions (the value of the parenthesized * expression is the last expression): * ```rb * (foo; bar) * ``` * or even an empty sequence (value is `nil`): * ```rb * () * ``` */ class ParenthesizedExpr extends StmtSequence, @parenthesized_statements { final override ParenthesizedExpr::Range range; final override string getAPrimaryQlClass() { result = "ParenthesizedExpr" } } /** * A pair expression. For example, in a hash: * ```rb * { foo: bar } * ``` * Or a keyword argument: * ```rb * baz(qux: 1) * ``` */ class Pair extends Expr, @pair { final override Pair::Range range; final override string getAPrimaryQlClass() { result = "Pair" } /** * Gets the key expression of this pair. For example, the `SymbolLiteral` * representing the keyword `foo` in the following example: * ```rb * bar(foo: 123) * ``` * Or the `StringLiteral` for `'foo'` in the following hash pair: * ```rb * { 'foo' => 123 } * ``` */ final Expr getKey() { result = range.getKey() } /** * Gets the value expression of this pair. For example, the `InteralLiteral` * 123 in the following hash pair: * ```rb * { 'foo' => 123 } * ``` */ final Expr getValue() { result = range.getValue() } }