merged src/java and src/rsc
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / TypeDeclaration.java
diff --git a/src/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java b/src/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java
new file mode 100644 (file)
index 0000000..b6ba6f1
--- /dev/null
@@ -0,0 +1,1135 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.ast;
+
+import org.eclipse.jdt.core.compiler.*;
+import org.eclipse.jdt.internal.compiler.ASTVisitor;
+import org.eclipse.jdt.internal.compiler.*;
+import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+import org.eclipse.jdt.internal.compiler.parser.*;
+import org.eclipse.jdt.internal.compiler.problem.*;
+
+public class TypeDeclaration
+       extends Statement
+       implements ProblemSeverities, ReferenceContext {
+
+       public static final char[] ANONYMOUS_EMPTY_NAME = new char[] {};
+
+       public int modifiers = AccDefault;
+       public int modifiersSourceStart;
+       public char[] name;
+       public TypeReference superclass;
+       public TypeReference[] superInterfaces;
+       public FieldDeclaration[] fields;
+       public AbstractMethodDeclaration[] methods;
+       public TypeDeclaration[] memberTypes;
+       public SourceTypeBinding binding;
+       public ClassScope scope;
+       public MethodScope initializerScope;
+       public MethodScope staticInitializerScope;
+       public boolean ignoreFurtherInvestigation = false;
+       public int maxFieldCount;
+       public int declarationSourceStart;
+       public int declarationSourceEnd;
+       public int bodyStart;
+       public int bodyEnd; // doesn't include the trailing comment if any.
+       protected boolean hasBeenGenerated = false;
+       public CompilationResult compilationResult;
+       private MethodDeclaration[] missingAbstractMethods;
+       public Javadoc javadoc; 
+
+       public QualifiedAllocationExpression allocation; // for anonymous only
+       public TypeDeclaration enclosingType; // for member types only
+       
+       public TypeDeclaration(CompilationResult compilationResult){
+               this.compilationResult = compilationResult;
+       }
+               
+       /*
+        *      We cause the compilation task to abort to a given extent.
+        */
+       public void abort(int abortLevel, IProblem problem) {
+
+               switch (abortLevel) {
+                       case AbortCompilation :
+                               throw new AbortCompilation(this.compilationResult, problem);
+                       case AbortCompilationUnit :
+                               throw new AbortCompilationUnit(this.compilationResult, problem);
+                       case AbortMethod :
+                               throw new AbortMethod(this.compilationResult, problem);
+                       default :
+                               throw new AbortType(this.compilationResult, problem);
+               }
+       }
+       /**
+        * This method is responsible for adding a <clinit> method declaration to the type method collections.
+        * Note that this implementation is inserting it in first place (as VAJ or javac), and that this
+        * impacts the behavior of the method ConstantPool.resetForClinit(int. int), in so far as 
+        * the latter will have to reset the constant pool state accordingly (if it was added first, it does 
+        * not need to preserve some of the method specific cached entries since this will be the first method).
+        * inserts the clinit method declaration in the first position.
+        * 
+        * @see org.eclipse.jdt.internal.compiler.codegen.ConstantPool#resetForClinit(int, int)
+        */
+       public final void addClinit() {
+
+               //see comment on needClassInitMethod
+               if (needClassInitMethod()) {
+                       int length;
+                       AbstractMethodDeclaration[] methodDeclarations;
+                       if ((methodDeclarations = this.methods) == null) {
+                               length = 0;
+                               methodDeclarations = new AbstractMethodDeclaration[1];
+                       } else {
+                               length = methodDeclarations.length;
+                               System.arraycopy(
+                                       methodDeclarations,
+                                       0,
+                                       (methodDeclarations = new AbstractMethodDeclaration[length + 1]),
+                                       1,
+                                       length);
+                       }
+                       Clinit clinit = new Clinit(this.compilationResult);
+                       methodDeclarations[0] = clinit;
+                       // clinit is added in first location, so as to minimize the use of ldcw (big consumer of constant inits)
+                       clinit.declarationSourceStart = clinit.sourceStart = sourceStart;
+                       clinit.declarationSourceEnd = clinit.sourceEnd = sourceEnd;
+                       clinit.bodyEnd = sourceEnd;
+                       this.methods = methodDeclarations;
+               }
+       }
+
+       /*
+        * INTERNAL USE ONLY - Creates a fake method declaration for the corresponding binding.
+        * It is used to report errors for missing abstract methods.
+        */
+       public MethodDeclaration addMissingAbstractMethodFor(MethodBinding methodBinding) {
+               TypeBinding[] argumentTypes = methodBinding.parameters;
+               int argumentsLength = argumentTypes.length;
+               //the constructor
+               MethodDeclaration methodDeclaration = new MethodDeclaration(this.compilationResult);
+               methodDeclaration.selector = methodBinding.selector;
+               methodDeclaration.sourceStart = sourceStart;
+               methodDeclaration.sourceEnd = sourceEnd;
+               methodDeclaration.modifiers = methodBinding.getAccessFlags() & ~AccAbstract;
+
+               if (argumentsLength > 0) {
+                       String baseName = "arg";//$NON-NLS-1$
+                       Argument[] arguments = (methodDeclaration.arguments = new Argument[argumentsLength]);
+                       for (int i = argumentsLength; --i >= 0;) {
+                               arguments[i] = new Argument((baseName + i).toCharArray(), 0L, null /*type ref*/, AccDefault);
+                       }
+               }
+
+               //adding the constructor in the methods list
+               if (this.missingAbstractMethods == null) {
+                       this.missingAbstractMethods = new MethodDeclaration[] { methodDeclaration };
+               } else {
+                       MethodDeclaration[] newMethods;
+                       System.arraycopy(
+                               this.missingAbstractMethods,
+                               0,
+                               newMethods = new MethodDeclaration[this.missingAbstractMethods.length + 1],
+                               1,
+                               this.missingAbstractMethods.length);
+                       newMethods[0] = methodDeclaration;
+                       this.missingAbstractMethods = newMethods;
+               }
+
+               //============BINDING UPDATE==========================
+               methodDeclaration.binding = new MethodBinding(
+                               methodDeclaration.modifiers, //methodDeclaration
+                               methodBinding.selector,
+                               methodBinding.returnType,
+                               argumentsLength == 0 ? NoParameters : argumentTypes, //arguments bindings
+                               methodBinding.thrownExceptions, //exceptions
+                               binding); //declaringClass
+                               
+               methodDeclaration.scope = new MethodScope(scope, methodDeclaration, true);
+               methodDeclaration.bindArguments();
+
+/*             if (binding.methods == null) {
+                       binding.methods = new MethodBinding[] { methodDeclaration.binding };
+               } else {
+                       MethodBinding[] newMethods;
+                       System.arraycopy(
+                               binding.methods,
+                               0,
+                               newMethods = new MethodBinding[binding.methods.length + 1],
+                               1,
+                               binding.methods.length);
+                       newMethods[0] = methodDeclaration.binding;
+                       binding.methods = newMethods;
+               }*/
+               //===================================================
+
+               return methodDeclaration;
+       }
+
+       /**
+        *      Flow analysis for a local innertype
+        *
+        */
+       public FlowInfo analyseCode(
+               BlockScope currentScope,
+               FlowContext flowContext,
+               FlowInfo flowInfo) {
+
+               if (ignoreFurtherInvestigation)
+                       return flowInfo;
+               try {
+                       if (flowInfo.isReachable()) {
+                               bits |= IsReachableMASK;
+                               LocalTypeBinding localType = (LocalTypeBinding) binding;
+                               localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType));
+                       }
+                       manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
+                       updateMaxFieldCount(); // propagate down the max field count
+                       internalAnalyseCode(flowContext, flowInfo); 
+               } catch (AbortType e) {
+                       this.ignoreFurtherInvestigation = true;
+               }
+               return flowInfo;
+       }
+
+       /**
+        *      Flow analysis for a member innertype
+        *
+        */
+       public void analyseCode(ClassScope enclosingClassScope) {
+
+               if (ignoreFurtherInvestigation)
+                       return;
+               try {
+                       // propagate down the max field count
+                       updateMaxFieldCount();
+                       internalAnalyseCode(null, FlowInfo.initial(maxFieldCount));
+               } catch (AbortType e) {
+                       this.ignoreFurtherInvestigation = true;
+               }
+       }
+
+       /**
+        *      Flow analysis for a local member innertype
+        *
+        */
+       public void analyseCode(
+               ClassScope currentScope,
+               FlowContext flowContext,
+               FlowInfo flowInfo) {
+
+               if (ignoreFurtherInvestigation)
+                       return;
+               try {
+                       if (flowInfo.isReachable()) {
+                               bits |= IsReachableMASK;
+                               LocalTypeBinding localType = (LocalTypeBinding) binding;
+                               localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType));
+                       }
+                       manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
+                       updateMaxFieldCount(); // propagate down the max field count
+                       internalAnalyseCode(flowContext, flowInfo);
+               } catch (AbortType e) {
+                       this.ignoreFurtherInvestigation = true;
+               }
+       }
+
+       /**
+        *      Flow analysis for a package member type
+        *
+        */
+       public void analyseCode(CompilationUnitScope unitScope) {
+
+               if (ignoreFurtherInvestigation)
+                       return;
+               try {
+                       internalAnalyseCode(null, FlowInfo.initial(maxFieldCount));
+               } catch (AbortType e) {
+                       this.ignoreFurtherInvestigation = true;
+               }
+       }
+
+       /*
+        * Check for constructor vs. method with no return type.
+        * Answers true if at least one constructor is defined
+        */
+       public boolean checkConstructors(Parser parser) {
+
+               //if a constructor has not the name of the type,
+               //convert it into a method with 'null' as its return type
+               boolean hasConstructor = false;
+               if (methods != null) {
+                       for (int i = methods.length; --i >= 0;) {
+                               AbstractMethodDeclaration am;
+                               if ((am = methods[i]).isConstructor()) {
+                                       if (!CharOperation.equals(am.selector, name)) {
+                                               // the constructor was in fact a method with no return type
+                                               // unless an explicit constructor call was supplied
+                                               ConstructorDeclaration c = (ConstructorDeclaration) am;
+                                               if (c.constructorCall == null || c.constructorCall.isImplicitSuper()) { //changed to a method
+                                                       MethodDeclaration m = parser.convertToMethodDeclaration(c, this.compilationResult);
+                                                       methods[i] = m;
+                                               }
+                                       } else {
+                                               if (this.isInterface()) {
+                                                       // report the problem and continue the parsing
+                                                       parser.problemReporter().interfaceCannotHaveConstructors(
+                                                               (ConstructorDeclaration) am);
+                                               }
+                                               hasConstructor = true;
+                                       }
+                               }
+                       }
+               }
+               return hasConstructor;
+       }
+
+       public CompilationResult compilationResult() {
+
+               return this.compilationResult;
+       }
+
+       public ConstructorDeclaration createsInternalConstructor(
+               boolean needExplicitConstructorCall,
+               boolean needToInsert) {
+
+               //Add to method'set, the default constuctor that just recall the
+               //super constructor with no arguments
+               //The arguments' type will be positionned by the TC so just use
+               //the default int instead of just null (consistency purpose)
+
+               //the constructor
+               ConstructorDeclaration constructor = new ConstructorDeclaration(this.compilationResult);
+               constructor.isDefaultConstructor = true;
+               constructor.selector = name;
+               if (modifiers != AccDefault) {
+                       constructor.modifiers =
+                               (((this.bits & ASTNode.IsMemberTypeMASK) != 0) && (modifiers & AccPrivate) != 0)
+                                       ? AccDefault
+                                       : modifiers & AccVisibilityMASK;
+               }
+
+               //if you change this setting, please update the 
+               //SourceIndexer2.buildTypeDeclaration(TypeDeclaration,char[]) method
+               constructor.declarationSourceStart = constructor.sourceStart = sourceStart;
+               constructor.declarationSourceEnd =
+                       constructor.sourceEnd = constructor.bodyEnd = sourceEnd;
+
+               //the super call inside the constructor
+               if (needExplicitConstructorCall) {
+                       constructor.constructorCall = SuperReference.implicitSuperConstructorCall();
+                       constructor.constructorCall.sourceStart = sourceStart;
+                       constructor.constructorCall.sourceEnd = sourceEnd;
+               }
+
+               //adding the constructor in the methods list
+               if (needToInsert) {
+                       if (methods == null) {
+                               methods = new AbstractMethodDeclaration[] { constructor };
+                       } else {
+                               AbstractMethodDeclaration[] newMethods;
+                               System.arraycopy(
+                                       methods,
+                                       0,
+                                       newMethods = new AbstractMethodDeclaration[methods.length + 1],
+                                       1,
+                                       methods.length);
+                               newMethods[0] = constructor;
+                               methods = newMethods;
+                       }
+               }
+               return constructor;
+       }
+       
+       // anonymous type constructor creation
+       public MethodBinding createsInternalConstructorWithBinding(MethodBinding inheritedConstructorBinding) {
+
+               //Add to method'set, the default constuctor that just recall the
+               //super constructor with the same arguments
+               String baseName = "$anonymous"; //$NON-NLS-1$
+               TypeBinding[] argumentTypes = inheritedConstructorBinding.parameters;
+               int argumentsLength = argumentTypes.length;
+               //the constructor
+               ConstructorDeclaration cd = new ConstructorDeclaration(this.compilationResult);
+               cd.selector = new char[] { 'x' }; //no maining
+               cd.sourceStart = sourceStart;
+               cd.sourceEnd = sourceEnd;
+               cd.modifiers = modifiers & AccVisibilityMASK;
+               cd.isDefaultConstructor = true;
+
+               if (argumentsLength > 0) {
+                       Argument[] arguments = (cd.arguments = new Argument[argumentsLength]);
+                       for (int i = argumentsLength; --i >= 0;) {
+                               arguments[i] = new Argument((baseName + i).toCharArray(), 0L, null /*type ref*/, AccDefault);
+                       }
+               }
+
+               //the super call inside the constructor
+               cd.constructorCall = SuperReference.implicitSuperConstructorCall();
+               cd.constructorCall.sourceStart = sourceStart;
+               cd.constructorCall.sourceEnd = sourceEnd;
+
+               if (argumentsLength > 0) {
+                       Expression[] args;
+                       args = cd.constructorCall.arguments = new Expression[argumentsLength];
+                       for (int i = argumentsLength; --i >= 0;) {
+                               args[i] = new SingleNameReference((baseName + i).toCharArray(), 0L);
+                       }
+               }
+
+               //adding the constructor in the methods list
+               if (methods == null) {
+                       methods = new AbstractMethodDeclaration[] { cd };
+               } else {
+                       AbstractMethodDeclaration[] newMethods;
+                       System.arraycopy(
+                               methods,
+                               0,
+                               newMethods = new AbstractMethodDeclaration[methods.length + 1],
+                               1,
+                               methods.length);
+                       newMethods[0] = cd;
+                       methods = newMethods;
+               }
+
+               //============BINDING UPDATE==========================
+               cd.binding = new MethodBinding(
+                               cd.modifiers, //methodDeclaration
+                               argumentsLength == 0 ? NoParameters : argumentTypes, //arguments bindings
+                               inheritedConstructorBinding.thrownExceptions, //exceptions
+                               binding); //declaringClass
+                               
+               cd.scope = new MethodScope(scope, cd, true);
+               cd.bindArguments();
+               cd.constructorCall.resolve(cd.scope);
+
+               if (binding.methods == null) {
+                       binding.methods = new MethodBinding[] { cd.binding };
+               } else {
+                       MethodBinding[] newMethods;
+                       System.arraycopy(
+                               binding.methods,
+                               0,
+                               newMethods = new MethodBinding[binding.methods.length + 1],
+                               1,
+                               binding.methods.length);
+                       newMethods[0] = cd.binding;
+                       binding.methods = newMethods;
+               }
+               //===================================================
+
+               return cd.binding;
+       }
+
+       /*
+        * Find the matching parse node, answers null if nothing found
+        */
+       public FieldDeclaration declarationOf(FieldBinding fieldBinding) {
+
+               if (fieldBinding != null) {
+                       for (int i = 0, max = this.fields.length; i < max; i++) {
+                               FieldDeclaration fieldDecl;
+                               if ((fieldDecl = this.fields[i]).binding == fieldBinding)
+                                       return fieldDecl;
+                       }
+               }
+               return null;
+       }
+
+       /*
+        * Find the matching parse node, answers null if nothing found
+        */
+       public TypeDeclaration declarationOf(MemberTypeBinding memberTypeBinding) {
+
+               if (memberTypeBinding != null) {
+                       for (int i = 0, max = this.memberTypes.length; i < max; i++) {
+                               TypeDeclaration memberTypeDecl;
+                               if ((memberTypeDecl = this.memberTypes[i]).binding == memberTypeBinding)
+                                       return memberTypeDecl;
+                       }
+               }
+               return null;
+       }
+
+       /*
+        * Find the matching parse node, answers null if nothing found
+        */
+       public AbstractMethodDeclaration declarationOf(MethodBinding methodBinding) {
+
+               if (methodBinding != null) {
+                       for (int i = 0, max = this.methods.length; i < max; i++) {
+                               AbstractMethodDeclaration methodDecl;
+
+                               if ((methodDecl = this.methods[i]).binding == methodBinding)
+                                       return methodDecl;
+                       }
+               }
+               return null;
+       }
+
+       /*
+        * 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 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}
+        */
+       public TypeDeclaration declarationOfType(char[][] typeName) {
+
+               int typeNameLength = typeName.length;
+               if (typeNameLength < 1 || !CharOperation.equals(typeName[0], this.name)) {
+                       return null;
+               }
+               if (typeNameLength == 1) {
+                       return this;
+               }
+               char[][] subTypeName = new char[typeNameLength - 1][];
+               System.arraycopy(typeName, 1, subTypeName, 0, typeNameLength - 1);
+               for (int i = 0; i < this.memberTypes.length; i++) {
+                       TypeDeclaration typeDecl = this.memberTypes[i].declarationOfType(subTypeName);
+                       if (typeDecl != null) {
+                               return typeDecl;
+                       }
+               }
+               return null;
+       }
+
+       /**
+        * Generic bytecode generation for type
+        */
+       public void generateCode(ClassFile enclosingClassFile) {
+
+               if (hasBeenGenerated)
+                       return;
+               hasBeenGenerated = true;
+               if (ignoreFurtherInvestigation) {
+                       if (binding == null)
+                               return;
+                       ClassFile.createProblemType(
+                               this,
+                               scope.referenceCompilationUnit().compilationResult);
+                       return;
+               }
+               try {
+                       // create the result for a compiled type
+                       ClassFile classFile = new ClassFile(binding, enclosingClassFile, false);
+                       // generate all fiels
+                       classFile.addFieldInfos();
+
+                       // record the inner type inside its own .class file to be able
+                       // to generate inner classes attributes
+                       if (binding.isMemberType())
+                               classFile.recordEnclosingTypeAttributes(binding);
+                       if (binding.isLocalType()) {
+                               enclosingClassFile.recordNestedLocalAttribute(binding);
+                               classFile.recordNestedLocalAttribute(binding);
+                       }
+                       if (memberTypes != null) {
+                               for (int i = 0, max = memberTypes.length; i < max; i++) {
+                                       // record the inner type inside its own .class file to be able
+                                       // to generate inner classes attributes
+                                       classFile.recordNestedMemberAttribute(memberTypes[i].binding);
+                                       memberTypes[i].generateCode(scope, classFile);
+                               }
+                       }
+                       // generate all methods
+                       classFile.setForMethodInfos();
+                       if (methods != null) {
+                               for (int i = 0, max = methods.length; i < max; i++) {
+                                       methods[i].generateCode(scope, classFile);
+                               }
+                       }
+                       
+                       classFile.generateMissingAbstractMethods(this.missingAbstractMethods, scope.referenceCompilationUnit().compilationResult);
+
+                       // generate all methods
+                       classFile.addSpecialMethods();
+
+                       if (ignoreFurtherInvestigation) { // trigger problem type generation for code gen errors
+                               throw new AbortType(scope.referenceCompilationUnit().compilationResult, null);
+                       }
+
+                       // finalize the compiled type result
+                       classFile.addAttributes();
+                       scope.referenceCompilationUnit().compilationResult.record(
+                               binding.constantPoolName(),
+                               classFile);
+               } catch (AbortType e) {
+                       if (binding == null)
+                               return;
+                       ClassFile.createProblemType(
+                               this,
+                               scope.referenceCompilationUnit().compilationResult);
+               }
+       }
+
+       /**
+        * Bytecode generation for a local inner type (API as a normal statement code gen)
+        */
+       public void generateCode(BlockScope blockScope, CodeStream codeStream) {
+
+               if ((this.bits & IsReachableMASK) == 0) {
+                       return;
+               }               
+               if (hasBeenGenerated) return;
+               int pc = codeStream.position;
+               if (binding != null) ((NestedTypeBinding) binding).computeSyntheticArgumentSlotSizes();
+               generateCode(codeStream.classFile);
+               codeStream.recordPositionsFrom(pc, this.sourceStart);
+       }
+
+       /**
+        * Bytecode generation for a member inner type
+        */
+       public void generateCode(ClassScope classScope, ClassFile enclosingClassFile) {
+
+               if (hasBeenGenerated) return;
+               if (binding != null) ((NestedTypeBinding) binding).computeSyntheticArgumentSlotSizes();
+               generateCode(enclosingClassFile);
+       }
+
+       /**
+        * Bytecode generation for a package member
+        */
+       public void generateCode(CompilationUnitScope unitScope) {
+
+               generateCode((ClassFile) null);
+       }
+
+       public boolean hasErrors() {
+               return this.ignoreFurtherInvestigation;
+       }
+
+       /**
+        *      Common flow analysis for all types
+        *
+        */
+       public void internalAnalyseCode(FlowContext flowContext, FlowInfo flowInfo) {
+
+               if (this.binding.isPrivate() && !this.binding.isPrivateUsed()) {
+                       if (!scope.referenceCompilationUnit().compilationResult.hasSyntaxError()) {
+                               scope.problemReporter().unusedPrivateType(this);
+                       }
+               }
+
+               InitializationFlowContext initializerContext = new InitializationFlowContext(null, this, initializerScope);
+               InitializationFlowContext staticInitializerContext = new InitializationFlowContext(null, this, staticInitializerScope);
+               FlowInfo nonStaticFieldInfo = flowInfo.copy().unconditionalInits().discardFieldInitializations();
+               FlowInfo staticFieldInfo = flowInfo.copy().unconditionalInits().discardFieldInitializations();
+               if (fields != null) {
+                       for (int i = 0, count = fields.length; i < count; i++) {
+                               FieldDeclaration field = fields[i];
+                               if (field.isStatic()) {
+                                       /*if (field.isField()){
+                                               staticInitializerContext.handledExceptions = NoExceptions; // no exception is allowed jls8.3.2
+                                       } else {*/
+                                       staticInitializerContext.handledExceptions = AnyException; // tolerate them all, and record them
+                                       /*}*/
+                                       staticFieldInfo =
+                                               field.analyseCode(
+                                                       staticInitializerScope,
+                                                       staticInitializerContext,
+                                                       staticFieldInfo);
+                                       // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable
+                                       // branch, since the previous initializer already got the blame.
+                                       if (staticFieldInfo == FlowInfo.DEAD_END) {
+                                               staticInitializerScope.problemReporter().initializerMustCompleteNormally(field);
+                                               staticFieldInfo = FlowInfo.initial(maxFieldCount).setReachMode(FlowInfo.UNREACHABLE);
+                                       }
+                               } else {
+                                       /*if (field.isField()){
+                                               initializerContext.handledExceptions = NoExceptions; // no exception is allowed jls8.3.2
+                                       } else {*/
+                                               initializerContext.handledExceptions = AnyException; // tolerate them all, and record them
+                                       /*}*/
+                                       nonStaticFieldInfo =
+                                               field.analyseCode(initializerScope, initializerContext, nonStaticFieldInfo);
+                                       // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable
+                                       // branch, since the previous initializer already got the blame.
+                                       if (nonStaticFieldInfo == FlowInfo.DEAD_END) {
+                                               initializerScope.problemReporter().initializerMustCompleteNormally(field);
+                                               nonStaticFieldInfo = FlowInfo.initial(maxFieldCount).setReachMode(FlowInfo.UNREACHABLE);
+                                       }
+                               }
+                       }
+               }
+               if (memberTypes != null) {
+                       for (int i = 0, count = memberTypes.length; i < count; i++) {
+                               if (flowContext != null){ // local type
+                                       memberTypes[i].analyseCode(scope, flowContext, nonStaticFieldInfo.copy());
+                               } else {
+                                       memberTypes[i].analyseCode(scope);
+                               }
+                       }
+               }
+               if (methods != null) {
+                       UnconditionalFlowInfo outerInfo = flowInfo.copy().unconditionalInits().discardFieldInitializations();
+                       FlowInfo constructorInfo = nonStaticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo);
+                       for (int i = 0, count = methods.length; i < count; i++) {
+                               AbstractMethodDeclaration method = methods[i];
+                               if (method.ignoreFurtherInvestigation)
+                                       continue;
+                               if (method.isInitializationMethod()) {
+                                       if (method.isStatic()) { // <clinit>
+                                               method.analyseCode(
+                                                       scope, 
+                                                       staticInitializerContext, 
+                                                       staticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo));
+                                       } else { // constructor
+                                               method.analyseCode(scope, initializerContext, constructorInfo.copy());
+                                       }
+                               } else { // regular method
+                                       method.analyseCode(scope, null, flowInfo.copy());
+                               }
+                       }
+               }
+       }
+
+       public boolean isInterface() {
+
+               return (modifiers & AccInterface) != 0;
+       }
+
+       /* 
+        * Access emulation for a local type
+        * force to emulation of access to direct enclosing instance.
+        * By using the initializer scope, we actually only request an argument emulation, the
+        * field is not added until actually used. However we will force allocations to be qualified
+        * with an enclosing instance.
+        * 15.9.2
+        */
+       public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
+
+               if (!flowInfo.isReachable()) return;
+               NestedTypeBinding nestedType = (NestedTypeBinding) binding;
+               
+               MethodScope methodScope = currentScope.methodScope();
+               if (!methodScope.isStatic && !methodScope.isConstructorCall){
+
+                       nestedType.addSyntheticArgumentAndField(binding.enclosingType());       
+               }
+               // add superclass enclosing instance arg for anonymous types (if necessary)
+               if (binding.isAnonymousType()) { 
+                       ReferenceBinding superclassBinding = binding.superclass;
+                       if (superclassBinding.enclosingType() != null && !superclassBinding.isStatic()) {
+                               if (!superclassBinding.isLocalType()
+                                               || ((NestedTypeBinding)superclassBinding).getSyntheticField(superclassBinding.enclosingType(), true) != null){
+
+                                       nestedType.addSyntheticArgument(superclassBinding.enclosingType());     
+                               }
+                       }
+               }
+       }
+       
+       /* 
+        * Access emulation for a local member type
+        * force to emulation of access to direct enclosing instance.
+        * By using the initializer scope, we actually only request an argument emulation, the
+        * field is not added until actually used. However we will force allocations to be qualified
+        * with an enclosing instance.
+        * 
+        * Local member cannot be static.
+        */
+       public void manageEnclosingInstanceAccessIfNecessary(ClassScope currentScope, FlowInfo flowInfo) {
+
+               if (!flowInfo.isReachable()) return;
+               NestedTypeBinding nestedType = (NestedTypeBinding) binding;
+               nestedType.addSyntheticArgumentAndField(binding.enclosingType());
+       }       
+       
+       /**
+        * A <clinit> will be requested as soon as static fields or assertions are present. It will be eliminated during
+        * classfile creation if no bytecode was actually produced based on some optimizations/compiler settings.
+        */
+       public final boolean needClassInitMethod() {
+
+               // always need a <clinit> when assertions are present
+               if ((this.bits & AddAssertionMASK) != 0)
+                       return true;
+               if (fields == null)
+                       return false;
+               if (isInterface())
+                       return true; // fields are implicitly statics
+               for (int i = fields.length; --i >= 0;) {
+                       FieldDeclaration field = fields[i];
+                       //need to test the modifier directly while there is no binding yet
+                       if ((field.modifiers & AccStatic) != 0)
+                               return true;
+               }
+               return false;
+       }
+
+       public void parseMethod(Parser parser, CompilationUnitDeclaration unit) {
+
+               //connect method bodies
+               if (unit.ignoreMethodBodies)
+                       return;
+
+               //members
+               if (memberTypes != null) {
+                       int length = memberTypes.length;
+                       for (int i = 0; i < length; i++)
+                               memberTypes[i].parseMethod(parser, unit);
+               }
+
+               //methods
+               if (methods != null) {
+                       int length = methods.length;
+                       for (int i = 0; i < length; i++)
+                               methods[i].parseStatements(parser, unit);
+               }
+
+               //initializers
+               if (fields != null) {
+                       int length = fields.length;
+                       for (int i = 0; i < length; i++) {
+                               if (fields[i] instanceof Initializer) {
+                                       ((Initializer) fields[i]).parseStatements(parser, this, unit);
+                               }
+                       }
+               }
+       }
+
+       public StringBuffer print(int indent, StringBuffer output) {
+
+               if ((this.bits & IsAnonymousTypeMASK) == 0) {
+                       printIndent(indent, output);
+                       printHeader(0, output);
+               }
+               return printBody(indent, output);
+       }
+
+       public StringBuffer printBody(int indent, StringBuffer output) {
+
+               output.append(" {"); //$NON-NLS-1$
+               if (memberTypes != null) {
+                       for (int i = 0; i < memberTypes.length; i++) {
+                               if (memberTypes[i] != null) {
+                                       output.append('\n');
+                                       memberTypes[i].print(indent + 1, output);
+                               }
+                       }
+               }
+               if (fields != null) {
+                       for (int fieldI = 0; fieldI < fields.length; fieldI++) {
+                               if (fields[fieldI] != null) {
+                                       output.append('\n');
+                                       fields[fieldI].print(indent + 1, output);
+                               }
+                       }
+               }
+               if (methods != null) {
+                       for (int i = 0; i < methods.length; i++) {
+                               if (methods[i] != null) {
+                                       output.append('\n');
+                                       methods[i].print(indent + 1, output); 
+                               }
+                       }
+               }
+               output.append('\n');
+               return printIndent(indent, output).append('}');
+       }
+
+       public StringBuffer printHeader(int indent, StringBuffer output) {
+
+               printModifiers(this.modifiers, output);
+               output.append(isInterface() ? "interface " : "class "); //$NON-NLS-1$ //$NON-NLS-2$
+               output.append(name);
+               if (superclass != null) {
+                       output.append(" extends ");  //$NON-NLS-1$
+                       superclass.print(0, output);
+               }
+               if (superInterfaces != null && superInterfaces.length > 0) {
+                       output.append(isInterface() ? " extends " : " implements ");//$NON-NLS-2$ //$NON-NLS-1$
+                       for (int i = 0; i < superInterfaces.length; i++) {
+                               if (i > 0) output.append( ", "); //$NON-NLS-1$
+                               superInterfaces[i].print(0, output);
+                       }
+               }
+               return output;
+       }
+
+       public StringBuffer printStatement(int tab, StringBuffer output) {
+               return print(tab, output);
+       }
+
+       public void resolve() {
+
+               if (this.binding == null) {
+                       this.ignoreFurtherInvestigation = true;
+                       return;
+               }
+               try {
+                       if ((this.bits & UndocumentedEmptyBlockMASK) != 0) {
+                               this.scope.problemReporter().undocumentedEmptyBlock(this.bodyStart-1, this.bodyEnd);
+                       }
+                       // check superclass & interfaces
+                       if (this.binding.superclass != null) // watch out for Object ! (and other roots)        
+                               if (isTypeUseDeprecated(this.binding.superclass, this.scope))
+                                       this.scope.problemReporter().deprecatedType(this.binding.superclass, this.superclass);
+                       if (this.superInterfaces != null)
+                               for (int i = this.superInterfaces.length; --i >= 0;)
+                                       if (this.superInterfaces[i].resolvedType != null)
+                                               if (isTypeUseDeprecated(this.superInterfaces[i].resolvedType, this.scope))
+                                                       this.scope.problemReporter().deprecatedType(
+                                                               this.superInterfaces[i].resolvedType,
+                                                               this.superInterfaces[i]);
+                       this.maxFieldCount = 0;
+                       int lastVisibleFieldID = -1;
+                       if (this.fields != null) {
+                               for (int i = 0, count = this.fields.length; i < count; i++) {
+                                       FieldDeclaration field = this.fields[i];
+                                       if (field.isField()) {
+                                               if (field.binding == null) {
+                                                       // still discover secondary errors
+                                                       if (field.initialization != null) field.initialization.resolve(field.isStatic() ? this.staticInitializerScope : this.initializerScope);
+                                                       this.ignoreFurtherInvestigation = true;
+                                                       continue;
+                                               }
+                                               this.maxFieldCount++;
+                                               lastVisibleFieldID = field.binding.id;
+                                       } else { // initializer
+                                                ((Initializer) field).lastVisibleFieldID = lastVisibleFieldID + 1;
+                                       }
+                                       field.resolve(field.isStatic() ? this.staticInitializerScope : this.initializerScope);
+                               }
+                       }
+                       if (this.memberTypes != null) {
+                               for (int i = 0, count = this.memberTypes.length; i < count; i++) {
+                                       this.memberTypes[i].resolve(this.scope);
+                               }
+                       }
+                       int missingAbstractMethodslength = this.missingAbstractMethods == null ? 0 : this.missingAbstractMethods.length;
+                       int methodsLength = this.methods == null ? 0 : this.methods.length;
+                       if ((methodsLength + missingAbstractMethodslength) > 0xFFFF) {
+                               this.scope.problemReporter().tooManyMethods(this);
+                       }
+                       
+                       if (this.methods != null) {
+                               for (int i = 0, count = this.methods.length; i < count; i++) {
+                                       this.methods[i].resolve(this.scope);
+                               }
+                       }
+                       // Resolve javadoc
+                       if (this.javadoc != null) {
+                               if (this.scope != null) {
+                                       this.javadoc.resolve(this.scope);
+                               }
+                       } else if (this.binding != null && !this.binding.isLocalType()) {
+                               this.scope.problemReporter().javadocMissing(this.sourceStart, this.sourceEnd, this.binding.modifiers);
+                       }
+                       
+               } catch (AbortType e) {
+                       this.ignoreFurtherInvestigation = true;
+                       return;
+               }
+       }
+
+       public void resolve(BlockScope blockScope) {
+               // local type declaration
+
+               // need to build its scope first and proceed with binding's creation
+               if ((this.bits & IsAnonymousTypeMASK) == 0) blockScope.addLocalType(this);
+
+               if (binding != null) {
+                       // remember local types binding for innerclass emulation propagation
+                       blockScope.referenceCompilationUnit().record((LocalTypeBinding)binding);
+
+                       // binding is not set if the receiver could not be created
+                       resolve();
+                       updateMaxFieldCount();
+               }
+       }
+       
+       public void resolve(ClassScope upperScope) {
+               // member scopes are already created
+               // request the construction of a binding if local member type
+
+               if (binding != null && binding instanceof LocalTypeBinding) {
+                       // remember local types binding for innerclass emulation propagation
+                       upperScope.referenceCompilationUnit().record((LocalTypeBinding)binding);
+               }
+               resolve();
+               updateMaxFieldCount();
+       }
+
+       public void resolve(CompilationUnitScope upperScope) {
+               // top level : scope are already created
+
+               resolve();
+               updateMaxFieldCount();
+       }
+
+       public void tagAsHavingErrors() {
+               ignoreFurtherInvestigation = true;
+       }
+
+
+       /**
+        *      Iteration for a package member type
+        *
+        */
+       public void traverse(
+               ASTVisitor visitor,
+               CompilationUnitScope unitScope) {
+
+               if (ignoreFurtherInvestigation)
+                       return;
+               try {
+                       if (visitor.visit(this, unitScope)) {
+                               if (superclass != null)
+                                       superclass.traverse(visitor, scope);
+                               if (superInterfaces != null) {
+                                       int superInterfaceLength = superInterfaces.length;
+                                       for (int i = 0; i < superInterfaceLength; i++)
+                                               superInterfaces[i].traverse(visitor, scope);
+                               }
+                               if (memberTypes != null) {
+                                       int memberTypesLength = memberTypes.length;
+                                       for (int i = 0; i < memberTypesLength; i++)
+                                               memberTypes[i].traverse(visitor, scope);
+                               }
+                               if (fields != null) {
+                                       int fieldsLength = fields.length;
+                                       for (int i = 0; i < fieldsLength; i++) {
+                                               FieldDeclaration field;
+                                               if ((field = fields[i]).isStatic()) {
+                                                       field.traverse(visitor, staticInitializerScope);
+                                               } else {
+                                                       field.traverse(visitor, initializerScope);
+                                               }
+                                       }
+                               }
+                               if (methods != null) {
+                                       int methodsLength = methods.length;
+                                       for (int i = 0; i < methodsLength; i++)
+                                               methods[i].traverse(visitor, scope);
+                               }
+                       }
+                       visitor.endVisit(this, unitScope);
+               } catch (AbortType e) {
+                       // silent abort
+               }
+       }
+
+       /**
+        *      Iteration for a local innertype
+        *
+        */
+       public void traverse(ASTVisitor visitor, BlockScope blockScope) {
+               if (ignoreFurtherInvestigation)
+                       return;
+               try {
+                       if (visitor.visit(this, blockScope)) {
+                               if (superclass != null)
+                                       superclass.traverse(visitor, scope);
+                               if (superInterfaces != null) {
+                                       int superInterfaceLength = superInterfaces.length;
+                                       for (int i = 0; i < superInterfaceLength; i++)
+                                               superInterfaces[i].traverse(visitor, scope);
+                               }
+                               if (memberTypes != null) {
+                                       int memberTypesLength = memberTypes.length;
+                                       for (int i = 0; i < memberTypesLength; i++)
+                                               memberTypes[i].traverse(visitor, scope);
+                               }
+                               if (fields != null) {
+                                       int fieldsLength = fields.length;
+                                       for (int i = 0; i < fieldsLength; i++) {
+                                               FieldDeclaration field;
+                                               if ((field = fields[i]).isStatic()) {
+                                                       // local type cannot have static fields
+                                               } else {
+                                                       field.traverse(visitor, initializerScope);
+                                               }
+                                       }
+                               }
+                               if (methods != null) {
+                                       int methodsLength = methods.length;
+                                       for (int i = 0; i < methodsLength; i++)
+                                               methods[i].traverse(visitor, scope);
+                               }
+                       }
+                       visitor.endVisit(this, blockScope);
+               } catch (AbortType e) {
+                       // silent abort
+               }
+       }
+
+       /**
+        *      Iteration for a member innertype
+        *
+        */
+       public void traverse(ASTVisitor visitor, ClassScope classScope) {
+               if (ignoreFurtherInvestigation)
+                       return;
+               try {
+                       if (visitor.visit(this, classScope)) {
+                               if (superclass != null)
+                                       superclass.traverse(visitor, scope);
+                               if (superInterfaces != null) {
+                                       int superInterfaceLength = superInterfaces.length;
+                                       for (int i = 0; i < superInterfaceLength; i++)
+                                               superInterfaces[i].traverse(visitor, scope);
+                               }
+                               if (memberTypes != null) {
+                                       int memberTypesLength = memberTypes.length;
+                                       for (int i = 0; i < memberTypesLength; i++)
+                                               memberTypes[i].traverse(visitor, scope);
+                               }
+                               if (fields != null) {
+                                       int fieldsLength = fields.length;
+                                       for (int i = 0; i < fieldsLength; i++) {
+                                               FieldDeclaration field;
+                                               if ((field = fields[i]).isStatic()) {
+                                                       field.traverse(visitor, staticInitializerScope);
+                                               } else {
+                                                       field.traverse(visitor, initializerScope);
+                                               }
+                                       }
+                               }
+                               if (methods != null) {
+                                       int methodsLength = methods.length;
+                                       for (int i = 0; i < methodsLength; i++)
+                                               methods[i].traverse(visitor, scope);
+                               }
+                       }
+                       visitor.endVisit(this, classScope);
+               } catch (AbortType e) {
+                       // silent abort
+               }
+       }       
+
+       /**
+        * MaxFieldCount's computation is necessary so as to reserve space for
+        * the flow info field portions. It corresponds to the maximum amount of
+        * fields this class or one of its innertypes have.
+        *
+        * During name resolution, types are traversed, and the max field count is recorded
+        * on the outermost type. It is then propagated down during the flow analysis.
+        *
+        * This method is doing either up/down propagation.
+        */
+       void updateMaxFieldCount() {
+
+               if (binding == null)
+                       return; // error scenario
+               TypeDeclaration outerMostType = scope.outerMostClassScope().referenceType();
+               if (maxFieldCount > outerMostType.maxFieldCount) {
+                       outerMostType.maxFieldCount = maxFieldCount; // up
+               } else {
+                       maxFieldCount = outerMostType.maxFieldCount; // down
+               }
+       }       
+}