mirror of
https://github.com/github/codeql.git
synced 2026-02-20 00:43:44 +01:00
CFG: Implement logic for rescue-ensure blocks
This commit is contained in:
@@ -186,12 +186,17 @@ module SuccessorTypes {
|
||||
|
||||
/**
|
||||
* A conditional control flow successor. Either a Boolean successor (`BooleanSuccessor`),
|
||||
* or an emptiness successor (`EmptinessSuccessor`).
|
||||
* an emptiness successor (`EmptinessSuccessor`), or a matching successor
|
||||
* (`MatchingSuccessor`)
|
||||
*/
|
||||
class ConditionalSuccessor extends SuccessorType {
|
||||
boolean value;
|
||||
|
||||
ConditionalSuccessor() { this = TBooleanSuccessor(value) or this = TEmptinessSuccessor(value) }
|
||||
ConditionalSuccessor() {
|
||||
this = TBooleanSuccessor(value) or
|
||||
this = TEmptinessSuccessor(value) or
|
||||
this = TMatchingSuccessor(value)
|
||||
}
|
||||
|
||||
/** Gets the Boolean value of this successor. */
|
||||
final boolean getValue() { result = value }
|
||||
@@ -248,12 +253,38 @@ module SuccessorTypes {
|
||||
* ```
|
||||
*/
|
||||
class EmptinessSuccessor extends ConditionalSuccessor, TEmptinessSuccessor {
|
||||
/** Holds if this is an empty successor. */
|
||||
predicate isEmpty() { value = true }
|
||||
override string toString() { if value = true then result = "empty" else result = "non-empty" }
|
||||
}
|
||||
|
||||
final override string toString() {
|
||||
if this.isEmpty() then result = "empty" else result = "non-empty"
|
||||
}
|
||||
/**
|
||||
* A matching control flow successor.
|
||||
*
|
||||
* For example, this program fragment:
|
||||
*
|
||||
* ```rb
|
||||
* case x
|
||||
* when 1 then puts "one"
|
||||
* else puts "not one"
|
||||
* end
|
||||
* ```
|
||||
*
|
||||
* has a control flow graph containing matching successors:
|
||||
*
|
||||
* ```
|
||||
* x
|
||||
* |
|
||||
* 1
|
||||
* / \
|
||||
* / \
|
||||
* / \
|
||||
* / \
|
||||
* match non-match
|
||||
* | |
|
||||
* puts "one" puts "not one"
|
||||
* ```
|
||||
*/
|
||||
class MatchingSuccessor extends ConditionalSuccessor, TMatchingSuccessor {
|
||||
override string toString() { if value = true then result = "match" else result = "no-match" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,13 +7,15 @@
|
||||
private import codeql_ruby.ast.internal.TreeSitter::Generated
|
||||
private import codeql_ruby.controlflow.ControlFlowGraph
|
||||
private import AstNodes
|
||||
private import ControlFlowGraphImpl
|
||||
private import NonReturning
|
||||
private import SuccessorTypes
|
||||
|
||||
private newtype TCompletion =
|
||||
TSimpleCompletion() or
|
||||
TBooleanCompletion(boolean b) { b = true or b = false } or
|
||||
TEmptinessCompletion(boolean isEmpty) { isEmpty = true or isEmpty = false } 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
|
||||
TNextCompletion() or
|
||||
@@ -21,11 +23,35 @@ private newtype TCompletion =
|
||||
TRetryCompletion() or
|
||||
TRaiseCompletion() or // TODO: Add exception type?
|
||||
TExitCompletion() or
|
||||
TNestedCompletion(Completion inner, Completion outer) {
|
||||
outer = TSimpleCompletion() and
|
||||
inner = TBreakCompletion()
|
||||
TNestedCompletion(Completion inner, Completion outer, int nestLevel) {
|
||||
inner = TBreakCompletion() and
|
||||
outer instanceof NonNestedNormalCompletion and
|
||||
nestLevel = 0
|
||||
or
|
||||
inner instanceof NormalCompletion and
|
||||
nestedEnsureCompletion(outer, nestLevel)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate nestedEnsureCompletion(Completion outer, int nestLevel) {
|
||||
(
|
||||
outer = TReturnCompletion()
|
||||
or
|
||||
outer = TBreakCompletion()
|
||||
or
|
||||
outer = TNextCompletion()
|
||||
or
|
||||
outer = TRedoCompletion()
|
||||
or
|
||||
outer = TRetryCompletion()
|
||||
or
|
||||
outer = TRaiseCompletion()
|
||||
or
|
||||
outer = TExitCompletion()
|
||||
) and
|
||||
nestLevel = any(Trees::RescueEnsureBlockTree t).nestLevel()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate completionIsValidForStmt(AstNode n, Completion c) {
|
||||
n instanceof Break and
|
||||
@@ -57,11 +83,15 @@ abstract class Completion extends TCompletion {
|
||||
this = TBooleanCompletion(_)
|
||||
)
|
||||
or
|
||||
mustHaveMatchingCompletion(n) and
|
||||
this = TMatchingCompletion(_)
|
||||
or
|
||||
n = any(RescueModifier parent).getBody() and this = TRaiseCompletion()
|
||||
or
|
||||
not n instanceof NonReturningCall and
|
||||
not completionIsValidForStmt(n, _) and
|
||||
not mustHaveBooleanCompletion(n) and
|
||||
not mustHaveMatchingCompletion(n) and
|
||||
this = TSimpleCompletion()
|
||||
}
|
||||
|
||||
@@ -143,14 +173,30 @@ private predicate inBooleanContext(AstNode n) {
|
||||
n instanceof Pattern
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a normal completion of `n` must be a matching completion.
|
||||
*/
|
||||
private predicate mustHaveMatchingCompletion(AstNode n) {
|
||||
inMatchingContext(n) and
|
||||
not n instanceof NonReturningCall
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` is used in a matching context. That is, whether or
|
||||
* not the value of `n` matches, determines the successor.
|
||||
*/
|
||||
private predicate inMatchingContext(AstNode n) { n = any(Rescue r).getExceptions().getChild(_) }
|
||||
|
||||
/**
|
||||
* A completion that represents normal evaluation of a statement or an
|
||||
* expression.
|
||||
*/
|
||||
abstract class NormalCompletion extends Completion { }
|
||||
|
||||
abstract private class NonNestedNormalCompletion extends NormalCompletion { }
|
||||
|
||||
/** A simple (normal) completion. */
|
||||
class SimpleCompletion extends NormalCompletion, TSimpleCompletion {
|
||||
class SimpleCompletion extends NonNestedNormalCompletion, TSimpleCompletion {
|
||||
override NormalSuccessor getAMatchingSuccessorType() { any() }
|
||||
|
||||
override string toString() { result = "simple" }
|
||||
@@ -158,10 +204,13 @@ class SimpleCompletion extends NormalCompletion, TSimpleCompletion {
|
||||
|
||||
/**
|
||||
* A completion that represents evaluation of an expression, whose value determines
|
||||
* the successor. Either a Boolean completion (`BooleanCompletion`)
|
||||
* or an emptiness completion (`EmptinessCompletion`).
|
||||
* the successor. Either a Boolean completion (`BooleanCompletion`), an emptiness
|
||||
* completion (`EmptinessCompletion`), or a matching completion (`MatchingCompletion`).
|
||||
*/
|
||||
abstract class ConditionalCompletion extends NormalCompletion { }
|
||||
abstract class ConditionalCompletion extends NonNestedNormalCompletion {
|
||||
/** Gets the Boolean value of this conditional completion. */
|
||||
abstract boolean getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* A completion that represents evaluation of an expression
|
||||
@@ -172,8 +221,7 @@ class BooleanCompletion extends ConditionalCompletion, TBooleanCompletion {
|
||||
|
||||
BooleanCompletion() { this = TBooleanCompletion(value) }
|
||||
|
||||
/** Gets the Boolean value of this completion. */
|
||||
boolean getValue() { result = value }
|
||||
override boolean getValue() { result = value }
|
||||
|
||||
/** Gets the dual Boolean completion. */
|
||||
BooleanCompletion getDual() { result = TBooleanCompletion(value.booleanNot()) }
|
||||
@@ -198,84 +246,157 @@ class FalseCompletion extends BooleanCompletion {
|
||||
* a test in a `for in` statement.
|
||||
*/
|
||||
class EmptinessCompletion extends ConditionalCompletion, TEmptinessCompletion {
|
||||
/** Holds if the emptiness test evaluates to `true`. */
|
||||
predicate isEmpty() { this = TEmptinessCompletion(true) }
|
||||
private boolean value;
|
||||
|
||||
override EmptinessSuccessor getAMatchingSuccessorType() {
|
||||
if isEmpty() then result.getValue() = true else result.getValue() = false
|
||||
}
|
||||
EmptinessCompletion() { this = TEmptinessCompletion(value) }
|
||||
|
||||
override string toString() { if this.isEmpty() then result = "empty" else result = "non-empty" }
|
||||
override boolean getValue() { result = 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.
|
||||
*/
|
||||
class MatchingCompletion extends ConditionalCompletion, TMatchingCompletion {
|
||||
private boolean value;
|
||||
|
||||
MatchingCompletion() { this = TMatchingCompletion(value) }
|
||||
|
||||
override boolean getValue() { result = value }
|
||||
|
||||
override MatchingSuccessor getAMatchingSuccessorType() { result.getValue() = value }
|
||||
|
||||
override string toString() { if value = true then result = "match" else result = "no-match" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A completion that represents evaluation of a statement or an
|
||||
* expression resulting in a return.
|
||||
*/
|
||||
class ReturnCompletion extends Completion, TReturnCompletion {
|
||||
class ReturnCompletion extends Completion {
|
||||
ReturnCompletion() {
|
||||
this = TReturnCompletion() or
|
||||
this = TNestedCompletion(_, TReturnCompletion(), _)
|
||||
}
|
||||
|
||||
override ReturnSuccessor getAMatchingSuccessorType() { any() }
|
||||
|
||||
override string toString() { result = "return" }
|
||||
override string toString() {
|
||||
// `NestedCompletion` defines `toString()` for the other case
|
||||
this = TReturnCompletion() and result = "return"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A completion that represents evaluation of a statement or an
|
||||
* expression resulting in a break from a loop.
|
||||
*/
|
||||
class BreakCompletion extends Completion, TBreakCompletion {
|
||||
class BreakCompletion extends Completion {
|
||||
BreakCompletion() {
|
||||
this = TBreakCompletion() or
|
||||
this = TNestedCompletion(_, TBreakCompletion(), _)
|
||||
}
|
||||
|
||||
override BreakSuccessor getAMatchingSuccessorType() { any() }
|
||||
|
||||
override string toString() { result = "break" }
|
||||
override string toString() {
|
||||
// `NestedCompletion` defines `toString()` for the other case
|
||||
this = TBreakCompletion() and result = "break"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A completion that represents evaluation of a statement or an
|
||||
* expression resulting in a continuation of a loop.
|
||||
*/
|
||||
class NextCompletion extends Completion, TNextCompletion {
|
||||
class NextCompletion extends Completion {
|
||||
NextCompletion() {
|
||||
this = TNextCompletion() or
|
||||
this = TNestedCompletion(_, TNextCompletion(), _)
|
||||
}
|
||||
|
||||
override NextSuccessor getAMatchingSuccessorType() { any() }
|
||||
|
||||
override string toString() { result = "next" }
|
||||
override string toString() {
|
||||
// `NestedCompletion` defines `toString()` for the other case
|
||||
this = TNextCompletion() and result = "next"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A completion that represents evaluation of a statement or an
|
||||
* expression resulting in a redo of a loop iteration.
|
||||
*/
|
||||
class RedoCompletion extends Completion, TRedoCompletion {
|
||||
class RedoCompletion extends Completion {
|
||||
RedoCompletion() {
|
||||
this = TRedoCompletion() or
|
||||
this = TNestedCompletion(_, TRedoCompletion(), _)
|
||||
}
|
||||
|
||||
override RedoSuccessor getAMatchingSuccessorType() { any() }
|
||||
|
||||
override string toString() { result = "redo" }
|
||||
override string toString() {
|
||||
// `NestedCompletion` defines `toString()` for the other case
|
||||
this = TRedoCompletion() and result = "redo"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A completion that represents evaluation of a statement or an
|
||||
* expression resulting in a retry.
|
||||
*/
|
||||
class RetryCompletion extends Completion, TRetryCompletion {
|
||||
class RetryCompletion extends Completion {
|
||||
RetryCompletion() {
|
||||
this = TRetryCompletion() or
|
||||
this = TNestedCompletion(_, TRetryCompletion(), _)
|
||||
}
|
||||
|
||||
override RetrySuccessor getAMatchingSuccessorType() { any() }
|
||||
|
||||
override string toString() { result = "retry" }
|
||||
override string toString() {
|
||||
// `NestedCompletion` defines `toString()` for the other case
|
||||
this = TRetryCompletion() and result = "retry"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A completion that represents evaluation of a statement or an
|
||||
* expression resulting in a thrown exception.
|
||||
*/
|
||||
class RaiseCompletion extends Completion, TRaiseCompletion {
|
||||
class RaiseCompletion extends Completion {
|
||||
RaiseCompletion() {
|
||||
this = TRaiseCompletion() or
|
||||
this = TNestedCompletion(_, TRaiseCompletion(), _)
|
||||
}
|
||||
|
||||
override RaiseSuccessor getAMatchingSuccessorType() { any() }
|
||||
|
||||
override string toString() { result = "raise" }
|
||||
override string toString() {
|
||||
// `NestedCompletion` defines `toString()` for the other case
|
||||
this = TRaiseCompletion() and result = "raise"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A completion that represents evaluation of a statement or an
|
||||
* expression resulting in an abort/exit.
|
||||
*/
|
||||
class ExitCompletion extends Completion, TExitCompletion {
|
||||
class ExitCompletion extends Completion {
|
||||
ExitCompletion() {
|
||||
this = TExitCompletion() or
|
||||
this = TNestedCompletion(_, TExitCompletion(), _)
|
||||
}
|
||||
|
||||
override ExitSuccessor getAMatchingSuccessorType() { any() }
|
||||
|
||||
override string toString() { result = "exit" }
|
||||
override string toString() {
|
||||
// `NestedCompletion` defines `toString()` for the other case
|
||||
this = TExitCompletion() and result = "exit"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -296,25 +417,60 @@ class ExitCompletion extends Completion, TExitCompletion {
|
||||
* the `while` loop can have a nested completion where the inner completion
|
||||
* is a `break` and the outer completion is a simple successor.
|
||||
*/
|
||||
class NestedCompletion extends Completion, TNestedCompletion {
|
||||
abstract class NestedCompletion extends Completion, TNestedCompletion {
|
||||
Completion inner;
|
||||
Completion outer;
|
||||
int nestLevel;
|
||||
|
||||
NestedCompletion() { this = TNestedCompletion(inner, outer) }
|
||||
NestedCompletion() { this = TNestedCompletion(inner, outer, nestLevel) }
|
||||
|
||||
override Completion getInnerCompletion() { result = inner }
|
||||
/** Gets a completion that is compatible with the inner completion. */
|
||||
abstract Completion getAnInnerCompatibleCompletion();
|
||||
|
||||
/** Gets the level of this nested completion. */
|
||||
final int getNestLevel() { result = nestLevel }
|
||||
|
||||
override string toString() { result = outer + " [" + inner + "] (" + nestLevel + ")" }
|
||||
}
|
||||
|
||||
class NestedBreakCompletion extends NormalCompletion, NestedCompletion {
|
||||
NestedBreakCompletion() {
|
||||
inner = TBreakCompletion() and
|
||||
outer instanceof NonNestedNormalCompletion
|
||||
}
|
||||
|
||||
override BreakCompletion getInnerCompletion() { result = inner }
|
||||
|
||||
override NonNestedNormalCompletion getOuterCompletion() { result = outer }
|
||||
|
||||
override Completion getAnInnerCompatibleCompletion() {
|
||||
result = inner and
|
||||
outer = TSimpleCompletion()
|
||||
or
|
||||
result = TNestedCompletion(outer, inner, _)
|
||||
}
|
||||
|
||||
override SuccessorType getAMatchingSuccessorType() {
|
||||
outer instanceof SimpleCompletion and
|
||||
result instanceof BreakSuccessor
|
||||
or
|
||||
result = outer.(ConditionalCompletion).getAMatchingSuccessorType()
|
||||
}
|
||||
}
|
||||
|
||||
class NestedEnsureCompletion extends NestedCompletion {
|
||||
NestedEnsureCompletion() {
|
||||
inner instanceof NormalCompletion and
|
||||
nestedEnsureCompletion(outer, nestLevel)
|
||||
}
|
||||
|
||||
override NormalCompletion getInnerCompletion() { result = inner }
|
||||
|
||||
override Completion getOuterCompletion() { result = outer }
|
||||
|
||||
override SuccessorType getAMatchingSuccessorType() {
|
||||
inner = TBreakCompletion() and
|
||||
outer = TSimpleCompletion() and
|
||||
result instanceof BreakSuccessor
|
||||
override Completion getAnInnerCompatibleCompletion() {
|
||||
result.getOuterCompletion() = this.getInnerCompletion()
|
||||
}
|
||||
|
||||
override string toString() { result = outer + " [" + inner + "]" }
|
||||
}
|
||||
|
||||
private class NestedNormalCompletion extends NormalCompletion, NestedCompletion {
|
||||
NestedNormalCompletion() { outer instanceof NormalCompletion }
|
||||
override SuccessorType getAMatchingSuccessorType() { none() }
|
||||
}
|
||||
|
||||
@@ -38,6 +38,14 @@ private import Completion
|
||||
private import SuccessorTypes
|
||||
private import Splitting
|
||||
|
||||
private AstNode parent(AstNode n) {
|
||||
result.getAFieldOrChild() = n and
|
||||
not n instanceof CfgScope
|
||||
}
|
||||
|
||||
/** Gets the CFG scope of node `n`. */
|
||||
CfgScope getScope(AstNode n) { result = parent+(n) }
|
||||
|
||||
abstract private class ControlFlowTree extends AstNode {
|
||||
/**
|
||||
* Holds if `first` is the first element executed within this AST node.
|
||||
@@ -227,7 +235,7 @@ abstract private class LeafTree extends PreOrderTree, PostOrderTree {
|
||||
}
|
||||
|
||||
/** Defines the CFG by dispatch on the various AST types. */
|
||||
private module Trees {
|
||||
module Trees {
|
||||
private class AliasTree extends StandardPreOrderTree, Alias {
|
||||
final override AstNode getChildNode(int i) {
|
||||
i = 0 and result = this.getName()
|
||||
@@ -262,12 +270,9 @@ private module Trees {
|
||||
final override Interpolation getChildNode(int i) { result = this.getChild(i) }
|
||||
}
|
||||
|
||||
private class BeginTree extends StandardPreOrderTree, Begin {
|
||||
final override AstNode getChildNode(int i) {
|
||||
result = this.getChild(i) and
|
||||
not result instanceof Rescue and
|
||||
not result instanceof Else and
|
||||
not result instanceof Ensure
|
||||
private class BeginTree extends RescueEnsureBlockTree, Begin {
|
||||
final override AstNode getChildNode(int i, boolean rescuable) {
|
||||
result = this.getChild(i) and rescuable = true
|
||||
}
|
||||
|
||||
override predicate isHidden() { any() }
|
||||
@@ -370,11 +375,14 @@ private module Trees {
|
||||
|
||||
private class CharacterTree extends LeafTree, Character { }
|
||||
|
||||
private class ClassTree extends StandardPreOrderTree, Class {
|
||||
final override AstNode getChildNode(int i) {
|
||||
result = this.getName() and i = 0
|
||||
or
|
||||
result = this.getChild(i - 1)
|
||||
private class ClassTree extends RescueEnsureBlockTree, Class {
|
||||
final override AstNode getChildNode(int i, boolean rescuable) {
|
||||
rescuable = true and
|
||||
(
|
||||
result = this.getName() and i = 0
|
||||
or
|
||||
result = this.getChild(i - 1)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,11 +407,11 @@ private module Trees {
|
||||
override predicate isHidden() { any() }
|
||||
}
|
||||
|
||||
private class DoBlockTree extends StandardPreOrderTree, DoBlock {
|
||||
final override AstNode getChildNode(int i) {
|
||||
result = this.getParameters() and i = 0
|
||||
private class DoBlockTree extends RescueEnsureBlockTree, DoBlock {
|
||||
final override AstNode getChildNode(int i, boolean rescuable) {
|
||||
result = this.getParameters() and i = 0 and rescuable = false
|
||||
or
|
||||
result = this.getChild(i - 1)
|
||||
result = this.getChild(i - 1) and rescuable = true
|
||||
}
|
||||
|
||||
override predicate isHidden() { any() }
|
||||
@@ -431,8 +439,6 @@ private module Trees {
|
||||
|
||||
private class EnsureTree extends StandardPreOrderTree, Ensure {
|
||||
final override AstNode getChildNode(int i) { result = this.getChild(i) }
|
||||
|
||||
override predicate isHidden() { any() }
|
||||
}
|
||||
|
||||
private class EscapeSequenceTree extends LeafTree, EscapeSequence { }
|
||||
@@ -443,8 +449,58 @@ private module Trees {
|
||||
override predicate isHidden() { any() }
|
||||
}
|
||||
|
||||
private class ExceptionsTree extends StandardPostOrderTree, Exceptions {
|
||||
final override AstNode getChildNode(int i) { result = this.getChild(i) }
|
||||
private class ExceptionsTree extends PreOrderTree, Exceptions {
|
||||
final override predicate propagatesAbnormal(AstNode child) { none() }
|
||||
|
||||
/** Holds if this exception filter belongs to a final `rescue` block. */
|
||||
pragma[noinline]
|
||||
private predicate inLastRescue() {
|
||||
exists(RescueEnsureBlockTree block, Rescue rescue, int i |
|
||||
rescue = block.getRescue(i) and
|
||||
this = rescue.getExceptions() and
|
||||
not exists(block.getRescue(i + 1))
|
||||
)
|
||||
}
|
||||
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
last(this.getChild(_), last, c) and
|
||||
c.(MatchingCompletion).getValue() = true
|
||||
or
|
||||
exists(int lst, Completion c0 |
|
||||
last(this.getChild(lst), last, c0) and
|
||||
not exists(this.getChild(lst + 1))
|
||||
|
|
||||
// The last exception filter in a last `rescue` block propagates
|
||||
// the exception when it doesn't match
|
||||
this.inLastRescue() and
|
||||
c =
|
||||
any(NestedEnsureCompletion nec |
|
||||
nec.getOuterCompletion() instanceof RaiseCompletion and
|
||||
nec.getInnerCompletion() = c0 and
|
||||
c0.(MatchingCompletion).getValue() = false and
|
||||
nec.getNestLevel() = 0
|
||||
)
|
||||
or
|
||||
c = c0 and
|
||||
(
|
||||
not this.inLastRescue()
|
||||
or
|
||||
not c0.(MatchingCompletion).getValue() = false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
pred = this and
|
||||
first(this.getChild(0), succ) and
|
||||
c instanceof SimpleCompletion
|
||||
or
|
||||
exists(int i |
|
||||
last(this.getChild(i), pred, c) and
|
||||
c.(MatchingCompletion).getValue() = false and
|
||||
first(this.getChild(i + 1), succ)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isHidden() { any() }
|
||||
}
|
||||
@@ -493,18 +549,14 @@ private module Trees {
|
||||
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
last = this and
|
||||
c.(EmptinessCompletion).isEmpty()
|
||||
c.(EmptinessCompletion).getValue() = true
|
||||
or
|
||||
last(this.getBody(), last, c) and
|
||||
not c.continuesLoop() and
|
||||
not c instanceof BreakCompletion and
|
||||
not c instanceof RedoCompletion
|
||||
or
|
||||
c =
|
||||
any(NestedCompletion nc |
|
||||
last(this.getBody(), last, nc.getInnerCompletion().(BreakCompletion)) and
|
||||
nc.getOuterCompletion() instanceof SimpleCompletion
|
||||
)
|
||||
last(this.getBody(), last, c.(NestedBreakCompletion).getAnInnerCompatibleCompletion())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -521,8 +573,7 @@ private module Trees {
|
||||
or
|
||||
pred = this and
|
||||
first(this.getPattern(0), succ) and
|
||||
c instanceof EmptinessCompletion and
|
||||
not c.(EmptinessCompletion).isEmpty()
|
||||
c.(EmptinessCompletion).getValue() = false
|
||||
or
|
||||
exists(int i, ControlFlowTree next |
|
||||
last(this.getPattern(i), pred, c) and
|
||||
@@ -719,11 +770,11 @@ private module Trees {
|
||||
}
|
||||
}
|
||||
|
||||
private class MethodTree extends StandardPreOrderTree, Method {
|
||||
final override AstNode getChildNode(int i) {
|
||||
result = this.getParameters() and i = 0
|
||||
private class MethodTree extends RescueEnsureBlockTree, Method {
|
||||
final override AstNode getChildNode(int i, boolean rescuable) {
|
||||
result = this.getParameters() and i = 0 and rescuable = false
|
||||
or
|
||||
result = this.getChild(i - 1)
|
||||
result = this.getChild(i - 1) and rescuable = true
|
||||
}
|
||||
|
||||
override predicate isHidden() { any() }
|
||||
@@ -744,11 +795,14 @@ private module Trees {
|
||||
override predicate isHidden() { any() }
|
||||
}
|
||||
|
||||
private class ModuleTree extends StandardPreOrderTree, Module {
|
||||
final override AstNode getChildNode(int i) {
|
||||
result = this.getName() and i = 0
|
||||
or
|
||||
result = this.getChild(i - 1)
|
||||
private class ModuleTree extends RescueEnsureBlockTree, Module {
|
||||
final override AstNode getChildNode(int i, boolean rescuable) {
|
||||
rescuable = true and
|
||||
(
|
||||
result = this.getName() and i = 0
|
||||
or
|
||||
result = this.getChild(i - 1)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -809,13 +863,272 @@ private module Trees {
|
||||
final override Interpolation getChildNode(int i) { result = this.getChild(i) }
|
||||
}
|
||||
|
||||
private class RescueTree extends StandardPreOrderTree, Rescue {
|
||||
final override AstNode getChildNode(int i) {
|
||||
result = this.getExceptions() and i = 0
|
||||
private class RescueTree extends PreOrderTree, Rescue {
|
||||
final override predicate propagatesAbnormal(AstNode child) { child = this.getExceptions() }
|
||||
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
last(this.getExceptions(), last, c) and
|
||||
c.(MatchingCompletion).getValue() = false
|
||||
or
|
||||
result = this.getVariable() and i = 1
|
||||
last(this.getBody(), last, c)
|
||||
or
|
||||
result = this.getBody() and i = 2
|
||||
not exists(this.getExceptions()) and
|
||||
not exists(this.getBody()) and
|
||||
(
|
||||
last(this.getVariable(), last, c)
|
||||
or
|
||||
not exists(this.getVariable()) and
|
||||
last = this and
|
||||
c.isValidFor(this)
|
||||
)
|
||||
}
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
exists(AstNode next |
|
||||
pred = this and
|
||||
first(next, succ) and
|
||||
c instanceof SimpleCompletion
|
||||
|
|
||||
next = this.getExceptions()
|
||||
or
|
||||
not exists(this.getExceptions()) and
|
||||
(
|
||||
next = this.getVariable()
|
||||
or
|
||||
not exists(this.getVariable()) and
|
||||
next = this.getBody()
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(AstNode next |
|
||||
last(this.getExceptions(), pred, c) and
|
||||
first(next, succ) and
|
||||
c.(MatchingCompletion).getValue() = true
|
||||
|
|
||||
next = this.getVariable()
|
||||
or
|
||||
not exists(this.getVariable()) and
|
||||
next = this.getBody()
|
||||
)
|
||||
or
|
||||
last(this.getVariable(), pred, c) and
|
||||
first(this.getBody(), succ) and
|
||||
c instanceof NormalCompletion
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets a child of `n` that is in CFG scope `scope`. */
|
||||
pragma[noinline]
|
||||
private AstNode getAChildInScope(AstNode n, CfgScope scope) {
|
||||
result.getParent() = n and
|
||||
scope = getScope(result)
|
||||
}
|
||||
|
||||
/** A block that may contain `rescue`/`ensure`. */
|
||||
abstract class RescueEnsureBlockTree extends PreOrderTree {
|
||||
/**
|
||||
* Gets the `i`th child of this block. `rescuable` indicates whether exceptional
|
||||
* execution of the child can be caught by `rescue`/`ensure`.
|
||||
*/
|
||||
abstract AstNode getChildNode(int i, boolean rescuable);
|
||||
|
||||
/** Gets the `i`th child in the body of this block. */
|
||||
final private AstNode getBodyChild(int i, boolean rescuable) {
|
||||
result = this.getChildNode(_, rescuable) and
|
||||
result =
|
||||
rank[i + 1](AstNode child, int j |
|
||||
child = this.getChildNode(j, _) and
|
||||
not result instanceof Rescue and
|
||||
not result instanceof Ensure and
|
||||
not result instanceof Else and
|
||||
not child instanceof CfgScope
|
||||
|
|
||||
child order by j
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `i`th `rescue` block in this block. */
|
||||
final Rescue getRescue(int i) {
|
||||
result = rank[i + 1](Rescue s | s = this.getAFieldOrChild() | s order by s.getParentIndex())
|
||||
}
|
||||
|
||||
/** Gets the `else` block in this block, if any. */
|
||||
final private Else getElse() { result = unique(Else s | s = this.getAFieldOrChild()) }
|
||||
|
||||
/** Gets the `ensure` block in this block, if any. */
|
||||
final Ensure getEnsure() { result = unique(Ensure s | s = this.getAFieldOrChild()) }
|
||||
|
||||
final private predicate hasEnsure() { exists(this.getEnsure()) }
|
||||
|
||||
final override predicate propagatesAbnormal(AstNode child) { child = this.getEnsure() }
|
||||
|
||||
/**
|
||||
* Gets a descendant that belongs to the `ensure` block of this block, if any.
|
||||
* Nested `ensure` blocks are not included.
|
||||
*/
|
||||
AstNode getAnEnsureDescendant() {
|
||||
result = this.getEnsure()
|
||||
or
|
||||
exists(AstNode mid |
|
||||
mid = this.getAnEnsureDescendant() and
|
||||
result = getAChildInScope(mid, getScope(mid)) and
|
||||
not exists(RescueEnsureBlockTree nestedBlock |
|
||||
result = nestedBlock.getEnsure() and
|
||||
nestedBlock != this
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `innerBlock` has an `ensure` block and is immediately nested inside the
|
||||
* `ensure` block of this block.
|
||||
*/
|
||||
private predicate nestedEnsure(RescueEnsureBlockTree innerBlock) {
|
||||
exists(Ensure innerEnsure |
|
||||
innerEnsure = getAChildInScope(this.getAnEnsureDescendant(), getScope(this)) and
|
||||
innerEnsure = innerBlock.getEnsure()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `ensure`-nesting level of this block. That is, the number of `ensure`
|
||||
* blocks that this block is nested under.
|
||||
*/
|
||||
int nestLevel() { result = count(RescueEnsureBlockTree outer | outer.nestedEnsure+(this)) }
|
||||
|
||||
/**
|
||||
* Holds if `last` is a last element in the body of this block. `ensurable`
|
||||
* indicates whether `last` may be a predecessor of an `ensure` block.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate lastBody(AstNode last, Completion c, boolean ensurable) {
|
||||
exists(boolean rescuable |
|
||||
if c instanceof RaiseCompletion then ensurable = rescuable else ensurable = true
|
||||
|
|
||||
last(this.getBodyChild(_, rescuable), last, c) and
|
||||
not c instanceof NormalCompletion
|
||||
or
|
||||
exists(int lst |
|
||||
last(this.getBodyChild(lst, rescuable), last, c) and
|
||||
not exists(this.getBodyChild(lst + 1, _))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a last element from this block that may finish with completion `c`, such
|
||||
* that control may be transferred to the `ensure` block (if it exists), but only
|
||||
* if `ensurable = true`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private AstNode getAnEnsurePredecessor(Completion c, boolean ensurable) {
|
||||
exists(boolean ensurable0 |
|
||||
// Exit completions ignore the `ensure` block (TODO: CHECK THIS)
|
||||
if c instanceof ExitCompletion then ensurable = false else ensurable = ensurable0
|
||||
|
|
||||
this.lastBody(result, c, ensurable0) and
|
||||
(
|
||||
// Any non-throw completion will always continue directly to the `ensure` block,
|
||||
// unless there is an `else` block
|
||||
not c instanceof RaiseCompletion and
|
||||
not exists(this.getElse())
|
||||
or
|
||||
// Any completion will continue to the `ensure` block when there are no `rescue`
|
||||
// blocks
|
||||
not exists(this.getRescue(_))
|
||||
)
|
||||
or
|
||||
// Last element from any of the `rescue` blocks continues to the `ensure` block
|
||||
last(this.getRescue(_).getBody(), result, c) and
|
||||
ensurable0 = true
|
||||
or
|
||||
// Last element of last `rescue` block continues to the `ensure` block
|
||||
exists(int lst |
|
||||
last(this.getRescue(lst), result, c) and
|
||||
not exists(this.getRescue(lst + 1)) and
|
||||
ensurable0 = true
|
||||
)
|
||||
or
|
||||
// Last element of `else` block continues to the `ensure` block
|
||||
last(this.getElse(), result, c) and
|
||||
ensurable0 = true
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate lastEnsure0(AstNode last, Completion c) { last(this.getEnsure(), last, c) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate lastEnsure(
|
||||
AstNode last, NormalCompletion ensure, Completion outer, int nestLevel
|
||||
) {
|
||||
this.lastEnsure0(last, ensure) and
|
||||
exists(
|
||||
this.getAnEnsurePredecessor(any(Completion c0 | outer = c0.getOuterCompletion()), true)
|
||||
) and
|
||||
nestLevel = this.nestLevel()
|
||||
}
|
||||
|
||||
override predicate last(AstNode last, Completion c) {
|
||||
exists(boolean ensurable | last = this.getAnEnsurePredecessor(c, ensurable) |
|
||||
not this.hasEnsure()
|
||||
or
|
||||
ensurable = false
|
||||
)
|
||||
or
|
||||
// If the body completes normally, take the completion from the `ensure` block
|
||||
this.lastEnsure(last, c, any(NormalCompletion nc), _)
|
||||
or
|
||||
// If the `ensure` block completes normally, it inherits any non-normal
|
||||
// completion from the body
|
||||
c =
|
||||
any(NestedEnsureCompletion nec |
|
||||
this
|
||||
.lastEnsure(last, nec.getAnInnerCompatibleCompletion(), nec.getOuterCompletion(),
|
||||
nec.getNestLevel())
|
||||
)
|
||||
}
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
pred = this and
|
||||
first(this.getBodyChild(0, _), succ) and
|
||||
c instanceof SimpleCompletion
|
||||
or
|
||||
// Normal left-to-right evaluation in the body
|
||||
exists(int i |
|
||||
last(this.getBodyChild(i, _), pred, c) and
|
||||
first(this.getBodyChild(i + 1, _), succ) and
|
||||
c instanceof NormalCompletion
|
||||
)
|
||||
or
|
||||
// Exceptional flow from body to first `rescue`
|
||||
this.lastBody(pred, c, true) and
|
||||
first(this.getRescue(0), succ) and
|
||||
c instanceof RaiseCompletion
|
||||
or
|
||||
exists(Rescue rescue, int i | rescue = this.getRescue(i) |
|
||||
pred = rescue and
|
||||
last(this.getRescue(i), rescue, c) and
|
||||
(
|
||||
// Flow from one `rescue` clause to the next when there is no match
|
||||
first(this.getRescue(i + 1), succ) and
|
||||
c.(MatchingCompletion).getValue() = false
|
||||
or
|
||||
// Flow from last `rescue` clause to `ensure` block
|
||||
not exists(this.getRescue(i + 1)) and
|
||||
first(this.getEnsure(), succ) and
|
||||
c.getInnerCompletion().(MatchingCompletion).getValue() = false
|
||||
)
|
||||
)
|
||||
or
|
||||
// Flow from body to `else` block when no exception
|
||||
this.lastBody(pred, c, _) and
|
||||
first(this.getElse(), succ) and
|
||||
c instanceof NormalCompletion
|
||||
or
|
||||
// Flow into `ensure` block
|
||||
pred = getAnEnsurePredecessor(c, true) and
|
||||
first(this.getEnsure(), succ)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -870,23 +1183,31 @@ private module Trees {
|
||||
|
||||
private class SetterTree extends LeafTree, Setter { }
|
||||
|
||||
private class SingletonClassTree extends StandardPreOrderTree, SingletonClass {
|
||||
final override AstNode getChildNode(int i) {
|
||||
result = this.getValue() and i = 0
|
||||
or
|
||||
result = this.getChild(i - 1)
|
||||
private class SingletonClassTree extends RescueEnsureBlockTree, SingletonClass {
|
||||
final override AstNode getChildNode(int i, boolean rescuable) {
|
||||
rescuable = true and
|
||||
(
|
||||
result = this.getValue() and i = 0
|
||||
or
|
||||
result = this.getChild(i - 1)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isHidden() { any() }
|
||||
}
|
||||
|
||||
private class SingletonMethodTree extends StandardPreOrderTree, SingletonMethod {
|
||||
final override AstNode getChildNode(int i) {
|
||||
result = this.getObject() and i = 0
|
||||
private class SingletonMethodTree extends RescueEnsureBlockTree, SingletonMethod {
|
||||
final override AstNode getChildNode(int i, boolean rescuable) {
|
||||
result = this.getObject() and
|
||||
i = 0 and
|
||||
rescuable = true // TODO: CHECK THIS
|
||||
or
|
||||
result = this.getParameters() and i = 1
|
||||
result = this.getParameters() and
|
||||
i = 1 and
|
||||
rescuable = false
|
||||
or
|
||||
result = this.getChild(i - 2)
|
||||
result = this.getChild(i - 2) and
|
||||
rescuable = true
|
||||
}
|
||||
|
||||
override predicate isHidden() { any() }
|
||||
@@ -990,11 +1311,7 @@ private module Trees {
|
||||
not c instanceof BreakCompletion and
|
||||
not c instanceof RedoCompletion
|
||||
or
|
||||
c =
|
||||
any(NestedCompletion nc |
|
||||
last(this.getBodyNode(), last, nc.getInnerCompletion().(BreakCompletion)) and
|
||||
nc.getOuterCompletion() instanceof SimpleCompletion
|
||||
)
|
||||
last(this.getBodyNode(), last, c.(NestedBreakCompletion).getAnInnerCompatibleCompletion())
|
||||
}
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
@@ -1048,8 +1365,9 @@ private module Cached {
|
||||
cached
|
||||
newtype TSuccessorType =
|
||||
TSuccessorSuccessor() or
|
||||
TBooleanSuccessor(boolean b) { b = true or b = false } or
|
||||
TEmptinessSuccessor(boolean isEmpty) { isEmpty = true or isEmpty = false } or
|
||||
TBooleanSuccessor(boolean b) { b in [false, true] } or
|
||||
TEmptinessSuccessor(boolean isEmpty) { isEmpty in [false, true] } or
|
||||
TMatchingSuccessor(boolean isMatch) { isMatch in [false, true] } or
|
||||
TReturnSuccessor() or
|
||||
TBreakSuccessor() or
|
||||
TNextSuccessor() or
|
||||
|
||||
@@ -12,7 +12,7 @@ abstract class NonReturningCall extends AstNode {
|
||||
private class RaiseCall extends NonReturningCall, MethodCall {
|
||||
RaiseCall() { this.getMethod().toString() = "raise" }
|
||||
|
||||
override RaiseCompletion getACompletion() { any() }
|
||||
override RaiseCompletion getACompletion() { not result instanceof NestedCompletion }
|
||||
}
|
||||
|
||||
private class ExitCall extends NonReturningCall, MethodCall {
|
||||
|
||||
@@ -15,10 +15,16 @@ private int maxSplits() { result = 5 }
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
newtype TSplitKind = TConditionalCompletionSplitKind()
|
||||
newtype TSplitKind =
|
||||
TConditionalCompletionSplitKind() or
|
||||
TEnsureSplitKind(int nestLevel) { nestLevel = any(Trees::RescueEnsureBlockTree t).nestLevel() }
|
||||
|
||||
cached
|
||||
newtype TSplit = TConditionalCompletionSplit(BooleanCompletion c)
|
||||
newtype TSplit =
|
||||
TConditionalCompletionSplit(ConditionalCompletion c) or
|
||||
TEnsureSplit(EnsureSplitting::EnsureSplitType type, int nestLevel) {
|
||||
nestLevel = any(Trees::RescueEnsureBlockTree t).nestLevel()
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TSplits =
|
||||
@@ -60,13 +66,6 @@ class Split extends TSplit {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
private AstNode parent(AstNode n) {
|
||||
result.getAFieldOrChild() = n and
|
||||
not n instanceof CfgScope
|
||||
}
|
||||
|
||||
private CfgScope getScope(AstNode n) { result = parent+(n) }
|
||||
|
||||
/**
|
||||
* Holds if split kinds `sk1` and `sk2` may overlap. That is, they may apply
|
||||
* to at least one common AST node inside `scope`.
|
||||
@@ -195,7 +194,7 @@ private module ConditionalCompletionSplitting {
|
||||
* restrict the edges out of `x < 2 and x > 0` accordingly.
|
||||
*/
|
||||
class ConditionalCompletionSplit extends Split, TConditionalCompletionSplit {
|
||||
BooleanCompletion completion;
|
||||
ConditionalCompletion completion;
|
||||
|
||||
ConditionalCompletionSplit() { this = TConditionalCompletionSplit(completion) }
|
||||
|
||||
@@ -238,19 +237,258 @@ private module ConditionalCompletionSplitting {
|
||||
override predicate hasExit(AstNode pred, AstNode succ, Completion c) {
|
||||
this.appliesTo(pred) and
|
||||
succ(pred, succ, c) and
|
||||
if c instanceof BooleanCompletion then completion = c else any()
|
||||
if c instanceof ConditionalCompletion then completion = c else any()
|
||||
}
|
||||
|
||||
override predicate hasExitScope(AstNode last, CfgScope scope, Completion c) {
|
||||
this.appliesTo(last) and
|
||||
succExit(last, scope, c) and
|
||||
if c instanceof BooleanCompletion then completion = c else any()
|
||||
if c instanceof ConditionalCompletion then completion = c else any()
|
||||
}
|
||||
|
||||
override predicate hasSuccessor(AstNode pred, AstNode succ, Completion c) { none() }
|
||||
}
|
||||
}
|
||||
|
||||
module EnsureSplitting {
|
||||
/**
|
||||
* The type of a split `ensure` node.
|
||||
*
|
||||
* The type represents one of the possible ways of entering an `ensure`
|
||||
* block. For example, if a block ends with a `return` statement, then
|
||||
* the `ensure` block must end with a `return` as well (provided that
|
||||
* the `ensure` block executes normally).
|
||||
*/
|
||||
class EnsureSplitType extends SuccessorType {
|
||||
EnsureSplitType() { not this instanceof ConditionalSuccessor }
|
||||
|
||||
/** Holds if this split type matches entry into an `ensure` block with completion `c`. */
|
||||
predicate isSplitForEntryCompletion(Completion c) {
|
||||
if c instanceof NormalCompletion
|
||||
then
|
||||
// If the entry into the `ensure` block completes with any normal completion,
|
||||
// it simply means normal execution after the `ensure` block
|
||||
this instanceof NormalSuccessor
|
||||
else this = c.getAMatchingSuccessorType()
|
||||
}
|
||||
}
|
||||
|
||||
/** A node that belongs to an `ensure` block. */
|
||||
private class EnsureNode extends AstNode {
|
||||
private Trees::RescueEnsureBlockTree block;
|
||||
|
||||
EnsureNode() { this = block.getAnEnsureDescendant() }
|
||||
|
||||
/** Gets the immediate block that this node belongs to. */
|
||||
Trees::RescueEnsureBlockTree getBlock() { result = block }
|
||||
|
||||
/** Holds if this node is the entry node in the `ensure` block it belongs to. */
|
||||
predicate isEntryNode() { first(block.getEnsure(), this) }
|
||||
}
|
||||
|
||||
/** A node that does not belong to an `ensure` block. */
|
||||
private class NonEnsureNode extends EnsureNode {
|
||||
NonEnsureNode() { not this = any(Trees::RescueEnsureBlockTree t).getAnEnsureDescendant() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A split for nodes belonging to an `ensure` block, which determines how to
|
||||
* continue execution after leaving the `ensure` block. For example, in
|
||||
*
|
||||
* ```rb
|
||||
* begin
|
||||
* if x
|
||||
* raise "Exception"
|
||||
* end
|
||||
* ensure
|
||||
* puts "Ensure"
|
||||
* end
|
||||
* ```
|
||||
*
|
||||
* all control flow nodes in the `ensure` block have two splits: one representing
|
||||
* normal execution of the body (when `x` evaluates to `true`), and one representing
|
||||
* exceptional execution of the body (when `x` evaluates to `false`).
|
||||
*/
|
||||
class EnsureSplit extends Split, TEnsureSplit {
|
||||
private EnsureSplitType type;
|
||||
private int nestLevel;
|
||||
|
||||
EnsureSplit() { this = TEnsureSplit(type, nestLevel) }
|
||||
|
||||
/**
|
||||
* Gets the type of this `ensure` split, that is, how to continue execution after the
|
||||
* `ensure` block.
|
||||
*/
|
||||
EnsureSplitType getType() { result = type }
|
||||
|
||||
/** Gets the nesting level. */
|
||||
int getNestLevel() { result = nestLevel }
|
||||
|
||||
override string toString() {
|
||||
if type instanceof NormalSuccessor
|
||||
then result = ""
|
||||
else
|
||||
if nestLevel > 0
|
||||
then result = "ensure(" + nestLevel + "): " + type.toString()
|
||||
else result = "ensure: " + type.toString()
|
||||
}
|
||||
}
|
||||
|
||||
private int getListOrder(EnsureSplitKind kind) {
|
||||
result = ConditionalCompletionSplitting::getNextListOrder() + kind.getNestLevel()
|
||||
}
|
||||
|
||||
int getNextListOrder() {
|
||||
result = max([getListOrder(_) + 1, ConditionalCompletionSplitting::getNextListOrder()])
|
||||
}
|
||||
|
||||
private class EnsureSplitKind extends SplitKind, TEnsureSplitKind {
|
||||
private int nestLevel;
|
||||
|
||||
EnsureSplitKind() { this = TEnsureSplitKind(nestLevel) }
|
||||
|
||||
/** Gets the nesting level. */
|
||||
int getNestLevel() { result = nestLevel }
|
||||
|
||||
override int getListOrder() { result = getListOrder(this) }
|
||||
|
||||
override string toString() { result = "ensure (" + nestLevel + ")" }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasEntry0(AstNode pred, EnsureNode succ, int nestLevel, Completion c) {
|
||||
succ.isEntryNode() and
|
||||
nestLevel = succ.getBlock().nestLevel() and
|
||||
succ(pred, succ, c)
|
||||
}
|
||||
|
||||
private class EnsureSplitImpl extends SplitImpl, EnsureSplit {
|
||||
override EnsureSplitKind getKind() { result.getNestLevel() = this.getNestLevel() }
|
||||
|
||||
override predicate hasEntry(AstNode pred, AstNode succ, Completion c) {
|
||||
hasEntry0(pred, succ, this.getNestLevel(), c) and
|
||||
this.getType().isSplitForEntryCompletion(c)
|
||||
}
|
||||
|
||||
override predicate hasEntryScope(CfgScope scope, AstNode first) { none() }
|
||||
|
||||
/**
|
||||
* Holds if this split applies to `pred`, where `pred` is a valid predecessor.
|
||||
*/
|
||||
private predicate appliesToPredecessor(AstNode pred) {
|
||||
this.appliesTo(pred) and
|
||||
(succ(pred, _, _) or succExit(pred, _, _))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate exit0(
|
||||
AstNode pred, Trees::RescueEnsureBlockTree block, int nestLevel, Completion c
|
||||
) {
|
||||
this.appliesToPredecessor(pred) and
|
||||
nestLevel = block.nestLevel() and
|
||||
last(block, pred, c)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `pred` may exit this split with completion `c`. The Boolean
|
||||
* `inherited` indicates whether `c` is an inherited completion from the
|
||||
* body.
|
||||
*/
|
||||
private predicate exit(
|
||||
Trees::RescueEnsureBlockTree block, AstNode pred, Completion c, boolean inherited
|
||||
) {
|
||||
exists(EnsureSplitType type |
|
||||
exit0(pred, block, this.getNestLevel(), c) and
|
||||
type = this.getType()
|
||||
|
|
||||
if last(block.getEnsure(), pred, c)
|
||||
then
|
||||
// `ensure` block can itself exit with completion `c`: either `c` must
|
||||
// match this split, `c` must be an abnormal completion, or this split
|
||||
// does not require another completion to be recovered
|
||||
inherited = false and
|
||||
(
|
||||
type = c.getAMatchingSuccessorType()
|
||||
or
|
||||
not c instanceof NormalCompletion
|
||||
or
|
||||
type instanceof NormalSuccessor
|
||||
)
|
||||
else (
|
||||
// `ensure` block can exit with inherited completion `c`, which must
|
||||
// match this split
|
||||
inherited = true and
|
||||
type = c.getAMatchingSuccessorType() and
|
||||
not type instanceof NormalSuccessor
|
||||
)
|
||||
)
|
||||
or
|
||||
// If this split is normal, and an outer split can exit based on an inherited
|
||||
// completion, we need to exit this split as well. For example, in
|
||||
//
|
||||
// ```rb
|
||||
// def m(b1, b2)
|
||||
// if b1
|
||||
// return
|
||||
// end
|
||||
// ensure
|
||||
// begin
|
||||
// if b2
|
||||
// raise "Exception"
|
||||
// end
|
||||
// ensure
|
||||
// puts "inner ensure"
|
||||
// end
|
||||
// end
|
||||
// ```
|
||||
//
|
||||
// if the outer split for `puts "inner ensure"` is `return` and the inner split
|
||||
// is "normal" (corresponding to `b1 = true` and `b2 = false`), then the inner
|
||||
// split must be able to exit with a `return` completion.
|
||||
this.appliesToPredecessor(pred) and
|
||||
exists(EnsureSplitImpl outer |
|
||||
outer.getNestLevel() = this.getNestLevel() - 1 and
|
||||
outer.exit(_, pred, c, inherited) and
|
||||
this.getType() instanceof NormalSuccessor and
|
||||
inherited = true
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasExit(AstNode pred, AstNode succ, Completion c) {
|
||||
succ(pred, succ, c) and
|
||||
(
|
||||
exit(_, pred, c, _)
|
||||
or
|
||||
exit(_, pred, c.(NestedBreakCompletion).getAnInnerCompatibleCompletion(), _)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasExitScope(AstNode last, CfgScope scope, Completion c) {
|
||||
succExit(last, scope, c) and
|
||||
(
|
||||
exit(_, last, c, _)
|
||||
or
|
||||
exit(_, last, c.(NestedBreakCompletion).getAnInnerCompatibleCompletion(), _)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasSuccessor(AstNode pred, AstNode succ, Completion c) {
|
||||
this.appliesToPredecessor(pred) and
|
||||
succ(pred, succ, c) and
|
||||
succ =
|
||||
any(EnsureNode en |
|
||||
if en.isEntryNode()
|
||||
then
|
||||
// entering a nested `ensure` block
|
||||
en.getBlock().nestLevel() > this.getNestLevel()
|
||||
else
|
||||
// staying in the same (possibly nested) `ensure` block as `pred`
|
||||
en.getBlock().nestLevel() >= this.getNestLevel()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of control flow node splits. The set is represented by a list of splits,
|
||||
* ordered by ascending rank.
|
||||
|
||||
@@ -11,6 +11,7 @@ nodes
|
||||
| break_ensure.rb:3:8:3:12 | Binary |
|
||||
| break_ensure.rb:3:12:3:12 | 0 |
|
||||
| break_ensure.rb:4:7:4:11 | Break |
|
||||
| break_ensure.rb:7:1:10:5 | Ensure |
|
||||
| break_ensure.rb:8:3:10:5 | If |
|
||||
| break_ensure.rb:8:6:8:13 | elements |
|
||||
| break_ensure.rb:8:6:8:18 | Call |
|
||||
@@ -30,6 +31,22 @@ nodes
|
||||
| break_ensure.rb:16:10:16:14 | Binary |
|
||||
| break_ensure.rb:16:14:16:14 | 0 |
|
||||
| break_ensure.rb:17:9:17:13 | Break |
|
||||
| break_ensure.rb:19:5:22:9 | Ensure |
|
||||
| break_ensure.rb:19:5:22:9 | [ensure: break] Ensure |
|
||||
| break_ensure.rb:20:7:22:9 | If |
|
||||
| break_ensure.rb:20:7:22:9 | [ensure: break] If |
|
||||
| break_ensure.rb:20:10:20:17 | [ensure: break] elements |
|
||||
| break_ensure.rb:20:10:20:17 | elements |
|
||||
| break_ensure.rb:20:10:20:22 | Call |
|
||||
| break_ensure.rb:20:10:20:22 | [ensure: break] Call |
|
||||
| break_ensure.rb:20:19:20:22 | [ensure: break] nil? |
|
||||
| break_ensure.rb:20:19:20:22 | nil? |
|
||||
| break_ensure.rb:21:9:21:12 | [ensure: break] puts |
|
||||
| break_ensure.rb:21:9:21:12 | puts |
|
||||
| break_ensure.rb:21:9:21:27 | MethodCall |
|
||||
| break_ensure.rb:21:9:21:27 | [ensure: break] MethodCall |
|
||||
| break_ensure.rb:21:14:21:27 | String |
|
||||
| break_ensure.rb:21:14:21:27 | [ensure: break] String |
|
||||
| break_ensure.rb:27:1:42:3 | enter m3 |
|
||||
| break_ensure.rb:27:1:42:3 | exit m3 |
|
||||
| break_ensure.rb:27:1:42:3 | exit m3 (normal) |
|
||||
@@ -39,6 +56,24 @@ nodes
|
||||
| break_ensure.rb:29:8:29:20 | Call |
|
||||
| break_ensure.rb:29:17:29:20 | nil? |
|
||||
| break_ensure.rb:30:7:30:12 | Return |
|
||||
| break_ensure.rb:32:3:39:7 | Ensure |
|
||||
| break_ensure.rb:32:3:39:7 | [ensure: return] Ensure |
|
||||
| break_ensure.rb:33:5:39:7 | For |
|
||||
| break_ensure.rb:33:5:39:7 | [ensure: return] For |
|
||||
| break_ensure.rb:33:9:33:15 | [ensure: return] element |
|
||||
| break_ensure.rb:33:9:33:15 | element |
|
||||
| break_ensure.rb:33:20:33:27 | [ensure: return] elements |
|
||||
| break_ensure.rb:33:20:33:27 | elements |
|
||||
| break_ensure.rb:35:9:37:11 | If |
|
||||
| break_ensure.rb:35:9:37:11 | [ensure: return] If |
|
||||
| break_ensure.rb:35:12:35:12 | [ensure: return] x |
|
||||
| break_ensure.rb:35:12:35:12 | x |
|
||||
| break_ensure.rb:35:12:35:16 | Binary |
|
||||
| break_ensure.rb:35:12:35:16 | [ensure: return] Binary |
|
||||
| break_ensure.rb:35:16:35:16 | 0 |
|
||||
| break_ensure.rb:35:16:35:16 | [ensure: return] 0 |
|
||||
| break_ensure.rb:36:11:36:15 | Break |
|
||||
| break_ensure.rb:36:11:36:15 | [ensure: return] Break |
|
||||
| break_ensure.rb:41:3:41:6 | puts |
|
||||
| break_ensure.rb:41:3:41:13 | MethodCall |
|
||||
| break_ensure.rb:41:8:41:13 | String |
|
||||
@@ -263,6 +298,13 @@ nodes
|
||||
| cfg.rb:75:35:75:36 | 10 |
|
||||
| cfg.rb:75:43:75:43 | x |
|
||||
| cfg.rb:78:3:78:3 | ; |
|
||||
| cfg.rb:83:3:83:6 | puts |
|
||||
| cfg.rb:83:3:83:11 | MethodCall |
|
||||
| cfg.rb:83:8:83:11 | String |
|
||||
| cfg.rb:84:1:85:12 | Ensure |
|
||||
| cfg.rb:85:3:85:6 | puts |
|
||||
| cfg.rb:85:3:85:12 | MethodCall |
|
||||
| cfg.rb:85:8:85:12 | String |
|
||||
| cfg.rb:88:1:88:6 | escape |
|
||||
| cfg.rb:88:1:88:23 | Assignment |
|
||||
| cfg.rb:88:10:88:23 | String |
|
||||
@@ -782,12 +824,16 @@ nodes
|
||||
| raise.rb:17:7:17:11 | raise |
|
||||
| raise.rb:17:7:17:22 | MethodCall |
|
||||
| raise.rb:17:13:17:22 | ExceptionA |
|
||||
| raise.rb:19:3:20:18 | Rescue |
|
||||
| raise.rb:19:10:19:19 | ExceptionA |
|
||||
| raise.rb:20:5:20:8 | puts |
|
||||
| raise.rb:20:5:20:18 | MethodCall |
|
||||
| raise.rb:20:10:20:18 | String |
|
||||
| raise.rb:22:3:22:6 | puts |
|
||||
| raise.rb:22:3:22:15 | MethodCall |
|
||||
| raise.rb:22:8:22:15 | String |
|
||||
| raise.rb:25:1:34:3 | enter m3 |
|
||||
| raise.rb:25:1:34:3 | exit m3 |
|
||||
| raise.rb:25:1:34:3 | exit m3 (abnormal) |
|
||||
| raise.rb:25:1:34:3 | exit m3 (normal) |
|
||||
| raise.rb:25:8:25:8 | b |
|
||||
| raise.rb:27:5:29:7 | If |
|
||||
@@ -795,12 +841,15 @@ nodes
|
||||
| raise.rb:28:7:28:11 | raise |
|
||||
| raise.rb:28:7:28:22 | MethodCall |
|
||||
| raise.rb:28:13:28:22 | ExceptionA |
|
||||
| raise.rb:30:3:31:18 | Rescue |
|
||||
| raise.rb:31:5:31:8 | puts |
|
||||
| raise.rb:31:5:31:18 | MethodCall |
|
||||
| raise.rb:31:10:31:18 | String |
|
||||
| raise.rb:33:3:33:6 | puts |
|
||||
| raise.rb:33:3:33:15 | MethodCall |
|
||||
| raise.rb:33:8:33:15 | String |
|
||||
| raise.rb:36:1:45:3 | enter m4 |
|
||||
| raise.rb:36:1:45:3 | exit m4 |
|
||||
| raise.rb:36:1:45:3 | exit m4 (abnormal) |
|
||||
| raise.rb:36:1:45:3 | exit m4 (normal) |
|
||||
| raise.rb:36:8:36:8 | b |
|
||||
| raise.rb:38:5:40:7 | If |
|
||||
@@ -808,12 +857,16 @@ nodes
|
||||
| raise.rb:39:7:39:11 | raise |
|
||||
| raise.rb:39:7:39:22 | MethodCall |
|
||||
| raise.rb:39:13:39:22 | ExceptionA |
|
||||
| raise.rb:41:3:42:22 | Rescue |
|
||||
| raise.rb:41:13:41:13 | e |
|
||||
| raise.rb:42:5:42:8 | puts |
|
||||
| raise.rb:42:5:42:22 | MethodCall |
|
||||
| raise.rb:42:10:42:22 | String |
|
||||
| raise.rb:44:3:44:6 | puts |
|
||||
| raise.rb:44:3:44:15 | MethodCall |
|
||||
| raise.rb:44:8:44:15 | String |
|
||||
| raise.rb:47:1:55:3 | enter m5 |
|
||||
| raise.rb:47:1:55:3 | exit m5 |
|
||||
| raise.rb:47:1:55:3 | exit m5 (abnormal) |
|
||||
| raise.rb:47:1:55:3 | exit m5 (normal) |
|
||||
| raise.rb:47:8:47:8 | b |
|
||||
| raise.rb:49:5:51:7 | If |
|
||||
@@ -821,6 +874,8 @@ nodes
|
||||
| raise.rb:50:7:50:11 | raise |
|
||||
| raise.rb:50:7:50:22 | MethodCall |
|
||||
| raise.rb:50:13:50:22 | ExceptionA |
|
||||
| raise.rb:52:3:52:13 | Rescue |
|
||||
| raise.rb:52:13:52:13 | e |
|
||||
| raise.rb:54:3:54:6 | puts |
|
||||
| raise.rb:54:3:54:15 | MethodCall |
|
||||
| raise.rb:54:8:54:15 | String |
|
||||
@@ -834,6 +889,13 @@ nodes
|
||||
| raise.rb:60:7:60:11 | raise |
|
||||
| raise.rb:60:7:60:22 | MethodCall |
|
||||
| raise.rb:60:13:60:22 | ExceptionA |
|
||||
| raise.rb:62:3:63:22 | Rescue |
|
||||
| raise.rb:62:10:62:19 | ExceptionA |
|
||||
| raise.rb:62:22:62:31 | ExceptionB |
|
||||
| raise.rb:62:36:62:36 | e |
|
||||
| raise.rb:63:5:63:8 | puts |
|
||||
| raise.rb:63:5:63:22 | MethodCall |
|
||||
| raise.rb:63:10:63:22 | String |
|
||||
| raise.rb:65:3:65:6 | puts |
|
||||
| raise.rb:65:3:65:15 | MethodCall |
|
||||
| raise.rb:65:8:65:15 | String |
|
||||
@@ -858,9 +920,18 @@ nodes
|
||||
| raise.rb:74:3:74:6 | puts |
|
||||
| raise.rb:74:3:74:20 | MethodCall |
|
||||
| raise.rb:74:8:74:20 | String |
|
||||
| raise.rb:75:1:76:15 | Ensure |
|
||||
| raise.rb:75:1:76:15 | [ensure: raise] Ensure |
|
||||
| raise.rb:75:1:76:15 | [ensure: return] Ensure |
|
||||
| raise.rb:76:3:76:6 | [ensure: raise] puts |
|
||||
| raise.rb:76:3:76:6 | [ensure: return] puts |
|
||||
| raise.rb:76:3:76:6 | puts |
|
||||
| raise.rb:76:3:76:15 | MethodCall |
|
||||
| raise.rb:76:3:76:15 | [ensure: raise] MethodCall |
|
||||
| raise.rb:76:3:76:15 | [ensure: return] MethodCall |
|
||||
| raise.rb:76:8:76:15 | String |
|
||||
| raise.rb:76:8:76:15 | [ensure: raise] String |
|
||||
| raise.rb:76:8:76:15 | [ensure: return] String |
|
||||
| raise.rb:79:1:92:3 | enter m8 |
|
||||
| raise.rb:79:1:92:3 | exit m8 |
|
||||
| raise.rb:79:1:92:3 | exit m8 (abnormal) |
|
||||
@@ -885,6 +956,18 @@ nodes
|
||||
| raise.rb:87:5:87:8 | puts |
|
||||
| raise.rb:87:5:87:22 | MethodCall |
|
||||
| raise.rb:87:10:87:22 | String |
|
||||
| raise.rb:88:3:89:17 | Ensure |
|
||||
| raise.rb:88:3:89:17 | [ensure: raise] Ensure |
|
||||
| raise.rb:88:3:89:17 | [ensure: return] Ensure |
|
||||
| raise.rb:89:5:89:8 | [ensure: raise] puts |
|
||||
| raise.rb:89:5:89:8 | [ensure: return] puts |
|
||||
| raise.rb:89:5:89:8 | puts |
|
||||
| raise.rb:89:5:89:17 | MethodCall |
|
||||
| raise.rb:89:5:89:17 | [ensure: raise] MethodCall |
|
||||
| raise.rb:89:5:89:17 | [ensure: return] MethodCall |
|
||||
| raise.rb:89:10:89:17 | String |
|
||||
| raise.rb:89:10:89:17 | [ensure: raise] String |
|
||||
| raise.rb:89:10:89:17 | [ensure: return] String |
|
||||
| raise.rb:91:3:91:6 | puts |
|
||||
| raise.rb:91:3:91:15 | MethodCall |
|
||||
| raise.rb:91:8:91:15 | String |
|
||||
@@ -914,17 +997,87 @@ nodes
|
||||
| raise.rb:102:5:102:8 | puts |
|
||||
| raise.rb:102:5:102:22 | MethodCall |
|
||||
| raise.rb:102:10:102:22 | String |
|
||||
| raise.rb:103:3:111:7 | Ensure |
|
||||
| raise.rb:103:3:111:7 | [ensure: raise] Ensure |
|
||||
| raise.rb:103:3:111:7 | [ensure: return] Ensure |
|
||||
| raise.rb:104:5:104:8 | [ensure: raise] puts |
|
||||
| raise.rb:104:5:104:8 | [ensure: return] puts |
|
||||
| raise.rb:104:5:104:8 | puts |
|
||||
| raise.rb:104:5:104:23 | MethodCall |
|
||||
| raise.rb:104:5:104:23 | [ensure: raise] MethodCall |
|
||||
| raise.rb:104:5:104:23 | [ensure: return] MethodCall |
|
||||
| raise.rb:104:10:104:23 | String |
|
||||
| raise.rb:104:10:104:23 | [ensure: raise] String |
|
||||
| raise.rb:104:10:104:23 | [ensure: return] String |
|
||||
| raise.rb:106:7:108:9 | If |
|
||||
| raise.rb:106:7:108:9 | [ensure: raise] If |
|
||||
| raise.rb:106:7:108:9 | [ensure: return] If |
|
||||
| raise.rb:106:10:106:11 | [ensure: raise] b1 |
|
||||
| raise.rb:106:10:106:11 | [ensure: return] b1 |
|
||||
| raise.rb:106:10:106:11 | b1 |
|
||||
| raise.rb:107:9:107:13 | [ensure: raise] raise |
|
||||
| raise.rb:107:9:107:13 | [ensure: return] raise |
|
||||
| raise.rb:107:9:107:13 | raise |
|
||||
| raise.rb:107:9:107:26 | MethodCall |
|
||||
| raise.rb:107:9:107:26 | [ensure: raise] MethodCall |
|
||||
| raise.rb:107:9:107:26 | [ensure: return] MethodCall |
|
||||
| raise.rb:107:15:107:26 | String |
|
||||
| raise.rb:107:15:107:26 | [ensure: raise] String |
|
||||
| raise.rb:107:15:107:26 | [ensure: return] String |
|
||||
| raise.rb:109:5:110:25 | Ensure |
|
||||
| raise.rb:109:5:110:25 | [ensure(1): raise] Ensure |
|
||||
| raise.rb:109:5:110:25 | [ensure: raise, ensure(1): raise] Ensure |
|
||||
| raise.rb:109:5:110:25 | [ensure: raise] Ensure |
|
||||
| raise.rb:109:5:110:25 | [ensure: return, ensure(1): raise] Ensure |
|
||||
| raise.rb:109:5:110:25 | [ensure: return] Ensure |
|
||||
| raise.rb:110:7:110:10 | [ensure(1): raise] puts |
|
||||
| raise.rb:110:7:110:10 | [ensure: raise, ensure(1): raise] puts |
|
||||
| raise.rb:110:7:110:10 | [ensure: raise] puts |
|
||||
| raise.rb:110:7:110:10 | [ensure: return, ensure(1): raise] puts |
|
||||
| raise.rb:110:7:110:10 | [ensure: return] puts |
|
||||
| raise.rb:110:7:110:10 | puts |
|
||||
| raise.rb:110:7:110:25 | MethodCall |
|
||||
| raise.rb:110:7:110:25 | [ensure(1): raise] MethodCall |
|
||||
| raise.rb:110:7:110:25 | [ensure: raise, ensure(1): raise] MethodCall |
|
||||
| raise.rb:110:7:110:25 | [ensure: raise] MethodCall |
|
||||
| raise.rb:110:7:110:25 | [ensure: return, ensure(1): raise] MethodCall |
|
||||
| raise.rb:110:7:110:25 | [ensure: return] MethodCall |
|
||||
| raise.rb:110:12:110:25 | String |
|
||||
| raise.rb:110:12:110:25 | [ensure(1): raise] String |
|
||||
| raise.rb:110:12:110:25 | [ensure: raise, ensure(1): raise] String |
|
||||
| raise.rb:110:12:110:25 | [ensure: raise] String |
|
||||
| raise.rb:110:12:110:25 | [ensure: return, ensure(1): raise] String |
|
||||
| raise.rb:110:12:110:25 | [ensure: return] String |
|
||||
| raise.rb:113:3:113:6 | puts |
|
||||
| raise.rb:113:3:113:15 | MethodCall |
|
||||
| raise.rb:113:8:113:15 | String |
|
||||
| raise.rb:114:1:118:5 | Ensure |
|
||||
| raise.rb:114:1:118:5 | [ensure: raise] Ensure |
|
||||
| raise.rb:114:1:118:5 | [ensure: return] Ensure |
|
||||
| raise.rb:115:3:115:6 | [ensure: raise] puts |
|
||||
| raise.rb:115:3:115:6 | [ensure: return] puts |
|
||||
| raise.rb:115:3:115:6 | puts |
|
||||
| raise.rb:115:3:115:22 | MethodCall |
|
||||
| raise.rb:115:3:115:22 | [ensure: raise] MethodCall |
|
||||
| raise.rb:115:3:115:22 | [ensure: return] MethodCall |
|
||||
| raise.rb:115:8:115:22 | String |
|
||||
| raise.rb:115:8:115:22 | [ensure: raise] String |
|
||||
| raise.rb:115:8:115:22 | [ensure: return] String |
|
||||
| raise.rb:116:3:118:5 | If |
|
||||
| raise.rb:116:3:118:5 | [ensure: raise] If |
|
||||
| raise.rb:116:3:118:5 | [ensure: return] If |
|
||||
| raise.rb:116:6:116:7 | [ensure: raise] b2 |
|
||||
| raise.rb:116:6:116:7 | [ensure: return] b2 |
|
||||
| raise.rb:116:6:116:7 | b2 |
|
||||
| raise.rb:117:5:117:9 | [ensure: raise] raise |
|
||||
| raise.rb:117:5:117:9 | [ensure: return] raise |
|
||||
| raise.rb:117:5:117:9 | raise |
|
||||
| raise.rb:117:5:117:22 | MethodCall |
|
||||
| raise.rb:117:5:117:22 | [ensure: raise] MethodCall |
|
||||
| raise.rb:117:5:117:22 | [ensure: return] MethodCall |
|
||||
| raise.rb:117:11:117:22 | String |
|
||||
| raise.rb:117:11:117:22 | [ensure: raise] String |
|
||||
| raise.rb:117:11:117:22 | [ensure: return] String |
|
||||
| raise.rb:121:1:124:3 | enter m10 |
|
||||
| raise.rb:121:1:124:3 | exit m10 |
|
||||
| raise.rb:121:1:124:3 | exit m10 (abnormal) |
|
||||
@@ -936,7 +1089,7 @@ edges
|
||||
| break_ensure.rb:1:1:11:3 | exit m1 (normal) | break_ensure.rb:1:1:11:3 | exit m1 | semmle.label | successor |
|
||||
| break_ensure.rb:1:8:1:15 | elements | break_ensure.rb:2:18:2:25 | elements | semmle.label | successor |
|
||||
| break_ensure.rb:2:3:6:5 | For | break_ensure.rb:2:7:2:13 | element | semmle.label | non-empty |
|
||||
| break_ensure.rb:2:3:6:5 | For | break_ensure.rb:8:3:10:5 | If | semmle.label | empty |
|
||||
| break_ensure.rb:2:3:6:5 | For | break_ensure.rb:7:1:10:5 | Ensure | semmle.label | empty |
|
||||
| break_ensure.rb:2:7:2:13 | element | break_ensure.rb:3:5:5:7 | If | semmle.label | successor |
|
||||
| break_ensure.rb:2:18:2:25 | elements | break_ensure.rb:2:3:6:5 | For | semmle.label | successor |
|
||||
| break_ensure.rb:3:5:5:7 | If | break_ensure.rb:3:8:3:8 | x | semmle.label | successor |
|
||||
@@ -944,7 +1097,8 @@ edges
|
||||
| break_ensure.rb:3:8:3:12 | Binary | break_ensure.rb:2:3:6:5 | For | semmle.label | false |
|
||||
| break_ensure.rb:3:8:3:12 | Binary | break_ensure.rb:4:7:4:11 | Break | semmle.label | true |
|
||||
| break_ensure.rb:3:12:3:12 | 0 | break_ensure.rb:3:8:3:12 | Binary | semmle.label | successor |
|
||||
| break_ensure.rb:4:7:4:11 | Break | break_ensure.rb:8:3:10:5 | If | semmle.label | break |
|
||||
| break_ensure.rb:4:7:4:11 | Break | break_ensure.rb:7:1:10:5 | Ensure | semmle.label | break |
|
||||
| break_ensure.rb:7:1:10:5 | Ensure | break_ensure.rb:8:3:10:5 | If | semmle.label | successor |
|
||||
| break_ensure.rb:8:3:10:5 | If | break_ensure.rb:8:6:8:13 | elements | semmle.label | successor |
|
||||
| break_ensure.rb:8:6:8:13 | elements | break_ensure.rb:8:15:8:18 | nil? | semmle.label | successor |
|
||||
| break_ensure.rb:8:6:8:18 | Call | break_ensure.rb:1:1:11:3 | exit m1 (normal) | semmle.label | false |
|
||||
@@ -962,19 +1116,59 @@ edges
|
||||
| break_ensure.rb:14:18:14:25 | elements | break_ensure.rb:14:3:24:5 | For | semmle.label | successor |
|
||||
| break_ensure.rb:16:7:18:9 | If | break_ensure.rb:16:10:16:10 | x | semmle.label | successor |
|
||||
| break_ensure.rb:16:10:16:10 | x | break_ensure.rb:16:14:16:14 | 0 | semmle.label | successor |
|
||||
| break_ensure.rb:16:10:16:14 | Binary | break_ensure.rb:14:3:24:5 | For | semmle.label | false |
|
||||
| break_ensure.rb:16:10:16:14 | Binary | break_ensure.rb:17:9:17:13 | Break | semmle.label | true |
|
||||
| break_ensure.rb:16:10:16:14 | Binary | break_ensure.rb:19:5:22:9 | Ensure | semmle.label | false |
|
||||
| break_ensure.rb:16:14:16:14 | 0 | break_ensure.rb:16:10:16:14 | Binary | semmle.label | successor |
|
||||
| break_ensure.rb:17:9:17:13 | Break | break_ensure.rb:13:1:25:3 | exit m2 (normal) | semmle.label | break |
|
||||
| break_ensure.rb:17:9:17:13 | Break | break_ensure.rb:19:5:22:9 | [ensure: break] Ensure | semmle.label | break |
|
||||
| break_ensure.rb:19:5:22:9 | Ensure | break_ensure.rb:20:7:22:9 | If | semmle.label | successor |
|
||||
| break_ensure.rb:19:5:22:9 | [ensure: break] Ensure | break_ensure.rb:20:7:22:9 | [ensure: break] If | semmle.label | successor |
|
||||
| break_ensure.rb:20:7:22:9 | If | break_ensure.rb:20:10:20:17 | elements | semmle.label | successor |
|
||||
| break_ensure.rb:20:7:22:9 | [ensure: break] If | break_ensure.rb:20:10:20:17 | [ensure: break] elements | semmle.label | successor |
|
||||
| break_ensure.rb:20:10:20:17 | [ensure: break] elements | break_ensure.rb:20:19:20:22 | [ensure: break] nil? | semmle.label | successor |
|
||||
| break_ensure.rb:20:10:20:17 | elements | break_ensure.rb:20:19:20:22 | nil? | semmle.label | successor |
|
||||
| break_ensure.rb:20:10:20:22 | Call | break_ensure.rb:14:3:24:5 | For | semmle.label | false |
|
||||
| break_ensure.rb:20:10:20:22 | Call | break_ensure.rb:21:14:21:27 | String | semmle.label | true |
|
||||
| break_ensure.rb:20:10:20:22 | [ensure: break] Call | break_ensure.rb:13:1:25:3 | exit m2 (normal) | semmle.label | false |
|
||||
| break_ensure.rb:20:10:20:22 | [ensure: break] Call | break_ensure.rb:21:14:21:27 | [ensure: break] String | semmle.label | true |
|
||||
| break_ensure.rb:20:19:20:22 | [ensure: break] nil? | break_ensure.rb:20:10:20:22 | [ensure: break] Call | semmle.label | successor |
|
||||
| break_ensure.rb:20:19:20:22 | nil? | break_ensure.rb:20:10:20:22 | Call | semmle.label | successor |
|
||||
| break_ensure.rb:21:9:21:12 | [ensure: break] puts | break_ensure.rb:21:9:21:27 | [ensure: break] MethodCall | semmle.label | successor |
|
||||
| break_ensure.rb:21:9:21:12 | puts | break_ensure.rb:21:9:21:27 | MethodCall | semmle.label | successor |
|
||||
| break_ensure.rb:21:9:21:27 | MethodCall | break_ensure.rb:14:3:24:5 | For | semmle.label | successor |
|
||||
| break_ensure.rb:21:9:21:27 | [ensure: break] MethodCall | break_ensure.rb:13:1:25:3 | exit m2 (normal) | semmle.label | break |
|
||||
| break_ensure.rb:21:14:21:27 | String | break_ensure.rb:21:9:21:12 | puts | semmle.label | successor |
|
||||
| break_ensure.rb:21:14:21:27 | [ensure: break] String | break_ensure.rb:21:9:21:12 | [ensure: break] puts | semmle.label | successor |
|
||||
| break_ensure.rb:27:1:42:3 | enter m3 | break_ensure.rb:27:8:27:15 | elements | semmle.label | successor |
|
||||
| break_ensure.rb:27:1:42:3 | exit m3 (normal) | break_ensure.rb:27:1:42:3 | exit m3 | semmle.label | successor |
|
||||
| break_ensure.rb:27:8:27:15 | elements | break_ensure.rb:29:5:31:7 | If | semmle.label | successor |
|
||||
| break_ensure.rb:29:5:31:7 | If | break_ensure.rb:29:8:29:15 | elements | semmle.label | successor |
|
||||
| break_ensure.rb:29:8:29:15 | elements | break_ensure.rb:29:17:29:20 | nil? | semmle.label | successor |
|
||||
| break_ensure.rb:29:8:29:20 | Call | break_ensure.rb:30:7:30:12 | Return | semmle.label | true |
|
||||
| break_ensure.rb:29:8:29:20 | Call | break_ensure.rb:41:8:41:13 | String | semmle.label | false |
|
||||
| break_ensure.rb:29:8:29:20 | Call | break_ensure.rb:32:3:39:7 | Ensure | semmle.label | false |
|
||||
| break_ensure.rb:29:17:29:20 | nil? | break_ensure.rb:29:8:29:20 | Call | semmle.label | successor |
|
||||
| break_ensure.rb:30:7:30:12 | Return | break_ensure.rb:27:1:42:3 | exit m3 (normal) | semmle.label | return |
|
||||
| break_ensure.rb:30:7:30:12 | Return | break_ensure.rb:32:3:39:7 | [ensure: return] Ensure | semmle.label | return |
|
||||
| break_ensure.rb:32:3:39:7 | Ensure | break_ensure.rb:33:20:33:27 | elements | semmle.label | successor |
|
||||
| break_ensure.rb:32:3:39:7 | [ensure: return] Ensure | break_ensure.rb:33:20:33:27 | [ensure: return] elements | semmle.label | successor |
|
||||
| break_ensure.rb:33:5:39:7 | For | break_ensure.rb:33:9:33:15 | element | semmle.label | non-empty |
|
||||
| break_ensure.rb:33:5:39:7 | For | break_ensure.rb:41:8:41:13 | String | semmle.label | empty |
|
||||
| break_ensure.rb:33:5:39:7 | [ensure: return] For | break_ensure.rb:27:1:42:3 | exit m3 (normal) | semmle.label | return |
|
||||
| break_ensure.rb:33:5:39:7 | [ensure: return] For | break_ensure.rb:33:9:33:15 | [ensure: return] element | semmle.label | non-empty |
|
||||
| break_ensure.rb:33:9:33:15 | [ensure: return] element | break_ensure.rb:35:9:37:11 | [ensure: return] If | semmle.label | successor |
|
||||
| break_ensure.rb:33:9:33:15 | element | break_ensure.rb:35:9:37:11 | If | semmle.label | successor |
|
||||
| break_ensure.rb:33:20:33:27 | [ensure: return] elements | break_ensure.rb:33:5:39:7 | [ensure: return] For | semmle.label | successor |
|
||||
| break_ensure.rb:33:20:33:27 | elements | break_ensure.rb:33:5:39:7 | For | semmle.label | successor |
|
||||
| break_ensure.rb:35:9:37:11 | If | break_ensure.rb:35:12:35:12 | x | semmle.label | successor |
|
||||
| break_ensure.rb:35:9:37:11 | [ensure: return] If | break_ensure.rb:35:12:35:12 | [ensure: return] x | semmle.label | successor |
|
||||
| break_ensure.rb:35:12:35:12 | [ensure: return] x | break_ensure.rb:35:16:35:16 | [ensure: return] 0 | semmle.label | successor |
|
||||
| break_ensure.rb:35:12:35:12 | x | break_ensure.rb:35:16:35:16 | 0 | semmle.label | successor |
|
||||
| break_ensure.rb:35:12:35:16 | Binary | break_ensure.rb:33:5:39:7 | For | semmle.label | false |
|
||||
| break_ensure.rb:35:12:35:16 | Binary | break_ensure.rb:36:11:36:15 | Break | semmle.label | true |
|
||||
| break_ensure.rb:35:12:35:16 | [ensure: return] Binary | break_ensure.rb:33:5:39:7 | [ensure: return] For | semmle.label | false |
|
||||
| break_ensure.rb:35:12:35:16 | [ensure: return] Binary | break_ensure.rb:36:11:36:15 | [ensure: return] Break | semmle.label | true |
|
||||
| break_ensure.rb:35:16:35:16 | 0 | break_ensure.rb:35:12:35:16 | Binary | semmle.label | successor |
|
||||
| break_ensure.rb:35:16:35:16 | [ensure: return] 0 | break_ensure.rb:35:12:35:16 | [ensure: return] Binary | semmle.label | successor |
|
||||
| break_ensure.rb:36:11:36:15 | Break | break_ensure.rb:41:8:41:13 | String | semmle.label | break |
|
||||
| break_ensure.rb:36:11:36:15 | [ensure: return] Break | break_ensure.rb:27:1:42:3 | exit m3 (normal) | semmle.label | return |
|
||||
| break_ensure.rb:41:3:41:6 | puts | break_ensure.rb:41:3:41:13 | MethodCall | semmle.label | successor |
|
||||
| break_ensure.rb:41:3:41:13 | MethodCall | break_ensure.rb:27:1:42:3 | exit m3 (normal) | semmle.label | successor |
|
||||
| break_ensure.rb:41:8:41:13 | String | break_ensure.rb:41:3:41:6 | puts | semmle.label | successor |
|
||||
@@ -1203,7 +1397,14 @@ edges
|
||||
| cfg.rb:75:27:75:28 | 10 | cfg.rb:75:23:75:28 | Binary | semmle.label | successor |
|
||||
| cfg.rb:75:35:75:36 | 10 | cfg.rb:78:3:78:3 | ; | semmle.label | successor |
|
||||
| cfg.rb:75:43:75:43 | x | cfg.rb:78:3:78:3 | ; | semmle.label | successor |
|
||||
| cfg.rb:78:3:78:3 | ; | cfg.rb:88:19:88:19 | x | semmle.label | successor |
|
||||
| cfg.rb:78:3:78:3 | ; | cfg.rb:83:8:83:11 | String | semmle.label | successor |
|
||||
| cfg.rb:83:3:83:6 | puts | cfg.rb:83:3:83:11 | MethodCall | semmle.label | successor |
|
||||
| cfg.rb:83:3:83:11 | MethodCall | cfg.rb:84:1:85:12 | Ensure | semmle.label | successor |
|
||||
| cfg.rb:83:8:83:11 | String | cfg.rb:83:3:83:6 | puts | semmle.label | successor |
|
||||
| cfg.rb:84:1:85:12 | Ensure | cfg.rb:85:8:85:12 | String | semmle.label | successor |
|
||||
| cfg.rb:85:3:85:6 | puts | cfg.rb:85:3:85:12 | MethodCall | semmle.label | successor |
|
||||
| cfg.rb:85:3:85:12 | MethodCall | cfg.rb:88:19:88:19 | x | semmle.label | successor |
|
||||
| cfg.rb:85:8:85:12 | String | cfg.rb:85:3:85:6 | puts | semmle.label | successor |
|
||||
| cfg.rb:88:1:88:6 | escape | cfg.rb:88:1:88:23 | Assignment | semmle.label | successor |
|
||||
| cfg.rb:88:1:88:23 | Assignment | cfg.rb:90:11:90:13 | 1.4 | semmle.label | successor |
|
||||
| cfg.rb:88:10:88:23 | String | cfg.rb:88:1:88:6 | escape | semmle.label | successor |
|
||||
@@ -1729,47 +1930,61 @@ edges
|
||||
| raise.rb:16:8:16:8 | b | raise.rb:17:13:17:22 | ExceptionA | semmle.label | true |
|
||||
| raise.rb:16:8:16:8 | b | raise.rb:22:8:22:15 | String | semmle.label | false |
|
||||
| raise.rb:17:7:17:11 | raise | raise.rb:17:7:17:22 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:17:7:17:22 | MethodCall | raise.rb:14:1:23:3 | exit m2 (abnormal) | semmle.label | raise |
|
||||
| raise.rb:17:7:17:22 | MethodCall | raise.rb:19:3:20:18 | Rescue | semmle.label | raise |
|
||||
| raise.rb:17:13:17:22 | ExceptionA | raise.rb:17:7:17:11 | raise | semmle.label | successor |
|
||||
| raise.rb:19:3:20:18 | Rescue | raise.rb:19:10:19:19 | ExceptionA | semmle.label | successor |
|
||||
| raise.rb:19:10:19:19 | ExceptionA | raise.rb:14:1:23:3 | exit m2 (abnormal) | semmle.label | raise |
|
||||
| raise.rb:19:10:19:19 | ExceptionA | raise.rb:20:10:20:18 | String | semmle.label | match |
|
||||
| raise.rb:20:5:20:8 | puts | raise.rb:20:5:20:18 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:20:5:20:18 | MethodCall | raise.rb:22:8:22:15 | String | semmle.label | successor |
|
||||
| raise.rb:20:10:20:18 | String | raise.rb:20:5:20:8 | puts | semmle.label | successor |
|
||||
| raise.rb:22:3:22:6 | puts | raise.rb:22:3:22:15 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:22:3:22:15 | MethodCall | raise.rb:14:1:23:3 | exit m2 (normal) | semmle.label | successor |
|
||||
| raise.rb:22:8:22:15 | String | raise.rb:22:3:22:6 | puts | semmle.label | successor |
|
||||
| raise.rb:25:1:34:3 | enter m3 | raise.rb:25:8:25:8 | b | semmle.label | successor |
|
||||
| raise.rb:25:1:34:3 | exit m3 (abnormal) | raise.rb:25:1:34:3 | exit m3 | semmle.label | successor |
|
||||
| raise.rb:25:1:34:3 | exit m3 (normal) | raise.rb:25:1:34:3 | exit m3 | semmle.label | successor |
|
||||
| raise.rb:25:8:25:8 | b | raise.rb:27:5:29:7 | If | semmle.label | successor |
|
||||
| raise.rb:27:5:29:7 | If | raise.rb:27:8:27:8 | b | semmle.label | successor |
|
||||
| raise.rb:27:8:27:8 | b | raise.rb:28:13:28:22 | ExceptionA | semmle.label | true |
|
||||
| raise.rb:27:8:27:8 | b | raise.rb:33:8:33:15 | String | semmle.label | false |
|
||||
| raise.rb:28:7:28:11 | raise | raise.rb:28:7:28:22 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:28:7:28:22 | MethodCall | raise.rb:25:1:34:3 | exit m3 (abnormal) | semmle.label | raise |
|
||||
| raise.rb:28:7:28:22 | MethodCall | raise.rb:30:3:31:18 | Rescue | semmle.label | raise |
|
||||
| raise.rb:28:13:28:22 | ExceptionA | raise.rb:28:7:28:11 | raise | semmle.label | successor |
|
||||
| raise.rb:30:3:31:18 | Rescue | raise.rb:31:10:31:18 | String | semmle.label | successor |
|
||||
| raise.rb:31:5:31:8 | puts | raise.rb:31:5:31:18 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:31:5:31:18 | MethodCall | raise.rb:33:8:33:15 | String | semmle.label | successor |
|
||||
| raise.rb:31:10:31:18 | String | raise.rb:31:5:31:8 | puts | semmle.label | successor |
|
||||
| raise.rb:33:3:33:6 | puts | raise.rb:33:3:33:15 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:33:3:33:15 | MethodCall | raise.rb:25:1:34:3 | exit m3 (normal) | semmle.label | successor |
|
||||
| raise.rb:33:8:33:15 | String | raise.rb:33:3:33:6 | puts | semmle.label | successor |
|
||||
| raise.rb:36:1:45:3 | enter m4 | raise.rb:36:8:36:8 | b | semmle.label | successor |
|
||||
| raise.rb:36:1:45:3 | exit m4 (abnormal) | raise.rb:36:1:45:3 | exit m4 | semmle.label | successor |
|
||||
| raise.rb:36:1:45:3 | exit m4 (normal) | raise.rb:36:1:45:3 | exit m4 | semmle.label | successor |
|
||||
| raise.rb:36:8:36:8 | b | raise.rb:38:5:40:7 | If | semmle.label | successor |
|
||||
| raise.rb:38:5:40:7 | If | raise.rb:38:8:38:8 | b | semmle.label | successor |
|
||||
| raise.rb:38:8:38:8 | b | raise.rb:39:13:39:22 | ExceptionA | semmle.label | true |
|
||||
| raise.rb:38:8:38:8 | b | raise.rb:44:8:44:15 | String | semmle.label | false |
|
||||
| raise.rb:39:7:39:11 | raise | raise.rb:39:7:39:22 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:39:7:39:22 | MethodCall | raise.rb:36:1:45:3 | exit m4 (abnormal) | semmle.label | raise |
|
||||
| raise.rb:39:7:39:22 | MethodCall | raise.rb:41:3:42:22 | Rescue | semmle.label | raise |
|
||||
| raise.rb:39:13:39:22 | ExceptionA | raise.rb:39:7:39:11 | raise | semmle.label | successor |
|
||||
| raise.rb:41:3:42:22 | Rescue | raise.rb:41:13:41:13 | e | semmle.label | successor |
|
||||
| raise.rb:41:13:41:13 | e | raise.rb:42:10:42:22 | String | semmle.label | successor |
|
||||
| raise.rb:42:5:42:8 | puts | raise.rb:42:5:42:22 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:42:5:42:22 | MethodCall | raise.rb:44:8:44:15 | String | semmle.label | successor |
|
||||
| raise.rb:42:10:42:22 | String | raise.rb:42:5:42:8 | puts | semmle.label | successor |
|
||||
| raise.rb:44:3:44:6 | puts | raise.rb:44:3:44:15 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:44:3:44:15 | MethodCall | raise.rb:36:1:45:3 | exit m4 (normal) | semmle.label | successor |
|
||||
| raise.rb:44:8:44:15 | String | raise.rb:44:3:44:6 | puts | semmle.label | successor |
|
||||
| raise.rb:47:1:55:3 | enter m5 | raise.rb:47:8:47:8 | b | semmle.label | successor |
|
||||
| raise.rb:47:1:55:3 | exit m5 (abnormal) | raise.rb:47:1:55:3 | exit m5 | semmle.label | successor |
|
||||
| raise.rb:47:1:55:3 | exit m5 (normal) | raise.rb:47:1:55:3 | exit m5 | semmle.label | successor |
|
||||
| raise.rb:47:8:47:8 | b | raise.rb:49:5:51:7 | If | semmle.label | successor |
|
||||
| raise.rb:49:5:51:7 | If | raise.rb:49:8:49:8 | b | semmle.label | successor |
|
||||
| raise.rb:49:8:49:8 | b | raise.rb:50:13:50:22 | ExceptionA | semmle.label | true |
|
||||
| raise.rb:49:8:49:8 | b | raise.rb:54:8:54:15 | String | semmle.label | false |
|
||||
| raise.rb:50:7:50:11 | raise | raise.rb:50:7:50:22 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:50:7:50:22 | MethodCall | raise.rb:47:1:55:3 | exit m5 (abnormal) | semmle.label | raise |
|
||||
| raise.rb:50:7:50:22 | MethodCall | raise.rb:52:3:52:13 | Rescue | semmle.label | raise |
|
||||
| raise.rb:50:13:50:22 | ExceptionA | raise.rb:50:7:50:11 | raise | semmle.label | successor |
|
||||
| raise.rb:52:3:52:13 | Rescue | raise.rb:52:13:52:13 | e | semmle.label | successor |
|
||||
| raise.rb:52:13:52:13 | e | raise.rb:54:8:54:15 | String | semmle.label | successor |
|
||||
| raise.rb:54:3:54:6 | puts | raise.rb:54:3:54:15 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:54:3:54:15 | MethodCall | raise.rb:47:1:55:3 | exit m5 (normal) | semmle.label | successor |
|
||||
| raise.rb:54:8:54:15 | String | raise.rb:54:3:54:6 | puts | semmle.label | successor |
|
||||
@@ -1781,8 +1996,17 @@ edges
|
||||
| raise.rb:59:8:59:8 | b | raise.rb:60:13:60:22 | ExceptionA | semmle.label | true |
|
||||
| raise.rb:59:8:59:8 | b | raise.rb:65:8:65:15 | String | semmle.label | false |
|
||||
| raise.rb:60:7:60:11 | raise | raise.rb:60:7:60:22 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:60:7:60:22 | MethodCall | raise.rb:57:1:66:3 | exit m6 (abnormal) | semmle.label | raise |
|
||||
| raise.rb:60:7:60:22 | MethodCall | raise.rb:62:3:63:22 | Rescue | semmle.label | raise |
|
||||
| raise.rb:60:13:60:22 | ExceptionA | raise.rb:60:7:60:11 | raise | semmle.label | successor |
|
||||
| raise.rb:62:3:63:22 | Rescue | raise.rb:62:10:62:19 | ExceptionA | semmle.label | successor |
|
||||
| raise.rb:62:10:62:19 | ExceptionA | raise.rb:62:22:62:31 | ExceptionB | semmle.label | no-match |
|
||||
| raise.rb:62:10:62:19 | ExceptionA | raise.rb:62:36:62:36 | e | semmle.label | match |
|
||||
| raise.rb:62:22:62:31 | ExceptionB | raise.rb:57:1:66:3 | exit m6 (abnormal) | semmle.label | raise |
|
||||
| raise.rb:62:22:62:31 | ExceptionB | raise.rb:62:36:62:36 | e | semmle.label | match |
|
||||
| raise.rb:62:36:62:36 | e | raise.rb:63:10:63:22 | String | semmle.label | successor |
|
||||
| raise.rb:63:5:63:8 | puts | raise.rb:63:5:63:22 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:63:5:63:22 | MethodCall | raise.rb:65:8:65:15 | String | semmle.label | successor |
|
||||
| raise.rb:63:10:63:22 | String | raise.rb:63:5:63:8 | puts | semmle.label | successor |
|
||||
| raise.rb:65:3:65:6 | puts | raise.rb:65:3:65:15 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:65:3:65:15 | MethodCall | raise.rb:57:1:66:3 | exit m6 (normal) | semmle.label | successor |
|
||||
| raise.rb:65:8:65:15 | String | raise.rb:65:3:65:6 | puts | semmle.label | successor |
|
||||
@@ -1796,21 +2020,30 @@ edges
|
||||
| raise.rb:69:6:69:10 | Binary | raise.rb:71:3:72:18 | Elsif | semmle.label | false |
|
||||
| raise.rb:69:10:69:10 | 2 | raise.rb:69:6:69:10 | Binary | semmle.label | successor |
|
||||
| raise.rb:70:5:70:9 | raise | raise.rb:70:5:70:17 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:70:5:70:17 | MethodCall | raise.rb:68:1:77:3 | exit m7 (abnormal) | semmle.label | raise |
|
||||
| raise.rb:70:5:70:17 | MethodCall | raise.rb:75:1:76:15 | [ensure: raise] Ensure | semmle.label | raise |
|
||||
| raise.rb:70:11:70:17 | String | raise.rb:70:5:70:9 | raise | semmle.label | successor |
|
||||
| raise.rb:71:3:72:18 | Elsif | raise.rb:71:9:71:9 | x | semmle.label | successor |
|
||||
| raise.rb:71:9:71:9 | x | raise.rb:71:13:71:13 | 0 | semmle.label | successor |
|
||||
| raise.rb:71:9:71:13 | Binary | raise.rb:72:12:72:18 | String | semmle.label | true |
|
||||
| raise.rb:71:9:71:13 | Binary | raise.rb:74:8:74:20 | String | semmle.label | false |
|
||||
| raise.rb:71:13:71:13 | 0 | raise.rb:71:9:71:13 | Binary | semmle.label | successor |
|
||||
| raise.rb:72:5:72:18 | Return | raise.rb:68:1:77:3 | exit m7 (normal) | semmle.label | return |
|
||||
| raise.rb:72:5:72:18 | Return | raise.rb:75:1:76:15 | [ensure: return] Ensure | semmle.label | return |
|
||||
| raise.rb:72:12:72:18 | String | raise.rb:72:5:72:18 | Return | semmle.label | successor |
|
||||
| raise.rb:74:3:74:6 | puts | raise.rb:74:3:74:20 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:74:3:74:20 | MethodCall | raise.rb:76:8:76:15 | String | semmle.label | successor |
|
||||
| raise.rb:74:3:74:20 | MethodCall | raise.rb:75:1:76:15 | Ensure | semmle.label | successor |
|
||||
| raise.rb:74:8:74:20 | String | raise.rb:74:3:74:6 | puts | semmle.label | successor |
|
||||
| raise.rb:75:1:76:15 | Ensure | raise.rb:76:8:76:15 | String | semmle.label | successor |
|
||||
| raise.rb:75:1:76:15 | [ensure: raise] Ensure | raise.rb:76:8:76:15 | [ensure: raise] String | semmle.label | successor |
|
||||
| raise.rb:75:1:76:15 | [ensure: return] Ensure | raise.rb:76:8:76:15 | [ensure: return] String | semmle.label | successor |
|
||||
| raise.rb:76:3:76:6 | [ensure: raise] puts | raise.rb:76:3:76:15 | [ensure: raise] MethodCall | semmle.label | successor |
|
||||
| raise.rb:76:3:76:6 | [ensure: return] puts | raise.rb:76:3:76:15 | [ensure: return] MethodCall | semmle.label | successor |
|
||||
| raise.rb:76:3:76:6 | puts | raise.rb:76:3:76:15 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:76:3:76:15 | MethodCall | raise.rb:68:1:77:3 | exit m7 (normal) | semmle.label | successor |
|
||||
| raise.rb:76:3:76:15 | [ensure: raise] MethodCall | raise.rb:68:1:77:3 | exit m7 (abnormal) | semmle.label | raise |
|
||||
| raise.rb:76:3:76:15 | [ensure: return] MethodCall | raise.rb:68:1:77:3 | exit m7 (normal) | semmle.label | return |
|
||||
| raise.rb:76:8:76:15 | String | raise.rb:76:3:76:6 | puts | semmle.label | successor |
|
||||
| raise.rb:76:8:76:15 | [ensure: raise] String | raise.rb:76:3:76:6 | [ensure: raise] puts | semmle.label | successor |
|
||||
| raise.rb:76:8:76:15 | [ensure: return] String | raise.rb:76:3:76:6 | [ensure: return] puts | semmle.label | successor |
|
||||
| raise.rb:79:1:92:3 | enter m8 | raise.rb:79:8:79:8 | x | semmle.label | successor |
|
||||
| raise.rb:79:1:92:3 | exit m8 (abnormal) | raise.rb:79:1:92:3 | exit m8 | semmle.label | successor |
|
||||
| raise.rb:79:1:92:3 | exit m8 (normal) | raise.rb:79:1:92:3 | exit m8 | semmle.label | successor |
|
||||
@@ -1824,18 +2057,30 @@ edges
|
||||
| raise.rb:82:8:82:12 | Binary | raise.rb:84:5:85:20 | Elsif | semmle.label | false |
|
||||
| raise.rb:82:12:82:12 | 2 | raise.rb:82:8:82:12 | Binary | semmle.label | successor |
|
||||
| raise.rb:83:7:83:11 | raise | raise.rb:83:7:83:19 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:83:7:83:19 | MethodCall | raise.rb:79:1:92:3 | exit m8 (abnormal) | semmle.label | raise |
|
||||
| raise.rb:83:7:83:19 | MethodCall | raise.rb:88:3:89:17 | [ensure: raise] Ensure | semmle.label | raise |
|
||||
| raise.rb:83:13:83:19 | String | raise.rb:83:7:83:11 | raise | semmle.label | successor |
|
||||
| raise.rb:84:5:85:20 | Elsif | raise.rb:84:11:84:11 | x | semmle.label | successor |
|
||||
| raise.rb:84:11:84:11 | x | raise.rb:84:15:84:15 | 0 | semmle.label | successor |
|
||||
| raise.rb:84:11:84:15 | Binary | raise.rb:85:14:85:20 | String | semmle.label | true |
|
||||
| raise.rb:84:11:84:15 | Binary | raise.rb:87:10:87:22 | String | semmle.label | false |
|
||||
| raise.rb:84:15:84:15 | 0 | raise.rb:84:11:84:15 | Binary | semmle.label | successor |
|
||||
| raise.rb:85:7:85:20 | Return | raise.rb:79:1:92:3 | exit m8 (normal) | semmle.label | return |
|
||||
| raise.rb:85:7:85:20 | Return | raise.rb:88:3:89:17 | [ensure: return] Ensure | semmle.label | return |
|
||||
| raise.rb:85:14:85:20 | String | raise.rb:85:7:85:20 | Return | semmle.label | successor |
|
||||
| raise.rb:87:5:87:8 | puts | raise.rb:87:5:87:22 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:87:5:87:22 | MethodCall | raise.rb:91:8:91:15 | String | semmle.label | successor |
|
||||
| raise.rb:87:5:87:22 | MethodCall | raise.rb:88:3:89:17 | Ensure | semmle.label | successor |
|
||||
| raise.rb:87:10:87:22 | String | raise.rb:87:5:87:8 | puts | semmle.label | successor |
|
||||
| raise.rb:88:3:89:17 | Ensure | raise.rb:89:10:89:17 | String | semmle.label | successor |
|
||||
| raise.rb:88:3:89:17 | [ensure: raise] Ensure | raise.rb:89:10:89:17 | [ensure: raise] String | semmle.label | successor |
|
||||
| raise.rb:88:3:89:17 | [ensure: return] Ensure | raise.rb:89:10:89:17 | [ensure: return] String | semmle.label | successor |
|
||||
| raise.rb:89:5:89:8 | [ensure: raise] puts | raise.rb:89:5:89:17 | [ensure: raise] MethodCall | semmle.label | successor |
|
||||
| raise.rb:89:5:89:8 | [ensure: return] puts | raise.rb:89:5:89:17 | [ensure: return] MethodCall | semmle.label | successor |
|
||||
| raise.rb:89:5:89:8 | puts | raise.rb:89:5:89:17 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:89:5:89:17 | MethodCall | raise.rb:91:8:91:15 | String | semmle.label | successor |
|
||||
| raise.rb:89:5:89:17 | [ensure: raise] MethodCall | raise.rb:79:1:92:3 | exit m8 (abnormal) | semmle.label | raise |
|
||||
| raise.rb:89:5:89:17 | [ensure: return] MethodCall | raise.rb:79:1:92:3 | exit m8 (normal) | semmle.label | return |
|
||||
| raise.rb:89:10:89:17 | String | raise.rb:89:5:89:8 | puts | semmle.label | successor |
|
||||
| raise.rb:89:10:89:17 | [ensure: raise] String | raise.rb:89:5:89:8 | [ensure: raise] puts | semmle.label | successor |
|
||||
| raise.rb:89:10:89:17 | [ensure: return] String | raise.rb:89:5:89:8 | [ensure: return] puts | semmle.label | successor |
|
||||
| raise.rb:91:3:91:6 | puts | raise.rb:91:3:91:15 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:91:3:91:15 | MethodCall | raise.rb:79:1:92:3 | exit m8 (normal) | semmle.label | successor |
|
||||
| raise.rb:91:8:91:15 | String | raise.rb:91:3:91:6 | puts | semmle.label | successor |
|
||||
@@ -1854,30 +2099,105 @@ edges
|
||||
| raise.rb:97:8:97:12 | Binary | raise.rb:99:5:100:20 | Elsif | semmle.label | false |
|
||||
| raise.rb:97:12:97:12 | 2 | raise.rb:97:8:97:12 | Binary | semmle.label | successor |
|
||||
| raise.rb:98:7:98:11 | raise | raise.rb:98:7:98:19 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:98:7:98:19 | MethodCall | raise.rb:94:1:119:3 | exit m9 (abnormal) | semmle.label | raise |
|
||||
| raise.rb:98:7:98:19 | MethodCall | raise.rb:103:3:111:7 | [ensure: raise] Ensure | semmle.label | raise |
|
||||
| raise.rb:98:13:98:19 | String | raise.rb:98:7:98:11 | raise | semmle.label | successor |
|
||||
| raise.rb:99:5:100:20 | Elsif | raise.rb:99:11:99:11 | x | semmle.label | successor |
|
||||
| raise.rb:99:11:99:11 | x | raise.rb:99:15:99:15 | 0 | semmle.label | successor |
|
||||
| raise.rb:99:11:99:15 | Binary | raise.rb:100:14:100:20 | String | semmle.label | true |
|
||||
| raise.rb:99:11:99:15 | Binary | raise.rb:102:10:102:22 | String | semmle.label | false |
|
||||
| raise.rb:99:15:99:15 | 0 | raise.rb:99:11:99:15 | Binary | semmle.label | successor |
|
||||
| raise.rb:100:7:100:20 | Return | raise.rb:94:1:119:3 | exit m9 (normal) | semmle.label | return |
|
||||
| raise.rb:100:7:100:20 | Return | raise.rb:103:3:111:7 | [ensure: return] Ensure | semmle.label | return |
|
||||
| raise.rb:100:14:100:20 | String | raise.rb:100:7:100:20 | Return | semmle.label | successor |
|
||||
| raise.rb:102:5:102:8 | puts | raise.rb:102:5:102:22 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:102:5:102:22 | MethodCall | raise.rb:113:8:113:15 | String | semmle.label | successor |
|
||||
| raise.rb:102:5:102:22 | MethodCall | raise.rb:103:3:111:7 | Ensure | semmle.label | successor |
|
||||
| raise.rb:102:10:102:22 | String | raise.rb:102:5:102:8 | puts | semmle.label | successor |
|
||||
| raise.rb:103:3:111:7 | Ensure | raise.rb:104:10:104:23 | String | semmle.label | successor |
|
||||
| raise.rb:103:3:111:7 | [ensure: raise] Ensure | raise.rb:104:10:104:23 | [ensure: raise] String | semmle.label | successor |
|
||||
| raise.rb:103:3:111:7 | [ensure: return] Ensure | raise.rb:104:10:104:23 | [ensure: return] String | semmle.label | successor |
|
||||
| raise.rb:104:5:104:8 | [ensure: raise] puts | raise.rb:104:5:104:23 | [ensure: raise] MethodCall | semmle.label | successor |
|
||||
| raise.rb:104:5:104:8 | [ensure: return] puts | raise.rb:104:5:104:23 | [ensure: return] MethodCall | semmle.label | successor |
|
||||
| raise.rb:104:5:104:8 | puts | raise.rb:104:5:104:23 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:104:5:104:23 | MethodCall | raise.rb:106:7:108:9 | If | semmle.label | successor |
|
||||
| raise.rb:104:5:104:23 | [ensure: raise] MethodCall | raise.rb:106:7:108:9 | [ensure: raise] If | semmle.label | successor |
|
||||
| raise.rb:104:5:104:23 | [ensure: return] MethodCall | raise.rb:106:7:108:9 | [ensure: return] If | semmle.label | successor |
|
||||
| raise.rb:104:10:104:23 | String | raise.rb:104:5:104:8 | puts | semmle.label | successor |
|
||||
| raise.rb:104:10:104:23 | [ensure: raise] String | raise.rb:104:5:104:8 | [ensure: raise] puts | semmle.label | successor |
|
||||
| raise.rb:104:10:104:23 | [ensure: return] String | raise.rb:104:5:104:8 | [ensure: return] puts | semmle.label | successor |
|
||||
| raise.rb:106:7:108:9 | If | raise.rb:106:10:106:11 | b1 | semmle.label | successor |
|
||||
| raise.rb:106:7:108:9 | [ensure: raise] If | raise.rb:106:10:106:11 | [ensure: raise] b1 | semmle.label | successor |
|
||||
| raise.rb:106:7:108:9 | [ensure: return] If | raise.rb:106:10:106:11 | [ensure: return] b1 | semmle.label | successor |
|
||||
| raise.rb:106:10:106:11 | [ensure: raise] b1 | raise.rb:107:15:107:26 | [ensure: raise] String | semmle.label | true |
|
||||
| raise.rb:106:10:106:11 | [ensure: raise] b1 | raise.rb:109:5:110:25 | [ensure: raise] Ensure | semmle.label | false |
|
||||
| raise.rb:106:10:106:11 | [ensure: return] b1 | raise.rb:107:15:107:26 | [ensure: return] String | semmle.label | true |
|
||||
| raise.rb:106:10:106:11 | [ensure: return] b1 | raise.rb:109:5:110:25 | [ensure: return] Ensure | semmle.label | false |
|
||||
| raise.rb:106:10:106:11 | b1 | raise.rb:107:15:107:26 | String | semmle.label | true |
|
||||
| raise.rb:106:10:106:11 | b1 | raise.rb:109:5:110:25 | Ensure | semmle.label | false |
|
||||
| raise.rb:107:9:107:13 | [ensure: raise] raise | raise.rb:107:9:107:26 | [ensure: raise] MethodCall | semmle.label | successor |
|
||||
| raise.rb:107:9:107:13 | [ensure: return] raise | raise.rb:107:9:107:26 | [ensure: return] MethodCall | semmle.label | successor |
|
||||
| raise.rb:107:9:107:13 | raise | raise.rb:107:9:107:26 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:107:9:107:26 | MethodCall | raise.rb:109:5:110:25 | [ensure(1): raise] Ensure | semmle.label | raise |
|
||||
| raise.rb:107:9:107:26 | [ensure: raise] MethodCall | raise.rb:109:5:110:25 | [ensure: raise, ensure(1): raise] Ensure | semmle.label | raise |
|
||||
| raise.rb:107:9:107:26 | [ensure: return] MethodCall | raise.rb:109:5:110:25 | [ensure: return, ensure(1): raise] Ensure | semmle.label | raise |
|
||||
| raise.rb:107:15:107:26 | String | raise.rb:107:9:107:13 | raise | semmle.label | successor |
|
||||
| raise.rb:107:15:107:26 | [ensure: raise] String | raise.rb:107:9:107:13 | [ensure: raise] raise | semmle.label | successor |
|
||||
| raise.rb:107:15:107:26 | [ensure: return] String | raise.rb:107:9:107:13 | [ensure: return] raise | semmle.label | successor |
|
||||
| raise.rb:109:5:110:25 | Ensure | raise.rb:110:12:110:25 | String | semmle.label | successor |
|
||||
| raise.rb:109:5:110:25 | [ensure(1): raise] Ensure | raise.rb:110:12:110:25 | [ensure(1): raise] String | semmle.label | successor |
|
||||
| raise.rb:109:5:110:25 | [ensure: raise, ensure(1): raise] Ensure | raise.rb:110:12:110:25 | [ensure: raise, ensure(1): raise] String | semmle.label | successor |
|
||||
| raise.rb:109:5:110:25 | [ensure: raise] Ensure | raise.rb:110:12:110:25 | [ensure: raise] String | semmle.label | successor |
|
||||
| raise.rb:109:5:110:25 | [ensure: return, ensure(1): raise] Ensure | raise.rb:110:12:110:25 | [ensure: return, ensure(1): raise] String | semmle.label | successor |
|
||||
| raise.rb:109:5:110:25 | [ensure: return] Ensure | raise.rb:110:12:110:25 | [ensure: return] String | semmle.label | successor |
|
||||
| raise.rb:110:7:110:10 | [ensure(1): raise] puts | raise.rb:110:7:110:25 | [ensure(1): raise] MethodCall | semmle.label | successor |
|
||||
| raise.rb:110:7:110:10 | [ensure: raise, ensure(1): raise] puts | raise.rb:110:7:110:25 | [ensure: raise, ensure(1): raise] MethodCall | semmle.label | successor |
|
||||
| raise.rb:110:7:110:10 | [ensure: raise] puts | raise.rb:110:7:110:25 | [ensure: raise] MethodCall | semmle.label | successor |
|
||||
| raise.rb:110:7:110:10 | [ensure: return, ensure(1): raise] puts | raise.rb:110:7:110:25 | [ensure: return, ensure(1): raise] MethodCall | semmle.label | successor |
|
||||
| raise.rb:110:7:110:10 | [ensure: return] puts | raise.rb:110:7:110:25 | [ensure: return] MethodCall | semmle.label | successor |
|
||||
| raise.rb:110:7:110:10 | puts | raise.rb:110:7:110:25 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:110:7:110:25 | MethodCall | raise.rb:113:8:113:15 | String | semmle.label | successor |
|
||||
| raise.rb:110:7:110:25 | [ensure(1): raise] MethodCall | raise.rb:114:1:118:5 | [ensure: raise] Ensure | semmle.label | raise |
|
||||
| raise.rb:110:7:110:25 | [ensure: raise, ensure(1): raise] MethodCall | raise.rb:114:1:118:5 | [ensure: raise] Ensure | semmle.label | raise |
|
||||
| raise.rb:110:7:110:25 | [ensure: raise] MethodCall | raise.rb:114:1:118:5 | [ensure: raise] Ensure | semmle.label | raise |
|
||||
| raise.rb:110:7:110:25 | [ensure: return, ensure(1): raise] MethodCall | raise.rb:114:1:118:5 | [ensure: raise] Ensure | semmle.label | raise |
|
||||
| raise.rb:110:7:110:25 | [ensure: return] MethodCall | raise.rb:114:1:118:5 | [ensure: return] Ensure | semmle.label | return |
|
||||
| raise.rb:110:12:110:25 | String | raise.rb:110:7:110:10 | puts | semmle.label | successor |
|
||||
| raise.rb:110:12:110:25 | [ensure(1): raise] String | raise.rb:110:7:110:10 | [ensure(1): raise] puts | semmle.label | successor |
|
||||
| raise.rb:110:12:110:25 | [ensure: raise, ensure(1): raise] String | raise.rb:110:7:110:10 | [ensure: raise, ensure(1): raise] puts | semmle.label | successor |
|
||||
| raise.rb:110:12:110:25 | [ensure: raise] String | raise.rb:110:7:110:10 | [ensure: raise] puts | semmle.label | successor |
|
||||
| raise.rb:110:12:110:25 | [ensure: return, ensure(1): raise] String | raise.rb:110:7:110:10 | [ensure: return, ensure(1): raise] puts | semmle.label | successor |
|
||||
| raise.rb:110:12:110:25 | [ensure: return] String | raise.rb:110:7:110:10 | [ensure: return] puts | semmle.label | successor |
|
||||
| raise.rb:113:3:113:6 | puts | raise.rb:113:3:113:15 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:113:3:113:15 | MethodCall | raise.rb:115:8:115:22 | String | semmle.label | successor |
|
||||
| raise.rb:113:3:113:15 | MethodCall | raise.rb:114:1:118:5 | Ensure | semmle.label | successor |
|
||||
| raise.rb:113:8:113:15 | String | raise.rb:113:3:113:6 | puts | semmle.label | successor |
|
||||
| raise.rb:114:1:118:5 | Ensure | raise.rb:115:8:115:22 | String | semmle.label | successor |
|
||||
| raise.rb:114:1:118:5 | [ensure: raise] Ensure | raise.rb:115:8:115:22 | [ensure: raise] String | semmle.label | successor |
|
||||
| raise.rb:114:1:118:5 | [ensure: return] Ensure | raise.rb:115:8:115:22 | [ensure: return] String | semmle.label | successor |
|
||||
| raise.rb:115:3:115:6 | [ensure: raise] puts | raise.rb:115:3:115:22 | [ensure: raise] MethodCall | semmle.label | successor |
|
||||
| raise.rb:115:3:115:6 | [ensure: return] puts | raise.rb:115:3:115:22 | [ensure: return] MethodCall | semmle.label | successor |
|
||||
| raise.rb:115:3:115:6 | puts | raise.rb:115:3:115:22 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:115:3:115:22 | MethodCall | raise.rb:116:3:118:5 | If | semmle.label | successor |
|
||||
| raise.rb:115:3:115:22 | [ensure: raise] MethodCall | raise.rb:116:3:118:5 | [ensure: raise] If | semmle.label | successor |
|
||||
| raise.rb:115:3:115:22 | [ensure: return] MethodCall | raise.rb:116:3:118:5 | [ensure: return] If | semmle.label | successor |
|
||||
| raise.rb:115:8:115:22 | String | raise.rb:115:3:115:6 | puts | semmle.label | successor |
|
||||
| raise.rb:115:8:115:22 | [ensure: raise] String | raise.rb:115:3:115:6 | [ensure: raise] puts | semmle.label | successor |
|
||||
| raise.rb:115:8:115:22 | [ensure: return] String | raise.rb:115:3:115:6 | [ensure: return] puts | semmle.label | successor |
|
||||
| raise.rb:116:3:118:5 | If | raise.rb:116:6:116:7 | b2 | semmle.label | successor |
|
||||
| raise.rb:116:3:118:5 | [ensure: raise] If | raise.rb:116:6:116:7 | [ensure: raise] b2 | semmle.label | successor |
|
||||
| raise.rb:116:3:118:5 | [ensure: return] If | raise.rb:116:6:116:7 | [ensure: return] b2 | semmle.label | successor |
|
||||
| raise.rb:116:6:116:7 | [ensure: raise] b2 | raise.rb:94:1:119:3 | exit m9 (abnormal) | semmle.label | raise |
|
||||
| raise.rb:116:6:116:7 | [ensure: raise] b2 | raise.rb:117:11:117:22 | [ensure: raise] String | semmle.label | true |
|
||||
| raise.rb:116:6:116:7 | [ensure: return] b2 | raise.rb:94:1:119:3 | exit m9 (normal) | semmle.label | return |
|
||||
| raise.rb:116:6:116:7 | [ensure: return] b2 | raise.rb:117:11:117:22 | [ensure: return] String | semmle.label | true |
|
||||
| raise.rb:116:6:116:7 | b2 | raise.rb:94:1:119:3 | exit m9 (normal) | semmle.label | false |
|
||||
| raise.rb:116:6:116:7 | b2 | raise.rb:117:11:117:22 | String | semmle.label | true |
|
||||
| raise.rb:117:5:117:9 | [ensure: raise] raise | raise.rb:117:5:117:22 | [ensure: raise] MethodCall | semmle.label | successor |
|
||||
| raise.rb:117:5:117:9 | [ensure: return] raise | raise.rb:117:5:117:22 | [ensure: return] MethodCall | semmle.label | successor |
|
||||
| raise.rb:117:5:117:9 | raise | raise.rb:117:5:117:22 | MethodCall | semmle.label | successor |
|
||||
| raise.rb:117:5:117:22 | MethodCall | raise.rb:94:1:119:3 | exit m9 (abnormal) | semmle.label | raise |
|
||||
| raise.rb:117:5:117:22 | [ensure: raise] MethodCall | raise.rb:94:1:119:3 | exit m9 (abnormal) | semmle.label | raise |
|
||||
| raise.rb:117:5:117:22 | [ensure: return] MethodCall | raise.rb:94:1:119:3 | exit m9 (abnormal) | semmle.label | raise |
|
||||
| raise.rb:117:11:117:22 | String | raise.rb:117:5:117:9 | raise | semmle.label | successor |
|
||||
| raise.rb:117:11:117:22 | [ensure: raise] String | raise.rb:117:5:117:9 | [ensure: raise] raise | semmle.label | successor |
|
||||
| raise.rb:117:11:117:22 | [ensure: return] String | raise.rb:117:5:117:9 | [ensure: return] raise | semmle.label | successor |
|
||||
| raise.rb:121:1:124:3 | enter m10 | raise.rb:121:20:121:30 | String | semmle.label | successor |
|
||||
| raise.rb:121:1:124:3 | exit m10 (abnormal) | raise.rb:121:1:124:3 | exit m10 | semmle.label | successor |
|
||||
| raise.rb:121:14:121:18 | raise | raise.rb:121:14:121:30 | MethodCall | semmle.label | successor |
|
||||
|
||||
Reference in New Issue
Block a user