@@ -85,7 +85,8 @@ module Ast implements AstSig<CS::Location> {
8585
8686 Callable getEnclosingCallable ( AstNode node ) {
8787 result = node .( CS:: ControlFlowElement ) .getEnclosingCallable ( ) or
88- Initializers:: obinitInitializes ( result , getParent * ( node ) )
88+ result .( CS:: ObjectInitMethod ) .initializes ( getParent * ( node ) ) or
89+ Initializers:: staticMemberInitializer ( result , getParent * ( node ) )
8990 }
9091
9192 class Callable = CS:: Callable ;
@@ -94,7 +95,8 @@ module Ast implements AstSig<CS::Location> {
9495 result = c .getBody ( ) or
9596 result = c .( CS:: Constructor ) .getObjectInitializerCall ( ) or
9697 result = c .( CS:: Constructor ) .getInitializer ( ) or
97- Initializers:: obinitInitializes ( c , result )
98+ c .( CS:: ObjectInitMethod ) .initializes ( result ) or
99+ Initializers:: staticMemberInitializer ( c , result )
98100 }
99101
100102 class Stmt = CS:: Stmt ;
@@ -248,44 +250,64 @@ private CompilationExt getCompilation(CS::File f) {
248250}
249251
250252private module Initializers {
253+ private import semmle.code.csharp.ExprOrStmtParent as ExprOrStmtParent
254+
251255 /**
252- * A non-static member with an initializer, for example a field `int Field = 0`.
256+ * The `expr_parent_top_level_adjusted()` relation restricted to exclude relations
257+ * between properties and their getters' expression bodies in properties such as
258+ * `int P => 0`.
259+ *
260+ * This is in order to only associate the expression body with one CFG scope, namely
261+ * the getter (and not the declaration itself).
253262 */
254- class InitializedInstanceMember extends CS:: Member {
255- private CS:: AssignExpr ae ;
256-
257- InitializedInstanceMember ( ) {
258- not this .isStatic ( ) and
259- expr_parent_top_level ( ae , _, this ) and
260- not ae = any ( CS:: Callable c ) .getExpressionBody ( )
261- }
262-
263- /** Gets the initializer expression. */
264- CS:: AssignExpr getInitializer ( ) { result = ae }
263+ private predicate expr_parent_top_level_adjusted2 (
264+ CS:: Expr child , int i , @top_level_exprorstmt_parent parent
265+ ) {
266+ ExprOrStmtParent:: expr_parent_top_level_adjusted ( child , i , parent ) and
267+ not exists ( CS:: Getter g |
268+ g .getDeclaration ( ) = parent and
269+ i = 0
270+ )
265271 }
266272
267273 /**
268- * Holds if `obinit` is an object initializer method that performs the initialization
269- * of a member via assignment `init`.
274+ * Holds if `init` is a static member initializer and `staticCtor` is the
275+ * static constructor in the same declaring type. Hence, `staticCtor` can be
276+ * considered to execute `init` prior to the execution of its body.
270277 */
271- predicate obinitInitializes ( CS:: ObjectInitMethod obinit , CS:: AssignExpr init ) {
272- exists ( InitializedInstanceMember m |
273- obinit .getDeclaringType ( ) .getAMember ( ) = m and
274- init = m .getInitializer ( )
278+ predicate staticMemberInitializer ( CS:: Constructor staticCtor , CS:: Expr init ) {
279+ exists ( CS:: Assignable a |
280+ a .( CS:: Modifiable ) .isStatic ( ) and
281+ expr_parent_top_level_adjusted2 ( init , _, a ) and
282+ a .getDeclaringType ( ) = staticCtor .getDeclaringType ( ) and
283+ staticCtor .isStatic ( )
275284 )
276285 }
277286
287+ /**
288+ * Gets the `i`th static member initializer expression for static constructor `staticCtor`.
289+ */
290+ CS:: Expr initializedStaticMemberOrder ( CS:: Constructor staticCtor , int i ) {
291+ result =
292+ rank [ i + 1 ] ( CS:: Expr init , CS:: Location l |
293+ staticMemberInitializer ( staticCtor , init ) and
294+ l = init .getLocation ( )
295+ |
296+ init order by l .getStartLine ( ) , l .getStartColumn ( ) , l .getFile ( ) .getAbsolutePath ( )
297+ )
298+ }
299+
278300 /**
279301 * Gets the `i`th member initializer expression for object initializer method `obinit`
280302 * in compilation `comp`.
281303 */
282304 CS:: AssignExpr initializedInstanceMemberOrder (
283305 CS:: ObjectInitMethod obinit , CompilationExt comp , int i
284306 ) {
285- obinitInitializes ( obinit , result ) and
307+ obinit . initializes ( result ) and
286308 result =
287309 rank [ i + 1 ] ( CS:: AssignExpr ae0 , CS:: Location l |
288- obinitInitializes ( obinit , ae0 ) and
310+ obinit . initializes ( ae0 ) and
289311 l = ae0 .getLocation ( ) and
290312 getCompilation ( l .getFile ( ) ) = comp
291313 |
@@ -306,7 +328,6 @@ private module Initializers {
306328}
307329
308330// module Consistency = ControlFlow::Consistency;
309-
310331private module Input implements InputSig1 , InputSig2 {
311332 predicate cfgCachedStageRef ( ) { CfgCachedStage:: ref ( ) }
312333
@@ -407,12 +428,22 @@ private module Input implements InputSig1, InputSig2 {
407428 predicate step ( PreControlFlowNode n1 , PreControlFlowNode n2 ) {
408429 exists ( CS:: Constructor ctor |
409430 n1 .( EntryNodeImpl ) .getEnclosingCallable ( ) = ctor and
410- if exists ( ctor . getObjectInitializerCall ( ) )
411- then n2 .isBefore ( ctor . getObjectInitializerCall ( ) )
431+ if Initializers :: staticMemberInitializer ( ctor , _ )
432+ then n2 .isBefore ( Initializers :: initializedStaticMemberOrder ( ctor , 0 ) )
412433 else
413- if exists ( ctor .getInitializer ( ) )
414- then n2 .isBefore ( ctor .getInitializer ( ) )
415- else n2 .isBefore ( ctor .getBody ( ) )
434+ if exists ( ctor .getObjectInitializerCall ( ) )
435+ then n2 .isBefore ( ctor .getObjectInitializerCall ( ) )
436+ else
437+ if exists ( ctor .getInitializer ( ) )
438+ then n2 .isBefore ( ctor .getInitializer ( ) )
439+ else n2 .isBefore ( ctor .getBody ( ) )
440+ or
441+ exists ( int i | n1 .isAfter ( Initializers:: initializedStaticMemberOrder ( ctor , i ) ) |
442+ n2 .isBefore ( Initializers:: initializedStaticMemberOrder ( ctor , i + 1 ) )
443+ or
444+ not exists ( Initializers:: initializedStaticMemberOrder ( ctor , i + 1 ) ) and
445+ n2 .isBefore ( ctor .getBody ( ) )
446+ )
416447 or
417448 exists ( CompilationExt comp |
418449 n1 .isAfter ( getObjectInitializerCall ( ctor , comp ) ) and
0 commit comments