Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
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
10 changes: 5 additions & 5 deletions csharp/ql/lib/semmle/code/csharp/Assignable.qll
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class AssignableRead extends AssignableAccess {
}

pragma[noinline]
private ControlFlow::Node getAnAdjacentReadSameVar() {
private ControlFlowNode getAnAdjacentReadSameVar() {
SsaImpl::adjacentReadPairSameVar(_, this.getAControlFlowNode(), result)
}

Expand Down Expand Up @@ -115,7 +115,7 @@ class AssignableRead extends AssignableAccess {
*/
pragma[nomagic]
AssignableRead getANextRead() {
forex(ControlFlow::Node cfn | cfn = result.getAControlFlowNode() |
forex(ControlFlowNode cfn | cfn = result.getAControlFlowNode() |
cfn = this.getAnAdjacentReadSameVar()
)
}
Expand Down Expand Up @@ -419,7 +419,7 @@ class AssignableDefinition extends TAssignableDefinition {
* the definitions of `x` and `y` in `M(out x, out y)` and `(x, y) = (0, 1)`
* relate to the same call to `M` and assignment node, respectively.
*/
deprecated ControlFlow::Node getAControlFlowNode() {
deprecated ControlFlowNode getAControlFlowNode() {
result = this.getExpr().getAControlFlowNode()
}

Expand Down Expand Up @@ -494,7 +494,7 @@ class AssignableDefinition extends TAssignableDefinition {
*/
pragma[nomagic]
AssignableRead getAFirstRead() {
forex(ControlFlow::Node cfn | cfn = result.getAControlFlowNode() |
forex(ControlFlowNode cfn | cfn = result.getAControlFlowNode() |
exists(Ssa::ExplicitDefinition def | result = def.getAFirstReadAtNode(cfn) |
this = def.getADefinition()
)
Expand Down Expand Up @@ -688,7 +688,7 @@ module AssignableDefinitions {
/** Gets the underlying parameter. */
Parameter getParameter() { result = p }

deprecated override ControlFlow::Node getAControlFlowNode() {
deprecated override ControlFlowNode getAControlFlowNode() {
result = p.getCallable().getEntryPoint()
}

Expand Down
2 changes: 1 addition & 1 deletion csharp/ql/lib/semmle/code/csharp/Caching.qll
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ module Stages {
private predicate forceCachingInSameStageRev() {
exists(Split s)
or
exists(ControlFlow::Node n)
exists(ControlFlowNode n)
or
forceCachingInSameStageRev()
}
Expand Down
2 changes: 1 addition & 1 deletion csharp/ql/lib/semmle/code/csharp/Callable.qll
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ private import TypeRef
* an anonymous function (`AnonymousFunctionExpr`), or a local function
* (`LocalFunction`).
*/
class Callable extends Parameterizable, ExprOrStmtParent, @callable {
class Callable extends Parameterizable, ControlFlowElementOrCallable, @callable {
/** Gets the return type of this callable. */
Type getReturnType() { none() }

Expand Down
12 changes: 7 additions & 5 deletions csharp/ql/lib/semmle/code/csharp/controlflow/BasicBlocks.qll
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,16 @@ final class BasicBlock extends BasicBlocksImpl::BasicBlock {
BasicBlock getASuccessor() { result = super.getASuccessor() }

/** Gets the control flow node at a specific (zero-indexed) position in this basic block. */
ControlFlow::Node getNode(int pos) { result = super.getNode(pos) }
ControlFlowNode getNode(int pos) { result = super.getNode(pos) }

/** Gets a control flow node in this basic block. */
ControlFlow::Node getANode() { result = super.getANode() }
ControlFlowNode getANode() { result = super.getANode() }

/** Gets the first control flow node in this basic block. */
ControlFlow::Node getFirstNode() { result = super.getFirstNode() }
ControlFlowNode getFirstNode() { result = super.getFirstNode() }

/** Gets the last control flow node in this basic block. */
ControlFlow::Node getLastNode() { result = super.getLastNode() }
ControlFlowNode getLastNode() { result = super.getLastNode() }

/** Gets the callable that this basic block belongs to. */
final Callable getCallable() { result = this.getFirstNode().getEnclosingCallable() }
Expand Down Expand Up @@ -339,12 +339,14 @@ final class ConditionBlock extends BasicBlock, BasicBlocksImpl::ConditionBasicBl
}
}

private class ControlFlowNodeAlias = ControlFlowNode;

private class BasicBlockAlias = BasicBlock;

private class EntryBasicBlockAlias = EntryBasicBlock;

module Cfg implements BB::CfgSig<Location> {
class ControlFlowNode = ControlFlow::Node;
class ControlFlowNode = ControlFlowNodeAlias;

class BasicBlock = BasicBlockAlias;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,20 @@ private import ControlFlow::BasicBlocks
private import semmle.code.csharp.Caching
private import internal.ControlFlowGraphImpl as Impl

private class TControlFlowElementOrCallable = @callable or @control_flow_element;

class ControlFlowElementOrCallable extends ExprOrStmtParent, TControlFlowElementOrCallable { }

/**
* A program element that can possess control flow. That is, either a statement or
* an expression.
*
* A control flow element can be mapped to a control flow node (`ControlFlow::Node`)
* A control flow element can be mapped to a control flow node (`ControlFlowNode`)
* via `getAControlFlowNode()`. There is a one-to-many relationship between
* control flow elements and control flow nodes. This allows control flow
* splitting, for example modeling the control flow through `finally` blocks.
*/
class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
class ControlFlowElement extends ControlFlowElementOrCallable, @control_flow_element {
/** Gets the enclosing callable of this element, if any. */
Callable getEnclosingCallable() { none() }

Expand All @@ -33,15 +37,15 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
* Gets a control flow node for this element. That is, a node in the
* control flow graph that corresponds to this element.
*
* Typically, there is exactly one `ControlFlow::Node` associated with a
* Typically, there is exactly one `ControlFlowNode` associated with a
* `ControlFlowElement`, but a `ControlFlowElement` may be split into
* several `ControlFlow::Node`s, for example to represent the continuation
* several `ControlFlowNode`s, for example to represent the continuation
* flow in a `try/catch/finally` construction.
*/
Nodes::ElementNode getAControlFlowNode() { result.getAstNode() = this }

/** Gets the control flow node for this element. */
Comment thread
hvitved marked this conversation as resolved.
Outdated
ControlFlow::Node getControlFlowNode() { result.getAstNode() = this }
ControlFlowNode getControlFlowNode() { result.getAstNode() = this }

/** Gets the basic block in which this element occurs. */
BasicBlock getBasicBlock() { result = this.getAControlFlowNode().getBasicBlock() }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import csharp

class ControlFlowNode = ControlFlow::Node;

/**
* Provides classes representing the control flow graph within callables.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ private import semmle.code.csharp.controlflow.Guards as Guards
private import semmle.code.csharp.ExprOrStmtParent

private module ControlFlowInput implements
InputSig<Location, ControlFlow::Node, ControlFlow::BasicBlock>
InputSig<Location, ControlFlowNode, ControlFlow::BasicBlock>
{
private import csharp as CS

AstNode getEnclosingAstNode(ControlFlow::Node node) {
AstNode getEnclosingAstNode(ControlFlowNode node) {
node.getAstNode() = result
or
not exists(node.getAstNode()) and result = node.getEnclosingCallable()
Expand Down
24 changes: 12 additions & 12 deletions csharp/ql/lib/semmle/code/csharp/controlflow/Guards.qll
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ private import semmle.code.csharp.frameworks.system.collections.Generic
private import codeql.controlflow.Guards as SharedGuards

private module GuardsInput implements
SharedGuards::InputSig<Location, ControlFlow::Node, ControlFlow::BasicBlock>
SharedGuards::InputSig<Location, ControlFlowNode, ControlFlow::BasicBlock>
{
private import csharp as CS

Expand Down Expand Up @@ -605,22 +605,22 @@ class AccessOrCallExpr extends Expr {
* An expression can have more than one SSA qualifier in the presence
* of control flow splitting.
*/
Ssa::Definition getAnSsaQualifier(ControlFlow::Node cfn) { result = getAnSsaQualifier(this, cfn) }
Ssa::Definition getAnSsaQualifier(ControlFlowNode cfn) { result = getAnSsaQualifier(this, cfn) }
}

private Declaration getDeclarationTarget(Expr e) {
e = any(AssignableAccess aa | result = aa.getTarget()) or
result = e.(Call).getTarget()
}

private Ssa::Definition getAnSsaQualifier(Expr e, ControlFlow::Node cfn) {
private Ssa::Definition getAnSsaQualifier(Expr e, ControlFlowNode cfn) {
e = getATrackedAccess(result, cfn)
or
not e = getATrackedAccess(_, _) and
result = getAnSsaQualifier(e.(QualifiableExpr).getQualifier(), cfn)
}

private AssignableAccess getATrackedAccess(Ssa::Definition def, ControlFlow::Node cfn) {
private AssignableAccess getATrackedAccess(Ssa::Definition def, ControlFlowNode cfn) {
result = def.getAReadAtNode(cfn)
or
result = def.(Ssa::ExplicitDefinition).getADefinition().getTargetAccess() and
Expand Down Expand Up @@ -1115,7 +1115,7 @@ module Internal {

pragma[nomagic]
private predicate nodeIsGuardedBySameSubExpr0(
ControlFlow::Node guardedCfn, BasicBlock guardedBB, AccessOrCallExpr guarded, Guard g,
ControlFlowNode guardedCfn, BasicBlock guardedBB, AccessOrCallExpr guarded, Guard g,
AccessOrCallExpr sub, GuardValue v
) {
Stages::GuardsStage::forceCachingInSameStage() and
Expand All @@ -1128,7 +1128,7 @@ module Internal {

pragma[nomagic]
private predicate nodeIsGuardedBySameSubExpr(
ControlFlow::Node guardedCfn, BasicBlock guardedBB, AccessOrCallExpr guarded, Guard g,
ControlFlowNode guardedCfn, BasicBlock guardedBB, AccessOrCallExpr guarded, Guard g,
AccessOrCallExpr sub, GuardValue v
) {
nodeIsGuardedBySameSubExpr0(guardedCfn, guardedBB, guarded, g, sub, v) and
Expand All @@ -1137,8 +1137,8 @@ module Internal {

pragma[nomagic]
private predicate nodeIsGuardedBySameSubExprSsaDef0(
ControlFlow::Node cfn, BasicBlock guardedBB, AccessOrCallExpr guarded, Guard g,
ControlFlow::Node subCfn, BasicBlock subCfnBB, AccessOrCallExpr sub, GuardValue v,
ControlFlowNode cfn, BasicBlock guardedBB, AccessOrCallExpr guarded, Guard g,
ControlFlowNode subCfn, BasicBlock subCfnBB, AccessOrCallExpr sub, GuardValue v,
Ssa::Definition def
) {
nodeIsGuardedBySameSubExpr(cfn, guardedBB, guarded, g, sub, v) and
Expand All @@ -1148,7 +1148,7 @@ module Internal {

pragma[nomagic]
private predicate nodeIsGuardedBySameSubExprSsaDef(
ControlFlow::Node guardedCfn, AccessOrCallExpr guarded, Guard g, ControlFlow::Node subCfn,
ControlFlowNode guardedCfn, AccessOrCallExpr guarded, Guard g, ControlFlowNode subCfn,
AccessOrCallExpr sub, GuardValue v, Ssa::Definition def
) {
exists(BasicBlock guardedBB, BasicBlock subCfnBB |
Expand All @@ -1162,15 +1162,15 @@ module Internal {
private predicate isGuardedByExpr0(
AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, GuardValue v
) {
forex(ControlFlow::Node cfn | cfn = guarded.getAControlFlowNode() |
forex(ControlFlowNode cfn | cfn = guarded.getAControlFlowNode() |
nodeIsGuardedBySameSubExpr(cfn, _, guarded, g, sub, v)
)
}

cached
predicate isGuardedByExpr(AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, GuardValue v) {
isGuardedByExpr0(guarded, g, sub, v) and
forall(ControlFlow::Node subCfn, Ssa::Definition def |
forall(ControlFlowNode subCfn, Ssa::Definition def |
nodeIsGuardedBySameSubExprSsaDef(_, guarded, g, subCfn, sub, v, def)
|
def = guarded.getAnSsaQualifier(_)
Expand All @@ -1182,7 +1182,7 @@ module Internal {
ControlFlow::Nodes::ElementNode guarded, Guard g, AccessOrCallExpr sub, GuardValue v
) {
nodeIsGuardedBySameSubExpr(guarded, _, _, g, sub, v) and
forall(ControlFlow::Node subCfn, Ssa::Definition def |
forall(ControlFlowNode subCfn, Ssa::Definition def |
nodeIsGuardedBySameSubExprSsaDef(guarded, _, g, subCfn, sub, v, def)
|
def =
Expand Down
18 changes: 7 additions & 11 deletions csharp/ql/lib/semmle/code/csharp/dataflow/Nullness.qll
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ private predicate nonNullDef(Ssa::ExplicitDefinition def) {
/**
* Holds if `node` is a dereference `d` of SSA definition `def`.
*/
private predicate dereferenceAt(ControlFlow::Node node, Ssa::Definition def, Dereference d) {
private predicate dereferenceAt(ControlFlowNode node, Ssa::Definition def, Dereference d) {
d = def.getAReadAtNode(node)
}

Expand Down Expand Up @@ -192,9 +192,7 @@ private predicate isNullDefaultArgument(Ssa::ImplicitParameterDefinition def, Al
}

/** Holds if `def` is an SSA definition that may be `null`. */
private predicate defMaybeNull(
Ssa::Definition def, ControlFlow::Node node, string msg, Element reason
) {
private predicate defMaybeNull(Ssa::Definition def, ControlFlowNode node, string msg, Element reason) {
not nonNullDef(def) and
(
// A variable compared to `null` might be `null`
Expand Down Expand Up @@ -256,19 +254,19 @@ private Ssa::Definition getAnUltimateDefinition(Ssa::Definition def) {
* through an intermediate dereference that always throws a null reference
* exception.
*/
private predicate defReaches(Ssa::Definition def, ControlFlow::Node cfn) {
private predicate defReaches(Ssa::Definition def, ControlFlowNode cfn) {
exists(def.getAFirstReadAtNode(cfn))
or
exists(ControlFlow::Node mid | defReaches(def, mid) |
exists(ControlFlowNode mid | defReaches(def, mid) |
SsaImpl::adjacentReadPairSameVar(_, mid, cfn) and
not mid = any(Dereference d | d.isAlwaysNull(def.getSourceVariable())).getAControlFlowNode()
)
}

private module NullnessConfig implements ControlFlowReachability::ConfigSig {
predicate source(ControlFlow::Node node, Ssa::Definition def) { defMaybeNull(def, node, _, _) }
predicate source(ControlFlowNode node, Ssa::Definition def) { defMaybeNull(def, node, _, _) }

predicate sink(ControlFlow::Node node, Ssa::Definition def) {
predicate sink(ControlFlowNode node, Ssa::Definition def) {
exists(Dereference d |
dereferenceAt(node, def, d) and
not d instanceof NonNullExpr
Expand All @@ -283,9 +281,7 @@ private module NullnessConfig implements ControlFlowReachability::ConfigSig {
private module NullnessFlow = ControlFlowReachability::Flow<NullnessConfig>;

predicate maybeNullDeref(Dereference d, Ssa::SourceVariable v, string msg, Element reason) {
exists(
Ssa::Definition origin, Ssa::Definition ssa, ControlFlow::Node src, ControlFlow::Node sink
|
exists(Ssa::Definition origin, Ssa::Definition ssa, ControlFlowNode src, ControlFlowNode sink |
defMaybeNull(origin, src, msg, reason) and
NullnessFlow::flow(src, origin, sink, ssa) and
ssa.getSourceVariable() = v and
Expand Down
8 changes: 4 additions & 4 deletions csharp/ql/lib/semmle/code/csharp/dataflow/SSA.qll
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ module Ssa {
*/
class Definition extends SsaImpl::Definition {
/** Gets the control flow node of this SSA definition. */
final ControlFlow::Node getControlFlowNode() {
final ControlFlowNode getControlFlowNode() {
exists(ControlFlow::BasicBlock bb, int i | this.definesAt(_, bb, i) |
result = bb.getNode(0.maximum(i))
)
Expand Down Expand Up @@ -236,7 +236,7 @@ module Ssa {
* - The reads of `this.Field` on lines 10 and 11 can be reached from the phi
* node between lines 9 and 10.
*/
final AssignableRead getAReadAtNode(ControlFlow::Node cfn) {
final AssignableRead getAReadAtNode(ControlFlowNode cfn) {
result = SsaImpl::getAReadAtNode(this, cfn)
}

Expand Down Expand Up @@ -310,7 +310,7 @@ module Ssa {
* Subsequent reads can be found by following the steps defined by
* `AssignableRead.getANextRead()`.
*/
final AssignableRead getAFirstReadAtNode(ControlFlow::Node cfn) {
final AssignableRead getAFirstReadAtNode(ControlFlowNode cfn) {
SsaImpl::firstReadSameVar(this, cfn) and
result.getAControlFlowNode() = cfn
}
Expand Down Expand Up @@ -373,7 +373,7 @@ module Ssa {
* - The read of `this.Field` on line 11 is a last read of the phi node
* between lines 9 and 10.
*/
deprecated final AssignableRead getALastReadAtNode(ControlFlow::Node cfn) {
deprecated final AssignableRead getALastReadAtNode(ControlFlowNode cfn) {
SsaImpl::lastReadSameVar(this, cfn) and
result.getAControlFlowNode() = cfn
}
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 @@ -11,26 +11,26 @@ private import semmle.code.csharp.dataflow.internal.rangeanalysis.SignAnalysisCo

/** Holds if `e` can be positive and cannot be negative. */
predicate positiveExpr(Expr e) {
forex(ControlFlow::Node cfn | cfn = e.getAControlFlowNode() |
forex(ControlFlowNode cfn | cfn = e.getAControlFlowNode() |
positive(cfn) or strictlyPositive(cfn)
)
}

/** Holds if `e` can be negative and cannot be positive. */
predicate negativeExpr(Expr e) {
forex(ControlFlow::Node cfn | cfn = e.getAControlFlowNode() |
forex(ControlFlowNode cfn | cfn = e.getAControlFlowNode() |
negative(cfn) or strictlyNegative(cfn)
)
}

/** Holds if `e` is strictly positive. */
predicate strictlyPositiveExpr(Expr e) {
forex(ControlFlow::Node cfn | cfn = e.getAControlFlowNode() | strictlyPositive(cfn))
forex(ControlFlowNode cfn | cfn = e.getAControlFlowNode() | strictlyPositive(cfn))
}

/** Holds if `e` is strictly negative. */
predicate strictlyNegativeExpr(Expr e) {
forex(ControlFlow::Node cfn | cfn = e.getAControlFlowNode() | strictlyNegative(cfn))
forex(ControlFlowNode cfn | cfn = e.getAControlFlowNode() | strictlyNegative(cfn))
}

/** Holds if `e` can be positive and cannot be negative. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ class DataFlowCallable extends TDataFlowCallable {

/** Gets a control flow node belonging to this callable. */
pragma[inline]
ControlFlow::Node getAControlFlowNode() {
ControlFlowNode getAControlFlowNode() {
result = this.getAMultiBodyControlFlowNode()
or
not this.isMultiBodied() and
Expand Down
Loading