Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
93a594e
Cfg: Support Throw expressions.
aschackmull Mar 5, 2026
a53cffc
Cfg: Support GotoStmt.
aschackmull Mar 5, 2026
0b6c416
Cfg: Support short-circuiting compound assignments.
aschackmull Mar 3, 2026
035b83c
C#: Introduce ControlFlowElementOrCallable.
aschackmull Mar 9, 2026
6ffed85
Cfg/Java: Move InstanceOfExpr CFG into shared lib.
aschackmull Mar 11, 2026
88aaff8
Cfg: Extend consistency checks.
aschackmull Mar 12, 2026
61976e3
C#: Rename ControlFlow::Node to ControlFlowNode.
aschackmull Mar 12, 2026
b85b02a
Cfg: Add dominance predicates to shared ControlFlowNode.
aschackmull Mar 18, 2026
03f6bdb
C#: Update some references in preparation for CFG swap.
aschackmull Mar 18, 2026
b878ae3
C#: Update some references to ControlFlow::Nodes.
aschackmull Mar 18, 2026
13a4141
C#: Rename remaining references to ControlFlow::Nodes.
aschackmull Mar 18, 2026
9cf9a36
C#: Rename ControlFlow::BasicBlock to BasicBlock.
aschackmull Mar 18, 2026
ff978d1
C#: Replace CFG.
aschackmull Mar 9, 2026
b179033
C#: Fix test.
aschackmull Mar 20, 2026
700d56f
C#: Fix UncheckedCastInEquals.
aschackmull Mar 20, 2026
ac88b73
C#: Bugfix in enclosing callable.
aschackmull Mar 24, 2026
093eb57
C#: Fix CFG position of property setter calls.
aschackmull Mar 26, 2026
43fe411
C#: Accept SSA location changes.
aschackmull Mar 26, 2026
1a6670a
C#: Phi nodes are not expected to have associated Elements.
aschackmull Mar 26, 2026
6010640
C#: Accept bugfix.
aschackmull Mar 30, 2026
a5c99f9
C#: Accept harmless CFG changes.
aschackmull Mar 30, 2026
5d58909
C#: Accept CFG changes.
aschackmull Mar 30, 2026
49cc931
C#: Compile-time constants no longer have CFG nodes.
aschackmull Mar 30, 2026
e90243c
C#: Accept irrelevant changes.
aschackmull Mar 31, 2026
88256ee
C#: GuardedExpr no longer contains expressions guarded solely by disj…
aschackmull Mar 31, 2026
773881f
C#: Accept data flow inconsistency check for read+write calls.
aschackmull Mar 31, 2026
a997d9f
C#: Accept fixed consistency check.
aschackmull Mar 31, 2026
a695819
C#: Accept CFG changes for "first" relation.
aschackmull Mar 31, 2026
a7d4b00
C#: Accept changed location for phi nodes.
aschackmull Apr 7, 2026
371bc30
C#: CFG and data flow nodes now exist for LHSs.
aschackmull Apr 7, 2026
1d9c0ae
C#: Fix perf.
aschackmull Apr 8, 2026
bfbd0f7
C#: Fix some bad join orders.
aschackmull Apr 9, 2026
bbd403d
C#: Rework DataFlowCallable-to-cfg relation in terms of basic blocks …
aschackmull Apr 9, 2026
2d5a184
C#: Accept new CFG in tests.
aschackmull Apr 9, 2026
aaf9bb2
C#: Accept fewer CallContextSpecificCall due to no splitting.
aschackmull Apr 9, 2026
452913f
C#: Improve perf of UnsynchronizedStaticAccess.ql.
aschackmull Apr 10, 2026
d5c9fd1
C#/Cfg: A bit more qldoc.
aschackmull Apr 10, 2026
88160ef
C#: Add change note.
aschackmull Apr 13, 2026
e928c22
C#/Cfg: Some simple review fixes.
aschackmull Apr 20, 2026
3ceb96a
C#: Eliminate Completion.qll.
aschackmull Apr 20, 2026
b6f50f5
C#: Simplify.
aschackmull Apr 20, 2026
9de02b7
Cfg: Use consistent casing in additional node tags.
aschackmull Apr 21, 2026
a2a4e82
C#: Deprecate ControlFlowElement.getAControlFlowNode and remove some …
aschackmull Apr 21, 2026
67c0515
Cfg: Undo consistency check change.
aschackmull Apr 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
C#: Rename remaining references to ControlFlow::Nodes.
  • Loading branch information
aschackmull committed Apr 10, 2026
commit 13a4141cc66e9681ff0d8be2f72b37fdb21d19c5
2 changes: 1 addition & 1 deletion csharp/ql/consistency-queries/DataFlowConsistency.ql
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ private module Input implements InputSig<Location, CsharpDataFlow> {
init.getInitializer().getNumberOfChildren() > 1
)
or
exists(ControlFlow::Nodes::ElementNode cfn, ControlFlow::Nodes::Split split |
exists(ControlFlowNodes::ElementNode cfn, ControlFlowNodes::Split split |
exists(arg.asExprAtNode(cfn))
|
split = cfn.getASplit() and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class ControlFlowElement extends ControlFlowElementOrCallable, @control_flow_ele
* several `ControlFlowNode`s, for example to represent the continuation
* flow in a `try/catch/finally` construction.
*/
Nodes::ElementNode getAControlFlowNode() { result.getAstNode() = this }
ControlFlowNodes::ElementNode getAControlFlowNode() { result.getAstNode() = this }

/** Gets the control flow node for this element. */
Comment thread
hvitved marked this conversation as resolved.
Outdated
ControlFlowNode getControlFlowNode() { result.getAstNode() = this }
Expand All @@ -53,14 +53,14 @@ class ControlFlowElement extends ControlFlowElementOrCallable, @control_flow_ele
/**
* Gets a first control flow node executed within this element.
*/
Nodes::ElementNode getAControlFlowEntryNode() {
ControlFlowNodes::ElementNode getAControlFlowEntryNode() {
result = Impl::getAControlFlowEntryNode(this).(ControlFlowElement).getAControlFlowNode()
}

/**
* Gets a potential last control flow node executed within this element.
*/
Nodes::ElementNode getAControlFlowExitNode() {
ControlFlowNodes::ElementNode getAControlFlowExitNode() {
result = Impl::getAControlFlowExitNode(this).(ControlFlowElement).getAControlFlowNode()
}

Expand Down
75 changes: 39 additions & 36 deletions csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll
Original file line number Diff line number Diff line change
Expand Up @@ -255,42 +255,6 @@ module ControlFlow {
Callable getEnclosingCallable() { result = this.getScope() }
}

/** Provides different types of control flow nodes. */
module Nodes {
/**
* A node for a control flow element, that is, an expression or a statement.
*
* Each control flow element maps to zero or more `ElementNode`s: zero when
* the element is in unreachable (dead) code, and multiple when there are
* different splits for the element.
*/
class ElementNode extends Node instanceof Impl::AstCfgNode {
/** Gets a comma-separated list of strings for each split in this node, if any. */
final string getSplitsString() { result = super.getSplitsString() }

/** Gets a split for this control flow node, if any. */
final Split getASplit() { result = super.getASplit() }
}

/** A control-flow node for an expression. */
class ExprNode extends ElementNode {
Expr e;

ExprNode() { e = unique(Expr e_ | e_ = this.asExpr() | e_) }

/** Gets the expression that this control-flow node belongs to. */
Expr getExpr() { result = e }

/** Gets the value of this expression node, if any. */
string getValue() { result = e.getValue() }

/** Gets the type of this expression node. */
Type getType() { result = e.getType() }
}

class Split = Splitting::Split;
}

class BasicBlock = BBs::BasicBlock;

/** Provides different types of basic blocks. */
Expand All @@ -308,3 +272,42 @@ module ControlFlow {
class ConditionBlock = BBs::ConditionBlock;
}
}

/** Provides different types of control flow nodes. */
module ControlFlowNodes {
private import internal.ControlFlowGraphImpl as Impl
private import internal.Splitting as Splitting

/**
* A node for a control flow element, that is, an expression or a statement.
*
* Each control flow element maps to zero or more `ElementNode`s: zero when
* the element is in unreachable (dead) code, and multiple when there are
* different splits for the element.
*/
class ElementNode extends ControlFlowNode instanceof Impl::AstCfgNode {
/** Gets a comma-separated list of strings for each split in this node, if any. */
final string getSplitsString() { result = super.getSplitsString() }

/** Gets a split for this control flow node, if any. */
final Split getASplit() { result = super.getASplit() }
}

/** A control-flow node for an expression. */
class ExprNode extends ElementNode {
Expr e;

ExprNode() { e = unique(Expr e_ | e_ = this.asExpr() | e_) }

/** Gets the expression that this control-flow node belongs to. */
Expr getExpr() { result = e }

/** Gets the value of this expression node, if any. */
string getValue() { result = e.getValue() }

/** Gets the type of this expression node. */
Type getType() { result = e.getType() }
}

class Split = Splitting::Split;
}
10 changes: 5 additions & 5 deletions csharp/ql/lib/semmle/code/csharp/controlflow/Guards.qll
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ class Guard extends Guards::Guard {
* In case `cfn` or `sub` access an SSA variable in their left-most qualifier, then
* so must the other (accessing the same SSA variable).
*/
predicate controlsNode(ControlFlow::Nodes::ElementNode cfn, AccessOrCallExpr sub, GuardValue v) {
predicate controlsNode(ControlFlowNodes::ElementNode cfn, AccessOrCallExpr sub, GuardValue v) {
isGuardedByNode(cfn, this, sub, v)
}

Expand All @@ -332,7 +332,7 @@ class Guard extends Guards::Guard {
* Note: This predicate is inlined.
*/
pragma[inline]
predicate controlsNode(ControlFlow::Nodes::ElementNode cfn, GuardValue v) {
predicate controlsNode(ControlFlowNodes::ElementNode cfn, GuardValue v) {
guardControls(this, cfn.getBasicBlock(), v)
}

Expand Down Expand Up @@ -729,7 +729,7 @@ class GuardedExpr extends AccessOrCallExpr {
* In the example above, the node for `x.ToString()` is null-guarded in the
* split `b == true`, but not in the split `b == false`.
*/
class GuardedControlFlowNode extends ControlFlow::Nodes::ElementNode {
class GuardedControlFlowNode extends ControlFlowNodes::ElementNode {
private Guard g;
private AccessOrCallExpr sub0;
private GuardValue v0;
Expand Down Expand Up @@ -785,7 +785,7 @@ class GuardedDataFlowNode extends DataFlow::ExprNode {
private GuardValue v0;

GuardedDataFlowNode() {
exists(ControlFlow::Nodes::ElementNode cfn | exists(this.getExprAtNode(cfn)) |
exists(ControlFlowNodes::ElementNode cfn | exists(this.getExprAtNode(cfn)) |
g.controlsNode(cfn, sub0, v0)
)
}
Expand Down Expand Up @@ -1179,7 +1179,7 @@ module Internal {

cached
predicate isGuardedByNode(
ControlFlow::Nodes::ElementNode guarded, Guard g, AccessOrCallExpr sub, GuardValue v
ControlFlowNodes::ElementNode guarded, Guard g, AccessOrCallExpr sub, GuardValue v
) {
nodeIsGuardedBySameSubExpr(guarded, _, _, g, sub, v) and
forall(ControlFlowNode subCfn, Ssa::Definition def |
Expand Down
2 changes: 1 addition & 1 deletion csharp/ql/lib/semmle/code/csharp/dataflow/SSA.qll
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ module Ssa {
* `M2` via the call on line 6.
*/
deprecated final predicate isCapturedVariableDefinitionFlowIn(
ImplicitEntryDefinition def, ControlFlow::Nodes::ElementNode c, boolean additionalCalls
ImplicitEntryDefinition def, ControlFlowNodes::ElementNode c, boolean additionalCalls
) {
none()
}
Expand Down
8 changes: 4 additions & 4 deletions csharp/ql/lib/semmle/code/csharp/dataflow/SignAnalysis.qll
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ predicate strictlyNegativeExpr(Expr e) {
}

/** Holds if `e` can be positive and cannot be negative. */
predicate positive(ControlFlow::Nodes::ExprNode e) { Common::positive(e) }
predicate positive(ControlFlowNodes::ExprNode e) { Common::positive(e) }

/** Holds if `e` can be negative and cannot be positive. */
predicate negative(ControlFlow::Nodes::ExprNode e) { Common::negative(e) }
predicate negative(ControlFlowNodes::ExprNode e) { Common::negative(e) }

/** Holds if `e` is strictly positive. */
predicate strictlyPositive(ControlFlow::Nodes::ExprNode e) { Common::strictlyPositive(e) }
predicate strictlyPositive(ControlFlowNodes::ExprNode e) { Common::strictlyPositive(e) }

/** Holds if `e` is strictly negative. */
predicate strictlyNegative(ControlFlow::Nodes::ExprNode e) { Common::strictlyNegative(e) }
predicate strictlyNegative(ControlFlowNodes::ExprNode e) { Common::strictlyNegative(e) }
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,11 @@ private module Cached {

cached
newtype TDataFlowCall =
TNonDelegateCall(ControlFlow::Nodes::ElementNode cfn, DispatchCall dc) {
TNonDelegateCall(ControlFlowNodes::ElementNode cfn, DispatchCall dc) {
DataFlowImplCommon::forceCachingInSameStage() and
cfn.asExpr() = dc.getCall()
} or
TExplicitDelegateLikeCall(ControlFlow::Nodes::ElementNode cfn, DelegateLikeCall dc) {
TExplicitDelegateLikeCall(ControlFlowNodes::ElementNode cfn, DelegateLikeCall dc) {
cfn.asExpr() = dc
} or
TSummaryCall(FlowSummary::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver) {
Expand Down Expand Up @@ -210,7 +210,7 @@ class DataFlowCallable extends TDataFlowCallable {
}

pragma[nomagic]
private ControlFlow::Nodes::ElementNode getAMultiBodyEntryNode(ControlFlow::BasicBlock bb, int i) {
private ControlFlowNodes::ElementNode getAMultiBodyEntryNode(ControlFlow::BasicBlock bb, int i) {
this.isMultiBodied() and
exists(ControlFlowElement body, Location l |
body = this.asCallable(l).getBody() or
Expand All @@ -223,14 +223,14 @@ class DataFlowCallable extends TDataFlowCallable {
}

pragma[nomagic]
private ControlFlow::Nodes::ElementNode getAMultiBodyControlFlowNodePred() {
private ControlFlowNodes::ElementNode getAMultiBodyControlFlowNodePred() {
result = this.getAMultiBodyEntryNode(_, _).getAPredecessor()
or
result = this.getAMultiBodyControlFlowNodePred().getAPredecessor()
}

pragma[nomagic]
private ControlFlow::Nodes::ElementNode getAMultiBodyControlFlowNodeSuccSameBasicBlock() {
private ControlFlowNodes::ElementNode getAMultiBodyControlFlowNodeSuccSameBasicBlock() {
exists(ControlFlow::BasicBlock bb, int i, int j |
exists(this.getAMultiBodyEntryNode(bb, i)) and
result = bb.getNode(j) and
Expand All @@ -246,7 +246,7 @@ class DataFlowCallable extends TDataFlowCallable {
}

pragma[inline]
private ControlFlow::Nodes::ElementNode getAMultiBodyControlFlowNode() {
private ControlFlowNodes::ElementNode getAMultiBodyControlFlowNode() {
result =
[
this.getAMultiBodyEntryNode(_, _), this.getAMultiBodyControlFlowNodePred(),
Expand Down Expand Up @@ -307,7 +307,7 @@ abstract class DataFlowCall extends TDataFlowCall {
abstract DataFlowCallable getARuntimeTarget();

/** Gets the control flow node where this call happens, if any. */
abstract ControlFlow::Nodes::ElementNode getControlFlowNode();
abstract ControlFlowNodes::ElementNode getControlFlowNode();

/** Gets the data flow node corresponding to this call, if any. */
abstract DataFlow::Node getNode();
Expand Down Expand Up @@ -363,7 +363,7 @@ private predicate folderDist(Folder f1, Folder f2, int i) =

/** A non-delegate C# call relevant for data flow. */
class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall {
private ControlFlow::Nodes::ElementNode cfn;
private ControlFlowNodes::ElementNode cfn;
private DispatchCall dc;

NonDelegateDataFlowCall() { this = TNonDelegateCall(cfn, dc) }
Expand Down Expand Up @@ -436,7 +436,7 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall {
not dc.isReflection()
}

override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn }
override ControlFlowNodes::ElementNode getControlFlowNode() { result = cfn }

override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn }

Expand All @@ -452,7 +452,7 @@ abstract class DelegateDataFlowCall extends DataFlowCall { }

/** An explicit delegate or function pointer call relevant for data flow. */
class ExplicitDelegateLikeDataFlowCall extends DelegateDataFlowCall, TExplicitDelegateLikeCall {
private ControlFlow::Nodes::ElementNode cfn;
private ControlFlowNodes::ElementNode cfn;
private DelegateLikeCall dc;

ExplicitDelegateLikeDataFlowCall() { this = TExplicitDelegateLikeCall(cfn, dc) }
Expand All @@ -464,7 +464,7 @@ class ExplicitDelegateLikeDataFlowCall extends DelegateDataFlowCall, TExplicitDe
none() // handled by the shared library
}

override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn }
override ControlFlowNodes::ElementNode getControlFlowNode() { result = cfn }

override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn }

Expand Down Expand Up @@ -495,7 +495,7 @@ class SummaryCall extends DelegateDataFlowCall, TSummaryCall {
none() // handled by the shared library
}

override ControlFlow::Nodes::ElementNode getControlFlowNode() { none() }
override ControlFlowNodes::ElementNode getControlFlowNode() { none() }

override DataFlow::Node getNode() { none() }

Expand Down
Loading