diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll index c94184b4f66f..755c2368f9bd 100644 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll +++ b/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll @@ -25,7 +25,7 @@ module ControlFlow { * Only nodes that can be reached from the callable entry point are included in * the CFG. */ - class Node extends TNode { + class Node extends TCfgNode { /** Gets a textual representation of this control flow node. */ string toString() { none() } diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll index ee901b9192ec..85c9e0b4f0b9 100644 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll +++ b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll @@ -788,7 +788,7 @@ private module Cached { * The control flow graph is pruned for unreachable nodes. */ cached - newtype TNode = + newtype TCfgNode = TEntryNode(CfgScope scope) { succEntrySplits(scope, _, _, _) } or TAnnotatedExitNode(CfgScope scope, boolean normal) { exists(Reachability::SameSplitsBlock b, SuccessorType t | b.isReachable(_) | @@ -807,7 +807,7 @@ private module Cached { /** Gets a successor node of a given flow type, if any. */ cached - TNode getASuccessor(TNode pred, SuccessorType t) { + TCfgNode getASuccessor(TCfgNode pred, SuccessorType t) { // Callable entry node -> callable body exists(ControlFlowElement succElement, Splits succSplits, CfgScope scope | result = TElementNode(succElement, succSplits) and diff --git a/ruby/ql/lib/codeql/ruby/AST.qll b/ruby/ql/lib/codeql/ruby/AST.qll index 2d006b6312ae..e09d1d5b7d97 100644 --- a/ruby/ql/lib/codeql/ruby/AST.qll +++ b/ruby/ql/lib/codeql/ruby/AST.qll @@ -18,6 +18,27 @@ private import ast.internal.Scope private import ast.internal.Synthesis private import ast.internal.TreeSitter +cached +private module Cached { + cached + ModuleBase getEnclosingModule(Scope s) { + result = s + or + not s instanceof ModuleBase and result = getEnclosingModule(s.getOuterScope()) + } + + cached + MethodBase getEnclosingMethod(Scope s) { + result = s + or + not s instanceof MethodBase and + not s instanceof ModuleBase and + result = getEnclosingMethod(s.getOuterScope()) + } +} + +private import Cached + /** * A node in the abstract syntax tree. This class is the base class for all Ruby * program elements. @@ -39,20 +60,10 @@ class AstNode extends TAstNode { final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } /** Gets the enclosing module, if any. */ - ModuleBase getEnclosingModule() { - exists(Scope::Range s | - s = scopeOf(toGeneratedInclSynth(this)) and - toGeneratedInclSynth(result) = s.getEnclosingModule() - ) - } + ModuleBase getEnclosingModule() { result = getEnclosingModule(scopeOfInclSynth(this)) } /** Gets the enclosing method, if any. */ - MethodBase getEnclosingMethod() { - exists(Scope::Range s | - s = scopeOf(toGeneratedInclSynth(this)) and - toGeneratedInclSynth(result) = s.getEnclosingMethod() - ) - } + MethodBase getEnclosingMethod() { result = getEnclosingMethod(scopeOfInclSynth(this)) } /** Gets a textual representation of this node. */ cached diff --git a/ruby/ql/lib/codeql/ruby/ast/Control.qll b/ruby/ql/lib/codeql/ruby/ast/Control.qll index d209e2861c02..8562f1b47401 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Control.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Control.qll @@ -583,7 +583,7 @@ class ForExpr extends Loop, TForExpr { final override string getAPrimaryQlClass() { result = "ForExpr" } /** Gets the body of this `for` loop. */ - final override Stmt getBody() { toGenerated(result) = g.getBody() } + final override StmtSequence getBody() { toGenerated(result) = g.getBody() } /** Gets the pattern representing the iteration argument. */ final Pattern getPattern() { toGenerated(result) = g.getPattern() } diff --git a/ruby/ql/lib/codeql/ruby/ast/Expr.qll b/ruby/ql/lib/codeql/ruby/ast/Expr.qll index 35bdb1d89114..d76fdb7cc628 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Expr.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Expr.qll @@ -1,6 +1,7 @@ private import codeql.ruby.AST private import codeql.ruby.CFG private import internal.AST +private import internal.Expr private import internal.TreeSitter /** @@ -91,90 +92,19 @@ class StmtSequence extends Expr, TStmtSequence { } } -private class StmtSequenceSynth extends StmtSequence, TStmtSequenceSynth { - final override Stmt getStmt(int n) { synthChild(this, n, result) } - - final override string toString() { result = "..." } -} - -private class Then extends StmtSequence, TThen { - private Ruby::Then g; - - Then() { this = TThen(g) } - - override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } - - final override string toString() { result = "then ..." } -} - -private class Else extends StmtSequence, TElse { - private Ruby::Else g; - - Else() { this = TElse(g) } - - override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } - - final override string toString() { result = "else ..." } -} - -private class Do extends StmtSequence, TDo { - private Ruby::Do g; - - Do() { this = TDo(g) } - - override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } - - final override string toString() { result = "do ..." } -} - -private class Ensure extends StmtSequence, TEnsure { - private Ruby::Ensure g; - - Ensure() { this = TEnsure(g) } - - override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } - - final override string toString() { result = "ensure ..." } -} - /** * A sequence of statements representing the body of a method, class, module, * or do-block. That is, any body that may also include rescue/ensure/else * statements. */ class BodyStmt extends StmtSequence, TBodyStmt { - // Not defined by dispatch, as it should not be exposed - private Ruby::AstNode getChild(int i) { - result = any(Ruby::Method g | this = TMethod(g)).getChild(i) - or - result = any(Ruby::SingletonMethod g | this = TSingletonMethod(g)).getChild(i) - or - exists(Ruby::Lambda g | this = TLambda(g) | - result = g.getBody().(Ruby::DoBlock).getChild(i) or - result = g.getBody().(Ruby::Block).getChild(i) - ) - or - result = any(Ruby::DoBlock g | this = TDoBlock(g)).getChild(i) - or - result = any(Ruby::Program g | this = TToplevel(g)).getChild(i) and - not result instanceof Ruby::BeginBlock - or - result = any(Ruby::Class g | this = TClassDeclaration(g)).getChild(i) - or - result = any(Ruby::SingletonClass g | this = TSingletonClass(g)).getChild(i) - or - result = any(Ruby::Module g | this = TModuleDeclaration(g)).getChild(i) - or - result = any(Ruby::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 + toGenerated(result) = + rank[n + 1](Ruby::AstNode node, int i | + node = getBodyStmtChild(this, i) and + not node instanceof Ruby::Else and + not node instanceof Ruby::Rescue and + not node instanceof Ruby::Ensure | node order by i ) @@ -183,17 +113,25 @@ class BodyStmt extends StmtSequence, TBodyStmt { /** Gets the `n`th rescue clause in this block. */ final RescueClause getRescue(int n) { result = - rank[n + 1](RescueClause node, int i | toGenerated(node) = this.getChild(i) | node order by i) + rank[n + 1](RescueClause node, int i | + toGenerated(node) = getBodyStmtChild(this, 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 = unique(Else s | toGenerated(s) = getChild(_)) } + final StmtSequence getElse() { + result = unique(Else s | toGenerated(s) = getBodyStmtChild(this, _)) + } /** Gets the `ensure` clause in this block, if any. */ - final StmtSequence getEnsure() { result = unique(Ensure s | toGenerated(s) = getChild(_)) } + final StmtSequence getEnsure() { + result = unique(Ensure s | toGenerated(s) = getBodyStmtChild(this, _)) + } final predicate hasEnsure() { exists(this.getEnsure()) } diff --git a/ruby/ql/lib/codeql/ruby/ast/Method.qll b/ruby/ql/lib/codeql/ruby/ast/Method.qll index bf40d77034e6..d5fea5ed4c45 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Method.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Method.qll @@ -2,6 +2,7 @@ private import codeql.ruby.AST private import codeql.ruby.controlflow.ControlFlowGraph private import internal.AST private import internal.TreeSitter +private import internal.Method /** A callable. */ class Callable extends StmtSequence, Expr, Scope, TCallable { @@ -212,16 +213,6 @@ class DoBlock extends Block, BodyStmt, TDoBlock { * ``` */ class BraceBlock extends Block, TBraceBlock { - private Ruby::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/ruby/ql/lib/codeql/ruby/ast/Parameter.qll b/ruby/ql/lib/codeql/ruby/ast/Parameter.qll index 6e6b5395d435..28e40635b74e 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Parameter.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Parameter.qll @@ -57,7 +57,11 @@ class NamedParameter extends Parameter, TNamedParameter { final VariableAccess getAnAccess() { result = this.getVariable().getAnAccess() } /** Gets the access that defines the underlying local variable. */ - final VariableAccess getDefiningAccess() { result = this.getVariable().getDefiningAccess() } + final VariableAccess getDefiningAccess() { + result = this.getVariable().getDefiningAccess() + or + result = this.(SimpleParameterSynthImpl).getDefininingAccess() + } override AstNode getAChild(string pred) { result = super.getAChild(pred) @@ -68,14 +72,12 @@ class NamedParameter extends Parameter, TNamedParameter { } /** A simple (normal) parameter. */ -class SimpleParameter extends NamedParameter, PatternParameter, VariablePattern, TSimpleParameter { - private Ruby::Identifier g; - - SimpleParameter() { this = TSimpleParameter(g) } +class SimpleParameter extends NamedParameter, PatternParameter, VariablePattern, TSimpleParameter instanceof SimpleParameterImpl { + final override string getName() { result = SimpleParameterImpl.super.getNameImpl() } - final override string getName() { result = g.getValue() } - - final override LocalVariable getVariable() { result = TLocalVariableReal(_, _, g) } + final override LocalVariable getVariable() { + result = SimpleParameterImpl.super.getVariableImpl() + } final override LocalVariable getAVariable() { result = this.getVariable() } diff --git a/ruby/ql/lib/codeql/ruby/ast/Pattern.qll b/ruby/ql/lib/codeql/ruby/ast/Pattern.qll index b275a8d813a7..d3df031980e2 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Pattern.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Pattern.qll @@ -4,6 +4,7 @@ private import internal.AST private import internal.Pattern private import internal.TreeSitter private import internal.Variable +private import internal.Parameter /** A pattern. */ class Pattern extends AstNode { @@ -15,6 +16,8 @@ class Pattern extends AstNode { implicitParameterAssignmentNode(toGenerated(this), _) or this = getSynthChild(any(AssignExpr ae), 0) + or + this instanceof SimpleParameterImpl } /** Gets a variable used in (or introduced by) this pattern. */ diff --git a/ruby/ql/lib/codeql/ruby/ast/Scope.qll b/ruby/ql/lib/codeql/ruby/ast/Scope.qll index fe3b1b45cd10..3e8437f79b35 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Scope.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Scope.qll @@ -3,22 +3,20 @@ private import internal.AST private import internal.Scope private import internal.TreeSitter -class Scope extends AstNode, TScopeType { - private Scope::Range range; +/** + * A variable scope. This is either a top-level (file), a module, a class, + * or a callable. + */ +class Scope extends AstNode, TScopeType instanceof ScopeImpl { + /** Gets the outer scope, if any. */ + Scope getOuterScope() { result = super.getOuterScopeImpl() } - Scope() { range = toGenerated(this) } + /** Gets a variable declared in this scope. */ + Variable getAVariable() { result = super.getAVariableImpl() } - /** Gets the scope in which this scope is nested, if any. */ - Scope getOuterScope() { toGenerated(result) = range.getOuterScope() } - - /** Gets a variable that is declared in this scope. */ - final Variable getAVariable() { result.getDeclaringScope() = this } - - /** Gets the variable declared in this scope with the given name, if any. */ - final Variable getVariable(string name) { - result = this.getAVariable() and - result.getName() = name - } + /** Gets the variable named `name` declared in this scope. */ + Variable getVariable(string name) { result = super.getVariableImpl(name) } } +/** A scope in which a `self` variable exists. */ class SelfScope extends Scope, TSelfScopeType { } diff --git a/ruby/ql/lib/codeql/ruby/ast/Variable.qll b/ruby/ql/lib/codeql/ruby/ast/Variable.qll index 12be2f99f5b2..1aa63938dbe5 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Variable.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Variable.qll @@ -5,6 +5,7 @@ private import codeql.Locations private import internal.AST private import internal.TreeSitter private import internal.Variable +private import internal.Parameter /** A variable declared in a scope. */ class Variable instanceof VariableImpl { @@ -50,7 +51,7 @@ class LocalVariable extends Variable, TLocalVariable { * * `x` is a captured variable, whereas `y` is not. */ - predicate isCaptured() { this.getAnAccess().isCapturedAccess() } + final predicate isCaptured() { this.getAnAccess().isCapturedAccess() } } /** A global variable. */ @@ -110,7 +111,11 @@ class VariableAccess extends Expr instanceof VariableAccessImpl { * the access to `elements` in the parameter list is an implicit assignment, * as is the first access to `e`. */ - predicate isImplicitWrite() { implicitWriteAccess(toGenerated(this)) } + predicate isImplicitWrite() { + implicitWriteAccess(toGenerated(this)) + or + this = any(SimpleParameterSynthImpl p).getDefininingAccess() + } final override string toString() { result = VariableAccessImpl.super.toString() } } @@ -147,7 +152,7 @@ class LocalVariableAccess extends VariableAccess instanceof LocalVariableAccessI * the access to `x` in the first `puts x` is a captured access, while * the access to `x` in the second `puts x` is not. */ - predicate isCapturedAccess() { isCapturedAccess(this) } + final predicate isCapturedAccess() { isCapturedAccess(this) } } /** An access to a local variable where the value is updated. */ @@ -195,10 +200,4 @@ class SelfVariableAccess extends LocalVariableAccess instanceof SelfVariableAcce } /** An access to the `self` variable where the value is read. */ -class SelfVariableReadAccess extends SelfVariableAccess, VariableReadAccess { - // We override the definition in `LocalVariableAccess` because it gives the - // wrong result for synthesised `self` variables. - override predicate isCapturedAccess() { - this.getVariable().getDeclaringScope() != this.getCfgScope() - } -} +class SelfVariableReadAccess extends SelfVariableAccess, VariableReadAccess { } diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll b/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll index 349b28474baa..0000570e57e9 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/AST.qll @@ -93,7 +93,8 @@ private module Cached { } or TBlockArgument(Ruby::BlockArgument g) or TBlockParameter(Ruby::BlockParameter g) or - TBraceBlock(Ruby::Block g) { not g.getParent() instanceof Ruby::Lambda } or + TBraceBlockSynth(AST::AstNode parent, int i) { mkSynthChild(BraceBlockKind(), parent, i) } or + TBraceBlockReal(Ruby::Block g) { not g.getParent() instanceof Ruby::Lambda } or TBreakStmt(Ruby::Break g) or TCaseEqExpr(Ruby::Binary g) { g instanceof @ruby_binary_equalequalequal } or TCaseExpr(Ruby::Case g) or @@ -131,7 +132,6 @@ private module Cached { TFalseLiteral(Ruby::False g) or TFloatLiteral(Ruby::Float g) { not any(Ruby::Rational r).getChild() = g } or TForExpr(Ruby::For g) or - TForIn(Ruby::In g) or // TODO REMOVE TForwardParameter(Ruby::ForwardParameter g) or TForwardArgument(Ruby::ForwardArgument g) or TGEExpr(Ruby::Binary g) { g instanceof @ruby_binary_rangleequal } or @@ -238,7 +238,10 @@ private module Cached { TSelfSynth(AST::AstNode parent, int i, AST::SelfVariable v) { mkSynthChild(SelfKind(v), parent, i) } or - TSimpleParameter(Ruby::Identifier g) { g instanceof Parameter::Range } or + TSimpleParameterReal(Ruby::Identifier g) { g instanceof Parameter::Range } or + TSimpleParameterSynth(AST::AstNode parent, int i) { + mkSynthChild(SimpleParameterKind(), parent, i) + } or TSimpleSymbolLiteral(Ruby::SimpleSymbol g) or TSingletonClass(Ruby::SingletonClass g) or TSingletonMethod(Ruby::SingletonMethod g) or @@ -291,12 +294,12 @@ private module Cached { TAssignModuloExpr or TAssignMulExpr or TAssignRShiftExpr or TAssignSubExpr or TBareStringLiteral or TBareSymbolLiteral or TBeginBlock or TBeginExpr or TBitwiseAndExprReal or TBitwiseOrExprReal or TBitwiseXorExprReal or TBlockArgument or - TBlockParameter or TBraceBlock or TBreakStmt or TCaseEqExpr or TCaseExpr or + TBlockParameter or TBraceBlockReal or TBreakStmt or TCaseEqExpr or TCaseExpr or TCharacterLiteral or TClassDeclaration or TClassVariableAccessReal or TComplementExpr or TComplexLiteral or TDefinedExpr or TDelimitedSymbolLiteral or TDestructuredLeftAssignment or TDivExprReal or TDo or TDoBlock or TElementReference or TElse or TElsif or TEmptyStmt or TEndBlock or TEnsure or TEqExpr or TExponentExprReal or TFalseLiteral or TFloatLiteral or - TForExpr or TForIn or TForwardParameter or TForwardArgument or TGEExpr or TGTExpr or + TForExpr or TForwardParameter or TForwardArgument or TGEExpr or TGTExpr or TGlobalVariableAccessReal or THashKeySymbolLiteral or THashLiteral or THashSplatExpr or THashSplatParameter or THereDoc or TIdentifierMethodCall or TIf or TIfModifierExpr or TInstanceVariableAccessReal or TIntegerLiteralReal or TKeywordParameter or TLEExpr or @@ -308,7 +311,7 @@ private module Cached { TRegExpMatchExpr or TRegularArrayLiteral or TRegularMethodCall or TRegularStringLiteral or TRegularSuperCall or TRescueClause or TRescueModifierExpr or TRetryStmt or TReturnStmt or TScopeResolutionConstantAccess or TScopeResolutionMethodCall or TSelfReal or - TSimpleParameter or TSimpleSymbolLiteral or TSingletonClass or TSingletonMethod or + TSimpleParameterReal or TSimpleSymbolLiteral or TSingletonClass or TSingletonMethod or TSpaceshipExpr or TSplatExprReal or TSplatParameter or TStringArrayLiteral or TStringConcatenation or TStringEscapeSequenceComponent or TStringInterpolationComponent or TStringTextComponent or TSubExprReal or TSubshellLiteral or TSymbolArrayLiteral or @@ -319,12 +322,13 @@ private module Cached { class TAstNodeSynth = TAddExprSynth or TAssignExprSynth or TBitwiseAndExprSynth or TBitwiseOrExprSynth or - TBitwiseXorExprSynth or TClassVariableAccessSynth or TConstantReadAccessSynth or - TDivExprSynth or TExponentExprSynth or TGlobalVariableAccessSynth or - TInstanceVariableAccessSynth or TIntegerLiteralSynth or TLShiftExprSynth or - TLocalVariableAccessSynth or TLogicalAndExprSynth or TLogicalOrExprSynth or - TMethodCallSynth or TModuloExprSynth or TMulExprSynth or TRShiftExprSynth or - TRangeLiteralSynth or TSelfSynth or TSplatExprSynth or TStmtSequenceSynth or TSubExprSynth; + TBitwiseXorExprSynth or TBraceBlockSynth or TClassVariableAccessSynth or + TConstantReadAccessSynth or TDivExprSynth or TExponentExprSynth or + TGlobalVariableAccessSynth or TInstanceVariableAccessSynth or TIntegerLiteralSynth or + TLShiftExprSynth or TLocalVariableAccessSynth or TLogicalAndExprSynth or + TLogicalOrExprSynth or TMethodCallSynth or TModuloExprSynth or TMulExprSynth or + TRShiftExprSynth or TRangeLiteralSynth or TSelfSynth or TSimpleParameterSynth or + TSplatExprSynth or TStmtSequenceSynth or TSubExprSynth; /** * Gets the underlying TreeSitter entity for a given AST node. This does not @@ -359,7 +363,7 @@ private module Cached { n = TBitwiseXorExprReal(result) or n = TBlockArgument(result) or n = TBlockParameter(result) or - n = TBraceBlock(result) or + n = TBraceBlockReal(result) or n = TBreakStmt(result) or n = TCaseEqExpr(result) or n = TCaseExpr(result) or @@ -385,7 +389,6 @@ private module Cached { n = TFalseLiteral(result) or n = TFloatLiteral(result) or n = TForExpr(result) or - n = TForIn(result) or // TODO REMOVE n = TForwardArgument(result) or n = TForwardParameter(result) or n = TGEExpr(result) or @@ -439,7 +442,7 @@ private module Cached { n = TScopeResolutionConstantAccess(result, _) or n = TScopeResolutionMethodCall(result, _) or n = TSelfReal(result) or - n = TSimpleParameter(result) or + n = TSimpleParameterReal(result) or n = TSimpleSymbolLiteral(result) or n = TSingletonClass(result) or n = TSingletonMethod(result) or @@ -488,6 +491,8 @@ private module Cached { or result = TBitwiseXorExprSynth(parent, i) or + result = TBraceBlockSynth(parent, i) + or result = TClassVariableAccessSynth(parent, i, _) or result = TConstantReadAccessSynth(parent, i, _) @@ -522,6 +527,8 @@ private module Cached { or result = TSelfSynth(parent, i, _) or + result = TSimpleParameterSynth(parent, i) + or result = TSplatExprSynth(parent, i) or result = TStmtSequenceSynth(parent, i) @@ -639,6 +646,8 @@ class TCallable = TMethodBase or TLambda or TBlock; class TMethodBase = TMethod or TSingletonMethod; +class TBraceBlock = TBraceBlockReal or TBraceBlockSynth; + class TBlock = TDoBlock or TBraceBlock; class TModuleBase = TToplevel or TNamespace or TSingletonClass; @@ -730,6 +739,8 @@ class TParameter = TPatternParameter or TBlockParameter or THashSplatParameter or TKeywordParameter or TOptionalParameter or TSplatParameter or TForwardParameter; +class TSimpleParameter = TSimpleParameterReal or TSimpleParameterSynth; + class TPatternParameter = TSimpleParameter or TTuplePatternParameter; class TNamedParameter = diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Call.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Call.qll index eea4392a4fb4..58e9f912091a 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Call.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Call.qll @@ -50,7 +50,7 @@ class MethodCallSynth extends MethodCallImpl, TMethodCallSynth { final override int getNumberOfArgumentsImpl() { this = TMethodCallSynth(_, _, _, _, result) } - final override Block getBlockImpl() { none() } + final override Block getBlockImpl() { synthChild(this, -2, result) } } class IdentifierMethodCall extends MethodCallImpl, TIdentifierMethodCall { diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Expr.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Expr.qll new file mode 100644 index 000000000000..4aa4dd4b79cf --- /dev/null +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Expr.qll @@ -0,0 +1,75 @@ +private import codeql.ruby.AST +private import codeql.ruby.CFG +private import AST +private import TreeSitter + +class StmtSequenceSynth extends StmtSequence, TStmtSequenceSynth { + final override Stmt getStmt(int n) { synthChild(this, n, result) } + + final override string toString() { result = "..." } +} + +class Then extends StmtSequence, TThen { + private Ruby::Then g; + + Then() { this = TThen(g) } + + override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } + + final override string toString() { result = "then ..." } +} + +class Else extends StmtSequence, TElse { + private Ruby::Else g; + + Else() { this = TElse(g) } + + override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } + + final override string toString() { result = "else ..." } +} + +class Do extends StmtSequence, TDo { + private Ruby::Do g; + + Do() { this = TDo(g) } + + override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } + + final override string toString() { result = "do ..." } +} + +class Ensure extends StmtSequence, TEnsure { + private Ruby::Ensure g; + + Ensure() { this = TEnsure(g) } + + override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) } + + final override string toString() { result = "ensure ..." } +} + +// Not defined by dispatch, as it should not be exposed +Ruby::AstNode getBodyStmtChild(TBodyStmt b, int i) { + result = any(Ruby::Method g | b = TMethod(g)).getChild(i) + or + result = any(Ruby::SingletonMethod g | b = TSingletonMethod(g)).getChild(i) + or + exists(Ruby::Lambda g | b = TLambda(g) | + result = g.getBody().(Ruby::DoBlock).getChild(i) or + result = g.getBody().(Ruby::Block).getChild(i) + ) + or + result = any(Ruby::DoBlock g | b = TDoBlock(g)).getChild(i) + or + result = any(Ruby::Program g | b = TToplevel(g)).getChild(i) and + not result instanceof Ruby::BeginBlock + or + result = any(Ruby::Class g | b = TClassDeclaration(g)).getChild(i) + or + result = any(Ruby::SingletonClass g | b = TSingletonClass(g)).getChild(i) + or + result = any(Ruby::Module g | b = TModuleDeclaration(g)).getChild(i) + or + result = any(Ruby::Begin g | b = TBeginExpr(g)).getChild(i) +} diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Method.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Method.qll new file mode 100644 index 000000000000..09a16350096e --- /dev/null +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Method.qll @@ -0,0 +1,28 @@ +private import codeql.ruby.AST +private import AST +private import TreeSitter + +class BraceBlockReal extends BraceBlock, TBraceBlockReal { + private Ruby::Block g; + + BraceBlockReal() { this = TBraceBlockReal(g) } + + final override Parameter getParameter(int n) { + toGenerated(result) = g.getParameters().getChild(n) + } + + final override Stmt getStmt(int i) { toGenerated(result) = g.getChild(i) } +} + +/** + * A synthesized block, such as the block synthesized from the body of + * a `for` loop. + */ +class BraceBlockSynth extends BraceBlock, TBraceBlockSynth { + final override Parameter getParameter(int n) { synthChild(this, n, result) } + + final override Stmt getStmt(int i) { + i >= 0 and + synthChild(this, i + this.getNumberOfParameters(), result) + } +} diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Parameter.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Parameter.qll index f888d89c1ace..b1312b4d1dfb 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Parameter.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Parameter.qll @@ -1,6 +1,7 @@ private import codeql.ruby.AST private import AST private import TreeSitter +private import Variable module Parameter { class Range extends Ruby::AstNode { @@ -17,3 +18,29 @@ module Parameter { int getPosition() { result = pos } } } + +abstract class SimpleParameterImpl extends AstNode, TSimpleParameter { + abstract LocalVariable getVariableImpl(); + + abstract string getNameImpl(); +} + +class SimpleParameterRealImpl extends SimpleParameterImpl, TSimpleParameterReal { + private Ruby::Identifier g; + + SimpleParameterRealImpl() { this = TSimpleParameterReal(g) } + + override LocalVariable getVariableImpl() { result = TLocalVariableReal(_, _, g) } + + override string getNameImpl() { result = g.getValue() } +} + +class SimpleParameterSynthImpl extends SimpleParameterImpl, TSimpleParameterSynth { + SimpleParameterSynthImpl() { this = TSimpleParameterSynth(_, _) } + + LocalVariableAccessSynth getDefininingAccess() { synthChild(this, 0, result) } + + override LocalVariable getVariableImpl() { result = TLocalVariableSynth(this, _) } + + override string getNameImpl() { result = this.getVariableImpl().getName() } +} diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Scope.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Scope.qll index cab6a7ad3b16..b07e05ac2b25 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Scope.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Scope.qll @@ -1,7 +1,9 @@ private import TreeSitter +private import codeql.ruby.AST private import codeql.ruby.ast.Scope private import codeql.ruby.ast.internal.AST private import codeql.ruby.ast.internal.Parameter +private import codeql.ruby.ast.internal.Variable class TScopeType = TMethodBase or TModuleLike or TBlockLike; @@ -15,6 +17,8 @@ private class TBlockLike = TDoBlock or TLambda or TBlock or TEndBlock; private class TModuleLike = TToplevel or TModuleDeclaration or TClassDeclaration or TSingletonClass; +private class TScopeReal = TMethodBase or TModuleLike or TDoBlock or TLambda or TBraceBlock; + module Scope { class TypeRange = Callable::TypeRange or ModuleBase::TypeRange or @ruby_end_block; @@ -102,29 +106,105 @@ Ruby::HeredocBody getHereDocBody(Ruby::HeredocBeginning g) { ) } +private Ruby::AstNode specialParentOf(Ruby::AstNode n) { + n = + [ + result.(Ruby::Module).getName(), result.(Ruby::Class).getName(), + result.(Ruby::Class).getSuperclass(), result.(Ruby::SingletonClass).getValue(), + result.(Ruby::Method).getName(), result.(Ruby::SingletonMethod).getName(), + result.(Ruby::SingletonMethod).getObject() + ] +} + private Ruby::AstNode parentOf(Ruby::AstNode n) { n = getHereDocBody(result) or - exists(Ruby::AstNode parent | parent = n.getParent() | - if - n = - [ - parent.(Ruby::Module).getName(), parent.(Ruby::Class).getName(), - parent.(Ruby::Class).getSuperclass(), parent.(Ruby::SingletonClass).getValue(), - parent.(Ruby::Method).getName(), parent.(Ruby::SingletonMethod).getName(), - parent.(Ruby::SingletonMethod).getObject() - ] - then result = parent.getParent() - else result = parent - ) + result = specialParentOf(n).getParent() + or + not exists(specialParentOf(n)) and + result = n.getParent() } -/** Gets the enclosing scope of a node */ -cached -Scope::Range scopeOf(Ruby::AstNode n) { - exists(Ruby::AstNode p | p = parentOf(n) | - p = result +private AstNode specialParentOfInclSynth(AstNode n) { + n = + [ + result.(Namespace).getScopeExpr(), result.(ClassDeclaration).getSuperclassExpr(), + result.(SingletonMethod).getObject() + ] +} + +private AstNode parentOfInclSynth(AstNode n) { + ( + result = specialParentOfInclSynth(n).getParent() or - not p instanceof Scope::Range and result = scopeOf(p) - ) + not exists(specialParentOfInclSynth(n)) and + result = n.getParent() + ) and + (synthChild(_, _, n) implies synthChild(result, _, n)) +} + +cached +private module Cached { + /** Gets the enclosing scope of a node */ + cached + Scope::Range scopeOf(Ruby::AstNode n) { + exists(Ruby::AstNode p | p = parentOf(n) | + p = result + or + not p instanceof Scope::Range and result = scopeOf(p) + ) + } + + /** + * Gets the enclosing scope of a node. Unlike `scopeOf`, this predicate + * operates on the external AST API, and therefore takes synthesized nodes + * and synthesized scopes into account. + */ + cached + Scope scopeOfInclSynth(AstNode n) { + exists(AstNode p | p = parentOfInclSynth(n) | + p = result + or + not p instanceof Scope and result = scopeOfInclSynth(p) + ) + } +} + +import Cached + +abstract class ScopeImpl extends AstNode, TScopeType { + final Scope getOuterScopeImpl() { result = scopeOfInclSynth(this) } + + abstract Variable getAVariableImpl(); + + final Variable getVariableImpl(string name) { + result = this.getAVariableImpl() and + result.getName() = name + } +} + +private class ScopeRealImpl extends ScopeImpl, TScopeReal { + private Scope::Range range; + + ScopeRealImpl() { range = toGenerated(this) } + + override Variable getAVariableImpl() { result.getDeclaringScope() = this } +} + +// We desugar for loops by implementing them as calls to `each` with a block +// argument. Though this is how the desugaring is described in the MRI parser, +// in practice there is not a real nested scope created, so variables that +// may appear to be local to the loop body (e.g. the iteration variable) are +// scoped to the outer scope rather than the loop body. +private class ScopeSynthImpl extends ScopeImpl, TBraceBlockSynth { + ScopeSynthImpl() { this = TBraceBlockSynth(_, _) } + + override Variable getAVariableImpl() { + // Synthesized variables introduced as parameters to this scope + // As this variable is also synthetic, it is genuinely local to this scope. + exists(SimpleParameterSynthImpl p | + p = TSimpleParameterSynth(this, _) and + p.getVariableImpl() = result + ) + } } diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll index 6683d025536e..1afef58cd49c 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll @@ -3,6 +3,7 @@ private import AST private import TreeSitter private import codeql.ruby.ast.internal.Call +private import codeql.ruby.ast.internal.Expr private import codeql.ruby.ast.internal.Variable private import codeql.ruby.ast.internal.Pattern private import codeql.ruby.ast.internal.Scope @@ -15,6 +16,7 @@ newtype SynthKind = BitwiseAndExprKind() or BitwiseOrExprKind() or BitwiseXorExprKind() or + BraceBlockKind() or ClassVariableAccessKind(ClassVariable v) or DivExprKind() or ExponentExprKind() or @@ -33,6 +35,7 @@ newtype SynthKind = MulExprKind() or RangeLiteralKind(boolean inclusive) { inclusive in [false, true] } or RShiftExprKind() or + SimpleParameterKind() or SplatExprKind() or StmtSequenceKind() or SelfKind(SelfVariable v) or @@ -814,3 +817,94 @@ private module ArrayLiteralDesugar { final override predicate constantReadAccess(string name) { name = "::Array" } } } + +/** + * ```rb + * for x in xs + * + * end + * ``` + * desugars to, roughly, + * ```rb + * xs.each { |__synth__0| x = __synth__0; } + * ``` + * + * Note that for-loops, unlike blocks, do not create a new variable scope, so + * variables within this block inherit the enclosing scope. The exception to + * this is the synthesized variable declared by the block parameter, which is + * scoped to the synthesized block. + */ +private module ForLoopDesugar { + pragma[nomagic] + private predicate forLoopSynthesis(AstNode parent, int i, Child child) { + exists(ForExpr for | + // each call + parent = for and + i = -1 and + child = SynthChild(MethodCallKind("each", false, 0)) + or + exists(MethodCall eachCall | eachCall = TMethodCallSynth(for, -1, "each", false, 0) | + // receiver + parent = eachCall and + i = 0 and + child = childRef(for.getValue()) // value is the Enumerable + or + parent = eachCall and + i = -2 and + child = SynthChild(BraceBlockKind()) + or + exists(Block block | block = TBraceBlockSynth(eachCall, -2) | + // block params + parent = block and + i = 0 and + child = SynthChild(SimpleParameterKind()) + or + exists(SimpleParameter param | param = TSimpleParameterSynth(block, 0) | + parent = param and + i = 0 and + child = SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(param, 0))) + or + // assignment to pattern from for loop to synth parameter + parent = block and + i = 1 and + child = SynthChild(AssignExprKind()) + or + parent = TAssignExprSynth(block, 1) and + ( + i = 0 and + child = childRef(for.getPattern()) + or + i = 1 and + child = SynthChild(LocalVariableAccessSynthKind(TLocalVariableSynth(param, 0))) + ) + ) + or + // rest of block body + parent = block and + child = childRef(for.getBody().(Do).getStmt(i - 2)) + ) + ) + ) + } + + private class ForLoopSynthesis extends Synthesis { + final override predicate child(AstNode parent, int i, Child child) { + forLoopSynthesis(parent, i, child) + } + + final override predicate methodCall(string name, boolean setter, int arity) { + name = "each" and + setter = false and + arity = 0 + } + + final override predicate localVariable(AstNode n, int i) { + n instanceof TSimpleParameterSynth and + i = 0 + } + + final override predicate excludeFromControlFlowTree(AstNode n) { + n = any(ForExpr for).getBody() + } + } +} diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Variable.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Variable.qll index ebe88f13107a..ea7d7393b380 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Variable.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Variable.qll @@ -327,7 +327,7 @@ private module Cached { cached predicate isCapturedAccess(LocalVariableAccess access) { - toGenerated(access.getVariable().getDeclaringScope()) != scopeOf(toGenerated(access)) + access.getVariable().getDeclaringScope() != access.getCfgScope() } cached @@ -524,7 +524,7 @@ private class LocalVariableAccessReal extends LocalVariableAccessImpl, TLocalVar final override string toString() { result = g.getValue() } } -private class LocalVariableAccessSynth extends LocalVariableAccessImpl, TLocalVariableAccessSynth { +class LocalVariableAccessSynth extends LocalVariableAccessImpl, TLocalVariableAccessSynth { private LocalVariable v; LocalVariableAccessSynth() { this = TLocalVariableAccessSynth(_, _, v) } diff --git a/ruby/ql/lib/codeql/ruby/controlflow/ControlFlowGraph.qll b/ruby/ql/lib/codeql/ruby/controlflow/ControlFlowGraph.qll index 4b2785265cff..67f08c4da5ed 100644 --- a/ruby/ql/lib/codeql/ruby/controlflow/ControlFlowGraph.qll +++ b/ruby/ql/lib/codeql/ruby/controlflow/ControlFlowGraph.qll @@ -27,7 +27,7 @@ class CfgScope extends Scope instanceof CfgScope::Range_ { * * Only nodes that can be reached from an entry point are included in the CFG. */ -class CfgNode extends TNode { +class CfgNode extends TCfgNode { /** Gets a textual representation of this control flow node. */ string toString() { none() } diff --git a/ruby/ql/lib/codeql/ruby/controlflow/internal/Completion.qll b/ruby/ql/lib/codeql/ruby/controlflow/internal/Completion.qll index e7f64d1318e6..3cb5e2a9dcc8 100644 --- a/ruby/ql/lib/codeql/ruby/controlflow/internal/Completion.qll +++ b/ruby/ql/lib/codeql/ruby/controlflow/internal/Completion.qll @@ -14,7 +14,6 @@ private import SuccessorTypes private newtype TCompletion = TSimpleCompletion() or TBooleanCompletion(boolean b) { b in [false, true] } or - TEmptinessCompletion(boolean isEmpty) { isEmpty in [false, true] } or TMatchingCompletion(boolean isMatch) { isMatch in [false, true] } or TReturnCompletion() or TBreakCompletion() or @@ -54,9 +53,6 @@ private predicate nestedEnsureCompletion(Completion outer, int nestLevel) { pragma[noinline] private predicate completionIsValidForStmt(AstNode n, Completion c) { - n = TForIn(_) and - c instanceof EmptinessCompletion - or n instanceof BreakStmt and c = TBreakCompletion() or @@ -242,8 +238,8 @@ class SimpleCompletion extends NonNestedNormalCompletion, TSimpleCompletion { /** * A completion that represents evaluation of an expression, whose value determines - * the successor. Either a Boolean completion (`BooleanCompletion`), an emptiness - * completion (`EmptinessCompletion`), or a matching completion (`MatchingCompletion`). + * the successor. Either a Boolean completion (`BooleanCompletion`), or a matching + * completion (`MatchingCompletion`). */ abstract class ConditionalCompletion extends NonNestedNormalCompletion { boolean value; @@ -280,18 +276,6 @@ class FalseCompletion extends BooleanCompletion { FalseCompletion() { this.getValue() = false } } -/** - * A completion that represents evaluation of an emptiness test, for example - * a test in a `for in` statement. - */ -class EmptinessCompletion extends ConditionalCompletion, TEmptinessCompletion { - EmptinessCompletion() { this = TEmptinessCompletion(value) } - - override EmptinessSuccessor getAMatchingSuccessorType() { result.getValue() = value } - - override string toString() { if value = true then result = "empty" else result = "non-empty" } -} - /** * A completion that represents evaluation of a matching test, for example * a test in a `rescue` statement. diff --git a/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll b/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll index 198329eff1e0..702266302c66 100644 --- a/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll +++ b/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll @@ -61,6 +61,9 @@ module CfgScope { final override predicate exit(AstNode last, Completion c) { last(this.(Trees::EndBlockTree).getLastBodyChild(), last, c) + or + last(this.(Trees::EndBlockTree).getBodyChild(_, _), last, c) and + not c instanceof NormalCompletion } } @@ -79,6 +82,9 @@ module CfgScope { final override predicate exit(AstNode last, Completion c) { last(this.(Trees::BraceBlockTree).getLastBodyChild(), last, c) + or + last(this.(Trees::BraceBlockTree).getBodyChild(_, _), last, c) and + not c instanceof NormalCompletion } } } @@ -91,25 +97,6 @@ predicate succEntry(CfgScope::Range_ scope, AstNode first) { scope.entry(first) pragma[nomagic] predicate succExit(CfgScope::Range_ scope, AstNode last, Completion c) { scope.exit(last, c) } -// TODO: remove this class; it should be replaced with an implicit non AST node -private class ForIn extends AstNode, ASTInternal::TForIn { - final override string toString() { result = "In" } -} - -// TODO: remove this class; it should be replaced with an implicit non AST node -private class ForRange extends ForExpr { - override AstNode getAChild(string pred) { - result = super.getAChild(pred) - or - pred = "" and - result = this.getIn() - } - - ForIn getIn() { - result = ASTInternal::TForIn(ASTInternal::toGenerated(this).(Ruby::For).getValue()) - } -} - /** Defines the CFG by dispatch on the various AST types. */ module Trees { private class AliasStmtTree extends StandardPreOrderTree, AliasStmt { @@ -610,89 +597,6 @@ module Trees { private class ForwardParameterTree extends LeafTree, ForwardParameter { } - private class ForInTree extends LeafTree, ForIn { } - - /** - * Control flow of a for-in loop - * - * For example, this program fragment: - * - * ```rb - * for arg in args do - * puts arg - * end - * puts "done"; - * ``` - * - * has the following control flow graph: - * - * ``` - * args - * | - * in------<----- - * / \ \ - * / \ | - * / \ | - * / \ | - * empty non-empty | - * | \ | - * for \ | - * | arg | - * | | | - * puts "done" puts arg | - * \___/ - * ``` - */ - private class ForTree extends PostOrderTree, ForRange { - final override predicate propagatesAbnormal(AstNode child) { - child = this.getPattern() or child = this.getValue() - } - - final override predicate first(AstNode first) { first(this.getValue(), first) } - - /** - * for pattern in array do body end - * ``` - * array +-> in +--[non empty]--> pattern -> body -> in - * |--[empty]--> for - * ``` - */ - final override predicate succ(AstNode pred, AstNode succ, Completion c) { - last(this.getValue(), pred, c) and - first(this.getIn(), succ) and - c instanceof SimpleCompletion - or - last(this.getIn(), pred, c) and - first(this.getPattern(), succ) and - c.(EmptinessCompletion).getValue() = false - or - last(this.getPattern(), pred, c) and - first(this.getBody(), succ) and - c instanceof NormalCompletion - or - last(this.getBody(), pred, c) and - first(this.getIn(), succ) and - c.continuesLoop() - or - last(this.getBody(), pred, c) and - first(this.getBody(), succ) and - c instanceof RedoCompletion - or - succ = this and - ( - last(this.getIn(), pred, c) and - c.(EmptinessCompletion).getValue() = true - or - last(this.getBody(), pred, c) and - not c.continuesLoop() and - not c instanceof BreakCompletion and - not c instanceof RedoCompletion - or - last(this.getBody(), pred, c.(NestedBreakCompletion).getAnInnerCompatibleCompletion()) - ) - } - } - private class GlobalVariableTree extends LeafTree, GlobalVariableAccess { } private class HashLiteralTree extends StandardPostOrderTree, HashLiteral { @@ -1137,6 +1041,9 @@ private Scope parent(Scope n) { not n instanceof CfgScope::Range_ } +cached +private CfgScope getCfgScopeImpl(AstNode n) { result = parent*(scopeOfInclSynth(n)) } + /** Gets the CFG scope of node `n`. */ pragma[inline] CfgScope getCfgScope(AstNode n) { @@ -1148,13 +1055,6 @@ CfgScope getCfgScope(AstNode n) { cached private module Cached { - /** Gets the CFG scope of node `n`. */ - cached - CfgScope getCfgScopeImpl(AstNode n) { - forceCachingInSameStage() and - result = parent*(ASTInternal::fromGenerated(scopeOf(ASTInternal::toGeneratedInclSynth(n)))) - } - cached newtype TSuccessorType = TSuccessorSuccessor() or diff --git a/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll b/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll index ee901b9192ec..85c9e0b4f0b9 100644 --- a/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll +++ b/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll @@ -788,7 +788,7 @@ private module Cached { * The control flow graph is pruned for unreachable nodes. */ cached - newtype TNode = + newtype TCfgNode = TEntryNode(CfgScope scope) { succEntrySplits(scope, _, _, _) } or TAnnotatedExitNode(CfgScope scope, boolean normal) { exists(Reachability::SameSplitsBlock b, SuccessorType t | b.isReachable(_) | @@ -807,7 +807,7 @@ private module Cached { /** Gets a successor node of a given flow type, if any. */ cached - TNode getASuccessor(TNode pred, SuccessorType t) { + TCfgNode getASuccessor(TCfgNode pred, SuccessorType t) { // Callable entry node -> callable body exists(ControlFlowElement succElement, Splits succSplits, CfgScope scope | result = TElementNode(succElement, succSplits) and diff --git a/ruby/ql/test/library-tests/ast/Ast.expected b/ruby/ql/test/library-tests/ast/Ast.expected index c03b34dac99f..dea0f55b2bb2 100644 --- a/ruby/ql/test/library-tests/ast/Ast.expected +++ b/ruby/ql/test/library-tests/ast/Ast.expected @@ -365,7 +365,6 @@ calls/calls.rb: # 223| getReceiver: [ConstantReadAccess] X # 226| getStmt: [ForExpr] for ... in ... # 226| getPattern: [LocalVariableAccess] x -# 226| : [???] In # 226| getValue: [MethodCall] call to bar # 226| getReceiver: [Self, SelfVariableAccess] self # 226| getBody: [StmtSequence] do ... @@ -373,7 +372,6 @@ calls/calls.rb: # 227| getReceiver: [Self, SelfVariableAccess] self # 229| getStmt: [ForExpr] for ... in ... # 229| getPattern: [LocalVariableAccess] x -# 229| : [???] In # 229| getValue: [MethodCall] call to bar # 229| getReceiver: [ConstantReadAccess] X # 229| getBody: [StmtSequence] do ... @@ -655,6 +653,26 @@ calls/calls.rb: # 336| getReceiver: [Self, SelfVariableAccess] self # 336| getArgument: [LocalVariableAccess] b # 336| getArgument: [ForwardedArguments] ... +# 340| getStmt: [ForExpr] for ... in ... +# 340| getPattern: [TuplePattern] (..., ...) +# 340| getElement: [LocalVariableAccess] x +# 340| getElement: [LocalVariableAccess] y +# 340| getElement: [LocalVariableAccess] z +# 340| getValue: [ArrayLiteral] [...] +# 340| getElement: [ArrayLiteral] [...] +# 340| getElement: [IntegerLiteral] 1 +# 340| getElement: [IntegerLiteral] 2 +# 340| getElement: [IntegerLiteral] 3 +# 340| getElement: [ArrayLiteral] [...] +# 340| getElement: [IntegerLiteral] 4 +# 340| getElement: [IntegerLiteral] 5 +# 340| getElement: [IntegerLiteral] 6 +# 340| getBody: [StmtSequence] do ... +# 341| getStmt: [MethodCall] call to foo +# 341| getReceiver: [Self, SelfVariableAccess] self +# 341| getArgument: [LocalVariableAccess] x +# 341| getArgument: [LocalVariableAccess] y +# 341| getArgument: [LocalVariableAccess] z control/cases.rb: # 1| [Toplevel] cases.rb # 2| getStmt: [AssignExpr] ... = ... @@ -1422,7 +1440,6 @@ control/loops.rb: # 6| getAnOperand/getRightOperand: [IntegerLiteral] 0 # 9| getStmt: [ForExpr] for ... in ... # 9| getPattern: [LocalVariableAccess] n -# 9| : [???] In # 9| getValue: [RangeLiteral] _ .. _ # 9| getBegin: [IntegerLiteral] 1 # 9| getEnd: [IntegerLiteral] 10 @@ -1435,7 +1452,6 @@ control/loops.rb: # 11| getAnOperand/getRightOperand: [LocalVariableAccess] n # 16| getStmt: [ForExpr] for ... in ... # 16| getPattern: [LocalVariableAccess] n -# 16| : [???] In # 16| getValue: [RangeLiteral] _ .. _ # 16| getBegin: [IntegerLiteral] 1 # 16| getEnd: [IntegerLiteral] 10 @@ -1450,7 +1466,6 @@ control/loops.rb: # 22| getPattern: [TuplePattern] (..., ...) # 22| getElement: [LocalVariableAccess] key # 22| getElement: [LocalVariableAccess] value -# 22| : [???] In # 22| getValue: [HashLiteral] {...} # 22| getElement: [Pair] Pair # 22| getKey: [SymbolLiteral] :foo @@ -1469,7 +1484,6 @@ control/loops.rb: # 28| getPattern: [TuplePattern] (..., ...) # 28| getElement: [LocalVariableAccess] key # 28| getElement: [LocalVariableAccess] value -# 28| : [???] In # 28| getValue: [HashLiteral] {...} # 28| getElement: [Pair] Pair # 28| getKey: [SymbolLiteral] :foo @@ -2140,7 +2154,6 @@ erb/template.html.erb: # 25| getAnOperand/getRightOperand: [StringLiteral] "" # 27| getStmt: [ForExpr] for ... in ... # 27| getPattern: [LocalVariableAccess] x -# 27| : [???] In # 27| getValue: [ArrayLiteral] [...] # 27| getElement: [StringLiteral] "foo" # 27| getComponent: [StringTextComponent] foo diff --git a/ruby/ql/test/library-tests/ast/AstDesugar.expected b/ruby/ql/test/library-tests/ast/AstDesugar.expected index dbd8aaad91c9..1fa17e30c4a4 100644 --- a/ruby/ql/test/library-tests/ast/AstDesugar.expected +++ b/ruby/ql/test/library-tests/ast/AstDesugar.expected @@ -23,6 +23,30 @@ calls/calls.rb: # 67| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] var1 # 67| getAnOperand/getArgument/getRightOperand: [MethodCall] call to bar # 67| getReceiver: [ConstantReadAccess] X +# 226| [ForExpr] for ... in ... +# 226| getDesugared: [MethodCall] call to each +# 226| getBlock: [BraceBlock] { ... } +# 226| getParameter: [SimpleParameter] __synth__0__1 +# 226| getDefiningAccess: [LocalVariableAccess] __synth__0__1 +# 226| getStmt: [AssignExpr] ... = ... +# 226| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1 +# 226| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 227| getStmt: [MethodCall] call to baz +# 227| getReceiver: [Self, SelfVariableAccess] self +# 226| getReceiver: [MethodCall] call to bar +# 226| getReceiver: [Self, SelfVariableAccess] self +# 229| [ForExpr] for ... in ... +# 229| getDesugared: [MethodCall] call to each +# 229| getBlock: [BraceBlock] { ... } +# 229| getParameter: [SimpleParameter] __synth__0__1 +# 229| getDefiningAccess: [LocalVariableAccess] __synth__0__1 +# 229| getStmt: [AssignExpr] ... = ... +# 229| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1 +# 229| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 230| getStmt: [MethodCall] call to baz +# 230| getReceiver: [ConstantReadAccess] X +# 229| getReceiver: [MethodCall] call to bar +# 229| getReceiver: [ConstantReadAccess] X # 314| [AssignExpr] ... = ... # 314| getDesugared: [StmtSequence] ... # 314| getStmt: [SetterMethodCall] call to foo= @@ -195,6 +219,53 @@ calls/calls.rb: # 320| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 2 # 320| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__4 # 320| getStmt: [LocalVariableAccess] __synth__4 +# 340| [ForExpr] for ... in ... +# 340| getDesugared: [MethodCall] call to each +# 340| getBlock: [BraceBlock] { ... } +# 340| getParameter: [SimpleParameter] __synth__0__1 +# 340| getDefiningAccess: [LocalVariableAccess] __synth__0__1 +# 340| getStmt: [AssignExpr] ... = ... +# 340| getDesugared: [StmtSequence] ... +# 340| getStmt: [AssignExpr] ... = ... +# 340| getAnOperand/getRightOperand: [SplatExpr] * ... +# 340| getAnOperand/getOperand/getReceiver: [LocalVariableAccess] __synth__0__1 +# 340| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1 +# 340| getStmt: [AssignExpr] ... = ... +# 340| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 340| getAnOperand/getRightOperand: [MethodCall] call to [] +# 340| getArgument: [IntegerLiteral] 0 +# 340| getReceiver: [LocalVariableAccess] __synth__0__1 +# 340| getStmt: [AssignExpr] ... = ... +# 340| getAnOperand/getLeftOperand: [LocalVariableAccess] y +# 340| getAnOperand/getRightOperand: [MethodCall] call to [] +# 340| getArgument: [IntegerLiteral] 1 +# 340| getReceiver: [LocalVariableAccess] __synth__0__1 +# 340| getStmt: [AssignExpr] ... = ... +# 340| getAnOperand/getLeftOperand: [LocalVariableAccess] z +# 340| getAnOperand/getRightOperand: [MethodCall] call to [] +# 340| getArgument: [IntegerLiteral] 2 +# 340| getReceiver: [LocalVariableAccess] __synth__0__1 +# 340| getLeftOperand: [TuplePattern] (..., ...) +# 341| getStmt: [MethodCall] call to foo +# 341| getReceiver: [Self, SelfVariableAccess] self +# 341| getArgument: [LocalVariableAccess] x +# 341| getArgument: [LocalVariableAccess] y +# 341| getArgument: [LocalVariableAccess] z +# 340| getReceiver: [ArrayLiteral] [...] +# 340| getDesugared: [MethodCall] call to [] +# 340| getReceiver: [ConstantReadAccess] Array +# 340| getArgument: [ArrayLiteral] [...] +# 340| getDesugared: [MethodCall] call to [] +# 340| getReceiver: [ConstantReadAccess] Array +# 340| getArgument: [IntegerLiteral] 1 +# 340| getArgument: [IntegerLiteral] 2 +# 340| getArgument: [IntegerLiteral] 3 +# 340| getArgument: [ArrayLiteral] [...] +# 340| getDesugared: [MethodCall] call to [] +# 340| getReceiver: [ConstantReadAccess] Array +# 340| getArgument: [IntegerLiteral] 4 +# 340| getArgument: [IntegerLiteral] 5 +# 340| getArgument: [IntegerLiteral] 6 constants/constants.rb: # 20| [ArrayLiteral] [...] # 20| getDesugared: [MethodCall] call to [] @@ -327,48 +398,132 @@ literals/literals.rb: # 109| getArgument: [SymbolLiteral] :"baz" # 109| getComponent: [StringTextComponent] baz control/loops.rb: -# 10| [AssignAddExpr] ... += ... -# 10| getDesugared: [AssignExpr] ... = ... -# 10| getAnOperand/getLeftOperand: [LocalVariableAccess] sum -# 10| getAnOperand/getRightOperand: [AddExpr] ... + ... -# 10| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] sum -# 10| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] n -# 17| [AssignAddExpr] ... += ... -# 17| getDesugared: [AssignExpr] ... = ... -# 17| getAnOperand/getLeftOperand: [LocalVariableAccess] sum -# 17| getAnOperand/getRightOperand: [AddExpr] ... + ... -# 17| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] sum -# 17| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] n -# 18| [AssignSubExpr] ... -= ... -# 18| getDesugared: [AssignExpr] ... = ... -# 18| getAnOperand/getLeftOperand: [LocalVariableAccess] foo -# 18| getAnOperand/getRightOperand: [SubExpr] ... - ... -# 18| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] foo -# 18| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] n -# 23| [AssignAddExpr] ... += ... -# 23| getDesugared: [AssignExpr] ... = ... -# 23| getAnOperand/getLeftOperand: [LocalVariableAccess] sum -# 23| getAnOperand/getRightOperand: [AddExpr] ... + ... -# 23| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] sum -# 23| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] value -# 24| [AssignMulExpr] ... *= ... -# 24| getDesugared: [AssignExpr] ... = ... -# 24| getAnOperand/getLeftOperand: [LocalVariableAccess] foo -# 24| getAnOperand/getRightOperand: [MulExpr] ... * ... -# 24| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] foo -# 24| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] value -# 29| [AssignAddExpr] ... += ... -# 29| getDesugared: [AssignExpr] ... = ... -# 29| getAnOperand/getLeftOperand: [LocalVariableAccess] sum -# 29| getAnOperand/getRightOperand: [AddExpr] ... + ... -# 29| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] sum -# 29| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] value -# 30| [AssignDivExpr] ... /= ... -# 30| getDesugared: [AssignExpr] ... = ... -# 30| getAnOperand/getLeftOperand: [LocalVariableAccess] foo -# 30| getAnOperand/getRightOperand: [DivExpr] ... / ... -# 30| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] foo -# 30| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] value +# 9| [ForExpr] for ... in ... +# 9| getDesugared: [MethodCall] call to each +# 9| getBlock: [BraceBlock] { ... } +# 9| getParameter: [SimpleParameter] __synth__0__1 +# 9| getDefiningAccess: [LocalVariableAccess] __synth__0__1 +# 9| getStmt: [AssignExpr] ... = ... +# 9| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1 +# 9| getAnOperand/getLeftOperand: [LocalVariableAccess] n +# 10| getStmt: [AssignAddExpr] ... += ... +# 10| getDesugared: [AssignExpr] ... = ... +# 10| getAnOperand/getLeftOperand: [LocalVariableAccess] sum +# 10| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 10| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] sum +# 10| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] n +# 11| getStmt: [AssignExpr] ... = ... +# 11| getAnOperand/getLeftOperand: [LocalVariableAccess] foo +# 11| getAnOperand/getRightOperand: [LocalVariableAccess] n +# 9| getReceiver: [RangeLiteral] _ .. _ +# 9| getBegin: [IntegerLiteral] 1 +# 9| getEnd: [IntegerLiteral] 10 +# 16| [ForExpr] for ... in ... +# 16| getDesugared: [MethodCall] call to each +# 16| getBlock: [BraceBlock] { ... } +# 16| getParameter: [SimpleParameter] __synth__0__1 +# 16| getDefiningAccess: [LocalVariableAccess] __synth__0__1 +# 16| getStmt: [AssignExpr] ... = ... +# 16| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1 +# 16| getAnOperand/getLeftOperand: [LocalVariableAccess] n +# 17| getStmt: [AssignAddExpr] ... += ... +# 17| getDesugared: [AssignExpr] ... = ... +# 17| getAnOperand/getLeftOperand: [LocalVariableAccess] sum +# 17| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 17| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] sum +# 17| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] n +# 18| getStmt: [AssignSubExpr] ... -= ... +# 18| getDesugared: [AssignExpr] ... = ... +# 18| getAnOperand/getLeftOperand: [LocalVariableAccess] foo +# 18| getAnOperand/getRightOperand: [SubExpr] ... - ... +# 18| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] foo +# 18| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] n +# 16| getReceiver: [RangeLiteral] _ .. _ +# 16| getBegin: [IntegerLiteral] 1 +# 16| getEnd: [IntegerLiteral] 10 +# 22| [ForExpr] for ... in ... +# 22| getDesugared: [MethodCall] call to each +# 22| getBlock: [BraceBlock] { ... } +# 22| getParameter: [SimpleParameter] __synth__0__1 +# 22| getDefiningAccess: [LocalVariableAccess] __synth__0__1 +# 22| getStmt: [AssignExpr] ... = ... +# 22| getDesugared: [StmtSequence] ... +# 22| getStmt: [AssignExpr] ... = ... +# 22| getAnOperand/getRightOperand: [SplatExpr] * ... +# 22| getAnOperand/getOperand/getReceiver: [LocalVariableAccess] __synth__0__1 +# 22| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1 +# 22| getStmt: [AssignExpr] ... = ... +# 22| getAnOperand/getLeftOperand: [LocalVariableAccess] key +# 22| getAnOperand/getRightOperand: [MethodCall] call to [] +# 22| getArgument: [IntegerLiteral] 0 +# 22| getReceiver: [LocalVariableAccess] __synth__0__1 +# 22| getStmt: [AssignExpr] ... = ... +# 22| getAnOperand/getLeftOperand: [LocalVariableAccess] value +# 22| getAnOperand/getRightOperand: [MethodCall] call to [] +# 22| getArgument: [IntegerLiteral] 1 +# 22| getReceiver: [LocalVariableAccess] __synth__0__1 +# 22| getLeftOperand: [TuplePattern] (..., ...) +# 23| getStmt: [AssignAddExpr] ... += ... +# 23| getDesugared: [AssignExpr] ... = ... +# 23| getAnOperand/getLeftOperand: [LocalVariableAccess] sum +# 23| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 23| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] sum +# 23| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] value +# 24| getStmt: [AssignMulExpr] ... *= ... +# 24| getDesugared: [AssignExpr] ... = ... +# 24| getAnOperand/getLeftOperand: [LocalVariableAccess] foo +# 24| getAnOperand/getRightOperand: [MulExpr] ... * ... +# 24| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] foo +# 24| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] value +# 22| getReceiver: [HashLiteral] {...} +# 22| getElement: [Pair] Pair +# 22| getKey: [SymbolLiteral] :foo +# 22| getValue: [IntegerLiteral] 0 +# 22| getElement: [Pair] Pair +# 22| getKey: [SymbolLiteral] :bar +# 22| getValue: [IntegerLiteral] 1 +# 28| [ForExpr] for ... in ... +# 28| getDesugared: [MethodCall] call to each +# 28| getBlock: [BraceBlock] { ... } +# 28| getParameter: [SimpleParameter] __synth__0__1 +# 28| getDefiningAccess: [LocalVariableAccess] __synth__0__1 +# 28| getStmt: [AssignExpr] ... = ... +# 28| getDesugared: [StmtSequence] ... +# 28| getStmt: [AssignExpr] ... = ... +# 28| getAnOperand/getRightOperand: [SplatExpr] * ... +# 28| getAnOperand/getOperand/getReceiver: [LocalVariableAccess] __synth__0__1 +# 28| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0__1 +# 28| getStmt: [AssignExpr] ... = ... +# 28| getAnOperand/getLeftOperand: [LocalVariableAccess] key +# 28| getAnOperand/getRightOperand: [MethodCall] call to [] +# 28| getArgument: [IntegerLiteral] 0 +# 28| getReceiver: [LocalVariableAccess] __synth__0__1 +# 28| getStmt: [AssignExpr] ... = ... +# 28| getAnOperand/getLeftOperand: [LocalVariableAccess] value +# 28| getAnOperand/getRightOperand: [MethodCall] call to [] +# 28| getArgument: [IntegerLiteral] 1 +# 28| getReceiver: [LocalVariableAccess] __synth__0__1 +# 28| getLeftOperand: [TuplePattern] (..., ...) +# 29| getStmt: [AssignAddExpr] ... += ... +# 29| getDesugared: [AssignExpr] ... = ... +# 29| getAnOperand/getLeftOperand: [LocalVariableAccess] sum +# 29| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 29| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] sum +# 29| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] value +# 30| getStmt: [AssignDivExpr] ... /= ... +# 30| getDesugared: [AssignExpr] ... = ... +# 30| getAnOperand/getLeftOperand: [LocalVariableAccess] foo +# 30| getAnOperand/getRightOperand: [DivExpr] ... / ... +# 30| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] foo +# 30| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] value +# 31| getStmt: [BreakStmt] break +# 28| getReceiver: [HashLiteral] {...} +# 28| getElement: [Pair] Pair +# 28| getKey: [SymbolLiteral] :foo +# 28| getValue: [IntegerLiteral] 0 +# 28| getElement: [Pair] Pair +# 28| getKey: [SymbolLiteral] :bar +# 28| getValue: [IntegerLiteral] 1 # 36| [AssignAddExpr] ... += ... # 36| getDesugared: [AssignExpr] ... = ... # 36| getAnOperand/getLeftOperand: [LocalVariableAccess] x @@ -535,21 +690,30 @@ params/params.rb: # 21| getDesugared: [MethodCall] call to [] # 21| getReceiver: [ConstantReadAccess] Array erb/template.html.erb: -# 27| [ArrayLiteral] [...] -# 27| getDesugared: [MethodCall] call to [] -# 27| getReceiver: [ConstantReadAccess] Array -# 27| getArgument: [StringLiteral] "foo" -# 27| getComponent: [StringTextComponent] foo -# 27| getArgument: [StringLiteral] "bar" -# 27| getComponent: [StringTextComponent] bar -# 27| getArgument: [StringLiteral] "baz" -# 27| getComponent: [StringTextComponent] baz -# 28| [AssignAddExpr] ... += ... -# 28| getDesugared: [AssignExpr] ... = ... -# 28| getAnOperand/getLeftOperand: [LocalVariableAccess] xs -# 28| getAnOperand/getRightOperand: [AddExpr] ... + ... -# 28| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] xs -# 28| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] x +# 27| [ForExpr] for ... in ... +# 27| getDesugared: [MethodCall] call to each +# 27| getBlock: [BraceBlock] { ... } +# 27| getParameter: [SimpleParameter] __synth__0__1 +# 27| getDefiningAccess: [LocalVariableAccess] __synth__0__1 +# 27| getStmt: [AssignExpr] ... = ... +# 27| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1 +# 27| getAnOperand/getLeftOperand: [LocalVariableAccess] x +# 28| getStmt: [AssignAddExpr] ... += ... +# 28| getDesugared: [AssignExpr] ... = ... +# 28| getAnOperand/getLeftOperand: [LocalVariableAccess] xs +# 28| getAnOperand/getRightOperand: [AddExpr] ... + ... +# 28| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] xs +# 28| getAnOperand/getArgument/getRightOperand: [LocalVariableAccess] x +# 29| getStmt: [LocalVariableAccess] xs +# 27| getReceiver: [ArrayLiteral] [...] +# 27| getDesugared: [MethodCall] call to [] +# 27| getReceiver: [ConstantReadAccess] Array +# 27| getArgument: [StringLiteral] "foo" +# 27| getComponent: [StringTextComponent] foo +# 27| getArgument: [StringLiteral] "bar" +# 27| getComponent: [StringTextComponent] bar +# 27| getArgument: [StringLiteral] "baz" +# 27| getComponent: [StringTextComponent] baz gems/test.gemspec: # 2| [AssignExpr] ... = ... # 2| getDesugared: [StmtSequence] ... diff --git a/ruby/ql/test/library-tests/ast/ValueText.expected b/ruby/ql/test/library-tests/ast/ValueText.expected index 4204a27a40f4..76a4b23bc18c 100644 --- a/ruby/ql/test/library-tests/ast/ValueText.expected +++ b/ruby/ql/test/library-tests/ast/ValueText.expected @@ -56,6 +56,15 @@ | calls/calls.rb:320:31:320:31 | 1 | 1 | | calls/calls.rb:320:37:320:37 | 2 | 2 | | calls/calls.rb:328:31:328:37 | "error" | error | +| calls/calls.rb:340:5:340:5 | 0 | 0 | +| calls/calls.rb:340:8:340:8 | 1 | 1 | +| calls/calls.rb:340:11:340:11 | 2 | 2 | +| calls/calls.rb:340:18:340:18 | 1 | 1 | +| calls/calls.rb:340:20:340:20 | 2 | 2 | +| calls/calls.rb:340:22:340:22 | 3 | 3 | +| calls/calls.rb:340:27:340:27 | 4 | 4 | +| calls/calls.rb:340:29:340:29 | 5 | 5 | +| calls/calls.rb:340:31:340:31 | 6 | 6 | | constants/constants.rb:3:19:3:27 | "const_a" | const_a | | constants/constants.rb:6:15:6:23 | "const_b" | const_b | | constants/constants.rb:17:12:17:18 | "Hello" | Hello | @@ -150,10 +159,14 @@ | control/loops.rb:9:13:9:14 | 10 | 10 | | control/loops.rb:16:10:16:10 | 1 | 1 | | control/loops.rb:16:13:16:14 | 10 | 10 | +| control/loops.rb:22:5:22:7 | 0 | 0 | +| control/loops.rb:22:10:22:14 | 1 | 1 | | control/loops.rb:22:20:22:22 | :foo | foo | | control/loops.rb:22:25:22:25 | 0 | 0 | | control/loops.rb:22:28:22:30 | :bar | bar | | control/loops.rb:22:33:22:33 | 1 | 1 | +| control/loops.rb:28:6:28:8 | 0 | 0 | +| control/loops.rb:28:11:28:15 | 1 | 1 | | control/loops.rb:28:22:28:24 | :foo | foo | | control/loops.rb:28:27:28:27 | 0 | 0 | | control/loops.rb:28:30:28:32 | :bar | bar | diff --git a/ruby/ql/test/library-tests/ast/calls/arguments.expected b/ruby/ql/test/library-tests/ast/calls/arguments.expected index 526de133d0b1..d952fa9b8882 100644 --- a/ruby/ql/test/library-tests/ast/calls/arguments.expected +++ b/ruby/ql/test/library-tests/ast/calls/arguments.expected @@ -6,6 +6,7 @@ splatExpr | calls.rb:271:5:271:11 | * ... | calls.rb:271:6:271:11 | call to bar | | calls.rb:316:31:316:42 | * ... | calls.rb:316:31:316:42 | [...] | | calls.rb:317:14:317:22 | * ... | calls.rb:317:14:317:22 | [...] | +| calls.rb:340:1:342:3 | * ... | calls.rb:340:1:342:3 | __synth__0__1 | hashSplatExpr | calls.rb:274:5:274:9 | ** ... | calls.rb:274:7:274:9 | call to bar | | calls.rb:275:5:275:12 | ** ... | calls.rb:275:7:275:12 | call to bar | diff --git a/ruby/ql/test/library-tests/ast/calls/calls.expected b/ruby/ql/test/library-tests/ast/calls/calls.expected index 1e7ecd8fa7ba..ed7ef735f871 100644 --- a/ruby/ql/test/library-tests/ast/calls/calls.expected +++ b/ruby/ql/test/library-tests/ast/calls/calls.expected @@ -90,6 +90,20 @@ callsWithArguments | calls.rb:332:3:332:12 | call to super | super | 0 | calls.rb:332:9:332:11 | ... | | calls.rb:336:3:336:13 | call to bar | bar | 0 | calls.rb:336:7:336:7 | b | | calls.rb:336:3:336:13 | call to bar | bar | 1 | calls.rb:336:10:336:12 | ... | +| calls.rb:340:5:340:5 | call to [] | [] | 0 | calls.rb:340:5:340:5 | 0 | +| calls.rb:340:8:340:8 | call to [] | [] | 0 | calls.rb:340:8:340:8 | 1 | +| calls.rb:340:11:340:11 | call to [] | [] | 0 | calls.rb:340:11:340:11 | 2 | +| calls.rb:340:16:340:33 | call to [] | [] | 0 | calls.rb:340:17:340:23 | [...] | +| calls.rb:340:16:340:33 | call to [] | [] | 1 | calls.rb:340:26:340:32 | [...] | +| calls.rb:340:17:340:23 | call to [] | [] | 0 | calls.rb:340:18:340:18 | 1 | +| calls.rb:340:17:340:23 | call to [] | [] | 1 | calls.rb:340:20:340:20 | 2 | +| calls.rb:340:17:340:23 | call to [] | [] | 2 | calls.rb:340:22:340:22 | 3 | +| calls.rb:340:26:340:32 | call to [] | [] | 0 | calls.rb:340:27:340:27 | 4 | +| calls.rb:340:26:340:32 | call to [] | [] | 1 | calls.rb:340:29:340:29 | 5 | +| calls.rb:340:26:340:32 | call to [] | [] | 2 | calls.rb:340:31:340:31 | 6 | +| calls.rb:341:3:341:13 | call to foo | foo | 0 | calls.rb:341:7:341:7 | x | +| calls.rb:341:3:341:13 | call to foo | foo | 1 | calls.rb:341:10:341:10 | y | +| calls.rb:341:3:341:13 | call to foo | foo | 2 | calls.rb:341:13:341:13 | z | callsWithReceiver | calls.rb:2:1:2:5 | call to foo | calls.rb:2:1:2:5 | self | | calls.rb:5:1:5:10 | call to bar | calls.rb:5:1:5:3 | Foo | @@ -214,8 +228,10 @@ callsWithReceiver | calls.rb:222:11:222:13 | call to foo | calls.rb:222:11:222:13 | self | | calls.rb:223:1:223:6 | call to bar | calls.rb:223:1:223:1 | X | | calls.rb:223:14:223:19 | call to foo | calls.rb:223:14:223:14 | X | +| calls.rb:226:1:228:3 | call to each | calls.rb:226:10:226:12 | call to bar | | calls.rb:226:10:226:12 | call to bar | calls.rb:226:10:226:12 | self | | calls.rb:227:3:227:5 | call to baz | calls.rb:227:3:227:5 | self | +| calls.rb:229:1:231:3 | call to each | calls.rb:229:10:229:15 | call to bar | | calls.rb:229:10:229:15 | call to bar | calls.rb:229:10:229:10 | X | | calls.rb:230:3:230:8 | call to baz | calls.rb:230:3:230:3 | X | | calls.rb:234:1:234:3 | call to foo | calls.rb:234:1:234:3 | self | @@ -328,16 +344,28 @@ callsWithReceiver | calls.rb:328:13:328:15 | call to bar | calls.rb:328:13:328:15 | self | | calls.rb:328:25:328:37 | call to print | calls.rb:328:25:328:37 | self | | calls.rb:336:3:336:13 | call to bar | calls.rb:336:3:336:13 | self | +| calls.rb:340:1:342:3 | * ... | calls.rb:340:1:342:3 | __synth__0__1 | +| calls.rb:340:1:342:3 | call to each | calls.rb:340:16:340:33 | [...] | +| calls.rb:340:5:340:5 | call to [] | calls.rb:340:5:340:5 | __synth__0__1 | +| calls.rb:340:8:340:8 | call to [] | calls.rb:340:8:340:8 | __synth__0__1 | +| calls.rb:340:11:340:11 | call to [] | calls.rb:340:11:340:11 | __synth__0__1 | +| calls.rb:340:16:340:33 | call to [] | calls.rb:340:16:340:33 | Array | +| calls.rb:340:17:340:23 | call to [] | calls.rb:340:17:340:23 | Array | +| calls.rb:340:26:340:32 | call to [] | calls.rb:340:26:340:32 | Array | +| calls.rb:341:3:341:13 | call to foo | calls.rb:341:3:341:13 | self | callsWithBlock | calls.rb:17:1:17:17 | call to foo | calls.rb:17:5:17:17 | { ... } | | calls.rb:20:1:22:3 | call to foo | calls.rb:20:5:22:3 | do ... end | | calls.rb:25:1:27:3 | call to bar | calls.rb:25:16:27:3 | do ... end | | calls.rb:92:1:92:21 | call to foo | calls.rb:92:7:92:21 | { ... } | | calls.rb:95:1:98:3 | call to foo | calls.rb:95:7:98:3 | do ... end | +| calls.rb:226:1:228:3 | call to each | calls.rb:226:1:228:3 | { ... } | +| calls.rb:229:1:231:3 | call to each | calls.rb:229:1:231:3 | { ... } | | calls.rb:290:5:290:23 | call to super | calls.rb:290:11:290:23 | { ... } | | calls.rb:291:5:291:26 | call to super | calls.rb:291:11:291:26 | do ... end | | calls.rb:292:5:292:30 | call to super | calls.rb:292:16:292:30 | { ... } | | calls.rb:293:5:293:33 | call to super | calls.rb:293:16:293:33 | do ... end | +| calls.rb:340:1:342:3 | call to each | calls.rb:340:1:342:3 | { ... } | yieldCalls | calls.rb:31:3:31:7 | yield ... | | calls.rb:36:3:36:16 | yield ... | diff --git a/ruby/ql/test/library-tests/ast/calls/calls.rb b/ruby/ql/test/library-tests/ast/calls/calls.rb index f4bb18d9fe52..674fa89f49f3 100644 --- a/ruby/ql/test/library-tests/ast/calls/calls.rb +++ b/ruby/ql/test/library-tests/ast/calls/calls.rb @@ -335,3 +335,8 @@ def foo(...) def foo(a, b, ...) bar(b, ...) end + +# for loop over nested array +for x, y, z in [[1,2,3], [4,5,6]] + foo x, y, z +end diff --git a/ruby/ql/test/library-tests/controlflow/graph/Cfg.expected b/ruby/ql/test/library-tests/controlflow/graph/Cfg.expected index 931fc560bb4c..2b981f65f435 100644 --- a/ruby/ql/test/library-tests/controlflow/graph/Cfg.expected +++ b/ruby/ql/test/library-tests/controlflow/graph/Cfg.expected @@ -1,6 +1,6 @@ break_ensure.rb: # 1| enter m1 -#-----| -> elements +#-----| -> x # 1| enter break_ensure.rb #-----| -> m1 @@ -12,75 +12,110 @@ break_ensure.rb: # 1| exit break_ensure.rb +# 1| exit m1 (abnormal) +#-----| -> exit m1 + # 1| exit m1 (normal) #-----| -> exit m1 # 1| exit break_ensure.rb (normal) #-----| -> exit break_ensure.rb -# 1| elements -#-----| -> elements +# 1| x +#-----| -> x -# 2| for ... in ... -#-----| -> elements +# 2| while ... +#-----| -> self -# 2| element -#-----| -> element +# 2| ... < ... +#-----| false -> while ... +#-----| true -> x +#-----| raise -> [ensure: raise] self -# 2| In -#-----| empty -> for ... in ... -#-----| non-empty -> element +# 2| x +#-----| -> 0 -# 2| elements -#-----| -> In +# 2| 0 +#-----| -> ... < ... # 2| do ... -#-----| -> In +#-----| -> x # 3| if ... #-----| -> do ... # 3| ... > ... #-----| true -> break -#-----| raise -> for ... in ... #-----| false -> if ... +#-----| raise -> while ... -# 3| element +# 3| x #-----| -> 0 # 3| 0 #-----| -> ... > ... # 4| break -#-----| break -> for ... in ... +#-----| break -> while ... # 7| ensure ... #-----| -> exit m1 (normal) +# 7| [ensure: raise] ensure ... +#-----| raise -> exit m1 (abnormal) + # 8| if ... #-----| -> ensure ... +# 8| [ensure: raise] if ... +#-----| -> [ensure: raise] ensure ... + # 8| call to nil? #-----| false -> if ... #-----| true -> self -# 8| elements +# 8| [ensure: raise] call to nil? +#-----| false -> [ensure: raise] if ... +#-----| true -> [ensure: raise] self + +# 8| call to elements #-----| -> call to nil? +# 8| [ensure: raise] call to elements +#-----| -> [ensure: raise] call to nil? + +# 8| self +#-----| -> call to elements + +# 8| [ensure: raise] self +#-----| -> [ensure: raise] call to elements + # 8| then ... #-----| -> if ... +# 8| [ensure: raise] then ... +#-----| -> [ensure: raise] if ... + # 9| call to puts #-----| -> then ... +# 9| [ensure: raise] call to puts +#-----| -> [ensure: raise] then ... + # 9| self #-----| -> "elements nil" +# 9| [ensure: raise] self +#-----| -> [ensure: raise] "elements nil" + # 9| "elements nil" #-----| -> call to puts +# 9| [ensure: raise] "elements nil" +#-----| -> [ensure: raise] call to puts + # 13| enter m2 -#-----| -> elements +#-----| -> x # 13| m2 #-----| -> m3 @@ -90,50 +125,53 @@ break_ensure.rb: # 13| exit m2 (normal) #-----| -> exit m2 -# 13| elements -#-----| -> elements +# 13| x +#-----| -> y -# 14| for ... in ... +# 13| y +#-----| -> x + +# 14| while ... #-----| -> exit m2 (normal) -# 14| element -#-----| -> element +# 14| ... < ... +#-----| false -> while ... +#-----| true -> x -# 14| In -#-----| empty -> for ... in ... -#-----| non-empty -> element +# 14| x +#-----| -> 0 -# 14| elements -#-----| -> In +# 14| 0 +#-----| -> ... < ... # 14| do ... -#-----| -> In +#-----| -> x # 16| if ... -#-----| -> elements +#-----| -> y # 16| ... > ... #-----| true -> break #-----| false -> if ... -#-----| raise -> [ensure: raise] elements +#-----| raise -> [ensure: raise] y -# 16| element +# 16| x #-----| -> 0 # 16| 0 #-----| -> ... > ... # 17| break -#-----| break -> [ensure: break] elements +#-----| break -> [ensure: break] y # 19| ensure ... #-----| -> do ... # 19| [ensure: break] ensure ... -#-----| break -> for ... in ... +#-----| break -> while ... # 19| [ensure: raise] ensure ... -#-----| raise -> for ... in ... +#-----| raise -> while ... # 20| if ... #-----| -> ensure ... @@ -156,13 +194,13 @@ break_ensure.rb: #-----| false -> [ensure: raise] if ... #-----| true -> [ensure: raise] self -# 20| elements +# 20| y #-----| -> call to nil? -# 20| [ensure: break] elements +# 20| [ensure: break] y #-----| -> [ensure: break] call to nil? -# 20| [ensure: raise] elements +# 20| [ensure: raise] y #-----| -> [ensure: raise] call to nil? # 20| then ... @@ -184,25 +222,25 @@ break_ensure.rb: #-----| -> [ensure: raise] then ... # 21| self -#-----| -> "elements nil" +#-----| -> "y nil" # 21| [ensure: break] self -#-----| -> [ensure: break] "elements nil" +#-----| -> [ensure: break] "y nil" # 21| [ensure: raise] self -#-----| -> [ensure: raise] "elements nil" +#-----| -> [ensure: raise] "y nil" -# 21| "elements nil" +# 21| "y nil" #-----| -> call to puts -# 21| [ensure: break] "elements nil" +# 21| [ensure: break] "y nil" #-----| -> [ensure: break] call to puts -# 21| [ensure: raise] "elements nil" +# 21| [ensure: raise] "y nil" #-----| -> [ensure: raise] call to puts # 27| enter m3 -#-----| -> elements +#-----| -> x # 27| m3 #-----| -> m4 @@ -215,136 +253,127 @@ break_ensure.rb: # 27| exit m3 (normal) #-----| -> exit m3 -# 27| elements -#-----| -> elements +# 27| x +#-----| -> y + +# 27| y +#-----| -> x # 29| if ... -#-----| -> elements +#-----| -> y # 29| call to nil? #-----| false -> if ... #-----| true -> return -#-----| raise -> [ensure: raise] elements +#-----| raise -> [ensure: raise] y -# 29| elements +# 29| x #-----| -> call to nil? # 30| return -#-----| return -> [ensure: return] elements +#-----| return -> [ensure: return] y # 32| ensure ... #-----| -> self -# 32| [ensure: raise] ensure ... -#-----| raise -> exit m3 (abnormal) - # 32| [ensure: return] ensure ... #-----| return -> exit m3 (normal) -# 33| for ... in ... -#-----| -> ensure ... +# 32| [ensure: raise] ensure ... +#-----| raise -> exit m3 (abnormal) -# 33| [ensure: raise] for ... in ... -#-----| -> [ensure: raise] ensure ... +# 33| while ... +#-----| -> ensure ... -# 33| [ensure: return] for ... in ... +# 33| [ensure: return] while ... #-----| -> [ensure: return] ensure ... -# 33| element -#-----| -> self +# 33| [ensure: raise] while ... +#-----| -> [ensure: raise] ensure ... -# 33| [ensure: raise] element -#-----| -> [ensure: raise] self +# 33| ... < ... +#-----| false -> while ... +#-----| true -> x -# 33| [ensure: return] element -#-----| -> [ensure: return] self +# 33| [ensure: return] ... < ... +#-----| false -> [ensure: return] while ... +#-----| true -> [ensure: return] x -# 33| In -#-----| empty -> for ... in ... -#-----| non-empty -> element +# 33| [ensure: raise] ... < ... +#-----| false -> [ensure: raise] while ... +#-----| true -> [ensure: raise] x -# 33| [ensure: raise] In -#-----| empty -> [ensure: raise] for ... in ... -#-----| non-empty -> [ensure: raise] element +# 33| y +#-----| -> 0 -# 33| [ensure: return] In -#-----| empty -> [ensure: return] for ... in ... -#-----| non-empty -> [ensure: return] element +# 33| [ensure: return] y +#-----| -> [ensure: return] 0 -# 33| elements -#-----| -> In +# 33| [ensure: raise] y +#-----| -> [ensure: raise] 0 -# 33| [ensure: raise] elements -#-----| -> [ensure: raise] In +# 33| 0 +#-----| -> ... < ... -# 33| [ensure: return] elements -#-----| -> [ensure: return] In +# 33| [ensure: return] 0 +#-----| -> [ensure: return] ... < ... -# 33| do ... -#-----| -> In +# 33| [ensure: raise] 0 +#-----| -> [ensure: raise] ... < ... -# 33| [ensure: raise] do ... -#-----| -> [ensure: raise] In +# 33| do ... # 33| [ensure: return] do ... -#-----| -> [ensure: return] In + +# 33| [ensure: raise] do ... # 35| if ... #-----| -> do ... -# 35| [ensure: raise] if ... -#-----| -> [ensure: raise] do ... - # 35| [ensure: return] if ... #-----| -> [ensure: return] do ... +# 35| [ensure: raise] if ... +#-----| -> [ensure: raise] do ... + # 35| ... > ... #-----| true -> break #-----| false -> if ... -# 35| [ensure: raise] ... > ... -#-----| true -> [ensure: raise] break -#-----| false -> [ensure: raise] if ... - # 35| [ensure: return] ... > ... #-----| true -> [ensure: return] break #-----| false -> [ensure: return] if ... -# 35| call to x -#-----| -> 0 +# 35| [ensure: raise] ... > ... +#-----| true -> [ensure: raise] break +#-----| false -> [ensure: raise] if ... -# 35| [ensure: raise] call to x -#-----| -> [ensure: raise] 0 +# 35| x +#-----| -> 0 -# 35| [ensure: return] call to x +# 35| [ensure: return] x #-----| -> [ensure: return] 0 -# 35| self -#-----| -> call to x - -# 35| [ensure: raise] self -#-----| -> [ensure: raise] call to x - -# 35| [ensure: return] self -#-----| -> [ensure: return] call to x +# 35| [ensure: raise] x +#-----| -> [ensure: raise] 0 # 35| 0 #-----| -> ... > ... -# 35| [ensure: raise] 0 -#-----| -> [ensure: raise] ... > ... - # 35| [ensure: return] 0 #-----| -> [ensure: return] ... > ... -# 36| break -#-----| break -> for ... in ... +# 35| [ensure: raise] 0 +#-----| -> [ensure: raise] ... > ... -# 36| [ensure: raise] break -#-----| break -> [ensure: raise] for ... in ... +# 36| break +#-----| break -> while ... # 36| [ensure: return] break -#-----| break -> [ensure: return] for ... in ... +#-----| break -> [ensure: return] while ... + +# 36| [ensure: raise] break +#-----| break -> [ensure: raise] while ... # 41| call to puts #-----| -> exit m3 (normal) @@ -356,7 +385,7 @@ break_ensure.rb: #-----| -> call to puts # 44| enter m4 -#-----| -> elements +#-----| -> x # 44| m4 #-----| -> exit break_ensure.rb (normal) @@ -366,41 +395,41 @@ break_ensure.rb: # 44| exit m4 (normal) #-----| -> exit m4 -# 44| elements -#-----| -> elements +# 44| x +#-----| -> x -# 45| for ... in ... +# 45| while ... #-----| -> exit m4 (normal) -# 45| element -#-----| -> element +# 45| ... < ... +#-----| false -> while ... +#-----| true -> x -# 45| In -#-----| empty -> for ... in ... -#-----| non-empty -> element +# 45| x +#-----| -> 0 -# 45| elements -#-----| -> In +# 45| 0 +#-----| -> ... < ... # 45| do ... -#-----| -> In +#-----| -> x # 47| if ... -#-----| -> element +#-----| -> x # 47| ... > ... #-----| false -> if ... -#-----| raise -> [ensure: raise] element +#-----| raise -> [ensure: raise] x #-----| true -> self -# 47| element +# 47| x #-----| -> 1 # 47| 1 #-----| -> ... > ... # 48| call to raise -#-----| raise -> [ensure: raise] element +#-----| raise -> [ensure: raise] x # 48| self #-----| -> "" @@ -412,7 +441,7 @@ break_ensure.rb: #-----| -> do ... # 50| [ensure: raise] ensure ... -#-----| raise -> for ... in ... +#-----| raise -> while ... # 51| if ... #-----| -> ensure ... @@ -428,10 +457,10 @@ break_ensure.rb: #-----| false -> [ensure: raise] if ... #-----| true -> [ensure: raise] 10 -# 51| element +# 51| x #-----| -> 0 -# 51| [ensure: raise] element +# 51| [ensure: raise] x #-----| -> [ensure: raise] 0 # 51| 0 @@ -441,10 +470,10 @@ break_ensure.rb: #-----| -> [ensure: raise] ... > ... # 52| break -#-----| break -> for ... in ... +#-----| break -> while ... # 52| [ensure: raise] break -#-----| break -> for ... in ... +#-----| break -> while ... # 52| 10 #-----| -> break @@ -784,26 +813,9 @@ cfg.rb: # 16| "hello" #-----| -> call to puts -# 19| enter END { ... } -#-----| -> self - # 19| END { ... } #-----| -> 41 -# 19| exit END { ... } - -# 19| exit END { ... } (normal) -#-----| -> exit END { ... } - -# 20| call to puts -#-----| -> exit END { ... } (normal) - -# 20| self -#-----| -> "world" - -# 20| "world" -#-----| -> call to puts - # 23| ... + ... #-----| -> 2 @@ -1404,18 +1416,34 @@ cfg.rb: # 88| x #-----| -> #{...} -# 90| for ... in ... +# 90| enter { ... } +#-----| -> __synth__0__1 + +# 90| call to each #-----| -> $global -# 90| x +# 90| { ... } +#-----| -> call to each + +# 90| ... = ... #-----| -> x -# 90| In -#-----| empty -> for ... in ... -#-----| non-empty -> x +# 90| __synth__0__1 +#-----| -> x + +# 90| __synth__0__1 +#-----| -> ... = ... + +# 90| exit { ... } + +# 90| exit { ... } (normal) +#-----| -> exit { ... } + +# 90| x +#-----| -> __synth__0__1 # 90| call to [] -#-----| -> In +#-----| -> { ... } # 90| Array #-----| -> 1.4 @@ -1429,9 +1457,6 @@ cfg.rb: # 90| 3.4e5 #-----| -> call to [] -# 90| do ... -#-----| -> In - # 91| if ... #-----| -> self @@ -1446,10 +1471,10 @@ cfg.rb: #-----| -> ... > ... # 91| next -#-----| next -> In +#-----| next -> exit { ... } (normal) # 92| call to puts -#-----| -> do ... +#-----| -> exit { ... } (normal) # 92| self #-----| -> x @@ -4361,39 +4386,39 @@ raise.rb: # 75| ensure ... #-----| -> exit m7 (normal) -# 75| [ensure: raise] ensure ... -#-----| raise -> exit m7 (abnormal) - # 75| [ensure: return] ensure ... #-----| return -> exit m7 (normal) +# 75| [ensure: raise] ensure ... +#-----| raise -> exit m7 (abnormal) + # 76| call to puts #-----| -> ensure ... -# 76| [ensure: raise] call to puts -#-----| -> [ensure: raise] ensure ... - # 76| [ensure: return] call to puts #-----| -> [ensure: return] ensure ... +# 76| [ensure: raise] call to puts +#-----| -> [ensure: raise] ensure ... + # 76| self #-----| -> "ensure" -# 76| [ensure: raise] self -#-----| -> [ensure: raise] "ensure" - # 76| [ensure: return] self #-----| -> [ensure: return] "ensure" +# 76| [ensure: raise] self +#-----| -> [ensure: raise] "ensure" + # 76| "ensure" #-----| -> call to puts -# 76| [ensure: raise] "ensure" -#-----| -> [ensure: raise] call to puts - # 76| [ensure: return] "ensure" #-----| -> [ensure: return] call to puts +# 76| [ensure: raise] "ensure" +#-----| -> [ensure: raise] call to puts + # 79| enter m8 #-----| -> x @@ -4476,39 +4501,39 @@ raise.rb: # 88| ensure ... #-----| -> self -# 88| [ensure: raise] ensure ... -#-----| raise -> exit m8 (abnormal) - # 88| [ensure: return] ensure ... #-----| return -> exit m8 (normal) +# 88| [ensure: raise] ensure ... +#-----| raise -> exit m8 (abnormal) + # 89| call to puts #-----| -> ensure ... -# 89| [ensure: raise] call to puts -#-----| -> [ensure: raise] ensure ... - # 89| [ensure: return] call to puts #-----| -> [ensure: return] ensure ... +# 89| [ensure: raise] call to puts +#-----| -> [ensure: raise] ensure ... + # 89| self #-----| -> "ensure" -# 89| [ensure: raise] self -#-----| -> [ensure: raise] "ensure" - # 89| [ensure: return] self #-----| -> [ensure: return] "ensure" +# 89| [ensure: raise] self +#-----| -> [ensure: raise] "ensure" + # 89| "ensure" #-----| -> call to puts -# 89| [ensure: raise] "ensure" -#-----| -> [ensure: raise] call to puts - # 89| [ensure: return] "ensure" #-----| -> [ensure: return] call to puts +# 89| [ensure: raise] "ensure" +#-----| -> [ensure: raise] call to puts + # 91| call to puts #-----| -> exit m8 (normal) @@ -4607,108 +4632,108 @@ raise.rb: # 103| ensure ... #-----| -> self -# 103| [ensure: raise] ensure ... -#-----| raise -> [ensure: raise] self - # 103| [ensure: return] ensure ... #-----| return -> [ensure: return] self -# 104| call to puts -#-----| -> b1 +# 103| [ensure: raise] ensure ... #-----| raise -> [ensure: raise] self -# 104| [ensure: raise] call to puts -#-----| -> [ensure: raise] b1 +# 104| call to puts +#-----| -> b1 #-----| raise -> [ensure: raise] self # 104| [ensure: return] call to puts #-----| -> [ensure: return] b1 #-----| raise -> [ensure: raise] self +# 104| [ensure: raise] call to puts +#-----| -> [ensure: raise] b1 +#-----| raise -> [ensure: raise] self + # 104| self #-----| -> "outer ensure" -# 104| [ensure: raise] self -#-----| -> [ensure: raise] "outer ensure" - # 104| [ensure: return] self #-----| -> [ensure: return] "outer ensure" +# 104| [ensure: raise] self +#-----| -> [ensure: raise] "outer ensure" + # 104| "outer ensure" #-----| -> call to puts -# 104| [ensure: raise] "outer ensure" -#-----| -> [ensure: raise] call to puts - # 104| [ensure: return] "outer ensure" #-----| -> [ensure: return] call to puts +# 104| [ensure: raise] "outer ensure" +#-----| -> [ensure: raise] call to puts + # 106| if ... #-----| -> self -# 106| [ensure: raise] if ... -#-----| -> [ensure: raise] self - # 106| [ensure: return] if ... #-----| -> [ensure: return] self +# 106| [ensure: raise] if ... +#-----| -> [ensure: raise] self + # 106| b1 #-----| false -> if ... #-----| true -> self -# 106| [ensure: raise] b1 -#-----| false -> [ensure: raise] if ... -#-----| true -> [ensure: raise] self - # 106| [ensure: return] b1 #-----| false -> [ensure: return] if ... #-----| true -> [ensure: return] self +# 106| [ensure: raise] b1 +#-----| false -> [ensure: raise] if ... +#-----| true -> [ensure: raise] self + # 107| call to raise #-----| raise -> [ensure(1): raise] self -# 107| [ensure: raise] call to raise -#-----| raise -> [ensure: raise, ensure(1): raise] self - # 107| [ensure: return] call to raise #-----| raise -> [ensure: return, ensure(1): raise] self +# 107| [ensure: raise] call to raise +#-----| raise -> [ensure: raise, ensure(1): raise] self + # 107| self #-----| -> "b1 is true" -# 107| [ensure: raise] self -#-----| -> [ensure: raise] "b1 is true" - # 107| [ensure: return] self #-----| -> [ensure: return] "b1 is true" +# 107| [ensure: raise] self +#-----| -> [ensure: raise] "b1 is true" + # 107| "b1 is true" #-----| -> call to raise -# 107| [ensure: raise] "b1 is true" -#-----| -> [ensure: raise] call to raise - # 107| [ensure: return] "b1 is true" #-----| -> [ensure: return] call to raise +# 107| [ensure: raise] "b1 is true" +#-----| -> [ensure: raise] call to raise + # 109| ensure ... #-----| -> ensure ... # 109| [ensure(1): raise] ensure ... #-----| raise -> [ensure: raise] self -# 109| [ensure: raise] ensure ... -#-----| -> [ensure: raise] ensure ... - -# 109| [ensure: raise, ensure(1): raise] ensure ... -#-----| raise -> [ensure: raise] self - # 109| [ensure: return] ensure ... #-----| -> [ensure: return] ensure ... # 109| [ensure: return, ensure(1): raise] ensure ... #-----| raise -> [ensure: raise] self +# 109| [ensure: raise] ensure ... +#-----| -> [ensure: raise] ensure ... + +# 109| [ensure: raise, ensure(1): raise] ensure ... +#-----| raise -> [ensure: raise] self + # 110| call to puts #-----| -> ensure ... #-----| raise -> [ensure: raise] self @@ -4717,14 +4742,6 @@ raise.rb: #-----| -> [ensure(1): raise] ensure ... #-----| raise -> [ensure: raise] self -# 110| [ensure: raise] call to puts -#-----| -> [ensure: raise] ensure ... -#-----| raise -> [ensure: raise] self - -# 110| [ensure: raise, ensure(1): raise] call to puts -#-----| -> [ensure: raise, ensure(1): raise] ensure ... -#-----| raise -> [ensure: raise] self - # 110| [ensure: return] call to puts #-----| -> [ensure: return] ensure ... #-----| raise -> [ensure: raise] self @@ -4733,42 +4750,50 @@ raise.rb: #-----| -> [ensure: return, ensure(1): raise] ensure ... #-----| raise -> [ensure: raise] self +# 110| [ensure: raise] call to puts +#-----| -> [ensure: raise] ensure ... +#-----| raise -> [ensure: raise] self + +# 110| [ensure: raise, ensure(1): raise] call to puts +#-----| -> [ensure: raise, ensure(1): raise] ensure ... +#-----| raise -> [ensure: raise] self + # 110| self #-----| -> "inner ensure" # 110| [ensure(1): raise] self #-----| -> [ensure(1): raise] "inner ensure" -# 110| [ensure: raise] self -#-----| -> [ensure: raise] "inner ensure" - -# 110| [ensure: raise, ensure(1): raise] self -#-----| -> [ensure: raise, ensure(1): raise] "inner ensure" - # 110| [ensure: return] self #-----| -> [ensure: return] "inner ensure" # 110| [ensure: return, ensure(1): raise] self #-----| -> [ensure: return, ensure(1): raise] "inner ensure" +# 110| [ensure: raise] self +#-----| -> [ensure: raise] "inner ensure" + +# 110| [ensure: raise, ensure(1): raise] self +#-----| -> [ensure: raise, ensure(1): raise] "inner ensure" + # 110| "inner ensure" #-----| -> call to puts # 110| [ensure(1): raise] "inner ensure" #-----| -> [ensure(1): raise] call to puts -# 110| [ensure: raise] "inner ensure" -#-----| -> [ensure: raise] call to puts - -# 110| [ensure: raise, ensure(1): raise] "inner ensure" -#-----| -> [ensure: raise, ensure(1): raise] call to puts - # 110| [ensure: return] "inner ensure" #-----| -> [ensure: return] call to puts # 110| [ensure: return, ensure(1): raise] "inner ensure" #-----| -> [ensure: return, ensure(1): raise] call to puts +# 110| [ensure: raise] "inner ensure" +#-----| -> [ensure: raise] call to puts + +# 110| [ensure: raise, ensure(1): raise] "inner ensure" +#-----| -> [ensure: raise, ensure(1): raise] call to puts + # 113| call to puts #-----| -> self #-----| raise -> [ensure: raise] self @@ -4782,87 +4807,87 @@ raise.rb: # 114| ensure ... #-----| -> exit m9 (normal) -# 114| [ensure: raise] ensure ... -#-----| raise -> exit m9 (abnormal) - # 114| [ensure: return] ensure ... #-----| return -> exit m9 (normal) +# 114| [ensure: raise] ensure ... +#-----| raise -> exit m9 (abnormal) + # 115| call to puts #-----| -> b2 -# 115| [ensure: raise] call to puts -#-----| -> [ensure: raise] b2 - # 115| [ensure: return] call to puts #-----| -> [ensure: return] b2 +# 115| [ensure: raise] call to puts +#-----| -> [ensure: raise] b2 + # 115| self #-----| -> "method ensure" -# 115| [ensure: raise] self -#-----| -> [ensure: raise] "method ensure" - # 115| [ensure: return] self #-----| -> [ensure: return] "method ensure" +# 115| [ensure: raise] self +#-----| -> [ensure: raise] "method ensure" + # 115| "method ensure" #-----| -> call to puts -# 115| [ensure: raise] "method ensure" -#-----| -> [ensure: raise] call to puts - # 115| [ensure: return] "method ensure" #-----| -> [ensure: return] call to puts +# 115| [ensure: raise] "method ensure" +#-----| -> [ensure: raise] call to puts + # 116| if ... #-----| -> ensure ... -# 116| [ensure: raise] if ... -#-----| -> [ensure: raise] ensure ... - # 116| [ensure: return] if ... #-----| -> [ensure: return] ensure ... +# 116| [ensure: raise] if ... +#-----| -> [ensure: raise] ensure ... + # 116| b2 #-----| false -> if ... #-----| true -> self -# 116| [ensure: raise] b2 -#-----| false -> [ensure: raise] if ... -#-----| true -> [ensure: raise] self - # 116| [ensure: return] b2 #-----| false -> [ensure: return] if ... #-----| true -> [ensure: return] self +# 116| [ensure: raise] b2 +#-----| false -> [ensure: raise] if ... +#-----| true -> [ensure: raise] self + # 117| call to raise #-----| raise -> exit m9 (abnormal) -# 117| [ensure: raise] call to raise +# 117| [ensure: return] call to raise #-----| raise -> exit m9 (abnormal) -# 117| [ensure: return] call to raise +# 117| [ensure: raise] call to raise #-----| raise -> exit m9 (abnormal) # 117| self #-----| -> "b2 is true" -# 117| [ensure: raise] self -#-----| -> [ensure: raise] "b2 is true" - # 117| [ensure: return] self #-----| -> [ensure: return] "b2 is true" +# 117| [ensure: raise] self +#-----| -> [ensure: raise] "b2 is true" + # 117| "b2 is true" #-----| -> call to raise -# 117| [ensure: raise] "b2 is true" -#-----| -> [ensure: raise] call to raise - # 117| [ensure: return] "b2 is true" #-----| -> [ensure: return] call to raise +# 117| [ensure: raise] "b2 is true" +#-----| -> [ensure: raise] call to raise + # 121| enter m10 #-----| -> p diff --git a/ruby/ql/test/library-tests/controlflow/graph/break_ensure.rb b/ruby/ql/test/library-tests/controlflow/graph/break_ensure.rb index 4ee587049f3c..1040efdeba0d 100644 --- a/ruby/ql/test/library-tests/controlflow/graph/break_ensure.rb +++ b/ruby/ql/test/library-tests/controlflow/graph/break_ensure.rb @@ -1,6 +1,6 @@ -def m1 elements - for element in elements do - if element > 0 then +def m1 x + while x < 0 + if x > 0 then break end end @@ -10,27 +10,27 @@ def m1 elements end end -def m2 elements - for element in elements do +def m2(x, y) + while x < 0 begin - if element > 0 then + if x > 0 then break end ensure - if elements.nil? then - puts "elements nil" + if y.nil? then + puts "y nil" end end end end -def m3 elements +def m3(x,y) begin - if elements.nil? then + if x.nil? then return end ensure - for element in elements do + while y < 0 begin if x > 0 then break @@ -41,14 +41,14 @@ def m3 elements puts "Done" end -def m4 elements - for element in elements do +def m4 x + while x < 0 begin - if element > 1 then + if x > 1 then raise "" end ensure - if element > 0 then + if x > 0 then break 10; end end diff --git a/ruby/ql/test/library-tests/dataflow/local/DataflowStep.expected b/ruby/ql/test/library-tests/dataflow/local/DataflowStep.expected index 7496d7b55979..7e0150f77639 100644 --- a/ruby/ql/test/library-tests/dataflow/local/DataflowStep.expected +++ b/ruby/ql/test/library-tests/dataflow/local/DataflowStep.expected @@ -1,5 +1,4 @@ | local_dataflow.rb:1:1:7:3 | self (foo) | local_dataflow.rb:3:8:3:10 | self | -| local_dataflow.rb:1:1:7:3 | self (local_dataflow.rb) | local_dataflow.rb:11:1:11:2 | self | | local_dataflow.rb:1:1:7:3 | self (local_dataflow.rb) | local_dataflow.rb:49:1:53:3 | self | | local_dataflow.rb:1:1:7:3 | self in foo | local_dataflow.rb:3:8:3:10 | self | | local_dataflow.rb:1:9:1:9 | a | local_dataflow.rb:1:9:1:9 | a | @@ -26,25 +25,29 @@ | local_dataflow.rb:9:1:9:15 | ... = ... | local_dataflow.rb:10:14:10:18 | array | | local_dataflow.rb:9:9:9:15 | call to [] | local_dataflow.rb:9:1:9:15 | ... = ... | | local_dataflow.rb:9:9:9:15 | call to [] | local_dataflow.rb:9:1:9:15 | ... = ... | -| local_dataflow.rb:10:5:13:3 | for ... in ... | local_dataflow.rb:10:1:13:3 | ... = ... | -| local_dataflow.rb:10:9:10:9 | x | local_dataflow.rb:12:5:12:5 | x | -| local_dataflow.rb:10:14:10:18 | array | local_dataflow.rb:10:5:13:3 | for ... in ... | +| local_dataflow.rb:10:5:13:3 | ... = ... | local_dataflow.rb:12:5:12:5 | x | +| local_dataflow.rb:10:5:13:3 | | local_dataflow.rb:11:1:11:2 | self | +| local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | ... = ... | +| local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | ... = ... | +| local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | __synth__0__1 | +| local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | __synth__0__1 | +| local_dataflow.rb:10:5:13:3 | call to each | local_dataflow.rb:10:1:13:3 | ... = ... | +| local_dataflow.rb:10:14:10:18 | [post] array | local_dataflow.rb:15:10:15:14 | array | | local_dataflow.rb:10:14:10:18 | array | local_dataflow.rb:15:10:15:14 | array | | local_dataflow.rb:11:1:11:2 | [post] self | local_dataflow.rb:12:3:12:5 | self | | local_dataflow.rb:11:1:11:2 | self | local_dataflow.rb:12:3:12:5 | self | -| local_dataflow.rb:12:3:12:5 | [post] self | local_dataflow.rb:11:1:11:2 | self | -| local_dataflow.rb:12:3:12:5 | [post] self | local_dataflow.rb:49:1:53:3 | self | -| local_dataflow.rb:12:3:12:5 | call to p | local_dataflow.rb:10:19:13:3 | do ... | -| local_dataflow.rb:12:3:12:5 | self | local_dataflow.rb:11:1:11:2 | self | -| local_dataflow.rb:12:3:12:5 | self | local_dataflow.rb:49:1:53:3 | self | -| local_dataflow.rb:15:10:15:14 | array | local_dataflow.rb:15:1:17:3 | for ... in ... | +| local_dataflow.rb:15:1:17:3 | __synth__0__1 | local_dataflow.rb:15:1:17:3 | ... = ... | +| local_dataflow.rb:15:1:17:3 | __synth__0__1 | local_dataflow.rb:15:1:17:3 | ... = ... | +| local_dataflow.rb:15:1:17:3 | __synth__0__1 | local_dataflow.rb:15:1:17:3 | __synth__0__1 | +| local_dataflow.rb:15:1:17:3 | __synth__0__1 | local_dataflow.rb:15:1:17:3 | __synth__0__1 | +| local_dataflow.rb:15:10:15:14 | [post] array | local_dataflow.rb:19:10:19:14 | array | | local_dataflow.rb:15:10:15:14 | array | local_dataflow.rb:19:10:19:14 | array | -| local_dataflow.rb:16:3:16:10 | break | local_dataflow.rb:15:1:17:3 | for ... in ... | | local_dataflow.rb:16:9:16:10 | 10 | local_dataflow.rb:16:3:16:10 | break | -| local_dataflow.rb:19:5:19:5 | x | local_dataflow.rb:20:6:20:6 | x | -| local_dataflow.rb:19:10:19:14 | array | local_dataflow.rb:19:1:21:3 | for ... in ... | -| local_dataflow.rb:20:3:20:25 | if ... | local_dataflow.rb:19:16:21:3 | do ... | -| local_dataflow.rb:20:17:20:21 | break | local_dataflow.rb:19:1:21:3 | for ... in ... | +| local_dataflow.rb:19:1:21:3 | ... = ... | local_dataflow.rb:20:6:20:6 | x | +| local_dataflow.rb:19:1:21:3 | __synth__0__1 | local_dataflow.rb:19:1:21:3 | ... = ... | +| local_dataflow.rb:19:1:21:3 | __synth__0__1 | local_dataflow.rb:19:1:21:3 | ... = ... | +| local_dataflow.rb:19:1:21:3 | __synth__0__1 | local_dataflow.rb:19:1:21:3 | __synth__0__1 | +| local_dataflow.rb:19:1:21:3 | __synth__0__1 | local_dataflow.rb:19:1:21:3 | __synth__0__1 | | local_dataflow.rb:24:2:24:8 | break | local_dataflow.rb:23:1:25:3 | while ... | | local_dataflow.rb:24:8:24:8 | 5 | local_dataflow.rb:24:2:24:8 | break | | local_dataflow.rb:28:5:28:26 | M | local_dataflow.rb:28:1:28:26 | ... = ... | diff --git a/ruby/ql/test/library-tests/dataflow/local/Nodes.expected b/ruby/ql/test/library-tests/dataflow/local/Nodes.expected index 6defc9d0e750..9399f18ca123 100644 --- a/ruby/ql/test/library-tests/dataflow/local/Nodes.expected +++ b/ruby/ql/test/library-tests/dataflow/local/Nodes.expected @@ -1,5 +1,9 @@ ret | local_dataflow.rb:6:3:6:14 | ... = ... | +| local_dataflow.rb:12:3:12:5 | call to p | +| local_dataflow.rb:16:3:16:10 | break | +| local_dataflow.rb:20:3:20:25 | if ... | +| local_dataflow.rb:20:17:20:21 | break | | local_dataflow.rb:32:14:32:21 | "method" | | local_dataflow.rb:36:6:36:13 | return | | local_dataflow.rb:38:3:38:13 | "reachable" | @@ -17,9 +21,15 @@ arg | local_dataflow.rb:9:10:9:10 | 1 | local_dataflow.rb:9:9:9:15 | call to [] | 0 | | local_dataflow.rb:9:12:9:12 | 2 | local_dataflow.rb:9:9:9:15 | call to [] | 1 | | local_dataflow.rb:9:14:9:14 | 3 | local_dataflow.rb:9:9:9:15 | call to [] | 2 | +| local_dataflow.rb:10:5:13:3 | { ... } | local_dataflow.rb:10:5:13:3 | call to each | -2 | +| local_dataflow.rb:10:14:10:18 | array | local_dataflow.rb:10:5:13:3 | call to each | -1 | | local_dataflow.rb:11:1:11:2 | self | local_dataflow.rb:11:1:11:2 | call to do | -1 | | local_dataflow.rb:12:3:12:5 | self | local_dataflow.rb:12:3:12:5 | call to p | -1 | | local_dataflow.rb:12:5:12:5 | x | local_dataflow.rb:12:3:12:5 | call to p | 0 | +| local_dataflow.rb:15:1:17:3 | { ... } | local_dataflow.rb:15:1:17:3 | call to each | -2 | +| local_dataflow.rb:15:10:15:14 | array | local_dataflow.rb:15:1:17:3 | call to each | -1 | +| local_dataflow.rb:19:1:21:3 | { ... } | local_dataflow.rb:19:1:21:3 | call to each | -2 | +| local_dataflow.rb:19:10:19:14 | array | local_dataflow.rb:19:1:21:3 | call to each | -1 | | local_dataflow.rb:20:6:20:6 | x | local_dataflow.rb:20:6:20:10 | ... > ... | -1 | | local_dataflow.rb:20:10:20:10 | 1 | local_dataflow.rb:20:6:20:10 | ... > ... | 0 | | local_dataflow.rb:35:6:35:6 | x | local_dataflow.rb:35:6:35:11 | ... == ... | -1 | diff --git a/ruby/ql/test/library-tests/variables/parameter.expected b/ruby/ql/test/library-tests/variables/parameter.expected index 6e21d46b2121..eaee1d26da3b 100644 --- a/ruby/ql/test/library-tests/variables/parameter.expected +++ b/ruby/ql/test/library-tests/variables/parameter.expected @@ -28,6 +28,7 @@ parameterVariable | ssa.rb:1:7:1:7 | b | ssa.rb:1:7:1:7 | b | | ssa.rb:18:8:18:8 | x | ssa.rb:18:8:18:8 | x | | ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | +| ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | | ssa.rb:33:20:33:20 | x | ssa.rb:33:20:33:20 | x | | ssa.rb:44:8:44:8 | b | ssa.rb:44:8:44:8 | b | | ssa.rb:49:9:49:9 | x | ssa.rb:49:9:49:9 | x | diff --git a/ruby/ql/test/library-tests/variables/ssa.expected b/ruby/ql/test/library-tests/variables/ssa.expected index b17ef242f27f..05701ea74660 100644 --- a/ruby/ql/test/library-tests/variables/ssa.expected +++ b/ruby/ql/test/library-tests/variables/ssa.expected @@ -82,8 +82,12 @@ definition | scopes.rb:13:14:13:14 | ... = ... | scopes.rb:13:14:13:14 | d | | scopes.rb:13:19:13:32 | ... = ... | scopes.rb:13:4:13:32 | __synth__0 | | scopes.rb:27:1:27:5 | ... = ... | scopes.rb:27:1:27:1 | x | +| scopes.rb:29:3:29:7 | ... = ... | scopes.rb:29:3:29:3 | x | +| scopes.rb:32:3:32:7 | ... = ... | scopes.rb:32:3:32:3 | x | +| scopes.rb:35:3:35:7 | ... = ... | scopes.rb:35:3:35:3 | x | | scopes.rb:41:1:49:3 | self (M) | scopes.rb:41:1:49:3 | self | | scopes.rb:42:2:42:9 | ... = ... | scopes.rb:42:2:42:4 | var | +| scopes.rb:43:2:43:13 | ... = ... | scopes.rb:43:2:43:4 | foo | | scopes.rb:46:5:46:13 | ... = ... | scopes.rb:46:5:46:8 | var2 | | ssa.rb:1:1:16:3 | self (m) | ssa.rb:1:1:16:3 | self | | ssa.rb:1:7:1:7 | b | ssa.rb:1:7:1:7 | b | @@ -98,8 +102,10 @@ definition | ssa.rb:25:1:30:3 | | ssa.rb:26:7:26:10 | elem | | ssa.rb:25:1:30:3 | self (m2) | ssa.rb:25:1:30:3 | self | | ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | -| ssa.rb:26:7:26:10 | elem | ssa.rb:26:7:26:10 | elem | -| ssa.rb:26:12:26:22 | phi | ssa.rb:26:7:26:10 | elem | +| ssa.rb:26:3:28:5 | ... = ... | ssa.rb:26:7:26:10 | elem | +| ssa.rb:26:3:28:5 | | ssa.rb:25:1:30:3 | self | +| ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | +| ssa.rb:26:3:28:5 | call to each | ssa.rb:26:7:26:10 | elem | | ssa.rb:33:16:35:5 | | ssa.rb:32:1:36:3 | self | | ssa.rb:33:20:33:20 | x | ssa.rb:33:20:33:20 | x | | ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | @@ -264,11 +270,12 @@ read | ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:19:9:19:9 | x | | ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:20:10:20:10 | x | | ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:21:5:21:5 | x | -| ssa.rb:25:1:30:3 | self (m2) | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self | | ssa.rb:25:1:30:3 | self (m2) | ssa.rb:25:1:30:3 | self | ssa.rb:29:3:29:11 | self | | ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:26:15:26:22 | elements | -| ssa.rb:26:7:26:10 | elem | ssa.rb:26:7:26:10 | elem | ssa.rb:27:10:27:13 | elem | -| ssa.rb:26:12:26:22 | phi | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem | +| ssa.rb:26:3:28:5 | ... = ... | ssa.rb:26:7:26:10 | elem | ssa.rb:27:10:27:13 | elem | +| ssa.rb:26:3:28:5 | | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self | +| ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | +| ssa.rb:26:3:28:5 | call to each | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem | | ssa.rb:33:16:35:5 | | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self | | ssa.rb:33:20:33:20 | x | ssa.rb:33:20:33:20 | x | ssa.rb:34:10:34:10 | x | | ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:39:3:39:9 | self | @@ -392,11 +399,12 @@ firstRead | ssa.rb:10:5:10:9 | ... = ... | ssa.rb:2:3:2:3 | i | ssa.rb:11:10:11:10 | i | | ssa.rb:18:1:23:3 | self (m1) | ssa.rb:18:1:23:3 | self | ssa.rb:20:5:20:10 | self | | ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:19:9:19:9 | x | -| ssa.rb:25:1:30:3 | self (m2) | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self | | ssa.rb:25:1:30:3 | self (m2) | ssa.rb:25:1:30:3 | self | ssa.rb:29:3:29:11 | self | | ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:26:15:26:22 | elements | -| ssa.rb:26:7:26:10 | elem | ssa.rb:26:7:26:10 | elem | ssa.rb:27:10:27:13 | elem | -| ssa.rb:26:12:26:22 | phi | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem | +| ssa.rb:26:3:28:5 | ... = ... | ssa.rb:26:7:26:10 | elem | ssa.rb:27:10:27:13 | elem | +| ssa.rb:26:3:28:5 | | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self | +| ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | +| ssa.rb:26:3:28:5 | call to each | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem | | ssa.rb:33:16:35:5 | | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self | | ssa.rb:33:20:33:20 | x | ssa.rb:33:20:33:20 | x | ssa.rb:34:10:34:10 | x | | ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:39:3:39:9 | self | @@ -519,8 +527,10 @@ lastRead | ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:21:5:21:5 | x | | ssa.rb:25:1:30:3 | self (m2) | ssa.rb:25:1:30:3 | self | ssa.rb:29:3:29:11 | self | | ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:26:15:26:22 | elements | -| ssa.rb:26:7:26:10 | elem | ssa.rb:26:7:26:10 | elem | ssa.rb:27:10:27:13 | elem | -| ssa.rb:26:12:26:22 | phi | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem | +| ssa.rb:26:3:28:5 | ... = ... | ssa.rb:26:7:26:10 | elem | ssa.rb:27:10:27:13 | elem | +| ssa.rb:26:3:28:5 | | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self | +| ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | +| ssa.rb:26:3:28:5 | call to each | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem | | ssa.rb:33:16:35:5 | | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self | | ssa.rb:33:20:33:20 | x | ssa.rb:33:20:33:20 | x | ssa.rb:34:10:34:10 | x | | ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:41:3:41:13 | self | @@ -591,8 +601,6 @@ adjacentReads | ssa.rb:18:1:23:3 | self (m1) | ssa.rb:18:1:23:3 | self | ssa.rb:20:5:20:10 | self | ssa.rb:20:5:20:10 | self | | ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:19:9:19:9 | x | ssa.rb:20:10:20:10 | x | | ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:20:10:20:10 | x | ssa.rb:21:5:21:5 | x | -| ssa.rb:25:1:30:3 | self (m2) | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self | ssa.rb:27:5:27:13 | self | -| ssa.rb:25:1:30:3 | self (m2) | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self | ssa.rb:29:3:29:11 | self | | ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:39:3:39:9 | self | ssa.rb:39:8:39:9 | self | | ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:39:8:39:9 | self | ssa.rb:41:3:41:13 | self | | ssa.rb:66:11:70:5 | | ssa.rb:64:1:72:3 | self | ssa.rb:67:5:67:10 | self | ssa.rb:68:5:68:17 | self | @@ -608,8 +616,6 @@ phi | ssa.rb:5:3:13:5 | phi | ssa.rb:2:3:2:3 | i | ssa.rb:10:5:10:9 | ... = ... | | ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:18:8:18:8 | x | | ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:21:5:21:10 | ... = ... | -| ssa.rb:26:12:26:22 | phi | ssa.rb:26:7:26:10 | elem | ssa.rb:25:1:30:3 | | -| ssa.rb:26:12:26:22 | phi | ssa.rb:26:7:26:10 | elem | ssa.rb:26:7:26:10 | elem | | ssa.rb:45:3:45:12 | phi | ssa.rb:45:3:45:3 | x | ssa.rb:44:1:47:3 | | | ssa.rb:45:3:45:12 | phi | ssa.rb:45:3:45:3 | x | ssa.rb:45:3:45:7 | ... = ... | | ssa.rb:50:3:50:8 | phi | ssa.rb:49:14:49:14 | y | ssa.rb:49:1:51:3 | | diff --git a/ruby/ql/test/library-tests/variables/varaccess.expected b/ruby/ql/test/library-tests/variables/varaccess.expected index 332f3fa8af98..ff2e1af49bc4 100644 --- a/ruby/ql/test/library-tests/variables/varaccess.expected +++ b/ruby/ql/test/library-tests/variables/varaccess.expected @@ -316,6 +316,7 @@ explicitWrite | ssa.rb:10:5:10:5 | i | ssa.rb:10:5:10:9 | ... = ... | | ssa.rb:21:5:21:5 | x | ssa.rb:21:5:21:10 | ... -= ... | | ssa.rb:21:5:21:5 | x | ssa.rb:21:5:21:10 | ... = ... | +| ssa.rb:26:7:26:10 | elem | ssa.rb:26:3:28:5 | ... = ... | | ssa.rb:40:3:40:4 | m3 | ssa.rb:40:3:40:9 | ... = ... | | ssa.rb:45:3:45:3 | x | ssa.rb:45:3:45:7 | ... = ... | | ssa.rb:49:14:49:14 | y | ssa.rb:49:14:49:19 | ... = ... | @@ -358,6 +359,7 @@ implicitWrite | ssa.rb:1:7:1:7 | b | | ssa.rb:18:8:18:8 | x | | ssa.rb:25:8:25:15 | elements | +| ssa.rb:26:3:28:5 | __synth__0__1 | | ssa.rb:26:7:26:10 | elem | | ssa.rb:33:20:33:20 | x | | ssa.rb:44:8:44:8 | b | @@ -502,6 +504,7 @@ readAccess | ssa.rb:20:5:20:10 | self | | ssa.rb:20:10:20:10 | x | | ssa.rb:21:5:21:5 | x | +| ssa.rb:26:3:28:5 | __synth__0__1 | | ssa.rb:26:15:26:22 | elements | | ssa.rb:27:5:27:13 | self | | ssa.rb:27:10:27:13 | elem | diff --git a/ruby/ql/test/library-tests/variables/variable.expected b/ruby/ql/test/library-tests/variables/variable.expected index 4076efdeb883..0da853550735 100644 --- a/ruby/ql/test/library-tests/variables/variable.expected +++ b/ruby/ql/test/library-tests/variables/variable.expected @@ -123,6 +123,7 @@ | ssa.rb:18:8:18:8 | x | | ssa.rb:25:1:30:3 | self | | ssa.rb:25:8:25:15 | elements | +| ssa.rb:26:3:28:5 | __synth__0__1 | | ssa.rb:26:7:26:10 | elem | | ssa.rb:32:1:36:3 | self | | ssa.rb:33:20:33:20 | x | diff --git a/ruby/ql/test/library-tests/variables/varscopes.expected b/ruby/ql/test/library-tests/variables/varscopes.expected index 090243e57a80..70db175cfe0f 100644 --- a/ruby/ql/test/library-tests/variables/varscopes.expected +++ b/ruby/ql/test/library-tests/variables/varscopes.expected @@ -59,6 +59,7 @@ | ssa.rb:1:1:88:3 | ssa.rb | | ssa.rb:18:1:23:3 | m1 | | ssa.rb:25:1:30:3 | m2 | +| ssa.rb:26:3:28:5 | { ... } | | ssa.rb:32:1:36:3 | m3 | | ssa.rb:33:16:35:5 | do ... end | | ssa.rb:38:1:42:3 | m4 |