@@ -89,9 +89,11 @@ public void analyseCode(ClassScope classScope, InitializationFlowContext initial
8989public void analyseCode (ClassScope classScope , InitializationFlowContext initializerFlowContext , FlowInfo flowInfo , int initialReachMode , AnalysisMode mode ) {
9090 // Effect of 'AnalysisMode mode':
9191 // ALL: analyse in one go as normal.
92- // PROLOGUE: analyse only statements *before* the explicit constructor call (if any)
93- // REST: analyse only starting with the explicit constructor call, if none present behaves like ALL
92+ // PROLOGUE: analyse only statements up-to the explicit constructor call (arguments of this call are technically prologue, too)
93+ // if no relevant prologue exists, this invocation does nothing, and due to prologueInfo==null the next invocation will use mode ALL
94+ // REST: analyse only statements after the explicit constructor call
9495 // FlowContext and FlowInfo produced during PROLOGUE will be held in fields prologueContext and prologueInfo for use during REST
96+ // prologueInfo is furthermore assumed to happen *before* any field initializers, see its use in TypeDeclaration.internalAnalyseCode()
9597 if (this .ignoreFurtherInvestigation )
9698 return ;
9799
@@ -111,16 +113,6 @@ public void analyseCode(ClassScope classScope, InitializationFlowContext initial
111113 constructorContext = this .prologueContext ;
112114 flowInfo = this .prologueInfo .addInitializationsFrom (flowInfo );
113115 // skip the part already done during PROLOGUE analysis ...
114- if (this .constructorCall != null ) {
115- if (this .constructorCall .accessMode == ExplicitConstructorCall .This ) {
116- FieldBinding [] fields = this .binding .declaringClass .fields ();
117- for (FieldBinding field : fields ) {
118- if (!field .isStatic ()) {
119- flowInfo .markAsDefinitelyAssigned (field );
120- }
121- }
122- }
123- }
124116 } else {
125117 flowInfo .setReachMode (initialReachMode );
126118
@@ -223,20 +215,16 @@ public void analyseCode(ClassScope classScope, InitializationFlowContext initial
223215 // propagate to constructor call
224216 if (this .constructorCall != null ) {
225217 flowInfo = this .constructorCall .analyseCode (this .scope , constructorContext , flowInfo );
226- if (mode == AnalysisMode .PROLOGUE && hasArgumentNeedingAnalysis )
227- this .prologueInfo = flowInfo .copy ();
228- // if calling 'this(...)', then flag all non-static fields as definitely
229- // set since they are supposed to be set inside other local constructor
230- if (this .constructorCall .accessMode == ExplicitConstructorCall .This ) {
231- FieldBinding [] fields = this .binding .declaringClass .fields ();
232- for (FieldBinding field : fields ) {
233- if (!field .isStatic ()) {
234- flowInfo .markAsDefinitelyAssigned (field );
235- }
236- }
218+ if (mode == AnalysisMode .PROLOGUE ) {
219+ if (hasArgumentNeedingAnalysis )
220+ this .prologueInfo = flowInfo .copy ();
221+ return ;
237222 }
238223 }
239224 }
225+ if (this .constructorCall != null && mode != AnalysisMode .PROLOGUE ) {
226+ markFieldsAsInitializedAfterThisCall (this .constructorCall , flowInfo );
227+ }
240228 // reuse the reachMode from non static field info
241229 flowInfo .setReachMode (nonStaticFieldInfoReachMode );
242230
@@ -247,8 +235,10 @@ public void analyseCode(ClassScope classScope, InitializationFlowContext initial
247235 int complaintLevel = (nonStaticFieldInfoReachMode & FlowInfo .UNREACHABLE ) == 0 ? Statement .NOT_COMPLAINED : Statement .COMPLAINED_FAKE_REACHABLE ;
248236 for (Statement stat : this .statements ) {
249237 if (mode == AnalysisMode .REST && lateConstructorCall != null ) {
250- if (stat == lateConstructorCall ) // if true this is where we start analysing
238+ if (stat == lateConstructorCall ) { // if true this is where we start analysing
239+ markFieldsAsInitializedAfterThisCall (lateConstructorCall , flowInfo );
251240 lateConstructorCall = null ; // no more checking for subsequent statements
241+ }
252242 continue ; // skip statements already processed during PROLOGUE analysis
253243 }
254244 if ((complaintLevel = stat .complainIfUnreachable (flowInfo , this .scope , complaintLevel , true )) < Statement .COMPLAINED_UNREACHABLE ) {
@@ -265,9 +255,8 @@ public void analyseCode(ClassScope classScope, InitializationFlowContext initial
265255 }
266256 }
267257 if (mode == AnalysisMode .PROLOGUE ) {
268- if (this .prologueInfo == null ) // don't overwrite info stored in the context of this.constructorCall
269- this .prologueInfo = flowInfo ; // keep for second iteration, also signals the need for REST analysis
270- return ; // we're done for this time
258+ this .prologueInfo = flowInfo ; // keep for second iteration, also signals the need for REST analysis
259+ return ; // we're done for this time
271260 }
272261 }
273262 // check for missing returning path
@@ -305,6 +294,19 @@ public void analyseCode(ClassScope classScope, InitializationFlowContext initial
305294 }
306295}
307296
297+ private void markFieldsAsInitializedAfterThisCall (ExplicitConstructorCall call , FlowInfo flowInfo ) {
298+ if (call .accessMode == ExplicitConstructorCall .This ) {
299+ // if calling 'this(...)', then flag all non-static fields as definitely
300+ // set since they are supposed to be set inside other local constructor
301+ FieldBinding [] fields = this .binding .declaringClass .fields ();
302+ for (FieldBinding field : fields ) {
303+ if (!field .isStatic ()) {
304+ flowInfo .markAsDefinitelyAssigned (field );
305+ }
306+ }
307+ }
308+ }
309+
308310@ Override
309311public AbstractVariableDeclaration [] arguments (boolean includedElided ) {
310312 return includedElided && this .isCompactConstructor () ? this .protoArguments : super .arguments (includedElided );
0 commit comments