diff --git a/ql/src/codeql_ruby/AST.qll b/ql/src/codeql_ruby/AST.qll index d64e6d6f1b5..11f201ac6dd 100644 --- a/ql/src/codeql_ruby/AST.qll +++ b/ql/src/codeql_ruby/AST.qll @@ -18,11 +18,7 @@ private import ast.internal.AST * A node in the abstract syntax tree. This class is the base class for all Ruby * program elements. */ -class AstNode extends @ast_node { - AstNode::Range range; - - AstNode() { range = this } - +class AstNode extends TAstNode { /** * Gets the name of a primary CodeQL class to which this node belongs. * @@ -33,14 +29,22 @@ class AstNode extends @ast_node { string getAPrimaryQlClass() { result = "???" } /** Gets a textual representation of this node. */ - final string toString() { result = range.toString() } + cached + string toString() { none() } /** Gets the location of this node. */ - final Location getLocation() { result = range.getLocation() } + Location getLocation() { result = toGenerated(this).getLocation() } /** Gets a child node of this `AstNode`. */ - final AstNode getAChild() { range.child(_, result) } + final AstNode getAChild() { result = this.getAChild(_) } /** Gets the parent of this `AstNode`, if this node is not a root node. */ final AstNode getParent() { result.getAChild() = this } + + /** + * Gets a child of this node, which can also be retrieved using a predicate + * named `pred`. + */ + cached + AstNode getAChild(string pred) { none() } } diff --git a/ql/src/codeql_ruby/ast/Call.qll b/ql/src/codeql_ruby/ast/Call.qll index c7a73c1fa7e..b38b2b37263 100644 --- a/ql/src/codeql_ruby/ast/Call.qll +++ b/ql/src/codeql_ruby/ast/Call.qll @@ -1,12 +1,11 @@ private import codeql_ruby.AST -private import internal.Call +private import internal.AST +private import internal.TreeSitter /** * A call. */ -class Call extends Expr { - override Call::Range range; - +class Call extends Expr, TCall { override string getAPrimaryQlClass() { result = "Call" } /** @@ -21,7 +20,7 @@ class Call extends Expr { * yield 0, bar: 1 * ``` */ - final Expr getArgument(int n) { result = range.getArgument(n) } + Expr getArgument(int n) { none() } /** * Gets an argument of this method call. @@ -48,14 +47,27 @@ class Call extends Expr { * Gets the number of arguments of this method call. */ final int getNumberOfArguments() { result = count(this.getAnArgument()) } + + override AstNode getAChild(string pred) { pred = "getArgument" and result = this.getArgument(_) } +} + +bindingset[s] +private string getMethodName(MethodCall mc, string s) { + ( + not mc instanceof LhsExpr + or + mc.getParent() instanceof AssignOperation + ) and + result = s + or + mc instanceof LhsExpr and + result = s + "=" } /** * A method call. */ -class MethodCall extends Call { - override MethodCall::Range range; - +class MethodCall extends Call, TMethodCall { override string getAPrimaryQlClass() { result = "MethodCall" } /** @@ -71,7 +83,7 @@ class MethodCall extends Call { * the call to `qux` is the `Expr` for `Baz`; for the call to `corge` there * is no result. */ - final Expr getReceiver() { result = range.getReceiver() } + Expr getReceiver() { none() } /** * Gets the name of the method being called. For example, in: @@ -82,7 +94,7 @@ class MethodCall extends Call { * * the result is `"bar"`. */ - final string getMethodName() { result = range.getMethodName() } + string getMethodName() { none() } /** * Gets the block of this method call, if any. @@ -90,7 +102,67 @@ class MethodCall extends Call { * foo.each { |x| puts x } * ``` */ - final Block getBlock() { result = range.getBlock() } + Block getBlock() { none() } + + override string toString() { result = "call to " + concat(this.getMethodName(), "/") } + + final override AstNode getAChild(string pred) { + result = Call.super.getAChild(pred) + or + pred = "getReceiver" and result = this.getReceiver() + or + pred = "getBlock" and result = this.getBlock() + } +} + +private class IdentifierMethodCall extends MethodCall, TIdentifierMethodCall { + private Generated::Identifier g; + + IdentifierMethodCall() { this = TIdentifierMethodCall(g) } + + final override string getMethodName() { result = getMethodName(this, g.getValue()) } +} + +private class ScopeResolutionMethodCall extends MethodCall, TScopeResolutionMethodCall { + private Generated::ScopeResolution g; + private Generated::Identifier i; + + ScopeResolutionMethodCall() { this = TScopeResolutionMethodCall(g, i) } + + final override Expr getReceiver() { toGenerated(result) = g.getScope() } + + final override string getMethodName() { result = getMethodName(this, i.getValue()) } +} + +private class RegularMethodCall extends MethodCall, TRegularMethodCall { + private Generated::Call g; + + RegularMethodCall() { this = TRegularMethodCall(g) } + + final override Expr getReceiver() { + toGenerated(result) = g.getReceiver() + or + not exists(g.getReceiver()) and + toGenerated(result) = g.getMethod().(Generated::ScopeResolution).getScope() + } + + final override string getMethodName() { + exists(string res | result = getMethodName(this, res) | + res = "call" and g.getMethod() instanceof Generated::ArgumentList + or + res = g.getMethod().(Generated::Token).getValue() + or + res = g.getMethod().(Generated::ScopeResolution).getName().(Generated::Token).getValue() + ) + } + + final override Expr getArgument(int n) { + toGenerated(result) = g.getArguments().getChild(n) + or + toGenerated(result) = g.getMethod().(Generated::ArgumentList).getChild(n) + } + + final override Block getBlock() { toGenerated(result) = g.getBlock() } } /** @@ -101,8 +173,6 @@ class MethodCall extends Call { * ``` */ class SetterMethodCall extends MethodCall, LhsExpr { - final override SetterMethodCall::Range range; - final override string getAPrimaryQlClass() { result = "SetterMethodCall" } } @@ -112,10 +182,20 @@ class SetterMethodCall extends MethodCall, LhsExpr { * a[0] * ``` */ -class ElementReference extends MethodCall, @element_reference { - final override ElementReference::Range range; +class ElementReference extends MethodCall, TElementReference { + private Generated::ElementReference g; + + ElementReference() { this = TElementReference(g) } final override string getAPrimaryQlClass() { result = "ElementReference" } + + final override Expr getReceiver() { toGenerated(result) = g.getObject() } + + final override string getMethodName() { result = getMethodName(this, "[]") } + + final override Expr getArgument(int n) { toGenerated(result) = g.getChild(n) } + + final override string toString() { result = "...[...]" } } /** @@ -124,10 +204,16 @@ class ElementReference extends MethodCall, @element_reference { * yield x, y * ``` */ -class YieldCall extends Call, @yield { - final override YieldCall::Range range; +class YieldCall extends Call, TYieldCall { + private Generated::Yield g; + + YieldCall() { this = TYieldCall(g) } final override string getAPrimaryQlClass() { result = "YieldCall" } + + final override Expr getArgument(int n) { toGenerated(result) = g.getChild().getChild(n) } + + final override string toString() { result = "yield ..." } } /** @@ -140,20 +226,42 @@ class YieldCall extends Call, @yield { * end * ``` */ -class SuperCall extends MethodCall { - final override SuperCall::Range range; - +class SuperCall extends MethodCall, TSuperCall { final override string getAPrimaryQlClass() { result = "SuperCall" } } +private class TokenSuperCall extends SuperCall, TTokenSuperCall { + private Generated::Super g; + + TokenSuperCall() { this = TTokenSuperCall(g) } + + final override string getMethodName() { result = getMethodName(this, g.getValue()) } +} + +private class RegularSuperCall extends SuperCall, TRegularSuperCall { + private Generated::Call g; + + RegularSuperCall() { this = TRegularSuperCall(g) } + + final override string getMethodName() { + result = getMethodName(this, g.getMethod().(Generated::Super).getValue()) + } + + final override Expr getArgument(int n) { toGenerated(result) = g.getArguments().getChild(n) } + + final override Block getBlock() { toGenerated(result) = g.getBlock() } +} + /** * A block argument in a method call. * ```rb * foo(&block) * ``` */ -class BlockArgument extends Expr, @block_argument { - final override BlockArgument::Range range; +class BlockArgument extends Expr, TBlockArgument { + private Generated::BlockArgument g; + + BlockArgument() { this = TBlockArgument(g) } final override string getAPrimaryQlClass() { result = "BlockArgument" } @@ -164,7 +272,11 @@ class BlockArgument extends Expr, @block_argument { * foo(&bar) * ``` */ - final Expr getValue() { result = range.getValue() } + final Expr getValue() { toGenerated(result) = g.getChild() } + + final override string toString() { result = "&..." } + + final override AstNode getAChild(string pred) { pred = "getValue" and result = this.getValue() } } /** @@ -173,8 +285,10 @@ class BlockArgument extends Expr, @block_argument { * foo(*args) * ``` */ -class SplatArgument extends Expr, @splat_argument { - final override SplatArgument::Range range; +class SplatArgument extends Expr, TSplatArgument { + private Generated::SplatArgument g; + + SplatArgument() { this = TSplatArgument(g) } final override string getAPrimaryQlClass() { result = "SplatArgument" } @@ -185,7 +299,11 @@ class SplatArgument extends Expr, @splat_argument { * foo(*bar) * ``` */ - final Expr getValue() { result = range.getValue() } + final Expr getValue() { toGenerated(result) = g.getChild() } + + final override string toString() { result = "*..." } + + final override AstNode getAChild(string pred) { pred = "getValue" and result = this.getValue() } } /** @@ -194,8 +312,10 @@ class SplatArgument extends Expr, @splat_argument { * foo(**options) * ``` */ -class HashSplatArgument extends Expr, @hash_splat_argument { - final override HashSplatArgument::Range range; +class HashSplatArgument extends Expr, THashSplatArgument { + private Generated::HashSplatArgument g; + + HashSplatArgument() { this = THashSplatArgument(g) } final override string getAPrimaryQlClass() { result = "HashSplatArgument" } @@ -206,5 +326,9 @@ class HashSplatArgument extends Expr, @hash_splat_argument { * foo(**bar) * ``` */ - final Expr getValue() { result = range.getValue() } + final Expr getValue() { toGenerated(result) = g.getChild() } + + final override string toString() { result = "**..." } + + final override AstNode getAChild(string pred) { pred = "getValue" and result = this.getValue() } } diff --git a/ql/src/codeql_ruby/ast/Constant.qll b/ql/src/codeql_ruby/ast/Constant.qll index 3c11c0f8e91..d8a5b9030a1 100644 --- a/ql/src/codeql_ruby/ast/Constant.qll +++ b/ql/src/codeql_ruby/ast/Constant.qll @@ -1,12 +1,12 @@ private import codeql_ruby.AST -private import internal.Constant +private import internal.AST +private import internal.Variable +private import internal.TreeSitter /** An access to a constant. */ -class ConstantAccess extends Expr { - override ConstantAccess::Range range; - +class ConstantAccess extends Expr, TConstantAccess { /** Gets the name of the constant being accessed. */ - string getName() { result = range.getName() } + string getName() { none() } /** * Gets the expression used in the access's scope resolution operation, if @@ -24,7 +24,7 @@ class ConstantAccess extends Expr { * MESSAGE * ``` */ - Expr getScopeExpr() { result = range.getScopeExpr() } + Expr getScopeExpr() { none() } /** * Holds if the access uses the scope resolution operator to refer to the @@ -34,7 +34,32 @@ class ConstantAccess extends Expr { * ::MESSAGE * ``` */ - predicate hasGlobalScope() { range.hasGlobalScope() } + predicate hasGlobalScope() { none() } + + override string toString() { result = this.getName() } + + override AstNode getAChild(string pred) { pred = "getScopeExpr" and result = this.getScopeExpr() } +} + +private class TokenConstantAccess extends ConstantAccess, TTokenConstantAccess { + private Generated::Constant g; + + TokenConstantAccess() { this = TTokenConstantAccess(g) } + + final override string getName() { result = g.getValue() } +} + +private class ScopeResolutionConstantAccess extends ConstantAccess, TScopeResolutionConstantAccess { + private Generated::ScopeResolution g; + private Generated::Constant constant; + + ScopeResolutionConstantAccess() { this = TScopeResolutionConstantAccess(g, constant) } + + final override string getName() { result = constant.getValue() } + + final override Expr getScopeExpr() { toGenerated(result) = g.getScope() } + + final override predicate hasGlobalScope() { not exists(g.getScope()) } } /** @@ -54,7 +79,12 @@ class ConstantAccess extends Expr { * ``` */ class ConstantReadAccess extends ConstantAccess { - final override ConstantReadAccess::Range range; + ConstantReadAccess() { + not this instanceof ConstantWriteAccess + or + // `X` in `X ||= 10` is considered both a read and a write + this = any(AssignOperation a).getLeftOperand() + } final override string getAPrimaryQlClass() { result = "ConstantReadAccess" } } @@ -76,7 +106,9 @@ class ConstantReadAccess extends ConstantAccess { * ``` */ class ConstantWriteAccess extends ConstantAccess { - override ConstantWriteAccess::Range range; + ConstantWriteAccess() { + explicitAssignmentNode(toGenerated(this), _) or this instanceof TNamespace + } override string getAPrimaryQlClass() { result = "ConstantWriteAccess" } } @@ -89,8 +121,6 @@ class ConstantWriteAccess extends ConstantAccess { * MAX_SIZE = 100 * ``` */ -class ConstantAssignment extends ConstantWriteAccess { - override ConstantAssignment::Range range; - +class ConstantAssignment extends ConstantWriteAccess, LhsExpr { override string getAPrimaryQlClass() { result = "ConstantAssignment" } } diff --git a/ql/src/codeql_ruby/ast/Control.qll b/ql/src/codeql_ruby/ast/Control.qll index b8cf8144b2e..69588659002 100644 --- a/ql/src/codeql_ruby/ast/Control.qll +++ b/ql/src/codeql_ruby/ast/Control.qll @@ -1,5 +1,6 @@ private import codeql_ruby.AST -private import internal.Control +private import internal.AST +private import internal.TreeSitter /** * A control expression that can be any of the following: @@ -9,17 +10,13 @@ private import internal.Control * - `while`/`until` (including expression-modifier variants) * - `for` */ -class ControlExpr extends Expr { - override ControlExpr::Range range; -} +class ControlExpr extends Expr, TControlExpr { } /** * A conditional expression: `if`/`unless` (including expression-modifier * variants), and ternary-if (`?:`) expressions. */ -class ConditionalExpr extends ControlExpr { - override ConditionalExpr::Range range; - +class ConditionalExpr extends ControlExpr, TConditionalExpr { /** * Gets the condition expression. For example, the result is `foo` in the * following: @@ -29,13 +26,19 @@ class ConditionalExpr extends ControlExpr { * end * ``` */ - final Expr getCondition() { result = range.getCondition() } + Expr getCondition() { none() } /** * 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) } + Stmt getBranch(boolean cond) { none() } + + override AstNode getAChild(string pred) { + pred = "getCondition" and result = this.getCondition() + or + pred = "getBranch" and result = this.getBranch(_) + } } /** @@ -48,16 +51,14 @@ class ConditionalExpr extends ControlExpr { * end * ``` */ -class IfExpr extends ConditionalExpr { - override IfExpr::Range range; - +class IfExpr extends ConditionalExpr, TIfExpr { final override string getAPrimaryQlClass() { result = "IfExpr" } /** Holds if this is an `elsif` expression. */ - final predicate isElsif() { this instanceof @elsif } + predicate isElsif() { none() } /** Gets the 'then' branch of this `if`/`elsif` expression. */ - final Stmt getThen() { result = range.getThen() } + Stmt getThen() { none() } /** * Gets the `elsif`/`else` branch of this `if`/`elsif` expression, if any. In @@ -90,7 +91,51 @@ class IfExpr extends ConditionalExpr { * end * ``` */ - final Stmt getElse() { result = range.getElse() } + Stmt getElse() { none() } + + final override Stmt getBranch(boolean cond) { + cond = true and result = this.getThen() + or + cond = false and result = this.getElse() + } + + override AstNode getAChild(string pred) { + result = ConditionalExpr.super.getAChild(pred) + or + pred = "getThen" and result = this.getThen() + or + pred = "getElse" and result = this.getElse() + } +} + +private class If extends IfExpr, TIf { + private Generated::If g; + + If() { this = TIf(g) } + + final override Expr getCondition() { toGenerated(result) = g.getCondition() } + + final override Stmt getThen() { toGenerated(result) = g.getConsequence() } + + final override Stmt getElse() { toGenerated(result) = g.getAlternative() } + + final override string toString() { result = "if ..." } +} + +private class Elsif extends IfExpr, TElsif { + private Generated::Elsif g; + + Elsif() { this = TElsif(g) } + + final override predicate isElsif() { any() } + + final override Expr getCondition() { toGenerated(result) = g.getCondition() } + + final override Stmt getThen() { toGenerated(result) = g.getConsequence() } + + final override Stmt getElse() { toGenerated(result) = g.getAlternative() } + + final override string toString() { result = "elsif ..." } } /** @@ -101,11 +146,15 @@ class IfExpr extends ConditionalExpr { * end * ``` */ -class UnlessExpr extends ConditionalExpr, @unless { - final override UnlessExpr::Range range; +class UnlessExpr extends ConditionalExpr, TUnlessExpr { + private Generated::Unless g; + + UnlessExpr() { this = TUnlessExpr(g) } final override string getAPrimaryQlClass() { result = "UnlessExpr" } + final override Expr getCondition() { toGenerated(result) = g.getCondition() } + /** * Gets the 'then' branch of this `unless` expression. In the following * example, the result is the `StmtSequence` containing `foo`. @@ -117,7 +166,7 @@ class UnlessExpr extends ConditionalExpr, @unless { * end * ``` */ - final Stmt getThen() { result = range.getThen() } + final Stmt getThen() { toGenerated(result) = g.getConsequence() } /** * Gets the 'else' branch of this `unless` expression. In the following @@ -130,7 +179,23 @@ class UnlessExpr extends ConditionalExpr, @unless { * end * ``` */ - final Stmt getElse() { result = range.getElse() } + final Stmt getElse() { toGenerated(result) = g.getAlternative() } + + final override Expr getBranch(boolean cond) { + cond = false and result = getThen() + or + cond = true and result = getElse() + } + + final override string toString() { result = "unless ..." } + + override AstNode getAChild(string pred) { + result = ConditionalExpr.super.getAChild(pred) + or + pred = "getThen" and result = this.getThen() + or + pred = "getElse" and result = this.getElse() + } } /** @@ -139,11 +204,17 @@ class UnlessExpr extends ConditionalExpr, @unless { * foo if bar * ``` */ -class IfModifierExpr extends ConditionalExpr, @if_modifier { - final override IfModifierExpr::Range range; +class IfModifierExpr extends ConditionalExpr, TIfModifierExpr { + private Generated::IfModifier g; + + IfModifierExpr() { this = TIfModifierExpr(g) } final override string getAPrimaryQlClass() { result = "IfModifierExpr" } + final override Expr getCondition() { toGenerated(result) = g.getCondition() } + + final override Stmt getBranch(boolean cond) { cond = true and result = this.getBody() } + /** * Gets the statement that is conditionally evaluated. In the following * example, the result is the `Expr` for `foo`. @@ -151,7 +222,15 @@ class IfModifierExpr extends ConditionalExpr, @if_modifier { * foo if bar * ``` */ - final Stmt getBody() { result = range.getBody() } + final Stmt getBody() { toGenerated(result) = g.getBody() } + + final override string toString() { result = "... if ..." } + + override AstNode getAChild(string pred) { + result = ConditionalExpr.super.getAChild(pred) + or + pred = "getBody" and result = this.getBody() + } } /** @@ -160,11 +239,17 @@ class IfModifierExpr extends ConditionalExpr, @if_modifier { * y /= x unless x == 0 * ``` */ -class UnlessModifierExpr extends ConditionalExpr, @unless_modifier { - final override UnlessModifierExpr::Range range; +class UnlessModifierExpr extends ConditionalExpr, TUnlessModifierExpr { + private Generated::UnlessModifier g; + + UnlessModifierExpr() { this = TUnlessModifierExpr(g) } final override string getAPrimaryQlClass() { result = "UnlessModifierExpr" } + final override Expr getCondition() { toGenerated(result) = g.getCondition() } + + final override Stmt getBranch(boolean cond) { cond = false and result = this.getBody() } + /** * Gets the statement that is conditionally evaluated. In the following * example, the result is the `Expr` for `foo`. @@ -172,7 +257,15 @@ class UnlessModifierExpr extends ConditionalExpr, @unless_modifier { * foo unless bar * ``` */ - final Stmt getBody() { result = range.getBody() } + final Stmt getBody() { toGenerated(result) = g.getBody() } + + final override string toString() { result = "... unless ..." } + + override AstNode getAChild(string pred) { + result = ConditionalExpr.super.getAChild(pred) + or + pred = "getBody" and result = this.getBody() + } } /** @@ -181,20 +274,42 @@ class UnlessModifierExpr extends ConditionalExpr, @unless_modifier { * (a > b) ? a : b * ``` */ -class TernaryIfExpr extends ConditionalExpr, @conditional { - final override TernaryIfExpr::Range range; +class TernaryIfExpr extends ConditionalExpr, TTernaryIfExpr { + private Generated::Conditional g; + + TernaryIfExpr() { this = TTernaryIfExpr(g) } final override string getAPrimaryQlClass() { result = "TernaryIfExpr" } + final override Expr getCondition() { toGenerated(result) = g.getCondition() } + /** Gets the 'then' branch of this ternary if expression. */ - final Stmt getThen() { result = range.getThen() } + final Stmt getThen() { toGenerated(result) = g.getConsequence() } /** Gets the 'else' branch of this ternary if expression. */ - final Stmt getElse() { result = range.getElse() } + final Stmt getElse() { toGenerated(result) = g.getAlternative() } + + final override Stmt getBranch(boolean cond) { + cond = true and result = getThen() + or + cond = false and result = getElse() + } + + final override string toString() { result = "... ? ... : ..." } + + override AstNode getAChild(string pred) { + result = ConditionalExpr.super.getAChild(pred) + or + pred = "getThen" and result = this.getThen() + or + pred = "getElse" and result = this.getElse() + } } -class CaseExpr extends ControlExpr, @case__ { - final override CaseExpr::Range range; +class CaseExpr extends ControlExpr, TCaseExpr { + private Generated::Case g; + + CaseExpr() { this = TCaseExpr(g) } final override string getAPrimaryQlClass() { result = "CaseExpr" } @@ -217,13 +332,13 @@ class CaseExpr extends ControlExpr, @case__ { * end * ``` */ - final Expr getValue() { result = range.getValue() } + final Expr getValue() { toGenerated(result) = g.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) } + final Expr getBranch(int n) { toGenerated(result) = g.getChild(n) } /** * Gets a branch of this case expression, either a `WhenExpr` or an @@ -241,6 +356,14 @@ class CaseExpr extends ControlExpr, @case__ { * Gets the number of branches of this case expression. */ final int getNumberOfBranches() { result = count(this.getBranch(_)) } + + final override string toString() { result = "case ..." } + + override AstNode getAChild(string pred) { + pred = "getValue" and result = this.getValue() + or + pred = "getBranch" and result = this.getBranch(_) + } } /** @@ -251,13 +374,15 @@ class CaseExpr extends ControlExpr, @case__ { * end * ``` */ -class WhenExpr extends Expr, @when { - final override WhenExpr::Range range; +class WhenExpr extends Expr, TWhenExpr { + private Generated::When g; + + WhenExpr() { this = TWhenExpr(g) } final override string getAPrimaryQlClass() { result = "WhenExpr" } /** Gets the body of this case-when expression. */ - final Stmt getBody() { result = range.getBody() } + final Stmt getBody() { toGenerated(result) = g.getBody() } /** * Gets the `n`th pattern (or condition) in this case-when expression. In the @@ -270,7 +395,7 @@ class WhenExpr extends Expr, @when { * end * ``` */ - final Expr getPattern(int n) { result = range.getPattern(n) } + final Expr getPattern(int n) { toGenerated(result) = g.getPattern(n).getChild() } /** * Gets a pattern (or condition) in this case-when expression. @@ -281,28 +406,40 @@ class WhenExpr extends Expr, @when { * Gets the number of patterns in this case-when expression. */ final int getNumberOfPatterns() { result = count(this.getPattern(_)) } + + final override string toString() { result = "when ..." } + + override AstNode getAChild(string pred) { + pred = "getBody" and result = this.getBody() + or + pred = "getPattern" and result = 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; - +class Loop extends ControlExpr, TLoop { /** Gets the body of this loop. */ - Stmt getBody() { result = range.getBody() } + Stmt getBody() { none() } + + override AstNode getAChild(string pred) { pred = "getBody" and result = this.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; - +class ConditionalLoop extends Loop, TConditionalLoop { /** Gets the condition expression of this loop. */ - final Expr getCondition() { result = range.getCondition() } + Expr getCondition() { none() } + + override AstNode getAChild(string pred) { + result = Loop.super.getAChild(pred) + or + pred = "getCondition" and result = this.getCondition() + } } /** @@ -314,13 +451,19 @@ class ConditionalLoop extends Loop { * end * ``` */ -class WhileExpr extends ConditionalLoop, @while { - final override WhileExpr::Range range; +class WhileExpr extends ConditionalLoop, TWhileExpr { + private Generated::While g; + + WhileExpr() { this = TWhileExpr(g) } final override string getAPrimaryQlClass() { result = "WhileExpr" } /** Gets the body of this `while` loop. */ - final override Stmt getBody() { result = range.getBody() } + final override Stmt getBody() { toGenerated(result) = g.getBody() } + + final override Expr getCondition() { toGenerated(result) = g.getCondition() } + + final override string toString() { result = "while ..." } } /** @@ -332,13 +475,19 @@ class WhileExpr extends ConditionalLoop, @while { * end * ``` */ -class UntilExpr extends ConditionalLoop, @until { - final override UntilExpr::Range range; +class UntilExpr extends ConditionalLoop, TUntilExpr { + private Generated::Until g; + + UntilExpr() { this = TUntilExpr(g) } final override string getAPrimaryQlClass() { result = "UntilExpr" } /** Gets the body of this `until` loop. */ - final override Stmt getBody() { result = range.getBody() } + final override Stmt getBody() { toGenerated(result) = g.getBody() } + + final override Expr getCondition() { toGenerated(result) = g.getCondition() } + + final override string toString() { result = "until ..." } } /** @@ -347,10 +496,18 @@ class UntilExpr extends ConditionalLoop, @until { * foo while bar * ``` */ -class WhileModifierExpr extends ConditionalLoop, @while_modifier { - final override WhileModifierExpr::Range range; +class WhileModifierExpr extends ConditionalLoop, TWhileModifierExpr { + private Generated::WhileModifier g; + + WhileModifierExpr() { this = TWhileModifierExpr(g) } + + final override Stmt getBody() { toGenerated(result) = g.getBody() } + + final override Expr getCondition() { toGenerated(result) = g.getCondition() } final override string getAPrimaryQlClass() { result = "WhileModifierExpr" } + + final override string toString() { result = "... while ..." } } /** @@ -359,10 +516,18 @@ class WhileModifierExpr extends ConditionalLoop, @while_modifier { * foo until bar * ``` */ -class UntilModifierExpr extends ConditionalLoop, @until_modifier { - final override UntilModifierExpr::Range range; +class UntilModifierExpr extends ConditionalLoop, TUntilModifierExpr { + private Generated::UntilModifier g; + + UntilModifierExpr() { this = TUntilModifierExpr(g) } + + final override Stmt getBody() { toGenerated(result) = g.getBody() } + + final override Expr getCondition() { toGenerated(result) = g.getCondition() } final override string getAPrimaryQlClass() { result = "UntilModifierExpr" } + + final override string toString() { result = "... until ..." } } /** @@ -373,16 +538,18 @@ class UntilModifierExpr extends ConditionalLoop, @until_modifier { * end * ``` */ -class ForExpr extends Loop, @for { - final override ForExpr::Range range; +class ForExpr extends Loop, TForExpr { + private Generated::For g; + + ForExpr() { this = TForExpr(g) } final override string getAPrimaryQlClass() { result = "ForExpr" } /** Gets the body of this `for` loop. */ - final override Stmt getBody() { result = range.getBody() } + final override Stmt getBody() { toGenerated(result) = g.getBody() } /** Gets the pattern representing the iteration argument. */ - final Pattern getPattern() { result = range.getPattern() } + final Pattern getPattern() { toGenerated(result) = g.getPattern() } /** * Gets the value being iterated over. In the following example, the result @@ -393,5 +560,15 @@ class ForExpr extends Loop, @for { * end * ``` */ - final Expr getValue() { result = range.getValue() } + final Expr getValue() { toGenerated(result) = g.getValue().getChild() } + + final override string toString() { result = "for ... in ..." } + + override AstNode getAChild(string pred) { + result = Loop.super.getAChild(pred) + or + pred = "getPattern" and result = this.getPattern() + or + pred = "getValue" and result = this.getValue() + } } diff --git a/ql/src/codeql_ruby/ast/Expr.qll b/ql/src/codeql_ruby/ast/Expr.qll index dedcf04de4e..f584b7f96f7 100644 --- a/ql/src/codeql_ruby/ast/Expr.qll +++ b/ql/src/codeql_ruby/ast/Expr.qll @@ -1,16 +1,13 @@ private import codeql_ruby.AST -private import internal.Expr +private import internal.AST +private import internal.TreeSitter /** * An expression. * * This is the root QL class for all expressions. */ -class Expr extends Stmt { - override Expr::Range range; - - Expr() { this = range } -} +class Expr extends Stmt, TExpr { } /** * A reference to the current object. For example: @@ -18,10 +15,10 @@ class Expr extends Stmt { * - `self.method_name` * - `def self.method_name ... end` */ -class Self extends Expr, @token_self { - override Self::Range range; - +class Self extends Expr, TSelf { final override string getAPrimaryQlClass() { result = "Self" } + + final override string toString() { result = "self" } } /** @@ -35,20 +32,43 @@ class Self extends Expr, @token_self { * return 1, 2, *items, k: 5, **map * ``` */ -class ArgumentList extends Expr { - override ArgumentList::Range range; +class ArgumentList extends Expr, TArgumentList { + private Generated::AstNode g; - override string getAPrimaryQlClass() { result = "ArgumentList" } + ArgumentList() { this = TArgumentList(g) } + + /** Gets the `i`th element in this argument list. */ + Expr getElement(int i) { + toGenerated(result) in [ + g.(Generated::ArgumentList).getChild(i), g.(Generated::RightAssignmentList).getChild(i) + ] + } + + final override string getAPrimaryQlClass() { result = "ArgumentList" } + + final override string toString() { result = "..., ..." } + + final override AstNode getAChild(string pred) { + pred = "getElement" and result = this.getElement(_) + } } /** A sequence of expressions. */ -class StmtSequence extends Expr { - override StmtSequence::Range range; - +class StmtSequence extends Expr, TStmtSequence { override string getAPrimaryQlClass() { result = "StmtSequence" } + override string toString() { + exists(int c | c = this.getNumberOfStatements() | + c = 0 and result = ";" + or + c = 1 and result = this.getStmt(0).toString() + or + c > 1 and result = "...; ..." + ) + } + /** Gets the `n`th statement in this sequence. */ - final Stmt getStmt(int n) { result = range.getStmt(n) } + Stmt getStmt(int n) { none() } /** Gets a statement in this sequence. */ final Stmt getAStmt() { result = this.getStmt(_) } @@ -61,6 +81,42 @@ class StmtSequence extends Expr { /** Holds if this sequence has no statements. */ final predicate isEmpty() { this.getNumberOfStatements() = 0 } + + override AstNode getAChild(string pred) { pred = "getStmt" and result = this.getStmt(_) } +} + +private class Then extends StmtSequence, TThen { + private Generated::Then g; + + Then() { this = TThen(g) } + + override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } +} + +private class Else extends StmtSequence, TElse { + private Generated::Else g; + + Else() { this = TElse(g) } + + override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } +} + +private class Do extends StmtSequence, TDo { + private Generated::Do g; + + Do() { this = TDo(g) } + + override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } +} + +private class Ensure extends StmtSequence, TEnsure { + private Generated::Ensure g; + + Ensure() { this = TEnsure(g) } + + override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } + + final override string toString() { result = "ensure ..." } } /** @@ -68,22 +124,70 @@ class StmtSequence extends Expr { * or do-block. That is, any body that may also include rescue/ensure/else * statements. */ -class BodyStatement extends StmtSequence { - override BodyStatement::Range range; +class BodyStmt extends StmtSequence, TBodyStmt { + // Not defined by dispatch, as it should not be exposed + private Generated::AstNode getChild(int i) { + result = any(Generated::Method g | this = TMethod(g)).getChild(i) + or + result = any(Generated::SingletonMethod g | this = TSingletonMethod(g)).getChild(i) + or + exists(Generated::Lambda g | this = TLambda(g) | + result = g.getBody().(Generated::DoBlock).getChild(i) or + result = g.getBody().(Generated::Block).getChild(i) + ) + or + result = any(Generated::DoBlock g | this = TDoBlock(g)).getChild(i) + or + result = any(Generated::Program g | this = TToplevel(g)).getChild(i) and + not result instanceof Generated::BeginBlock + or + result = any(Generated::Class g | this = TClass(g)).getChild(i) + or + result = any(Generated::SingletonClass g | this = TSingletonClass(g)).getChild(i) + or + result = any(Generated::Module g | this = TModule(g)).getChild(i) + or + result = any(Generated::Begin g | this = TBeginExpr(g)).getChild(i) + } + + final override Stmt getStmt(int n) { + result = + rank[n + 1](AstNode node, int i | + toGenerated(node) = this.getChild(i) and + not node instanceof Else and + not node instanceof RescueClause and + not node instanceof Ensure + | + node order by i + ) + } /** Gets the `n`th rescue clause in this block. */ - final RescueClause getRescue(int n) { result = range.getRescue(n) } + final RescueClause getRescue(int n) { + result = + rank[n + 1](RescueClause node, int i | toGenerated(node) = getChild(i) | node order by i) + } /** Gets a rescue clause in this block. */ final RescueClause getARescue() { result = this.getRescue(_) } /** Gets the `else` clause in this block, if any. */ - final StmtSequence getElse() { result = range.getElse() } + final StmtSequence getElse() { result = unique(Else s | toGenerated(s) = getChild(_)) } /** Gets the `ensure` clause in this block, if any. */ - final StmtSequence getEnsure() { result = range.getEnsure() } + final StmtSequence getEnsure() { result = unique(Ensure s | toGenerated(s) = getChild(_)) } final predicate hasEnsure() { exists(this.getEnsure()) } + + override AstNode getAChild(string pred) { + result = StmtSequence.super.getAChild(pred) + or + pred = "getRescue" and result = this.getRescue(_) + or + pred = "getElse" and result = this.getElse() + or + pred = "getEnsure" and result = this.getEnsure() + } } /** @@ -101,10 +205,22 @@ class BodyStatement extends StmtSequence { * () * ``` */ -class ParenthesizedExpr extends StmtSequence, @parenthesized_statements { - final override ParenthesizedExpr::Range range; +class ParenthesizedExpr extends StmtSequence, TParenthesizedExpr { + private Generated::ParenthesizedStatements g; + + ParenthesizedExpr() { this = TParenthesizedExpr(g) } final override string getAPrimaryQlClass() { result = "ParenthesizedExpr" } + + final override string toString() { + exists(int c | c = this.getNumberOfStatements() | + c = 0 and result = "()" + or + c > 0 and result = "(" + StmtSequence.super.toString() + ")" + ) + } + + final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } } /** @@ -117,8 +233,10 @@ class ParenthesizedExpr extends StmtSequence, @parenthesized_statements { * baz(qux: 1) * ``` */ -class Pair extends Expr, @pair { - final override Pair::Range range; +class Pair extends Expr, TPair { + private Generated::Pair g; + + Pair() { this = TPair(g) } final override string getAPrimaryQlClass() { result = "Pair" } @@ -133,7 +251,7 @@ class Pair extends Expr, @pair { * { 'foo' => 123 } * ``` */ - final Expr getKey() { result = range.getKey() } + final Expr getKey() { toGenerated(result) = g.getKey() } /** * Gets the value expression of this pair. For example, the `InteralLiteral` @@ -142,7 +260,15 @@ class Pair extends Expr, @pair { * { 'foo' => 123 } * ``` */ - final Expr getValue() { result = range.getValue() } + final Expr getValue() { toGenerated(result) = g.getValue() } + + final override string toString() { result = "Pair" } + + override AstNode getAChild(string pred) { + pred = "getKey" and result = this.getKey() + or + pred = "getValue" and result = this.getValue() + } } /** @@ -154,8 +280,10 @@ class Pair extends Expr, @pair { * puts msg * end */ -class RescueClause extends Expr, @rescue { - final override RescueClause::Range range; +class RescueClause extends Expr, TRescueClause { + private Generated::Rescue g; + + RescueClause() { this = TRescueClause(g) } final override string getAPrimaryQlClass() { result = "RescueClause" } @@ -169,7 +297,7 @@ class RescueClause extends Expr, @rescue { * end * ``` */ - final Expr getException(int n) { result = range.getException(n) } + final Expr getException(int n) { toGenerated(result) = g.getExceptions().getChild(n) } /** * Gets an exception to match, if any. For example `FirstError` or `SecondError` in: @@ -181,7 +309,7 @@ class RescueClause extends Expr, @rescue { * end * ``` */ - final Expr getAnException() { result = getException(_) } + final Expr getAnException() { result = this.getException(_) } /** * Gets the variable to which to assign the matched exception, if any. @@ -194,12 +322,22 @@ class RescueClause extends Expr, @rescue { * end * ``` */ - final LhsExpr getVariableExpr() { result = range.getVariableExpr() } + final LhsExpr getVariableExpr() { toGenerated(result) = g.getVariable().getChild() } /** * Gets the exception handler body. */ - final StmtSequence getBody() { result = range.getBody() } + final StmtSequence getBody() { toGenerated(result) = g.getBody() } + + final override string toString() { result = "rescue ..." } + + override AstNode getAChild(string pred) { + pred = "getException" and result = this.getException(_) + or + pred = "getVariableExpr" and result = this.getVariableExpr() + or + pred = "getBody" and result = this.getBody() + } } /** @@ -208,8 +346,10 @@ class RescueClause extends Expr, @rescue { * contents = read_file rescue "" * ``` */ -class RescueModifierExpr extends Expr, @rescue_modifier { - final override RescueModifierExpr::Range range; +class RescueModifierExpr extends Expr, TRescueModifierExpr { + private Generated::RescueModifier g; + + RescueModifierExpr() { this = TRescueModifierExpr(g) } final override string getAPrimaryQlClass() { result = "RescueModifierExpr" } @@ -219,7 +359,7 @@ class RescueModifierExpr extends Expr, @rescue_modifier { * body rescue handler * ``` */ - final Stmt getBody() { result = range.getBody() } + final Stmt getBody() { toGenerated(result) = g.getBody() } /** * Gets the exception handler of this `RescueModifierExpr`. @@ -227,7 +367,15 @@ class RescueModifierExpr extends Expr, @rescue_modifier { * body rescue handler * ``` */ - final Stmt getHandler() { result = range.getHandler() } + final Stmt getHandler() { toGenerated(result) = g.getHandler() } + + final override string toString() { result = "... rescue ..." } + + override AstNode getAChild(string pred) { + pred = "getBody" and result = this.getBody() + or + pred = "getHandler" and result = this.getHandler() + } } /** @@ -237,13 +385,15 @@ class RescueModifierExpr extends Expr, @rescue_modifier { * "foo" "bar" "baz" * ``` */ -class StringConcatenation extends Expr, @chained_string { - final override StringConcatenation::Range range; +class StringConcatenation extends Expr, TStringConcatenation { + private Generated::ChainedString g; + + StringConcatenation() { this = TStringConcatenation(g) } final override string getAPrimaryQlClass() { result = "StringConcatenation" } /** Gets the `n`th string literal in this concatenation. */ - final StringLiteral getString(int n) { result = range.getString(n) } + final StringLiteral getString(int n) { toGenerated(result) = g.getChild(n) } /** Gets a string literal in this concatenation. */ final StringLiteral getAString() { result = this.getString(_) } @@ -277,4 +427,8 @@ class StringConcatenation extends Expr, @chained_string { valueText order by i ) } + + final override string toString() { result = "\"...\" \"...\"" } + + override AstNode getAChild(string pred) { pred = "getString" and result = this.getString(_) } } diff --git a/ql/src/codeql_ruby/ast/Literal.qll b/ql/src/codeql_ruby/ast/Literal.qll index 00aa5359acb..2354084910a 100644 --- a/ql/src/codeql_ruby/ast/Literal.qll +++ b/ql/src/codeql_ruby/ast/Literal.qll @@ -1,21 +1,20 @@ private import codeql_ruby.AST -private import internal.Literal +private import internal.AST +private import internal.TreeSitter /** * A literal. * * This is the QL root class for all literals. */ -class Literal extends Expr { - override Literal::Range range; - +class Literal extends Expr, TLiteral { /** * Gets the source text for this literal, if this is a simple literal. * * For complex literals, such as arrays, hashes, and strings with * interpolations, this predicate has no result. */ - final string getValueText() { result = range.getValueText() } + string getValueText() { none() } } /** @@ -31,9 +30,7 @@ class Literal extends Expr { * 1i * ``` */ -class NumericLiteral extends Literal { - override NumericLiteral::Range range; -} +class NumericLiteral extends Literal, TNumericLiteral { } /** * An integer literal. @@ -43,8 +40,14 @@ class NumericLiteral extends Literal { * 0xff * ``` */ -class IntegerLiteral extends NumericLiteral, @token_integer { - final override IntegerLiteral::Range range; +class IntegerLiteral extends NumericLiteral, TIntegerLiteral { + private Generated::Integer g; + + IntegerLiteral() { this = TIntegerLiteral(g) } + + final override string getValueText() { result = g.getValue() } + + final override string toString() { result = this.getValueText() } final override string getAPrimaryQlClass() { result = "IntegerLiteral" } } @@ -57,8 +60,14 @@ class IntegerLiteral extends NumericLiteral, @token_integer { * 2.7e+5 * ``` */ -class FloatLiteral extends NumericLiteral, @token_float { - final override FloatLiteral::Range range; +class FloatLiteral extends NumericLiteral, TFloatLiteral { + private Generated::Float g; + + FloatLiteral() { this = TFloatLiteral(g) } + + final override string getValueText() { result = g.getValue() } + + final override string toString() { result = this.getValueText() } final override string getAPrimaryQlClass() { result = "FloatLiteral" } } @@ -70,8 +79,14 @@ class FloatLiteral extends NumericLiteral, @token_float { * 123r * ``` */ -class RationalLiteral extends NumericLiteral, @rational { - final override RationalLiteral::Range range; +class RationalLiteral extends NumericLiteral, TRationalLiteral { + private Generated::Rational g; + + RationalLiteral() { this = TRationalLiteral(g) } + + final override string getValueText() { result = g.getChild().(Generated::Token).getValue() + "r" } + + final override string toString() { result = this.getValueText() } final override string getAPrimaryQlClass() { result = "RationalLiteral" } } @@ -83,15 +98,27 @@ class RationalLiteral extends NumericLiteral, @rational { * 1i * ``` */ -class ComplexLiteral extends NumericLiteral, @token_complex { - final override ComplexLiteral::Range range; +class ComplexLiteral extends NumericLiteral, TComplexLiteral { + private Generated::Complex g; + + ComplexLiteral() { this = TComplexLiteral(g) } + + final override string getValueText() { result = g.getValue() } + + final override string toString() { result = this.getValueText() } final override string getAPrimaryQlClass() { result = "ComplexLiteral" } } /** A `nil` literal. */ -class NilLiteral extends Literal, @token_nil { - final override NilLiteral::Range range; +class NilLiteral extends Literal, TNilLiteral { + private Generated::Nil g; + + NilLiteral() { this = TNilLiteral(g) } + + final override string getValueText() { result = g.getValue() } + + final override string toString() { result = this.getValueText() } final override string getAPrimaryQlClass() { result = "NilLiteral" } } @@ -105,30 +132,48 @@ class NilLiteral extends Literal, @token_nil { * FALSE * ``` */ -class BooleanLiteral extends Literal, BooleanLiteral::DbUnion { - final override BooleanLiteral::Range range; - +class BooleanLiteral extends Literal, TBooleanLiteral { final override string getAPrimaryQlClass() { result = "BooleanLiteral" } + final override string toString() { result = this.getValueText() } + /** Holds if the Boolean literal is `true` or `TRUE`. */ - predicate isTrue() { range.isTrue() } + predicate isTrue() { none() } /** Holds if the Boolean literal is `false` or `FALSE`. */ - predicate isFalse() { range.isFalse() } + predicate isFalse() { none() } +} + +private class TrueLiteral extends BooleanLiteral, TTrueLiteral { + private Generated::True g; + + TrueLiteral() { this = TTrueLiteral(g) } + + final override string getValueText() { result = g.getValue() } + + final override predicate isTrue() { any() } +} + +private class FalseLiteral extends BooleanLiteral, TFalseLiteral { + private Generated::False g; + + FalseLiteral() { this = TFalseLiteral(g) } + + final override string getValueText() { result = g.getValue() } + + final override predicate isFalse() { any() } } /** * The base class for a component of a string: `StringTextComponent`, * `StringEscapeSequenceComponent`, or `StringInterpolationComponent`. */ -class StringComponent extends AstNode { - override StringComponent::Range range; - +class StringComponent extends AstNode, TStringComponent { /** * Gets the source text for this string component. Has no result if this is * a `StringInterpolationComponent`. */ - final string getValueText() { result = range.getValueText() } + string getValueText() { none() } } /** @@ -143,8 +188,14 @@ class StringComponent extends AstNode { * "foo#{ bar() } baz" * ``` */ -class StringTextComponent extends StringComponent, StringTextComponent::StringContentToken { - final override StringTextComponent::Range range; +class StringTextComponent extends StringComponent, TStringTextComponent { + private Generated::Token g; + + StringTextComponent() { this = TStringTextComponent(g) } + + final override string toString() { result = g.getValue() } + + final override string getValueText() { result = g.getValue() } final override string getAPrimaryQlClass() { result = "StringTextComponent" } } @@ -152,8 +203,14 @@ class StringTextComponent extends StringComponent, StringTextComponent::StringCo /** * An escape sequence component of a string or string-like literal. */ -class StringEscapeSequenceComponent extends StringComponent, @token_escape_sequence { - final override StringEscapeSequenceComponent::Range range; +class StringEscapeSequenceComponent extends StringComponent, TStringEscapeSequenceComponent { + private Generated::EscapeSequence g; + + StringEscapeSequenceComponent() { this = TStringEscapeSequenceComponent(g) } + + final override string toString() { result = g.getValue() } + + final override string getValueText() { result = g.getValue() } final override string getAPrimaryQlClass() { result = "StringEscapeSequenceComponent" } } @@ -161,8 +218,17 @@ class StringEscapeSequenceComponent extends StringComponent, @token_escape_seque /** * An interpolation expression component of a string or string-like literal. */ -class StringInterpolationComponent extends StringComponent, StmtSequence, @interpolation { - final override StringInterpolationComponent::Range range; +class StringInterpolationComponent extends StringComponent, StmtSequence, + TStringInterpolationComponent { + private Generated::Interpolation g; + + StringInterpolationComponent() { this = TStringInterpolationComponent(g) } + + final override string toString() { result = "#{...}" } + + final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } + + final override string getValueText() { none() } final override string getAPrimaryQlClass() { result = "StringInterpolationComponent" } } @@ -170,9 +236,7 @@ class StringInterpolationComponent extends StringComponent, StmtSequence, @inter /** * A string, symbol, regex, or subshell literal. */ -class StringlikeLiteral extends Literal { - override StringlikeLiteral::Range range; - +class StringlikeLiteral extends Literal, TStringlikeLiteral { /** * Gets the `n`th component of this string or string-like literal. The result * will be one of `StringTextComponent`, `StringInterpolationComponent`, and @@ -186,7 +250,7 @@ class StringlikeLiteral extends Literal { * "foo_#{ Time.now }" * ``` */ - final StringComponent getComponent(int n) { result = range.getComponent(n) } + StringComponent getComponent(int n) { none() } /** * Gets the number of components in this string or string-like literal. @@ -206,6 +270,91 @@ class StringlikeLiteral extends Literal { * ``` */ final int getNumberOfComponents() { result = count(this.getComponent(_)) } + + private string getStartDelimiter() { + this instanceof TStringLiteral and + result = "\"" + or + this instanceof TRegexLiteral and + result = "/" + or + this instanceof TSimpleSymbolLiteral and + result = ":" + or + this instanceof TComplexSymbolLiteral and + result = ":\"" + or + this instanceof THashKeySymbolLiteral and + result = "" + or + this instanceof TSubshellLiteral and + result = "`" + or + this instanceof THereDoc and + result = "" + } + + private string getEndDelimiter() { + this instanceof TStringLiteral and + result = "\"" + or + this instanceof TRegexLiteral and + result = "/" + or + this instanceof TSimpleSymbolLiteral and + result = "" + or + this instanceof TComplexSymbolLiteral and + result = "\"" + or + this instanceof THashKeySymbolLiteral and + result = "" + or + this instanceof TSubshellLiteral and + result = "`" + or + this instanceof THereDoc and + result = "" + } + + override string getValueText() { + // 0 components should result in the empty string + // if there are any interpolations, there should be no result + // otherwise, concatenate all the components + forall(StringComponent c | c = this.getComponent(_) | + not c instanceof StringInterpolationComponent + ) and + result = + concat(StringComponent c, int i | c = this.getComponent(i) | c.getValueText() order by i) + } + + override string toString() { + exists(string full, string summary | + full = + concat(StringComponent c, int i, string s | + c = this.getComponent(i) and + ( + s = toGenerated(c).(Generated::Token).getValue() + or + not toGenerated(c) instanceof Generated::Token and + s = "#{...}" + ) + | + s order by i + ) and + ( + // summary should be 32 chars max (incl. ellipsis) + full.length() > 32 and summary = full.substring(0, 29) + "..." + or + full.length() <= 32 and summary = full + ) and + result = this.getStartDelimiter() + summary + this.getEndDelimiter() + ) + } + + final override AstNode getAChild(string pred) { + pred = "getComponent" and result = this.getComponent(_) + } } /** @@ -216,12 +365,26 @@ class StringlikeLiteral extends Literal { * "hello, #{name}" * ``` */ -class StringLiteral extends StringlikeLiteral { - final override StringLiteral::Range range; - +class StringLiteral extends StringlikeLiteral, TStringLiteral { final override string getAPrimaryQlClass() { result = "StringLiteral" } } +private class RegularStringLiteral extends StringLiteral, TRegularStringLiteral { + private Generated::String g; + + RegularStringLiteral() { this = TRegularStringLiteral(g) } + + final override StringComponent getComponent(int n) { toGenerated(result) = g.getChild(n) } +} + +private class BareStringLiteral extends StringLiteral, TBareStringLiteral { + private Generated::BareString g; + + BareStringLiteral() { this = TBareStringLiteral(g) } + + final override StringComponent getComponent(int n) { toGenerated(result) = g.getChild(n) } +} + /** * A regular expression literal. * @@ -229,11 +392,15 @@ class StringLiteral extends StringlikeLiteral { * /[a-z]+/ * ``` */ -class RegexLiteral extends StringlikeLiteral, @regex { - final override RegexLiteral::Range range; +class RegexLiteral extends StringlikeLiteral, TRegexLiteral { + private Generated::Regex g; + + RegexLiteral() { this = TRegexLiteral(g) } final override string getAPrimaryQlClass() { result = "RegexLiteral" } + final override StringComponent getComponent(int i) { toGenerated(result) = g.getChild(i) } + /** * Gets the regex flags as a string. * @@ -242,7 +409,16 @@ class RegexLiteral extends StringlikeLiteral, @regex { * /foo/i # => "i" * /foo/imxo # => "imxo" */ - final string getFlagString() { result = range.getFlagString() } + final string getFlagString() { + // For `/foo/i`, there should be an `/i` token in the database with `this` + // as its parents. Strip the delimiter, which can vary. + result = + max(Generated::Token t | + t.getParent() = g + | + t.getValue().suffix(1) order by t.getParentIndex() + ) + } /** * Holds if the regex was specified using the `i` flag to indicate case @@ -264,16 +440,49 @@ class RegexLiteral extends StringlikeLiteral, @regex { * :"foo bar #{baz}" * ``` */ -class SymbolLiteral extends StringlikeLiteral { - final override SymbolLiteral::Range range; - - SymbolLiteral() { - not any(UndefStmt u).getAMethodName() = this and - not any(AliasStmt a).getNewName() = this and - not any(AliasStmt a).getOldName() = this +class SymbolLiteral extends StringlikeLiteral, TSymbolLiteral { + final override string getAPrimaryQlClass() { + not this instanceof MethodName and result = "SymbolLiteral" } +} - final override string getAPrimaryQlClass() { result = "SymbolLiteral" } +private class SimpleSymbolLiteral extends SymbolLiteral, TSimpleSymbolLiteral { + private Generated::SimpleSymbol g; + + SimpleSymbolLiteral() { this = TSimpleSymbolLiteral(g) } + + // Tree-sitter gives us value text including the colon, which we skip. + final override string getValueText() { result = g.getValue().suffix(1) } + + final override string toString() { result = g.getValue() } +} + +private class ComplexSymbolLiteral extends SymbolLiteral, TComplexSymbolLiteral { } + +private class DelimitedSymbolLiteral extends ComplexSymbolLiteral, TDelimitedSymbolLiteral { + private Generated::DelimitedSymbol g; + + DelimitedSymbolLiteral() { this = TDelimitedSymbolLiteral(g) } + + final override StringComponent getComponent(int i) { toGenerated(result) = g.getChild(i) } +} + +private class BareSymbolLiteral extends ComplexSymbolLiteral, TBareSymbolLiteral { + private Generated::BareSymbol g; + + BareSymbolLiteral() { this = TBareSymbolLiteral(g) } + + final override StringComponent getComponent(int i) { toGenerated(result) = g.getChild(i) } +} + +private class HashKeySymbolLiteral extends SymbolLiteral, THashKeySymbolLiteral { + private Generated::HashKeySymbol g; + + HashKeySymbolLiteral() { this = THashKeySymbolLiteral(g) } + + final override string getValueText() { result = g.getValue() } + + final override string toString() { result = ":" + this.getValueText() } } /** @@ -284,10 +493,14 @@ class SymbolLiteral extends StringlikeLiteral { * %x(/bin/sh foo.sh) * ``` */ -class SubshellLiteral extends StringlikeLiteral, @subshell { - final override SubshellLiteral::Range range; +class SubshellLiteral extends StringlikeLiteral, TSubshellLiteral { + private Generated::Subshell g; + + SubshellLiteral() { this = TSubshellLiteral(g) } final override string getAPrimaryQlClass() { result = "SubshellLiteral" } + + final override StringComponent getComponent(int i) { toGenerated(result) = g.getChild(i) } } /** @@ -298,8 +511,14 @@ class SubshellLiteral extends StringlikeLiteral, @subshell { * ?\u{61} * ``` */ -class CharacterLiteral extends Literal, @token_character { - final override CharacterLiteral::Range range; +class CharacterLiteral extends Literal, TCharacterLiteral { + private Generated::Character g; + + CharacterLiteral() { this = TCharacterLiteral(g) } + + final override string getValueText() { result = g.getValue() } + + final override string toString() { result = g.getValue() } final override string getAPrimaryQlClass() { result = "CharacterLiteral" } } @@ -313,8 +532,10 @@ class CharacterLiteral extends Literal, @token_character { * SQL * ``` */ -class HereDoc extends StringlikeLiteral { - final override HereDoc::Range range; +class HereDoc extends StringlikeLiteral, THereDoc { + private Generated::HeredocBeginning g; + + HereDoc() { this = THereDoc(g) } final override string getAPrimaryQlClass() { result = "HereDoc" } @@ -336,7 +557,13 @@ class HereDoc extends StringlikeLiteral { * <<`IDENTIFIER` * ``` */ - final string getQuoteStyle() { result = range.getQuoteStyle() } + final string getQuoteStyle() { + exists(string s | + s = g.getValue() and + s.charAt(s.length() - 1) = result and + result = ["'", "`", "\""] + ) + } /** * Gets the indentation modifier (`-` or `~`) of the here document identifier, if any. @@ -346,7 +573,36 @@ class HereDoc extends StringlikeLiteral { * < (x) { x + 1 } * ``` */ -class Lambda extends Callable, BodyStatement, @lambda { - final override Lambda::Range range; +class Lambda extends Callable, BodyStmt, TLambda { + private Generated::Lambda g; + + Lambda() { this = TLambda(g) } final override string getAPrimaryQlClass() { result = "Lambda" } + + final override Parameter getParameter(int n) { + toGenerated(result) = g.getParameters().getChild(n) + } + + final override string toString() { result = "-> { ... }" } + + final override AstNode getAChild(string pred) { + result = Callable.super.getAChild(pred) + or + result = BodyStmt.super.getAChild(pred) + } } /** A block. */ -class Block extends Callable, StmtSequence, Scope { - override Block::Range range; +class Block extends Callable, StmtSequence, Scope, TBlock { + override AstNode getAChild(string pred) { + result = Callable.super.getAChild(pred) + or + result = StmtSequence.super.getAChild(pred) + } } /** A block enclosed within `do` and `end`. */ -class DoBlock extends Block, BodyStatement, @do_block { - final override DoBlock::Range range; +class DoBlock extends Block, BodyStmt, TDoBlock { + private Generated::DoBlock g; + + DoBlock() { this = TDoBlock(g) } + + final override Parameter getParameter(int n) { + toGenerated(result) = g.getParameters().getChild(n) + } + + final override string toString() { result = "do ... end" } + + final override AstNode getAChild(string pred) { + result = Block.super.getAChild(pred) + or + result = BodyStmt.super.getAChild(pred) + } final override string getAPrimaryQlClass() { result = "DoBlock" } } @@ -84,8 +155,18 @@ class DoBlock extends Block, BodyStatement, @do_block { * names.each { |name| puts name } * ``` */ -class BraceBlock extends Block, @block { - final override BraceBlock::Range range; +class BraceBlock extends Block, TBraceBlock { + private Generated::Block g; + + BraceBlock() { this = TBraceBlock(g) } + + final override Parameter getParameter(int n) { + toGenerated(result) = g.getParameters().getChild(n) + } + + final override Stmt getStmt(int i) { toGenerated(result) = g.getChild(i) } + + final override string toString() { result = "{ ... }" } final override string getAPrimaryQlClass() { result = "BraceBlock" } } diff --git a/ql/src/codeql_ruby/ast/Module.qll b/ql/src/codeql_ruby/ast/Module.qll index 5f3e150e79a..568a5d64cac 100644 --- a/ql/src/codeql_ruby/ast/Module.qll +++ b/ql/src/codeql_ruby/ast/Module.qll @@ -1,13 +1,12 @@ private import codeql_ruby.AST private import codeql_ruby.ast.Constant -private import internal.Module +private import internal.AST +private import internal.TreeSitter /** * The base class for classes, singleton classes, and modules. */ -class ModuleBase extends BodyStatement, Scope { - override ModuleBase::Range range; - +class ModuleBase extends BodyStmt, TModuleBase { /** Gets a method defined in this module/class. */ MethodBase getAMethod() { result = this.getAStmt() } @@ -37,20 +36,32 @@ class ModuleBase extends BodyStatement, Scope { * main * ``` */ -class Toplevel extends ModuleBase, @program { - final override Toplevel::Range range; +class Toplevel extends ModuleBase, TToplevel { + private Generated::Program g; + + Toplevel() { this = TToplevel(g) } final override string getAPrimaryQlClass() { result = "Toplevel" } /** * Gets the `n`th `BEGIN` block. */ - final BeginBlock getBeginBlock(int n) { result = range.getBeginBlock(n) } + final BeginBlock getBeginBlock(int n) { + toGenerated(result) = rank[n](int i, Generated::BeginBlock b | b = g.getChild(i) | b order by i) + } /** * Gets a `BEGIN` block. */ final BeginBlock getABeginBlock() { result = getBeginBlock(_) } + + final override AstNode getAChild(string pred) { + result = ModuleBase.super.getAChild(pred) + or + pred = "getBeginBlock" and result = this.getBeginBlock(_) + } + + final override string toString() { result = g.getLocation().getFile().getBaseName() } } /** @@ -67,9 +78,7 @@ class Toplevel extends ModuleBase, @program { * end * ``` */ -class Namespace extends ModuleBase, ConstantWriteAccess { - override Namespace::Range range; - +class Namespace extends ModuleBase, ConstantWriteAccess, TNamespace { override string getAPrimaryQlClass() { result = "Namespace" } /** @@ -88,7 +97,7 @@ class Namespace extends ModuleBase, ConstantWriteAccess { * end * ``` */ - override string getName() { result = range.getName() } + override string getName() { none() } /** * Gets the scope expression used in the module/class name's scope resolution @@ -109,7 +118,7 @@ class Namespace extends ModuleBase, ConstantWriteAccess { * end * ``` */ - override Expr getScopeExpr() { result = range.getScopeExpr() } + override Expr getScopeExpr() { none() } /** * Holds if the module/class name uses the scope resolution operator to access the @@ -120,7 +129,14 @@ class Namespace extends ModuleBase, ConstantWriteAccess { * end * ``` */ - override predicate hasGlobalScope() { range.hasGlobalScope() } + override predicate hasGlobalScope() { none() } + + override AstNode getAChild(string pred) { + result = ModuleBase.super.getAChild(pred) or + result = ConstantWriteAccess.super.getAChild(pred) + } + + final override string toString() { result = ConstantWriteAccess.super.toString() } } /** @@ -133,8 +149,10 @@ class Namespace extends ModuleBase, ConstantWriteAccess { * end * ``` */ -class Class extends Namespace, @class { - final override Class::Range range; +class Class extends Namespace, TClass { + private Generated::Class g; + + Class() { this = TClass(g) } final override string getAPrimaryQlClass() { result = "Class" } @@ -154,7 +172,29 @@ class Class extends Namespace, @class { * end * ``` */ - final Expr getSuperclassExpr() { result = range.getSuperclassExpr() } + final Expr getSuperclassExpr() { toGenerated(result) = g.getSuperclass().getChild() } + + final override string getName() { + result = g.getName().(Generated::Token).getValue() or + result = g.getName().(Generated::ScopeResolution).getName().(Generated::Token).getValue() + } + + final override Expr getScopeExpr() { + toGenerated(result) = g.getName().(Generated::ScopeResolution).getScope() + } + + final override predicate hasGlobalScope() { + exists(Generated::ScopeResolution sr | + sr = g.getName() and + not exists(sr.getScope()) + ) + } + + final override AstNode getAChild(string pred) { + result = Namespace.super.getAChild(pred) + or + pred = "getSuperclassExpr" and result = this.getSuperclassExpr() + } } /** @@ -168,8 +208,10 @@ class Class extends Namespace, @class { * end * ``` */ -class SingletonClass extends ModuleBase, @singleton_class { - final override SingletonClass::Range range; +class SingletonClass extends ModuleBase, TSingletonClass { + private Generated::SingletonClass g; + + SingletonClass() { this = TSingletonClass(g) } final override string getAPrimaryQlClass() { result = "Class" } @@ -182,7 +224,15 @@ class SingletonClass extends ModuleBase, @singleton_class { * end * ``` */ - final Expr getValue() { result = range.getValue() } + final Expr getValue() { toGenerated(result) = g.getValue() } + + final override string toString() { result = "class << ..." } + + final override AstNode getAChild(string pred) { + result = ModuleBase.super.getAChild(pred) + or + pred = "getValue" and result = this.getValue() + } } /** @@ -210,8 +260,26 @@ class SingletonClass extends ModuleBase, @singleton_class { * end * ``` */ -class Module extends Namespace, @module { - final override Module::Range range; +class Module extends Namespace, TModule { + private Generated::Module g; + + Module() { this = TModule(g) } final override string getAPrimaryQlClass() { result = "Module" } + + final override string getName() { + result = g.getName().(Generated::Token).getValue() or + result = g.getName().(Generated::ScopeResolution).getName().(Generated::Token).getValue() + } + + final override Expr getScopeExpr() { + toGenerated(result) = g.getName().(Generated::ScopeResolution).getScope() + } + + final override predicate hasGlobalScope() { + exists(Generated::ScopeResolution sr | + sr = g.getName() and + not exists(sr.getScope()) + ) + } } diff --git a/ql/src/codeql_ruby/ast/Operation.qll b/ql/src/codeql_ruby/ast/Operation.qll index 8f3da5ffb5c..b5acf8c8116 100644 --- a/ql/src/codeql_ruby/ast/Operation.qll +++ b/ql/src/codeql_ruby/ast/Operation.qll @@ -1,33 +1,46 @@ private import codeql_ruby.AST -private import internal.Operation +private import internal.AST +private import internal.TreeSitter /** * An operation. * * This is the QL root class for all operations. */ -class Operation extends Expr { - override Operation::Range range; - +class Operation extends Expr, TOperation { /** Gets the operator of this operation. */ - final string getOperator() { result = range.getOperator() } + string getOperator() { none() } /** Gets an operand of this operation. */ - final Expr getAnOperand() { result = range.getAnOperand() } + Expr getAnOperand() { none() } + + override AstNode getAChild(string pred) { pred = "getAnOperand" and result = this.getAnOperand() } } /** A unary operation. */ -class UnaryOperation extends Operation, @unary { - override UnaryOperation::Range range; +class UnaryOperation extends Operation, TUnaryOperation { + private Generated::Unary g; + + UnaryOperation() { g = toGenerated(this) } /** Gets the operand of this unary operation. */ - final Expr getOperand() { result = range.getOperand() } + final Expr getOperand() { toGenerated(result) = g.getOperand() } + + final override string getOperator() { result = g.getOperator() } + + final override Expr getAnOperand() { result = this.getOperand() } + + final override AstNode getAChild(string pred) { + result = Operation.super.getAChild(pred) + or + pred = "getOperand" and result = this.getOperand() + } + + final override string toString() { result = this.getOperator() + " ..." } } /** A unary logical operation. */ -class UnaryLogicalOperation extends UnaryOperation { - override UnaryLogicalOperation::Range range; -} +class UnaryLogicalOperation extends UnaryOperation, TUnaryLogicalOperation { } /** * A logical NOT operation, using either `!` or `not`. @@ -36,16 +49,12 @@ class UnaryLogicalOperation extends UnaryOperation { * not params.empty? * ``` */ -class NotExpr extends UnaryLogicalOperation, NotExpr::DbUnion { - final override NotExpr::Range range; - +class NotExpr extends UnaryLogicalOperation, TNotExpr { final override string getAPrimaryQlClass() { result = "NotExpr" } } /** A unary arithmetic operation. */ -class UnaryArithmeticOperation extends UnaryOperation { - override UnaryArithmeticOperation::Range range; -} +class UnaryArithmeticOperation extends UnaryOperation, TUnaryArithmeticOperation { } /** * A unary plus expression. @@ -53,9 +62,7 @@ class UnaryArithmeticOperation extends UnaryOperation { * + a * ``` */ -class UnaryPlusExpr extends UnaryArithmeticOperation, @unary_plus { - final override UnaryPlusExpr::Range range; - +class UnaryPlusExpr extends UnaryArithmeticOperation, TUnaryPlusExpr { final override string getAPrimaryQlClass() { result = "UnaryPlusExpr" } } @@ -65,16 +72,12 @@ class UnaryPlusExpr extends UnaryArithmeticOperation, @unary_plus { * - a * ``` */ -class UnaryMinusExpr extends UnaryArithmeticOperation, @unary_minus { - final override UnaryMinusExpr::Range range; - +class UnaryMinusExpr extends UnaryArithmeticOperation, TUnaryMinusExpr { final override string getAPrimaryQlClass() { result = "UnaryMinusExpr" } } /** A unary bitwise operation. */ -class UnaryBitwiseOperation extends UnaryOperation { - override UnaryBitwiseOperation::Range range; -} +class UnaryBitwiseOperation extends UnaryOperation, TUnaryBitwiseOperation { } /** * A complement (bitwise NOT) expression. @@ -82,9 +85,7 @@ class UnaryBitwiseOperation extends UnaryOperation { * ~x * ``` */ -class ComplementExpr extends UnaryBitwiseOperation, @unary_tilde { - final override ComplementExpr::Range range; - +class ComplementExpr extends UnaryBitwiseOperation, TComplementExpr { final override string getAPrimaryQlClass() { result = "ComplementExpr" } } @@ -94,29 +95,43 @@ class ComplementExpr extends UnaryBitwiseOperation, @unary_tilde { * defined? some_method * ``` */ -class DefinedExpr extends UnaryOperation, @unary_definedquestion { - final override DefinedExpr::Range range; - +class DefinedExpr extends UnaryOperation, TDefinedExpr { final override string getAPrimaryQlClass() { result = "DefinedExpr" } } /** A binary operation. */ -class BinaryOperation extends Operation, @binary { - override BinaryOperation::Range range; +class BinaryOperation extends Operation, TBinaryOperation { + private Generated::Binary g; + + BinaryOperation() { g = toGenerated(this) } + + final override string getOperator() { result = g.getOperator() } + + final override Expr getAnOperand() { + result = this.getLeftOperand() or result = this.getRightOperand() + } + + final override string toString() { result = "... " + this.getOperator() + " ..." } + + override AstNode getAChild(string pred) { + result = Operation.super.getAChild(pred) + or + pred = "getLeftOperand" and result = this.getLeftOperand() + or + pred = "getRightOperand" and result = this.getRightOperand() + } /** Gets the left operand of this binary operation. */ - final Stmt getLeftOperand() { result = range.getLeftOperand() } + final Stmt getLeftOperand() { toGenerated(result) = g.getLeft() } /** Gets the right operand of this binary operation. */ - final Stmt getRightOperand() { result = range.getRightOperand() } + final Stmt getRightOperand() { toGenerated(result) = g.getRight() } } /** * A binary arithmetic operation. */ -class BinaryArithmeticOperation extends BinaryOperation { - override BinaryArithmeticOperation::Range range; -} +class BinaryArithmeticOperation extends BinaryOperation, TBinaryArithmeticOperation { } /** * An add expression. @@ -124,9 +139,7 @@ class BinaryArithmeticOperation extends BinaryOperation { * x + 1 * ``` */ -class AddExpr extends BinaryArithmeticOperation, @binary_plus { - final override AddExpr::Range range; - +class AddExpr extends BinaryArithmeticOperation, TAddExpr { final override string getAPrimaryQlClass() { result = "AddExpr" } } @@ -136,9 +149,7 @@ class AddExpr extends BinaryArithmeticOperation, @binary_plus { * x - 3 * ``` */ -class SubExpr extends BinaryArithmeticOperation, @binary_minus { - final override SubExpr::Range range; - +class SubExpr extends BinaryArithmeticOperation, TSubExpr { final override string getAPrimaryQlClass() { result = "SubExpr" } } @@ -148,9 +159,7 @@ class SubExpr extends BinaryArithmeticOperation, @binary_minus { * x * 10 * ``` */ -class MulExpr extends BinaryArithmeticOperation, @binary_star { - final override MulExpr::Range range; - +class MulExpr extends BinaryArithmeticOperation, TMulExpr { final override string getAPrimaryQlClass() { result = "MulExpr" } } @@ -160,9 +169,7 @@ class MulExpr extends BinaryArithmeticOperation, @binary_star { * x / y * ``` */ -class DivExpr extends BinaryArithmeticOperation, @binary_slash { - final override DivExpr::Range range; - +class DivExpr extends BinaryArithmeticOperation, TDivExpr { final override string getAPrimaryQlClass() { result = "DivExpr" } } @@ -172,9 +179,7 @@ class DivExpr extends BinaryArithmeticOperation, @binary_slash { * x % 2 * ``` */ -class ModuloExpr extends BinaryArithmeticOperation, @binary_percent { - final override ModuloExpr::Range range; - +class ModuloExpr extends BinaryArithmeticOperation, TModuloExpr { final override string getAPrimaryQlClass() { result = "ModuloExpr" } } @@ -184,18 +189,14 @@ class ModuloExpr extends BinaryArithmeticOperation, @binary_percent { * x ** 2 * ``` */ -class ExponentExpr extends BinaryArithmeticOperation, @binary_starstar { - final override ExponentExpr::Range range; - +class ExponentExpr extends BinaryArithmeticOperation, TExponentExpr { final override string getAPrimaryQlClass() { result = "ExponentExpr" } } /** * A binary logical operation. */ -class BinaryLogicalOperation extends BinaryOperation { - override BinaryLogicalOperation::Range range; -} +class BinaryLogicalOperation extends BinaryOperation, TBinaryLogicalOperation { } /** * A logical AND operation, using either `and` or `&&`. @@ -204,9 +205,7 @@ class BinaryLogicalOperation extends BinaryOperation { * a && b * ``` */ -class LogicalAndExpr extends BinaryLogicalOperation, LogicalAndExpr::DbUnion { - final override LogicalAndExpr::Range range; - +class LogicalAndExpr extends BinaryLogicalOperation, TLogicalAndExpr { final override string getAPrimaryQlClass() { result = "LogicalAndExpr" } } @@ -217,18 +216,14 @@ class LogicalAndExpr extends BinaryLogicalOperation, LogicalAndExpr::DbUnion { * a || b * ``` */ -class LogicalOrExpr extends BinaryLogicalOperation, LogicalOrExpr::DbUnion { - final override LogicalOrExpr::Range range; - +class LogicalOrExpr extends BinaryLogicalOperation, TLogicalOrExpr { final override string getAPrimaryQlClass() { result = "LogicalOrExpr" } } /** * A binary bitwise operation. */ -class BinaryBitwiseOperation extends BinaryOperation { - override BinaryBitwiseOperation::Range range; -} +class BinaryBitwiseOperation extends BinaryOperation, TBinaryBitwiseOperation { } /** * A left-shift operation. @@ -236,9 +231,7 @@ class BinaryBitwiseOperation extends BinaryOperation { * x << n * ``` */ -class LShiftExpr extends BinaryBitwiseOperation, @binary_langlelangle { - final override LShiftExpr::Range range; - +class LShiftExpr extends BinaryBitwiseOperation, TLShiftExpr { final override string getAPrimaryQlClass() { result = "LShiftExpr" } } @@ -248,9 +241,7 @@ class LShiftExpr extends BinaryBitwiseOperation, @binary_langlelangle { * x >> n * ``` */ -class RShiftExpr extends BinaryBitwiseOperation, @binary_ranglerangle { - final override RShiftExpr::Range range; - +class RShiftExpr extends BinaryBitwiseOperation, TRShiftExpr { final override string getAPrimaryQlClass() { result = "RShiftExpr" } } @@ -260,9 +251,7 @@ class RShiftExpr extends BinaryBitwiseOperation, @binary_ranglerangle { * x & 0xff * ``` */ -class BitwiseAndExpr extends BinaryBitwiseOperation, @binary_ampersand { - final override BitwiseAndExpr::Range range; - +class BitwiseAndExpr extends BinaryBitwiseOperation, TBitwiseAndExpr { final override string getAPrimaryQlClass() { result = "BitwiseAndExpr" } } @@ -272,9 +261,7 @@ class BitwiseAndExpr extends BinaryBitwiseOperation, @binary_ampersand { * x | 0x01 * ``` */ -class BitwiseOrExpr extends BinaryBitwiseOperation, @binary_pipe { - final override BitwiseOrExpr::Range range; - +class BitwiseOrExpr extends BinaryBitwiseOperation, TBitwiseOrExpr { final override string getAPrimaryQlClass() { result = "BitwiseOrExpr" } } @@ -284,9 +271,7 @@ class BitwiseOrExpr extends BinaryBitwiseOperation, @binary_pipe { * x ^ y * ``` */ -class BitwiseXorExpr extends BinaryBitwiseOperation, @binary_caret { - final override BitwiseXorExpr::Range range; - +class BitwiseXorExpr extends BinaryBitwiseOperation, TBitwiseXorExpr { final override string getAPrimaryQlClass() { result = "BitwiseXorExpr" } } @@ -294,16 +279,12 @@ class BitwiseXorExpr extends BinaryBitwiseOperation, @binary_caret { * A comparison operation. That is, either an equality operation or a * relational operation. */ -class ComparisonOperation extends BinaryOperation { - override ComparisonOperation::Range range; -} +class ComparisonOperation extends BinaryOperation, TComparisonOperation { } /** * An equality operation. */ -class EqualityOperation extends ComparisonOperation { - override EqualityOperation::Range range; -} +class EqualityOperation extends ComparisonOperation, TEqualityOperation { } /** * An equals expression. @@ -311,9 +292,7 @@ class EqualityOperation extends ComparisonOperation { * x == y * ``` */ -class EqExpr extends EqualityOperation, @binary_equalequal { - final override EqExpr::Range range; - +class EqExpr extends EqualityOperation, TEqExpr { final override string getAPrimaryQlClass() { result = "EqExpr" } } @@ -323,9 +302,7 @@ class EqExpr extends EqualityOperation, @binary_equalequal { * x != y * ``` */ -class NEExpr extends EqualityOperation, @binary_bangequal { - final override NEExpr::Range range; - +class NEExpr extends EqualityOperation, TNEExpr { final override string getAPrimaryQlClass() { result = "NEExpr" } } @@ -335,21 +312,27 @@ class NEExpr extends EqualityOperation, @binary_bangequal { * String === "foo" * ``` */ -class CaseEqExpr extends EqualityOperation, @binary_equalequalequal { - final override CaseEqExpr::Range range; - +class CaseEqExpr extends EqualityOperation, TCaseEqExpr { final override string getAPrimaryQlClass() { result = "CaseEqExpr" } } /** * A relational operation, that is, one of `<=`, `<`, `>`, or `>=`. */ -class RelationalOperation extends ComparisonOperation { - override RelationalOperation::Range range; +class RelationalOperation extends ComparisonOperation, TRelationalOperation { + /** Gets the greater operand. */ + Expr getGreaterOperand() { none() } - final Expr getGreaterOperand() { result = range.getGreaterOperand() } + /** Gets the lesser operand. */ + Expr getLesserOperand() { none() } - final Expr getLesserOperand() { result = range.getLesserOperand() } + final override AstNode getAChild(string pred) { + result = ComparisonOperation.super.getAChild(pred) + or + pred = "getGreaterOperand" and result = this.getGreaterOperand() + or + pred = "getLesserOperand" and result = this.getLesserOperand() + } } /** @@ -358,10 +341,12 @@ class RelationalOperation extends ComparisonOperation { * x > 0 * ``` */ -class GTExpr extends RelationalOperation, @binary_rangle { - final override GTExpr::Range range; - +class GTExpr extends RelationalOperation, TGTExpr { final override string getAPrimaryQlClass() { result = "GTExpr" } + + final override Expr getGreaterOperand() { result = this.getLeftOperand() } + + final override Expr getLesserOperand() { result = this.getRightOperand() } } /** @@ -370,10 +355,12 @@ class GTExpr extends RelationalOperation, @binary_rangle { * x >= 0 * ``` */ -class GEExpr extends RelationalOperation, @binary_rangleequal { - final override GEExpr::Range range; - +class GEExpr extends RelationalOperation, TGEExpr { final override string getAPrimaryQlClass() { result = "GEExpr" } + + final override Expr getGreaterOperand() { result = this.getLeftOperand() } + + final override Expr getLesserOperand() { result = this.getRightOperand() } } /** @@ -382,10 +369,12 @@ class GEExpr extends RelationalOperation, @binary_rangleequal { * x < 10 * ``` */ -class LTExpr extends RelationalOperation, @binary_langle { - final override LTExpr::Range range; - +class LTExpr extends RelationalOperation, TLTExpr { final override string getAPrimaryQlClass() { result = "LTExpr" } + + final override Expr getGreaterOperand() { result = this.getRightOperand() } + + final override Expr getLesserOperand() { result = this.getLeftOperand() } } /** @@ -394,10 +383,12 @@ class LTExpr extends RelationalOperation, @binary_langle { * x <= 10 * ``` */ -class LEExpr extends RelationalOperation, @binary_langleequal { - final override LEExpr::Range range; - +class LEExpr extends RelationalOperation, TLEExpr { final override string getAPrimaryQlClass() { result = "LEExpr" } + + final override Expr getGreaterOperand() { result = this.getRightOperand() } + + final override Expr getLesserOperand() { result = this.getLeftOperand() } } /** @@ -406,9 +397,7 @@ class LEExpr extends RelationalOperation, @binary_langleequal { * a <=> b * ``` */ -class SpaceshipExpr extends BinaryOperation, @binary_langleequalrangle { - final override SpaceshipExpr::Range range; - +class SpaceshipExpr extends BinaryOperation, TSpaceshipExpr { final override string getAPrimaryQlClass() { result = "SpaceshipExpr" } } @@ -418,9 +407,7 @@ class SpaceshipExpr extends BinaryOperation, @binary_langleequalrangle { * input =~ /\d/ * ``` */ -class RegexMatchExpr extends BinaryOperation, @binary_equaltilde { - final override RegexMatchExpr::Range range; - +class RegexMatchExpr extends BinaryOperation, TRegexMatchExpr { final override string getAPrimaryQlClass() { result = "RegexMatchExpr" } } @@ -430,9 +417,7 @@ class RegexMatchExpr extends BinaryOperation, @binary_equaltilde { * input !~ /\d/ * ``` */ -class NoRegexMatchExpr extends BinaryOperation, @binary_bangtilde { - final override NoRegexMatchExpr::Range range; - +class NoRegexMatchExpr extends BinaryOperation, TNoRegexMatchExpr { final override string getAPrimaryQlClass() { result = "NoRegexMatchExpr" } } @@ -441,14 +426,26 @@ class NoRegexMatchExpr extends BinaryOperation, @binary_bangtilde { * * This is a QL base class for all assignments. */ -class Assignment extends Operation { - override Assignment::Range range; - +class Assignment extends Operation, TAssignment { /** Gets the left hand side of this assignment. */ - Pattern getLeftOperand() { result = range.getLeftOperand() } + Pattern getLeftOperand() { none() } /** Gets the right hand side of this assignment. */ - final Expr getRightOperand() { result = range.getRightOperand() } + Expr getRightOperand() { none() } + + final override Expr getAnOperand() { + result = this.getLeftOperand() or result = this.getRightOperand() + } + + final override string toString() { result = "... " + this.getOperator() + " ..." } + + override AstNode getAChild(string pred) { + result = Operation.super.getAChild(pred) + or + pred = "getLeftOperand" and result = getLeftOperand() + or + pred = "getRightOperand" and result = getRightOperand() + } } /** @@ -457,8 +454,16 @@ class Assignment extends Operation { * x = 123 * ``` */ -class AssignExpr extends Assignment { - override AssignExpr::Range range; +class AssignExpr extends Assignment, TAssignExpr { + private Generated::Assignment g; + + AssignExpr() { this = TAssignExpr(g) } + + final override Pattern getLeftOperand() { toGenerated(result) = g.getLeft() } + + final override Expr getRightOperand() { toGenerated(result) = g.getRight() } + + final override string getOperator() { result = "=" } override string getAPrimaryQlClass() { result = "AssignExpr" } } @@ -466,16 +471,22 @@ class AssignExpr extends Assignment { /** * A binary assignment operation other than `=`. */ -class AssignOperation extends Assignment { - override AssignOperation::Range range; +class AssignOperation extends Assignment, TAssignOperation { + private Generated::OperatorAssignment g; + + AssignOperation() { g = toGenerated(this) } + + final override string getOperator() { result = g.getOperator() } + + final override LhsExpr getLeftOperand() { toGenerated(result) = g.getLeft() } + + final override Expr getRightOperand() { toGenerated(result) = g.getRight() } } /** * An arithmetic assignment operation: `+=`, `-=`, `*=`, `/=`, `**=`, and `%=`. */ -class AssignArithmeticOperation extends AssignOperation { - override AssignArithmeticOperation::Range range; -} +class AssignArithmeticOperation extends AssignOperation, TAssignArithmeticOperation { } /** * A `+=` assignment expression. @@ -483,9 +494,7 @@ class AssignArithmeticOperation extends AssignOperation { * x += 1 * ``` */ -class AssignAddExpr extends AssignArithmeticOperation, @operator_assignment_plusequal { - final override AssignAddExpr::Range range; - +class AssignAddExpr extends AssignArithmeticOperation, TAssignAddExpr { final override string getAPrimaryQlClass() { result = "AssignAddExpr" } } @@ -495,9 +504,7 @@ class AssignAddExpr extends AssignArithmeticOperation, @operator_assignment_plus * x -= 3 * ``` */ -class AssignSubExpr extends AssignArithmeticOperation, @operator_assignment_minusequal { - final override AssignSubExpr::Range range; - +class AssignSubExpr extends AssignArithmeticOperation, TAssignSubExpr { final override string getAPrimaryQlClass() { result = "AssignSubExpr" } } @@ -507,9 +514,7 @@ class AssignSubExpr extends AssignArithmeticOperation, @operator_assignment_minu * x *= 10 * ``` */ -class AssignMulExpr extends AssignArithmeticOperation, @operator_assignment_starequal { - final override AssignMulExpr::Range range; - +class AssignMulExpr extends AssignArithmeticOperation, TAssignMulExpr { final override string getAPrimaryQlClass() { result = "AssignMulExpr" } } @@ -519,9 +524,7 @@ class AssignMulExpr extends AssignArithmeticOperation, @operator_assignment_star * x /= y * ``` */ -class AssignDivExpr extends AssignArithmeticOperation, @operator_assignment_slashequal { - final override AssignDivExpr::Range range; - +class AssignDivExpr extends AssignArithmeticOperation, TAssignDivExpr { final override string getAPrimaryQlClass() { result = "AssignDivExpr" } } @@ -531,9 +534,7 @@ class AssignDivExpr extends AssignArithmeticOperation, @operator_assignment_slas * x %= 4 * ``` */ -class AssignModuloExpr extends AssignArithmeticOperation, @operator_assignment_percentequal { - final override AssignModuloExpr::Range range; - +class AssignModuloExpr extends AssignArithmeticOperation, TAssignModuloExpr { final override string getAPrimaryQlClass() { result = "AssignModuloExpr" } } @@ -543,20 +544,14 @@ class AssignModuloExpr extends AssignArithmeticOperation, @operator_assignment_p * x **= 2 * ``` */ -class AssignExponentExpr extends AssignArithmeticOperation, @operator_assignment_starstarequal { - final override AssignExponentExpr::Range range; - +class AssignExponentExpr extends AssignArithmeticOperation, TAssignExponentExpr { final override string getAPrimaryQlClass() { result = "AssignExponentExpr" } } /** * A logical assignment operation: `&&=` and `||=`. */ -class AssignLogicalOperation extends AssignOperation { - override AssignLogicalOperation::Range range; - - final override LhsExpr getLeftOperand() { result = super.getLeftOperand() } -} +class AssignLogicalOperation extends AssignOperation, TAssignLogicalOperation { } /** * A logical AND assignment operation. @@ -564,10 +559,7 @@ class AssignLogicalOperation extends AssignOperation { * x &&= y.even? * ``` */ -class AssignLogicalAndExpr extends AssignLogicalOperation, - @operator_assignment_ampersandampersandequal { - final override AssignLogicalAndExpr::Range range; - +class AssignLogicalAndExpr extends AssignLogicalOperation, TAssignLogicalAndExpr { final override string getAPrimaryQlClass() { result = "AssignLogicalAndExpr" } } @@ -577,18 +569,14 @@ class AssignLogicalAndExpr extends AssignLogicalOperation, * x ||= y * ``` */ -class AssignLogicalOrExpr extends AssignLogicalOperation, @operator_assignment_pipepipeequal { - final override AssignLogicalOrExpr::Range range; - +class AssignLogicalOrExpr extends AssignLogicalOperation, TAssignLogicalOrExpr { final override string getAPrimaryQlClass() { result = "AssignLogicalOrExpr" } } /** * A bitwise assignment operation: `<<=`, `>>=`, `&=`, `|=` and `^=`. */ -class AssignBitwiseOperation extends AssignOperation { - override AssignBitwiseOperation::Range range; -} +class AssignBitwiseOperation extends AssignOperation, TAssignBitwiseOperation { } /** * A left-shift assignment operation. @@ -596,9 +584,7 @@ class AssignBitwiseOperation extends AssignOperation { * x <<= 3 * ``` */ -class AssignLShiftExpr extends AssignBitwiseOperation, @operator_assignment_langlelangleequal { - final override AssignLShiftExpr::Range range; - +class AssignLShiftExpr extends AssignBitwiseOperation, TAssignLShiftExpr { final override string getAPrimaryQlClass() { result = "AssignLShiftExpr" } } @@ -608,9 +594,7 @@ class AssignLShiftExpr extends AssignBitwiseOperation, @operator_assignment_lang * x >>= 3 * ``` */ -class AssignRShiftExpr extends AssignBitwiseOperation, @operator_assignment_ranglerangleequal { - final override AssignRShiftExpr::Range range; - +class AssignRShiftExpr extends AssignBitwiseOperation, TAssignRShiftExpr { final override string getAPrimaryQlClass() { result = "AssignRShiftExpr" } } @@ -620,9 +604,7 @@ class AssignRShiftExpr extends AssignBitwiseOperation, @operator_assignment_rang * x &= 0xff * ``` */ -class AssignBitwiseAndExpr extends AssignBitwiseOperation, @operator_assignment_ampersandequal { - final override AssignBitwiseAndExpr::Range range; - +class AssignBitwiseAndExpr extends AssignBitwiseOperation, TAssignBitwiseAndExpr { final override string getAPrimaryQlClass() { result = "AssignBitwiseAndExpr" } } @@ -632,9 +614,7 @@ class AssignBitwiseAndExpr extends AssignBitwiseOperation, @operator_assignment_ * x |= 0x01 * ``` */ -class AssignBitwiseOrExpr extends AssignBitwiseOperation, @operator_assignment_pipeequal { - final override AssignBitwiseOrExpr::Range range; - +class AssignBitwiseOrExpr extends AssignBitwiseOperation, TAssignBitwiseOrExpr { final override string getAPrimaryQlClass() { result = "AssignBitwiseOrExpr" } } @@ -644,8 +624,6 @@ class AssignBitwiseOrExpr extends AssignBitwiseOperation, @operator_assignment_p * x ^= y * ``` */ -class AssignBitwiseXorExpr extends AssignBitwiseOperation, @operator_assignment_caretequal { - final override AssignBitwiseXorExpr::Range range; - +class AssignBitwiseXorExpr extends AssignBitwiseOperation, TAssignBitwiseXorExpr { final override string getAPrimaryQlClass() { result = "AssignBitwiseXorExpr" } } diff --git a/ql/src/codeql_ruby/ast/Parameter.qll b/ql/src/codeql_ruby/ast/Parameter.qll index e81c9c930f6..7f9c11b417b 100644 --- a/ql/src/codeql_ruby/ast/Parameter.qll +++ b/ql/src/codeql_ruby/ast/Parameter.qll @@ -1,20 +1,19 @@ private import codeql_ruby.AST -private import internal.Pattern +private import internal.AST private import internal.Variable private import internal.Parameter +private import internal.TreeSitter /** A parameter. */ -class Parameter extends AstNode { - override Parameter::Range range; - +class Parameter extends AstNode, TParameter { /** Gets the callable that this parameter belongs to. */ final Callable getCallable() { result.getAParameter() = this } /** Gets the zero-based position of this parameter. */ - final int getPosition() { result = range.getPosition() } + final int getPosition() { this = any(Callable c).getParameter(result) } /** Gets a variable introduced by this parameter. */ - LocalVariable getAVariable() { result = range.getAVariable() } + LocalVariable getAVariable() { none() } /** Gets the variable named `name` introduced by this parameter. */ final LocalVariable getVariable(string name) { @@ -28,44 +27,61 @@ class Parameter extends AstNode { * * This includes both simple parameters and tuple parameters. */ -class PatternParameter extends Parameter, Pattern { - override PatternParameter::Range range; - +class PatternParameter extends Parameter, Pattern, TPatternParameter { override LocalVariable getAVariable() { result = Pattern.super.getAVariable() } } /** A parameter defined using a tuple pattern. */ -class TuplePatternParameter extends PatternParameter, TuplePattern { - override TuplePatternParameter::Range range; +class TuplePatternParameter extends PatternParameter, TuplePattern, TTuplePatternParameter { + final override LocalVariable getAVariable() { result = TuplePattern.super.getAVariable() } final override string getAPrimaryQlClass() { result = "TuplePatternParameter" } + + override AstNode getAChild(string pred) { + result = PatternParameter.super.getAChild(pred) or + result = TuplePattern.super.getAChild(pred) + } } /** A named parameter. */ -class NamedParameter extends Parameter { - override NamedParameter::Range range; - +class NamedParameter extends Parameter, TNamedParameter { /** Gets the name of this parameter. */ - final string getName() { result = range.getName() } + string getName() { none() } /** Gets the variable introduced by this parameter. */ - LocalVariable getVariable() { result = range.getVariable() } + LocalVariable getVariable() { none() } override LocalVariable getAVariable() { result = this.getVariable() } /** Gets an access to this parameter. */ final VariableAccess getAnAccess() { result = this.getVariable().getAnAccess() } + + /** Gets the access that defines the underlying local variable. */ + final VariableAccess getDefiningAccess() { result = this.getVariable().getDefiningAccess() } + + override AstNode getAChild(string pred) { + result = Parameter.super.getAChild(pred) + or + pred = "getDefiningAccess" and + result = this.getDefiningAccess() + } } /** A simple (normal) parameter. */ -class SimpleParameter extends NamedParameter, PatternParameter, VariablePattern { - override SimpleParameter::Range range; +class SimpleParameter extends NamedParameter, PatternParameter, VariablePattern, TSimpleParameter { + private Generated::Identifier g; - final override LocalVariable getVariable() { result = range.getVariable() } + SimpleParameter() { this = TSimpleParameter(g) } - final override LocalVariable getAVariable() { result = range.getAVariable() } + final override string getName() { result = g.getValue() } + + final override LocalVariable getVariable() { result = TLocalVariable(_, _, g) } + + final override LocalVariable getAVariable() { result = this.getVariable() } final override string getAPrimaryQlClass() { result = "SimpleParameter" } + + final override string toString() { result = this.getName() } } /** @@ -76,10 +92,16 @@ class SimpleParameter extends NamedParameter, PatternParameter, VariablePattern * end * ``` */ -class BlockParameter extends @block_parameter, NamedParameter { - final override BlockParameter::Range range; +class BlockParameter extends NamedParameter, TBlockParameter { + private Generated::BlockParameter g; - final override LocalVariable getVariable() { result = range.getVariable() } + BlockParameter() { this = TBlockParameter(g) } + + final override string getName() { result = g.getName().getValue() } + + final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) } + + final override string toString() { result = "&" + this.getName() } final override string getAPrimaryQlClass() { result = "BlockParameter" } } @@ -93,10 +115,18 @@ class BlockParameter extends @block_parameter, NamedParameter { * end * ``` */ -class HashSplatParameter extends @hash_splat_parameter, NamedParameter { - final override HashSplatParameter::Range range; +class HashSplatParameter extends NamedParameter, THashSplatParameter { + private Generated::HashSplatParameter g; + + HashSplatParameter() { this = THashSplatParameter(g) } final override string getAPrimaryQlClass() { result = "HashSplatParameter" } + + final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) } + + final override string toString() { result = "**" + this.getName() } + + final override string getName() { result = g.getName().getValue() } } /** @@ -110,23 +140,39 @@ class HashSplatParameter extends @hash_splat_parameter, NamedParameter { * end * ``` */ -class KeywordParameter extends @keyword_parameter, NamedParameter { - final override KeywordParameter::Range range; +class KeywordParameter extends NamedParameter, TKeywordParameter { + private Generated::KeywordParameter g; + + KeywordParameter() { this = TKeywordParameter(g) } final override string getAPrimaryQlClass() { result = "KeywordParameter" } + final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) } + /** * Gets the default value, i.e. the value assigned to the parameter when one * is not provided by the caller. If the parameter is mandatory and does not * have a default value, this predicate has no result. */ - final Expr getDefaultValue() { result = range.getDefaultValue() } + final Expr getDefaultValue() { toGenerated(result) = g.getValue() } /** * Holds if the parameter is optional. That is, there is a default value that * is used when the caller omits this parameter. */ final predicate isOptional() { exists(this.getDefaultValue()) } + + final override string toString() { result = this.getName() } + + final override string getName() { result = g.getName().getValue() } + + final override Location getLocation() { result = g.getName().getLocation() } + + final override AstNode getAChild(string pred) { + result = NamedParameter.super.getAChild(pred) + or + pred = "getDefaultValue" and result = this.getDefaultValue() + } } /** @@ -138,8 +184,10 @@ class KeywordParameter extends @keyword_parameter, NamedParameter { * end * ``` */ -class OptionalParameter extends @optional_parameter, NamedParameter { - final override OptionalParameter::Range range; +class OptionalParameter extends NamedParameter, TOptionalParameter { + private Generated::OptionalParameter g; + + OptionalParameter() { this = TOptionalParameter(g) } final override string getAPrimaryQlClass() { result = "OptionalParameter" } @@ -147,7 +195,21 @@ class OptionalParameter extends @optional_parameter, NamedParameter { * Gets the default value, i.e. the value assigned to the parameter when one * is not provided by the caller. */ - final Expr getDefaultValue() { result = range.getDefaultValue() } + final Expr getDefaultValue() { toGenerated(result) = g.getValue() } + + final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) } + + final override string toString() { result = this.getName() } + + final override string getName() { result = g.getName().getValue() } + + final override Location getLocation() { result = g.getName().getLocation() } + + final override AstNode getAChild(string pred) { + result = NamedParameter.super.getAChild(pred) + or + pred = "getDefaultValue" and result = this.getDefaultValue() + } } /** @@ -158,8 +220,16 @@ class OptionalParameter extends @optional_parameter, NamedParameter { * end * ``` */ -class SplatParameter extends @splat_parameter, NamedParameter { - final override SplatParameter::Range range; +class SplatParameter extends NamedParameter, TSplatParameter { + private Generated::SplatParameter g; + + SplatParameter() { this = TSplatParameter(g) } final override string getAPrimaryQlClass() { result = "SplatParameter" } + + final override LocalVariable getVariable() { result = TLocalVariable(_, _, g.getName()) } + + final override string toString() { result = "*" + this.getName() } + + final override string getName() { result = g.getName().getValue() } } diff --git a/ql/src/codeql_ruby/ast/Pattern.qll b/ql/src/codeql_ruby/ast/Pattern.qll index 78edd4ad0d3..8cf30a3ea4b 100644 --- a/ql/src/codeql_ruby/ast/Pattern.qll +++ b/ql/src/codeql_ruby/ast/Pattern.qll @@ -1,18 +1,25 @@ private import codeql_ruby.AST private import codeql.Locations -private import internal.Pattern +private import internal.AST +private import internal.TreeSitter private import internal.Variable /** A pattern. */ class Pattern extends AstNode { - override Pattern::Range range; - - Pattern() { range = this } + Pattern() { + explicitAssignmentNode(toGenerated(this), _) or + implicitAssignmentNode(toGenerated(this)) or + implicitParameterAssignmentNode(toGenerated(this), _) + } /** Gets a variable used in (or introduced by) this pattern. */ - Variable getAVariable() { result = range.getAVariable() } + Variable getAVariable() { none() } } +private class LhsExpr_ = + TVariableAccess or TTokenConstantAccess or TScopeResolutionConstantAccess or TMethodCall or + TSimpleParameter; + /** * A "left-hand-side" expression. An `LhsExpr` can occur on the left-hand side of * operator assignments (`AssignOperation`), in patterns (`Pattern`) on the left-hand side of @@ -29,17 +36,14 @@ class Pattern extends AstNode { * rescue E => var * ``` */ -class LhsExpr extends Pattern, Expr { - override LhsExpr::Range range; +class LhsExpr extends Pattern, LhsExpr_, Expr { + override Variable getAVariable() { result = this.(VariableAccess).getVariable() } } +private class TVariablePattern = TVariableAccess or TSimpleParameter; + /** A simple variable pattern. */ -class VariablePattern extends Pattern, VariablePattern::VariableToken { - override VariablePattern::Range range; - - /** Gets the variable used in (or introduced by) this pattern. */ - Variable getVariable() { access(this, result) } -} +class VariablePattern extends Pattern, LhsExpr, TVariablePattern { } /** * A tuple pattern. @@ -51,13 +55,25 @@ class VariablePattern extends Pattern, VariablePattern::VariableToken { * a, b, *rest, c, d = value * ``` */ -class TuplePattern extends Pattern { - override TuplePattern::Range range; - +class TuplePattern extends Pattern, TTuplePattern { override string getAPrimaryQlClass() { result = "TuplePattern" } + private Generated::AstNode getChild(int i) { + result = toGenerated(this).(Generated::DestructuredParameter).getChild(i) + or + result = toGenerated(this).(Generated::DestructuredLeftAssignment).getChild(i) + or + result = toGenerated(this).(Generated::LeftAssignmentList).getChild(i) + } + /** Gets the `i`th pattern in this tuple pattern. */ - final Pattern getElement(int i) { result = range.getElement(i) } + final Pattern getElement(int i) { + exists(Generated::AstNode c | c = this.getChild(i) | + toGenerated(result) = c.(Generated::RestAssignment).getChild() + or + toGenerated(result) = c + ) + } /** Gets a sub pattern in this tuple pattern. */ final Pattern getAnElement() { result = this.getElement(_) } @@ -69,5 +85,13 @@ class TuplePattern extends Pattern { * a, b, *rest, c, d = value * ``` */ - final int getRestIndex() { result = range.getRestIndex() } + final int getRestIndex() { + result = unique(int i | getChild(i) instanceof Generated::RestAssignment) + } + + override Variable getAVariable() { result = this.getElement(_).getAVariable() } + + override string toString() { result = "(..., ...)" } + + override AstNode getAChild(string pred) { pred = "getElement" and result = getElement(_) } } diff --git a/ql/src/codeql_ruby/ast/Scope.qll b/ql/src/codeql_ruby/ast/Scope.qll index c0484232a3d..36b23e880e5 100644 --- a/ql/src/codeql_ruby/ast/Scope.qll +++ b/ql/src/codeql_ruby/ast/Scope.qll @@ -1,17 +1,21 @@ private import codeql_ruby.AST +private import internal.AST private import internal.Scope +private import internal.TreeSitter -class Scope extends AstNode, Scope::ScopeType { - override Scope::Range range; +class Scope extends AstNode, TScopeType { + private Scope::Range range; - AstNode getADescendant() { result = range.getADescendant() } + Scope() { range = toGenerated(this) } - ModuleBase getEnclosingModule() { result = range.getEnclosingModule() } + /** Gets the enclosing module, if any. */ + ModuleBase getEnclosingModule() { toGenerated(result) = range.getEnclosingModule() } - MethodBase getEnclosingMethod() { result = range.getEnclosingMethod() } + /** Gets the enclosing method, if any. */ + MethodBase getEnclosingMethod() { toGenerated(result) = range.getEnclosingMethod() } /** Gets the scope in which this scope is nested, if any. */ - Scope getOuterScope() { result = range.getOuterScope() } + Scope getOuterScope() { toGenerated(result) = range.getOuterScope() } /** Gets a variable that is declared in this scope. */ final Variable getAVariable() { result.getDeclaringScope() = this } diff --git a/ql/src/codeql_ruby/ast/Statement.qll b/ql/src/codeql_ruby/ast/Statement.qll index 2842ba23661..fcc2ac8c09f 100644 --- a/ql/src/codeql_ruby/ast/Statement.qll +++ b/ql/src/codeql_ruby/ast/Statement.qll @@ -1,7 +1,8 @@ private import codeql_ruby.AST private import codeql_ruby.CFG -private import internal.Expr -private import internal.Statement +private import internal.AST +private import internal.TreeSitter +private import internal.Variable private import codeql_ruby.controlflow.internal.ControlFlowGraphImpl /** @@ -9,14 +10,12 @@ private import codeql_ruby.controlflow.internal.ControlFlowGraphImpl * * This is the root QL class for all statements. */ -class Stmt extends AstNode { - override Stmt::Range range; - +class Stmt extends AstNode, TStmt { /** Gets a control-flow node for this statement, if any. */ CfgNodes::AstCfgNode getAControlFlowNode() { result.getNode() = this } /** Gets the control-flow scope of this statement, if any. */ - CfgScope getCfgScope() { result = getCfgScope(this) } + CfgScope getCfgScope() { result = getCfgScope(toGenerated(this)) } /** Gets the enclosing callable, if any. */ Callable getEnclosingCallable() { result = this.getCfgScope() } @@ -25,10 +24,10 @@ class Stmt extends AstNode { /** * An empty statement (`;`). */ -class EmptyStmt extends Stmt, @token_empty_statement { - final override EmptyStmt::Range range; - +class EmptyStmt extends Stmt, TEmptyStmt { final override string getAPrimaryQlClass() { result = "EmptyStmt" } + + final override string toString() { result = ";" } } /** @@ -39,10 +38,10 @@ class EmptyStmt extends Stmt, @token_empty_statement { * end * ``` */ -class BeginExpr extends BodyStatement, @begin { - final override Begin::Range range; - +class BeginExpr extends BodyStmt, TBeginExpr { final override string getAPrimaryQlClass() { result = "BeginExpr" } + + final override string toString() { result = "begin ... " } } /** @@ -51,10 +50,16 @@ class BeginExpr extends BodyStatement, @begin { * BEGIN { puts "starting ..." } * ``` */ -class BeginBlock extends StmtSequence, @begin_block { - final override BeginBlock::Range range; +class BeginBlock extends StmtSequence, TBeginBlock { + private Generated::BeginBlock g; + + BeginBlock() { this = TBeginBlock(g) } final override string getAPrimaryQlClass() { result = "BeginBlock" } + + final override string toString() { result = "BEGIN { ... }" } + + final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } } /** @@ -63,10 +68,16 @@ class BeginBlock extends StmtSequence, @begin_block { * END { puts "shutting down" } * ``` */ -class EndBlock extends StmtSequence, @end_block { - final override EndBlock::Range range; +class EndBlock extends StmtSequence, TEndBlock { + private Generated::EndBlock g; + + EndBlock() { this = TEndBlock(g) } final override string getAPrimaryQlClass() { result = "EndBlock" } + + final override string toString() { result = "END { ... }" } + + final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } } /** @@ -77,16 +88,24 @@ class EndBlock extends StmtSequence, @end_block { * - undef :"method_#{ name }" * ``` */ -class UndefStmt extends Stmt, @undef { - final override UndefStmt::Range range; +class UndefStmt extends Stmt, TUndefStmt { + private Generated::Undef g; + + UndefStmt() { this = TUndefStmt(g) } /** Gets the `n`th method name to undefine. */ - final MethodName getMethodName(int n) { result = range.getMethodName(n) } + final MethodName getMethodName(int n) { toGenerated(result) = g.getChild(n) } /** Gets a method name to undefine. */ final MethodName getAMethodName() { result = getMethodName(_) } final override string getAPrimaryQlClass() { result = "UndefStmt" } + + final override string toString() { result = "undef ..." } + + final override AstNode getAChild(string pred) { + pred = "getMethodName" and result = this.getMethodName(_) + } } /** @@ -97,16 +116,26 @@ class UndefStmt extends Stmt, @undef { * - alias bar :"method_#{ name }" * ``` */ -class AliasStmt extends Stmt, @alias { - final override AliasStmt::Range range; +class AliasStmt extends Stmt, TAliasStmt { + private Generated::Alias g; + + AliasStmt() { this = TAliasStmt(g) } /** Gets the new method name. */ - final MethodName getNewName() { result = range.getNewName() } + final MethodName getNewName() { toGenerated(result) = g.getName() } /** Gets the original method name. */ - final MethodName getOldName() { result = range.getOldName() } + final MethodName getOldName() { toGenerated(result) = g.getAlias() } final override string getAPrimaryQlClass() { result = "AliasStmt" } + + final override string toString() { result = "alias ..." } + + final override AstNode getAChild(string pred) { + pred = "getNewName" and result = this.getNewName() + or + pred = "getOldName" and result = this.getOldName() + } } /** @@ -121,11 +150,30 @@ class AliasStmt extends Stmt, @alias { * next value * ``` */ -class ReturningStmt extends Stmt { - override ReturningStmt::Range range; +class ReturningStmt extends Stmt, TReturningStmt { + private Generated::ArgumentList getArgumentList() { + result = any(Generated::Return g | this = TReturnStmt(g)).getChild() + or + result = any(Generated::Break g | this = TBreakStmt(g)).getChild() + or + result = any(Generated::Next g | this = TNextStmt(g)).getChild() + } /** Gets the returned value, if any. */ - final Expr getValue() { result = range.getValue() } + final Expr getValue() { + toGenerated(result) = + any(Generated::AstNode res | + exists(Generated::ArgumentList a, int c | + a = this.getArgumentList() and c = count(a.getChild(_)) + | + res = a.getChild(0) and c = 1 + or + res = a and c > 1 + ) + ) + } + + final override AstNode getAChild(string pred) { pred = "getValue" and result = this.getValue() } } /** @@ -135,10 +183,10 @@ class ReturningStmt extends Stmt { * return value * ``` */ -class ReturnStmt extends ReturningStmt, @return { - final override ReturnStmt::Range range; - +class ReturnStmt extends ReturningStmt, TReturnStmt { final override string getAPrimaryQlClass() { result = "ReturnStmt" } + + final override string toString() { result = "return" } } /** @@ -148,10 +196,10 @@ class ReturnStmt extends ReturningStmt, @return { * break value * ``` */ -class BreakStmt extends ReturningStmt, @break { - final override BreakStmt::Range range; - +class BreakStmt extends ReturningStmt, TBreakStmt { final override string getAPrimaryQlClass() { result = "BreakStmt" } + + final override string toString() { result = "break" } } /** @@ -161,10 +209,10 @@ class BreakStmt extends ReturningStmt, @break { * next value * ``` */ -class NextStmt extends ReturningStmt, @next { - final override NextStmt::Range range; - +class NextStmt extends ReturningStmt, TNextStmt { final override string getAPrimaryQlClass() { result = "NextStmt" } + + final override string toString() { result = "next" } } /** @@ -173,10 +221,10 @@ class NextStmt extends ReturningStmt, @next { * redo * ``` */ -class RedoStmt extends Stmt, @redo { - final override RedoStmt::Range range; - +class RedoStmt extends Stmt, TRedoStmt { final override string getAPrimaryQlClass() { result = "RedoStmt" } + + final override string toString() { result = "redo" } } /** @@ -185,8 +233,8 @@ class RedoStmt extends Stmt, @redo { * retry * ``` */ -class RetryStmt extends Stmt, @retry { - final override RetryStmt::Range range; - +class RetryStmt extends Stmt, TRetryStmt { final override string getAPrimaryQlClass() { result = "RetryStmt" } + + final override string toString() { result = "retry" } } diff --git a/ql/src/codeql_ruby/ast/Variable.qll b/ql/src/codeql_ruby/ast/Variable.qll index 955723399dd..bc2ab278e6c 100644 --- a/ql/src/codeql_ruby/ast/Variable.qll +++ b/ql/src/codeql_ruby/ast/Variable.qll @@ -2,6 +2,8 @@ private import codeql_ruby.AST private import codeql.Locations +private import internal.AST +private import internal.TreeSitter private import internal.Variable /** A variable declared in a scope. */ @@ -20,7 +22,7 @@ class Variable extends TVariable { final Location getLocation() { result = range.getLocation() } /** Gets the scope this variable is declared in. */ - final Scope getDeclaringScope() { result = range.getDeclaringScope() } + final Scope getDeclaringScope() { toGenerated(result) = range.getDeclaringScope() } /** Gets an access to this variable. */ VariableAccess getAnAccess() { result.getVariable() = this } @@ -77,11 +79,9 @@ class ClassVariable extends Variable, TClassVariable { } /** An access to a variable. */ -class VariableAccess extends Expr { - override VariableAccess::Range range; - +class VariableAccess extends Expr, TVariableAccess { /** Gets the variable this identifier refers to. */ - Variable getVariable() { result = range.getVariable() } + Variable getVariable() { none() } /** * Holds if this access is a write access belonging to the explicit @@ -93,7 +93,9 @@ class VariableAccess extends Expr { * * both `a` and `b` are write accesses belonging to the same assignment. */ - predicate isExplicitWrite(AstNode assignment) { range.isExplicitWrite(assignment) } + predicate isExplicitWrite(AstNode assignment) { + explicitWriteAccess(toGenerated(this), toGenerated(assignment)) + } /** * Holds if this access is a write access belonging to an implicit assignment. @@ -110,7 +112,7 @@ class VariableAccess extends Expr { * the access to `elements` in the parameter list is an implicit assignment, * as is the first access to `e`. */ - predicate isImplicitWrite() { range.isImplicitWrite() } + predicate isImplicitWrite() { implicitWriteAccess(toGenerated(this)) } } /** An access to a variable where the value is updated. */ @@ -132,14 +134,15 @@ class VariableReadAccess extends VariableAccess { } /** An access to a local variable. */ -class LocalVariableAccess extends VariableAccess, LocalVariableAccess::LocalVariableRange { - final override LocalVariableAccess::Range range; +class LocalVariableAccess extends VariableAccess, TLocalVariableAccess { + private Generated::Identifier g; + private LocalVariable v; - final override LocalVariable getVariable() { result = range.getVariable() } + LocalVariableAccess() { this = TLocalVariableAccess(g, v) } - final override string getAPrimaryQlClass() { - not this instanceof NamedParameter and result = "LocalVariableAccess" - } + final override LocalVariable getVariable() { result = v } + + final override string getAPrimaryQlClass() { result = "LocalVariableAccess" } /** * Holds if this access is a captured variable access. For example in @@ -157,6 +160,8 @@ class LocalVariableAccess extends VariableAccess, LocalVariableAccess::LocalVari * the access to `x` in the second `puts x` is not. */ final predicate isCapturedAccess() { isCapturedAccess(this) } + + final override string toString() { result = g.getValue() } } /** An access to a local variable where the value is updated. */ @@ -166,12 +171,17 @@ class LocalVariableWriteAccess extends LocalVariableAccess, VariableWriteAccess class LocalVariableReadAccess extends LocalVariableAccess, VariableReadAccess { } /** An access to a global variable. */ -class GlobalVariableAccess extends VariableAccess, @token_global_variable { - final override GlobalVariableAccess::Range range; +class GlobalVariableAccess extends VariableAccess, TGlobalVariableAccess { + private Generated::GlobalVariable g; + private GlobalVariable v; - final override GlobalVariable getVariable() { result = range.getVariable() } + GlobalVariableAccess() { this = TGlobalVariableAccess(g, v) } + + final override GlobalVariable getVariable() { result = v } final override string getAPrimaryQlClass() { result = "GlobalVariableAccess" } + + final override string toString() { result = g.getValue() } } /** An access to a global variable where the value is updated. */ @@ -181,19 +191,29 @@ class GlobalVariableWriteAccess extends GlobalVariableAccess, VariableWriteAcces class GlobalVariableReadAccess extends GlobalVariableAccess, VariableReadAccess { } /** An access to an instance variable. */ -class InstanceVariableAccess extends VariableAccess, @token_instance_variable { - final override InstanceVariableAccess::Range range; +class InstanceVariableAccess extends VariableAccess, TInstanceVariableAccess { + private Generated::InstanceVariable g; + private InstanceVariable v; - final override InstanceVariable getVariable() { result = range.getVariable() } + InstanceVariableAccess() { this = TInstanceVariableAccess(g, v) } + + final override InstanceVariable getVariable() { result = v } final override string getAPrimaryQlClass() { result = "InstanceVariableAccess" } + + final override string toString() { result = g.getValue() } } /** An access to a class variable. */ -class ClassVariableAccess extends VariableAccess, @token_class_variable { - final override ClassVariableAccess::Range range; +class ClassVariableAccess extends VariableAccess, TClassVariableAccess { + private Generated::ClassVariable g; + private ClassVariable v; - final override ClassVariable getVariable() { result = range.getVariable() } + ClassVariableAccess() { this = TClassVariableAccess(g, v) } + + final override ClassVariable getVariable() { result = v } final override string getAPrimaryQlClass() { result = "ClassVariableAccess" } + + final override string toString() { result = g.getValue() } } diff --git a/ql/src/codeql_ruby/ast/internal/AST.qll b/ql/src/codeql_ruby/ast/internal/AST.qll index 6cced8abe30..6cf9696c510 100644 --- a/ql/src/codeql_ruby/ast/internal/AST.qll +++ b/ql/src/codeql_ruby/ast/internal/AST.qll @@ -1,17 +1,500 @@ import codeql.Locations private import TreeSitter +private import codeql_ruby.ast.internal.Parameter +private import codeql_ruby.ast.internal.Variable +private import codeql_ruby.AST as AST -module AstNode { - abstract class Range extends @ast_node { - Generated::AstNode generated; +module MethodName { + predicate range(Generated::UnderscoreMethodName g) { + exists(Generated::Undef u | u.getChild(_) = g) + or + exists(Generated::Alias a | a.getName() = g or a.getAlias() = g) + } - Range() { this = generated } + class Token = + @setter or @token_class_variable or @token_constant or @token_global_variable or + @token_identifier or @token_instance_variable or @token_operator; +} - cached - abstract string toString(); +cached +private module Cached { + cached + newtype TAstNode = + TAddExpr(Generated::Binary g) { g instanceof @binary_plus } or + TAliasStmt(Generated::Alias g) or + TArgumentList(Generated::AstNode g) { + ( + g.getParent() instanceof Generated::Break or + g.getParent() instanceof Generated::Return or + g.getParent() instanceof Generated::Next or + g.getParent() instanceof Generated::Assignment or + g.getParent() instanceof Generated::OperatorAssignment + ) and + ( + strictcount(g.(Generated::ArgumentList).getChild(_)) > 1 + or + g instanceof Generated::RightAssignmentList + ) + } or + TAssignAddExpr(Generated::OperatorAssignment g) { g instanceof @operator_assignment_plusequal } or + TAssignBitwiseAndExpr(Generated::OperatorAssignment g) { + g instanceof @operator_assignment_ampersandequal + } or + TAssignBitwiseOrExpr(Generated::OperatorAssignment g) { + g instanceof @operator_assignment_pipeequal + } or + TAssignBitwiseXorExpr(Generated::OperatorAssignment g) { + g instanceof @operator_assignment_caretequal + } or + TAssignDivExpr(Generated::OperatorAssignment g) { g instanceof @operator_assignment_slashequal } or + TAssignExponentExpr(Generated::OperatorAssignment g) { + g instanceof @operator_assignment_starstarequal + } or + TAssignExpr(Generated::Assignment g) or + TAssignLShiftExpr(Generated::OperatorAssignment g) { + g instanceof @operator_assignment_langlelangleequal + } or + TAssignLogicalAndExpr(Generated::OperatorAssignment g) { + g instanceof @operator_assignment_ampersandampersandequal + } or + TAssignLogicalOrExpr(Generated::OperatorAssignment g) { + g instanceof @operator_assignment_pipepipeequal + } or + TAssignModuloExpr(Generated::OperatorAssignment g) { + g instanceof @operator_assignment_percentequal + } or + TAssignMulExpr(Generated::OperatorAssignment g) { g instanceof @operator_assignment_starequal } or + TAssignRShiftExpr(Generated::OperatorAssignment g) { + g instanceof @operator_assignment_ranglerangleequal + } or + TAssignSubExpr(Generated::OperatorAssignment g) { g instanceof @operator_assignment_minusequal } or + TBareStringLiteral(Generated::BareString g) or + TBareSymbolLiteral(Generated::BareSymbol g) or + TBeginBlock(Generated::BeginBlock g) or + TBeginExpr(Generated::Begin g) or + TBitwiseAndExpr(Generated::Binary g) { g instanceof @binary_ampersand } or + TBitwiseOrExpr(Generated::Binary g) { g instanceof @binary_pipe } or + TBitwiseXorExpr(Generated::Binary g) { g instanceof @binary_caret } or + TBlockArgument(Generated::BlockArgument g) or + TBlockParameter(Generated::BlockParameter g) or + TBraceBlock(Generated::Block g) { not g.getParent() instanceof Generated::Lambda } or + TBreakStmt(Generated::Break g) or + TCaseEqExpr(Generated::Binary g) { g instanceof @binary_equalequalequal } or + TCaseExpr(Generated::Case g) or + TCharacterLiteral(Generated::Character g) or + TClass(Generated::Class g) or + TClassVariableAccess(Generated::ClassVariable g, AST::ClassVariable v) { + ClassVariableAccess::range(g, v) + } or + TComplementExpr(Generated::Unary g) { g instanceof @unary_tilde } or + TComplexLiteral(Generated::Complex g) or + TDefinedExpr(Generated::Unary g) { g instanceof @unary_definedquestion } or + TDelimitedSymbolLiteral(Generated::DelimitedSymbol g) or + TDestructuredLeftAssignment(Generated::DestructuredLeftAssignment g) or + TDivExpr(Generated::Binary g) { g instanceof @binary_slash } or + TDo(Generated::Do g) or + TDoBlock(Generated::DoBlock g) { not g.getParent() instanceof Generated::Lambda } or + TElementReference(Generated::ElementReference g) or + TElse(Generated::Else g) or + TElsif(Generated::Elsif g) or + TEmptyStmt(Generated::EmptyStatement g) or + TEndBlock(Generated::EndBlock g) or + TEnsure(Generated::Ensure g) or + TEqExpr(Generated::Binary g) { g instanceof @binary_equalequal } or + TExponentExpr(Generated::Binary g) { g instanceof @binary_starstar } or + TFalseLiteral(Generated::False g) or + TFloatLiteral(Generated::Float g) { not any(Generated::Rational r).getChild() = g } or + TForExpr(Generated::For g) or + TForIn(Generated::In g) or // TODO REMOVE + TGEExpr(Generated::Binary g) { g instanceof @binary_rangleequal } or + TGTExpr(Generated::Binary g) { g instanceof @binary_rangle } or + TGlobalVariableAccess(Generated::GlobalVariable g, AST::GlobalVariable v) { + GlobalVariableAccess::range(g, v) + } or + THashKeySymbolLiteral(Generated::HashKeySymbol g) or + THashLiteral(Generated::Hash g) or + THashSplatArgument(Generated::HashSplatArgument g) or + THashSplatParameter(Generated::HashSplatParameter g) or + THereDoc(Generated::HeredocBeginning g) or + TIdentifierMethodCall(Generated::Identifier g) { vcall(g) and not access(g, _) } or + TIf(Generated::If g) or + TIfModifierExpr(Generated::IfModifier g) or + TInstanceVariableAccess(Generated::InstanceVariable g, AST::InstanceVariable v) { + InstanceVariableAccess::range(g, v) + } or + TIntegerLiteral(Generated::Integer g) { not any(Generated::Rational r).getChild() = g } or + TKeywordParameter(Generated::KeywordParameter g) or + TLEExpr(Generated::Binary g) { g instanceof @binary_langleequal } or + TLShiftExpr(Generated::Binary g) { g instanceof @binary_langlelangle } or + TLTExpr(Generated::Binary g) { g instanceof @binary_langle } or + TLambda(Generated::Lambda g) or + TLeftAssignmentList(Generated::LeftAssignmentList g) or + TLocalVariableAccess(Generated::Identifier g, AST::LocalVariable v) { + LocalVariableAccess::range(g, v) + } or + TLogicalAndExpr(Generated::Binary g) { + g instanceof @binary_and or g instanceof @binary_ampersandampersand + } or + TLogicalOrExpr(Generated::Binary g) { g instanceof @binary_or or g instanceof @binary_pipepipe } or + TMethod(Generated::Method g) or + TModule(Generated::Module g) or + TModuloExpr(Generated::Binary g) { g instanceof @binary_percent } or + TMulExpr(Generated::Binary g) { g instanceof @binary_star } or + TNEExpr(Generated::Binary g) { g instanceof @binary_bangequal } or + TNextStmt(Generated::Next g) or + TNilLiteral(Generated::Nil g) or + TNoRegexMatchExpr(Generated::Binary g) { g instanceof @binary_bangtilde } or + TNotExpr(Generated::Unary g) { g instanceof @unary_bang or g instanceof @unary_not } or + TOptionalParameter(Generated::OptionalParameter g) or + TPair(Generated::Pair g) or + TParenthesizedExpr(Generated::ParenthesizedStatements g) or + TRShiftExpr(Generated::Binary g) { g instanceof @binary_ranglerangle } or + TRangeLiteral(Generated::Range g) or + TRationalLiteral(Generated::Rational g) or + TRedoStmt(Generated::Redo g) or + TRegexLiteral(Generated::Regex g) or + TRegexMatchExpr(Generated::Binary g) { g instanceof @binary_equaltilde } or + TRegularArrayLiteral(Generated::Array g) or + TRegularMethodCall(Generated::Call g) { not g.getMethod() instanceof Generated::Super } or + TRegularStringLiteral(Generated::String g) or + TRegularSuperCall(Generated::Call g) { g.getMethod() instanceof Generated::Super } or + TRescueClause(Generated::Rescue g) or + TRescueModifierExpr(Generated::RescueModifier g) or + TRetryStmt(Generated::Retry g) or + TReturnStmt(Generated::Return g) or + TScopeResolutionConstantAccess(Generated::ScopeResolution g, Generated::Constant constant) { + constant = g.getName() and + ( + // A tree-sitter `scope_resolution` node with a `constant` name field is a + // read of that constant in any context where an identifier would be a + // vcall. + vcall(g) + or + explicitAssignmentNode(g, _) + ) + } or + TScopeResolutionMethodCall(Generated::ScopeResolution g, Generated::Identifier i) { + i = g.getName() and + not exists(Generated::Call c | c.getMethod() = g) + } or + TSelf(Generated::Self g) or + TSimpleParameter(Generated::Identifier g) { g instanceof Parameter::Range } or + TSimpleSymbolLiteral(Generated::SimpleSymbol g) or + TSingletonClass(Generated::SingletonClass g) or + TSingletonMethod(Generated::SingletonMethod g) or + TSpaceshipExpr(Generated::Binary g) { g instanceof @binary_langleequalrangle } or + TSplatArgument(Generated::SplatArgument g) or + TSplatParameter(Generated::SplatParameter g) or + TStringArrayLiteral(Generated::StringArray g) or + TStringConcatenation(Generated::ChainedString g) or + TStringEscapeSequenceComponent(Generated::EscapeSequence g) or + TStringInterpolationComponent(Generated::Interpolation g) or + TStringTextComponent(Generated::Token g) { + g instanceof Generated::StringContent or g instanceof Generated::HeredocContent + } or + TSubExpr(Generated::Binary g) { g instanceof @binary_minus } or + TSubshellLiteral(Generated::Subshell g) or + TSymbolArrayLiteral(Generated::SymbolArray g) or + TTernaryIfExpr(Generated::Conditional g) or + TThen(Generated::Then g) or + TTokenConstantAccess(Generated::Constant g) { + // A tree-sitter `constant` token is a read of that constant in any context + // where an identifier would be a vcall. + vcall(g) + or + explicitAssignmentNode(g, _) + } or + TTokenMethodName(MethodName::Token g) { MethodName::range(g) } or + TTokenSuperCall(Generated::Super g) { vcall(g) } or + TToplevel(Generated::Program g) { g.getLocation().getFile().getExtension() != "erb" } or + TTrueLiteral(Generated::True g) or + TTuplePatternParameter(Generated::DestructuredParameter g) or + TUnaryMinusExpr(Generated::Unary g) { g instanceof @unary_minus } or + TUnaryPlusExpr(Generated::Unary g) { g instanceof @unary_plus } or + TUndefStmt(Generated::Undef g) or + TUnlessExpr(Generated::Unless g) or + TUnlessModifierExpr(Generated::UnlessModifier g) or + TUntilExpr(Generated::Until g) or + TUntilModifierExpr(Generated::UntilModifier g) or + TWhenExpr(Generated::When g) or + TWhileExpr(Generated::While g) or + TWhileModifierExpr(Generated::WhileModifier g) or + TYieldCall(Generated::Yield g) - Location getLocation() { result = generated.getLocation() } - - predicate child(string label, AstNode::Range child) { none() } + /** Gets the underlying TreeSitter entity for a given AST node. */ + cached + Generated::AstNode toGenerated(AST::AstNode n) { + n = TAddExpr(result) or + n = TAliasStmt(result) or + n = TArgumentList(result) or + n = TAssignAddExpr(result) or + n = TAssignBitwiseAndExpr(result) or + n = TAssignBitwiseOrExpr(result) or + n = TAssignBitwiseXorExpr(result) or + n = TAssignDivExpr(result) or + n = TAssignExponentExpr(result) or + n = TAssignExpr(result) or + n = TAssignLShiftExpr(result) or + n = TAssignLogicalAndExpr(result) or + n = TAssignLogicalOrExpr(result) or + n = TAssignModuloExpr(result) or + n = TAssignMulExpr(result) or + n = TAssignRShiftExpr(result) or + n = TAssignSubExpr(result) or + n = TBareStringLiteral(result) or + n = TBareSymbolLiteral(result) or + n = TBeginBlock(result) or + n = TBeginExpr(result) or + n = TBitwiseAndExpr(result) or + n = TBitwiseOrExpr(result) or + n = TBitwiseXorExpr(result) or + n = TBlockArgument(result) or + n = TBlockParameter(result) or + n = TBraceBlock(result) or + n = TBreakStmt(result) or + n = TCaseEqExpr(result) or + n = TCaseExpr(result) or + n = TCharacterLiteral(result) or + n = TClass(result) or + n = TClassVariableAccess(result, _) or + n = TComplementExpr(result) or + n = TComplexLiteral(result) or + n = TDefinedExpr(result) or + n = TDelimitedSymbolLiteral(result) or + n = TDestructuredLeftAssignment(result) or + n = TDivExpr(result) or + n = TDo(result) or + n = TDoBlock(result) or + n = TElementReference(result) or + n = TElse(result) or + n = TElsif(result) or + n = TEmptyStmt(result) or + n = TEndBlock(result) or + n = TEnsure(result) or + n = TEqExpr(result) or + n = TExponentExpr(result) or + n = TFalseLiteral(result) or + n = TFloatLiteral(result) or + n = TForExpr(result) or + n = TForIn(result) or // TODO REMOVE + n = TGEExpr(result) or + n = TGTExpr(result) or + n = TGlobalVariableAccess(result, _) or + n = THashKeySymbolLiteral(result) or + n = THashLiteral(result) or + n = THashSplatArgument(result) or + n = THashSplatParameter(result) or + n = THereDoc(result) or + n = TIdentifierMethodCall(result) or + n = TIf(result) or + n = TIfModifierExpr(result) or + n = TInstanceVariableAccess(result, _) or + n = TIntegerLiteral(result) or + n = TKeywordParameter(result) or + n = TLEExpr(result) or + n = TLShiftExpr(result) or + n = TLTExpr(result) or + n = TLambda(result) or + n = TLeftAssignmentList(result) or + n = TLocalVariableAccess(result, _) or + n = TLogicalAndExpr(result) or + n = TLogicalOrExpr(result) or + n = TMethod(result) or + n = TModule(result) or + n = TModuloExpr(result) or + n = TMulExpr(result) or + n = TNEExpr(result) or + n = TNextStmt(result) or + n = TNilLiteral(result) or + n = TNoRegexMatchExpr(result) or + n = TNotExpr(result) or + n = TOptionalParameter(result) or + n = TPair(result) or + n = TParenthesizedExpr(result) or + n = TRShiftExpr(result) or + n = TRangeLiteral(result) or + n = TRationalLiteral(result) or + n = TRedoStmt(result) or + n = TRegexLiteral(result) or + n = TRegexMatchExpr(result) or + n = TRegularArrayLiteral(result) or + n = TRegularMethodCall(result) or + n = TRegularStringLiteral(result) or + n = TRegularSuperCall(result) or + n = TRescueClause(result) or + n = TRescueModifierExpr(result) or + n = TRetryStmt(result) or + n = TReturnStmt(result) or + n = TScopeResolutionConstantAccess(result, _) or + n = TScopeResolutionMethodCall(result, _) or + n = TSelf(result) or + n = TSimpleParameter(result) or + n = TSimpleSymbolLiteral(result) or + n = TSingletonClass(result) or + n = TSingletonMethod(result) or + n = TSpaceshipExpr(result) or + n = TSplatArgument(result) or + n = TSplatParameter(result) or + n = TStringArrayLiteral(result) or + n = TStringConcatenation(result) or + n = TStringEscapeSequenceComponent(result) or + n = TStringInterpolationComponent(result) or + n = TStringTextComponent(result) or + n = TSubExpr(result) or + n = TSubshellLiteral(result) or + n = TSymbolArrayLiteral(result) or + n = TTernaryIfExpr(result) or + n = TThen(result) or + n = TTokenConstantAccess(result) or + n = TTokenMethodName(result) or + n = TTokenSuperCall(result) or + n = TToplevel(result) or + n = TTrueLiteral(result) or + n = TTuplePatternParameter(result) or + n = TUnaryMinusExpr(result) or + n = TUnaryPlusExpr(result) or + n = TUndefStmt(result) or + n = TUnlessExpr(result) or + n = TUnlessModifierExpr(result) or + n = TUntilExpr(result) or + n = TUntilModifierExpr(result) or + n = TWhenExpr(result) or + n = TWhileExpr(result) or + n = TWhileModifierExpr(result) or + n = TYieldCall(result) } } + +import Cached + +TAstNode fromGenerated(Generated::AstNode n) { n = toGenerated(result) } + +class TCall = TMethodCall or TYieldCall; + +class TMethodCall = + TIdentifierMethodCall or TScopeResolutionMethodCall or TRegularMethodCall or TElementReference or + TSuperCall; + +class TSuperCall = TTokenSuperCall or TRegularSuperCall; + +class TConstantAccess = TTokenConstantAccess or TScopeResolutionConstantAccess or TNamespace; + +class TControlExpr = TConditionalExpr or TCaseExpr or TLoop; + +class TConditionalExpr = + TIfExpr or TUnlessExpr or TIfModifierExpr or TUnlessModifierExpr or TTernaryIfExpr; + +class TIfExpr = TIf or TElsif; + +class TConditionalLoop = TWhileExpr or TUntilExpr or TWhileModifierExpr or TUntilModifierExpr; + +class TLoop = TConditionalLoop or TForExpr; + +class TExpr = + TSelf or TArgumentList or TRescueClause or TRescueModifierExpr or TPair or TStringConcatenation or + TCall or TBlockArgument or TSplatArgument or THashSplatArgument or TConstantAccess or + TControlExpr or TWhenExpr or TLiteral or TCallable or TVariableAccess or TStmtSequence or + TOperation or TSimpleParameter; + +class TStmtSequence = + TBeginBlock or TEndBlock or TThen or TElse or TDo or TEnsure or TStringInterpolationComponent or + TBlock or TBodyStmt or TParenthesizedExpr; + +class TBodyStmt = TBeginExpr or TModuleBase or TMethod or TLambda or TDoBlock or TSingletonMethod; + +class TLiteral = + TNumericLiteral or TNilLiteral or TBooleanLiteral or TStringlikeLiteral or TCharacterLiteral or + TArrayLiteral or THashLiteral or TRangeLiteral or TTokenMethodName; + +class TNumericLiteral = TIntegerLiteral or TFloatLiteral or TRationalLiteral or TComplexLiteral; + +class TBooleanLiteral = TTrueLiteral or TFalseLiteral; + +class TStringComponent = + TStringTextComponent or TStringEscapeSequenceComponent or TStringInterpolationComponent; + +class TStringlikeLiteral = + TStringLiteral or TRegexLiteral or TSymbolLiteral or TSubshellLiteral or THereDoc; + +class TStringLiteral = TRegularStringLiteral or TBareStringLiteral; + +class TSymbolLiteral = TSimpleSymbolLiteral or TComplexSymbolLiteral or THashKeySymbolLiteral; + +class TComplexSymbolLiteral = TDelimitedSymbolLiteral or TBareSymbolLiteral; + +class TArrayLiteral = TRegularArrayLiteral or TStringArrayLiteral or TSymbolArrayLiteral; + +class TCallable = TMethodBase or TLambda or TBlock; + +class TMethodBase = TMethod or TSingletonMethod; + +class TBlock = TDoBlock or TBraceBlock; + +class TModuleBase = TToplevel or TNamespace or TSingletonClass; + +class TNamespace = TClass or TModule; + +class TOperation = TUnaryOperation or TBinaryOperation or TAssignment; + +class TUnaryOperation = + TUnaryLogicalOperation or TUnaryArithmeticOperation or TUnaryBitwiseOperation or TDefinedExpr; + +class TUnaryLogicalOperation = TNotExpr; + +class TUnaryArithmeticOperation = TUnaryPlusExpr or TUnaryMinusExpr; + +class TUnaryBitwiseOperation = TComplementExpr; + +class TBinaryOperation = + TBinaryArithmeticOperation or TBinaryLogicalOperation or TBinaryBitwiseOperation or + TComparisonOperation or TSpaceshipExpr or TRegexMatchExpr or TNoRegexMatchExpr; + +class TBinaryArithmeticOperation = + TAddExpr or TSubExpr or TMulExpr or TDivExpr or TModuloExpr or TExponentExpr; + +class TBinaryLogicalOperation = TLogicalAndExpr or TLogicalOrExpr; + +class TBinaryBitwiseOperation = + TLShiftExpr or TRShiftExpr or TBitwiseAndExpr or TBitwiseOrExpr or TBitwiseXorExpr; + +class TComparisonOperation = TEqualityOperation or TRelationalOperation; + +class TEqualityOperation = TEqExpr or TNEExpr or TCaseEqExpr; + +class TRelationalOperation = TGTExpr or TGEExpr or TLTExpr or TLEExpr; + +class TAssignment = TAssignExpr or TAssignOperation; + +class TAssignOperation = + TAssignArithmeticOperation or TAssignLogicalOperation or TAssignBitwiseOperation; + +class TAssignArithmeticOperation = + TAssignAddExpr or TAssignSubExpr or TAssignMulExpr or TAssignDivExpr or TAssignModuloExpr or + TAssignExponentExpr; + +class TAssignLogicalOperation = TAssignLogicalAndExpr or TAssignLogicalOrExpr; + +class TAssignBitwiseOperation = + TAssignLShiftExpr or TAssignRShiftExpr or TAssignBitwiseAndExpr or TAssignBitwiseOrExpr or + TAssignBitwiseXorExpr; + +class TStmt = + TEmptyStmt or TBodyStmt or TStmtSequence or TUndefStmt or TAliasStmt or TReturningStmt or + TRedoStmt or TRetryStmt or TExpr; + +class TReturningStmt = TReturnStmt or TBreakStmt or TNextStmt; + +class TParameter = + TPatternParameter or TBlockParameter or THashSplatParameter or TKeywordParameter or + TOptionalParameter or TSplatParameter; + +class TPatternParameter = TSimpleParameter or TTuplePatternParameter; + +class TNamedParameter = + TSimpleParameter or TBlockParameter or THashSplatParameter or TKeywordParameter or + TOptionalParameter or TSplatParameter; + +class TTuplePattern = TTuplePatternParameter or TDestructuredLeftAssignment or TLeftAssignmentList; + +class TVariableAccess = + TLocalVariableAccess or TGlobalVariableAccess or TInstanceVariableAccess or TClassVariableAccess; diff --git a/ql/src/codeql_ruby/ast/internal/Call.qll b/ql/src/codeql_ruby/ast/internal/Call.qll deleted file mode 100644 index 697b57653e9..00000000000 --- a/ql/src/codeql_ruby/ast/internal/Call.qll +++ /dev/null @@ -1,262 +0,0 @@ -private import codeql_ruby.AST -private import codeql_ruby.ast.internal.AST -private import codeql_ruby.ast.internal.Expr -private import codeql_ruby.ast.internal.Pattern -private import codeql_ruby.ast.internal.TreeSitter -private import codeql_ruby.ast.internal.Variable - -module Call { - abstract class Range extends Expr::Range { - abstract Expr getArgument(int n); - - override predicate child(string label, AstNode::Range child) { - label = "getArgument" and child = getArgument(_) - } - } -} - -module MethodCall { - class Range extends Call::Range { - MethodCallRange::Range range; - - Range() { this = range } - - final Block getBlock() { result = range.getBlock() } - - final Expr getReceiver() { result = range.getReceiver() } - - final override Expr getArgument(int n) { result = range.getArgument(n) } - - abstract string getMethodName(); - - override string toString() { - result = range.toString() - or - not exists(range.toString()) and result = "call to " + concat(this.getMethodName(), "/") - } - - final override predicate child(string label, AstNode::Range child) { - super.child(label, child) - or - label = "getReceiver" and child = getReceiver() - or - label = "getBlock" and child = getBlock() - } - } -} - -module MethodCallRange { - abstract class Range extends @ast_node { - Generated::AstNode generated; - - Range() { this = generated } - - abstract Block getBlock(); - - abstract Expr getReceiver(); - - abstract string getMethod(); - - abstract Expr getArgument(int n); - - string toString() { none() } - } - - private class IdentifierCallRange extends MethodCallRange::Range, @token_identifier { - final override Generated::Identifier generated; - - IdentifierCallRange() { vcall(this) and not access(this, _) } - - final override Expr getReceiver() { none() } - - final override string getMethod() { result = generated.getValue() } - - final override Expr getArgument(int n) { none() } - - final override Block getBlock() { none() } - } - - private class ScopeResolutionIdentifierCallRange extends MethodCallRange::Range, @scope_resolution { - final override Generated::ScopeResolution generated; - Generated::Identifier identifier; - - ScopeResolutionIdentifierCallRange() { - identifier = generated.getName() and - not exists(Generated::Call c | c.getMethod() = this) - } - - final override Expr getReceiver() { result = generated.getScope() } - - final override string getMethod() { result = identifier.getValue() } - - final override Expr getArgument(int n) { none() } - - final override Block getBlock() { none() } - } - - private class RegularCallRange extends MethodCallRange::Range, @call { - final override Generated::Call generated; - - final override Expr getReceiver() { - result = generated.getReceiver() - or - not exists(generated.getReceiver()) and - result = generated.getMethod().(Generated::ScopeResolution).getScope() - } - - final override string getMethod() { - result = "call" and generated.getMethod() instanceof Generated::ArgumentList - or - result = generated.getMethod().(Generated::Token).getValue() - or - result = - generated.getMethod().(Generated::ScopeResolution).getName().(Generated::Token).getValue() - } - - final override Expr getArgument(int n) { - result = generated.getArguments().getChild(n) - or - not exists(generated.getArguments()) and - result = generated.getMethod().(Generated::ArgumentList).getChild(n) - } - - final override Block getBlock() { result = generated.getBlock() } - } -} - -module ElementReferenceRange { - class Range extends MethodCallRange::Range, @element_reference { - final override Generated::ElementReference generated; - - final override Expr getReceiver() { result = generated.getObject() } - - final override string getMethod() { result = "[]" } - - final override string toString() { result = "...[...]" } - - final override Expr getArgument(int n) { result = generated.getChild(n) } - - final override Block getBlock() { none() } - } -} - -module NormalMethodCall { - class Range extends MethodCall::Range { - Range() { - not this instanceof LhsExpr::Range or - generated.getParent() instanceof AssignOperation - } - - final override string getMethodName() { result = range.getMethod() } - } -} - -module SetterMethodCall { - class Range extends MethodCall::Range, LhsExpr::Range { - final override string getMethodName() { result = range.getMethod() + "=" } - - final override string toString() { result = MethodCall::Range.super.toString() } - } -} - -module ElementReference { - class Range extends MethodCall::Range { - override ElementReferenceRange::Range range; - - final override string getMethodName() { none() } - } -} - -module SuperCall { - class Range extends NormalMethodCall::Range { - override SuperCallRange::Range range; - } -} - -module YieldCall { - class Range extends Call::Range, @yield { - final override Generated::Yield generated; - - final override Expr getArgument(int n) { result = generated.getChild().getChild(n) } - - final override string toString() { result = "yield ..." } - } -} - -module SuperCallRange { - abstract class Range extends MethodCallRange::Range { } - - private class SuperTokenCallRange extends SuperCallRange::Range, @token_super { - final override Generated::Super generated; - - // N.B. `super` tokens can never be accesses, so any vcall with `super` must - // be a call. - SuperTokenCallRange() { vcall(this) } - - final override Expr getReceiver() { none() } - - final override string getMethod() { result = generated.getValue() } - - final override Expr getArgument(int n) { none() } - - final override Block getBlock() { none() } - } - - private class RegularSuperCallRange extends SuperCallRange::Range, @call { - final override Generated::Call generated; - - RegularSuperCallRange() { generated.getMethod() instanceof Generated::Super } - - final override Expr getReceiver() { none() } - - final override string getMethod() { - result = generated.getMethod().(Generated::Super).getValue() - } - - final override Expr getArgument(int n) { result = generated.getArguments().getChild(n) } - - final override Block getBlock() { result = generated.getBlock() } - } -} - -module BlockArgument { - class Range extends Expr::Range, @block_argument { - final override Generated::BlockArgument generated; - - final Expr getValue() { result = generated.getChild() } - - final override string toString() { result = "&..." } - - final override predicate child(string label, AstNode::Range child) { - label = "getValue" and child = getValue() - } - } -} - -module SplatArgument { - class Range extends Expr::Range, @splat_argument { - final override Generated::SplatArgument generated; - - final Expr getValue() { result = generated.getChild() } - - final override string toString() { result = "*..." } - - final override predicate child(string label, AstNode::Range child) { - label = "getValue" and child = getValue() - } - } -} - -module HashSplatArgument { - class Range extends Expr::Range, @hash_splat_argument { - final override Generated::HashSplatArgument generated; - - final Expr getValue() { result = generated.getChild() } - - final override string toString() { result = "**..." } - - final override predicate child(string label, AstNode::Range child) { - label = "getValue" and child = getValue() - } - } -} diff --git a/ql/src/codeql_ruby/ast/internal/Constant.qll b/ql/src/codeql_ruby/ast/internal/Constant.qll deleted file mode 100644 index 87082ae35c7..00000000000 --- a/ql/src/codeql_ruby/ast/internal/Constant.qll +++ /dev/null @@ -1,93 +0,0 @@ -private import codeql_ruby.ast.internal.AST -private import codeql_ruby.ast.internal.Expr -private import codeql_ruby.ast.internal.Pattern -private import codeql_ruby.ast.internal.TreeSitter -private import codeql_ruby.ast.internal.Variable - -module ConstantAccess { - abstract class Range extends Expr::Range { - override string toString() { result = this.getName() } - - abstract string getName(); - - abstract Expr::Range getScopeExpr(); - - abstract predicate hasGlobalScope(); - - override predicate child(string label, AstNode::Range child) { - label = "getScopeExpr" and child = getScopeExpr() - } - } -} - -module ConstantReadAccess { - abstract class Range extends ConstantAccess::Range { } - - private class TokenConstantReadAccessRange extends ConstantReadAccess::Range, @token_constant { - final override Generated::Constant generated; - - // A tree-sitter `constant` token is a read of that constant in any context - // where an identifier would be a vcall. - TokenConstantReadAccessRange() { vcall(this) } - - final override string getName() { result = generated.getValue() } - - final override Expr::Range getScopeExpr() { none() } - - final override predicate hasGlobalScope() { none() } - } - - private class ScopeResolutionReadAccessRange extends ConstantReadAccess::Range, @scope_resolution { - final override Generated::ScopeResolution generated; - Generated::Constant constant; - - // A tree-sitter `scope_resolution` node with a `constant` name field is a - // read of that constant in any context where an identifier would be a - // vcall. - ScopeResolutionReadAccessRange() { - constant = generated.getName() and - vcall(this) - } - - final override string getName() { result = constant.getValue() } - - final override Expr::Range getScopeExpr() { result = generated.getScope() } - - final override predicate hasGlobalScope() { not exists(generated.getScope()) } - } -} - -module ConstantWriteAccess { - abstract class Range extends ConstantAccess::Range { } -} - -module ConstantAssignment { - abstract class Range extends ConstantWriteAccess::Range, LhsExpr::Range { - Range() { explicitAssignmentNode(this, _) } - - override string toString() { result = ConstantWriteAccess::Range.super.toString() } - } - - private class TokenConstantAssignmentRange extends ConstantAssignment::Range, @token_constant { - final override Generated::Constant generated; - - final override string getName() { result = generated.getValue() } - - final override Expr::Range getScopeExpr() { none() } - - final override predicate hasGlobalScope() { none() } - } - - private class ScopeResolutionAssignmentRange extends ConstantAssignment::Range, @scope_resolution { - final override Generated::ScopeResolution generated; - Generated::Constant constant; - - ScopeResolutionAssignmentRange() { constant = generated.getName() } - - final override string getName() { result = constant.getValue() } - - final override Expr::Range getScopeExpr() { result = generated.getScope() } - - final override predicate hasGlobalScope() { not exists(generated.getScope()) } - } -} diff --git a/ql/src/codeql_ruby/ast/internal/Control.qll b/ql/src/codeql_ruby/ast/internal/Control.qll deleted file mode 100644 index 3f034ce20b3..00000000000 --- a/ql/src/codeql_ruby/ast/internal/Control.qll +++ /dev/null @@ -1,299 +0,0 @@ -private import codeql_ruby.AST -private import codeql_ruby.ast.internal.AST -private import codeql_ruby.ast.internal.Expr -private import codeql_ruby.ast.internal.Pattern -private import codeql_ruby.ast.internal.TreeSitter - -module ControlExpr { - abstract class Range extends Expr::Range { } -} - -module ConditionalExpr { - abstract class Range extends ControlExpr::Range { - abstract Expr getCondition(); - - abstract Stmt getBranch(boolean cond); - - override predicate child(string label, AstNode::Range child) { - label = "getCondition" and child = getCondition() - or - label = "getBranch" and child = getBranch(_) - } - } -} - -module IfExpr { - abstract class Range extends ConditionalExpr::Range { - abstract Stmt getThen(); - - abstract Stmt getElse(); - - final override string toString() { - if this instanceof @elsif then result = "elsif ..." else result = "if ..." - } - - override predicate child(string label, AstNode::Range child) { - super.child(label, child) - or - label = "getThen" and child = getThen() - or - label = "getElse" and child = getElse() - } - } - - private class IfRange extends IfExpr::Range, @if { - final override Generated::If generated; - - final override Expr getCondition() { result = generated.getCondition() } - - final override Stmt getThen() { result = generated.getConsequence() } - - final override Stmt getElse() { result = generated.getAlternative() } - - final override Stmt getBranch(boolean cond) { - cond = true and result = getThen() - or - cond = false and result = getElse() - } - } - - private class ElsifRange extends IfExpr::Range, @elsif { - final override Generated::Elsif generated; - - final override Expr getCondition() { result = generated.getCondition() } - - final override Stmt getThen() { result = generated.getConsequence() } - - final override Stmt getElse() { result = generated.getAlternative() } - - final override Expr getBranch(boolean cond) { - cond = true and result = getThen() - or - cond = false and result = getElse() - } - } -} - -module UnlessExpr { - class Range extends ConditionalExpr::Range, @unless { - final override Generated::Unless generated; - - final override Expr getCondition() { result = generated.getCondition() } - - final Stmt getThen() { result = generated.getConsequence() } - - final Stmt getElse() { result = generated.getAlternative() } - - final override Expr getBranch(boolean cond) { - cond = false and result = getThen() - or - cond = true and result = getElse() - } - - final override string toString() { result = "unless ..." } - - override predicate child(string label, AstNode::Range child) { - ConditionalExpr::Range.super.child(label, child) - or - label = "getThen" and child = getThen() - or - label = "getElse" and child = getElse() - } - } -} - -module IfModifierExpr { - class Range extends ConditionalExpr::Range, @if_modifier { - final override Generated::IfModifier generated; - - final override Expr getCondition() { result = generated.getCondition() } - - final Stmt getBody() { result = generated.getBody() } - - final override Stmt getBranch(boolean cond) { cond = true and result = getBody() } - - final override string toString() { result = "... if ..." } - - override predicate child(string label, AstNode::Range child) { - ConditionalExpr::Range.super.child(label, child) - or - label = "getBody" and child = getBody() - } - } -} - -module UnlessModifierExpr { - class Range extends ConditionalExpr::Range, @unless_modifier { - final override Generated::UnlessModifier generated; - - final override Expr getCondition() { result = generated.getCondition() } - - final Stmt getBody() { result = generated.getBody() } - - final override Stmt getBranch(boolean cond) { cond = false and result = getBody() } - - final override string toString() { result = "... unless ..." } - - override predicate child(string label, AstNode::Range child) { - ConditionalExpr::Range.super.child(label, child) - or - label = "getBody" and child = getBody() - } - } -} - -module TernaryIfExpr { - class Range extends ConditionalExpr::Range, @conditional { - final override Generated::Conditional generated; - - final override Expr getCondition() { result = generated.getCondition() } - - final Stmt getThen() { result = generated.getConsequence() } - - final Stmt getElse() { result = generated.getAlternative() } - - final override Stmt getBranch(boolean cond) { - cond = true and result = getThen() - or - cond = false and result = getElse() - } - - final override string toString() { result = "... ? ... : ..." } - - override predicate child(string label, AstNode::Range child) { - ConditionalExpr::Range.super.child(label, child) - or - label = "getThen" and child = getThen() - or - label = "getElse" and child = getElse() - } - } -} - -module CaseExpr { - class Range extends ControlExpr::Range, @case__ { - final override Generated::Case generated; - - final Expr getValue() { result = generated.getValue() } - - final Expr getBranch(int n) { result = generated.getChild(n) } - - final override string toString() { result = "case ..." } - - override predicate child(string label, AstNode::Range child) { - label = "getValue" and child = getValue() - or - label = "getBranch" and child = getBranch(_) - } - } -} - -module WhenExpr { - class Range extends Expr::Range, @when { - final override Generated::When generated; - - final Stmt getBody() { result = generated.getBody() } - - final Expr getPattern(int n) { result = generated.getPattern(n).getChild() } - - final override string toString() { result = "when ..." } - - override predicate child(string label, AstNode::Range child) { - label = "getBody" and child = getBody() - or - label = "getPattern" and child = getPattern(_) - } - } -} - -module Loop { - abstract class Range extends ControlExpr::Range { - abstract Stmt getBody(); - - override predicate child(string label, AstNode::Range child) { - label = "getBody" and child = getBody() - } - } -} - -module ConditionalLoop { - abstract class Range extends Loop::Range { - abstract Expr getCondition(); - - override predicate child(string label, AstNode::Range child) { - super.child(label, child) - or - label = "getCondition" and child = getCondition() - } - } -} - -module WhileExpr { - class Range extends ConditionalLoop::Range, @while { - final override Generated::While generated; - - final override Stmt getBody() { result = generated.getBody() } - - final override Expr getCondition() { result = generated.getCondition() } - - final override string toString() { result = "while ..." } - } -} - -module UntilExpr { - class Range extends ConditionalLoop::Range, @until { - final override Generated::Until generated; - - final override Stmt getBody() { result = generated.getBody() } - - final override Expr getCondition() { result = generated.getCondition() } - - final override string toString() { result = "until ..." } - } -} - -module WhileModifierExpr { - class Range extends ConditionalLoop::Range, @while_modifier { - final override Generated::WhileModifier generated; - - final override Stmt getBody() { result = generated.getBody() } - - final override Expr getCondition() { result = generated.getCondition() } - - final override string toString() { result = "... while ..." } - } -} - -module UntilModifierExpr { - class Range extends ConditionalLoop::Range, @until_modifier { - final override Generated::UntilModifier generated; - - final override Stmt getBody() { result = generated.getBody() } - - final override Expr getCondition() { result = generated.getCondition() } - - final override string toString() { result = "... until ..." } - } -} - -module ForExpr { - class Range extends Loop::Range, @for { - final override Generated::For generated; - - final override StmtSequence getBody() { result = generated.getBody() } - - final Pattern getPattern() { result = generated.getPattern() } - - final Expr getValue() { result = generated.getValue().getChild() } - - final override string toString() { result = "for ... in ..." } - - override predicate child(string label, AstNode::Range child) { - Loop::Range.super.child(label, child) - or - label = "getPattern" and child = getPattern() - or - label = "getValue" and child = getValue() - } - } -} diff --git a/ql/src/codeql_ruby/ast/internal/Expr.qll b/ql/src/codeql_ruby/ast/internal/Expr.qll deleted file mode 100644 index f2014dcdd54..00000000000 --- a/ql/src/codeql_ruby/ast/internal/Expr.qll +++ /dev/null @@ -1,227 +0,0 @@ -private import codeql_ruby.AST -private import codeql_ruby.ast.internal.AST -private import codeql_ruby.ast.internal.Literal -private import codeql_ruby.ast.internal.Statement -private import codeql_ruby.ast.internal.TreeSitter - -module Expr { - abstract class Range extends Stmt::Range { } -} - -module Self { - class Range extends Expr::Range, @token_self { - final override Generated::Self generated; - - final override string toString() { result = "self" } - } -} - -module ArgumentList { - private class ValidParent = @break or @return or @next or @assignment or @operator_assignment; - - abstract class Range extends Expr::Range { - Range() { generated.getParent() instanceof ValidParent } - - abstract Expr getElement(int i); - - final override string toString() { result = "..., ..." } - - override predicate child(string label, AstNode::Range child) { - label = "getElement" and child = getElement(_) - } - } - - private class ArgArgumentList extends ArgumentList::Range, @argument_list { - final override Generated::ArgumentList generated; - - ArgArgumentList() { strictcount(generated.getChild(_)) > 1 } - - final override Expr getElement(int i) { result = generated.getChild(i) } - } - - private class AssignmentList extends ArgumentList::Range, @right_assignment_list { - final override Generated::RightAssignmentList generated; - - final override Expr getElement(int i) { result = generated.getChild(i) } - } -} - -module StmtSequence { - abstract class Range extends Expr::Range { - abstract Stmt getStmt(int n); - - int getNumberOfStatements() { result = count(this.getStmt(_)) } - - override string toString() { - exists(int c | c = this.getNumberOfStatements() | - c = 0 and result = ";" - or - c = 1 and result = this.getStmt(0).toString() - or - c > 1 and result = "...; ..." - ) - } - - override predicate child(string label, AstNode::Range child) { - label = "getStmt" and child = getStmt(_) - } - } -} - -module BodyStatement { - abstract class Range extends StmtSequence::Range { - final override Stmt getStmt(int n) { - result = - rank[n + 1](Generated::AstNode node, int i | - node = getChild(i) and - not node instanceof Generated::Else and - not node instanceof Generated::Rescue and - not node instanceof Generated::Ensure - | - node order by i - ) - } - - final RescueClause getRescue(int n) { - result = rank[n + 1](Generated::Rescue node, int i | node = getChild(i) | node order by i) - } - - final StmtSequence getElse() { result = unique(Generated::Else s | s = getChild(_)) } - - final StmtSequence getEnsure() { result = unique(Generated::Ensure s | s = getChild(_)) } - - abstract Generated::AstNode getChild(int i); - - override predicate child(string label, AstNode::Range child) { - StmtSequence::Range.super.child(label, child) - or - label = "getRescue" and child = getRescue(_) - or - label = "getElse" and child = getElse() - or - label = "getEnsure" and child = getEnsure() - } - } -} - -module ParenthesizedExpr { - class Range extends StmtSequence::Range, @parenthesized_statements { - final override Generated::ParenthesizedStatements generated; - - final override Stmt getStmt(int n) { result = generated.getChild(n) } - - final override string toString() { - exists(int c | c = this.getNumberOfStatements() | - c = 0 and result = "()" - or - c > 0 and result = "(" + StmtSequence::Range.super.toString() + ")" - ) - } - } -} - -module ThenExpr { - class Range extends StmtSequence::Range, @then { - final override Generated::Then generated; - - final override Stmt getStmt(int n) { result = generated.getChild(n) } - } -} - -module ElseExpr { - class Range extends StmtSequence::Range, @else { - final override Generated::Else generated; - - final override Stmt getStmt(int n) { result = generated.getChild(n) } - } -} - -module DoExpr { - class Range extends StmtSequence::Range, @do { - final override Generated::Do generated; - - final override Stmt getStmt(int n) { result = generated.getChild(n) } - } -} - -module Ensure { - class Range extends StmtSequence::Range, @ensure { - final override Generated::Ensure generated; - - final override Stmt getStmt(int n) { result = generated.getChild(n) } - - final override string toString() { result = "ensure ..." } - } -} - -module RescueClause { - class Range extends Expr::Range, @rescue { - final override Generated::Rescue generated; - - final Expr getException(int n) { result = generated.getExceptions().getChild(n) } - - final LhsExpr getVariableExpr() { result = generated.getVariable().getChild() } - - final StmtSequence getBody() { result = generated.getBody() } - - final override string toString() { result = "rescue ..." } - - override predicate child(string label, AstNode::Range child) { - label = "getException" and child = getException(_) - or - label = "getVariableExpr" and child = getVariableExpr() - or - label = "getBody" and child = getBody() - } - } -} - -module RescueModifierExpr { - class Range extends Expr::Range, @rescue_modifier { - final override Generated::RescueModifier generated; - - final Stmt getBody() { result = generated.getBody() } - - final Stmt getHandler() { result = generated.getHandler() } - - final override string toString() { result = "... rescue ..." } - - override predicate child(string label, AstNode::Range child) { - label = "getBody" and child = getBody() - or - label = "getHandler" and child = getHandler() - } - } -} - -module Pair { - class Range extends Expr::Range, @pair { - final override Generated::Pair generated; - - final Expr getKey() { result = generated.getKey() } - - final Expr getValue() { result = generated.getValue() } - - final override string toString() { result = "Pair" } - - override predicate child(string label, AstNode::Range child) { - label = "getKey" and child = getKey() - or - label = "getValue" and child = getValue() - } - } -} - -module StringConcatenation { - class Range extends Expr::Range, @chained_string { - final override Generated::ChainedString generated; - - final StringLiteral::Range getString(int i) { result = generated.getChild(i) } - - final override string toString() { result = "\"...\" \"...\"" } - - override predicate child(string label, AstNode::Range child) { - label = "getString" and child = getString(_) - } - } -} diff --git a/ql/src/codeql_ruby/ast/internal/Literal.qll b/ql/src/codeql_ruby/ast/internal/Literal.qll deleted file mode 100644 index 0f46a1fabd9..00000000000 --- a/ql/src/codeql_ruby/ast/internal/Literal.qll +++ /dev/null @@ -1,446 +0,0 @@ -private import codeql_ruby.AST -private import codeql_ruby.ast.internal.AST -private import codeql_ruby.ast.internal.Expr -private import codeql_ruby.ast.internal.TreeSitter - -module Literal { - abstract class Range extends Expr::Range { - abstract string getValueText(); - - override string toString() { result = this.getValueText() } - } -} - -module NumericLiteral { - abstract class Range extends Literal::Range { } -} - -module IntegerLiteral { - class Range extends NumericLiteral::Range, @token_integer { - final override Generated::Integer generated; - - Range() { not any(Generated::Rational r).getChild() = this } - - final override string getValueText() { result = generated.getValue() } - - final override string toString() { result = this.getValueText() } - } -} - -module FloatLiteral { - class Range extends NumericLiteral::Range, @token_float { - final override Generated::Float generated; - - Range() { not any(Generated::Rational r).getChild() = this } - - final override string getValueText() { result = generated.getValue() } - - final override string toString() { result = this.getValueText() } - } -} - -module RationalLiteral { - class Range extends NumericLiteral::Range, @rational { - final override Generated::Rational generated; - - final override string getValueText() { - result = generated.getChild().(Generated::Token).getValue() + "r" - } - - final override string toString() { result = this.getValueText() } - } -} - -module ComplexLiteral { - class Range extends NumericLiteral::Range, @token_complex { - final override Generated::Complex generated; - - final override string getValueText() { result = generated.getValue() } - - final override string toString() { result = this.getValueText() } - } -} - -module NilLiteral { - class Range extends Literal::Range, @token_nil { - final override Generated::Nil generated; - - final override string getValueText() { result = generated.getValue() } - - final override string toString() { result = this.getValueText() } - } -} - -module BooleanLiteral { - class DbUnion = @token_true or @token_false; - - class Range extends Literal::Range, DbUnion { - final override Generated::Token generated; - - final override string getValueText() { result = generated.getValue() } - - final override string toString() { result = this.getValueText() } - - predicate isTrue() { this instanceof @token_true } - - predicate isFalse() { this instanceof @token_false } - } -} - -module StringComponent { - abstract class Range extends AstNode::Range { - abstract string getValueText(); - } -} - -module StringTextComponent { - class StringContentToken = @token_string_content or @token_heredoc_content; - - class Range extends StringComponent::Range, StringContentToken { - final override Generated::Token generated; - - final override string toString() { result = generated.getValue() } - - final override string getValueText() { result = generated.getValue() } - } -} - -module StringEscapeSequenceComponent { - class Range extends StringComponent::Range, @token_escape_sequence { - final override Generated::EscapeSequence generated; - - final override string toString() { result = generated.getValue() } - - final override string getValueText() { result = generated.getValue() } - } -} - -module StringInterpolationComponent { - class Range extends StringComponent::Range, StmtSequence::Range, @interpolation { - final override Generated::Interpolation generated; - - final override string toString() { result = "#{...}" } - - final override Stmt getStmt(int n) { result = generated.getChild(n) } - - final override string getValueText() { none() } - - override predicate child(string label, AstNode::Range child) { - StmtSequence::Range.super.child(label, child) - } - } -} - -module StringlikeLiteral { - abstract class Range extends Literal::Range { - abstract StringComponent::Range getComponent(int i); - - string getStartDelimiter() { result = "" } - - string getEndDelimiter() { result = "" } - - final predicate isSimple() { count(this.getComponent(_)) <= 1 } - - override string getValueText() { - // 0 components should result in the empty string - // if there are any interpolations, there should be no result - // otherwise, concatenate all the components - forall(StringComponent c | c = this.getComponent(_) | - not c instanceof StringInterpolationComponent::Range - ) and - result = - concat(StringComponent::Range c, int i | - c = this.getComponent(i) - | - c.getValueText() order by i - ) - } - - override string toString() { - exists(string full, string summary | - full = - concat(StringComponent::Range c, int i, string s | - c = this.getComponent(i) and - if c instanceof Generated::Token - then s = c.(Generated::Token).getValue() - else s = "#{...}" - | - s order by i - ) and - ( - // summary should be 32 chars max (incl. ellipsis) - full.length() > 32 and summary = full.substring(0, 29) + "..." - or - full.length() <= 32 and summary = full - ) and - result = this.getStartDelimiter() + summary + this.getEndDelimiter() - ) - } - - override predicate child(string label, AstNode::Range child) { - label = "getComponent" and child = getComponent(_) - } - } -} - -module StringLiteral { - abstract class Range extends StringlikeLiteral::Range { - final override string getStartDelimiter() { result = "\"" } - - final override string getEndDelimiter() { result = "\"" } - } - - private class RegularStringRange extends StringLiteral::Range, @string__ { - final override Generated::String generated; - - final override StringComponent::Range getComponent(int i) { result = generated.getChild(i) } - } - - private class BareStringRange extends StringLiteral::Range, @bare_string { - final override Generated::BareString generated; - - final override StringComponent::Range getComponent(int i) { result = generated.getChild(i) } - } -} - -module RegexLiteral { - class Range extends StringlikeLiteral::Range, @regex { - final override Generated::Regex generated; - - final override StringComponent::Range getComponent(int i) { result = generated.getChild(i) } - - final override string getStartDelimiter() { result = "/" } - - final override string getEndDelimiter() { result = "/" } - - final string getFlagString() { - // For `/foo/i`, there should be an `/i` token in the database with `this` - // as its parents. Strip the delimiter, which can vary. - result = - max(Generated::Token t | - t.getParent() = this - | - t.getValue().suffix(1) order by t.getParentIndex() - ) - } - } -} - -module SymbolLiteral { - abstract class Range extends StringlikeLiteral::Range { } - - class SimpleSymbolRange extends SymbolLiteral::Range { - final override Generated::SimpleSymbol generated; - - final override StringComponent::Range getComponent(int i) { none() } - - final override string getStartDelimiter() { result = ":" } - - // Tree-sitter gives us value text including the colon, which we skip. - final override string getValueText() { result = generated.getValue().suffix(1) } - - final override string toString() { result = generated.getValue() } - } - - abstract private class ComplexSymbolRange extends SymbolLiteral::Range { - final override string getStartDelimiter() { result = ":\"" } - - final override string getEndDelimiter() { result = "\"" } - } - - class DelimitedSymbolRange extends ComplexSymbolRange, @delimited_symbol { - final override Generated::DelimitedSymbol generated; - - final override StringComponent::Range getComponent(int i) { result = generated.getChild(i) } - } - - class BareSymbolRange extends ComplexSymbolRange, @bare_symbol { - final override Generated::BareSymbol generated; - - final override StringComponent::Range getComponent(int i) { result = generated.getChild(i) } - } - - class HashKeySymbolRange extends SymbolLiteral::Range, @token_hash_key_symbol { - final override Generated::HashKeySymbol generated; - - final override StringComponent::Range getComponent(int i) { none() } - - final override string getValueText() { result = generated.getValue() } - - final override string toString() { result = ":" + this.getValueText() } - } -} - -module SubshellLiteral { - class Range extends StringlikeLiteral::Range, @subshell { - final override Generated::Subshell generated; - - final override StringComponent::Range getComponent(int i) { result = generated.getChild(i) } - - final override string getStartDelimiter() { result = "`" } - - final override string getEndDelimiter() { result = "`" } - } -} - -module CharacterLiteral { - class Range extends Literal::Range, @token_character { - final override Generated::Character generated; - - final override string getValueText() { result = generated.getValue() } - - final override string toString() { result = generated.getValue() } - } -} - -module HereDoc { - private Generated::HeredocBody heredoc(Generated::HeredocBeginning start) { - exists(int i, File f | - start = - rank[i](Generated::HeredocBeginning b | - f = b.getLocation().getFile() - | - b order by b.getLocation().getStartLine(), b.getLocation().getStartColumn() - ) and - result = - rank[i](Generated::HeredocBody b | - f = b.getLocation().getFile() - | - b order by b.getLocation().getStartLine(), b.getLocation().getStartColumn() - ) - ) - } - - class Range extends StringlikeLiteral::Range, @token_heredoc_beginning { - final override Generated::HeredocBeginning generated; - private Generated::HeredocBody body; - - Range() { body = heredoc(this) } - - final override StringComponent::Range getComponent(int n) { result = body.getChild(n) } - - final string getQuoteStyle() { - exists(string s | - s = generated.getValue() and - s.charAt(s.length() - 1) = result and - result = ["'", "`", "\""] - ) - } - - final string getIndentationModifier() { - exists(string s | - s = generated.getValue() and - s.charAt(2) = result and - result = ["-", "~"] - ) - } - - final override string toString() { result = generated.getValue() } - } -} - -module ArrayLiteral { - abstract class Range extends Literal::Range { - final override string getValueText() { none() } - - abstract Expr getElement(int i); - - override predicate child(string label, AstNode::Range child) { - label = "getElement" and child = getElement(_) - } - } - - private class RegularArrayRange extends ArrayLiteral::Range, @array { - final override Generated::Array generated; - - final override Expr getElement(int i) { result = generated.getChild(i) } - - final override string toString() { result = "[...]" } - } - - private class StringArrayRange extends ArrayLiteral::Range, @string_array { - final override Generated::StringArray generated; - - final override Expr getElement(int i) { result = generated.getChild(i) } - - final override string toString() { result = "%w(...)" } - } - - private class SymbolArrayRange extends ArrayLiteral::Range, @symbol_array { - final override Generated::SymbolArray generated; - - final override Expr getElement(int i) { result = generated.getChild(i) } - - final override string toString() { result = "%i(...)" } - } -} - -module HashLiteral { - class Range extends Literal::Range, @hash { - final override Generated::Hash generated; - - final override string getValueText() { none() } - - final Expr getElement(int i) { result = generated.getChild(i) } - - final override string toString() { result = "{...}" } - - override predicate child(string label, AstNode::Range child) { - label = "getElement" and child = getElement(_) - } - } -} - -module RangeLiteral { - class Range extends Literal::Range, @range { - final override Generated::Range generated; - - final override string getValueText() { none() } - - final override string toString() { result = "_ " + generated.getOperator() + " _" } - - final Expr getBegin() { result = generated.getBegin() } - - final Expr getEnd() { result = generated.getEnd() } - - final predicate isInclusive() { this instanceof @range_dotdot } - - final predicate isExclusive() { this instanceof @range_dotdotdot } - - override predicate child(string label, AstNode::Range child) { - label = "getBegin" and child = getBegin() - or - label = "getEnd" and child = getEnd() - } - } -} - -module MethodName { - private class TokenTypes = - @setter or @token_class_variable or @token_constant or @token_global_variable or - @token_identifier or @token_instance_variable or @token_operator; - - abstract class Range extends Literal::Range, @underscore_method_name { - Range() { - exists(Generated::Undef u | u.getChild(_) = generated) - or - exists(Generated::Alias a | a.getName() = generated or a.getAlias() = generated) - } - } - - private class TokenMethodName extends MethodName::Range, TokenTypes { - final override Generated::UnderscoreMethodName generated; - - final override string getValueText() { - result = generated.(Generated::Token).getValue() - or - result = generated.(Generated::Setter).getName().getValue() + "=" - } - } - - private class SimpleSymbolMethodName extends MethodName::Range, SymbolLiteral::SimpleSymbolRange, - @token_simple_symbol { } - - private class DelimitedSymbolMethodName extends MethodName::Range, - SymbolLiteral::DelimitedSymbolRange, @delimited_symbol { } -} diff --git a/ql/src/codeql_ruby/ast/internal/Method.qll b/ql/src/codeql_ruby/ast/internal/Method.qll deleted file mode 100644 index 0b31ca2d22d..00000000000 --- a/ql/src/codeql_ruby/ast/internal/Method.qll +++ /dev/null @@ -1,144 +0,0 @@ -private import codeql_ruby.AST -private import codeql_ruby.ast.internal.AST -private import codeql_ruby.ast.internal.Expr -private import codeql_ruby.ast.internal.Parameter -private import codeql_ruby.ast.internal.Scope -private import TreeSitter - -module Callable { - abstract class Range extends Expr::Range { - abstract Parameter::Range getParameter(int n); - - override predicate child(string label, AstNode::Range child) { - label = "getParameter" and child = getParameter(_) - } - } -} - -module MethodBase { - abstract class Range extends Callable::Range, BodyStatement::Range, Scope::Range { - abstract string getName(); - - override predicate child(string label, AstNode::Range child) { - Callable::Range.super.child(label, child) or BodyStatement::Range.super.child(label, child) - } - - override string toString() { result = BodyStatement::Range.super.toString() } - } -} - -module Method { - class Range extends MethodBase::Range, @method { - final override Generated::Method generated; - - override Parameter::Range getParameter(int n) { result = generated.getParameters().getChild(n) } - - override string getName() { - result = generated.getName().(Generated::Token).getValue() or - result = generated.getName().(Generated::Setter).getName().getValue() + "=" - } - - final predicate isSetter() { generated.getName() instanceof Generated::Setter } - - final override Generated::AstNode getChild(int i) { result = generated.getChild(i) } - - final override string toString() { result = this.getName() } - } -} - -module SingletonMethod { - class Range extends MethodBase::Range, @singleton_method { - final override Generated::SingletonMethod generated; - - override Parameter::Range getParameter(int n) { result = generated.getParameters().getChild(n) } - - override string getName() { - result = generated.getName().(Generated::Token).getValue() or - result = generated.getName().(SymbolLiteral).getValueText() or - result = generated.getName().(Generated::Setter).getName().getValue() + "=" - } - - final Generated::AstNode getObject() { result = generated.getObject() } - - final override Generated::AstNode getChild(int i) { result = generated.getChild(i) } - - final override string toString() { result = this.getName() } - - override predicate child(string label, AstNode::Range child) { - MethodBase::Range.super.child(label, child) - or - label = "getObject" and child = getObject() - } - } -} - -module Lambda { - class Range extends Callable::Range, BodyStatement::Range, @lambda { - final override Generated::Lambda generated; - - final override Parameter::Range getParameter(int n) { - result = generated.getParameters().getChild(n) - } - - final override Generated::AstNode getChild(int i) { - result = generated.getBody().(Generated::DoBlock).getChild(i) or - result = generated.getBody().(Generated::Block).getChild(i) - } - - final override string toString() { result = "-> { ... }" } - - override predicate child(string label, AstNode::Range child) { - Callable::Range.super.child(label, child) - or - BodyStatement::Range.super.child(label, child) - } - } -} - -module Block { - abstract class Range extends Callable::Range, StmtSequence::Range, Scope::Range { - Range() { not generated.getParent() instanceof Generated::Lambda } - - override predicate child(string label, AstNode::Range child) { - Callable::Range.super.child(label, child) - or - StmtSequence::Range.super.child(label, child) - } - - override string toString() { result = StmtSequence::Range.super.toString() } - } -} - -module DoBlock { - class Range extends Block::Range, BodyStatement::Range, @do_block { - final override Generated::DoBlock generated; - - final override Generated::AstNode getChild(int i) { result = generated.getChild(i) } - - final override Parameter::Range getParameter(int n) { - result = generated.getParameters().getChild(n) - } - - final override string toString() { result = "do ... end" } - - override predicate child(string label, AstNode::Range child) { - Block::Range.super.child(label, child) - or - BodyStatement::Range.super.child(label, child) - } - } -} - -module BraceBlock { - class Range extends Block::Range, @block { - final override Generated::Block generated; - - final override Parameter::Range getParameter(int n) { - result = generated.getParameters().getChild(n) - } - - final override Stmt getStmt(int i) { result = generated.getChild(i) } - - final override string toString() { result = "{ ... }" } - } -} diff --git a/ql/src/codeql_ruby/ast/internal/Module.qll b/ql/src/codeql_ruby/ast/internal/Module.qll deleted file mode 100644 index 349e6ced59a..00000000000 --- a/ql/src/codeql_ruby/ast/internal/Module.qll +++ /dev/null @@ -1,132 +0,0 @@ -private import codeql_ruby.AST -private import codeql_ruby.ast.internal.AST -private import codeql_ruby.ast.internal.Constant -private import codeql_ruby.ast.internal.Expr -private import codeql_ruby.ast.internal.Scope -private import codeql_ruby.ast.internal.TreeSitter - -module ModuleBase { - abstract class Range extends BodyStatement::Range, Scope::Range { - override string toString() { result = BodyStatement::Range.super.toString() } - } -} - -module Namespace { - abstract class Range extends ModuleBase::Range, ConstantWriteAccess::Range { - override predicate child(string label, AstNode::Range child) { - ModuleBase::Range.super.child(label, child) or - ConstantWriteAccess::Range.super.child(label, child) - } - - override string toString() { result = ModuleBase::Range.super.toString() } - } -} - -module Toplevel { - class Range extends ModuleBase::Range, @program { - final override Generated::Program generated; - - Range() { generated.getLocation().getFile().getExtension() != "erb" } - - final override Generated::AstNode getChild(int i) { - result = generated.getChild(i) and - not result instanceof Generated::BeginBlock - } - - final StmtSequence getBeginBlock(int n) { - result = rank[n](int i, Generated::BeginBlock b | b = generated.getChild(i) | b order by i) - } - - final override string toString() { result = generated.getLocation().getFile().getBaseName() } - - override predicate child(string label, AstNode::Range child) { - ModuleBase::Range.super.child(label, child) - or - label = "getBeginBlock" and child = getBeginBlock(_) - } - } -} - -module Class { - class Range extends Namespace::Range, @class { - final override Generated::Class generated; - - final override Generated::AstNode getChild(int i) { result = generated.getChild(i) } - - final override string getName() { - result = generated.getName().(Generated::Token).getValue() or - result = - generated.getName().(Generated::ScopeResolution).getName().(Generated::Token).getValue() - } - - final override Expr::Range getScopeExpr() { - result = generated.getName().(Generated::ScopeResolution).getScope() - } - - final override predicate hasGlobalScope() { - exists(Generated::ScopeResolution sr | - sr = generated.getName() and - not exists(sr.getScope()) - ) - } - - final Expr getSuperclassExpr() { result = generated.getSuperclass().getChild() } - - final override string toString() { result = this.getName() } - - override predicate child(string label, AstNode::Range child) { - Namespace::Range.super.child(label, child) - or - label = "getSuperclassExpr" and child = getSuperclassExpr() - } - } -} - -module SingletonClass { - class Range extends ModuleBase::Range, @singleton_class { - final override Generated::SingletonClass generated; - - final override Generated::AstNode getChild(int i) { result = generated.getChild(i) } - - final Expr getValue() { result = generated.getValue() } - - final override string toString() { result = "class << ..." } - - override predicate child(string label, AstNode::Range child) { - ModuleBase::Range.super.child(label, child) - or - label = "getValue" and child = getValue() - } - } -} - -module Module { - class Range extends Namespace::Range, @module { - final override Generated::Module generated; - - final override Generated::AstNode getChild(int i) { result = generated.getChild(i) } - - final override string getName() { - result = generated.getName().(Generated::Token).getValue() or - result = - generated.getName().(Generated::ScopeResolution).getName().(Generated::Token).getValue() - } - - final override Expr::Range getScopeExpr() { - result = generated.getName().(Generated::ScopeResolution).getScope() - } - - final override predicate hasGlobalScope() { - exists(Generated::ScopeResolution sr | - sr = generated.getName() and - not exists(sr.getScope()) - ) - } - - final override string toString() { result = this.getName() } - - override predicate child(string label, AstNode::Range child) { - Namespace::Range.super.child(label, child) - } - } -} diff --git a/ql/src/codeql_ruby/ast/internal/Operation.qll b/ql/src/codeql_ruby/ast/internal/Operation.qll deleted file mode 100644 index ee11ad805ad..00000000000 --- a/ql/src/codeql_ruby/ast/internal/Operation.qll +++ /dev/null @@ -1,355 +0,0 @@ -private import codeql_ruby.AST -private import codeql_ruby.ast.internal.AST -private import codeql_ruby.ast.internal.TreeSitter -private import codeql_ruby.ast.internal.Expr - -module Operation { - abstract class Range extends Expr::Range { - abstract string getOperator(); - - abstract Stmt getAnOperand(); - - override predicate child(string label, AstNode::Range child) { - label = "getAnOperand" and child = getAnOperand() - } - } -} - -module UnaryOperation { - abstract class Range extends Operation::Range, @unary { - final override Generated::Unary generated; - - final override string getOperator() { result = generated.getOperator() } - - Expr getOperand() { result = generated.getOperand() } - - final override Expr getAnOperand() { result = this.getOperand() } - - override string toString() { result = this.getOperator() + " ..." } - - override predicate child(string label, AstNode::Range child) { - Operation::Range.super.child(label, child) - or - label = "getOperand" and child = getOperand() - } - } -} - -module UnaryLogicalOperation { - abstract class Range extends UnaryOperation::Range { } -} - -module UnaryArithmeticOperation { - abstract class Range extends UnaryOperation::Range { } -} - -module UnaryBitwiseOperation { - abstract class Range extends UnaryOperation::Range { } -} - -module NotExpr { - class DbUnion = @unary_bang or @unary_not; - - class Range extends UnaryLogicalOperation::Range, DbUnion { } -} - -module UnaryPlusExpr { - class Range extends UnaryArithmeticOperation::Range, @unary_plus { } -} - -module UnaryMinusExpr { - class Range extends UnaryArithmeticOperation::Range, @unary_minus { } -} - -module ComplementExpr { - class Range extends UnaryBitwiseOperation::Range, @unary_tilde { } -} - -module DefinedExpr { - class Range extends UnaryOperation::Range, @unary_definedquestion { } -} - -module BinaryOperation { - abstract class Range extends Operation::Range, @binary { - final override Generated::Binary generated; - - final override string getOperator() { result = generated.getOperator() } - - final Expr getLeftOperand() { result = generated.getLeft() } - - final Stmt getRightOperand() { result = generated.getRight() } - - final override Stmt getAnOperand() { - result = this.getLeftOperand() or result = this.getRightOperand() - } - - override string toString() { result = "... " + this.getOperator() + " ..." } - - override predicate child(string label, AstNode::Range child) { - Operation::Range.super.child(label, child) - or - label = "getLeftOperand" and child = getLeftOperand() - or - label = "getRightOperand" and child = getRightOperand() - } - } -} - -module BinaryArithmeticOperation { - abstract class Range extends BinaryOperation::Range { } -} - -module BinaryLogicalOperation { - abstract class Range extends BinaryOperation::Range { } -} - -module BinaryBitwiseOperation { - abstract class Range extends BinaryOperation::Range { } -} - -module ComparisonOperation { - abstract class Range extends BinaryOperation::Range, @binary { } -} - -module AddExpr { - class Range extends BinaryArithmeticOperation::Range, @binary_plus { } -} - -module SubExpr { - class Range extends BinaryArithmeticOperation::Range, @binary_minus { } -} - -module MulExpr { - class Range extends BinaryArithmeticOperation::Range, @binary_star { } -} - -module DivExpr { - class Range extends BinaryArithmeticOperation::Range, @binary_slash { } -} - -module ModuloExpr { - class Range extends BinaryArithmeticOperation::Range, @binary_percent { } -} - -module ExponentExpr { - class Range extends BinaryArithmeticOperation::Range, @binary_starstar { } -} - -module LogicalAndExpr { - class DbUnion = @binary_and or @binary_ampersandampersand; - - class Range extends BinaryLogicalOperation::Range, DbUnion { } -} - -module LogicalOrExpr { - class DbUnion = @binary_or or @binary_pipepipe; - - class Range extends BinaryLogicalOperation::Range, DbUnion { } -} - -module LShiftExpr { - class Range extends BinaryBitwiseOperation::Range, @binary_langlelangle { } -} - -module RShiftExpr { - class Range extends BinaryBitwiseOperation::Range, @binary_ranglerangle { } -} - -module BitwiseAndExpr { - class Range extends BinaryBitwiseOperation::Range, @binary_ampersand { } -} - -module BitwiseOrExpr { - class Range extends BinaryBitwiseOperation::Range, @binary_pipe { } -} - -module BitwiseXorExpr { - class Range extends BinaryBitwiseOperation::Range, @binary_caret { } -} - -module EqualityOperation { - abstract class Range extends ComparisonOperation::Range { } -} - -module EqExpr { - class Range extends EqualityOperation::Range, @binary_equalequal { } -} - -module NEExpr { - class Range extends EqualityOperation::Range, @binary_bangequal { } -} - -module CaseEqExpr { - class Range extends EqualityOperation::Range, @binary_equalequalequal { } -} - -module RelationalOperation { - abstract class Range extends ComparisonOperation::Range { - abstract Expr getGreaterOperand(); - - abstract Expr getLesserOperand(); - - override predicate child(string label, AstNode::Range child) { - ComparisonOperation::Range.super.child(label, child) - or - label = "getGreaterOperand" and child = getGreaterOperand() - or - label = "getLesserOperand" and child = getLesserOperand() - } - } -} - -module GTExpr { - class Range extends RelationalOperation::Range, @binary_rangle { - final override Expr getGreaterOperand() { result = this.getLeftOperand() } - - final override Expr getLesserOperand() { result = this.getRightOperand() } - } -} - -module GEExpr { - class Range extends RelationalOperation::Range, @binary_rangleequal { - final override Expr getGreaterOperand() { result = this.getLeftOperand() } - - final override Expr getLesserOperand() { result = this.getRightOperand() } - } -} - -module LTExpr { - class Range extends RelationalOperation::Range, @binary_langle { - final override Expr getGreaterOperand() { result = this.getRightOperand() } - - final override Expr getLesserOperand() { result = this.getLeftOperand() } - } -} - -module LEExpr { - class Range extends RelationalOperation::Range, @binary_langleequal { - final override Expr getGreaterOperand() { result = this.getRightOperand() } - - final override Expr getLesserOperand() { result = this.getLeftOperand() } - } -} - -module SpaceshipExpr { - class Range extends BinaryOperation::Range, @binary_langleequalrangle { } -} - -module RegexMatchExpr { - class Range extends BinaryOperation::Range, @binary_equaltilde { } -} - -module NoRegexMatchExpr { - class Range extends BinaryOperation::Range, @binary_bangtilde { } -} - -module Assignment { - abstract class Range extends Operation::Range { - abstract Pattern getLeftOperand(); - - abstract Expr getRightOperand(); - - final override Expr getAnOperand() { - result = this.getLeftOperand() or result = this.getRightOperand() - } - - override string toString() { result = "... " + this.getOperator() + " ..." } - - override predicate child(string label, AstNode::Range child) { - Operation::Range.super.child(label, child) - or - label = "getLeftOperand" and child = getLeftOperand() - or - label = "getRightOperand" and child = getRightOperand() - } - } -} - -module AssignExpr { - class Range extends Assignment::Range, @assignment { - final override Generated::Assignment generated; - - final override Pattern getLeftOperand() { result = generated.getLeft() } - - final override Expr getRightOperand() { result = generated.getRight() } - - final override string getOperator() { result = "=" } - } -} - -module AssignOperation { - abstract class Range extends Assignment::Range, @operator_assignment { - final override Generated::OperatorAssignment generated; - - final override string getOperator() { result = generated.getOperator() } - - final override LhsExpr getLeftOperand() { result = generated.getLeft() } - - final override Expr getRightOperand() { result = generated.getRight() } - } -} - -module AssignArithmeticOperation { - abstract class Range extends AssignOperation::Range { } -} - -module AssignLogicalOperation { - abstract class Range extends AssignOperation::Range { } -} - -module AssignBitwiseOperation { - abstract class Range extends AssignOperation::Range { } -} - -module AssignAddExpr { - class Range extends AssignArithmeticOperation::Range, @operator_assignment_plusequal { } -} - -module AssignSubExpr { - class Range extends AssignArithmeticOperation::Range, @operator_assignment_minusequal { } -} - -module AssignMulExpr { - class Range extends AssignArithmeticOperation::Range, @operator_assignment_starequal { } -} - -module AssignDivExpr { - class Range extends AssignArithmeticOperation::Range, @operator_assignment_slashequal { } -} - -module AssignExponentExpr { - class Range extends AssignArithmeticOperation::Range, @operator_assignment_starstarequal { } -} - -module AssignModuloExpr { - class Range extends AssignArithmeticOperation::Range, @operator_assignment_percentequal { } -} - -module AssignLogicalAndExpr { - class Range extends AssignLogicalOperation::Range, @operator_assignment_ampersandampersandequal { - } -} - -module AssignLogicalOrExpr { - class Range extends AssignLogicalOperation::Range, @operator_assignment_pipepipeequal { } -} - -module AssignLShiftExpr { - class Range extends AssignBitwiseOperation::Range, @operator_assignment_langlelangleequal { } -} - -module AssignRShiftExpr { - class Range extends AssignBitwiseOperation::Range, @operator_assignment_ranglerangleequal { } -} - -module AssignBitwiseAndExpr { - class Range extends AssignBitwiseOperation::Range, @operator_assignment_ampersandequal { } -} - -module AssignBitwiseOrExpr { - class Range extends AssignBitwiseOperation::Range, @operator_assignment_pipeequal { } -} - -module AssignBitwiseXorExpr { - class Range extends AssignBitwiseOperation::Range, @operator_assignment_caretequal { } -} diff --git a/ql/src/codeql_ruby/ast/internal/Parameter.qll b/ql/src/codeql_ruby/ast/internal/Parameter.qll index 6595f38be33..69f8068635e 100644 --- a/ql/src/codeql_ruby/ast/internal/Parameter.qll +++ b/ql/src/codeql_ruby/ast/internal/Parameter.qll @@ -1,14 +1,9 @@ private import codeql_ruby.AST +private import AST private import TreeSitter -private import codeql_ruby.ast.internal.AST -private import codeql_ruby.ast.internal.Expr -private import codeql_ruby.ast.internal.Variable -private import codeql_ruby.ast.internal.Method -private import codeql_ruby.ast.internal.Pattern -private import codeql.Locations module Parameter { - class Range extends AstNode::Range { + class Range extends Generated::AstNode { private int pos; Range() { @@ -19,143 +14,6 @@ module Parameter { this = any(Generated::LambdaParameters lp).getChild(pos) } - final int getPosition() { result = pos } - - LocalVariable getAVariable() { none() } - - override string toString() { none() } - } -} - -module NamedParameter { - abstract class Range extends Parameter::Range { - abstract string getName(); - - abstract LocalVariable getVariable(); - - override LocalVariable getAVariable() { result = this.getVariable() } - } -} - -module SimpleParameter { - class Range extends NamedParameter::Range, PatternParameter::Range, VariablePattern::Range { - final override string getName() { result = this.getVariableName() } - - final override LocalVariable getVariable() { result = TLocalVariable(_, _, this) } - - final override LocalVariable getAVariable() { result = this.getVariable() } - - final override string toString() { result = this.getName() } - } -} - -module PatternParameter { - class Range extends Parameter::Range, Pattern::Range { - override LocalVariable getAVariable() { result = this.(Pattern::Range).getAVariable() } - - override string toString() { none() } - } -} - -module TuplePatternParameter { - class Range extends PatternParameter::Range, TuplePattern::Range { - override LocalVariable getAVariable() { result = TuplePattern::Range.super.getAVariable() } - - override string toString() { result = TuplePattern::Range.super.toString() } - - override predicate child(string label, AstNode::Range child) { - PatternParameter::Range.super.child(label, child) or - TuplePattern::Range.super.child(label, child) - } - } -} - -module BlockParameter { - class Range extends NamedParameter::Range, @block_parameter { - final override Generated::BlockParameter generated; - - final override string getName() { result = generated.getName().getValue() } - - final override LocalVariable getVariable() { - result = TLocalVariable(_, _, generated.getName()) - } - - final override string toString() { result = "&" + this.getName() } - } -} - -module HashSplatParameter { - class Range extends NamedParameter::Range, @hash_splat_parameter { - final override Generated::HashSplatParameter generated; - - final override LocalVariable getVariable() { - result = TLocalVariable(_, _, generated.getName()) - } - - final override string toString() { result = "**" + this.getName() } - - final override string getName() { result = generated.getName().getValue() } - } -} - -module KeywordParameter { - class Range extends NamedParameter::Range, @keyword_parameter { - final override Generated::KeywordParameter generated; - - final override LocalVariable getVariable() { - result = TLocalVariable(_, _, generated.getName()) - } - - final Expr::Range getDefaultValue() { result = generated.getValue() } - - final override string toString() { result = this.getName() } - - final override string getName() { result = generated.getName().getValue() } - - final override Location getLocation() { result = generated.getName().getLocation() } - - final override predicate child(string label, AstNode::Range child) { - NamedParameter::Range.super.child(label, child) - or - label = "getDefaultValue" and child = getDefaultValue() - } - } -} - -module OptionalParameter { - class Range extends NamedParameter::Range, @optional_parameter { - final override Generated::OptionalParameter generated; - - final override LocalVariable getVariable() { - result = TLocalVariable(_, _, generated.getName()) - } - - final Expr::Range getDefaultValue() { result = generated.getValue() } - - final override string toString() { result = this.getName() } - - final override string getName() { result = generated.getName().getValue() } - - final override Location getLocation() { result = generated.getName().getLocation() } - - final override predicate child(string label, AstNode::Range child) { - NamedParameter::Range.super.child(label, child) - or - label = "getDefaultValue" and child = getDefaultValue() - } - } -} - -module SplatParameter { - class Range extends NamedParameter::Range, @splat_parameter { - final override Generated::SplatParameter generated; - - final override LocalVariable getVariable() { - result = TLocalVariable(_, _, generated.getName()) - } - - final override string toString() { result = "*" + this.getName() } - - final override string getName() { result = generated.getName().getValue() } + int getPosition() { result = pos } } } diff --git a/ql/src/codeql_ruby/ast/internal/Pattern.qll b/ql/src/codeql_ruby/ast/internal/Pattern.qll deleted file mode 100644 index 275e483107a..00000000000 --- a/ql/src/codeql_ruby/ast/internal/Pattern.qll +++ /dev/null @@ -1,112 +0,0 @@ -private import codeql_ruby.AST -private import TreeSitter -private import codeql_ruby.ast.internal.AST -private import codeql_ruby.ast.internal.Expr -private import codeql_ruby.ast.internal.Variable -private import codeql_ruby.ast.internal.Method -private import codeql.Locations - -/** - * Holds if `n` is in the left-hand-side of an explicit assignment `assignment`. - */ -predicate explicitAssignmentNode(Generated::AstNode n, Generated::AstNode assignment) { - n = assignment.(Generated::Assignment).getLeft() - or - n = assignment.(Generated::OperatorAssignment).getLeft() - or - exists(Generated::AstNode parent | - parent = n.getParent() and - explicitAssignmentNode(parent, assignment) - | - parent instanceof Generated::DestructuredLeftAssignment - or - parent instanceof Generated::LeftAssignmentList - or - parent instanceof Generated::RestAssignment - ) -} - -/** Holds if `n` is inside an implicit assignment. */ -predicate implicitAssignmentNode(Generated::AstNode n) { - n = any(Generated::ExceptionVariable ev).getChild() - or - n = any(Generated::For for).getPattern() - or - implicitAssignmentNode(n.getParent()) -} - -/** Holds if `n` is inside a parameter. */ -predicate implicitParameterAssignmentNode(Generated::AstNode n, Callable::Range c) { - n = c.getParameter(_) - or - implicitParameterAssignmentNode(n.getParent().(Generated::DestructuredParameter), c) -} - -module Pattern { - abstract class Range extends AstNode::Range { - cached - Range() { - explicitAssignmentNode(this, _) - or - implicitAssignmentNode(this) - or - implicitParameterAssignmentNode(this, _) - } - - Variable getAVariable() { none() } - - override string toString() { none() } - } -} - -module LhsExpr { - abstract class Range extends Pattern::Range, Expr::Range { } -} - -module VariablePattern { - class VariableToken = - @token_identifier or @token_instance_variable or @token_class_variable or @token_global_variable; - - class Range extends LhsExpr::Range, VariableToken { - override Generated::Token generated; - - string getVariableName() { result = generated.getValue() } - - override Variable getAVariable() { access(this, result) } - - override string toString() { result = this.getVariableName() } - } -} - -module TuplePattern { - private class Range_ = - @destructured_parameter or @destructured_left_assignment or @left_assignment_list; - - class Range extends Pattern::Range, Range_ { - Pattern::Range getElement(int i) { - exists(Generated::AstNode c | c = getChild(i) | - result = c.(Generated::RestAssignment).getChild() - or - not c instanceof Generated::RestAssignment and result = c - ) - } - - private Generated::AstNode getChild(int i) { - result = this.(Generated::DestructuredParameter).getChild(i) - or - result = this.(Generated::DestructuredLeftAssignment).getChild(i) - or - result = this.(Generated::LeftAssignmentList).getChild(i) - } - - int getRestIndex() { result = unique(int i | getChild(i) instanceof Generated::RestAssignment) } - - override Variable getAVariable() { result = this.getElement(_).getAVariable() } - - override string toString() { result = "(..., ...)" } - - override predicate child(string label, AstNode::Range child) { - label = "getElement" and child = getElement(_) - } - } -} diff --git a/ql/src/codeql_ruby/ast/internal/Scope.qll b/ql/src/codeql_ruby/ast/internal/Scope.qll index ab057c2d921..7c76ef8affa 100644 --- a/ql/src/codeql_ruby/ast/internal/Scope.qll +++ b/ql/src/codeql_ruby/ast/internal/Scope.qll @@ -1,22 +1,19 @@ private import TreeSitter +private import codeql_ruby.ast.Scope private import codeql_ruby.ast.internal.AST -private import codeql_ruby.ast.internal.Module -private import codeql_ruby.ast.internal.Method -private import codeql_ruby.ast.internal.Statement +private import codeql_ruby.ast.internal.Parameter + +class TScopeType = TMethodBase or TModuleLike or TBlockLike; + +private class TBlockLike = TDoBlock or TLambda or TBlock or TEndBlock; + +private class TModuleLike = TToplevel or TModule or TClass or TSingletonClass; module Scope { - class ScopeType = MethodLike or ModuleLike or BlockLike; + class TypeRange = Callable::TypeRange or ModuleBase::TypeRange or @end_block; - class BlockLike = @do_block or @lambda or @block or @end_block; - - class ModuleLike = @program or @module or @class or @singleton_class; - - class MethodLike = @method or @singleton_method; - - class Range extends AstNode::Range, ScopeType { - Range() { not exists(Generated::Lambda l | l.getBody() = this) } - - Generated::AstNode getADescendant() { this = scopeOf(result) } + class Range extends Generated::AstNode, TypeRange { + Range() { not this = any(Generated::Lambda l).getBody() } ModuleBase::Range getEnclosingModule() { result = this @@ -32,19 +29,34 @@ module Scope { result = this.getOuterScope().getEnclosingMethod() } - Scope::Range getOuterScope() { result = scopeOf(this) } - - override string toString() { none() } + Range getOuterScope() { result = scopeOf(this) } } } -/** Gets the enclosing scope of a node */ -private Scope::Range scopeOf(Generated::AstNode n) { - exists(Generated::AstNode p | p = parentOf(n) | - p instanceof Scope::Range and result = p - or - not p instanceof Scope::Range and result = scopeOf(p) - ) +module MethodBase { + class TypeRange = @method or @singleton_method; + + class Range extends Scope::Range, TypeRange { } +} + +module Callable { + class TypeRange = MethodBase::TypeRange or @do_block or @lambda or @block; + + class Range extends Scope::Range, TypeRange { + Parameter::Range getParameter(int i) { + result = this.(Generated::Method).getParameters().getChild(i) or + result = this.(Generated::SingletonMethod).getParameters().getChild(i) or + result = this.(Generated::DoBlock).getParameters().getChild(i) or + result = this.(Generated::Lambda).getParameters().getChild(i) or + result = this.(Generated::Block).getParameters().getChild(i) + } + } +} + +module ModuleBase { + class TypeRange = @program or @module or @class or @singleton_class; + + class Range extends Scope::Range, TypeRange { } } private Generated::AstNode parentOf(Generated::AstNode n) { @@ -61,3 +73,13 @@ private Generated::AstNode parentOf(Generated::AstNode n) { else result = parent ) } + +/** Gets the enclosing scope of a node */ +cached +Scope::Range scopeOf(Generated::AstNode n) { + exists(Generated::AstNode p | p = parentOf(n) | + p = result + or + not p instanceof Scope::Range and result = scopeOf(p) + ) +} diff --git a/ql/src/codeql_ruby/ast/internal/Statement.qll b/ql/src/codeql_ruby/ast/internal/Statement.qll deleted file mode 100644 index 08d5d2a19bc..00000000000 --- a/ql/src/codeql_ruby/ast/internal/Statement.qll +++ /dev/null @@ -1,146 +0,0 @@ -private import codeql_ruby.AST -private import codeql_ruby.ast.internal.AST -private import codeql_ruby.ast.internal.Expr -private import codeql_ruby.ast.internal.TreeSitter - -module Stmt { - abstract class Range extends AstNode::Range { } -} - -module EmptyStmt { - class Range extends Stmt::Range, @token_empty_statement { - final override Generated::EmptyStatement generated; - - final override string toString() { result = ";" } - - override predicate child(string label, AstNode::Range child) { none() } - } -} - -module Begin { - class Range extends BodyStatement::Range, @begin { - final override Generated::Begin generated; - - final override Generated::AstNode getChild(int n) { result = generated.getChild(n) } - - final override string toString() { result = "begin ... " } - } -} - -module BeginBlock { - class Range extends StmtSequence::Range, @begin_block { - final override Generated::BeginBlock generated; - - final override Stmt getStmt(int n) { result = generated.getChild(n) } - - final override string toString() { result = "BEGIN { ... }" } - } -} - -module EndBlock { - class Range extends StmtSequence::Range, @end_block { - final override Generated::EndBlock generated; - - final override Stmt getStmt(int n) { result = generated.getChild(n) } - - final override string toString() { result = "END { ... }" } - } -} - -module UndefStmt { - class Range extends Stmt::Range, @undef { - final override Generated::Undef generated; - - final MethodName getMethodName(int n) { result = generated.getChild(n) } - - final override string toString() { result = "undef ..." } - - override predicate child(string label, AstNode::Range child) { - label = "getMethodName" and child = getMethodName(_) - } - } -} - -module AliasStmt { - class Range extends Stmt::Range, @alias { - final override Generated::Alias generated; - - final MethodName getNewName() { result = generated.getName() } - - final MethodName getOldName() { result = generated.getAlias() } - - final override string toString() { result = "alias ..." } - - override predicate child(string label, AstNode::Range child) { - label = "getNewName" and child = getNewName() - or - label = "getOldName" and child = getOldName() - } - } -} - -module ReturningStmt { - abstract class Range extends Stmt::Range { - abstract Generated::ArgumentList getArgumentList(); - - final Expr getValue() { - exists(Generated::ArgumentList a, int c | - a = this.getArgumentList() and c = count(a.getChild(_)) - | - result = a.getChild(0) and c = 1 - or - result = a and c > 1 - ) - } - - override predicate child(string label, AstNode::Range child) { - label = "getValue" and child = getValue() - } - } -} - -module ReturnStmt { - class Range extends ReturningStmt::Range, @return { - final override Generated::Return generated; - - final override string toString() { result = "return" } - - final override Generated::ArgumentList getArgumentList() { result = generated.getChild() } - } -} - -module BreakStmt { - class Range extends ReturningStmt::Range, @break { - final override Generated::Break generated; - - final override string toString() { result = "break" } - - final override Generated::ArgumentList getArgumentList() { result = generated.getChild() } - } -} - -module NextStmt { - class Range extends ReturningStmt::Range, @next { - final override Generated::Next generated; - - final override string toString() { result = "next" } - - final override Generated::ArgumentList getArgumentList() { result = generated.getChild() } - } -} - -module RedoStmt { - class Range extends Stmt::Range, @redo { - final override Generated::Redo generated; - - final override string toString() { result = "redo" } - } -} - -module RetryStmt { - class Range extends Stmt::Range, @retry { - final override Generated::Retry generated; - - final override string toString() { result = "retry" } - } -} diff --git a/ql/src/codeql_ruby/ast/internal/Variable.qll b/ql/src/codeql_ruby/ast/internal/Variable.qll index d65c7f0304b..fcd1e428862 100644 --- a/ql/src/codeql_ruby/ast/internal/Variable.qll +++ b/ql/src/codeql_ruby/ast/internal/Variable.qll @@ -2,13 +2,45 @@ private import TreeSitter private import codeql.Locations private import codeql_ruby.AST private import codeql_ruby.ast.internal.AST -private import codeql_ruby.ast.internal.Expr -private import codeql_ruby.ast.internal.Method -private import codeql_ruby.ast.internal.Module -private import codeql_ruby.ast.internal.Pattern private import codeql_ruby.ast.internal.Parameter private import codeql_ruby.ast.internal.Scope +/** + * Holds if `n` is in the left-hand-side of an explicit assignment `assignment`. + */ +predicate explicitAssignmentNode(Generated::AstNode n, Generated::AstNode assignment) { + n = assignment.(Generated::Assignment).getLeft() + or + n = assignment.(Generated::OperatorAssignment).getLeft() + or + exists(Generated::AstNode parent | + parent = n.getParent() and + explicitAssignmentNode(parent, assignment) + | + parent instanceof Generated::DestructuredLeftAssignment + or + parent instanceof Generated::LeftAssignmentList + or + parent instanceof Generated::RestAssignment + ) +} + +/** Holds if `n` is inside an implicit assignment. */ +predicate implicitAssignmentNode(Generated::AstNode n) { + n = any(Generated::ExceptionVariable ev).getChild() + or + n = any(Generated::For for).getPattern() + or + implicitAssignmentNode(n.getParent()) +} + +/** Holds if `n` is inside a parameter. */ +predicate implicitParameterAssignmentNode(Generated::AstNode n, Callable::Range c) { + n = c.getParameter(_) + or + implicitParameterAssignmentNode(n.getParent().(Generated::DestructuredParameter), c) +} + private predicate instanceVariableAccess( Generated::InstanceVariable var, string name, Scope::Range scope, boolean instance ) { @@ -23,11 +55,11 @@ private predicate classVariableAccess(Generated::ClassVariable var, string name, } private predicate hasEnclosingMethod(Generated::AstNode node) { - exists(Scope::Range s | node = s.getADescendant() and exists(s.getEnclosingMethod())) + exists(Scope::Range s | scopeOf(node) = s and exists(s.getEnclosingMethod())) } private ModuleBase::Range enclosingModuleOrClass(Generated::AstNode node) { - exists(Scope::Range s | node = s.getADescendant() and result = s.getEnclosingModule()) + exists(Scope::Range s | scopeOf(node) = s and result = s.getEnclosingModule()) } private predicate parameterAssignment(Callable::Range scope, string name, Generated::Identifier i) { @@ -49,8 +81,8 @@ private predicate scopeDefinesParameterVariable( ) or exists(Parameter::Range p | - p = scope.(Callable::Range).getParameter(_) and - name = p.(NamedParameter::Range).getName() + p = scope.getParameter(_) and + name = i.getValue() | i = p.(Generated::BlockParameter).getName() or i = p.(Generated::HashSplatParameter).getName() or @@ -64,7 +96,7 @@ private predicate scopeDefinesParameterVariable( private predicate scopeAssigns(Scope::Range scope, string name, Generated::Identifier i) { (explicitAssignmentNode(i, _) or implicitAssignmentNode(i)) and name = i.getValue() and - scope = enclosingScope(i) + scope = scopeOf(i) } /** Holds if location `one` starts strictly before location `two` */ @@ -75,39 +107,8 @@ private predicate strictlyBefore(Location one, Location two) { one.getStartLine() = two.getStartLine() and one.getStartColumn() < two.getStartColumn() } -private Generated::AstNode getNodeForIdentifier(Generated::Identifier id) { - exists(Generated::AstNode parent | parent = id.getParent() | - if - parent instanceof Generated::BlockParameter - or - parent instanceof Generated::SplatParameter - or - parent instanceof Generated::HashSplatParameter - or - parent instanceof Generated::KeywordParameter - or - parent instanceof Generated::OptionalParameter - then result = parent - else result = id - ) -} - cached private module Cached { - /** Gets the enclosing scope for `node`. */ - cached - Scope::Range enclosingScope(Generated::AstNode node) { result.getADescendant() = node } - - cached - newtype TScope = - TGlobalScope() or - TTopLevelScope(Generated::Program node) or - TModuleScope(Generated::Module node) or - TClassScope(Generated::AstNode cls) { - cls instanceof Generated::Class or cls instanceof Generated::SingletonClass - } or - TCallableScope(Callable::Range c) - cached newtype TVariable = TGlobalVariable(string name) { name = any(Generated::GlobalVariable var).getValue() } or @@ -292,7 +293,7 @@ private module Cached { variable.getName() = name and name = access.getValue() | - variable.getDeclaringScope() = enclosingScope(access) and + variable.getDeclaringScope() = scopeOf(access) and not strictlyBefore(access.getLocation(), variable.getLocation()) and // In case of overlapping parameter names, later parameters should not // be considered accesses to the first parameter @@ -302,7 +303,7 @@ private module Cached { or exists(Scope::Range declScope | variable.getDeclaringScope() = declScope and - inherits(enclosingScope(access), name, declScope) + inherits(scopeOf(access), name, declScope) ) ) } @@ -329,8 +330,8 @@ private module Cached { } cached - predicate isCapturedAccess(LocalVariableAccess::Range access) { - access.getVariable().getDeclaringScope() != enclosingScope(access) + predicate isCapturedAccess(LocalVariableAccess access) { + toGenerated(access.getVariable().getDeclaringScope()) != scopeOf(toGenerated(access)) } cached @@ -353,7 +354,8 @@ private module Cached { import Cached /** Holds if this scope inherits `name` from an outer scope `outer`. */ -private predicate inherits(Block::Range scope, string name, Scope::Range outer) { +private predicate inherits(Scope::Range scope, string name, Scope::Range outer) { + (scope instanceof Generated::Block or scope instanceof Generated::DoBlock) and not scopeDefinesParameterVariable(scope, name, _) and ( outer = scope.getOuterScope() and @@ -362,7 +364,7 @@ private predicate inherits(Block::Range scope, string name, Scope::Range outer) or exists(Generated::Identifier i | scopeAssigns(outer, name, i) and - strictlyBefore(i.getLocation(), scope.(Generated::AstNode).getLocation()) + strictlyBefore(i.getLocation(), scope.getLocation()) ) ) or @@ -396,7 +398,7 @@ module LocalVariable { final override Scope::Range getDeclaringScope() { result = scope } - final VariableAccess getDefiningAccess() { result = getNodeForIdentifier(i) } + final VariableAccess getDefiningAccess() { toGenerated(result) = i } } } @@ -414,8 +416,6 @@ module GlobalVariable { } } -private class ModuleOrClassScope = TClassScope or TModuleScope or TTopLevelScope; - module InstanceVariable { class Range extends Variable::Range, TInstanceVariable { private ModuleBase::Range scope; @@ -451,86 +451,29 @@ module ClassVariable { } } -module VariableAccess { - abstract class Range extends Expr::Range { - abstract Variable getVariable(); - - final predicate isExplicitWrite(AstNode assignment) { - exists(Generated::Identifier i | this = getNodeForIdentifier(i) | - explicitWriteAccess(i, assignment) - ) - or - not this = getNodeForIdentifier(_) and explicitWriteAccess(this, assignment) - } - - final predicate isImplicitWrite() { - exists(Generated::Identifier i | this = getNodeForIdentifier(i) | implicitWriteAccess(i)) - or - not this = getNodeForIdentifier(_) and implicitWriteAccess(this) - } - } -} - module LocalVariableAccess { - class LocalVariableRange = - @token_identifier or @splat_parameter or @keyword_parameter or @optional_parameter or - @hash_splat_parameter or @block_parameter; - - class Range extends VariableAccess::Range, LocalVariableRange { - LocalVariable variable; - - Range() { - exists(Generated::Identifier id | - this = getNodeForIdentifier(id) and - access(id, variable) and - ( - explicitWriteAccess(id, _) - or - implicitWriteAccess(id) - or - vcall(id) - ) - ) - } - - override string toString() { result = generated.(Generated::Identifier).getValue() } - - final override LocalVariable getVariable() { result = variable } + predicate range(Generated::Identifier id, LocalVariable v) { + access(id, v) and + ( + explicitWriteAccess(id, _) + or + implicitWriteAccess(id) + or + vcall(id) + ) } } module GlobalVariableAccess { - class Range extends VariableAccess::Range, @token_global_variable { - GlobalVariable variable; - - Range() { this.(Generated::GlobalVariable).getValue() = variable.getName() } - - final override GlobalVariable getVariable() { result = variable } - - override string toString() { result = generated.(Generated::GlobalVariable).getValue() } - } + predicate range(Generated::GlobalVariable n, GlobalVariable v) { n.getValue() = v.getName() } } module InstanceVariableAccess { - class Range extends VariableAccess::Range, @token_instance_variable { - InstanceVariable variable; - - Range() { instanceVariableAccess(this, variable) } - - final override InstanceVariable getVariable() { result = variable } - - override string toString() { result = generated.(Generated::InstanceVariable).getValue() } + predicate range(Generated::InstanceVariable n, InstanceVariable v) { + instanceVariableAccess(n, v) } } module ClassVariableAccess { - class Range extends VariableAccess::Range, @token_class_variable { - ClassVariable variable; - - Range() { classVariableAccess(this, variable) } - - final override ClassVariable getVariable() { result = variable } - - override string toString() { result = generated.(Generated::ClassVariable).getValue() } - } + predicate range(Generated::ClassVariable n, ClassVariable v) { classVariableAccess(n, v) } } diff --git a/ql/src/codeql_ruby/controlflow/BasicBlocks.qll b/ql/src/codeql_ruby/controlflow/BasicBlocks.qll index 08001011625..2926d00fe18 100644 --- a/ql/src/codeql_ruby/controlflow/BasicBlocks.qll +++ b/ql/src/codeql_ruby/controlflow/BasicBlocks.qll @@ -2,6 +2,8 @@ private import codeql.Locations private import codeql_ruby.AST +private import codeql_ruby.ast.internal.AST +private import codeql_ruby.ast.internal.TreeSitter private import codeql_ruby.controlflow.ControlFlowGraph private import internal.ControlFlowGraphImpl private import CfgNodes @@ -351,14 +353,14 @@ class ExitBasicBlock extends BasicBlock { } private module JoinBlockPredecessors { - private predicate id(AstNode x, AstNode y) { x = y } + private predicate id(Generated::AstNode x, Generated::AstNode y) { x = y } - private predicate idOf(AstNode x, int y) = equivalenceRelation(id/2)(x, y) + private predicate idOf(Generated::AstNode x, int y) = equivalenceRelation(id/2)(x, y) int getId(JoinBlockPredecessor jbp) { - idOf(jbp.getFirstNode().(AstCfgNode).getNode(), result) + idOf(toGenerated(jbp.getFirstNode().(AstCfgNode).getNode()), result) or - idOf(jbp.(EntryBasicBlock).getScope(), result) + idOf(toGenerated(jbp.(EntryBasicBlock).getScope()), result) } string getSplitString(JoinBlockPredecessor jbp) { diff --git a/ql/src/codeql_ruby/controlflow/CfgNodes.qll b/ql/src/codeql_ruby/controlflow/CfgNodes.qll index 1004e092d6a..e2a4badff91 100644 --- a/ql/src/codeql_ruby/controlflow/CfgNodes.qll +++ b/ql/src/codeql_ruby/controlflow/CfgNodes.qll @@ -1,6 +1,7 @@ /** Provides classes representing nodes in a control flow graph. */ private import codeql_ruby.AST +private import codeql_ruby.ast.internal.AST private import codeql_ruby.controlflow.BasicBlocks private import ControlFlowGraph private import internal.ControlFlowGraphImpl @@ -62,11 +63,11 @@ class ExitNode extends CfgNode, TExitNode { * (dead) code or not important for control flow, and multiple when there are different * splits for the AST node. */ -class AstCfgNode extends CfgNode, TAstNode { +class AstCfgNode extends CfgNode, TAstCfgNode { private Splits splits; private AstNode n; - AstCfgNode() { this = TAstNode(n, splits) } + AstCfgNode() { this = TAstCfgNode(toGenerated(n), splits) } final override AstNode getNode() { result = n } @@ -131,7 +132,7 @@ abstract private class ExprChildMapping extends Expr { pragma[noinline] private BasicBlock getABasicBlockInScope() { - result.getANode() = TAstNode(this.getAChildStar(), _) + result.getANode() = TAstCfgNode(toGenerated(this.getAChildStar()), _) } pragma[nomagic] diff --git a/ql/src/codeql_ruby/controlflow/ControlFlowGraph.qll b/ql/src/codeql_ruby/controlflow/ControlFlowGraph.qll index 5465e03e247..d1aca73b49f 100644 --- a/ql/src/codeql_ruby/controlflow/ControlFlowGraph.qll +++ b/ql/src/codeql_ruby/controlflow/ControlFlowGraph.qll @@ -2,6 +2,7 @@ private import codeql.Locations private import codeql_ruby.AST as AST +private import codeql_ruby.ast.internal.AST as ASTInternal private import codeql_ruby.controlflow.BasicBlocks private import SuccessorTypes private import internal.ControlFlowGraphImpl @@ -10,13 +11,13 @@ private import internal.Completion /** An AST node with an associated control-flow graph. */ class CfgScope extends AST::AstNode { - CfgScope() { this instanceof CfgScope::Range_ } + CfgScope() { ASTInternal::toGenerated(this) instanceof CfgScope::Range_ } /** Gets the CFG scope that this scope is nested under, if any. */ final CfgScope getOuterCfgScope() { exists(AST::AstNode parent | parent = this.getParent() and - result = getCfgScope(parent) + result = getCfgScope(ASTInternal::toGenerated(parent)) ) } } diff --git a/ql/src/codeql_ruby/controlflow/internal/Completion.qll b/ql/src/codeql_ruby/controlflow/internal/Completion.qll index c1148d430e3..ed17cb5f125 100644 --- a/ql/src/codeql_ruby/controlflow/internal/Completion.qll +++ b/ql/src/codeql_ruby/controlflow/internal/Completion.qll @@ -5,6 +5,7 @@ */ private import codeql_ruby.AST +private import codeql_ruby.ast.internal.AST private import codeql_ruby.controlflow.ControlFlowGraph private import ControlFlowGraphImpl private import NonReturning @@ -53,7 +54,7 @@ private predicate nestedEnsureCompletion(Completion outer, int nestLevel) { pragma[noinline] private predicate completionIsValidForStmt(AstNode n, Completion c) { - n instanceof InRange and + n = TForIn(_) and c instanceof EmptinessCompletion or n instanceof BreakStmt and @@ -205,7 +206,7 @@ private predicate inMatchingContext(AstNode n) { w.getPattern(_) = n ) or - n = any(Trees::DefaultValueParameterTree t | t.hasDefaultValue()) + toGenerated(n).(Trees::DefaultValueParameterTree).hasDefaultValue() } /** diff --git a/ql/src/codeql_ruby/controlflow/internal/Consistency.qll b/ql/src/codeql_ruby/controlflow/internal/Consistency.qll index 0b8e07dd77c..ccec52fd56e 100644 --- a/ql/src/codeql_ruby/controlflow/internal/Consistency.qll +++ b/ql/src/codeql_ruby/controlflow/internal/Consistency.qll @@ -1,4 +1,4 @@ -private import codeql_ruby.AST +private import codeql_ruby.ast.internal.TreeSitter::Generated private import codeql_ruby.CFG private import Completion private import Splitting diff --git a/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll b/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll index f6d63161d94..89e3a604173 100644 --- a/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll +++ b/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll @@ -31,9 +31,10 @@ * caught up by its surrounding loop and turned into a `NormalCompletion`. */ +private import codeql_ruby.AST as AST private import codeql_ruby.ast.internal.AST as ASTInternal -private import codeql_ruby.ast.internal.Control as Control private import codeql_ruby.ast.internal.Scope +private import codeql_ruby.ast.Scope private import codeql_ruby.ast.internal.TreeSitter::Generated private import AstNodes private import codeql_ruby.ast.internal.Variable @@ -202,7 +203,7 @@ private predicate succImpl(AstNode pred, AstNode succ, Completion c) { } private predicate isHidden(ControlFlowTree t) { - not t instanceof ASTInternal::AstNode::Range + not t = ASTInternal::toGenerated(_) or t.isHidden() } @@ -290,16 +291,17 @@ abstract private class PreOrderTree extends ControlFlowTree { } // TODO: remove this class; it should be replaced with an implicit non AST node -class InRange extends ASTInternal::AstNode::Range, @in { +private class ForIn extends AST::AstNode, ASTInternal::TForIn { final override string toString() { result = "In" } } // TODO: remove this class; it should be replaced with an implicit non AST node -class ForRange extends Control::ForExpr::Range, @for { - override predicate child(string label, ASTInternal::AstNode::Range child) { - Control::ForExpr::Range.super.child(label, child) +private class ForRange extends AST::ForExpr { + override AST::AstNode getAChild(string pred) { + result = AST::ForExpr.super.getAChild(pred) or - label = "" and this.(AstNode).getAFieldOrChild().(In) = child + pred = "" and + result = ASTInternal::TForIn(ASTInternal::toGenerated(this).(For).getValue()) } } @@ -307,7 +309,7 @@ class ForRange extends Control::ForExpr::Range, @for { predicate isValidFor(Completion c, ControlFlowTree node) { c instanceof SimpleCompletion and isHidden(node) or - c.isValidFor(node) + c.isValidFor(ASTInternal::fromGenerated(node)) } abstract private class StandardPreOrderTree extends StandardNode, PreOrderTree { @@ -343,7 +345,8 @@ private class LeftToRightPostOrderNodes = @operator_assignment or @pair or @parenthesized_statements or @range or @redo or @regex or @rest_assignment or @retry or @return or @right_assignment_list or @scope_resolution or @token_simple_symbol or @splat_argument or @string__ or @string_array or @subshell or - @superclass or @symbol_array or @token_hash_key_symbol or @unary; + @superclass or @symbol_array or @token_hash_key_symbol or @unary or @splat_parameter or + @hash_splat_parameter or @block_parameter; private class LeftToRightPostOrderTree extends StandardPostOrderTree, LeftToRightPostOrderNodes { LeftToRightPostOrderTree() { @@ -357,7 +360,10 @@ private class LeftToRightPostOrderTree extends StandardPostOrderTree, LeftToRigh this instanceof ChainedString or this instanceof ExceptionVariable or this instanceof LeftAssignmentList or - this instanceof RightAssignmentList + this instanceof RightAssignmentList or + this instanceof SplatParameter or + this instanceof HashSplatParameter or + this instanceof BlockParameter } } @@ -441,8 +447,6 @@ module Trees { } } - private class BlockParameterTree extends LeafTree, BlockParameter { } - private class CaseTree extends PreOrderTree, Case { final override predicate propagatesAbnormal(AstNode child) { child = this.getValue() or child = this.getChild(_) @@ -505,18 +509,24 @@ module Trees { private class ConstantTree extends LeafTree, Constant { } /** A parameter that may have a default value. */ - abstract class DefaultValueParameterTree extends PreOrderTree { + abstract class DefaultValueParameterTree extends ControlFlowTree { abstract AstNode getDefaultValue(); + abstract AstNode getAccessNode(); + predicate hasDefaultValue() { exists(this.getDefaultValue()) } - final override predicate propagatesAbnormal(AstNode child) { child = this.getDefaultValue() } + final override predicate propagatesAbnormal(AstNode child) { + child = this.getDefaultValue() or child = this.getAccessNode() + } + + final override predicate first(AstNode first) { first = this.getAccessNode() } final override predicate last(AstNode last, Completion c) { last(this.getDefaultValue(), last, c) and c instanceof NormalCompletion or - last = this and + last = this.getAccessNode() and ( not this.hasDefaultValue() and c instanceof SimpleCompletion @@ -527,7 +537,7 @@ module Trees { } final override predicate succ(AstNode pred, AstNode succ, Completion c) { - pred = this and + pred = this.getAccessNode() and first(this.getDefaultValue(), succ) and c.(MatchingCompletion).getValue() = false } @@ -668,8 +678,6 @@ module Trees { private class GlobalVariableTree extends LeafTree, GlobalVariable { } - private class HashSplatParameterTree extends LeafTree, HashSplatParameter { } - private HeredocBody heredoc(HeredocBeginning start) { exists(int i, File f | start = @@ -725,6 +733,8 @@ module Trees { private class KeywordParameterTree extends DefaultValueParameterTree, KeywordParameter { final override AstNode getDefaultValue() { result = this.getValue() } + + final override AstNode getAccessNode() { result = this.getName() } } class LambdaTree extends LeafTree, Lambda { @@ -823,6 +833,8 @@ module Trees { private class OptionalParameterTree extends DefaultValueParameterTree, OptionalParameter { final override AstNode getDefaultValue() { result = this.getValue() } + + final override AstNode getAccessNode() { result = this.getName() } } private class RationalTree extends LeafTree, Rational { } @@ -1183,8 +1195,6 @@ module Trees { } } - private class SplatParameterTree extends LeafTree, SplatParameter { } - private class SuperTree extends LeafTree, Super { } private class TrueTree extends LeafTree, True { } @@ -1261,14 +1271,14 @@ module Trees { private Scope::Range parent(Scope::Range n) { result = n.getOuterScope() and - not n instanceof CfgScope + not n instanceof CfgScope::Range_ } cached private module Cached { /** Gets the CFG scope of node `n`. */ cached - CfgScope getCfgScope(AstNode n) { result = parent*(any(Scope::Range x | x.getADescendant() = n)) } + CfgScope getCfgScope(AstNode n) { ASTInternal::toGenerated(result) = parent*(scopeOf(n)) } private predicate isAbnormalExitType(SuccessorType t) { t instanceof RaiseSuccessor or t instanceof ExitSuccessor @@ -1288,7 +1298,7 @@ private module Cached { succExitSplits(b.getANode(), _, scope, _) ) } or - TAstNode(AstNode n, Splits splits) { + TAstCfgNode(AstNode n, Splits splits) { exists(Reachability::SameSplitsBlock b | b.isReachable(splits) | n = b.getANode()) } @@ -1312,10 +1322,10 @@ private module Cached { exists(CfgScope scope, AstNode succElement, Splits succSplits | pred = TEntryNode(scope) and succEntrySplits(scope, succElement, succSplits, t) and - result = TAstNode(succElement, succSplits) + result = TAstCfgNode(succElement, succSplits) ) or - exists(AstNode predNode, Splits predSplits | pred = TAstNode(predNode, predSplits) | + exists(AstNode predNode, Splits predSplits | pred = TAstCfgNode(predNode, predSplits) | exists(CfgScope scope, boolean normal | succExitSplits(predNode, predSplits, scope, t) and (if isAbnormalExitType(t) then normal = false else normal = true) and @@ -1325,7 +1335,7 @@ private module Cached { exists(AstNode succElement, Splits succSplits, Completion c | succSplits(predNode, predSplits, succElement, succSplits, c) and t = c.getAMatchingSuccessorType() and - result = TAstNode(succElement, succSplits) + result = TAstCfgNode(succElement, succSplits) ) ) or @@ -1349,5 +1359,5 @@ import Cached /** An AST node that is split into multiple control flow nodes. */ class SplitAstNode extends AstNode { - SplitAstNode() { strictcount(CfgNode n | n.getNode() = this) > 1 } + SplitAstNode() { strictcount(CfgNode n | ASTInternal::toGenerated(n.getNode()) = this) > 1 } } diff --git a/ql/src/codeql_ruby/controlflow/internal/Splitting.qll b/ql/src/codeql_ruby/controlflow/internal/Splitting.qll index c54cbc27b65..e1cf24a2815 100644 --- a/ql/src/codeql_ruby/controlflow/internal/Splitting.qll +++ b/ql/src/codeql_ruby/controlflow/internal/Splitting.qll @@ -2,7 +2,9 @@ * Provides classes and predicates relevant for splitting the control flow graph. */ -private import codeql_ruby.AST +private import codeql_ruby.ast.internal.TreeSitter::Generated +private import codeql_ruby.ast.internal.AST as ASTInternal +private import codeql_ruby.AST as AST private import Completion private import ControlFlowGraphImpl private import SuccessorTypes @@ -217,19 +219,28 @@ private module ConditionalCompletionSplitting { succ(pred, succ, c) and last(succ, _, completion) and ( - last(succ.(NotExpr).getOperand(), pred, c) and + last(ASTInternal::toGenerated(ASTInternal::fromGenerated(succ).(AST::NotExpr).getOperand()), + pred, c) and completion.(BooleanCompletion).getDual() = c or - last(succ.(LogicalAndExpr).getAnOperand(), pred, c) and + last(ASTInternal::toGenerated(ASTInternal::fromGenerated(succ) + .(AST::LogicalAndExpr) + .getAnOperand()), pred, c) and completion = c or - last(succ.(LogicalOrExpr).getAnOperand(), pred, c) and + last(ASTInternal::toGenerated(ASTInternal::fromGenerated(succ) + .(AST::LogicalOrExpr) + .getAnOperand()), pred, c) and completion = c or - last(succ.(ParenthesizedExpr).getLastExpr(), pred, c) and + last(ASTInternal::toGenerated(ASTInternal::fromGenerated(succ) + .(AST::ParenthesizedExpr) + .getLastExpr()), pred, c) and completion = c or - last(succ.(ConditionalExpr).getBranch(_), pred, c) and + last(ASTInternal::toGenerated(ASTInternal::fromGenerated(succ) + .(AST::ConditionalExpr) + .getBranch(_)), pred, c) and completion = c ) } @@ -244,7 +255,7 @@ private module ConditionalCompletionSplitting { override predicate hasExitScope(CfgScope scope, AstNode last, Completion c) { this.appliesTo(last) and - succExit(scope, last, c) and + succExit(ASTInternal::toGenerated(scope), last, c) and if c instanceof ConditionalCompletion then completion = c else any() } @@ -461,7 +472,7 @@ module EnsureSplitting { } override predicate hasExitScope(CfgScope scope, AstNode last, Completion c) { - succExit(scope, last, c) and + succExit(ASTInternal::toGenerated(scope), last, c) and ( exit(_, last, c, _) or @@ -506,7 +517,7 @@ class Splits extends TSplits { private predicate succEntrySplitsFromRank(CfgScope pred, AstNode succ, Splits splits, int rnk) { splits = TSplitsNil() and - succEntry(pred, succ) and + succEntry(ASTInternal::toGenerated(pred), succ) and rnk = 0 or exists(SplitImpl head, Splits tail | succEntrySplitsCons(pred, succ, head, tail, rnk) | @@ -529,7 +540,7 @@ private predicate succEntrySplitsCons( pragma[noinline] predicate succEntrySplits(CfgScope pred, AstNode succ, Splits succSplits, SuccessorType t) { exists(int rnk | - succEntry(pred, succ) and + succEntry(ASTInternal::toGenerated(pred), succ) and t instanceof NormalSuccessor and succEntrySplitsFromRank(pred, succ, succSplits, rnk) | @@ -548,7 +559,7 @@ predicate succExitSplits(AstNode last, Splits predSplits, CfgScope scope, Succes exists(Reachability::SameSplitsBlock b, Completion c | last = b.getANode() | b.isReachable(predSplits) and t = c.getAMatchingSuccessorType() and - succExit(scope, last, c) and + succExit(ASTInternal::toGenerated(scope), last, c) and forall(SplitImpl predSplit | predSplit = predSplits.getASplit() | predSplit.hasExitScope(scope, last, c) ) diff --git a/ql/src/codeql_ruby/printAst.qll b/ql/src/codeql_ruby/printAst.qll index 07cb40e180d..2737e456251 100644 --- a/ql/src/codeql_ruby/printAst.qll +++ b/ql/src/codeql_ruby/printAst.qll @@ -52,7 +52,7 @@ class PrintAstNode extends AstNode { /** * Gets the child node that is accessed using the predicate `edgeName`. */ - PrintAstNode getChild(string edgeName) { range.child(edgeName, result) } + PrintAstNode getChild(string edgeName) { result = this.getAChild(edgeName) } } private predicate shouldPrintNode(AstNode n) { diff --git a/ql/test/library-tests/ast/Ast.expected b/ql/test/library-tests/ast/Ast.expected index 5df02154eb5..246512d1ec6 100644 --- a/ql/test/library-tests/ast/Ast.expected +++ b/ql/test/library-tests/ast/Ast.expected @@ -13,12 +13,14 @@ calls/calls.rb: # 17| getStmt: [MethodCall] call to foo # 17| getBlock: [BraceBlock] { ... } # 17| getParameter: [SimpleParameter] x +# 17| getDefiningAccess: [LocalVariableAccess] x # 17| getStmt: [AddExpr] ... + ... # 17| getAnOperand/getLeftOperand: [LocalVariableAccess] x # 17| getAnOperand/getRightOperand: [IntegerLiteral] 1 # 20| getStmt: [MethodCall] call to foo # 20| getBlock: [DoBlock] do ... end # 20| getParameter: [SimpleParameter] x +# 20| getDefiningAccess: [LocalVariableAccess] x # 21| getStmt: [AddExpr] ... + ... # 21| getAnOperand/getLeftOperand: [LocalVariableAccess] x # 21| getAnOperand/getRightOperand: [IntegerLiteral] 1 @@ -28,6 +30,7 @@ calls/calls.rb: # 25| getComponent: [StringTextComponent] foo # 25| getBlock: [DoBlock] do ... end # 25| getParameter: [SimpleParameter] x +# 25| getDefiningAccess: [LocalVariableAccess] x # 26| getStmt: [AddExpr] ... + ... # 26| getAnOperand/getLeftOperand: [LocalVariableAccess] x # 26| getAnOperand/getRightOperand: [IntegerLiteral] 1 @@ -153,16 +156,20 @@ calls/calls.rb: # 144| getReceiver: [ConstantReadAccess] X # 148| getStmt: [Method] method_with_keyword_param # 148| getParameter: [KeywordParameter] keyword +# 148| getDefiningAccess: [LocalVariableAccess] keyword # 148| getDefaultValue: [MethodCall] call to foo # 150| getStmt: [Method] method_with_keyword_param2 # 150| getParameter: [KeywordParameter] keyword +# 150| getDefiningAccess: [LocalVariableAccess] keyword # 150| getDefaultValue: [MethodCall] call to foo # 150| getReceiver: [ConstantReadAccess] X # 154| getStmt: [Method] method_with_optional_param # 154| getParameter: [OptionalParameter] param +# 154| getDefiningAccess: [LocalVariableAccess] param # 154| getDefaultValue: [MethodCall] call to foo # 156| getStmt: [Method] method_with_optional_param2 # 156| getParameter: [OptionalParameter] param +# 156| getDefiningAccess: [LocalVariableAccess] param # 156| getDefaultValue: [MethodCall] call to foo # 156| getReceiver: [ConstantReadAccess] X # 160| getStmt: [Module] SomeModule @@ -383,12 +390,14 @@ calls/calls.rb: # 290| getStmt: [SuperCall] call to super # 290| getBlock: [BraceBlock] { ... } # 290| getParameter: [SimpleParameter] x +# 290| getDefiningAccess: [LocalVariableAccess] x # 290| getStmt: [AddExpr] ... + ... # 290| getAnOperand/getLeftOperand: [LocalVariableAccess] x # 290| getAnOperand/getRightOperand: [IntegerLiteral] 1 # 291| getStmt: [SuperCall] call to super # 291| getBlock: [DoBlock] do ... end # 291| getParameter: [SimpleParameter] x +# 291| getDefiningAccess: [LocalVariableAccess] x # 291| getStmt: [MulExpr] ... * ... # 291| getAnOperand/getLeftOperand: [LocalVariableAccess] x # 291| getAnOperand/getRightOperand: [IntegerLiteral] 2 @@ -397,6 +406,7 @@ calls/calls.rb: # 292| getArgument: [IntegerLiteral] 5 # 292| getBlock: [BraceBlock] { ... } # 292| getParameter: [SimpleParameter] x +# 292| getDefiningAccess: [LocalVariableAccess] x # 292| getStmt: [AddExpr] ... + ... # 292| getAnOperand/getLeftOperand: [LocalVariableAccess] x # 292| getAnOperand/getRightOperand: [IntegerLiteral] 100 @@ -405,6 +415,7 @@ calls/calls.rb: # 293| getArgument: [IntegerLiteral] 7 # 293| getBlock: [DoBlock] do ... end # 293| getParameter: [SimpleParameter] x +# 293| getDefiningAccess: [LocalVariableAccess] x # 293| getStmt: [AddExpr] ... + ... # 293| getAnOperand/getLeftOperand: [LocalVariableAccess] x # 293| getAnOperand/getRightOperand: [IntegerLiteral] 200 @@ -689,6 +700,7 @@ constants/constants.rb: # 19| getReceiver: [ConstantReadAccess] Names # 19| getBlock: [DoBlock] do ... end # 19| getParameter: [SimpleParameter] name +# 19| getDefiningAccess: [LocalVariableAccess] name # 20| getStmt: [MethodCall] call to puts # 20| getArgument: [StringLiteral] "#{...} #{...}" # 20| getComponent: [StringInterpolationComponent] #{...} @@ -1528,8 +1540,11 @@ params/params.rb: # 1| [Toplevel] params.rb # 4| getStmt: [Method] identifier_method_params # 4| getParameter: [SimpleParameter] foo +# 4| getDefiningAccess: [LocalVariableAccess] foo # 4| getParameter: [SimpleParameter] bar +# 4| getDefiningAccess: [LocalVariableAccess] bar # 4| getParameter: [SimpleParameter] baz +# 4| getDefiningAccess: [LocalVariableAccess] baz # 8| getStmt: [AssignExpr] ... = ... # 8| getAnOperand/getLeftOperand: [LocalVariableAccess] hash # 8| getAnOperand/getRightOperand: [HashLiteral] {...} @@ -1537,7 +1552,9 @@ params/params.rb: # 9| getReceiver: [LocalVariableAccess] hash # 9| getBlock: [DoBlock] do ... end # 9| getParameter: [SimpleParameter] key +# 9| getDefiningAccess: [LocalVariableAccess] key # 9| getParameter: [SimpleParameter] value +# 9| getDefiningAccess: [LocalVariableAccess] value # 10| getStmt: [MethodCall] call to puts # 10| getArgument: [StringLiteral] "#{...} -> #{...}" # 10| getComponent: [StringInterpolationComponent] #{...} @@ -1549,7 +1566,9 @@ params/params.rb: # 14| getAnOperand/getLeftOperand: [LocalVariableAccess] sum # 14| getAnOperand/getRightOperand: [Lambda] -> { ... } # 14| getParameter: [SimpleParameter] foo +# 14| getDefiningAccess: [LocalVariableAccess] foo # 14| getParameter: [SimpleParameter] bar +# 14| getDefiningAccess: [LocalVariableAccess] bar # 14| getStmt: [AddExpr] ... + ... # 14| getAnOperand/getLeftOperand: [LocalVariableAccess] foo # 14| getAnOperand/getRightOperand: [LocalVariableAccess] bar @@ -1589,24 +1608,36 @@ params/params.rb: # 26| getAnOperand/getRightOperand: [LocalVariableAccess] fourth # 30| getStmt: [Method] method_with_splat # 30| getParameter: [SimpleParameter] wibble +# 30| getDefiningAccess: [LocalVariableAccess] wibble # 30| getParameter: [SplatParameter] *splat +# 30| getDefiningAccess: [LocalVariableAccess] splat # 30| getParameter: [HashSplatParameter] **double_splat +# 30| getDefiningAccess: [LocalVariableAccess] double_splat # 34| getStmt: [MethodCall] call to each # 34| getReceiver: [LocalVariableAccess] array # 34| getBlock: [DoBlock] do ... end # 34| getParameter: [SimpleParameter] val +# 34| getDefiningAccess: [LocalVariableAccess] val # 34| getParameter: [SplatParameter] *splat +# 34| getDefiningAccess: [LocalVariableAccess] splat # 34| getParameter: [HashSplatParameter] **double_splat +# 34| getDefiningAccess: [LocalVariableAccess] double_splat # 38| getStmt: [AssignExpr] ... = ... # 38| getAnOperand/getLeftOperand: [LocalVariableAccess] lambda_with_splats # 38| getAnOperand/getRightOperand: [Lambda] -> { ... } # 38| getParameter: [SimpleParameter] x +# 38| getDefiningAccess: [LocalVariableAccess] x # 38| getParameter: [SplatParameter] *blah +# 38| getDefiningAccess: [LocalVariableAccess] blah # 38| getParameter: [HashSplatParameter] **wibble +# 38| getDefiningAccess: [LocalVariableAccess] wibble # 41| getStmt: [Method] method_with_keyword_params # 41| getParameter: [SimpleParameter] x +# 41| getDefiningAccess: [LocalVariableAccess] x # 41| getParameter: [KeywordParameter] foo +# 41| getDefiningAccess: [LocalVariableAccess] foo # 41| getParameter: [KeywordParameter] bar +# 41| getDefiningAccess: [LocalVariableAccess] bar # 41| getDefaultValue: [IntegerLiteral] 7 # 42| getStmt: [AddExpr] ... + ... # 42| getAnOperand/getLeftOperand: [AddExpr] ... + ... @@ -1615,6 +1646,7 @@ params/params.rb: # 42| getAnOperand/getRightOperand: [LocalVariableAccess] bar # 46| getStmt: [Method] use_block_with_keyword # 46| getParameter: [BlockParameter] &block +# 46| getDefiningAccess: [LocalVariableAccess] block # 47| getStmt: [MethodCall] call to puts # 47| getArgument: [MethodCall] call to call # 47| getReceiver: [LocalVariableAccess] block @@ -1627,7 +1659,9 @@ params/params.rb: # 49| getStmt: [MethodCall] call to use_block_with_keyword # 49| getBlock: [DoBlock] do ... end # 49| getParameter: [KeywordParameter] xx +# 49| getDefiningAccess: [LocalVariableAccess] xx # 49| getParameter: [KeywordParameter] yy +# 49| getDefiningAccess: [LocalVariableAccess] yy # 49| getDefaultValue: [IntegerLiteral] 100 # 50| getStmt: [AddExpr] ... + ... # 50| getAnOperand/getLeftOperand: [LocalVariableAccess] xx @@ -1636,8 +1670,11 @@ params/params.rb: # 53| getAnOperand/getLeftOperand: [LocalVariableAccess] lambda_with_keyword_params # 53| getAnOperand/getRightOperand: [Lambda] -> { ... } # 53| getParameter: [SimpleParameter] x +# 53| getDefiningAccess: [LocalVariableAccess] x # 53| getParameter: [KeywordParameter] y +# 53| getDefiningAccess: [LocalVariableAccess] y # 53| getParameter: [KeywordParameter] z +# 53| getDefiningAccess: [LocalVariableAccess] z # 53| getDefaultValue: [IntegerLiteral] 3 # 54| getStmt: [AddExpr] ... + ... # 54| getAnOperand/getLeftOperand: [AddExpr] ... + ... @@ -1646,12 +1683,16 @@ params/params.rb: # 54| getAnOperand/getRightOperand: [LocalVariableAccess] z # 58| getStmt: [Method] method_with_optional_params # 58| getParameter: [SimpleParameter] val1 +# 58| getDefiningAccess: [LocalVariableAccess] val1 # 58| getParameter: [OptionalParameter] val2 +# 58| getDefiningAccess: [LocalVariableAccess] val2 # 58| getDefaultValue: [IntegerLiteral] 0 # 58| getParameter: [OptionalParameter] val3 +# 58| getDefiningAccess: [LocalVariableAccess] val3 # 58| getDefaultValue: [IntegerLiteral] 100 # 62| getStmt: [Method] use_block_with_optional # 62| getParameter: [BlockParameter] &block +# 62| getDefiningAccess: [LocalVariableAccess] block # 63| getStmt: [MethodCall] call to call # 63| getReceiver: [LocalVariableAccess] block # 63| getArgument: [StringLiteral] "Zeus" @@ -1659,7 +1700,9 @@ params/params.rb: # 65| getStmt: [MethodCall] call to use_block_with_optional # 65| getBlock: [DoBlock] do ... end # 65| getParameter: [SimpleParameter] name +# 65| getDefiningAccess: [LocalVariableAccess] name # 65| getParameter: [OptionalParameter] age +# 65| getDefiningAccess: [LocalVariableAccess] age # 65| getDefaultValue: [IntegerLiteral] 99 # 66| getStmt: [MethodCall] call to puts # 66| getArgument: [StringLiteral] "#{...} is #{...} years old" @@ -1673,9 +1716,12 @@ params/params.rb: # 70| getAnOperand/getLeftOperand: [LocalVariableAccess] lambda_with_optional_params # 70| getAnOperand/getRightOperand: [Lambda] -> { ... } # 70| getParameter: [SimpleParameter] a +# 70| getDefiningAccess: [LocalVariableAccess] a # 70| getParameter: [OptionalParameter] b +# 70| getDefiningAccess: [LocalVariableAccess] b # 70| getDefaultValue: [IntegerLiteral] 1000 # 70| getParameter: [OptionalParameter] c +# 70| getDefiningAccess: [LocalVariableAccess] c # 70| getDefaultValue: [IntegerLiteral] 20 # 70| getStmt: [AddExpr] ... + ... # 70| getAnOperand/getLeftOperand: [AddExpr] ... + ... diff --git a/ql/test/library-tests/controlflow/graph/Cfg.expected b/ql/test/library-tests/controlflow/graph/Cfg.expected index d6f687ecb90..f106b06d2d8 100644 --- a/ql/test/library-tests/controlflow/graph/Cfg.expected +++ b/ql/test/library-tests/controlflow/graph/Cfg.expected @@ -1,26 +1,26 @@ break_ensure.rb: -# 1| enter break_ensure.rb -#-----| -> m1 - # 1| enter m1 #-----| -> elements +# 1| enter break_ensure.rb +#-----| -> m1 + # 1| m1 #-----| -> m2 # 1| elements #-----| -> elements -# 1| exit break_ensure.rb - # 1| exit m1 -# 1| exit break_ensure.rb (normal) -#-----| -> exit break_ensure.rb +# 1| exit break_ensure.rb # 1| exit m1 (normal) #-----| -> exit m1 +# 1| exit break_ensure.rb (normal) +#-----| -> exit break_ensure.rb + # 2| for ... in ... #-----| -> ensure ... @@ -338,25 +338,25 @@ break_ensure.rb: #-----| -> [ensure: raise] break case.rb: -# 1| enter case.rb -#-----| -> if_in_case - # 1| enter if_in_case #-----| -> case ... +# 1| enter case.rb +#-----| -> if_in_case + # 1| if_in_case #-----| -> exit case.rb (normal) -# 1| exit case.rb - # 1| exit if_in_case -# 1| exit case.rb (normal) -#-----| -> exit case.rb +# 1| exit case.rb # 1| exit if_in_case (normal) #-----| -> exit if_in_case +# 1| exit case.rb (normal) +#-----| -> exit case.rb + # 2| case ... #-----| -> call to x1 @@ -544,7 +544,7 @@ cfg.rb: #-----| -> &... # 29| enter { ... } -#-----| -> &x +#-----| -> x # 29| call to new #-----| -> true @@ -555,7 +555,7 @@ cfg.rb: # 29| { ... } #-----| -> call to new -# 29| &x +# 29| x #-----| -> x # 29| call to call @@ -1094,9 +1094,9 @@ cfg.rb: #-----| -> key # 101| key -#-----| -> **kwargs +#-----| -> kwargs -# 101| **kwargs +# 101| kwargs #-----| -> value # 101| exit parameters @@ -1456,7 +1456,7 @@ cfg.rb: #-----| -> call to new # 149| enter method -#-----| -> *x +#-----| -> x # 149| method #-----| -> two_parameters @@ -1464,7 +1464,7 @@ cfg.rb: # 149| silly #-----| -> method -# 149| *x +# 149| x #-----| -> x # 149| exit method @@ -1825,24 +1825,21 @@ cfg.rb: #-----| -> exit { ... } exit.rb: -# 1| enter exit.rb -#-----| -> m1 - # 1| enter m1 #-----| -> x +# 1| enter exit.rb +#-----| -> m1 + # 1| m1 #-----| -> m2 # 1| x #-----| -> x -# 1| exit exit.rb - # 1| exit m1 -# 1| exit exit.rb (normal) -#-----| -> exit exit.rb +# 1| exit exit.rb # 1| exit m1 (abnormal) #-----| -> exit m1 @@ -1850,6 +1847,9 @@ exit.rb: # 1| exit m1 (normal) #-----| -> exit m1 +# 1| exit exit.rb (normal) +#-----| -> exit exit.rb + # 2| if ... #-----| -> "x <= 2" @@ -1918,25 +1918,25 @@ exit.rb: #-----| -> call to puts heredoc.rb: -# 1| enter heredoc.rb -#-----| -> double_heredoc - # 1| enter double_heredoc #-----| -> < double_heredoc + # 1| double_heredoc #-----| -> exit heredoc.rb (normal) -# 1| exit heredoc.rb - # 1| exit double_heredoc -# 1| exit heredoc.rb (normal) -#-----| -> exit heredoc.rb +# 1| exit heredoc.rb # 1| exit double_heredoc (normal) #-----| -> exit double_heredoc +# 1| exit heredoc.rb (normal) +#-----| -> exit heredoc.rb + # 2| call to puts #-----| -> exit double_heredoc (normal) @@ -1947,28 +1947,28 @@ heredoc.rb: #-----| -> call to puts ifs.rb: -# 1| enter ifs.rb -#-----| -> m1 - # 1| enter m1 #-----| -> x +# 1| enter ifs.rb +#-----| -> m1 + # 1| m1 #-----| -> m2 # 1| x #-----| -> x -# 1| exit ifs.rb - # 1| exit m1 -# 1| exit ifs.rb (normal) -#-----| -> exit ifs.rb +# 1| exit ifs.rb # 1| exit m1 (normal) #-----| -> exit m1 +# 1| exit ifs.rb (normal) +#-----| -> exit ifs.rb + # 2| if ... #-----| -> exit m1 (normal) @@ -2343,28 +2343,28 @@ ifs.rb: #-----| true -> [false] ! ... loops.rb: -# 1| enter loops.rb -#-----| -> m1 - # 1| enter m1 #-----| -> x +# 1| enter loops.rb +#-----| -> m1 + # 1| m1 #-----| -> m2 # 1| x #-----| -> x -# 1| exit loops.rb - # 1| exit m1 -# 1| exit loops.rb (normal) -#-----| -> exit loops.rb +# 1| exit loops.rb # 1| exit m1 (normal) #-----| -> exit m1 +# 1| exit loops.rb (normal) +#-----| -> exit loops.rb + # 2| while ... #-----| -> exit m1 (normal) diff --git a/ql/test/library-tests/variables/ssa.expected b/ql/test/library-tests/variables/ssa.expected index cd3ce3e3047..513d0029e8c 100644 --- a/ql/test/library-tests/variables/ssa.expected +++ b/ql/test/library-tests/variables/ssa.expected @@ -13,11 +13,11 @@ definition | parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | | parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y | | parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | -| parameters.rb:7:25:7:31 | *pizzas | parameters.rb:7:26:7:31 | pizzas | -| parameters.rb:15:15:15:19 | **map | parameters.rb:15:17:15:19 | map | +| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | +| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | | parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | | parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | -| parameters.rb:21:16:21:21 | &block | parameters.rb:21:17:21:21 | block | +| parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | | parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | | parameters.rb:25:33:25:36 | size | parameters.rb:25:33:25:36 | size | | parameters.rb:30:15:30:19 | first | parameters.rb:30:15:30:19 | first | @@ -100,12 +100,12 @@ read | parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y | parameters.rb:4:9:4:9 | y | | parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:9:25:9:30 | client | | parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:11:41:11:46 | client | -| parameters.rb:7:25:7:31 | *pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas | -| parameters.rb:7:25:7:31 | *pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:11:14:11:19 | pizzas | -| parameters.rb:15:15:15:19 | **map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map | +| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas | +| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:11:14:11:19 | pizzas | +| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map | | parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | parameters.rb:17:13:17:15 | key | | parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | parameters.rb:17:22:17:26 | value | -| parameters.rb:21:16:21:21 | &block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block | +| parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block | | parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:40:25:43 | name | | parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:26:8:26:11 | name | | parameters.rb:25:33:25:36 | size | parameters.rb:25:33:25:36 | size | parameters.rb:27:8:27:11 | size | @@ -181,11 +181,11 @@ firstRead | parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y | parameters.rb:4:9:4:9 | y | | parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:9:25:9:30 | client | | parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:11:41:11:46 | client | -| parameters.rb:7:25:7:31 | *pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas | -| parameters.rb:15:15:15:19 | **map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map | +| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas | +| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map | | parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | parameters.rb:17:13:17:15 | key | | parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | parameters.rb:17:22:17:26 | value | -| parameters.rb:21:16:21:21 | &block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block | +| parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block | | parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:40:25:43 | name | | parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:26:8:26:11 | name | | parameters.rb:25:33:25:36 | size | parameters.rb:25:33:25:36 | size | parameters.rb:27:8:27:11 | size | @@ -250,12 +250,12 @@ lastRead | parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y | parameters.rb:4:9:4:9 | y | | parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:9:25:9:30 | client | | parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:11:41:11:46 | client | -| parameters.rb:7:25:7:31 | *pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas | -| parameters.rb:7:25:7:31 | *pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:11:14:11:19 | pizzas | -| parameters.rb:15:15:15:19 | **map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map | +| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas | +| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:11:14:11:19 | pizzas | +| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map | | parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | parameters.rb:17:13:17:15 | key | | parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | parameters.rb:17:22:17:26 | value | -| parameters.rb:21:16:21:21 | &block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block | +| parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block | | parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:26:8:26:11 | name | | parameters.rb:25:33:25:36 | size | parameters.rb:25:33:25:36 | size | parameters.rb:27:8:27:11 | size | | parameters.rb:30:15:30:19 | first | parameters.rb:30:15:30:19 | first | parameters.rb:31:11:31:15 | first | @@ -306,7 +306,7 @@ lastRead | ssa.rb:84:10:86:8 | | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured | adjacentReads | nested_scopes.rb:13:11:13:15 | ... = ... | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:14:16:14:16 | a | nested_scopes.rb:15:11:15:11 | a | -| parameters.rb:7:25:7:31 | *pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas | parameters.rb:11:14:11:19 | pizzas | +| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas | parameters.rb:11:14:11:19 | pizzas | | parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:40:25:43 | name | parameters.rb:26:8:26:11 | name | | scopes.rb:9:9:18:3 | | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | scopes.rb:11:4:11:4 | a | | scopes.rb:27:1:27:5 | ... = ... | scopes.rb:27:1:27:1 | x | scopes.rb:28:8:28:8 | x | scopes.rb:31:10:31:10 | x | diff --git a/ql/test/library-tests/variables/varaccess.expected b/ql/test/library-tests/variables/varaccess.expected index 783b40a3b2c..55ce10e6324 100644 --- a/ql/test/library-tests/variables/varaccess.expected +++ b/ql/test/library-tests/variables/varaccess.expected @@ -51,18 +51,18 @@ variableAccess | parameters.rb:3:9:3:9 | x | parameters.rb:1:14:1:14 | x | parameters.rb:1:9:5:3 | do ... end | | parameters.rb:4:9:4:9 | y | parameters.rb:1:18:1:18 | y | parameters.rb:1:9:5:3 | do ... end | | parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:7:1:13:3 | order_pizza | -| parameters.rb:7:25:7:31 | *pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:1:13:3 | order_pizza | +| parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:1:13:3 | order_pizza | | parameters.rb:8:6:8:11 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:1:13:3 | order_pizza | | parameters.rb:9:25:9:30 | client | parameters.rb:7:17:7:22 | client | parameters.rb:7:1:13:3 | order_pizza | | parameters.rb:11:14:11:19 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:1:13:3 | order_pizza | | parameters.rb:11:41:11:46 | client | parameters.rb:7:17:7:22 | client | parameters.rb:7:1:13:3 | order_pizza | -| parameters.rb:15:15:15:19 | **map | parameters.rb:15:17:15:19 | map | parameters.rb:15:1:19:3 | print_map | +| parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | parameters.rb:15:1:19:3 | print_map | | parameters.rb:16:3:16:5 | map | parameters.rb:15:17:15:19 | map | parameters.rb:15:1:19:3 | print_map | | parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | parameters.rb:16:12:18:5 | do ... end | | parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | parameters.rb:16:12:18:5 | do ... end | | parameters.rb:17:13:17:15 | key | parameters.rb:16:16:16:18 | key | parameters.rb:16:12:18:5 | do ... end | | parameters.rb:17:22:17:26 | value | parameters.rb:16:21:16:25 | value | parameters.rb:16:12:18:5 | do ... end | -| parameters.rb:21:16:21:21 | &block | parameters.rb:21:17:21:21 | block | parameters.rb:21:1:23:3 | call_block | +| parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | parameters.rb:21:1:23:3 | call_block | | parameters.rb:22:3:22:7 | block | parameters.rb:21:17:21:21 | block | parameters.rb:21:1:23:3 | call_block | | parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:1:28:3 | opt_param | | parameters.rb:25:33:25:36 | size | parameters.rb:25:33:25:36 | size | parameters.rb:25:1:28:3 | opt_param | @@ -239,11 +239,11 @@ implicitWrite | parameters.rb:1:14:1:14 | x | | parameters.rb:1:18:1:18 | y | | parameters.rb:7:17:7:22 | client | -| parameters.rb:7:25:7:31 | *pizzas | -| parameters.rb:15:15:15:19 | **map | +| parameters.rb:7:26:7:31 | pizzas | +| parameters.rb:15:17:15:19 | map | | parameters.rb:16:16:16:18 | key | | parameters.rb:16:21:16:25 | value | -| parameters.rb:21:16:21:21 | &block | +| parameters.rb:21:17:21:21 | block | | parameters.rb:25:15:25:18 | name | | parameters.rb:25:33:25:36 | size | | parameters.rb:30:15:30:19 | first |