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