mirror of
https://github.com/github/codeql.git
synced 2026-02-20 08:53:49 +01:00
398 lines
9.3 KiB
Plaintext
398 lines
9.3 KiB
Plaintext
private import codeql_ruby.AST
|
|
private import internal.Control
|
|
|
|
/**
|
|
* A control expression that can be any of the following:
|
|
* - `case`
|
|
* - `if`/`unless` (including expression-modifier variants)
|
|
* - ternary-if (`?:`)
|
|
* - `while`/`until` (including expression-modifier variants)
|
|
* - `for`
|
|
*/
|
|
class ControlExpr extends Expr {
|
|
override ControlExpr::Range range;
|
|
}
|
|
|
|
/**
|
|
* A conditional expression: `if`/`unless` (including expression-modifier
|
|
* variants), and ternary-if (`?:`) expressions.
|
|
*/
|
|
class ConditionalExpr extends ControlExpr {
|
|
override ConditionalExpr::Range range;
|
|
|
|
/**
|
|
* Gets the condition expression. For example, the result is `foo` in the
|
|
* following:
|
|
* ```rb
|
|
* if foo
|
|
* bar = 1
|
|
* end
|
|
* ```
|
|
*/
|
|
final Expr getCondition() { result = range.getCondition() }
|
|
|
|
/**
|
|
* Gets the branch of this conditional expression that is taken when the
|
|
* condition evaluates to `cond`, if any.
|
|
*/
|
|
Stmt getBranch(boolean cond) { result = range.getBranch(cond) }
|
|
}
|
|
|
|
/**
|
|
* An `if` or `elsif` expression.
|
|
* ```rb
|
|
* if x
|
|
* a += 1
|
|
* elsif y
|
|
* a += 2
|
|
* end
|
|
* ```
|
|
*/
|
|
class IfExpr extends ConditionalExpr {
|
|
override IfExpr::Range range;
|
|
|
|
final override string getAPrimaryQlClass() { result = "IfExpr" }
|
|
|
|
/** Holds if this is an `elsif` expression. */
|
|
final predicate isElsif() { this instanceof @elsif }
|
|
|
|
/** Gets the 'then' branch of this `if`/`elsif` expression. */
|
|
final Stmt getThen() { result = range.getThen() }
|
|
|
|
/**
|
|
* Gets the `elsif`/`else` branch of this `if`/`elsif` expression, if any. In
|
|
* the following example, the result is a `StmtSequence` containing `b`.
|
|
* ```rb
|
|
* if foo
|
|
* a
|
|
* else
|
|
* b
|
|
* end
|
|
* ```
|
|
* But there is no result for the following:
|
|
* ```rb
|
|
* if foo
|
|
* a
|
|
* end
|
|
* ```
|
|
* There can be at most one result, since `elsif` branches nest. In the
|
|
* following example, `ifExpr.getElse()` returns an `ElsifExpr`, and the
|
|
* `else` branch is nested inside that. To get the `StmtSequence` for the
|
|
* `else` branch, i.e. the one containing `c`, use
|
|
* `getElse().(ElsifExpr).getElse()`.
|
|
* ```rb
|
|
* if foo
|
|
* a
|
|
* elsif bar
|
|
* b
|
|
* else
|
|
* c
|
|
* end
|
|
* ```
|
|
*/
|
|
final Stmt getElse() { result = range.getElse() }
|
|
}
|
|
|
|
/**
|
|
* An `unless` expression.
|
|
* ```rb
|
|
* unless x == 0
|
|
* y /= x
|
|
* end
|
|
* ```
|
|
*/
|
|
class UnlessExpr extends ConditionalExpr, @unless {
|
|
final override UnlessExpr::Range range;
|
|
|
|
final override string getAPrimaryQlClass() { result = "UnlessExpr" }
|
|
|
|
/**
|
|
* Gets the 'then' branch of this `unless` expression. In the following
|
|
* example, the result is the `StmtSequence` containing `foo`.
|
|
* ```rb
|
|
* unless a == b then
|
|
* foo
|
|
* else
|
|
* bar
|
|
* end
|
|
* ```
|
|
*/
|
|
final Stmt getThen() { result = range.getThen() }
|
|
|
|
/**
|
|
* Gets the 'else' branch of this `unless` expression. In the following
|
|
* example, the result is the `StmtSequence` containing `bar`.
|
|
* ```rb
|
|
* unless a == b then
|
|
* foo
|
|
* else
|
|
* bar
|
|
* end
|
|
* ```
|
|
*/
|
|
final Stmt getElse() { result = range.getElse() }
|
|
}
|
|
|
|
/**
|
|
* An expression modified using `if`.
|
|
* ```rb
|
|
* foo if bar
|
|
* ```
|
|
*/
|
|
class IfModifierExpr extends ConditionalExpr, @if_modifier {
|
|
final override IfModifierExpr::Range range;
|
|
|
|
final override string getAPrimaryQlClass() { result = "IfModifierExpr" }
|
|
|
|
/**
|
|
* Gets the expression that is conditionally evaluated. In the following
|
|
* example, the result is the `Expr` for `foo`.
|
|
* ```rb
|
|
* foo if bar
|
|
* ```
|
|
*/
|
|
final Stmt getBody() { result = range.getBody() }
|
|
}
|
|
|
|
/**
|
|
* An expression modified using `unless`.
|
|
* ```rb
|
|
* y /= x unless x == 0
|
|
* ```
|
|
*/
|
|
class UnlessModifierExpr extends ConditionalExpr, @unless_modifier {
|
|
final override UnlessModifierExpr::Range range;
|
|
|
|
final override string getAPrimaryQlClass() { result = "UnlessModifierExpr" }
|
|
|
|
/**
|
|
* Gets the expression that is conditionally evaluated. In the following
|
|
* example, the result is the `Expr` for `foo`.
|
|
* ```rb
|
|
* foo unless bar
|
|
* ```
|
|
*/
|
|
final Stmt getBody() { result = range.getBody() }
|
|
}
|
|
|
|
/**
|
|
* A conditional expression using the ternary (`?:`) operator.
|
|
* ```rb
|
|
* (a > b) ? a : b
|
|
* ```
|
|
*/
|
|
class TernaryIfExpr extends ConditionalExpr, @conditional {
|
|
final override TernaryIfExpr::Range range;
|
|
|
|
final override string getAPrimaryQlClass() { result = "TernaryIfExpr" }
|
|
|
|
/** Gets the 'then' branch of this ternary if expression. */
|
|
final Stmt getThen() { result = range.getThen() }
|
|
|
|
/** Gets the 'else' branch of this ternary if expression. */
|
|
final Stmt getElse() { result = range.getElse() }
|
|
}
|
|
|
|
class CaseExpr extends ControlExpr, @case__ {
|
|
final override CaseExpr::Range range;
|
|
|
|
final override string getAPrimaryQlClass() { result = "CaseExpr" }
|
|
|
|
/**
|
|
* Gets the expression being compared, if any. For example, `foo` in the following example.
|
|
* ```rb
|
|
* case foo
|
|
* when 0
|
|
* puts 'zero'
|
|
* when 1
|
|
* puts 'one'
|
|
* end
|
|
* ```
|
|
* There is no result for the following example:
|
|
* ```rb
|
|
* case
|
|
* when a then 0
|
|
* when b then 1
|
|
* else 2
|
|
* end
|
|
* ```
|
|
*/
|
|
final Expr getValue() { result = range.getValue() }
|
|
|
|
/**
|
|
* Gets the `n`th branch of this case expression, either a `WhenExpr` or a
|
|
* `StmtSequence`.
|
|
*/
|
|
final Expr getBranch(int n) { result = range.getBranch(n) }
|
|
|
|
/**
|
|
* Gets a branch of this case expression, either a `WhenExpr` or an
|
|
* `ElseExpr`.
|
|
*/
|
|
final Expr getABranch() { result = this.getBranch(_) }
|
|
|
|
/** Gets a `when` branch of this case expression. */
|
|
final WhenExpr getAWhenBranch() { result = getABranch() }
|
|
|
|
/** Gets the `else` branch of this case expression, if any. */
|
|
final StmtSequence getElseBranch() { result = getABranch() }
|
|
|
|
/**
|
|
* Gets the number of branches of this case expression.
|
|
*/
|
|
final int getNumberOfBranches() { result = count(this.getBranch(_)) }
|
|
}
|
|
|
|
/**
|
|
* A `when` branch of a `case` expression.
|
|
* ```rb
|
|
* case
|
|
* when a > b then x
|
|
* end
|
|
* ```
|
|
*/
|
|
class WhenExpr extends Expr, @when {
|
|
final override WhenExpr::Range range;
|
|
|
|
final override string getAPrimaryQlClass() { result = "WhenExpr" }
|
|
|
|
/** Gets the body of this case-when expression. */
|
|
final Stmt getBody() { result = range.getBody() }
|
|
|
|
/**
|
|
* Gets the `n`th pattern (or condition) in this case-when expression. In the
|
|
* following example, the 0th pattern is `x`, the 1st pattern is `y`, and the
|
|
* 2nd pattern is `z`.
|
|
* ```rb
|
|
* case foo
|
|
* when x, y, z
|
|
* puts 'x/y/z'
|
|
* end
|
|
* ```
|
|
*/
|
|
final Expr getPattern(int n) { result = range.getPattern(n) }
|
|
|
|
/**
|
|
* Gets a pattern (or condition) in this case-when expression.
|
|
*/
|
|
final Expr getAPattern() { result = this.getPattern(_) }
|
|
|
|
/**
|
|
* Gets the number of patterns in this case-when expression.
|
|
*/
|
|
final int getNumberOfPatterns() { result = count(this.getPattern(_)) }
|
|
}
|
|
|
|
/**
|
|
* A loop. That is, a `for` loop, a `while` or `until` loop, or their
|
|
* expression-modifier variants.
|
|
*/
|
|
class Loop extends ControlExpr {
|
|
override Loop::Range range;
|
|
|
|
/** Gets the body of this loop. */
|
|
Stmt getBody() { result = range.getBody() }
|
|
}
|
|
|
|
/**
|
|
* A loop using a condition expression. That is, a `while` or `until` loop, or
|
|
* their expression-modifier variants.
|
|
*/
|
|
class ConditionalLoop extends Loop {
|
|
override ConditionalLoop::Range range;
|
|
|
|
/** Gets the condition expression of this loop. */
|
|
final Expr getCondition() { result = range.getCondition() }
|
|
}
|
|
|
|
/**
|
|
* A `while` loop.
|
|
* ```rb
|
|
* while a < b
|
|
* p a
|
|
* a += 2
|
|
* end
|
|
* ```
|
|
*/
|
|
class WhileExpr extends ConditionalLoop, @while {
|
|
final override WhileExpr::Range range;
|
|
|
|
final override string getAPrimaryQlClass() { result = "WhileExpr" }
|
|
|
|
/** Gets the body of this `while` loop. */
|
|
final override Stmt getBody() { result = range.getBody() }
|
|
}
|
|
|
|
/**
|
|
* An `until` loop.
|
|
* ```rb
|
|
* until a >= b
|
|
* p a
|
|
* a += 1
|
|
* end
|
|
* ```
|
|
*/
|
|
class UntilExpr extends ConditionalLoop, @until {
|
|
final override UntilExpr::Range range;
|
|
|
|
final override string getAPrimaryQlClass() { result = "UntilExpr" }
|
|
|
|
/** Gets the body of this `until` loop. */
|
|
final override Stmt getBody() { result = range.getBody() }
|
|
}
|
|
|
|
/**
|
|
* An expression looped using the `while` modifier.
|
|
* ```rb
|
|
* foo while bar
|
|
* ```
|
|
*/
|
|
class WhileModifierExpr extends ConditionalLoop, @while_modifier {
|
|
final override WhileModifierExpr::Range range;
|
|
|
|
final override string getAPrimaryQlClass() { result = "WhileModifierExpr" }
|
|
}
|
|
|
|
/**
|
|
* An expression looped using the `until` modifier.
|
|
* ```rb
|
|
* foo until bar
|
|
* ```
|
|
*/
|
|
class UntilModifierExpr extends ConditionalLoop, @until_modifier {
|
|
final override UntilModifierExpr::Range range;
|
|
|
|
final override string getAPrimaryQlClass() { result = "UntilModifierExpr" }
|
|
}
|
|
|
|
/**
|
|
* A `for` loop.
|
|
* ```rb
|
|
* for val in 1..n
|
|
* sum += val
|
|
* end
|
|
* ```
|
|
*/
|
|
class ForExpr extends Loop, @for {
|
|
final override ForExpr::Range range;
|
|
|
|
final override string getAPrimaryQlClass() { result = "ForExpr" }
|
|
|
|
/** Gets the body of this `for` loop. */
|
|
final override Stmt getBody() { result = range.getBody() }
|
|
|
|
/** Gets the pattern representing the iteration argument. */
|
|
final Pattern getPattern() { result = range.getPattern() }
|
|
|
|
/**
|
|
* Gets the value being iterated over. In the following example, the result
|
|
* is the expression `1..10`:
|
|
* ```rb
|
|
* for n in 1..10 do
|
|
* puts n
|
|
* end
|
|
* ```
|
|
*/
|
|
final Expr getValue() { result = range.getValue() }
|
|
}
|