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