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
 
   6  * Contributors: IBM Corporation - initial API and implementation
 
   7  **********************************************************************************************************************************/
 
   8 package net.sourceforge.phpeclipse.internal.compiler.ast;
 
  10 import net.sourceforge.phpeclipse.internal.compiler.ast.FieldDeclaration;
 
  12 import net.sourceforge.phpdt.core.compiler.CharOperation;
 
  13 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
 
  14 import net.sourceforge.phpdt.internal.compiler.CompilationResult;
 
  15 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
 
  16 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
 
  17 import net.sourceforge.phpdt.internal.compiler.flow.InitializationFlowContext;
 
  18 import net.sourceforge.phpdt.internal.compiler.flow.UnconditionalFlowInfo;
 
  19 import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
 
  20 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
 
  21 import net.sourceforge.phpdt.internal.compiler.lookup.ClassScope;
 
  22 import net.sourceforge.phpdt.internal.compiler.lookup.CompilationUnitScope;
 
  23 import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding;
 
  24 import net.sourceforge.phpdt.internal.compiler.lookup.LocalTypeBinding;
 
  25 import net.sourceforge.phpdt.internal.compiler.lookup.MemberTypeBinding;
 
  26 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
 
  27 import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope;
 
  28 import net.sourceforge.phpdt.internal.compiler.lookup.NestedTypeBinding;
 
  29 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
 
  30 import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding;
 
  31 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
 
  32 import net.sourceforge.phpdt.internal.compiler.parser.Parser;
 
  33 import net.sourceforge.phpdt.internal.compiler.parser.UnitParser;
 
  34 import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilation;
 
  35 import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilationUnit;
 
  36 import net.sourceforge.phpdt.internal.compiler.problem.AbortMethod;
 
  37 import net.sourceforge.phpdt.internal.compiler.problem.AbortType;
 
  38 import net.sourceforge.phpdt.internal.compiler.problem.ProblemSeverities;
 
  40 public class TypeDeclaration extends Statement implements ProblemSeverities, ReferenceContext {
 
  44   public int modifiersSourceStart;
 
  48   public TypeReference superclass;
 
  50   public TypeReference[] superInterfaces;
 
  52   public FieldDeclaration[] fields;
 
  54   public AbstractMethodDeclaration[] methods;
 
  56   public TypeDeclaration[] memberTypes;
 
  58   public SourceTypeBinding binding;
 
  60   public ClassScope scope;
 
  62   public MethodScope initializerScope;
 
  64   public MethodScope staticInitializerScope;
 
  66   public boolean ignoreFurtherInvestigation = false;
 
  68   public int maxFieldCount;
 
  70   public int declarationSourceStart;
 
  72   public int declarationSourceEnd;
 
  76   public int bodyEnd; // doesn't include the trailing comment if any.
 
  78   protected boolean hasBeenGenerated = false;
 
  80   public CompilationResult compilationResult;
 
  82   private MethodDeclaration[] missingAbstractMethods;
 
  84   public TypeDeclaration(CompilationResult compilationResult) {
 
  85     this.compilationResult = compilationResult;
 
  89    * We cause the compilation task to abort to a given extent.
 
  91   public void abort(int abortLevel) {
 
  94       throw new AbortCompilation(); // cannot do better
 
  97     CompilationResult compilationResult = scope.referenceCompilationUnit().compilationResult;
 
 100     case AbortCompilation:
 
 101       throw new AbortCompilation(compilationResult);
 
 102     case AbortCompilationUnit:
 
 103       throw new AbortCompilationUnit(compilationResult);
 
 105       throw new AbortMethod(compilationResult);
 
 107       throw new AbortType(compilationResult);
 
 112    * This method is responsible for adding a <clinit>method declaration to the type method collections. Note that this
 
 113    * implementation is inserting it in first place (as VAJ or javac), and that this impacts the behavior of the method
 
 114    * ConstantPool.resetForClinit(int. int), in so far as the latter will have to reset the constant pool state accordingly (if it
 
 115    * was added first, it does not need to preserve some of the method specific cached entries since this will be the first method).
 
 116    * inserts the clinit method declaration in the first position.
 
 118    * @see net.sourceforge.phpdt.internal.compiler.codegen.ConstantPool#resetForClinit(int, int)
 
 120   public final void addClinit() {
 
 122     //see comment on needClassInitMethod
 
 123     if (needClassInitMethod()) {
 
 125       AbstractMethodDeclaration[] methods;
 
 126       if ((methods = this.methods) == null) {
 
 128         methods = new AbstractMethodDeclaration[1];
 
 130         length = methods.length;
 
 131         System.arraycopy(methods, 0, (methods = new AbstractMethodDeclaration[length + 1]), 1, length);
 
 133       Clinit clinit = new Clinit(this.compilationResult);
 
 135       // clinit is added in first location, so as to minimize the use of ldcw (big consumer of constant inits)
 
 136       clinit.declarationSourceStart = clinit.sourceStart = sourceStart;
 
 137       clinit.declarationSourceEnd = clinit.sourceEnd = sourceEnd;
 
 138       clinit.bodyEnd = sourceEnd;
 
 139       this.methods = methods;
 
 144    * Flow analysis for a local innertype
 
 147   public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
 
 149     if (ignoreFurtherInvestigation)
 
 152       bits |= IsReachableMASK;
 
 153       LocalTypeBinding localType = (LocalTypeBinding) binding;
 
 155       localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType));
 
 156       manageEnclosingInstanceAccessIfNecessary(currentScope);
 
 158       updateMaxFieldCount(); // propagate down the max field count
 
 159       internalAnalyseCode(flowContext, flowInfo);
 
 160     } catch (AbortType e) {
 
 161       this.ignoreFurtherInvestigation = true;
 
 167    * Flow analysis for a member innertype
 
 170   public void analyseCode(ClassScope enclosingClassScope) {
 
 172     if (ignoreFurtherInvestigation)
 
 175       // propagate down the max field count
 
 176       updateMaxFieldCount();
 
 177       internalAnalyseCode(null, FlowInfo.initial(maxFieldCount));
 
 178     } catch (AbortType e) {
 
 179       this.ignoreFurtherInvestigation = true;
 
 184    * Flow analysis for a local member innertype
 
 187   public void analyseCode(ClassScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
 
 189     if (ignoreFurtherInvestigation)
 
 192       bits |= IsReachableMASK;
 
 193       LocalTypeBinding localType = (LocalTypeBinding) binding;
 
 195       localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType));
 
 196       manageEnclosingInstanceAccessIfNecessary(currentScope);
 
 198       updateMaxFieldCount(); // propagate down the max field count
 
 199       internalAnalyseCode(flowContext, flowInfo);
 
 200     } catch (AbortType e) {
 
 201       this.ignoreFurtherInvestigation = true;
 
 206    * Flow analysis for a package member type
 
 209   public void analyseCode(CompilationUnitScope unitScope) {
 
 211     if (ignoreFurtherInvestigation)
 
 214       internalAnalyseCode(null, FlowInfo.initial(maxFieldCount));
 
 215     } catch (AbortType e) {
 
 216       this.ignoreFurtherInvestigation = true;
 
 221    * Check for constructor vs. method with no return type. Answers true if at least one constructor is defined
 
 223   public boolean checkConstructors(Parser parser) {
 
 225     //if a constructor has not the name of the type,
 
 226     //convert it into a method with 'null' as its return type
 
 227     boolean hasConstructor = false;
 
 228     if (methods != null) {
 
 229       for (int i = methods.length; --i >= 0;) {
 
 230         AbstractMethodDeclaration am;
 
 231         if ((am = methods[i]).isConstructor()) {
 
 232           if (!CharOperation.equals(am.selector, name)) {
 
 233             // the constructor was in fact a method with no return type
 
 234             // unless an explicit constructor call was supplied
 
 235             ConstructorDeclaration c = (ConstructorDeclaration) am;
 
 236             if ((c.constructorCall == null) || (c.constructorCall.isImplicitSuper())) { //changed to a method
 
 237               MethodDeclaration m = new MethodDeclaration(this.compilationResult);
 
 238               m.sourceStart = c.sourceStart;
 
 239               m.sourceEnd = c.sourceEnd;
 
 240               m.bodyStart = c.bodyStart;
 
 241               m.bodyEnd = c.bodyEnd;
 
 242               m.declarationSourceEnd = c.declarationSourceEnd;
 
 243               m.declarationSourceStart = c.declarationSourceStart;
 
 244               m.selector = c.selector;
 
 245               m.statements = c.statements;
 
 246               m.modifiers = c.modifiers;
 
 247               m.arguments = c.arguments;
 
 248               m.thrownExceptions = c.thrownExceptions;
 
 249               m.explicitDeclarations = c.explicitDeclarations;
 
 254             if (this.isInterface()) {
 
 255               // report the problem and continue the parsing
 
 256               parser.problemReporter().interfaceCannotHaveConstructors((ConstructorDeclaration) am);
 
 258             hasConstructor = true;
 
 263     return hasConstructor;
 
 266   public CompilationResult compilationResult() {
 
 268     return this.compilationResult;
 
 271   public ConstructorDeclaration createsInternalConstructor(boolean needExplicitConstructorCall, boolean needToInsert) {
 
 273     //Add to method'set, the default constuctor that just recall the
 
 274     //super constructor with no arguments
 
 275     //The arguments' type will be positionned by the TC so just use
 
 276     //the default int instead of just null (consistency purpose)
 
 279     ConstructorDeclaration constructor = new ConstructorDeclaration(this.compilationResult);
 
 280     constructor.isDefaultConstructor = true;
 
 281     constructor.selector = name;
 
 282     if (modifiers != AccDefault) {
 
 283       constructor.modifiers = ((this instanceof MemberTypeDeclaration) && (modifiers & AccPrivate) != 0) ? AccDefault : modifiers
 
 287     //if you change this setting, please update the
 
 288     //SourceIndexer2.buildTypeDeclaration(TypeDeclaration,char[]) method
 
 289     constructor.declarationSourceStart = constructor.sourceStart = sourceStart;
 
 290     constructor.declarationSourceEnd = constructor.sourceEnd = constructor.bodyEnd = sourceEnd;
 
 292     //the super call inside the constructor
 
 293     if (needExplicitConstructorCall) {
 
 294       constructor.constructorCall = SuperReference.implicitSuperConstructorCall();
 
 295       constructor.constructorCall.sourceStart = sourceStart;
 
 296       constructor.constructorCall.sourceEnd = sourceEnd;
 
 299     //adding the constructor in the methods list
 
 301       if (methods == null) {
 
 302         methods = new AbstractMethodDeclaration[] { constructor };
 
 304         AbstractMethodDeclaration[] newMethods;
 
 305         System.arraycopy(methods, 0, newMethods = new AbstractMethodDeclaration[methods.length + 1], 1, methods.length);
 
 306         newMethods[0] = constructor;
 
 307         methods = newMethods;
 
 314    * INTERNAL USE ONLY - Creates a fake method declaration for the corresponding binding. It is used to report errors for missing
 
 317   public MethodDeclaration addMissingAbstractMethodFor(MethodBinding methodBinding) {
 
 318     TypeBinding[] argumentTypes = methodBinding.parameters;
 
 319     int argumentsLength = argumentTypes.length;
 
 321     MethodDeclaration methodDeclaration = new MethodDeclaration(this.compilationResult);
 
 322     methodDeclaration.selector = methodBinding.selector;
 
 323     methodDeclaration.sourceStart = sourceStart;
 
 324     methodDeclaration.sourceEnd = sourceEnd;
 
 325     methodDeclaration.modifiers = methodBinding.getAccessFlags() & ~AccAbstract;
 
 327     if (argumentsLength > 0) {
 
 328       String baseName = "arg";//$NON-NLS-1$
 
 329       Argument[] arguments = (methodDeclaration.arguments = new Argument[argumentsLength]);
 
 330       for (int i = argumentsLength; --i >= 0;) {
 
 331         arguments[i] = new Argument((baseName + i).toCharArray(), 0L, null /* type ref */, AccDefault);
 
 335     //adding the constructor in the methods list
 
 336     if (this.missingAbstractMethods == null) {
 
 337       this.missingAbstractMethods = new MethodDeclaration[] { methodDeclaration };
 
 339       MethodDeclaration[] newMethods;
 
 340       System.arraycopy(this.missingAbstractMethods, 0, newMethods = new MethodDeclaration[this.missingAbstractMethods.length + 1],
 
 341           1, this.missingAbstractMethods.length);
 
 342       newMethods[0] = methodDeclaration;
 
 343       this.missingAbstractMethods = newMethods;
 
 346     //============BINDING UPDATE==========================
 
 347     methodDeclaration.binding = new MethodBinding(methodDeclaration.modifiers, //methodDeclaration
 
 348         methodBinding.selector, methodBinding.returnType, argumentsLength == 0 ? NoParameters : argumentTypes, //arguments bindings
 
 349         methodBinding.thrownExceptions, //exceptions
 
 350         binding); //declaringClass
 
 352     methodDeclaration.scope = new MethodScope(scope, methodDeclaration, true);
 
 353     methodDeclaration.bindArguments();
 
 356      * if (binding.methods == null) { binding.methods = new MethodBinding[] { methodDeclaration.binding }; } else { MethodBinding[]
 
 357      * newMethods; System.arraycopy( binding.methods, 0, newMethods = new MethodBinding[binding.methods.length + 1], 1,
 
 358      * binding.methods.length); newMethods[0] = methodDeclaration.binding; binding.methods = newMethods; }
 
 360     //===================================================
 
 361     return methodDeclaration;
 
 365    * Find the matching parse node, answers null if nothing found
 
 367   public FieldDeclaration declarationOf(FieldBinding fieldBinding) {
 
 369     if (fieldBinding != null) {
 
 370       for (int i = 0, max = this.fields.length; i < max; i++) {
 
 371         FieldDeclaration fieldDecl;
 
 372         if ((fieldDecl = this.fields[i]).binding == fieldBinding)
 
 380    * Find the matching parse node, answers null if nothing found
 
 382   public TypeDeclaration declarationOf(MemberTypeBinding memberTypeBinding) {
 
 384     if (memberTypeBinding != null) {
 
 385       for (int i = 0, max = this.memberTypes.length; i < max; i++) {
 
 386         TypeDeclaration memberTypeDecl;
 
 387         if ((memberTypeDecl = this.memberTypes[i]).binding == memberTypeBinding)
 
 388           return memberTypeDecl;
 
 395    * Find the matching parse node, answers null if nothing found
 
 397   public AbstractMethodDeclaration declarationOf(MethodBinding methodBinding) {
 
 399     if (methodBinding != null) {
 
 400       for (int i = 0, max = this.methods.length; i < max; i++) {
 
 401         AbstractMethodDeclaration methodDecl;
 
 403         if ((methodDecl = this.methods[i]).binding == methodBinding)
 
 411    * Finds the matching type amoung this type's member types. Returns null if no type with this name is found. The type name is a
 
 412    * compound name relative to this type eg. if this type is X and we're looking for Y.X.A.B then a type name would be {X, A, B}
 
 414   public TypeDeclaration declarationOfType(char[][] typeName) {
 
 416     int typeNameLength = typeName.length;
 
 417     if (typeNameLength < 1 || !CharOperation.equals(typeName[0], this.name)) {
 
 420     if (typeNameLength == 1) {
 
 423     char[][] subTypeName = new char[typeNameLength - 1][];
 
 424     System.arraycopy(typeName, 1, subTypeName, 0, typeNameLength - 1);
 
 425     for (int i = 0; i < this.memberTypes.length; i++) {
 
 426       TypeDeclaration typeDecl = this.memberTypes[i].declarationOfType(subTypeName);
 
 427       if (typeDecl != null) {
 
 435    * Generic bytecode generation for type
 
 437   //    public void generateCode(ClassFile enclosingClassFile) {
 
 439   //            if (hasBeenGenerated)
 
 441   //            hasBeenGenerated = true;
 
 442   //            if (ignoreFurtherInvestigation) {
 
 443   //                    if (binding == null)
 
 445   //                    ClassFile.createProblemType(
 
 447   //                            scope.referenceCompilationUnit().compilationResult);
 
 451   //                    // create the result for a compiled type
 
 452   //                    ClassFile classFile = new ClassFile(binding, enclosingClassFile, false);
 
 453   //                    // generate all fiels
 
 454   //                    classFile.addFieldInfos();
 
 456   //                    // record the inner type inside its own .class file to be able
 
 457   //                    // to generate inner classes attributes
 
 458   //                    if (binding.isMemberType())
 
 459   //                            classFile.recordEnclosingTypeAttributes(binding);
 
 460   //                    if (binding.isLocalType()) {
 
 461   //                            enclosingClassFile.recordNestedLocalAttribute(binding);
 
 462   //                            classFile.recordNestedLocalAttribute(binding);
 
 464   //                    if (memberTypes != null) {
 
 465   //                            for (int i = 0, max = memberTypes.length; i < max; i++) {
 
 466   //                                    // record the inner type inside its own .class file to be able
 
 467   //                                    // to generate inner classes attributes
 
 468   //                                    classFile.recordNestedMemberAttribute(memberTypes[i].binding);
 
 469   //                                    memberTypes[i].generateCode(scope, classFile);
 
 472   //                    // generate all methods
 
 473   //                    classFile.setForMethodInfos();
 
 474   //                    if (methods != null) {
 
 475   //                            for (int i = 0, max = methods.length; i < max; i++) {
 
 476   //                                    methods[i].generateCode(scope, classFile);
 
 480   //                    classFile.generateMissingAbstractMethods(this.missingAbstractMethods, scope.referenceCompilationUnit().compilationResult);
 
 482   //                    // generate all methods
 
 483   //                    classFile.addSpecialMethods();
 
 485   //                    if (ignoreFurtherInvestigation) { // trigger problem type generation for code gen errors
 
 486   //                            throw new AbortType(scope.referenceCompilationUnit().compilationResult);
 
 489   //                    // finalize the compiled type result
 
 490   //                    classFile.addAttributes();
 
 491   //                    scope.referenceCompilationUnit().compilationResult.record(
 
 492   //                            binding.constantPoolName(),
 
 494   //            } catch (AbortType e) {
 
 495   //                    if (binding == null)
 
 497   //                    ClassFile.createProblemType(
 
 499   //                            scope.referenceCompilationUnit().compilationResult);
 
 503    * Bytecode generation for a local inner type (API as a normal statement code gen)
 
 505   //    public void generateCode(BlockScope blockScope, CodeStream codeStream) {
 
 507   //            if (hasBeenGenerated) return;
 
 508   //            int pc = codeStream.position;
 
 509   //            if (binding != null) ((NestedTypeBinding) binding).computeSyntheticArgumentSlotSizes();
 
 510   //            generateCode(codeStream.classFile);
 
 511   //            codeStream.recordPositionsFrom(pc, this.sourceStart);
 
 514    * Bytecode generation for a member inner type
 
 516   //    public void generateCode(ClassScope classScope, ClassFile enclosingClassFile) {
 
 518   //            if (hasBeenGenerated) return;
 
 519   //            if (binding != null) ((NestedTypeBinding) binding).computeSyntheticArgumentSlotSizes();
 
 520   //            generateCode(enclosingClassFile);
 
 523    * Bytecode generation for a package member
 
 525   //    public void generateCode(CompilationUnitScope unitScope) {
 
 527   //            generateCode((ClassFile) null);
 
 529   public boolean hasErrors() {
 
 530     return this.ignoreFurtherInvestigation;
 
 534    * Common flow analysis for all types
 
 537   public void internalAnalyseCode(FlowContext flowContext, FlowInfo flowInfo) {
 
 539     if (this.binding.isPrivate() && !this.binding.isPrivateUsed()) {
 
 540       if (!scope.referenceCompilationUnit().compilationResult.hasSyntaxError()) {
 
 541         scope.problemReporter().unusedPrivateType(this);
 
 545     ReferenceBinding[] defaultHandledExceptions = new ReferenceBinding[] { scope.getJavaLangThrowable() }; // tolerate any kind of
 
 547     InitializationFlowContext initializerContext = new InitializationFlowContext(null, this, initializerScope);
 
 548     InitializationFlowContext staticInitializerContext = new InitializationFlowContext(null, this, staticInitializerScope);
 
 549     FlowInfo nonStaticFieldInfo = flowInfo.copy().unconditionalInits().discardFieldInitializations();
 
 550     FlowInfo staticFieldInfo = flowInfo.copy().unconditionalInits().discardFieldInitializations();
 
 551     if (fields != null) {
 
 552       for (int i = 0, count = fields.length; i < count; i++) {
 
 553         FieldDeclaration field = fields[i];
 
 554         if (field.isStatic()) {
 
 556            * if (field.isField()){ staticInitializerContext.handledExceptions = NoExceptions; // no exception is allowed jls8.3.2 }
 
 559           staticInitializerContext.handledExceptions = defaultHandledExceptions; // tolerate them all, and record them
 
 561           staticFieldInfo = field.analyseCode(staticInitializerScope, staticInitializerContext, staticFieldInfo);
 
 562           // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable
 
 563           // branch, since the previous initializer already got the blame.
 
 564           if (staticFieldInfo == FlowInfo.DEAD_END) {
 
 565             staticInitializerScope.problemReporter().initializerMustCompleteNormally(field);
 
 566             staticFieldInfo = FlowInfo.initial(maxFieldCount).setReachMode(FlowInfo.UNREACHABLE);
 
 570            * if (field.isField()){ initializerContext.handledExceptions = NoExceptions; // no exception is allowed jls8.3.2 } else {
 
 572           initializerContext.handledExceptions = defaultHandledExceptions; // tolerate them all, and record them
 
 574           nonStaticFieldInfo = field.analyseCode(initializerScope, initializerContext, nonStaticFieldInfo);
 
 575           // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable
 
 576           // branch, since the previous initializer already got the blame.
 
 577           if (nonStaticFieldInfo == FlowInfo.DEAD_END) {
 
 578             initializerScope.problemReporter().initializerMustCompleteNormally(field);
 
 579             nonStaticFieldInfo = FlowInfo.initial(maxFieldCount).setReachMode(FlowInfo.UNREACHABLE);
 
 584     if (memberTypes != null) {
 
 585       for (int i = 0, count = memberTypes.length; i < count; i++) {
 
 586         if (flowContext != null) { // local type
 
 587           memberTypes[i].analyseCode(scope, flowContext, nonStaticFieldInfo.copy());
 
 589           memberTypes[i].analyseCode(scope);
 
 593     if (methods != null) {
 
 594       UnconditionalFlowInfo outerInfo = flowInfo.copy().unconditionalInits().discardFieldInitializations();
 
 595       FlowInfo constructorInfo = nonStaticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(
 
 597       for (int i = 0, count = methods.length; i < count; i++) {
 
 598         AbstractMethodDeclaration method = methods[i];
 
 599         if (method.ignoreFurtherInvestigation)
 
 601         if (method.isInitializationMethod()) {
 
 602           if (method.isStatic()) { // <clinit>
 
 603             method.analyseCode(scope, staticInitializerContext, staticFieldInfo.unconditionalInits()
 
 604                 .discardNonFieldInitializations().addInitializationsFrom(outerInfo));
 
 605           } else { // constructor
 
 606             method.analyseCode(scope, initializerContext, constructorInfo.copy());
 
 608         } else { // regular method
 
 609           method.analyseCode(scope, null, flowInfo.copy());
 
 615   public boolean isInterface() {
 
 617     return (modifiers & AccInterface) != 0;
 
 621    * Access emulation for a local type force to emulation of access to direct enclosing instance. By using the initializer scope, we
 
 622    * actually only request an argument emulation, the field is not added until actually used. However we will force allocations to
 
 623    * be qualified with an enclosing instance. 15.9.2
 
 625   public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
 
 627     NestedTypeBinding nestedType = (NestedTypeBinding) binding;
 
 629     MethodScope methodScope = currentScope.methodScope();
 
 630     if (!methodScope.isStatic && !methodScope.isConstructorCall) {
 
 632       nestedType.addSyntheticArgumentAndField(binding.enclosingType());
 
 634     // add superclass enclosing instance arg for anonymous types (if necessary)
 
 635     if (binding.isAnonymousType()) {
 
 636       ReferenceBinding superclass = binding.superclass;
 
 637       if (superclass.enclosingType() != null && !superclass.isStatic()) {
 
 638         if (!binding.superclass.isLocalType()
 
 639             || ((NestedTypeBinding) binding.superclass).getSyntheticField(superclass.enclosingType(), true) != null) {
 
 641           nestedType.addSyntheticArgument(superclass.enclosingType());
 
 648    * Access emulation for a local member type force to emulation of access to direct enclosing instance. By using the initializer
 
 649    * scope, we actually only request an argument emulation, the field is not added until actually used. However we will force
 
 650    * allocations to be qualified with an enclosing instance.
 
 652    * Local member cannot be static.
 
 654   public void manageEnclosingInstanceAccessIfNecessary(ClassScope currentScope) {
 
 656     NestedTypeBinding nestedType = (NestedTypeBinding) binding;
 
 657     nestedType.addSyntheticArgumentAndField(binding.enclosingType());
 
 661    * A <clinit>will be requested as soon as static fields or assertions are present. It will be eliminated during classfile creation
 
 662    * if no bytecode was actually produced based on some optimizations/compiler settings.
 
 664   public final boolean needClassInitMethod() {
 
 666     // always need a <clinit> when assertions are present
 
 667     if ((this.bits & AddAssertionMASK) != 0)
 
 672       return true; // fields are implicitly statics
 
 673     for (int i = fields.length; --i >= 0;) {
 
 674       FieldDeclaration field = fields[i];
 
 675       //need to test the modifier directly while there is no binding yet
 
 676       if ((field.modifiers & AccStatic) != 0)
 
 682   public void parseMethod(UnitParser parser, CompilationUnitDeclaration unit) {
 
 684     //connect method bodies
 
 685     if (unit.ignoreMethodBodies)
 
 688     // no scope were created, so cannot report further errors
 
 689     //          if (binding == null)
 
 693     if (memberTypes != null) {
 
 694       int length = memberTypes.length;
 
 695       for (int i = 0; i < length; i++)
 
 696         memberTypes[i].parseMethod(parser, unit);
 
 700     if (methods != null) {
 
 701       int length = methods.length;
 
 702       for (int i = 0; i < length; i++)
 
 703         methods[i].parseStatements(parser, unit);
 
 707     if (fields != null) {
 
 708       int length = fields.length;
 
 709       for (int i = 0; i < length; i++) {
 
 710         if (fields[i] instanceof Initializer) {
 
 711           ((Initializer) fields[i]).parseStatements(parser, this, unit);
 
 717   public void resolve() {
 
 719     if (binding == null) {
 
 720       ignoreFurtherInvestigation = true;
 
 725       // check superclass & interfaces
 
 726       if (binding.superclass != null) // watch out for Object ! (and other roots)
 
 727         if (isTypeUseDeprecated(binding.superclass, scope))
 
 728           scope.problemReporter().deprecatedType(binding.superclass, superclass);
 
 729       if (superInterfaces != null)
 
 730         for (int i = superInterfaces.length; --i >= 0;)
 
 731           if (superInterfaces[i].resolvedType != null)
 
 732             if (isTypeUseDeprecated(superInterfaces[i].resolvedType, scope))
 
 733               scope.problemReporter().deprecatedType(superInterfaces[i].resolvedType, superInterfaces[i]);
 
 735       int lastFieldID = -1;
 
 736       if (fields != null) {
 
 737         for (int i = 0, count = fields.length; i < count; i++) {
 
 738           FieldDeclaration field = fields[i];
 
 739           if (field.isField()) {
 
 740             if (field.binding == null) {
 
 741               // still discover secondary errors
 
 742               if (field.initialization != null)
 
 743                 field.initialization.resolve(field.isStatic() ? staticInitializerScope : initializerScope);
 
 744               ignoreFurtherInvestigation = true;
 
 748             lastFieldID = field.binding.id;
 
 749           } else { // initializer
 
 750             ((Initializer) field).lastFieldID = lastFieldID + 1;
 
 752           field.resolve(field.isStatic() ? staticInitializerScope : initializerScope);
 
 755       if (memberTypes != null) {
 
 756         for (int i = 0, count = memberTypes.length; i < count; i++) {
 
 757           memberTypes[i].resolve(scope);
 
 760       int missingAbstractMethodslength = this.missingAbstractMethods == null ? 0 : this.missingAbstractMethods.length;
 
 761       int methodsLength = this.methods == null ? 0 : methods.length;
 
 762       if ((methodsLength + missingAbstractMethodslength) > 0xFFFF) {
 
 763         scope.problemReporter().tooManyMethods(this);
 
 766       if (methods != null) {
 
 767         for (int i = 0, count = methods.length; i < count; i++) {
 
 768           methods[i].resolve(scope);
 
 771     } catch (AbortType e) {
 
 772       this.ignoreFurtherInvestigation = true;
 
 778   public void resolve(BlockScope blockScope) {
 
 779     // local type declaration
 
 781     // need to build its scope first and proceed with binding's creation
 
 782     blockScope.addLocalType(this);
 
 785     if (binding != null) {
 
 786       // remember local types binding for innerclass emulation propagation
 
 787       blockScope.referenceCompilationUnit().record((LocalTypeBinding) binding);
 
 789       // binding is not set if the receiver could not be created
 
 791       updateMaxFieldCount();
 
 795   public void resolve(ClassScope upperScope) {
 
 796     // member scopes are already created
 
 797     // request the construction of a binding if local member type
 
 799     if (binding != null && binding instanceof LocalTypeBinding) {
 
 800       // remember local types binding for innerclass emulation propagation
 
 801       upperScope.referenceCompilationUnit().record((LocalTypeBinding) binding);
 
 804     updateMaxFieldCount();
 
 807   public void resolve(CompilationUnitScope upperScope) {
 
 808     // top level : scope are already created
 
 811     updateMaxFieldCount();
 
 814   public void tagAsHavingErrors() {
 
 815     ignoreFurtherInvestigation = true;
 
 818   public StringBuffer print(int indent, StringBuffer output) {
 
 820     //    if ((this.bits & IsAnonymousTypeMASK) == 0) {
 
 821     printIndent(indent, output);
 
 822     printHeader(0, output);
 
 824     return printBody(indent, output);
 
 827   public StringBuffer printBody(int indent, StringBuffer output) {
 
 829     output.append(" {"); //$NON-NLS-1$
 
 830     if (memberTypes != null) {
 
 831       for (int i = 0; i < memberTypes.length; i++) {
 
 832         if (memberTypes[i] != null) {
 
 834           memberTypes[i].print(indent + 1, output);
 
 838     if (fields != null) {
 
 839       for (int fieldI = 0; fieldI < fields.length; fieldI++) {
 
 840         if (fields[fieldI] != null) {
 
 842           fields[fieldI].print(indent + 1, output);
 
 846     if (methods != null) {
 
 847       for (int i = 0; i < methods.length; i++) {
 
 848         if (methods[i] != null) {
 
 850           methods[i].print(indent + 1, output);
 
 855     return printIndent(indent, output).append('}');
 
 858   public StringBuffer printHeader(int indent, StringBuffer output) {
 
 860     printModifiers(this.modifiers, output);
 
 861     output.append(isInterface() ? "interface " : "class "); //$NON-NLS-1$ //$NON-NLS-2$
 
 863     if (superclass != null) {
 
 864       output.append(" extends "); //$NON-NLS-1$
 
 865       superclass.print(0, output);
 
 867     if (superInterfaces != null && superInterfaces.length > 0) {
 
 868       output.append(isInterface() ? " extends " : " implements ");//$NON-NLS-2$ //$NON-NLS-1$
 
 869       for (int i = 0; i < superInterfaces.length; i++) {
 
 871           output.append(", "); //$NON-NLS-1$
 
 872         superInterfaces[i].print(0, output);
 
 878   public StringBuffer printStatement(int tab, StringBuffer output) {
 
 879     return print(tab, output);
 
 882   public String toString(int tab) {
 
 884     return tabString(tab) + toStringHeader() + toStringBody(tab);
 
 887   public String toStringBody(int tab) {
 
 889     String s = " {"; //$NON-NLS-1$
 
 890     if (memberTypes != null) {
 
 891       for (int i = 0; i < memberTypes.length; i++) {
 
 892         if (memberTypes[i] != null) {
 
 893           s += "\n" + memberTypes[i].toString(tab + 1); //$NON-NLS-1$
 
 897     if (fields != null) {
 
 898       for (int fieldI = 0; fieldI < fields.length; fieldI++) {
 
 899         if (fields[fieldI] != null) {
 
 900           s += "\n" + fields[fieldI].toString(tab + 1); //$NON-NLS-1$
 
 901           if (fields[fieldI].isField())
 
 902             s += ";"; //$NON-NLS-1$
 
 906     if (methods != null) {
 
 907       for (int i = 0; i < methods.length; i++) {
 
 908         if (methods[i] != null) {
 
 909           s += "\n" + methods[i].toString(tab + 1); //$NON-NLS-1$
 
 913     s += "\n" + tabString(tab) + "}"; //$NON-NLS-2$ //$NON-NLS-1$
 
 917   public String toStringHeader() {
 
 919     String s = ""; //$NON-NLS-1$
 
 920     if (modifiers != AccDefault) {
 
 921       s += modifiersString(modifiers);
 
 923     s += (isInterface() ? "interface " : "class ") + new String(name);//$NON-NLS-1$ //$NON-NLS-2$
 
 924     if (superclass != null)
 
 925       s += " extends " + superclass.toString(0); //$NON-NLS-1$
 
 926     if (superInterfaces != null && superInterfaces.length > 0) {
 
 927       s += (isInterface() ? " extends " : " implements ");//$NON-NLS-2$ //$NON-NLS-1$
 
 928       for (int i = 0; i < superInterfaces.length; i++) {
 
 929         s += superInterfaces[i].toString(0);
 
 930         if (i != superInterfaces.length - 1)
 
 931           s += ", "; //$NON-NLS-1$
 
 940    * Iteration for a local innertype
 
 943   public void traverse(ASTVisitor visitor, BlockScope blockScope) {
 
 944     if (ignoreFurtherInvestigation)
 
 947       if (visitor.visit(this, blockScope)) {
 
 948         if (superclass != null)
 
 949           superclass.traverse(visitor, scope);
 
 950         if (superInterfaces != null) {
 
 951           int superInterfaceLength = superInterfaces.length;
 
 952           for (int i = 0; i < superInterfaceLength; i++)
 
 953             superInterfaces[i].traverse(visitor, scope);
 
 955         if (memberTypes != null) {
 
 956           int memberTypesLength = memberTypes.length;
 
 957           for (int i = 0; i < memberTypesLength; i++)
 
 958             memberTypes[i].traverse(visitor, scope);
 
 960         if (fields != null) {
 
 961           int fieldsLength = fields.length;
 
 962           for (int i = 0; i < fieldsLength; i++) {
 
 963             FieldDeclaration field;
 
 964             if ((field = fields[i]).isStatic()) {
 
 965               // local type cannot have static fields
 
 967               field.traverse(visitor, initializerScope);
 
 971         if (methods != null) {
 
 972           int methodsLength = methods.length;
 
 973           for (int i = 0; i < methodsLength; i++)
 
 974             methods[i].traverse(visitor, scope);
 
 977       visitor.endVisit(this, blockScope);
 
 978     } catch (AbortType e) {
 
 984    * Iteration for a member innertype
 
 987   public void traverse(ASTVisitor visitor, ClassScope classScope) {
 
 988     if (ignoreFurtherInvestigation)
 
 991       if (visitor.visit(this, classScope)) {
 
 992         if (superclass != null)
 
 993           superclass.traverse(visitor, scope);
 
 994         if (superInterfaces != null) {
 
 995           int superInterfaceLength = superInterfaces.length;
 
 996           for (int i = 0; i < superInterfaceLength; i++)
 
 997             superInterfaces[i].traverse(visitor, scope);
 
 999         if (memberTypes != null) {
 
1000           int memberTypesLength = memberTypes.length;
 
1001           for (int i = 0; i < memberTypesLength; i++)
 
1002             memberTypes[i].traverse(visitor, scope);
 
1004         if (fields != null) {
 
1005           int fieldsLength = fields.length;
 
1006           for (int i = 0; i < fieldsLength; i++) {
 
1007             FieldDeclaration field;
 
1008             if ((field = fields[i]).isStatic()) {
 
1009               field.traverse(visitor, staticInitializerScope);
 
1011               field.traverse(visitor, initializerScope);
 
1015         if (methods != null) {
 
1016           int methodsLength = methods.length;
 
1017           for (int i = 0; i < methodsLength; i++)
 
1018             methods[i].traverse(visitor, scope);
 
1021       visitor.endVisit(this, classScope);
 
1022     } catch (AbortType e) {
 
1028    * Iteration for a package member type
 
1031   public void traverse(ASTVisitor visitor, CompilationUnitScope unitScope) {
 
1033     if (ignoreFurtherInvestigation)
 
1036       if (visitor.visit(this, unitScope)) {
 
1037         if (superclass != null)
 
1038           superclass.traverse(visitor, scope);
 
1039         if (superInterfaces != null) {
 
1040           int superInterfaceLength = superInterfaces.length;
 
1041           for (int i = 0; i < superInterfaceLength; i++)
 
1042             superInterfaces[i].traverse(visitor, scope);
 
1044         if (memberTypes != null) {
 
1045           int memberTypesLength = memberTypes.length;
 
1046           for (int i = 0; i < memberTypesLength; i++)
 
1047             memberTypes[i].traverse(visitor, scope);
 
1049         if (fields != null) {
 
1050           int fieldsLength = fields.length;
 
1051           for (int i = 0; i < fieldsLength; i++) {
 
1052             FieldDeclaration field;
 
1053             if ((field = fields[i]).isStatic()) {
 
1054               field.traverse(visitor, staticInitializerScope);
 
1056               field.traverse(visitor, initializerScope);
 
1060         if (methods != null) {
 
1061           int methodsLength = methods.length;
 
1062           for (int i = 0; i < methodsLength; i++)
 
1063             methods[i].traverse(visitor, scope);
 
1066       visitor.endVisit(this, unitScope);
 
1067     } catch (AbortType e) {
 
1072    * MaxFieldCount's computation is necessary so as to reserve space for the flow info field portions. It corresponds to the maximum
 
1073    * amount of fields this class or one of its innertypes have.
 
1075    * During name resolution, types are traversed, and the max field count is recorded on the outermost type. It is then propagated
 
1076    * down during the flow analysis.
 
1078    * This method is doing either up/down propagation.
 
1080   void updateMaxFieldCount() {
 
1082     if (binding == null)
 
1083       return; // error scenario
 
1084     TypeDeclaration outerMostType = scope.outerMostClassScope().referenceType();
 
1085     if (maxFieldCount > outerMostType.maxFieldCount) {
 
1086       outerMostType.maxFieldCount = maxFieldCount; // up
 
1088       maxFieldCount = outerMostType.maxFieldCount; // down