mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Merge pull request #7283 from aibaars/ruby-pattern-matching-cfg
Ruby: pattern matching: CFG
This commit is contained in:
@@ -246,8 +246,6 @@ private module Cached {
|
||||
explicitAssignmentNode(g, _)
|
||||
or
|
||||
casePattern(g)
|
||||
or
|
||||
classReferencePattern(g)
|
||||
)
|
||||
} or
|
||||
TScopeResolutionMethodCall(Ruby::ScopeResolution g, Ruby::Identifier i) {
|
||||
@@ -293,8 +291,6 @@ private module Cached {
|
||||
explicitAssignmentNode(g, _)
|
||||
or
|
||||
casePattern(g)
|
||||
or
|
||||
classReferencePattern(g)
|
||||
} or
|
||||
TTokenMethodName(MethodName::Token g) { MethodName::range(g) } or
|
||||
TTokenSuperCall(Ruby::Super g) { vcall(g) } or
|
||||
|
||||
@@ -48,13 +48,7 @@ predicate casePattern(Ruby::AstNode node) {
|
||||
node = any(Ruby::KeywordPattern parent).getValue()
|
||||
or
|
||||
node = any(Ruby::ParenthesizedPattern parent).getChild()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is a class reference used in an
|
||||
* array, find, or hash pattern.
|
||||
*/
|
||||
predicate classReferencePattern(Ruby::AstNode node) {
|
||||
or
|
||||
node = any(Ruby::ArrayPattern p).getClass()
|
||||
or
|
||||
node = any(Ruby::FindPattern p).getClass()
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
private import codeql.ruby.AST
|
||||
private import codeql.ruby.ast.internal.AST
|
||||
private import codeql.ruby.ast.internal.Control
|
||||
private import codeql.ruby.controlflow.ControlFlowGraph
|
||||
private import ControlFlowGraphImpl
|
||||
private import NonReturning
|
||||
@@ -27,6 +28,10 @@ private newtype TCompletion =
|
||||
outer instanceof NonNestedNormalCompletion and
|
||||
nestLevel = 0
|
||||
or
|
||||
inner instanceof TBooleanCompletion and
|
||||
outer instanceof TMatchingCompletion and
|
||||
nestLevel = 0
|
||||
or
|
||||
inner instanceof NormalCompletion and
|
||||
nestedEnsureCompletion(outer, nestLevel)
|
||||
}
|
||||
@@ -81,8 +86,9 @@ private predicate mayRaise(Call c) {
|
||||
|
||||
/** A completion of a statement or an expression. */
|
||||
abstract class Completion extends TCompletion {
|
||||
/** Holds if this completion is valid for node `n`. */
|
||||
predicate isValidFor(AstNode n) {
|
||||
private predicate isValidForSpecific(AstNode n) {
|
||||
exists(AstNode other | n = other.getDesugared() and this.isValidForSpecific(other))
|
||||
or
|
||||
this = n.(NonReturningCall).getACompletion()
|
||||
or
|
||||
completionIsValidForStmt(n, this)
|
||||
@@ -98,15 +104,26 @@ abstract class Completion extends TCompletion {
|
||||
mustHaveMatchingCompletion(n) and
|
||||
this = TMatchingCompletion(_)
|
||||
or
|
||||
n = any(RescueModifierExpr parent).getBody() and this = TRaiseCompletion()
|
||||
n = any(RescueModifierExpr parent).getBody() and
|
||||
this = [TSimpleCompletion().(TCompletion), TRaiseCompletion()]
|
||||
or
|
||||
mayRaise(n) and
|
||||
this = TRaiseCompletion()
|
||||
(
|
||||
mayRaise(n)
|
||||
or
|
||||
n instanceof CaseMatch and not exists(n.(CaseExpr).getElseBranch())
|
||||
) and
|
||||
(
|
||||
this = TRaiseCompletion()
|
||||
or
|
||||
this = TSimpleCompletion() and not n instanceof NonReturningCall
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if this completion is valid for node `n`. */
|
||||
predicate isValidFor(AstNode n) {
|
||||
this.isValidForSpecific(n)
|
||||
or
|
||||
not n instanceof NonReturningCall and
|
||||
not completionIsValidForStmt(n, _) and
|
||||
not mustHaveBooleanCompletion(n) and
|
||||
not mustHaveMatchingCompletion(n) and
|
||||
not any(Completion c).isValidForSpecific(n) and
|
||||
this = TSimpleCompletion()
|
||||
}
|
||||
|
||||
@@ -172,6 +189,8 @@ private predicate inBooleanContext(AstNode n) {
|
||||
or
|
||||
n = any(ConditionalLoop parent).getCondition()
|
||||
or
|
||||
n = any(InClause parent).getCondition()
|
||||
or
|
||||
exists(LogicalAndExpr parent |
|
||||
n = parent.getLeftOperand()
|
||||
or
|
||||
@@ -218,6 +237,10 @@ private predicate inMatchingContext(AstNode n) {
|
||||
w.getPattern(_) = n
|
||||
)
|
||||
or
|
||||
n instanceof CasePattern
|
||||
or
|
||||
n = any(VariableReferencePattern p).getVariableAccess()
|
||||
or
|
||||
n.(Trees::DefaultValueParameterTree).hasDefaultValue()
|
||||
}
|
||||
|
||||
@@ -241,7 +264,7 @@ class SimpleCompletion extends NonNestedNormalCompletion, TSimpleCompletion {
|
||||
* the successor. Either a Boolean completion (`BooleanCompletion`), or a matching
|
||||
* completion (`MatchingCompletion`).
|
||||
*/
|
||||
abstract class ConditionalCompletion extends NonNestedNormalCompletion {
|
||||
abstract class ConditionalCompletion extends NormalCompletion {
|
||||
boolean value;
|
||||
|
||||
bindingset[value]
|
||||
@@ -255,7 +278,7 @@ abstract class ConditionalCompletion extends NonNestedNormalCompletion {
|
||||
* A completion that represents evaluation of an expression
|
||||
* with a Boolean value.
|
||||
*/
|
||||
class BooleanCompletion extends ConditionalCompletion, TBooleanCompletion {
|
||||
class BooleanCompletion extends ConditionalCompletion, NonNestedNormalCompletion, TBooleanCompletion {
|
||||
BooleanCompletion() { this = TBooleanCompletion(value) }
|
||||
|
||||
/** Gets the dual Boolean completion. */
|
||||
@@ -280,10 +303,16 @@ class FalseCompletion extends BooleanCompletion {
|
||||
* A completion that represents evaluation of a matching test, for example
|
||||
* a test in a `rescue` statement.
|
||||
*/
|
||||
class MatchingCompletion extends ConditionalCompletion, TMatchingCompletion {
|
||||
MatchingCompletion() { this = TMatchingCompletion(value) }
|
||||
class MatchingCompletion extends ConditionalCompletion {
|
||||
MatchingCompletion() {
|
||||
this = TMatchingCompletion(value)
|
||||
or
|
||||
this = TNestedCompletion(_, TMatchingCompletion(value), _)
|
||||
}
|
||||
|
||||
override MatchingSuccessor getAMatchingSuccessorType() { result.getValue() = value }
|
||||
override ConditionalSuccessor getAMatchingSuccessorType() {
|
||||
this = TMatchingCompletion(result.(MatchingSuccessor).getValue())
|
||||
}
|
||||
|
||||
override string toString() { if value = true then result = "match" else result = "no-match" }
|
||||
}
|
||||
@@ -440,7 +469,9 @@ abstract class NestedCompletion extends Completion, TNestedCompletion {
|
||||
NestedCompletion() { this = TNestedCompletion(inner, outer, nestLevel) }
|
||||
|
||||
/** Gets a completion that is compatible with the inner completion. */
|
||||
abstract Completion getAnInnerCompatibleCompletion();
|
||||
Completion getAnInnerCompatibleCompletion() {
|
||||
result.getOuterCompletion() = this.getInnerCompletion()
|
||||
}
|
||||
|
||||
/** Gets the level of this nested completion. */
|
||||
final int getNestLevel() { result = nestLevel }
|
||||
@@ -483,9 +514,39 @@ class NestedEnsureCompletion extends NestedCompletion {
|
||||
|
||||
override Completion getOuterCompletion() { result = outer }
|
||||
|
||||
override Completion getAnInnerCompatibleCompletion() {
|
||||
result.getOuterCompletion() = this.getInnerCompletion()
|
||||
}
|
||||
|
||||
override SuccessorType getAMatchingSuccessorType() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A completion used for conditions in pattern matching:
|
||||
*
|
||||
* ```rb
|
||||
* in x if x == 5 then puts "five"
|
||||
* in x unless x == 4 then puts "not four"
|
||||
* ```
|
||||
*
|
||||
* The outer (Matching) completion indicates whether there is a match, and
|
||||
* the inner (Boolean) completion indicates what the condition evaluated
|
||||
* to.
|
||||
*
|
||||
* For the condition `x == 5` above, `TNestedCompletion(true, true, 0)` and
|
||||
* `TNestedCompletion(false, false, 0)` are both valid completions, while
|
||||
* `TNestedCompletion(true, false, 0)` and `TNestedCompletion(false, true, 0)`
|
||||
* are valid completions for `x == 4`.
|
||||
*/
|
||||
class NestedMatchingCompletion extends NestedCompletion, MatchingCompletion {
|
||||
NestedMatchingCompletion() {
|
||||
inner instanceof TBooleanCompletion and
|
||||
outer instanceof TMatchingCompletion
|
||||
}
|
||||
|
||||
override BooleanCompletion getInnerCompletion() { result = inner }
|
||||
|
||||
override MatchingCompletion getOuterCompletion() { result = outer }
|
||||
|
||||
override BooleanSuccessor getAMatchingSuccessorType() {
|
||||
result.getValue() = this.getInnerCompletion().getValue()
|
||||
}
|
||||
|
||||
override string toString() { result = NestedCompletion.super.toString() }
|
||||
}
|
||||
|
||||
@@ -419,6 +419,387 @@ module Trees {
|
||||
}
|
||||
}
|
||||
|
||||
private class CaseMatchTree extends PreOrderTree, CaseExpr, ASTInternal::TCaseMatch {
|
||||
final override predicate propagatesAbnormal(AstNode child) {
|
||||
child = this.getValue() or child = this.getABranch()
|
||||
}
|
||||
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
last(this.getABranch(), last, c) and
|
||||
not c.(MatchingCompletion).getValue() = false
|
||||
or
|
||||
not exists(this.getElseBranch()) and
|
||||
exists(MatchingCompletion lc, Expr lastBranch |
|
||||
lastBranch = max(int i | | this.getBranch(i) order by i) and
|
||||
lc.getValue() = false and
|
||||
last(lastBranch, last, lc) and
|
||||
c instanceof RaiseCompletion and
|
||||
not c instanceof NestedCompletion
|
||||
)
|
||||
}
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
pred = this and
|
||||
first(this.getValue(), succ) and
|
||||
c instanceof SimpleCompletion
|
||||
or
|
||||
last(this.getValue(), pred, c) and
|
||||
first(this.getBranch(0), succ) and
|
||||
c instanceof SimpleCompletion
|
||||
or
|
||||
exists(int i, Expr branch | branch = this.getBranch(i) |
|
||||
last(branch, pred, c) and
|
||||
first(this.getBranch(i + 1), succ) and
|
||||
c.(MatchingCompletion).getValue() = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class PatternVariableAccessTree extends LocalVariableAccessTree, LocalVariableWriteAccess,
|
||||
CasePattern {
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
super.last(last, c) and
|
||||
c.(MatchingCompletion).getValue() = true
|
||||
}
|
||||
}
|
||||
|
||||
private class ArrayPatternTree extends ControlFlowTree, ArrayPattern {
|
||||
final override predicate propagatesAbnormal(AstNode child) {
|
||||
child = this.getClass() or
|
||||
child = this.getPrefixElement(_) or
|
||||
child = this.getRestVariableAccess() or
|
||||
child = this.getSuffixElement(_)
|
||||
}
|
||||
|
||||
final override predicate first(AstNode first) {
|
||||
first(this.getClass(), first)
|
||||
or
|
||||
not exists(this.getClass()) and first = this
|
||||
}
|
||||
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
c.(MatchingCompletion).getValue() = false and
|
||||
(
|
||||
last = this and
|
||||
c.isValidFor(this)
|
||||
or
|
||||
exists(AstNode node |
|
||||
node = this.getClass() or
|
||||
node = this.getPrefixElement(_) or
|
||||
node = this.getSuffixElement(_)
|
||||
|
|
||||
last(node, last, c)
|
||||
)
|
||||
)
|
||||
or
|
||||
c.(MatchingCompletion).getValue() = true and
|
||||
last = this and
|
||||
c.isValidFor(this) and
|
||||
not exists(this.getPrefixElement(_)) and
|
||||
not exists(this.getRestVariableAccess())
|
||||
or
|
||||
c.(MatchingCompletion).getValue() = true and
|
||||
last(max(int i | | this.getPrefixElement(i) order by i), last, c) and
|
||||
not exists(this.getRestVariableAccess())
|
||||
or
|
||||
last(this.getRestVariableAccess(), last, c) and
|
||||
not exists(this.getSuffixElement(_))
|
||||
or
|
||||
c.(MatchingCompletion).getValue() = true and
|
||||
last(max(int i | | this.getSuffixElement(i) order by i), last, c)
|
||||
}
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
last(this.getClass(), pred, c) and
|
||||
succ = this and
|
||||
c.(MatchingCompletion).getValue() = true
|
||||
or
|
||||
exists(AstNode next |
|
||||
pred = this and
|
||||
c.(MatchingCompletion).getValue() = true and
|
||||
first(next, succ)
|
||||
|
|
||||
next = this.getPrefixElement(0)
|
||||
or
|
||||
not exists(this.getPrefixElement(_)) and
|
||||
next = this.getRestVariableAccess()
|
||||
)
|
||||
or
|
||||
last(max(int i | | this.getPrefixElement(i) order by i), pred, c) and
|
||||
first(this.getRestVariableAccess(), succ) and
|
||||
c.(MatchingCompletion).getValue() = true
|
||||
or
|
||||
exists(int i |
|
||||
last(this.getPrefixElement(i), pred, c) and
|
||||
first(this.getPrefixElement(i + 1), succ) and
|
||||
c.(MatchingCompletion).getValue() = true
|
||||
)
|
||||
or
|
||||
last(this.getRestVariableAccess(), pred, c) and
|
||||
first(this.getSuffixElement(0), succ) and
|
||||
c instanceof SimpleCompletion
|
||||
or
|
||||
exists(int i |
|
||||
last(this.getSuffixElement(i), pred, c) and
|
||||
first(this.getSuffixElement(i + 1), succ) and
|
||||
c.(MatchingCompletion).getValue() = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class FindPatternTree extends ControlFlowTree, FindPattern {
|
||||
final override predicate propagatesAbnormal(AstNode child) {
|
||||
child = this.getClass() or
|
||||
child = this.getPrefixVariableAccess() or
|
||||
child = this.getElement(_) or
|
||||
child = this.getSuffixVariableAccess()
|
||||
}
|
||||
|
||||
final override predicate first(AstNode first) {
|
||||
first(this.getClass(), first)
|
||||
or
|
||||
not exists(this.getClass()) and first = this
|
||||
}
|
||||
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
last(this.getSuffixVariableAccess(), last, c)
|
||||
or
|
||||
last(max(int i | | this.getElement(i) order by i), last, c) and
|
||||
not exists(this.getSuffixVariableAccess())
|
||||
or
|
||||
c.(MatchingCompletion).getValue() = false and
|
||||
(
|
||||
last = this and
|
||||
c.isValidFor(this)
|
||||
or
|
||||
exists(AstNode node | node = this.getClass() or node = this.getElement(_) |
|
||||
last(node, last, c)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
last(this.getClass(), pred, c) and
|
||||
succ = this and
|
||||
c.(MatchingCompletion).getValue() = true
|
||||
or
|
||||
exists(AstNode next |
|
||||
pred = this and
|
||||
c.(MatchingCompletion).getValue() = true and
|
||||
first(next, succ)
|
||||
|
|
||||
next = this.getPrefixVariableAccess()
|
||||
or
|
||||
not exists(this.getPrefixVariableAccess()) and
|
||||
next = this.getElement(0)
|
||||
)
|
||||
or
|
||||
last(this.getPrefixVariableAccess(), pred, c) and
|
||||
first(this.getElement(0), succ) and
|
||||
c instanceof SimpleCompletion
|
||||
or
|
||||
c.(MatchingCompletion).getValue() = true and
|
||||
exists(int i |
|
||||
last(this.getElement(i), pred, c) and
|
||||
first(this.getElement(i + 1), succ)
|
||||
)
|
||||
or
|
||||
c.(MatchingCompletion).getValue() = true and
|
||||
last(max(int i | | this.getElement(i) order by i), pred, c) and
|
||||
first(this.getSuffixVariableAccess(), succ)
|
||||
}
|
||||
}
|
||||
|
||||
private class HashPatternTree extends ControlFlowTree, HashPattern {
|
||||
final override predicate propagatesAbnormal(AstNode child) {
|
||||
child = this.getClass() or
|
||||
child = this.getValue(_) or
|
||||
child = this.getRestVariableAccess()
|
||||
}
|
||||
|
||||
final override predicate first(AstNode first) {
|
||||
first(this.getClass(), first)
|
||||
or
|
||||
not exists(this.getClass()) and first = this
|
||||
}
|
||||
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
c.(MatchingCompletion).getValue() = false and
|
||||
(
|
||||
last = this and
|
||||
c.isValidFor(this)
|
||||
or
|
||||
exists(AstNode node |
|
||||
node = this.getClass() or
|
||||
node = this.getValue(_)
|
||||
|
|
||||
last(node, last, c)
|
||||
)
|
||||
)
|
||||
or
|
||||
c.(MatchingCompletion).getValue() = true and
|
||||
last = this and
|
||||
not exists(this.getValue(_)) and
|
||||
not exists(this.getRestVariableAccess())
|
||||
or
|
||||
c.(MatchingCompletion).getValue() = true and
|
||||
last(max(int i | | this.getValue(i) order by i), last, c) and
|
||||
not exists(this.getRestVariableAccess())
|
||||
or
|
||||
last(this.getRestVariableAccess(), last, c)
|
||||
}
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
last(this.getClass(), pred, c) and
|
||||
succ = this and
|
||||
c.(MatchingCompletion).getValue() = true
|
||||
or
|
||||
exists(AstNode next |
|
||||
pred = this and
|
||||
c.(MatchingCompletion).getValue() = true and
|
||||
first(next, succ)
|
||||
|
|
||||
next = this.getValue(0)
|
||||
or
|
||||
not exists(this.getValue(_)) and
|
||||
next = this.getRestVariableAccess()
|
||||
)
|
||||
or
|
||||
last(max(int i | | this.getValue(i) order by i), pred, c) and
|
||||
first(this.getRestVariableAccess(), succ) and
|
||||
c.(MatchingCompletion).getValue() = true
|
||||
or
|
||||
exists(int i |
|
||||
last(this.getValue(i), pred, c) and
|
||||
first(this.getValue(i + 1), succ) and
|
||||
c.(MatchingCompletion).getValue() = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class LineLiteralTree extends LeafTree, LineLiteral { }
|
||||
|
||||
private class FileLiteralTree extends LeafTree, FileLiteral { }
|
||||
|
||||
private class EncodingLiteralTree extends LeafTree, EncodingLiteral { }
|
||||
|
||||
private class AlternativePatternTree extends PreOrderTree, AlternativePattern {
|
||||
final override predicate propagatesAbnormal(AstNode child) { child = this.getAnAlternative() }
|
||||
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
last(this.getAnAlternative(), last, c) and
|
||||
c.(MatchingCompletion).getValue() = true
|
||||
or
|
||||
last(max(int i | | this.getAlternative(i) order by i), last, c) and
|
||||
c.(MatchingCompletion).getValue() = false
|
||||
}
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
pred = this and
|
||||
first(this.getAlternative(0), succ) and
|
||||
c instanceof SimpleCompletion
|
||||
or
|
||||
exists(int i |
|
||||
last(this.getAlternative(i), pred, c) and
|
||||
first(this.getAlternative(i + 1), succ) and
|
||||
c.(MatchingCompletion).getValue() = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class AsPatternTree extends PreOrderTree, AsPattern {
|
||||
final override predicate propagatesAbnormal(AstNode child) { child = this.getPattern() }
|
||||
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
last(this.getPattern(), last, c) and
|
||||
c.(MatchingCompletion).getValue() = false
|
||||
or
|
||||
last(this.getVariableAccess(), last, c)
|
||||
}
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
pred = this and
|
||||
first(this.getPattern(), succ) and
|
||||
c instanceof SimpleCompletion
|
||||
or
|
||||
last(this.getPattern(), pred, c) and
|
||||
first(this.getVariableAccess(), succ) and
|
||||
c.(MatchingCompletion).getValue() = true
|
||||
}
|
||||
}
|
||||
|
||||
private class ParenthesizedPatternTree extends StandardPreOrderTree, ParenthesizedPattern {
|
||||
override ControlFlowTree getChildElement(int i) { result = this.getPattern() and i = 0 }
|
||||
}
|
||||
|
||||
private class VariableReferencePatternTree extends StandardPreOrderTree, VariableReferencePattern {
|
||||
override ControlFlowTree getChildElement(int i) { result = this.getVariableAccess() and i = 0 }
|
||||
}
|
||||
|
||||
private class InClauseTree extends PreOrderTree, InClause {
|
||||
final override predicate propagatesAbnormal(AstNode child) {
|
||||
child = this.getPattern() or
|
||||
child = this.getCondition()
|
||||
}
|
||||
|
||||
private predicate lastCondition(AstNode last, BooleanCompletion c, boolean flag) {
|
||||
last(this.getCondition(), last, c) and
|
||||
(
|
||||
flag = true and this.hasIfCondition()
|
||||
or
|
||||
flag = false and this.hasUnlessCondition()
|
||||
)
|
||||
}
|
||||
|
||||
final override predicate last(AstNode last, Completion c) {
|
||||
last(this.getPattern(), last, c) and
|
||||
c.(MatchingCompletion).getValue() = false
|
||||
or
|
||||
exists(BooleanCompletion bc, boolean flag, MatchingCompletion mc |
|
||||
lastCondition(last, bc, flag) and
|
||||
c =
|
||||
any(NestedMatchingCompletion nmc |
|
||||
nmc.getInnerCompletion() = bc and nmc.getOuterCompletion() = mc
|
||||
)
|
||||
|
|
||||
mc.getValue() = false and
|
||||
bc.getValue() = flag.booleanNot()
|
||||
or
|
||||
not exists(this.getBody()) and
|
||||
mc.getValue() = true and
|
||||
bc.getValue() = flag
|
||||
)
|
||||
or
|
||||
last(this.getBody(), last, c)
|
||||
or
|
||||
not exists(this.getBody()) and
|
||||
not exists(this.getCondition()) and
|
||||
last(this.getPattern(), last, c)
|
||||
}
|
||||
|
||||
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
|
||||
pred = this and
|
||||
first(this.getPattern(), succ) and
|
||||
c instanceof SimpleCompletion
|
||||
or
|
||||
exists(Expr next |
|
||||
last(this.getPattern(), pred, c) and
|
||||
c.(MatchingCompletion).getValue() = true and
|
||||
first(next, succ)
|
||||
|
|
||||
next = this.getCondition()
|
||||
or
|
||||
not exists(this.getCondition()) and next = this.getBody()
|
||||
)
|
||||
or
|
||||
exists(boolean flag |
|
||||
lastCondition(pred, c, flag) and
|
||||
c.(BooleanCompletion).getValue() = flag and
|
||||
first(this.getBody(), succ)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class CharacterTree extends LeafTree, CharacterLiteral { }
|
||||
|
||||
private class ClassDeclarationTree extends NamespaceTree, ClassDeclaration {
|
||||
@@ -542,7 +923,8 @@ module Trees {
|
||||
c instanceof SimpleCompletion
|
||||
or
|
||||
this.hasDefaultValue() and
|
||||
c.(MatchingCompletion).getValue() = true
|
||||
c.(MatchingCompletion).getValue() = true and
|
||||
c.isValidFor(this)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -864,6 +864,7 @@ control/cases.rb:
|
||||
# 67| getPattern: [ArrayPattern] [ ..., * ]
|
||||
# 68| getBranch: [InClause] in ... then ...
|
||||
# 68| getPattern: [ArrayPattern] [ ..., * ]
|
||||
# 68| getRestVariableAccess: [LocalVariableAccess] x
|
||||
# 68| getSuffixElement: [IntegerLiteral] 3
|
||||
# 68| getSuffixElement: [IntegerLiteral] 4
|
||||
# 69| getBranch: [InClause] in ... then ...
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
deadEnd
|
||||
| control/cases.rb:19:13:19:19 | then ... |
|
||||
| control/cases.rb:20:13:20:19 | then ... |
|
||||
| control/cases.rb:21:13:21:19 | then ... |
|
||||
@@ -156,8 +156,8 @@
|
||||
| control/cases.rb:65:13:65:13 | 3 | 3 |
|
||||
| control/cases.rb:66:7:66:7 | 1 | 1 |
|
||||
| control/cases.rb:66:14:66:14 | 3 | 3 |
|
||||
| control/cases.rb:68:10:68:10 | 3 | 3 |
|
||||
| control/cases.rb:68:13:68:13 | 4 | 4 |
|
||||
| control/cases.rb:68:11:68:11 | 3 | 3 |
|
||||
| control/cases.rb:68:14:68:14 | 4 | 4 |
|
||||
| control/cases.rb:69:10:69:10 | 3 | 3 |
|
||||
| control/cases.rb:70:11:70:11 | 3 | 3 |
|
||||
| control/cases.rb:71:7:71:7 | :a | a |
|
||||
@@ -176,6 +176,7 @@
|
||||
| control/cases.rb:76:13:76:13 | :b | b |
|
||||
| control/cases.rb:84:7:84:8 | 42 | 42 |
|
||||
| control/cases.rb:87:6:87:6 | 5 | 5 |
|
||||
| control/cases.rb:88:7:88:9 | foo | 42 |
|
||||
| control/cases.rb:90:6:90:13 | "string" | string |
|
||||
| control/cases.rb:91:9:91:11 | "foo" | foo |
|
||||
| control/cases.rb:91:13:91:15 | "bar" | bar |
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
deadEnd
|
||||
| cases.rb:19:13:19:19 | then ... |
|
||||
| cases.rb:20:13:20:19 | then ... |
|
||||
| cases.rb:21:13:21:19 | then ... |
|
||||
@@ -67,7 +67,7 @@ caseAllBranches
|
||||
| cases.rb:39:1:80:3 | case ... | 25 | cases.rb:65:3:65:18 | in ... then ... |
|
||||
| cases.rb:39:1:80:3 | case ... | 26 | cases.rb:66:3:66:16 | in ... then ... |
|
||||
| cases.rb:39:1:80:3 | case ... | 27 | cases.rb:67:3:67:9 | in ... then ... |
|
||||
| cases.rb:39:1:80:3 | case ... | 28 | cases.rb:68:3:68:15 | in ... then ... |
|
||||
| cases.rb:39:1:80:3 | case ... | 28 | cases.rb:68:3:68:16 | in ... then ... |
|
||||
| cases.rb:39:1:80:3 | case ... | 29 | cases.rb:69:3:69:15 | in ... then ... |
|
||||
| cases.rb:39:1:80:3 | case ... | 30 | cases.rb:70:3:70:17 | in ... then ... |
|
||||
| cases.rb:39:1:80:3 | case ... | 31 | cases.rb:71:3:71:10 | in ... then ... |
|
||||
|
||||
@@ -65,7 +65,7 @@ case expr
|
||||
in [1, 2, 3, *]
|
||||
in [1, *x, 3]
|
||||
in [*]
|
||||
in [*, 3, 4]
|
||||
in [*x, 3, 4]
|
||||
in [*, 3, *]
|
||||
in [*a, 3, *b]
|
||||
in {a:}
|
||||
|
||||
@@ -492,7 +492,7 @@ case.rb:
|
||||
#-----| -> if_in_case
|
||||
|
||||
# 1| if_in_case
|
||||
#-----| -> exit case.rb (normal)
|
||||
#-----| -> case_match
|
||||
|
||||
# 1| exit if_in_case
|
||||
|
||||
@@ -567,6 +567,795 @@ case.rb:
|
||||
# 4| "2"
|
||||
#-----| -> call to puts
|
||||
|
||||
# 8| enter case_match
|
||||
#-----| -> value
|
||||
|
||||
# 8| case_match
|
||||
#-----| -> case_match_no_match
|
||||
|
||||
# 8| exit case_match
|
||||
|
||||
# 8| exit case_match (normal)
|
||||
#-----| -> exit case_match
|
||||
|
||||
# 8| value
|
||||
#-----| -> case ...
|
||||
|
||||
# 9| case ...
|
||||
#-----| -> value
|
||||
|
||||
# 9| value
|
||||
#-----| -> in ... then ...
|
||||
|
||||
# 10| in ... then ...
|
||||
#-----| -> 0
|
||||
|
||||
# 10| 0
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match (normal)
|
||||
|
||||
# 11| in ... then ...
|
||||
#-----| -> 1
|
||||
|
||||
# 11| 1
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> 3
|
||||
|
||||
# 11| then ...
|
||||
#-----| -> exit case_match (normal)
|
||||
|
||||
# 11| 3
|
||||
#-----| -> then ...
|
||||
|
||||
# 12| in ... then ...
|
||||
#-----| -> 2
|
||||
|
||||
# 12| 2
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> 4
|
||||
|
||||
# 12| then ...
|
||||
#-----| -> exit case_match (normal)
|
||||
|
||||
# 13| 4
|
||||
#-----| -> then ...
|
||||
|
||||
# 14| in ... then ...
|
||||
#-----| -> x
|
||||
|
||||
# 14| x
|
||||
#-----| match -> x
|
||||
|
||||
# 14| ... == ...
|
||||
#-----| false -> in ... then ...
|
||||
#-----| true -> 6
|
||||
|
||||
# 14| x
|
||||
#-----| -> 5
|
||||
|
||||
# 14| 5
|
||||
#-----| -> ... == ...
|
||||
|
||||
# 14| then ...
|
||||
#-----| -> exit case_match (normal)
|
||||
|
||||
# 14| 6
|
||||
#-----| -> then ...
|
||||
|
||||
# 15| in ... then ...
|
||||
#-----| -> x
|
||||
|
||||
# 15| x
|
||||
#-----| match -> x
|
||||
|
||||
# 15| ... < ...
|
||||
#-----| false -> 7
|
||||
#-----| true -> 8
|
||||
|
||||
# 15| x
|
||||
#-----| -> 0
|
||||
|
||||
# 15| 0
|
||||
#-----| -> ... < ...
|
||||
|
||||
# 15| then ...
|
||||
#-----| -> exit case_match (normal)
|
||||
|
||||
# 15| 7
|
||||
#-----| -> then ...
|
||||
|
||||
# 16| else ...
|
||||
#-----| -> exit case_match (normal)
|
||||
|
||||
# 16| 8
|
||||
#-----| -> else ...
|
||||
|
||||
# 20| enter case_match_no_match
|
||||
#-----| -> value
|
||||
|
||||
# 20| case_match_no_match
|
||||
#-----| -> case_match_raise
|
||||
|
||||
# 20| exit case_match_no_match
|
||||
|
||||
# 20| exit case_match_no_match (abnormal)
|
||||
#-----| -> exit case_match_no_match
|
||||
|
||||
# 20| exit case_match_no_match (normal)
|
||||
#-----| -> exit case_match_no_match
|
||||
|
||||
# 20| value
|
||||
#-----| -> case ...
|
||||
|
||||
# 21| case ...
|
||||
#-----| -> value
|
||||
|
||||
# 21| value
|
||||
#-----| -> in ... then ...
|
||||
|
||||
# 22| in ... then ...
|
||||
#-----| -> 1
|
||||
|
||||
# 22| 1
|
||||
#-----| raise -> exit case_match_no_match (abnormal)
|
||||
#-----| match -> exit case_match_no_match (normal)
|
||||
|
||||
# 26| enter case_match_raise
|
||||
#-----| -> value
|
||||
|
||||
# 26| case_match_raise
|
||||
#-----| -> case_match_array
|
||||
|
||||
# 26| exit case_match_raise
|
||||
|
||||
# 26| exit case_match_raise (abnormal)
|
||||
#-----| -> exit case_match_raise
|
||||
|
||||
# 26| exit case_match_raise (normal)
|
||||
#-----| -> exit case_match_raise
|
||||
|
||||
# 26| value
|
||||
#-----| -> case ...
|
||||
|
||||
# 27| case ...
|
||||
#-----| -> value
|
||||
|
||||
# 27| value
|
||||
#-----| -> in ... then ...
|
||||
|
||||
# 28| in ... then ...
|
||||
#-----| -> -> { ... }
|
||||
|
||||
# 28| enter -> { ... }
|
||||
#-----| -> x
|
||||
|
||||
# 28| -> { ... }
|
||||
#-----| raise -> exit case_match_raise (abnormal)
|
||||
#-----| match -> exit case_match_raise (normal)
|
||||
|
||||
# 28| exit -> { ... }
|
||||
|
||||
# 28| exit -> { ... } (abnormal)
|
||||
#-----| -> exit -> { ... }
|
||||
|
||||
# 28| x
|
||||
#-----| -> self
|
||||
|
||||
# 28| call to raise
|
||||
#-----| raise -> exit -> { ... } (abnormal)
|
||||
|
||||
# 28| self
|
||||
#-----| -> "oops"
|
||||
|
||||
# 28| "oops"
|
||||
#-----| -> call to raise
|
||||
|
||||
# 32| enter case_match_array
|
||||
#-----| -> value
|
||||
|
||||
# 32| case_match_array
|
||||
#-----| -> case_match_find
|
||||
|
||||
# 32| exit case_match_array
|
||||
|
||||
# 32| exit case_match_array (abnormal)
|
||||
#-----| -> exit case_match_array
|
||||
|
||||
# 32| exit case_match_array (normal)
|
||||
#-----| -> exit case_match_array
|
||||
|
||||
# 32| value
|
||||
#-----| -> case ...
|
||||
|
||||
# 33| case ...
|
||||
#-----| -> value
|
||||
|
||||
# 33| value
|
||||
#-----| -> in ... then ...
|
||||
|
||||
# 34| in ... then ...
|
||||
#-----| -> [ ..., * ]
|
||||
|
||||
# 34| [ ..., * ]
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_array (normal)
|
||||
|
||||
# 35| in ... then ...
|
||||
#-----| -> [ ..., * ]
|
||||
|
||||
# 35| [ ..., * ]
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> x
|
||||
|
||||
# 35| x
|
||||
#-----| match -> exit case_match_array (normal)
|
||||
|
||||
# 36| in ... then ...
|
||||
#-----| -> [ ..., * ]
|
||||
|
||||
# 36| [ ..., * ]
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> x
|
||||
|
||||
# 36| x
|
||||
#-----| match -> exit case_match_array (normal)
|
||||
|
||||
# 37| in ... then ...
|
||||
#-----| -> Bar
|
||||
|
||||
# 37| [ ..., * ]
|
||||
#-----| match -> a
|
||||
#-----| raise -> exit case_match_array (abnormal)
|
||||
|
||||
# 37| Bar
|
||||
#-----| match -> [ ..., * ]
|
||||
#-----| raise -> exit case_match_array (abnormal)
|
||||
|
||||
# 37| a
|
||||
#-----| match -> b
|
||||
|
||||
# 37| b
|
||||
#-----| match -> c
|
||||
|
||||
# 37| c
|
||||
#-----| -> d
|
||||
|
||||
# 37| d
|
||||
#-----| match -> e
|
||||
|
||||
# 37| e
|
||||
#-----| match -> exit case_match_array (normal)
|
||||
|
||||
# 41| enter case_match_find
|
||||
#-----| -> value
|
||||
|
||||
# 41| case_match_find
|
||||
#-----| -> case_match_hash
|
||||
|
||||
# 41| exit case_match_find
|
||||
|
||||
# 41| exit case_match_find (abnormal)
|
||||
#-----| -> exit case_match_find
|
||||
|
||||
# 41| exit case_match_find (normal)
|
||||
#-----| -> exit case_match_find
|
||||
|
||||
# 41| value
|
||||
#-----| -> case ...
|
||||
|
||||
# 42| case ...
|
||||
#-----| -> value
|
||||
|
||||
# 42| value
|
||||
#-----| -> in ... then ...
|
||||
|
||||
# 43| in ... then ...
|
||||
#-----| -> [ *,...,* ]
|
||||
|
||||
# 43| [ *,...,* ]
|
||||
#-----| match -> x
|
||||
#-----| raise -> exit case_match_find (abnormal)
|
||||
|
||||
# 43| x
|
||||
#-----| -> 1
|
||||
|
||||
# 43| 1
|
||||
#-----| match -> 2
|
||||
#-----| raise -> exit case_match_find (abnormal)
|
||||
|
||||
# 43| 2
|
||||
#-----| match -> y
|
||||
#-----| raise -> exit case_match_find (abnormal)
|
||||
|
||||
# 43| y
|
||||
#-----| -> exit case_match_find (normal)
|
||||
|
||||
# 47| enter case_match_hash
|
||||
#-----| -> value
|
||||
|
||||
# 47| case_match_hash
|
||||
#-----| -> case_match_variable
|
||||
|
||||
# 47| exit case_match_hash
|
||||
|
||||
# 47| exit case_match_hash (abnormal)
|
||||
#-----| -> exit case_match_hash
|
||||
|
||||
# 47| exit case_match_hash (normal)
|
||||
#-----| -> exit case_match_hash
|
||||
|
||||
# 47| value
|
||||
#-----| -> case ...
|
||||
|
||||
# 48| case ...
|
||||
#-----| -> value
|
||||
|
||||
# 48| value
|
||||
#-----| -> in ... then ...
|
||||
|
||||
# 49| in ... then ...
|
||||
#-----| -> Foo
|
||||
|
||||
# 49| { ..., ** }
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> 1
|
||||
|
||||
# 49| Foo
|
||||
#-----| -> Bar
|
||||
|
||||
# 49| Bar
|
||||
#-----| match -> { ..., ** }
|
||||
#-----| no-match -> in ... then ...
|
||||
|
||||
# 49| 1
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> rest
|
||||
|
||||
# 49| rest
|
||||
#-----| -> exit case_match_hash (normal)
|
||||
|
||||
# 50| in ... then ...
|
||||
#-----| -> Bar
|
||||
|
||||
# 50| { ..., ** }
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> 1
|
||||
|
||||
# 50| Bar
|
||||
#-----| match -> { ..., ** }
|
||||
#-----| no-match -> in ... then ...
|
||||
|
||||
# 50| 1
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_hash (normal)
|
||||
|
||||
# 51| in ... then ...
|
||||
#-----| -> Bar
|
||||
|
||||
# 51| { ..., ** }
|
||||
#-----| raise -> exit case_match_hash (abnormal)
|
||||
#-----| match -> exit case_match_hash (normal)
|
||||
|
||||
# 51| Bar
|
||||
#-----| match -> { ..., ** }
|
||||
#-----| raise -> exit case_match_hash (abnormal)
|
||||
|
||||
# 55| enter case_match_variable
|
||||
#-----| -> value
|
||||
|
||||
# 55| case_match_variable
|
||||
#-----| -> case_match_underscore
|
||||
|
||||
# 55| exit case_match_variable
|
||||
|
||||
# 55| exit case_match_variable (normal)
|
||||
#-----| -> exit case_match_variable
|
||||
|
||||
# 55| value
|
||||
#-----| -> case ...
|
||||
|
||||
# 56| case ...
|
||||
#-----| -> value
|
||||
|
||||
# 56| value
|
||||
#-----| -> in ... then ...
|
||||
|
||||
# 57| in ... then ...
|
||||
#-----| -> 5
|
||||
|
||||
# 57| 5
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_variable (normal)
|
||||
|
||||
# 58| in ... then ...
|
||||
#-----| -> var
|
||||
|
||||
# 58| var
|
||||
#-----| match -> exit case_match_variable (normal)
|
||||
|
||||
# 63| enter case_match_underscore
|
||||
#-----| -> value
|
||||
|
||||
# 63| case_match_underscore
|
||||
#-----| -> case_match_various
|
||||
|
||||
# 63| exit case_match_underscore
|
||||
|
||||
# 63| exit case_match_underscore (normal)
|
||||
#-----| -> exit case_match_underscore
|
||||
|
||||
# 63| value
|
||||
#-----| -> case ...
|
||||
|
||||
# 64| case ...
|
||||
#-----| -> value
|
||||
|
||||
# 64| value
|
||||
#-----| -> in ... then ...
|
||||
|
||||
# 65| in ... then ...
|
||||
#-----| -> ... | ...
|
||||
|
||||
# 65| ... | ...
|
||||
#-----| -> 5
|
||||
|
||||
# 65| 5
|
||||
#-----| no-match -> _
|
||||
#-----| match -> exit case_match_underscore (normal)
|
||||
|
||||
# 65| _
|
||||
#-----| match -> exit case_match_underscore (normal)
|
||||
|
||||
# 69| enter case_match_various
|
||||
#-----| -> value
|
||||
|
||||
# 69| case_match_various
|
||||
#-----| -> case_match_guard_no_else
|
||||
|
||||
# 69| exit case_match_various
|
||||
|
||||
# 69| exit case_match_various (abnormal)
|
||||
#-----| -> exit case_match_various
|
||||
|
||||
# 69| exit case_match_various (normal)
|
||||
#-----| -> exit case_match_various
|
||||
|
||||
# 69| value
|
||||
#-----| -> foo
|
||||
|
||||
# 70| ... = ...
|
||||
#-----| -> case ...
|
||||
|
||||
# 70| foo
|
||||
#-----| -> 42
|
||||
|
||||
# 70| 42
|
||||
#-----| -> ... = ...
|
||||
|
||||
# 72| case ...
|
||||
#-----| -> value
|
||||
|
||||
# 72| value
|
||||
#-----| -> in ... then ...
|
||||
|
||||
# 73| in ... then ...
|
||||
#-----| -> 5
|
||||
|
||||
# 73| 5
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 74| in ... then ...
|
||||
#-----| -> ^...
|
||||
|
||||
# 74| ^...
|
||||
#-----| -> foo
|
||||
|
||||
# 74| foo
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 75| in ... then ...
|
||||
#-----| -> "string"
|
||||
|
||||
# 75| "string"
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 76| in ... then ...
|
||||
#-----| -> Array
|
||||
|
||||
# 76| call to []
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 76| Array
|
||||
#-----| -> "foo"
|
||||
|
||||
# 76| "foo"
|
||||
#-----| -> "bar"
|
||||
|
||||
# 76| "bar"
|
||||
#-----| -> call to []
|
||||
|
||||
# 77| in ... then ...
|
||||
#-----| -> Array
|
||||
|
||||
# 77| call to []
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 77| Array
|
||||
#-----| -> :"foo"
|
||||
|
||||
# 77| :"foo"
|
||||
#-----| -> :"bar"
|
||||
|
||||
# 77| :"bar"
|
||||
#-----| -> call to []
|
||||
|
||||
# 78| in ... then ...
|
||||
#-----| -> /.*abc[0-9]/
|
||||
|
||||
# 78| /.*abc[0-9]/
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 79| in ... then ...
|
||||
#-----| -> 5
|
||||
|
||||
# 79| 5
|
||||
#-----| -> 10
|
||||
|
||||
# 79| _ .. _
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 79| 10
|
||||
#-----| -> _ .. _
|
||||
|
||||
# 80| in ... then ...
|
||||
#-----| -> 10
|
||||
|
||||
# 80| _ .. _
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 80| 10
|
||||
#-----| -> _ .. _
|
||||
|
||||
# 81| in ... then ...
|
||||
#-----| -> 5
|
||||
|
||||
# 81| 5
|
||||
#-----| -> _ .. _
|
||||
|
||||
# 81| _ .. _
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 82| in ... then ...
|
||||
#-----| -> ... => ...
|
||||
|
||||
# 82| ... => ...
|
||||
#-----| -> 5
|
||||
|
||||
# 82| 5
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> x
|
||||
|
||||
# 82| x
|
||||
#-----| -> exit case_match_various (normal)
|
||||
|
||||
# 83| in ... then ...
|
||||
#-----| -> ... | ...
|
||||
|
||||
# 83| ... | ...
|
||||
#-----| -> 5
|
||||
|
||||
# 83| 5
|
||||
#-----| no-match -> ^...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 83| ^...
|
||||
#-----| -> foo
|
||||
|
||||
# 83| foo
|
||||
#-----| no-match -> "string"
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 83| "string"
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 84| in ... then ...
|
||||
#-----| -> Foo
|
||||
|
||||
# 84| Bar
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 84| Foo
|
||||
#-----| -> Bar
|
||||
|
||||
# 85| in ... then ...
|
||||
#-----| -> -> { ... }
|
||||
|
||||
# 85| enter -> { ... }
|
||||
#-----| -> x
|
||||
|
||||
# 85| -> { ... }
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 85| exit -> { ... }
|
||||
|
||||
# 85| exit -> { ... } (normal)
|
||||
#-----| -> exit -> { ... }
|
||||
|
||||
# 85| x
|
||||
#-----| -> x
|
||||
|
||||
# 85| ... == ...
|
||||
#-----| -> exit -> { ... } (normal)
|
||||
|
||||
# 85| x
|
||||
#-----| -> 10
|
||||
|
||||
# 85| 10
|
||||
#-----| -> ... == ...
|
||||
|
||||
# 86| in ... then ...
|
||||
#-----| -> :foo
|
||||
|
||||
# 86| :foo
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 87| in ... then ...
|
||||
#-----| -> :"foo bar"
|
||||
|
||||
# 87| :"foo bar"
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 88| in ... then ...
|
||||
#-----| -> ... | ...
|
||||
|
||||
# 88| ... | ...
|
||||
#-----| -> 5
|
||||
|
||||
# 88| - ...
|
||||
#-----| no-match -> 10
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 88| 5
|
||||
#-----| -> - ...
|
||||
|
||||
# 88| + ...
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 88| 10
|
||||
#-----| -> + ...
|
||||
|
||||
# 89| in ... then ...
|
||||
#-----| -> ... | ...
|
||||
|
||||
# 89| ... | ...
|
||||
#-----| -> nil
|
||||
|
||||
# 89| nil
|
||||
#-----| no-match -> self
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 89| self
|
||||
#-----| no-match -> true
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 89| true
|
||||
#-----| no-match -> false
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 89| false
|
||||
#-----| no-match -> __LINE__
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 89| __LINE__
|
||||
#-----| no-match -> __FILE__
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 89| __FILE__
|
||||
#-----| no-match -> __ENCODING__
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 89| __ENCODING__
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 90| in ... then ...
|
||||
#-----| -> ( ... )
|
||||
|
||||
# 90| ( ... )
|
||||
#-----| -> 1
|
||||
|
||||
# 90| 1
|
||||
#-----| -> _ .. _
|
||||
|
||||
# 90| _ .. _
|
||||
#-----| no-match -> in ... then ...
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 91| in ... then ...
|
||||
#-----| -> ( ... )
|
||||
|
||||
# 91| ( ... )
|
||||
#-----| -> ... | ...
|
||||
|
||||
# 91| ... | ...
|
||||
#-----| -> 0
|
||||
|
||||
# 91| 0
|
||||
#-----| no-match -> ""
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 91| ""
|
||||
#-----| no-match -> [ ..., * ]
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 91| [ ..., * ]
|
||||
#-----| no-match -> { ..., ** }
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 91| { ..., ** }
|
||||
#-----| raise -> exit case_match_various (abnormal)
|
||||
#-----| match -> exit case_match_various (normal)
|
||||
|
||||
# 95| enter case_match_guard_no_else
|
||||
#-----| -> value
|
||||
|
||||
# 95| case_match_guard_no_else
|
||||
#-----| -> exit case.rb (normal)
|
||||
|
||||
# 95| exit case_match_guard_no_else
|
||||
|
||||
# 95| exit case_match_guard_no_else (abnormal)
|
||||
#-----| -> exit case_match_guard_no_else
|
||||
|
||||
# 95| exit case_match_guard_no_else (normal)
|
||||
#-----| -> exit case_match_guard_no_else
|
||||
|
||||
# 95| value
|
||||
#-----| -> case ...
|
||||
|
||||
# 96| case ...
|
||||
#-----| -> value
|
||||
|
||||
# 96| value
|
||||
#-----| -> in ... then ...
|
||||
|
||||
# 97| in ... then ...
|
||||
#-----| -> x
|
||||
|
||||
# 97| x
|
||||
#-----| match -> x
|
||||
|
||||
# 97| ... == ...
|
||||
#-----| true -> 6
|
||||
#-----| raise -> exit case_match_guard_no_else (abnormal)
|
||||
|
||||
# 97| x
|
||||
#-----| -> 5
|
||||
|
||||
# 97| 5
|
||||
#-----| -> ... == ...
|
||||
|
||||
# 97| then ...
|
||||
#-----| -> exit case_match_guard_no_else (normal)
|
||||
|
||||
# 97| 6
|
||||
#-----| -> then ...
|
||||
|
||||
cfg.html.erb:
|
||||
# 5| enter cfg.html.erb
|
||||
#-----| -> @title
|
||||
|
||||
@@ -9,6 +9,8 @@ callsWithNoArguments
|
||||
| break_ensure.rb:29:8:29:13 | call to nil? |
|
||||
| case.rb:2:8:2:9 | call to x1 |
|
||||
| case.rb:3:21:3:22 | call to x2 |
|
||||
| case.rb:88:8:88:9 | - ... |
|
||||
| case.rb:88:13:88:15 | + ... |
|
||||
| cfg.html.erb:12:24:12:24 | call to a |
|
||||
| cfg.html.erb:15:32:15:32 | call to a |
|
||||
| cfg.html.erb:16:32:16:32 | call to b |
|
||||
@@ -80,6 +82,15 @@ positionalArguments
|
||||
| break_ensure.rb:51:10:51:14 | [ensure: raise] ... > ... | break_ensure.rb:51:14:51:14 | [ensure: raise] 0 |
|
||||
| case.rb:3:29:3:37 | call to puts | case.rb:3:34:3:37 | "x2" |
|
||||
| case.rb:4:17:4:24 | call to puts | case.rb:4:22:4:24 | "2" |
|
||||
| case.rb:14:13:14:18 | ... == ... | case.rb:14:18:14:18 | 5 |
|
||||
| case.rb:15:17:15:21 | ... < ... | case.rb:15:21:15:21 | 0 |
|
||||
| case.rb:28:14:28:25 | call to raise | case.rb:28:20:28:25 | "oops" |
|
||||
| case.rb:76:8:76:18 | call to [] | case.rb:76:11:76:13 | "foo" |
|
||||
| case.rb:76:8:76:18 | call to [] | case.rb:76:15:76:17 | "bar" |
|
||||
| case.rb:77:8:77:18 | call to [] | case.rb:77:11:77:13 | :"foo" |
|
||||
| case.rb:77:8:77:18 | call to [] | case.rb:77:15:77:17 | :"bar" |
|
||||
| case.rb:85:15:85:21 | ... == ... | case.rb:85:20:85:21 | 10 |
|
||||
| case.rb:97:13:97:18 | ... == ... | case.rb:97:18:97:18 | 5 |
|
||||
| cfg.html.erb:6:9:6:58 | call to stylesheet_link_tag | cfg.html.erb:6:29:6:41 | "application" |
|
||||
| cfg.html.erb:6:9:6:58 | call to stylesheet_link_tag | cfg.html.erb:6:44:6:58 | Pair |
|
||||
| cfg.html.erb:12:11:12:33 | call to link_to | cfg.html.erb:12:19:12:21 | "A" |
|
||||
|
||||
@@ -4,3 +4,96 @@ def if_in_case
|
||||
when 2 then puts "2"
|
||||
end
|
||||
end
|
||||
|
||||
def case_match value
|
||||
case value
|
||||
in 0
|
||||
in 1 then 3
|
||||
in 2
|
||||
4
|
||||
in x if x == 5 then 6
|
||||
in x unless x < 0 then 7
|
||||
else 8
|
||||
end
|
||||
end
|
||||
|
||||
def case_match_no_match value
|
||||
case value
|
||||
in 1
|
||||
end
|
||||
end
|
||||
|
||||
def case_match_raise value
|
||||
case value
|
||||
in -> x { raise "oops" }
|
||||
end
|
||||
end
|
||||
|
||||
def case_match_array value
|
||||
case value
|
||||
in [];
|
||||
in [x];
|
||||
in [x, ];
|
||||
in Bar(a, b, *c, d, e);
|
||||
end
|
||||
end
|
||||
|
||||
def case_match_find value
|
||||
case value
|
||||
in [*x, 1, 2, *y];
|
||||
end
|
||||
end
|
||||
|
||||
def case_match_hash value
|
||||
case value
|
||||
in Foo::Bar[ x:1, a:, **rest ];
|
||||
in Bar( a: 1, **nil);
|
||||
in Bar( ** );
|
||||
end
|
||||
end
|
||||
|
||||
def case_match_variable value
|
||||
case value
|
||||
in 5
|
||||
in var
|
||||
in "unreachable"
|
||||
end
|
||||
end
|
||||
|
||||
def case_match_underscore value
|
||||
case value
|
||||
in 5 | _ | "unreachable"
|
||||
end
|
||||
end
|
||||
|
||||
def case_match_various value
|
||||
foo = 42
|
||||
|
||||
case value
|
||||
in 5
|
||||
in ^foo
|
||||
in "string"
|
||||
in %w(foo bar)
|
||||
in %i(foo bar)
|
||||
in /.*abc[0-9]/
|
||||
in 5 .. 10
|
||||
in .. 10
|
||||
in 5 ..
|
||||
in 5 => x
|
||||
in 5 | ^foo | "string"
|
||||
in ::Foo::Bar
|
||||
in -> x { x == 10 }
|
||||
in :foo
|
||||
in :"foo bar"
|
||||
in -5 | +10
|
||||
in nil | self | true | false | __LINE__ | __FILE__ | __ENCODING__
|
||||
in (1 ..)
|
||||
in (0 | "" | [] | {})
|
||||
end
|
||||
end
|
||||
|
||||
def case_match_guard_no_else value
|
||||
case value
|
||||
in x if x == 5 then 6
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user