Skip to content

Commit 17df059

Browse files
committed
C#: Replace matchesCompletion() with getAMatchingSuccessorType()
1 parent f3abaa4 commit 17df059

File tree

6 files changed

+68
-72
lines changed

6 files changed

+68
-72
lines changed

csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ module AbstractValues {
110110

111111
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
112112
s.(BooleanSuccessor).getValue() = this.getValue() and
113-
exists(BooleanCompletion c | s.matchesCompletion(c) |
113+
exists(BooleanCompletion c | s = c.getAMatchingSuccessorType() |
114114
c.isValidFor(cfe) and
115115
e = cfe
116116
)
@@ -161,7 +161,7 @@ module AbstractValues {
161161

162162
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
163163
this = TNullValue(s.(NullnessSuccessor).getValue()) and
164-
exists(NullnessCompletion c | s.matchesCompletion(c) |
164+
exists(NullnessCompletion c | s = c.getAMatchingSuccessorType() |
165165
c.isValidFor(cfe) and
166166
e = cfe
167167
)
@@ -190,7 +190,7 @@ module AbstractValues {
190190

191191
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
192192
this = TMatchValue(_, s.(MatchingSuccessor).getValue()) and
193-
exists(MatchingCompletion c, Switch switch, Case case | s.matchesCompletion(c) |
193+
exists(MatchingCompletion c, Switch switch, Case case | s = c.getAMatchingSuccessorType() |
194194
c.isValidFor(cfe) and
195195
switchMatching(switch, case, cfe) and
196196
e = switch.getExpr() and
@@ -227,7 +227,7 @@ module AbstractValues {
227227

228228
override predicate branch(ControlFlowElement cfe, ConditionalSuccessor s, Expr e) {
229229
this = TEmptyCollectionValue(s.(EmptinessSuccessor).getValue()) and
230-
exists(EmptinessCompletion c, ForeachStmt fs | s.matchesCompletion(c) |
230+
exists(EmptinessCompletion c, ForeachStmt fs | s = c.getAMatchingSuccessorType() |
231231
c.isValidFor(cfe) and
232232
foreachEmptiness(fs, cfe) and
233233
e = fs.getIterableExpr()

csharp/ql/src/semmle/code/csharp/controlflow/internal/Completion.qll

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ private import semmle.code.csharp.commons.Assertions
2424
private import semmle.code.csharp.commons.Constants
2525
private import semmle.code.csharp.frameworks.System
2626
private import NonReturning
27+
private import SuccessorType
28+
private import SuccessorTypes
2729

2830
// Internal representation of completions
2931
private newtype TCompletion =
30-
TNormalCompletion() or
32+
TSimpleCompletion() or
3133
TBooleanCompletion(boolean b) { b = true or b = false } or
3234
TNullnessCompletion(boolean isNull) { isNull = true or isNull = false } or
3335
TMatchingCompletion(boolean isMatch) { isMatch = true or isMatch = false } or
@@ -78,7 +80,7 @@ private predicate completionIsValidForStmt(Stmt s, Completion c) {
7880
/**
7981
* A completion of a statement or an expression.
8082
*/
81-
class Completion extends TCompletion {
83+
abstract class Completion extends TCompletion {
8284
/**
8385
* Holds if this completion is valid for control flow element `cfe`.
8486
*
@@ -143,7 +145,7 @@ class Completion extends TCompletion {
143145
not mustHaveNullnessCompletion(cfe) and
144146
not mustHaveMatchingCompletion(cfe) and
145147
not mustHaveEmptinessCompletion(cfe) and
146-
this = TNormalCompletion()
148+
this = TSimpleCompletion()
147149
}
148150

149151
/**
@@ -167,8 +169,11 @@ class Completion extends TCompletion {
167169
*/
168170
Completion getOuterCompletion() { result = this }
169171

172+
/** Gets a successor type that matches this completion. */
173+
abstract SuccessorType getAMatchingSuccessorType();
174+
170175
/** Gets a textual representation of this completion. */
171-
string toString() { none() }
176+
abstract string toString();
172177
}
173178

174179
/** Holds if expression `e` has the Boolean constant value `value`. */
@@ -529,10 +534,10 @@ private predicate mustHaveEmptinessCompletion(ControlFlowElement cfe) { foreachE
529534
*/
530535
abstract class NormalCompletion extends Completion { }
531536

532-
/**
533-
* A class to make `TNormalCompletion` a `NormalCompletion`
534-
*/
535-
class SimpleCompletion extends NormalCompletion, TNormalCompletion {
537+
/** A simple (normal) completion. */
538+
class SimpleCompletion extends NormalCompletion, TSimpleCompletion {
539+
override NormalSuccessor getAMatchingSuccessorType() { any() }
540+
536541
override string toString() { result = "normal" }
537542
}
538543

@@ -558,6 +563,8 @@ class BooleanCompletion extends ConditionalCompletion {
558563

559564
BooleanCompletion getDual() { result = TBooleanCompletion(value.booleanNot()) }
560565

566+
override BooleanSuccessor getAMatchingSuccessorType() { result.getValue() = value }
567+
561568
override string toString() { result = value.toString() }
562569
}
563570

@@ -576,11 +583,17 @@ class FalseCompletion extends BooleanCompletion {
576583
* `null` or non-`null`.
577584
*/
578585
class NullnessCompletion extends ConditionalCompletion, TNullnessCompletion {
586+
private boolean value;
587+
588+
NullnessCompletion() { this = TNullnessCompletion(value) }
589+
579590
/** Holds if the last sub expression of this expression evaluates to `null`. */
580-
predicate isNull() { this = TNullnessCompletion(true) }
591+
predicate isNull() { value = true }
581592

582593
/** Holds if the last sub expression of this expression evaluates to a non-`null` value. */
583-
predicate isNonNull() { this = TNullnessCompletion(false) }
594+
predicate isNonNull() { value = false }
595+
596+
override NullnessSuccessor getAMatchingSuccessorType() { result.getValue() = value }
584597

585598
override string toString() { if this.isNull() then result = "null" else result = "non-null" }
586599
}
@@ -590,11 +603,17 @@ class NullnessCompletion extends ConditionalCompletion, TNullnessCompletion {
590603
* `switch` statement.
591604
*/
592605
class MatchingCompletion extends ConditionalCompletion, TMatchingCompletion {
606+
private boolean value;
607+
608+
MatchingCompletion() { this = TMatchingCompletion(value) }
609+
593610
/** Holds if there is a match. */
594-
predicate isMatch() { this = TMatchingCompletion(true) }
611+
predicate isMatch() { value = true }
595612

596613
/** Holds if there is not a match. */
597-
predicate isNonMatch() { this = TMatchingCompletion(false) }
614+
predicate isNonMatch() { value = false }
615+
616+
override MatchingSuccessor getAMatchingSuccessorType() { result.getValue() = value }
598617

599618
override string toString() { if this.isMatch() then result = "match" else result = "no-match" }
600619
}
@@ -604,8 +623,14 @@ class MatchingCompletion extends ConditionalCompletion, TMatchingCompletion {
604623
* a test in a `foreach` statement.
605624
*/
606625
class EmptinessCompletion extends ConditionalCompletion, TEmptinessCompletion {
626+
private boolean value;
627+
628+
EmptinessCompletion() { this = TEmptinessCompletion(value) }
629+
607630
/** Holds if the emptiness test evaluates to `true`. */
608-
predicate isEmpty() { this = TEmptinessCompletion(true) }
631+
predicate isEmpty() { value = true }
632+
633+
override EmptinessSuccessor getAMatchingSuccessorType() { result.getValue() = value }
609634

610635
override string toString() { if this.isEmpty() then result = "empty" else result = "non-empty" }
611636
}
@@ -616,7 +641,7 @@ class EmptinessCompletion extends ConditionalCompletion, TEmptinessCompletion {
616641
*
617642
* This completion is added for technical reasons only: when a loop
618643
* body can complete with a break completion, the loop itself completes
619-
* normally. However, if we choose `TNormalCompletion` as the completion
644+
* normally. However, if we choose `TSimpleCompletion` as the completion
620645
* of the loop, we lose the information that the last element actually
621646
* completed with a break, meaning that the control flow edge out of the
622647
* breaking node cannot be marked with a `break` label.
@@ -634,10 +659,12 @@ class EmptinessCompletion extends ConditionalCompletion, TEmptinessCompletion {
634659
* The `break` on line 3 completes with a `TBreakCompletion`, therefore
635660
* the `while` loop can complete with a `TBreakNormalCompletion`, so we
636661
* get an edge `break --break--> return`. (If we instead used a
637-
* `TNormalCompletion`, we would get a less precise edge
662+
* `TSimpleCompletion`, we would get a less precise edge
638663
* `break --normal--> return`.)
639664
*/
640665
class BreakNormalCompletion extends NormalCompletion, TBreakNormalCompletion {
666+
override BreakSuccessor getAMatchingSuccessorType() { any() }
667+
641668
override string toString() { result = "normal (break)" }
642669
}
643670

@@ -673,6 +700,8 @@ class NestedCompletion extends Completion, TNestedCompletion {
673700

674701
override Completion getOuterCompletion() { result = outer }
675702

703+
override SuccessorType getAMatchingSuccessorType() { none() }
704+
676705
override string toString() { result = outer + " [" + inner + "]" }
677706
}
678707

@@ -686,6 +715,8 @@ class ReturnCompletion extends Completion {
686715
this = TNestedCompletion(_, TReturnCompletion())
687716
}
688717

718+
override ReturnSuccessor getAMatchingSuccessorType() { any() }
719+
689720
override string toString() {
690721
// `NestedCompletion` defines `toString()` for the other case
691722
this = TReturnCompletion() and result = "return"
@@ -703,6 +734,8 @@ class BreakCompletion extends Completion {
703734
this = TNestedCompletion(_, TBreakCompletion())
704735
}
705736

737+
override BreakSuccessor getAMatchingSuccessorType() { any() }
738+
706739
override string toString() {
707740
// `NestedCompletion` defines `toString()` for the other case
708741
this = TBreakCompletion() and result = "break"
@@ -720,6 +753,8 @@ class ContinueCompletion extends Completion {
720753
this = TNestedCompletion(_, TContinueCompletion())
721754
}
722755

756+
override ContinueSuccessor getAMatchingSuccessorType() { any() }
757+
723758
override string toString() {
724759
// `NestedCompletion` defines `toString()` for the other case
725760
this = TContinueCompletion() and result = "continue"
@@ -741,6 +776,8 @@ class GotoCompletion extends Completion {
741776
/** Gets the label of the `goto` completion. */
742777
string getLabel() { result = label }
743778

779+
override GotoSuccessor getAMatchingSuccessorType() { result.getLabel() = label }
780+
744781
override string toString() {
745782
// `NestedCompletion` defines `toString()` for the other case
746783
this = TGotoCompletion(label) and result = "goto(" + label + ")"
@@ -762,6 +799,8 @@ class ThrowCompletion extends Completion {
762799
/** Gets the type of the exception being thrown. */
763800
ExceptionClass getExceptionClass() { result = ec }
764801

802+
override ExceptionSuccessor getAMatchingSuccessorType() { result.getExceptionClass() = ec }
803+
765804
override string toString() {
766805
// `NestedCompletion` defines `toString()` for the other case
767806
this = TThrowCompletion(ec) and result = "throw(" + ec + ")"
@@ -783,6 +822,8 @@ class ExitCompletion extends Completion {
783822
this = TNestedCompletion(_, TExitCompletion())
784823
}
785824

825+
override ExitSuccessor getAMatchingSuccessorType() { any() }
826+
786827
override string toString() {
787828
// `NestedCompletion` defines `toString()` for the other case
788829
this = TExitCompletion() and result = "exit"

csharp/ql/src/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1619,7 +1619,7 @@ private module Cached {
16191619
result = TElementNode(succElement, succSplits)
16201620
|
16211621
succSplits(predElement, predSplits, succElement, succSplits, c) and
1622-
t.matchesCompletion(c)
1622+
t = c.getAMatchingSuccessorType()
16231623
)
16241624
)
16251625
or

csharp/ql/src/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class PreBasicBlock extends ControlFlowElement {
5454
PreBasicBlock() { startsBB(this) }
5555

5656
PreBasicBlock getASuccessorByType(SuccessorType t) {
57-
succ(this.getLastElement(), result, any(Completion c | t.matchesCompletion(c)))
57+
succ(this.getLastElement(), result, any(Completion c | t = c.getAMatchingSuccessorType()))
5858
}
5959

6060
PreBasicBlock getASuccessor() { result = this.getASuccessorByType(_) }
@@ -127,7 +127,7 @@ class ConditionBlock extends PreBasicBlock {
127127
predicate controls(PreBasicBlock controlled, SuccessorTypes::ConditionalSuccessor s) {
128128
exists(PreBasicBlock succ, ConditionalCompletion c | immediatelyControls(succ, c) |
129129
succ.dominates(controlled) and
130-
s.matchesCompletion(c)
130+
s = c.getAMatchingSuccessorType()
131131
)
132132
}
133133
}

csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,7 @@ module FinallySplitting {
635635
// If the entry into the `finally` block completes with any normal completion,
636636
// it simply means normal execution after the `finally` block
637637
this instanceof NormalSuccessor
638-
else this.matchesCompletion(c)
638+
else this = c.getAMatchingSuccessorType()
639639
}
640640
}
641641

@@ -806,7 +806,7 @@ module FinallySplitting {
806806
// does not require another completion to be recovered
807807
inherited = false and
808808
(
809-
type.matchesCompletion(c)
809+
type = c.getAMatchingSuccessorType()
810810
or
811811
not c instanceof NormalCompletion
812812
or
@@ -816,7 +816,7 @@ module FinallySplitting {
816816
// Finally block can exit with completion `c` inherited from try/catch
817817
// block: must match this split
818818
inherited = true and
819-
type.matchesCompletion(c) and
819+
type = c.getAMatchingSuccessorType() and
820820
not type instanceof NormalSuccessor
821821
)
822822
)
@@ -1587,7 +1587,7 @@ predicate succEntrySplits(
15871587
predicate succExitSplits(ControlFlowElement pred, Splits predSplits, Callable succ, SuccessorType t) {
15881588
exists(Reachability::SameSplitsBlock b, Completion c | pred = b.getAnElement() |
15891589
b.isReachable(predSplits) and
1590-
t.matchesCompletion(c) and
1590+
t = c.getAMatchingSuccessorType() and
15911591
succExit(pred, succ, c) and
15921592
forall(SplitImpl predSplit | predSplit = predSplits.getASplit() |
15931593
predSplit.hasExitScope(pred, succ, c)

0 commit comments

Comments
 (0)