@@ -108,8 +108,8 @@ module ControlFlow {
108108 /**
109109 * Holds if this node post-dominates `that` node.
110110 *
111- * That is, all paths reaching a callable exit node (`ExitNode`)
112- * from `that` node must go through this node.
111+ * That is, all paths reaching a normal callable exit node (an `AnnotatedExitNode`
112+ * with a normal normal exit type) from `that` node must go through this node.
113113 *
114114 * Example:
115115 *
@@ -145,9 +145,9 @@ module ControlFlow {
145145 /**
146146 * Holds if this node strictly post-dominates `that` node.
147147 *
148- * That is, all paths reaching a callable exit node (`ExitNode`)
149- * from `that` node must go through this node (which must be different
150- * from `that` node).
148+ * That is, all paths reaching a normal callable exit node (an `AnnotatedExitNode`
149+ * with a normal normal exit type) from `that` node must go through this node
150+ * (which must be different from `that` node).
151151 *
152152 * Example:
153153 *
@@ -259,6 +259,38 @@ module ControlFlow {
259259 override string toString ( ) { result = "enter " + getCallable ( ) .toString ( ) }
260260 }
261261
262+ /** A node for a callable exit point, annotated with the type of exit. */
263+ class AnnotatedExitNode extends Node , TAnnotatedExitNode {
264+ private Callable c ;
265+ private boolean normal ;
266+
267+ AnnotatedExitNode ( ) { this = TAnnotatedExitNode ( c , normal ) }
268+
269+ /** Gets the callable that this exit applies to. */
270+ Callable getCallable ( ) { result = c }
271+
272+ /** Holds if this node represent a normal exit. */
273+ predicate isNormal ( ) { normal = true }
274+
275+ override BasicBlocks:: AnnotatedExitBlock getBasicBlock ( ) {
276+ result = Node .super .getBasicBlock ( )
277+ }
278+
279+ override Callable getEnclosingCallable ( ) { result = this .getCallable ( ) }
280+
281+ override Location getLocation ( ) { result = getCallable ( ) .getLocation ( ) }
282+
283+ override string toString ( ) {
284+ exists ( string s |
285+ normal = true and s = "normal"
286+ or
287+ normal = false and s = "abnormal"
288+ |
289+ result = "exit " + getCallable ( ) + " (" + s + ")"
290+ )
291+ }
292+ }
293+
262294 /** A node for a callable exit point. */
263295 class ExitNode extends Node , TExitNode {
264296 /** Gets the callable that this exit applies to. */
@@ -343,6 +375,8 @@ module ControlFlow {
343375 module BasicBlocks {
344376 class EntryBlock = BBs:: EntryBasicBlock ;
345377
378+ class AnnotatedExitBlock = BBs:: AnnotatedExitBasicBlock ;
379+
346380 class ExitBlock = BBs:: ExitBasicBlock ;
347381
348382 class JoinBlock = BBs:: JoinBlock ;
@@ -1953,6 +1987,10 @@ module ControlFlow {
19531987 private module Cached {
19541988 private import semmle.code.csharp.Caching
19551989
1990+ private predicate isAbnormalExitType ( SuccessorType t ) {
1991+ t instanceof ExceptionSuccessor or t instanceof ExitSuccessor
1992+ }
1993+
19561994 /**
19571995 * Internal representation of control flow nodes in the control flow graph.
19581996 * The control flow graph is pruned for unreachable nodes.
@@ -1963,6 +2001,12 @@ module ControlFlow {
19632001 Stages:: ControlFlowStage:: forceCachingInSameStage ( ) and
19642002 succEntrySplits ( c , _, _, _)
19652003 } or
2004+ TAnnotatedExitNode ( Callable c , boolean normal ) {
2005+ exists ( Reachability:: SameSplitsBlock b , SuccessorType t | b .isReachable ( _) |
2006+ succExitSplits ( b .getAnElement ( ) , _, c , t ) and
2007+ if isAbnormalExitType ( t ) then normal = false else normal = true
2008+ )
2009+ } or
19662010 TExitNode ( Callable c ) {
19672011 exists ( Reachability:: SameSplitsBlock b | b .isReachable ( _) |
19682012 succExitSplits ( b .getAnElement ( ) , _, c , _)
@@ -1985,8 +2029,12 @@ module ControlFlow {
19852029 exists ( ControlFlowElement predElement , Splits predSplits |
19862030 pred = TElementNode ( predElement , predSplits )
19872031 |
1988- // Element node -> callable exit
1989- succExitSplits ( predElement , predSplits , result .( Nodes:: ExitNode ) .getCallable ( ) , t )
2032+ // Element node -> callable exit (annotated)
2033+ result =
2034+ any ( Nodes:: AnnotatedExitNode exit |
2035+ succExitSplits ( predElement , predSplits , exit .getCallable ( ) , t ) and
2036+ if isAbnormalExitType ( t ) then not exit .isNormal ( ) else exit .isNormal ( )
2037+ )
19902038 or
19912039 // Element node -> element node
19922040 exists ( ControlFlowElement succElement , Splits succSplits , Completion c |
@@ -1996,6 +2044,10 @@ module ControlFlow {
19962044 t .matchesCompletion ( c )
19972045 )
19982046 )
2047+ or
2048+ // Callable exit (annotated) -> callable exit
2049+ pred .( Nodes:: AnnotatedExitNode ) .getCallable ( ) = result .( Nodes:: ExitNode ) .getCallable ( ) and
2050+ t instanceof SuccessorTypes:: NormalSuccessor
19992051 }
20002052
20012053 /**
0 commit comments