C#: Generalize CFG entry/exit nodes to include field/property initializers

This commit is contained in:
Tom Hvitved
2019-08-15 11:27:14 +02:00
parent b28241ac6d
commit b7e732fddb
12 changed files with 119 additions and 60 deletions

View File

@@ -19,7 +19,8 @@ private import semmle.code.csharp.metrics.Complexity
* an anonymous function (`AnonymousFunctionExpr`), or a local function
* (`LocalFunction`).
*/
class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @callable {
class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, ControlFlowEntryElement,
@callable {
override Type getReturnType() { none() }
/** Gets the annotated return type of this callable. */

View File

@@ -54,11 +54,11 @@ module Internal {
getAChildExpr+(s) = e
}
private predicate childExprOfCallable(Callable parent, Expr child) {
private predicate childExprOfEntryElement(ControlFlowEntryElement parent, Expr child) {
child = getAChildExpr(parent)
or
exists(Expr mid | childExprOfCallable(parent, mid) |
not mid instanceof Callable and
exists(Expr mid | childExprOfEntryElement(parent, mid) |
not mid instanceof ControlFlowEntryElement and
child = getAChildExpr(mid)
)
}
@@ -66,18 +66,18 @@ module Internal {
/**
* INTERNAL: Do not use.
*
* Holds if `c` is the enclosing callable of expression `e`.
* Holds if `entry` is the enclosing entry element of expression `e`.
*/
cached
predicate exprEnclosingCallable(Expr e, Callable c) {
predicate exprEnclosingEntryElement(Expr e, ControlFlowEntryElement entry) {
// Compute the enclosing callable of an expression. Note that expressions in
// lambda functions should have the lambdas as enclosing callables, and their
// enclosing statement may be the same as the enclosing statement of the
// lambda; thus, it is *not* safe to go up to the enclosing statement and
// take its own enclosing callable.
childExprOfCallable(c, e)
childExprOfEntryElement(entry, e)
or
not childExprOfCallable(_, e) and
exists(Stmt s | enclosingStmt(e, s) | enclosingCallable(s, c))
not childExprOfEntryElement(_, e) and
exists(Stmt s | enclosingStmt(e, s) | enclosingCallable(s, entry))
}
}

View File

@@ -12,7 +12,7 @@ import csharp
* The `expr_parent_top_level()` relation extended to include a relation
* between getters and expression bodies in properties such as `int P => 0`.
*/
predicate expr_parent_top_level_adjusted(Expr child, int i, @top_level_exprorstmt_parent parent) {
predicate expr_parent_top_level_adjusted(Expr child, int i, ControlFlowEntryElement parent) {
expr_parent_top_level(child, i, parent)
or
parent = any(Getter g | expr_parent_top_level(child, i, g.getDeclaration())) and
@@ -108,7 +108,7 @@ class ExprOrStmtParent extends Element, @exprorstmt_parent {
*
* An element that can have a child top-level expression.
*/
class TopLevelExprParent extends Element, @top_level_expr_parent {
class TopLevelExprParent extends ControlFlowEntryElement, @top_level_expr_parent {
final override Expr getChild(int i) { result = this.getChildExpr(i) }
/** Gets the `i`th child expression of this element (zero-based). */

View File

@@ -74,8 +74,13 @@ class BasicBlock extends TBasicBlockStart {
/** Gets the last control flow node in this basic block. */
ControlFlow::Node getLastNode() { result = getNode(length() - 1) }
/** Gets the callable that this basic block belongs to. */
Callable getCallable() { result = this.getAPredecessor().getCallable() }
/** Gets the callable that this basic block belongs to, if any. */
final Callable getCallable() { result = this.getEntryElement() }
/** Gets the entry element that this basic block belongs to. */
final ControlFlowEntryElement getEntryElement() {
result = this.getFirstNode().getEnclosingElement()
}
/** Gets the length of this basic block. */
int length() { result = strictcount(getANode()) }
@@ -342,12 +347,10 @@ private import Internal
/**
* An entry basic block, that is, a basic block whose first node is
* the entry node of a callable.
* an entry node (`ControlFlow::Nodes::EntryNode`).
*/
class EntryBasicBlock extends BasicBlock {
EntryBasicBlock() { entryBB(this) }
override Callable getCallable() { result.getEntryPoint() = this.getFirstNode() }
}
/** Holds if `bb` is an entry basic block. */
@@ -357,7 +360,7 @@ private predicate entryBB(BasicBlock bb) {
/**
* An exit basic block, that is, a basic block whose last node is
* the exit node of a callable.
* an exit node (`ControlFlow::Nodes::ExitNode`).
*/
class ExitBasicBlock extends BasicBlock {
ExitBasicBlock() { exitBB(this) }

View File

@@ -7,6 +7,13 @@ private import ControlFlow::BasicBlocks
private import SuccessorTypes
private import semmle.code.csharp.Caching
/**
* An element that contains a top-level statement or expression. Either a callable
* (`Callable`), an attribute (`Attribute`), a field (`Field`), a property
* (`Property`), an indexer (`Indexer`), or a parameter (`Parameter`).
*/
class ControlFlowEntryElement extends Element, @top_level_exprorstmt_parent { }
/**
* A program element that can possess control flow. That is, either a statement or
* an expression.

View File

@@ -239,38 +239,55 @@ module ControlFlow {
/** Holds if this node has more than one successor. */
predicate isBranch() { strictcount(this.getASuccessor()) > 1 }
/** Gets the enclosing callable of this control flow node. */
/** Gets the enclosing callable of this control flow node, if any. */
Callable getEnclosingCallable() { none() }
/** Gets the enclosing entry element of this control flow node. */
ControlFlowEntryElement getEnclosingElement() { none() }
}
/** Provides different types of control flow nodes. */
module Nodes {
/** A node for a callable entry point. */
private import semmle.code.csharp.Enclosing::Internal
/** An entry node, for example a callable or a field initializer. */
class EntryNode extends Node, TEntryNode {
/** Gets the callable that this entry applies to. */
Callable getCallable() { this = TEntryNode(result) }
private ControlFlowEntryElement e;
EntryNode() { this = TEntryNode(e) }
/** Gets the callable that this entry applies to, if any. */
Callable getCallable() { result = e }
override BasicBlocks::EntryBlock getBasicBlock() { result = Node.super.getBasicBlock() }
override Callable getEnclosingCallable() { result = this.getCallable() }
override Location getLocation() { result = getCallable().getLocation() }
override ControlFlowEntryElement getEnclosingElement() { result = e }
override string toString() { result = "enter " + getCallable().toString() }
override Location getLocation() { result = this.getEnclosingElement().getLocation() }
override string toString() { result = "enter " + this.getEnclosingElement().toString() }
}
/** A node for a callable exit point. */
/** An exit node, for example a callable or a field initializer. */
class ExitNode extends Node, TExitNode {
/** Gets the callable that this exit applies to. */
Callable getCallable() { this = TExitNode(result) }
private ControlFlowEntryElement e;
ExitNode() { this = TExitNode(e) }
/** Gets the callable that this exit applies to, if any. */
Callable getCallable() { result = e }
override BasicBlocks::ExitBlock getBasicBlock() { result = Node.super.getBasicBlock() }
override Callable getEnclosingCallable() { result = this.getCallable() }
override Location getLocation() { result = getCallable().getLocation() }
override ControlFlowEntryElement getEnclosingElement() { result = e }
override string toString() { result = "exit " + getCallable().toString() }
override Location getLocation() { result = this.getEnclosingElement().getLocation() }
override string toString() { result = "exit " + this.getEnclosingElement().toString() }
}
/**
@@ -289,6 +306,10 @@ module ControlFlow {
override Callable getEnclosingCallable() { result = cfe.getEnclosingCallable() }
override ControlFlowEntryElement getEnclosingElement() {
exprEnclosingEntryElement(cfe, result)
}
override ControlFlowElement getElement() { result = cfe }
override string toString() {
@@ -1824,27 +1845,32 @@ module ControlFlow {
}
/**
* Gets the control flow element that is first executed when entering
* callable `c`.
* Gets the control flow element that is first executed when entering `e`.
*/
ControlFlowElement succEntry(@top_level_exprorstmt_parent p) {
p = any(Callable c |
ControlFlowElement succEntry(ControlFlowEntryElement e) {
e = any(Callable c |
if exists(c.(Constructor).getInitializer())
then result = first(c.(Constructor).getInitializer())
else result = first(c.getBody())
)
or
expr_parent_top_level_adjusted(any(Expr e | result = first(e)), _, p) and
not p instanceof Callable
expr_parent_top_level_adjusted(any(Expr e0 | result = first(e0)), _, e) and
not e instanceof Callable
}
/**
* Gets the callable that is exited when `cfe` finishes with completion `c`,
* Gets the element that is exited when `cfe` finishes with completion `c`,
* if any.
*/
Callable succExit(ControlFlowElement cfe, Completion c) {
cfe = last(result.getBody(), c) and
ControlFlowEntryElement succExit(ControlFlowElement cfe, Completion c) {
cfe = last(result.(Callable).getBody(), c) and
not c instanceof GotoCompletion
or
exists(Expr e |
expr_parent_top_level_adjusted(e, _, result) and
cfe = last(e, c) and
not result instanceof Callable
)
}
}
import Successor
@@ -1859,13 +1885,13 @@ module ControlFlow {
*/
cached
newtype TNode =
TEntryNode(Callable c) {
TEntryNode(ControlFlowEntryElement e) {
Stages::ControlFlowStage::forceCachingInSameStage() and
succEntrySplits(c, _, _, _)
succEntrySplits(e, _, _, _)
} or
TExitNode(Callable c) {
TExitNode(ControlFlowEntryElement e) {
exists(Reachability::SameSplitsBlock b | b.isReachable(_) |
succExitSplits(b.getAnElement(), _, c, _)
succExitSplits(b.getAnElement(), _, e, _)
)
} or
TElementNode(ControlFlowElement cfe, Splits splits) {
@@ -1875,18 +1901,20 @@ module ControlFlow {
/** Gets a successor node of a given flow type, if any. */
cached
Node getASuccessorByType(Node pred, SuccessorType t) {
// Callable entry node -> callable body
exists(ControlFlowElement succElement, Splits succSplits |
result = TElementNode(succElement, succSplits)
|
succEntrySplits(pred.(Nodes::EntryNode).getCallable(), succElement, succSplits, t)
// Entry node -> body
exists(ControlFlowElement succElement, Splits succSplits, ControlFlowEntryElement e |
result = TElementNode(succElement, succSplits) and
pred = TEntryNode(e) and
succEntrySplits(e, succElement, succSplits, t)
)
or
exists(ControlFlowElement predElement, Splits predSplits |
pred = TElementNode(predElement, predSplits)
|
// Element node -> callable exit
succExitSplits(predElement, predSplits, result.(Nodes::ExitNode).getCallable(), t)
// Element node -> exit node
exists(ControlFlowEntryElement e | result = TExitNode(e) |
succExitSplits(predElement, predSplits, e, t)
)
or
// Element node -> element node
exists(ControlFlowElement succElement, Splits succSplits, Completion c |

View File

@@ -836,7 +836,7 @@ class Splits extends TSplits {
*/
pragma[noinline]
predicate succEntrySplits(
@top_level_exprorstmt_parent pred, ControlFlowElement succ, Splits succSplits, SuccessorType t
ControlFlowEntryElement pred, ControlFlowElement succ, Splits succSplits, SuccessorType t
) {
succ = succEntry(pred) and
t instanceof NormalSuccessor and
@@ -847,7 +847,9 @@ predicate succEntrySplits(
* Holds if `pred` with splits `predSplits` can exit the enclosing callable
* `succ` with type `t`.
*/
predicate succExitSplits(ControlFlowElement pred, Splits predSplits, Callable succ, SuccessorType t) {
predicate succExitSplits(
ControlFlowElement pred, Splits predSplits, ControlFlowEntryElement succ, SuccessorType t
) {
exists(Reachability::SameSplitsBlock b, Completion c | pred = b.getAnElement() |
b.isReachable(predSplits) and
t.matchesCompletion(c) and

View File

@@ -59,7 +59,7 @@ class Expr extends DotNet::Expr, ControlFlowElement, @expr {
final Stmt getEnclosingStmt() { enclosingStmt(this, result) }
/** Gets the enclosing callable of this expression, if any. */
override Callable getEnclosingCallable() { exprEnclosingCallable(this, result) }
override Callable getEnclosingCallable() { exprEnclosingEntryElement(this, result) }
/**
* Holds if this expression is generated by the compiler and does not appear

View File

@@ -277,11 +277,11 @@
| Foreach.cs:36:10:36:11 | exit M6 | Foreach.cs:36:10:36:11 | exit M6 | 1 |
| Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | 1 |
| Foreach.cs:38:26:38:26 | String x | Foreach.cs:39:11:39:11 | ; | 4 |
| Initializers.cs:3:9:3:9 | this access | Initializers.cs:3:9:3:17 | ... = ... | 5 |
| Initializers.cs:4:9:4:9 | this access | Initializers.cs:4:25:4:31 | ... = ... | 6 |
| Initializers.cs:3:9:3:9 | enter F | Initializers.cs:3:9:3:9 | exit F | 7 |
| Initializers.cs:4:9:4:9 | enter G | Initializers.cs:4:9:4:9 | exit G | 8 |
| Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:5:6:16 | exit Initializers | 3 |
| Initializers.cs:8:10:8:10 | enter M | Initializers.cs:8:10:8:10 | exit M | 20 |
| Initializers.cs:14:20:14:20 | 1 | Initializers.cs:14:16:14:20 | ... = ... | 2 |
| Initializers.cs:14:16:14:16 | enter H | Initializers.cs:14:16:14:16 | exit H | 4 |
| NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:23:3:23 | access to parameter i | 3 |
| NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:9:3:10 | exit M1 | 1 |
| NullCoalescing.cs:3:28:3:28 | 0 | NullCoalescing.cs:3:28:3:28 | 0 | 1 |

View File

@@ -564,11 +564,11 @@
| post | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... |
| post | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:26:38:26 | String x |
| post | Foreach.cs:38:26:38:26 | String x | Foreach.cs:38:26:38:26 | String x |
| post | Initializers.cs:3:9:3:9 | this access | Initializers.cs:3:9:3:9 | this access |
| post | Initializers.cs:4:9:4:9 | this access | Initializers.cs:4:9:4:9 | this access |
| post | Initializers.cs:3:9:3:9 | enter F | Initializers.cs:3:9:3:9 | enter F |
| post | Initializers.cs:4:9:4:9 | enter G | Initializers.cs:4:9:4:9 | enter G |
| post | Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:5:6:16 | enter Initializers |
| post | Initializers.cs:8:10:8:10 | enter M | Initializers.cs:8:10:8:10 | enter M |
| post | Initializers.cs:14:20:14:20 | 1 | Initializers.cs:14:20:14:20 | 1 |
| post | Initializers.cs:14:16:14:16 | enter H | Initializers.cs:14:16:14:16 | enter H |
| post | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:9:3:10 | enter M1 |
| post | NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:9:3:10 | enter M1 |
| post | NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:9:3:10 | exit M1 |
@@ -2111,11 +2111,11 @@
| pre | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... |
| pre | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:26:38:26 | String x |
| pre | Foreach.cs:38:26:38:26 | String x | Foreach.cs:38:26:38:26 | String x |
| pre | Initializers.cs:3:9:3:9 | this access | Initializers.cs:3:9:3:9 | this access |
| pre | Initializers.cs:4:9:4:9 | this access | Initializers.cs:4:9:4:9 | this access |
| pre | Initializers.cs:3:9:3:9 | enter F | Initializers.cs:3:9:3:9 | enter F |
| pre | Initializers.cs:4:9:4:9 | enter G | Initializers.cs:4:9:4:9 | enter G |
| pre | Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:5:6:16 | enter Initializers |
| pre | Initializers.cs:8:10:8:10 | enter M | Initializers.cs:8:10:8:10 | enter M |
| pre | Initializers.cs:14:20:14:20 | 1 | Initializers.cs:14:20:14:20 | 1 |
| pre | Initializers.cs:14:16:14:16 | enter H | Initializers.cs:14:16:14:16 | enter H |
| pre | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:9:3:10 | enter M1 |
| pre | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:9:3:10 | exit M1 |
| pre | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:28:3:28 | 0 |

View File

@@ -1203,11 +1203,15 @@
| post | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:26:38:26 | String x |
| post | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:37:5:40:5 | {...} |
| post | Foreach.cs:39:11:39:11 | ; | Foreach.cs:38:18:38:34 | (..., ...) |
| post | Initializers.cs:3:9:3:9 | exit F | Initializers.cs:3:9:3:17 | ... = ... |
| post | Initializers.cs:3:9:3:9 | this access | Initializers.cs:3:9:3:9 | enter F |
| post | Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:3:13:3:17 | ... + ... |
| post | Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:9:3:9 | this access |
| post | Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:17:3:17 | 1 |
| post | Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:13 | access to field H |
| post | Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:4:27:4:31 | ... + ... |
| post | Initializers.cs:4:9:4:9 | exit G | Initializers.cs:4:25:4:31 | ... = ... |
| post | Initializers.cs:4:9:4:9 | this access | Initializers.cs:4:9:4:9 | enter G |
| post | Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:4:9:4:9 | access to property G |
| post | Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:9:4:9 | this access |
| post | Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:31:4:31 | 2 |
@@ -1233,7 +1237,9 @@
| post | Initializers.cs:11:39:11:39 | access to local variable i | Initializers.cs:11:18:11:63 | array creation of type Initializers[] |
| post | Initializers.cs:11:42:11:61 | object creation of type Initializers | Initializers.cs:11:59:11:60 | "" |
| post | Initializers.cs:11:59:11:60 | "" | Initializers.cs:11:39:11:39 | access to local variable i |
| post | Initializers.cs:14:16:14:16 | exit H | Initializers.cs:14:16:14:20 | ... = ... |
| post | Initializers.cs:14:16:14:20 | ... = ... | Initializers.cs:14:20:14:20 | 1 |
| post | Initializers.cs:14:20:14:20 | 1 | Initializers.cs:14:16:14:16 | enter H |
| post | NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:23:3:23 | access to parameter i |
| post | NullCoalescing.cs:3:9:3:10 | exit M1 | NullCoalescing.cs:3:28:3:28 | 0 |
| post | NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:23:3:28 | ... ?? ... |
@@ -3742,12 +3748,16 @@
| pre | Foreach.cs:38:26:38:26 | String x | Foreach.cs:38:33:38:33 | Int32 y |
| pre | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:18:38:34 | (..., ...) |
| pre | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... |
| pre | Initializers.cs:3:9:3:9 | enter F | Initializers.cs:3:9:3:9 | this access |
| pre | Initializers.cs:3:9:3:9 | this access | Initializers.cs:3:13:3:13 | access to field H |
| pre | Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:3:9:3:9 | exit F |
| pre | Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:17:3:17 | 1 |
| pre | Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:9:3:17 | ... = ... |
| pre | Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:17 | ... + ... |
| pre | Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:4:25:4:31 | ... = ... |
| pre | Initializers.cs:4:9:4:9 | enter G | Initializers.cs:4:9:4:9 | this access |
| pre | Initializers.cs:4:9:4:9 | this access | Initializers.cs:4:27:4:27 | access to field H |
| pre | Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:4:9:4:9 | exit G |
| pre | Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:31:4:31 | 2 |
| pre | Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:9:4:9 | access to property G |
| pre | Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:31 | ... + ... |
@@ -3772,6 +3782,8 @@
| pre | Initializers.cs:11:39:11:39 | access to local variable i | Initializers.cs:11:59:11:60 | "" |
| pre | Initializers.cs:11:42:11:61 | object creation of type Initializers | Initializers.cs:11:37:11:63 | { ..., ... } |
| pre | Initializers.cs:11:59:11:60 | "" | Initializers.cs:11:42:11:61 | object creation of type Initializers |
| pre | Initializers.cs:14:16:14:16 | enter H | Initializers.cs:14:20:14:20 | 1 |
| pre | Initializers.cs:14:16:14:20 | ... = ... | Initializers.cs:14:16:14:16 | exit H |
| pre | Initializers.cs:14:20:14:20 | 1 | Initializers.cs:14:16:14:20 | ... = ... |
| pre | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:23:3:28 | ... ?? ... |
| pre | NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:9:3:10 | exit M1 |

View File

@@ -1357,12 +1357,16 @@
| Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:18:38:34 | (..., ...) | semmle.label | successor |
| Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | semmle.label | successor |
| Foreach.cs:39:11:39:11 | ; | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | semmle.label | successor |
| Initializers.cs:3:9:3:9 | enter F | Initializers.cs:3:9:3:9 | this access | semmle.label | successor |
| Initializers.cs:3:9:3:9 | this access | Initializers.cs:3:13:3:13 | access to field H | semmle.label | successor |
| Initializers.cs:3:9:3:17 | ... = ... | Initializers.cs:3:9:3:9 | exit F | semmle.label | successor |
| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:17:3:17 | 1 | semmle.label | successor |
| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:9:3:17 | ... = ... | semmle.label | successor |
| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:17 | ... + ... | semmle.label | successor |
| Initializers.cs:4:9:4:9 | access to property G | Initializers.cs:4:25:4:31 | ... = ... | semmle.label | successor |
| Initializers.cs:4:9:4:9 | enter G | Initializers.cs:4:9:4:9 | this access | semmle.label | successor |
| Initializers.cs:4:9:4:9 | this access | Initializers.cs:4:27:4:27 | access to field H | semmle.label | successor |
| Initializers.cs:4:25:4:31 | ... = ... | Initializers.cs:4:9:4:9 | exit G | semmle.label | successor |
| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:31:4:31 | 2 | semmle.label | successor |
| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:9:4:9 | access to property G | semmle.label | successor |
| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:31 | ... + ... | semmle.label | successor |
@@ -1387,6 +1391,8 @@
| Initializers.cs:11:39:11:39 | access to local variable i | Initializers.cs:11:59:11:60 | "" | semmle.label | successor |
| Initializers.cs:11:42:11:61 | object creation of type Initializers | Initializers.cs:11:37:11:63 | { ..., ... } | semmle.label | successor |
| Initializers.cs:11:59:11:60 | "" | Initializers.cs:11:42:11:61 | object creation of type Initializers | semmle.label | successor |
| Initializers.cs:14:16:14:16 | enter H | Initializers.cs:14:20:14:20 | 1 | semmle.label | successor |
| Initializers.cs:14:16:14:20 | ... = ... | Initializers.cs:14:16:14:16 | exit H | semmle.label | successor |
| Initializers.cs:14:20:14:20 | 1 | Initializers.cs:14:16:14:20 | ... = ... | semmle.label | successor |
| NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:23:3:28 | ... ?? ... | semmle.label | successor |
| NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:9:3:10 | exit M1 | semmle.label | non-null |