308f8523c66497574498a20c7b65bb6e74850383
[phpeclipse.git] /
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpeclipse.internal.compiler.ast;
12
13 import net.sourceforge.phpdt.core.compiler.CharOperation;
14 import net.sourceforge.phpdt.internal.compiler.CompilationResult;
15 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
16 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
17 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
18 import net.sourceforge.phpdt.internal.compiler.flow.InitializationFlowContext;
19 import net.sourceforge.phpdt.internal.compiler.flow.UnconditionalFlowInfo;
20 import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
21 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
22 import net.sourceforge.phpdt.internal.compiler.lookup.ClassScope;
23 import net.sourceforge.phpdt.internal.compiler.lookup.CompilationUnitScope;
24 import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding;
25 import net.sourceforge.phpdt.internal.compiler.lookup.LocalTypeBinding;
26 import net.sourceforge.phpdt.internal.compiler.lookup.MemberTypeBinding;
27 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
28 import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope;
29 import net.sourceforge.phpdt.internal.compiler.lookup.NestedTypeBinding;
30 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
31 import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding;
32 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
33 import net.sourceforge.phpdt.internal.compiler.parser.Parser;
34 import net.sourceforge.phpdt.internal.compiler.parser.UnitParser;
35 import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilation;
36 import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilationUnit;
37 import net.sourceforge.phpdt.internal.compiler.problem.AbortMethod;
38 import net.sourceforge.phpdt.internal.compiler.problem.AbortType;
39 import net.sourceforge.phpdt.internal.compiler.problem.ProblemSeverities;
40
41 public class TypeDeclaration
42         extends Statement
43         implements ProblemSeverities, ReferenceContext {
44
45         public int modifiers;
46         public int modifiersSourceStart;
47         public char[] name;
48         public TypeReference superclass;
49         public TypeReference[] superInterfaces;
50         public FieldDeclaration[] fields;
51         public AbstractMethodDeclaration[] methods;
52         public MemberTypeDeclaration[] memberTypes;
53         public SourceTypeBinding binding;
54         public ClassScope scope;
55         public MethodScope initializerScope;
56         public MethodScope staticInitializerScope;
57         public boolean ignoreFurtherInvestigation = false;
58         public int maxFieldCount;
59         public int declarationSourceStart;
60         public int declarationSourceEnd;
61         public int bodyStart;
62         public int bodyEnd; // doesn't include the trailing comment if any.
63         protected boolean hasBeenGenerated = false;
64         public CompilationResult compilationResult;
65         private MethodDeclaration[] missingAbstractMethods;
66
67         public TypeDeclaration(CompilationResult compilationResult){
68                 this.compilationResult = compilationResult;
69         }
70                 
71         /*
72          *      We cause the compilation task to abort to a given extent.
73          */
74         public void abort(int abortLevel) {
75
76                 if (scope == null) {
77                         throw new AbortCompilation(); // cannot do better
78                 }
79
80                 CompilationResult compilationResult =
81                         scope.referenceCompilationUnit().compilationResult;
82
83                 switch (abortLevel) {
84                         case AbortCompilation :
85                                 throw new AbortCompilation(compilationResult);
86                         case AbortCompilationUnit :
87                                 throw new AbortCompilationUnit(compilationResult);
88                         case AbortMethod :
89                                 throw new AbortMethod(compilationResult);
90                         default :
91                                 throw new AbortType(compilationResult);
92                 }
93         }
94         /**
95          * This method is responsible for adding a <clinit> method declaration to the type method collections.
96          * Note that this implementation is inserting it in first place (as VAJ or javac), and that this
97          * impacts the behavior of the method ConstantPool.resetForClinit(int. int), in so far as 
98          * the latter will have to reset the constant pool state accordingly (if it was added first, it does 
99          * not need to preserve some of the method specific cached entries since this will be the first method).
100          * inserts the clinit method declaration in the first position.
101          * 
102          * @see org.eclipse.jdt.internal.compiler.codegen.ConstantPool#resetForClinit(int, int)
103          */
104         public final void addClinit() {
105
106                 //see comment on needClassInitMethod
107                 if (needClassInitMethod()) {
108                         int length;
109                         AbstractMethodDeclaration[] methods;
110                         if ((methods = this.methods) == null) {
111                                 length = 0;
112                                 methods = new AbstractMethodDeclaration[1];
113                         } else {
114                                 length = methods.length;
115                                 System.arraycopy(
116                                         methods,
117                                         0,
118                                         (methods = new AbstractMethodDeclaration[length + 1]),
119                                         1,
120                                         length);
121                         }
122                         Clinit clinit = new Clinit(this.compilationResult);
123                         methods[0] = clinit;
124                         // clinit is added in first location, so as to minimize the use of ldcw (big consumer of constant inits)
125                         clinit.declarationSourceStart = clinit.sourceStart = sourceStart;
126                         clinit.declarationSourceEnd = clinit.sourceEnd = sourceEnd;
127                         clinit.bodyEnd = sourceEnd;
128                         this.methods = methods;
129                 }
130         }
131
132         /**
133          *      Flow analysis for a local innertype
134          *
135          */
136         public FlowInfo analyseCode(
137                 BlockScope currentScope,
138                 FlowContext flowContext,
139                 FlowInfo flowInfo) {
140
141                 if (ignoreFurtherInvestigation)
142                         return flowInfo;
143                 try {
144                         bits |= IsReachableMASK;
145                         LocalTypeBinding localType = (LocalTypeBinding) binding;
146                         
147                         localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType));
148                         manageEnclosingInstanceAccessIfNecessary(currentScope);
149                         
150                         updateMaxFieldCount(); // propagate down the max field count
151                         internalAnalyseCode(flowContext, flowInfo); 
152                 } catch (AbortType e) {
153                         this.ignoreFurtherInvestigation = true;
154                 }
155                 return flowInfo;
156         }
157
158         /**
159          *      Flow analysis for a member innertype
160          *
161          */
162         public void analyseCode(ClassScope enclosingClassScope) {
163
164                 if (ignoreFurtherInvestigation)
165                         return;
166                 try {
167                         // propagate down the max field count
168                         updateMaxFieldCount();
169                         internalAnalyseCode(null, FlowInfo.initial(maxFieldCount));
170                 } catch (AbortType e) {
171                         this.ignoreFurtherInvestigation = true;
172                 }
173         }
174
175         /**
176          *      Flow analysis for a local member innertype
177          *
178          */
179         public void analyseCode(
180                 ClassScope currentScope,
181                 FlowContext flowContext,
182                 FlowInfo flowInfo) {
183
184                 if (ignoreFurtherInvestigation)
185                         return;
186                 try {
187                         bits |= IsReachableMASK;
188                         LocalTypeBinding localType = (LocalTypeBinding) binding;
189
190                         localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType));
191                         manageEnclosingInstanceAccessIfNecessary(currentScope);
192                         
193                         updateMaxFieldCount(); // propagate down the max field count
194                         internalAnalyseCode(flowContext, flowInfo);
195                 } catch (AbortType e) {
196                         this.ignoreFurtherInvestigation = true;
197                 }
198         }
199
200         /**
201          *      Flow analysis for a package member type
202          *
203          */
204         public void analyseCode(CompilationUnitScope unitScope) {
205
206                 if (ignoreFurtherInvestigation)
207                         return;
208                 try {
209                         internalAnalyseCode(null, FlowInfo.initial(maxFieldCount));
210                 } catch (AbortType e) {
211                         this.ignoreFurtherInvestigation = true;
212                 }
213         }
214
215         /*
216          * Check for constructor vs. method with no return type.
217          * Answers true if at least one constructor is defined
218          */
219         public boolean checkConstructors(Parser parser) {
220
221                 //if a constructor has not the name of the type,
222                 //convert it into a method with 'null' as its return type
223                 boolean hasConstructor = false;
224                 if (methods != null) {
225                         for (int i = methods.length; --i >= 0;) {
226                                 AbstractMethodDeclaration am;
227                                 if ((am = methods[i]).isConstructor()) {
228                                         if (!CharOperation.equals(am.selector, name)) {
229                                                 // the constructor was in fact a method with no return type
230                                                 // unless an explicit constructor call was supplied
231                                                 ConstructorDeclaration c = (ConstructorDeclaration) am;
232                                                 if ((c.constructorCall == null)
233                                                         || (c.constructorCall.isImplicitSuper())) { //changed to a method
234                                                         MethodDeclaration m = new MethodDeclaration(this.compilationResult);
235                                                         m.sourceStart = c.sourceStart;
236                                                         m.sourceEnd = c.sourceEnd;
237                                                         m.bodyStart = c.bodyStart;
238                                                         m.bodyEnd = c.bodyEnd;
239                                                         m.declarationSourceEnd = c.declarationSourceEnd;
240                                                         m.declarationSourceStart = c.declarationSourceStart;
241                                                         m.selector = c.selector;
242                                                         m.statements = c.statements;
243                                                         m.modifiers = c.modifiers;
244                                                         m.arguments = c.arguments;
245                                                         m.thrownExceptions = c.thrownExceptions;
246                                                         m.explicitDeclarations = c.explicitDeclarations;
247                                                         m.returnType = null;
248                                                         methods[i] = m;
249                                                 }
250                                         } else {
251                                                 if (this.isInterface()) {
252                                                         // report the problem and continue the parsing
253                                                         parser.problemReporter().interfaceCannotHaveConstructors(
254                                                                 (ConstructorDeclaration) am);
255                                                 }
256                                                 hasConstructor = true;
257                                         }
258                                 }
259                         }
260                 }
261                 return hasConstructor;
262         }
263
264         public CompilationResult compilationResult() {
265
266                 return this.compilationResult;
267         }
268
269         public ConstructorDeclaration createsInternalConstructor(
270                 boolean needExplicitConstructorCall,
271                 boolean needToInsert) {
272
273                 //Add to method'set, the default constuctor that just recall the
274                 //super constructor with no arguments
275                 //The arguments' type will be positionned by the TC so just use
276                 //the default int instead of just null (consistency purpose)
277
278                 //the constructor
279                 ConstructorDeclaration constructor = new ConstructorDeclaration(this.compilationResult);
280                 constructor.isDefaultConstructor = true;
281                 constructor.selector = name;
282                 if (modifiers != AccDefault) {
283                         constructor.modifiers =
284                                 ((this instanceof MemberTypeDeclaration) && (modifiers & AccPrivate) != 0)
285                                         ? AccDefault
286                                         : modifiers & AccVisibilityMASK;
287                 }
288
289                 //if you change this setting, please update the 
290                 //SourceIndexer2.buildTypeDeclaration(TypeDeclaration,char[]) method
291                 constructor.declarationSourceStart = constructor.sourceStart = sourceStart;
292                 constructor.declarationSourceEnd =
293                         constructor.sourceEnd = constructor.bodyEnd = sourceEnd;
294
295                 //the super call inside the constructor
296                 if (needExplicitConstructorCall) {
297                         constructor.constructorCall = SuperReference.implicitSuperConstructorCall();
298                         constructor.constructorCall.sourceStart = sourceStart;
299                         constructor.constructorCall.sourceEnd = sourceEnd;
300                 }
301
302                 //adding the constructor in the methods list
303                 if (needToInsert) {
304                         if (methods == null) {
305                                 methods = new AbstractMethodDeclaration[] { constructor };
306                         } else {
307                                 AbstractMethodDeclaration[] newMethods;
308                                 System.arraycopy(
309                                         methods,
310                                         0,
311                                         newMethods = new AbstractMethodDeclaration[methods.length + 1],
312                                         1,
313                                         methods.length);
314                                 newMethods[0] = constructor;
315                                 methods = newMethods;
316                         }
317                 }
318                 return constructor;
319         }
320
321         /**
322          * INTERNAL USE ONLY - Creates a fake method declaration for the corresponding binding.
323          * It is used to report errors for missing abstract methods.
324          */
325         public MethodDeclaration addMissingAbstractMethodFor(MethodBinding methodBinding) {
326                 TypeBinding[] argumentTypes = methodBinding.parameters;
327                 int argumentsLength = argumentTypes.length;
328                 //the constructor
329                 MethodDeclaration methodDeclaration = new MethodDeclaration(this.compilationResult);
330                 methodDeclaration.selector = methodBinding.selector;
331                 methodDeclaration.sourceStart = sourceStart;
332                 methodDeclaration.sourceEnd = sourceEnd;
333                 methodDeclaration.modifiers = methodBinding.getAccessFlags() & ~AccAbstract;
334
335                 if (argumentsLength > 0) {
336                         String baseName = "arg";//$NON-NLS-1$
337                         Argument[] arguments = (methodDeclaration.arguments = new Argument[argumentsLength]);
338                         for (int i = argumentsLength; --i >= 0;) {
339                                 arguments[i] = new Argument((baseName + i).toCharArray(), 0L, null /*type ref*/, AccDefault);
340                         }
341                 }
342
343                 //adding the constructor in the methods list
344                 if (this.missingAbstractMethods == null) {
345                         this.missingAbstractMethods = new MethodDeclaration[] { methodDeclaration };
346                 } else {
347                         MethodDeclaration[] newMethods;
348                         System.arraycopy(
349                                 this.missingAbstractMethods,
350                                 0,
351                                 newMethods = new MethodDeclaration[this.missingAbstractMethods.length + 1],
352                                 1,
353                                 this.missingAbstractMethods.length);
354                         newMethods[0] = methodDeclaration;
355                         this.missingAbstractMethods = newMethods;
356                 }
357
358                 //============BINDING UPDATE==========================
359                 methodDeclaration.binding = new MethodBinding(
360                                 methodDeclaration.modifiers, //methodDeclaration
361                                 methodBinding.selector,
362                                 methodBinding.returnType,
363                                 argumentsLength == 0 ? NoParameters : argumentTypes, //arguments bindings
364                                 methodBinding.thrownExceptions, //exceptions
365                                 binding); //declaringClass
366                                 
367                 methodDeclaration.scope = new MethodScope(scope, methodDeclaration, true);
368                 methodDeclaration.bindArguments();
369
370 /*              if (binding.methods == null) {
371                         binding.methods = new MethodBinding[] { methodDeclaration.binding };
372                 } else {
373                         MethodBinding[] newMethods;
374                         System.arraycopy(
375                                 binding.methods,
376                                 0,
377                                 newMethods = new MethodBinding[binding.methods.length + 1],
378                                 1,
379                                 binding.methods.length);
380                         newMethods[0] = methodDeclaration.binding;
381                         binding.methods = newMethods;
382                 }*/
383                 //===================================================
384
385                 return methodDeclaration;
386         }
387         
388         /*
389          * Find the matching parse node, answers null if nothing found
390          */
391         public FieldDeclaration declarationOf(FieldBinding fieldBinding) {
392
393                 if (fieldBinding != null) {
394                         for (int i = 0, max = this.fields.length; i < max; i++) {
395                                 FieldDeclaration fieldDecl;
396                                 if ((fieldDecl = this.fields[i]).binding == fieldBinding)
397                                         return fieldDecl;
398                         }
399                 }
400                 return null;
401         }
402
403         /*
404          * Find the matching parse node, answers null if nothing found
405          */
406         public TypeDeclaration declarationOf(MemberTypeBinding memberTypeBinding) {
407
408                 if (memberTypeBinding != null) {
409                         for (int i = 0, max = this.memberTypes.length; i < max; i++) {
410                                 TypeDeclaration memberTypeDecl;
411                                 if ((memberTypeDecl = this.memberTypes[i]).binding == memberTypeBinding)
412                                         return memberTypeDecl;
413                         }
414                 }
415                 return null;
416         }
417
418         /*
419          * Find the matching parse node, answers null if nothing found
420          */
421         public AbstractMethodDeclaration declarationOf(MethodBinding methodBinding) {
422
423                 if (methodBinding != null) {
424                         for (int i = 0, max = this.methods.length; i < max; i++) {
425                                 AbstractMethodDeclaration methodDecl;
426
427                                 if ((methodDecl = this.methods[i]).binding == methodBinding)
428                                         return methodDecl;
429                         }
430                 }
431                 return null;
432         }
433
434         /*
435          * Finds the matching type amoung this type's member types.
436          * Returns null if no type with this name is found.
437          * The type name is a compound name relative to this type
438          * eg. if this type is X and we're looking for Y.X.A.B
439          *     then a type name would be {X, A, B}
440          */
441         public TypeDeclaration declarationOfType(char[][] typeName) {
442
443                 int typeNameLength = typeName.length;
444                 if (typeNameLength < 1 || !CharOperation.equals(typeName[0], this.name)) {
445                         return null;
446                 }
447                 if (typeNameLength == 1) {
448                         return this;
449                 }
450                 char[][] subTypeName = new char[typeNameLength - 1][];
451                 System.arraycopy(typeName, 1, subTypeName, 0, typeNameLength - 1);
452                 for (int i = 0; i < this.memberTypes.length; i++) {
453                         TypeDeclaration typeDecl = this.memberTypes[i].declarationOfType(subTypeName);
454                         if (typeDecl != null) {
455                                 return typeDecl;
456                         }
457                 }
458                 return null;
459         }
460
461         /**
462          * Generic bytecode generation for type
463          */
464 //      public void generateCode(ClassFile enclosingClassFile) {
465 //
466 //              if (hasBeenGenerated)
467 //                      return;
468 //              hasBeenGenerated = true;
469 //              if (ignoreFurtherInvestigation) {
470 //                      if (binding == null)
471 //                              return;
472 //                      ClassFile.createProblemType(
473 //                              this,
474 //                              scope.referenceCompilationUnit().compilationResult);
475 //                      return;
476 //              }
477 //              try {
478 //                      // create the result for a compiled type
479 //                      ClassFile classFile = new ClassFile(binding, enclosingClassFile, false);
480 //                      // generate all fiels
481 //                      classFile.addFieldInfos();
482 //
483 //                      // record the inner type inside its own .class file to be able
484 //                      // to generate inner classes attributes
485 //                      if (binding.isMemberType())
486 //                              classFile.recordEnclosingTypeAttributes(binding);
487 //                      if (binding.isLocalType()) {
488 //                              enclosingClassFile.recordNestedLocalAttribute(binding);
489 //                              classFile.recordNestedLocalAttribute(binding);
490 //                      }
491 //                      if (memberTypes != null) {
492 //                              for (int i = 0, max = memberTypes.length; i < max; i++) {
493 //                                      // record the inner type inside its own .class file to be able
494 //                                      // to generate inner classes attributes
495 //                                      classFile.recordNestedMemberAttribute(memberTypes[i].binding);
496 //                                      memberTypes[i].generateCode(scope, classFile);
497 //                              }
498 //                      }
499 //                      // generate all methods
500 //                      classFile.setForMethodInfos();
501 //                      if (methods != null) {
502 //                              for (int i = 0, max = methods.length; i < max; i++) {
503 //                                      methods[i].generateCode(scope, classFile);
504 //                              }
505 //                      }
506 //                      
507 //                      classFile.generateMissingAbstractMethods(this.missingAbstractMethods, scope.referenceCompilationUnit().compilationResult);
508 //
509 //                      // generate all methods
510 //                      classFile.addSpecialMethods();
511 //
512 //                      if (ignoreFurtherInvestigation) { // trigger problem type generation for code gen errors
513 //                              throw new AbortType(scope.referenceCompilationUnit().compilationResult);
514 //                      }
515 //
516 //                      // finalize the compiled type result
517 //                      classFile.addAttributes();
518 //                      scope.referenceCompilationUnit().compilationResult.record(
519 //                              binding.constantPoolName(),
520 //                              classFile);
521 //              } catch (AbortType e) {
522 //                      if (binding == null)
523 //                              return;
524 //                      ClassFile.createProblemType(
525 //                              this,
526 //                              scope.referenceCompilationUnit().compilationResult);
527 //              }
528 //      }
529
530         /**
531          * Bytecode generation for a local inner type (API as a normal statement code gen)
532          */
533 //      public void generateCode(BlockScope blockScope, CodeStream codeStream) {
534 //
535 //              if (hasBeenGenerated) return;
536 //              int pc = codeStream.position;
537 //              if (binding != null) ((NestedTypeBinding) binding).computeSyntheticArgumentSlotSizes();
538 //              generateCode(codeStream.classFile);
539 //              codeStream.recordPositionsFrom(pc, this.sourceStart);
540 //      }
541
542         /**
543          * Bytecode generation for a member inner type
544          */
545 //      public void generateCode(ClassScope classScope, ClassFile enclosingClassFile) {
546 //
547 //              if (hasBeenGenerated) return;
548 //              if (binding != null) ((NestedTypeBinding) binding).computeSyntheticArgumentSlotSizes();
549 //              generateCode(enclosingClassFile);
550 //      }
551
552         /**
553          * Bytecode generation for a package member
554          */
555 //      public void generateCode(CompilationUnitScope unitScope) {
556 //
557 //              generateCode((ClassFile) null);
558 //      }
559
560         public boolean hasErrors() {
561                 return this.ignoreFurtherInvestigation;
562         }
563
564         /**
565          *      Common flow analysis for all types
566          *
567          */
568         public void internalAnalyseCode(FlowContext flowContext, FlowInfo flowInfo) {
569
570                 if (this.binding.isPrivate() && !this.binding.isPrivateUsed()) {
571                         if (!scope.referenceCompilationUnit().compilationResult.hasSyntaxError()) {
572                                 scope.problemReporter().unusedPrivateType(this);
573                         }
574                 }
575
576                 ReferenceBinding[] defaultHandledExceptions = new ReferenceBinding[] { scope.getJavaLangThrowable()}; // tolerate any kind of exception
577                 InitializationFlowContext initializerContext = new InitializationFlowContext(null, this, initializerScope);
578                 InitializationFlowContext staticInitializerContext = new InitializationFlowContext(null, this, staticInitializerScope);
579                 FlowInfo nonStaticFieldInfo = flowInfo.copy().unconditionalInits().discardFieldInitializations();
580                 FlowInfo staticFieldInfo = flowInfo.copy().unconditionalInits().discardFieldInitializations();
581                 if (fields != null) {
582                         for (int i = 0, count = fields.length; i < count; i++) {
583                                 FieldDeclaration field = fields[i];
584                                 if (field.isStatic()) {
585                                         /*if (field.isField()){
586                                                 staticInitializerContext.handledExceptions = NoExceptions; // no exception is allowed jls8.3.2
587                                         } else {*/
588                                         staticInitializerContext.handledExceptions = defaultHandledExceptions; // tolerate them all, and record them
589                                         /*}*/
590                                         staticFieldInfo =
591                                                 field.analyseCode(
592                                                         staticInitializerScope,
593                                                         staticInitializerContext,
594                                                         staticFieldInfo);
595                                         // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable
596                                         // branch, since the previous initializer already got the blame.
597                                         if (staticFieldInfo == FlowInfo.DEAD_END) {
598                                                 staticInitializerScope.problemReporter().initializerMustCompleteNormally(field);
599                                                 staticFieldInfo = FlowInfo.initial(maxFieldCount).setReachMode(FlowInfo.UNREACHABLE);
600                                         }
601                                 } else {
602                                         /*if (field.isField()){
603                                                 initializerContext.handledExceptions = NoExceptions; // no exception is allowed jls8.3.2
604                                         } else {*/
605                                                 initializerContext.handledExceptions = defaultHandledExceptions; // tolerate them all, and record them
606                                         /*}*/
607                                         nonStaticFieldInfo =
608                                                 field.analyseCode(initializerScope, initializerContext, nonStaticFieldInfo);
609                                         // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable
610                                         // branch, since the previous initializer already got the blame.
611                                         if (nonStaticFieldInfo == FlowInfo.DEAD_END) {
612                                                 initializerScope.problemReporter().initializerMustCompleteNormally(field);
613                                                 nonStaticFieldInfo = FlowInfo.initial(maxFieldCount).setReachMode(FlowInfo.UNREACHABLE);
614                                         }
615                                 }
616                         }
617                 }
618                 if (memberTypes != null) {
619                         for (int i = 0, count = memberTypes.length; i < count; i++) {
620                                 if (flowContext != null){ // local type
621                                         memberTypes[i].analyseCode(scope, flowContext, nonStaticFieldInfo.copy());
622                                 } else {
623                                         memberTypes[i].analyseCode(scope);
624                                 }
625                         }
626                 }
627                 if (methods != null) {
628                         UnconditionalFlowInfo outerInfo = flowInfo.copy().unconditionalInits().discardFieldInitializations();
629                         FlowInfo constructorInfo = nonStaticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo);
630                         for (int i = 0, count = methods.length; i < count; i++) {
631                                 AbstractMethodDeclaration method = methods[i];
632                                 if (method.ignoreFurtherInvestigation)
633                                         continue;
634                                 if (method.isInitializationMethod()) {
635                                         if (method.isStatic()) { // <clinit>
636                                                 method.analyseCode(
637                                                         scope, 
638                                                         staticInitializerContext, 
639                                                         staticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo));
640                                         } else { // constructor
641                                                 method.analyseCode(scope, initializerContext, constructorInfo.copy());
642                                         }
643                                 } else { // regular method
644                                         method.analyseCode(scope, null, flowInfo.copy());
645                                 }
646                         }
647                 }
648         }
649
650         public boolean isInterface() {
651
652                 return (modifiers & AccInterface) != 0;
653         }
654
655         /* 
656          * Access emulation for a local type
657          * force to emulation of access to direct enclosing instance.
658          * By using the initializer scope, we actually only request an argument emulation, the
659          * field is not added until actually used. However we will force allocations to be qualified
660          * with an enclosing instance.
661          * 15.9.2
662          */
663         public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
664
665                 NestedTypeBinding nestedType = (NestedTypeBinding) binding;
666                 
667                 MethodScope methodScope = currentScope.methodScope();
668                 if (!methodScope.isStatic && !methodScope.isConstructorCall){
669
670                         nestedType.addSyntheticArgumentAndField(binding.enclosingType());       
671                 }
672                 // add superclass enclosing instance arg for anonymous types (if necessary)
673                 if (binding.isAnonymousType()) { 
674                         ReferenceBinding superclass = binding.superclass;
675                         if (superclass.enclosingType() != null && !superclass.isStatic()) {
676                                 if (!binding.superclass.isLocalType()
677                                                 || ((NestedTypeBinding)binding.superclass).getSyntheticField(superclass.enclosingType(), true) != null){
678
679                                         nestedType.addSyntheticArgument(superclass.enclosingType());    
680                                 }
681                         }
682                 }
683         }
684         
685         /* 
686          * Access emulation for a local member type
687          * force to emulation of access to direct enclosing instance.
688          * By using the initializer scope, we actually only request an argument emulation, the
689          * field is not added until actually used. However we will force allocations to be qualified
690          * with an enclosing instance.
691          * 
692          * Local member cannot be static.
693          */
694         public void manageEnclosingInstanceAccessIfNecessary(ClassScope currentScope) {
695
696                 NestedTypeBinding nestedType = (NestedTypeBinding) binding;
697                 nestedType.addSyntheticArgumentAndField(binding.enclosingType());
698         }       
699         
700         /**
701          * A <clinit> will be requested as soon as static fields or assertions are present. It will be eliminated during
702          * classfile creation if no bytecode was actually produced based on some optimizations/compiler settings.
703          */
704         public final boolean needClassInitMethod() {
705
706                 // always need a <clinit> when assertions are present
707                 if ((this.bits & AddAssertionMASK) != 0)
708                         return true;
709                 if (fields == null)
710                         return false;
711                 if (isInterface())
712                         return true; // fields are implicitly statics
713                 for (int i = fields.length; --i >= 0;) {
714                         FieldDeclaration field = fields[i];
715                         //need to test the modifier directly while there is no binding yet
716                         if ((field.modifiers & AccStatic) != 0)
717                                 return true;
718                 }
719                 return false;
720         }
721
722         public void parseMethod(UnitParser parser, CompilationUnitDeclaration unit) {
723
724                 //connect method bodies
725                 if (unit.ignoreMethodBodies)
726                         return;
727
728                 // no scope were created, so cannot report further errors
729 //              if (binding == null)
730 //                      return;
731
732                 //members
733                 if (memberTypes != null) {
734                         int length = memberTypes.length;
735                         for (int i = 0; i < length; i++)
736                                 memberTypes[i].parseMethod(parser, unit);
737                 }
738
739                 //methods
740                 if (methods != null) {
741                         int length = methods.length;
742                         for (int i = 0; i < length; i++)
743                                 methods[i].parseStatements(parser, unit);
744                 }
745
746                 //initializers
747                 if (fields != null) {
748                         int length = fields.length;
749                         for (int i = 0; i < length; i++) {
750                                 if (fields[i] instanceof Initializer) {
751                                         ((Initializer) fields[i]).parseStatements(parser, this, unit);
752                                 }
753                         }
754                 }
755         }
756
757         public void resolve() {
758
759                 if (binding == null) {
760                         ignoreFurtherInvestigation = true;
761                         return;
762                 }
763
764                 try {
765                         // check superclass & interfaces
766                         if (binding.superclass != null) // watch out for Object ! (and other roots)     
767                                 if (isTypeUseDeprecated(binding.superclass, scope))
768                                         scope.problemReporter().deprecatedType(binding.superclass, superclass);
769                         if (superInterfaces != null)
770                                 for (int i = superInterfaces.length; --i >= 0;)
771                                         if (superInterfaces[i].resolvedType != null)
772                                                 if (isTypeUseDeprecated(superInterfaces[i].resolvedType, scope))
773                                                         scope.problemReporter().deprecatedType(
774                                                                 superInterfaces[i].resolvedType,
775                                                                 superInterfaces[i]);
776                         maxFieldCount = 0;
777                         int lastFieldID = -1;
778                         if (fields != null) {
779                                 for (int i = 0, count = fields.length; i < count; i++) {
780                                         FieldDeclaration field = fields[i];
781                                         if (field.isField()) {
782                                                 if (field.binding == null) {
783                                                         // still discover secondary errors
784                                                         if (field.initialization != null) field.initialization.resolve(field.isStatic() ? staticInitializerScope : initializerScope);
785                                                         ignoreFurtherInvestigation = true;
786                                                         continue;
787                                                 }
788                                                 maxFieldCount++;
789                                                 lastFieldID = field.binding.id;
790                                         } else { // initializer
791                                                  ((Initializer) field).lastFieldID = lastFieldID + 1;
792                                         }
793                                         field.resolve(field.isStatic() ? staticInitializerScope : initializerScope);
794                                 }
795                         }
796                         if (memberTypes != null) {
797                                 for (int i = 0, count = memberTypes.length; i < count; i++) {
798                                         memberTypes[i].resolve(scope);
799                                 }
800                         }
801                         int missingAbstractMethodslength = this.missingAbstractMethods == null ? 0 : this.missingAbstractMethods.length;
802                         int methodsLength = this.methods == null ? 0 : methods.length;
803                         if ((methodsLength + missingAbstractMethodslength) > 0xFFFF) {
804                                 scope.problemReporter().tooManyMethods(this);
805                         }
806                         
807                         if (methods != null) {
808                                 for (int i = 0, count = methods.length; i < count; i++) {
809                                         methods[i].resolve(scope);
810                                 }
811                         }
812                 } catch (AbortType e) {
813                         this.ignoreFurtherInvestigation = true;
814                         return;
815                 };
816         }
817
818         public void resolve(BlockScope blockScope) {
819                 // local type declaration
820
821                 // need to build its scope first and proceed with binding's creation
822                 blockScope.addLocalType(this);
823
824                 // and TC....
825                 if (binding != null) {
826                         // remember local types binding for innerclass emulation propagation
827                         blockScope.referenceCompilationUnit().record((LocalTypeBinding)binding);
828
829                         // binding is not set if the receiver could not be created
830                         resolve();
831                         updateMaxFieldCount();
832                 }
833         }
834
835         public void resolve(ClassScope upperScope) {
836                 // member scopes are already created
837                 // request the construction of a binding if local member type
838
839                 if (binding != null && binding instanceof LocalTypeBinding) {
840                         // remember local types binding for innerclass emulation propagation
841                         upperScope.referenceCompilationUnit().record((LocalTypeBinding)binding);
842                 }
843                 resolve();
844                 updateMaxFieldCount();
845         }
846
847         public void resolve(CompilationUnitScope upperScope) {
848                 // top level : scope are already created
849
850                 resolve();
851                 updateMaxFieldCount();
852         }
853
854         public void tagAsHavingErrors() {
855                 ignoreFurtherInvestigation = true;
856         }
857
858         public String toString(int tab) {
859
860                 return tabString(tab) + toStringHeader() + toStringBody(tab);
861         }
862
863         public String toStringBody(int tab) {
864
865                 String s = " {"; //$NON-NLS-1$
866                 if (memberTypes != null) {
867                         for (int i = 0; i < memberTypes.length; i++) {
868                                 if (memberTypes[i] != null) {
869                                         s += "\n" + memberTypes[i].toString(tab + 1); //$NON-NLS-1$
870                                 }
871                         }
872                 }
873                 if (fields != null) {
874                         for (int fieldI = 0; fieldI < fields.length; fieldI++) {
875                                 if (fields[fieldI] != null) {
876                                         s += "\n" + fields[fieldI].toString(tab + 1); //$NON-NLS-1$
877                                         if (fields[fieldI].isField())
878                                                 s += ";"; //$NON-NLS-1$
879                                 }
880                         }
881                 }
882                 if (methods != null) {
883                         for (int i = 0; i < methods.length; i++) {
884                                 if (methods[i] != null) {
885                                         s += "\n" + methods[i].toString(tab + 1); //$NON-NLS-1$
886                                 }
887                         }
888                 }
889                 s += "\n" + tabString(tab) + "}"; //$NON-NLS-2$ //$NON-NLS-1$
890                 return s;
891         }
892
893         public String toStringHeader() {
894
895                 String s = ""; //$NON-NLS-1$
896                 if (modifiers != AccDefault) {
897                         s += modifiersString(modifiers);
898                 }
899                 s += (isInterface() ? "interface " : "class ") + new String(name);//$NON-NLS-1$ //$NON-NLS-2$
900                 if (superclass != null)
901                         s += " extends " + superclass.toString(0); //$NON-NLS-1$
902                 if (superInterfaces != null && superInterfaces.length > 0) {
903                         s += (isInterface() ? " extends " : " implements ");//$NON-NLS-2$ //$NON-NLS-1$
904                         for (int i = 0; i < superInterfaces.length; i++) {
905                                 s += superInterfaces[i].toString(0);
906                                 if (i != superInterfaces.length - 1)
907                                         s += ", "; //$NON-NLS-1$
908                         };
909                 };
910                 return s;
911         }
912
913         /**
914          *      Iteration for a package member type
915          *
916          */
917         public void traverse(
918                 IAbstractSyntaxTreeVisitor visitor,
919                 CompilationUnitScope unitScope) {
920
921                 if (ignoreFurtherInvestigation)
922                         return;
923                 try {
924                         if (visitor.visit(this, unitScope)) {
925                                 if (superclass != null)
926                                         superclass.traverse(visitor, scope);
927                                 if (superInterfaces != null) {
928                                         int superInterfaceLength = superInterfaces.length;
929                                         for (int i = 0; i < superInterfaceLength; i++)
930                                                 superInterfaces[i].traverse(visitor, scope);
931                                 }
932                                 if (memberTypes != null) {
933                                         int memberTypesLength = memberTypes.length;
934                                         for (int i = 0; i < memberTypesLength; i++)
935                                                 memberTypes[i].traverse(visitor, scope);
936                                 }
937                                 if (fields != null) {
938                                         int fieldsLength = fields.length;
939                                         for (int i = 0; i < fieldsLength; i++) {
940                                                 FieldDeclaration field;
941                                                 if ((field = fields[i]).isStatic()) {
942                                                         field.traverse(visitor, staticInitializerScope);
943                                                 } else {
944                                                         field.traverse(visitor, initializerScope);
945                                                 }
946                                         }
947                                 }
948                                 if (methods != null) {
949                                         int methodsLength = methods.length;
950                                         for (int i = 0; i < methodsLength; i++)
951                                                 methods[i].traverse(visitor, scope);
952                                 }
953                         }
954                         visitor.endVisit(this, unitScope);
955                 } catch (AbortType e) {
956                 }
957         }
958
959         /**
960          * MaxFieldCount's computation is necessary so as to reserve space for
961          * the flow info field portions. It corresponds to the maximum amount of
962          * fields this class or one of its innertypes have.
963          *
964          * During name resolution, types are traversed, and the max field count is recorded
965          * on the outermost type. It is then propagated down during the flow analysis.
966          *
967          * This method is doing either up/down propagation.
968          */
969         void updateMaxFieldCount() {
970
971                 if (binding == null)
972                         return; // error scenario
973                 TypeDeclaration outerMostType = scope.outerMostClassScope().referenceType();
974                 if (maxFieldCount > outerMostType.maxFieldCount) {
975                         outerMostType.maxFieldCount = maxFieldCount; // up
976                 } else {
977                         maxFieldCount = outerMostType.maxFieldCount; // down
978                 }
979         }
980 }