Skip to content

Commit 404f4a8

Browse files
committed
C#: Include CFG scope in TElementNode
1 parent f2800ab commit 404f4a8

File tree

4 files changed

+58
-52
lines changed

4 files changed

+58
-52
lines changed

csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ module ControlFlow {
241241
predicate isBranch() { strictcount(this.getASuccessor()) > 1 }
242242

243243
/** Gets the enclosing callable of this control flow node. */
244-
Callable getEnclosingCallable() { none() }
244+
final Callable getEnclosingCallable() { result = getNodeCfgScope(this) }
245245
}
246246

247247
/** Provides different types of control flow nodes. */
@@ -253,8 +253,6 @@ module ControlFlow {
253253

254254
override BasicBlocks::EntryBlock getBasicBlock() { result = Node.super.getBasicBlock() }
255255

256-
override Callable getEnclosingCallable() { result = this.getCallable() }
257-
258256
private Assignable getAssignable() { this = TEntryNode(result) }
259257

260258
override Location getLocation() {
@@ -283,8 +281,6 @@ module ControlFlow {
283281
result = Node.super.getBasicBlock()
284282
}
285283

286-
override Callable getEnclosingCallable() { result = this.getCallable() }
287-
288284
override Location getLocation() { result = scope.getLocation() }
289285

290286
override string toString() {
@@ -309,8 +305,6 @@ module ControlFlow {
309305

310306
override BasicBlocks::ExitBlock getBasicBlock() { result = Node.super.getBasicBlock() }
311307

312-
override Callable getEnclosingCallable() { result = this.getCallable() }
313-
314308
override Location getLocation() { result = scope.getLocation() }
315309

316310
override string toString() { result = "exit " + scope }
@@ -327,14 +321,7 @@ module ControlFlow {
327321
private Splits splits;
328322
private ControlFlowElement cfe;
329323

330-
ElementNode() { this = TElementNode(cfe, splits) }
331-
332-
override Callable getEnclosingCallable() {
333-
result = cfe.getEnclosingCallable()
334-
or
335-
result =
336-
this.getASplit().(Splitting::InitializerSplitting::InitializerSplit).getConstructor()
337-
}
324+
ElementNode() { this = TElementNode(_, cfe, splits) }
338325

339326
override ControlFlowElement getElement() { result = cfe }
340327

csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ private predicate succExitSplits(
342342
ControlFlowElement pred, Splits predSplits, CfgScope succ, SuccessorType t
343343
) {
344344
exists(Reachability::SameSplitsBlock b, Completion c | pred = b.getAnElement() |
345-
b.isReachable(predSplits) and
345+
b.isReachable(succ, predSplits) and
346346
t = getAMatchingSuccessorType(c) and
347347
scopeLast(succ, pred, c) and
348348
forall(SplitImpl predSplit | predSplit = predSplits.getASplit() |
@@ -399,7 +399,7 @@ private module SuccSplits {
399399
ControlFlowElement succ, Completion c
400400
) {
401401
pred = b.getAnElement() and
402-
b.isReachable(predSplits) and
402+
b.isReachable(_, predSplits) and
403403
succ(pred, succ, c)
404404
}
405405

@@ -728,12 +728,12 @@ private module Reachability {
728728
* Holds if the elements of this block are reachable from a callable entry
729729
* point, with the splits `splits`.
730730
*/
731-
predicate isReachable(Splits splits) {
731+
predicate isReachable(CfgScope scope, Splits splits) {
732732
// Base case
733-
succEntrySplits(_, this, splits, _)
733+
succEntrySplits(scope, this, splits, _)
734734
or
735735
// Recursive case
736-
exists(SameSplitsBlock pred, Splits predSplits | pred.isReachable(predSplits) |
736+
exists(SameSplitsBlock pred, Splits predSplits | pred.isReachable(scope, predSplits) |
737737
this = pred.getASuccessor(predSplits, splits)
738738
)
739739
}
@@ -791,43 +791,45 @@ private module Cached {
791791
newtype TCfgNode =
792792
TEntryNode(CfgScope scope) { succEntrySplits(scope, _, _, _) } or
793793
TAnnotatedExitNode(CfgScope scope, boolean normal) {
794-
exists(Reachability::SameSplitsBlock b, SuccessorType t | b.isReachable(_) |
794+
exists(Reachability::SameSplitsBlock b, SuccessorType t | b.isReachable(scope, _) |
795795
succExitSplits(b.getAnElement(), _, scope, t) and
796796
if isAbnormalExitType(t) then normal = false else normal = true
797797
)
798798
} or
799799
TExitNode(CfgScope scope) {
800-
exists(Reachability::SameSplitsBlock b | b.isReachable(_) |
800+
exists(Reachability::SameSplitsBlock b | b.isReachable(scope, _) |
801801
succExitSplits(b.getAnElement(), _, scope, _)
802802
)
803803
} or
804-
TElementNode(ControlFlowElement cfe, Splits splits) {
805-
exists(Reachability::SameSplitsBlock b | b.isReachable(splits) | cfe = b.getAnElement())
804+
TElementNode(CfgScope scope, ControlFlowElement cfe, Splits splits) {
805+
exists(Reachability::SameSplitsBlock b | b.isReachable(scope, splits) |
806+
cfe = b.getAnElement()
807+
)
806808
}
807809

808810
/** Gets a successor node of a given flow type, if any. */
809811
cached
810812
TCfgNode getASuccessor(TCfgNode pred, SuccessorType t) {
811813
// Callable entry node -> callable body
812814
exists(ControlFlowElement succElement, Splits succSplits, CfgScope scope |
813-
result = TElementNode(succElement, succSplits) and
815+
result = TElementNode(scope, succElement, succSplits) and
814816
pred = TEntryNode(scope) and
815817
succEntrySplits(scope, succElement, succSplits, t)
816818
)
817819
or
818-
exists(ControlFlowElement predElement, Splits predSplits |
819-
pred = TElementNode(predElement, predSplits)
820+
exists(CfgScope scope, ControlFlowElement predElement, Splits predSplits |
821+
pred = TElementNode(pragma[only_bind_into](scope), predElement, predSplits)
820822
|
821823
// Element node -> callable exit (annotated)
822-
exists(CfgScope scope, boolean normal |
823-
result = TAnnotatedExitNode(scope, normal) and
824+
exists(boolean normal |
825+
result = TAnnotatedExitNode(pragma[only_bind_into](scope), normal) and
824826
succExitSplits(predElement, predSplits, scope, t) and
825827
if isAbnormalExitType(t) then normal = false else normal = true
826828
)
827829
or
828830
// Element node -> element node
829831
exists(ControlFlowElement succElement, Splits succSplits, Completion c |
830-
result = TElementNode(succElement, succSplits)
832+
result = TElementNode(pragma[only_bind_into](scope), succElement, succSplits)
831833
|
832834
succSplits(predElement, predSplits, succElement, succSplits, c) and
833835
t = getAMatchingSuccessorType(c)
@@ -853,6 +855,23 @@ private module Cached {
853855
*/
854856
cached
855857
ControlFlowElement getAControlFlowExitNode(ControlFlowElement cfe) { last(cfe, result, _) }
858+
859+
/**
860+
* Gets the CFG scope of node `n`. Unlike `getCfgScope`, this predicate
861+
* is calculated based on reachability from an entry node, and it may
862+
* yield different results for AST elements that are split into multiple
863+
* scopes.
864+
*/
865+
cached
866+
CfgScope getNodeCfgScope(TCfgNode n) {
867+
n = TEntryNode(result)
868+
or
869+
n = TAnnotatedExitNode(result, _)
870+
or
871+
n = TExitNode(result)
872+
or
873+
n = TElementNode(result, _, _)
874+
}
856875
}
857876

858877
import Cached

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ module InitializerSplitting {
179179
*
180180
* respectively.
181181
*/
182-
class InitializerSplit extends Split, TInitializerSplit {
182+
private class InitializerSplit extends Split, TInitializerSplit {
183183
private Constructor c;
184184

185185
InitializerSplit() { this = TInitializerSplit(c) }

csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8092,24 +8092,24 @@ Initializers.cs:
80928092
# 5| ... = ...
80938093
#-----| -> this access
80948094

8095-
# 5| ... = ...
8096-
#-----| -> this access
8097-
80988095
# 5| this access
80998096
#-----| -> access to field H
81008097

8098+
# 5| ... = ...
8099+
#-----| -> this access
8100+
81018101
# 5| this access
81028102
#-----| -> access to field H
81038103

81048104
# 5| ... + ...
81058105
#-----| -> ... = ...
81068106

8107-
# 5| ... + ...
8108-
#-----| -> ... = ...
8109-
81108107
# 5| access to field H
81118108
#-----| -> 1
81128109

8110+
# 5| ... + ...
8111+
#-----| -> ... = ...
8112+
81138113
# 5| access to field H
81148114
#-----| -> 1
81158115

@@ -8122,12 +8122,12 @@ Initializers.cs:
81228122
# 6| access to property G
81238123
#-----| -> ... = ...
81248124

8125-
# 6| access to property G
8126-
#-----| -> ... = ...
8127-
81288125
# 6| this access
81298126
#-----| -> access to field H
81308127

8128+
# 6| access to property G
8129+
#-----| -> ... = ...
8130+
81318131
# 6| this access
81328132
#-----| -> access to field H
81338133

@@ -8140,12 +8140,12 @@ Initializers.cs:
81408140
# 6| ... + ...
81418141
#-----| -> access to property G
81428142

8143-
# 6| ... + ...
8144-
#-----| -> access to property G
8145-
81468143
# 6| access to field H
81478144
#-----| -> 2
81488145

8146+
# 6| ... + ...
8147+
#-----| -> access to property G
8148+
81498149
# 6| access to field H
81508150
#-----| -> 2
81518151

@@ -8291,12 +8291,12 @@ Initializers.cs:
82918291
# 28| ... = ...
82928292
#-----| -> {...}
82938293

8294-
# 28| ... = ...
8295-
#-----| -> {...}
8296-
82978294
# 28| this access
82988295
#-----| -> 2
82998296

8297+
# 28| ... = ...
8298+
#-----| -> {...}
8299+
83008300
# 28| this access
83018301
#-----| -> 2
83028302

@@ -10299,12 +10299,12 @@ PartialImplementationB.cs:
1029910299
# 3| ... = ...
1030010300
#-----| -> this access
1030110301

10302-
# 3| ... = ...
10303-
#-----| -> this access
10304-
1030510302
# 3| this access
1030610303
#-----| -> 0
1030710304

10305+
# 3| ... = ...
10306+
#-----| -> this access
10307+
1030810308
# 3| this access
1030910309
#-----| -> 0
1031010310

@@ -10331,12 +10331,12 @@ PartialImplementationB.cs:
1033110331
# 5| access to property P
1033210332
#-----| -> ... = ...
1033310333

10334-
# 5| access to property P
10335-
#-----| -> ... = ...
10336-
1033710334
# 5| this access
1033810335
#-----| -> 0
1033910336

10337+
# 5| access to property P
10338+
#-----| -> ... = ...
10339+
1034010340
# 5| this access
1034110341
#-----| -> 0
1034210342

0 commit comments

Comments
 (0)