4343 */
4444
4545import csharp
46- private import semmle.code.csharp.controlflow.ControlFlowGraph:: ControlFlow
4746private import Completion
48- private import SuccessorType
49- private import SuccessorTypes
5047private import Splitting
5148private import semmle.code.csharp.ExprOrStmtParent
5249private import semmle.code.csharp.commons.Compilation
50+ import ControlFlowGraphImplShared
51+
52+ /** An element that defines a new CFG scope. */
53+ class CfgScope extends Element , @top_level_exprorstmt_parent {
54+ CfgScope ( ) {
55+ this instanceof Callable
56+ or
57+ // For now, static initializer values have their own scope. Eventually, they
58+ // should be treated like instance initializers.
59+ this .( Assignable ) .( Modifiable ) .isStatic ( )
60+ }
61+ }
5362
5463/**
5564 * A compilation.
@@ -71,16 +80,11 @@ CompilationExt getCompilation(SourceFile f) {
7180 result = TBuildless ( )
7281}
7382
74- /** An element that defines a new CFG scope. */
75- class CfgScope extends Element , @top_level_exprorstmt_parent {
76- CfgScope ( ) { not this instanceof Attribute }
77- }
78-
7983module ControlFlowTree {
8084 class Range_ = @callable or @control_flow_element;
8185
8286 class Range extends Element , Range_ {
83- Range ( ) { this = getAChild * ( any ( CfgScope scope ) ) }
87+ Range ( ) { this = getAChild * ( any ( @top_level_exprorstmt_parent p | not p instanceof Attribute ) ) }
8488 }
8589
8690 Element getAChild ( Element p ) {
@@ -93,61 +97,6 @@ module ControlFlowTree {
9397 predicate idOf ( Range_ x , int y ) = equivalenceRelation( id / 2 ) ( x , y )
9498}
9599
96- abstract private class ControlFlowTree extends ControlFlowTree:: Range {
97- /**
98- * Holds if `first` is the first element executed within this control
99- * flow element.
100- */
101- pragma [ nomagic]
102- abstract predicate first ( ControlFlowElement first ) ;
103-
104- /**
105- * Holds if `last` with completion `c` is a potential last element executed
106- * within this control flow element.
107- */
108- pragma [ nomagic]
109- abstract predicate last ( ControlFlowElement last , Completion c ) ;
110-
111- /** Holds if abnormal execution of `child` should propagate upwards. */
112- abstract predicate propagatesAbnormal ( ControlFlowElement child ) ;
113-
114- /**
115- * Holds if `succ` is a control flow successor for `pred`, given that `pred`
116- * finishes with completion `c`.
117- */
118- pragma [ nomagic]
119- abstract predicate succ ( ControlFlowElement pred , ControlFlowElement succ , Completion c ) ;
120- }
121-
122- /**
123- * Holds if `first` is the first element executed within control flow
124- * element `cft`.
125- */
126- predicate first ( ControlFlowTree cft , ControlFlowElement first ) { cft .first ( first ) }
127-
128- /**
129- * Holds if `last` with completion `c` is a potential last element executed
130- * within control flow element `cft`.
131- */
132- predicate last ( ControlFlowTree cft , ControlFlowElement last , Completion c ) {
133- cft .last ( last , c )
134- or
135- exists ( ControlFlowElement cfe |
136- cft .propagatesAbnormal ( cfe ) and
137- last ( cfe , last , c ) and
138- not c instanceof NormalCompletion
139- )
140- }
141-
142- /**
143- * Holds if `succ` is a control flow successor for `pred`, given that `pred`
144- * finishes with completion `c`.
145- */
146- pragma [ nomagic]
147- predicate succ ( ControlFlowElement pred , ControlFlowElement succ , Completion c ) {
148- any ( ControlFlowTree cft ) .succ ( pred , succ , c )
149- }
150-
151100/** Holds if `first` is first executed when entering `scope`. */
152101predicate scopeFirst ( CfgScope scope , ControlFlowElement first ) {
153102 scope =
@@ -161,8 +110,7 @@ predicate scopeFirst(CfgScope scope, ControlFlowElement first) {
161110 )
162111 or
163112 expr_parent_top_level_adjusted ( any ( Expr e | first ( e , first ) ) , _, scope ) and
164- not scope instanceof Callable and
165- not scope instanceof InitializerSplitting:: InitializedInstanceMember
113+ not scope instanceof Callable
166114}
167115
168116/** Holds if `scope` is exited when `last` finishes with completion `c`. */
@@ -204,53 +152,6 @@ private class ConstructorTree extends ControlFlowTree, Constructor {
204152 }
205153}
206154
207- /**
208- * A control flow element where the children are evaluated following a
209- * standard left-to-right evaluation. The actual evaluation order is
210- * determined by the predicate `getChildElement()`.
211- */
212- abstract private class StandardElement extends ControlFlowTree {
213- /** Gets the `i`th child element, in order of evaluation, starting from 0. */
214- abstract ControlFlowElement getChildElement ( int i ) ;
215-
216- /** Gets the first child element of this element. */
217- final ControlFlowElement getFirstChild ( ) { result = this .getChildElement ( 0 ) }
218-
219- /** Holds if this element has no children. */
220- final predicate isLeafElement ( ) { not exists ( this .getFirstChild ( ) ) }
221-
222- /** Gets the last child element of this element. */
223- final ControlFlowTree getLastChild ( ) {
224- exists ( int last |
225- result = this .getChildElement ( last ) and
226- not exists ( this .getChildElement ( last + 1 ) )
227- )
228- }
229-
230- final override predicate propagatesAbnormal ( ControlFlowElement child ) {
231- child = this .getChildElement ( _)
232- }
233-
234- override predicate succ ( ControlFlowElement pred , ControlFlowElement succ , Completion c ) {
235- exists ( int i |
236- last ( this .getChildElement ( i ) , pred , c ) and
237- first ( this .getChildElement ( i + 1 ) , succ ) and
238- c instanceof NormalCompletion
239- )
240- }
241- }
242-
243- abstract private class PreOrderTree extends ControlFlowTree {
244- final override predicate first ( ControlFlowElement first ) { first = this }
245- }
246-
247- abstract private class PostOrderTree extends ControlFlowTree {
248- override predicate last ( ControlFlowElement last , Completion c ) {
249- last = this and
250- c .isValidFor ( last )
251- }
252- }
253-
254155abstract private class SwitchTree extends ControlFlowTree , Switch {
255156 override predicate propagatesAbnormal ( ControlFlowElement child ) { child = this .getExpr ( ) }
256157
@@ -368,7 +269,7 @@ module Expressions {
368269 )
369270 }
370271
371- private class StandardExpr extends StandardElement , PostOrderTree , Expr {
272+ private class StandardExpr extends StandardPostOrderTree , Expr {
372273 StandardExpr ( ) {
373274 // The following expressions need special treatment
374275 not this instanceof LogicalNotExpr and
@@ -396,21 +297,6 @@ module Expressions {
396297 }
397298
398299 final override ControlFlowElement getChildElement ( int i ) { result = getExprChild ( this , i ) }
399-
400- final override predicate first ( ControlFlowElement first ) {
401- first ( this .getFirstChild ( ) , first )
402- or
403- not exists ( this .getFirstChild ( ) ) and
404- first = this
405- }
406-
407- final override predicate succ ( ControlFlowElement pred , ControlFlowElement succ , Completion c ) {
408- StandardElement .super .succ ( pred , succ , c )
409- or
410- last ( this .getLastChild ( ) , pred , c ) and
411- succ = this and
412- c instanceof NormalCompletion
413- }
414300 }
415301
416302 /**
@@ -1095,7 +981,7 @@ private class PropertyPatternExprExprTree extends PostOrderTree, PropertyPattern
1095981}
1096982
1097983module Statements {
1098- private class StandardStmt extends StandardElement , PreOrderTree , Stmt {
984+ private class StandardStmt extends StandardPreOrderTree , Stmt {
1099985 StandardStmt ( ) {
1100986 // The following statements need special treatment
1101987 not this instanceof IfStmt and
@@ -1140,22 +1026,6 @@ module Statements {
11401026 result =
11411027 rank [ i + 1 ] ( ControlFlowElement cfe , int j | cfe = this .getChildElement0 ( j ) | cfe order by j )
11421028 }
1143-
1144- final override predicate last ( ControlFlowElement last , Completion c ) {
1145- last ( this .getLastChild ( ) , last , c )
1146- or
1147- this .isLeafElement ( ) and
1148- last = this and
1149- c .isValidFor ( this )
1150- }
1151-
1152- final override predicate succ ( ControlFlowElement pred , ControlFlowElement succ , Completion c ) {
1153- StandardElement .super .succ ( pred , succ , c )
1154- or
1155- pred = this and
1156- first ( this .getFirstChild ( ) , succ ) and
1157- c instanceof SimpleCompletion
1158- }
11591029 }
11601030
11611031 private class IfStmtTree extends PreOrderTree , IfStmt {
@@ -1779,88 +1649,6 @@ module Statements {
17791649 }
17801650}
17811651
1782- cached
1783- private module Cached {
1784- private import semmle.code.csharp.Caching
1785-
1786- private predicate isAbnormalExitType ( SuccessorType t ) {
1787- t instanceof ExceptionSuccessor or t instanceof ExitSuccessor
1788- }
1789-
1790- /**
1791- * Internal representation of control flow nodes in the control flow graph.
1792- * The control flow graph is pruned for unreachable nodes.
1793- */
1794- cached
1795- newtype TNode =
1796- TEntryNode ( Callable c ) {
1797- Stages:: ControlFlowStage:: forceCachingInSameStage ( ) and
1798- succEntrySplits ( c , _, _, _)
1799- } or
1800- TAnnotatedExitNode ( Callable c , boolean normal ) {
1801- exists ( Reachability:: SameSplitsBlock b , SuccessorType t | b .isReachable ( _) |
1802- succExitSplits ( b .getAnElement ( ) , _, c , t ) and
1803- if isAbnormalExitType ( t ) then normal = false else normal = true
1804- )
1805- } or
1806- TExitNode ( Callable c ) {
1807- exists ( Reachability:: SameSplitsBlock b | b .isReachable ( _) |
1808- succExitSplits ( b .getAnElement ( ) , _, c , _)
1809- )
1810- } or
1811- TElementNode ( ControlFlowElement cfe , Splits splits ) {
1812- exists ( Reachability:: SameSplitsBlock b | b .isReachable ( splits ) | cfe = b .getAnElement ( ) )
1813- }
1814-
1815- /** Gets a successor node of a given flow type, if any. */
1816- cached
1817- Node getASuccessorByType ( Node pred , SuccessorType t ) {
1818- // Callable entry node -> callable body
1819- exists ( ControlFlowElement succElement , Splits succSplits |
1820- result = TElementNode ( succElement , succSplits )
1821- |
1822- succEntrySplits ( pred .( Nodes:: EntryNode ) .getCallable ( ) , succElement , succSplits , t )
1823- )
1824- or
1825- exists ( ControlFlowElement predElement , Splits predSplits |
1826- pred = TElementNode ( predElement , predSplits )
1827- |
1828- // Element node -> callable exit (annotated)
1829- result =
1830- any ( Nodes:: AnnotatedExitNode exit |
1831- succExitSplits ( predElement , predSplits , exit .getCallable ( ) , t ) and
1832- if isAbnormalExitType ( t ) then not exit .isNormal ( ) else exit .isNormal ( )
1833- )
1834- or
1835- // Element node -> element node
1836- exists ( ControlFlowElement succElement , Splits succSplits , Completion c |
1837- result = TElementNode ( succElement , succSplits )
1838- |
1839- succSplits ( predElement , predSplits , succElement , succSplits , c ) and
1840- t = c .getAMatchingSuccessorType ( )
1841- )
1842- )
1843- or
1844- // Callable exit (annotated) -> callable exit
1845- pred .( Nodes:: AnnotatedExitNode ) .getCallable ( ) = result .( Nodes:: ExitNode ) .getCallable ( ) and
1846- t instanceof SuccessorTypes:: NormalSuccessor
1847- }
1848-
1849- /**
1850- * Gets a first control flow element executed within `cfe`.
1851- */
1852- cached
1853- ControlFlowElement getAControlFlowEntryNode ( ControlFlowElement cfe ) { first ( cfe , result ) }
1854-
1855- /**
1856- * Gets a potential last control flow element executed within `cfe`.
1857- */
1858- cached
1859- ControlFlowElement getAControlFlowExitNode ( ControlFlowElement cfe ) { last ( cfe , result , _) }
1860- }
1861-
1862- import Cached
1863-
18641652/** A control flow element that is split into multiple control flow nodes. */
18651653class SplitControlFlowElement extends ControlFlowElement {
18661654 SplitControlFlowElement ( ) { strictcount ( this .getAControlFlowNode ( ) ) > 1 }
0 commit comments