@@ -90,6 +90,7 @@ public void analyseCode(ClassScope classScope, InitializationFlowContext initial
9090 // Effect of 'AnalysisMode mode':
9191 // ALL: analyse in one go as normal.
9292 // 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
9394 // 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
9596 // prologueInfo is furthermore assumed to happen *before* any field initializers, see its use in TypeDeclaration.internalAnalyseCode()
@@ -214,20 +215,16 @@ public void analyseCode(ClassScope classScope, InitializationFlowContext initial
214215 // propagate to constructor call
215216 if (this .constructorCall != null ) {
216217 flowInfo = this .constructorCall .analyseCode (this .scope , constructorContext , flowInfo );
217- if (mode == AnalysisMode .PROLOGUE && hasArgumentNeedingAnalysis )
218- this .prologueInfo = flowInfo .copy ();
219- }
220- }
221- if (this .constructorCall != null && this .constructorCall .accessMode == ExplicitConstructorCall .This ) {
222- // if calling 'this(...)', then flag all non-static fields as definitely
223- // set since they are supposed to be set inside other local constructor
224- FieldBinding [] fields = this .binding .declaringClass .fields ();
225- for (FieldBinding field : fields ) {
226- if (!field .isStatic ()) {
227- flowInfo .markAsDefinitelyAssigned (field );
218+ if (mode == AnalysisMode .PROLOGUE ) {
219+ if (hasArgumentNeedingAnalysis )
220+ this .prologueInfo = flowInfo .copy ();
221+ return ;
228222 }
229223 }
230224 }
225+ if (this .constructorCall != null && mode != AnalysisMode .PROLOGUE ) {
226+ markFieldsAsInitializedAfterThisCall (this .constructorCall , flowInfo );
227+ }
231228 // reuse the reachMode from non static field info
232229 flowInfo .setReachMode (nonStaticFieldInfoReachMode );
233230
@@ -238,8 +235,10 @@ public void analyseCode(ClassScope classScope, InitializationFlowContext initial
238235 int complaintLevel = (nonStaticFieldInfoReachMode & FlowInfo .UNREACHABLE ) == 0 ? Statement .NOT_COMPLAINED : Statement .COMPLAINED_FAKE_REACHABLE ;
239236 for (Statement stat : this .statements ) {
240237 if (mode == AnalysisMode .REST && lateConstructorCall != null ) {
241- 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 );
242240 lateConstructorCall = null ; // no more checking for subsequent statements
241+ }
243242 continue ; // skip statements already processed during PROLOGUE analysis
244243 }
245244 if ((complaintLevel = stat .complainIfUnreachable (flowInfo , this .scope , complaintLevel , true )) < Statement .COMPLAINED_UNREACHABLE ) {
@@ -256,9 +255,8 @@ public void analyseCode(ClassScope classScope, InitializationFlowContext initial
256255 }
257256 }
258257 if (mode == AnalysisMode .PROLOGUE ) {
259- if (this .prologueInfo == null ) // don't overwrite info stored in the context of this.constructorCall
260- this .prologueInfo = flowInfo ; // keep for second iteration, also signals the need for REST analysis
261- 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
262260 }
263261 }
264262 // check for missing returning path
@@ -296,6 +294,19 @@ public void analyseCode(ClassScope classScope, InitializationFlowContext initial
296294 }
297295}
298296
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+
299310@ Override
300311public AbstractVariableDeclaration [] arguments (boolean includedElided ) {
301312 return includedElided && this .isCompactConstructor () ? this .protoArguments : super .arguments (includedElided );
0 commit comments