/*********************************************************************************************************************************** * Copyright (c) 2000, 2003 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 net.sourceforge.phpdt.internal.compiler.ast; import net.sourceforge.phpdt.core.compiler.CharOperation; import net.sourceforge.phpdt.internal.compiler.ASTVisitor; import net.sourceforge.phpdt.internal.compiler.CompilationResult; import net.sourceforge.phpdt.internal.compiler.flow.FlowContext; import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo; import net.sourceforge.phpdt.internal.compiler.flow.InitializationFlowContext; import net.sourceforge.phpdt.internal.compiler.flow.UnconditionalFlowInfo; import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext; import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; import net.sourceforge.phpdt.internal.compiler.lookup.ClassScope; import net.sourceforge.phpdt.internal.compiler.lookup.CompilationUnitScope; import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding; import net.sourceforge.phpdt.internal.compiler.lookup.LocalTypeBinding; import net.sourceforge.phpdt.internal.compiler.lookup.MemberTypeBinding; import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding; import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope; import net.sourceforge.phpdt.internal.compiler.lookup.NestedTypeBinding; import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding; import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding; import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; import net.sourceforge.phpdt.internal.compiler.parser.Parser; import net.sourceforge.phpdt.internal.compiler.parser.UnitParser; import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilation; import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilationUnit; import net.sourceforge.phpdt.internal.compiler.problem.AbortMethod; import net.sourceforge.phpdt.internal.compiler.problem.AbortType; import net.sourceforge.phpdt.internal.compiler.problem.ProblemSeverities; public class TypeDeclaration extends Statement implements ProblemSeverities, ReferenceContext { public int modifiers; 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 TypeDeclaration(CompilationResult compilationResult) { this.compilationResult = compilationResult; } /* * We cause the compilation task to abort to a given extent. */ public void abort(int abortLevel) { if (scope == null) { throw new AbortCompilation(); // cannot do better } CompilationResult compilationResult = scope.referenceCompilationUnit().compilationResult; switch (abortLevel) { case AbortCompilation: throw new AbortCompilation(compilationResult); case AbortCompilationUnit: throw new AbortCompilationUnit(compilationResult); case AbortMethod: throw new AbortMethod(compilationResult); default: throw new AbortType(compilationResult); } } /** * This method is responsible for adding a 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 net.sourceforge.phpdt.internal.compiler.codegen.ConstantPool#resetForClinit(int, * int) */ public final void addClinit() { // see comment on needClassInitMethod if (needClassInitMethod()) { int length; AbstractMethodDeclaration[] methods; if ((methods = this.methods) == null) { length = 0; methods = new AbstractMethodDeclaration[1]; } else { length = methods.length; System.arraycopy(methods, 0, (methods = new AbstractMethodDeclaration[length + 1]), 1, length); } Clinit clinit = new Clinit(this.compilationResult); methods[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 = methods; } } /** * Flow analysis for a local innertype * */ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { if (ignoreFurtherInvestigation) return flowInfo; try { bits |= IsReachableMASK; LocalTypeBinding localType = (LocalTypeBinding) binding; localType.setConstantPoolName(currentScope.compilationUnitScope() .computeConstantPoolName(localType)); manageEnclosingInstanceAccessIfNecessary(currentScope); 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 { bits |= IsReachableMASK; LocalTypeBinding localType = (LocalTypeBinding) binding; localType.setConstantPoolName(currentScope.compilationUnitScope() .computeConstantPoolName(localType)); manageEnclosingInstanceAccessIfNecessary(currentScope); 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 = new MethodDeclaration( this.compilationResult); m.sourceStart = c.sourceStart; m.sourceEnd = c.sourceEnd; m.bodyStart = c.bodyStart; m.bodyEnd = c.bodyEnd; m.declarationSourceEnd = c.declarationSourceEnd; m.declarationSourceStart = c.declarationSourceStart; m.selector = c.selector; m.statements = c.statements; m.modifiers = c.modifiers; m.arguments = c.arguments; m.thrownExceptions = c.thrownExceptions; m.explicitDeclarations = c.explicitDeclarations; m.returnType = null; 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 instanceof MemberTypeDeclaration) && (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; } /** * 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; } /* * 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); // } // // // 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 (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); } } ReferenceBinding[] defaultHandledExceptions = new ReferenceBinding[] { scope .getJavaLangThrowable() }; // tolerate any kind of // exception 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 = defaultHandledExceptions; // 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 = defaultHandledExceptions; // 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()) { // 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) { 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 superclass = binding.superclass; if (superclass.enclosingType() != null && !superclass.isStatic()) { if (!binding.superclass.isLocalType() || ((NestedTypeBinding) binding.superclass) .getSyntheticField(superclass.enclosingType(), true) != null) { nestedType.addSyntheticArgument(superclass.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) { NestedTypeBinding nestedType = (NestedTypeBinding) binding; nestedType.addSyntheticArgumentAndField(binding.enclosingType()); } /** * A 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 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(UnitParser parser, CompilationUnitDeclaration unit) { // connect method bodies if (unit.ignoreMethodBodies) return; // no scope were created, so cannot report further errors // if (binding == null) // 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 void resolve() { if (binding == null) { ignoreFurtherInvestigation = true; return; } try { // check superclass & interfaces if (binding.superclass != null) // watch out for Object ! (and other // roots) if (isTypeUseDeprecated(binding.superclass, scope)) scope.problemReporter().deprecatedType(binding.superclass, superclass); if (superInterfaces != null) for (int i = superInterfaces.length; --i >= 0;) if (superInterfaces[i].resolvedType != null) if (isTypeUseDeprecated( superInterfaces[i].resolvedType, scope)) scope.problemReporter().deprecatedType( superInterfaces[i].resolvedType, superInterfaces[i]); maxFieldCount = 0; int lastFieldID = -1; if (fields != null) { for (int i = 0, count = fields.length; i < count; i++) { FieldDeclaration field = fields[i]; if (field.isField()) { if (field.binding == null) { // still discover secondary errors if (field.initialization != null) field.initialization .resolve(field.isStatic() ? staticInitializerScope : initializerScope); ignoreFurtherInvestigation = true; continue; } maxFieldCount++; lastFieldID = field.binding.id; } else { // initializer ((Initializer) field).lastFieldID = lastFieldID + 1; } field.resolve(field.isStatic() ? staticInitializerScope : initializerScope); } } if (memberTypes != null) { for (int i = 0, count = memberTypes.length; i < count; i++) { memberTypes[i].resolve(scope); } } int missingAbstractMethodslength = this.missingAbstractMethods == null ? 0 : this.missingAbstractMethods.length; int methodsLength = this.methods == null ? 0 : methods.length; if ((methodsLength + missingAbstractMethodslength) > 0xFFFF) { scope.problemReporter().tooManyMethods(this); } if (methods != null) { for (int i = 0, count = methods.length; i < count; i++) { methods[i].resolve(scope); } } } 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 blockScope.addLocalType(this); // and TC.... 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; } 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 String toString(int tab) { return tabString(tab) + toStringHeader() + toStringBody(tab); } public String toStringBody(int tab) { String s = " {"; //$NON-NLS-1$ if (memberTypes != null) { for (int i = 0; i < memberTypes.length; i++) { if (memberTypes[i] != null) { s += "\n" + memberTypes[i].toString(tab + 1); //$NON-NLS-1$ } } } if (fields != null) { for (int fieldI = 0; fieldI < fields.length; fieldI++) { if (fields[fieldI] != null) { s += "\n" + fields[fieldI].toString(tab + 1); //$NON-NLS-1$ if (fields[fieldI].isField()) s += ";"; //$NON-NLS-1$ } } } if (methods != null) { for (int i = 0; i < methods.length; i++) { if (methods[i] != null) { s += "\n" + methods[i].toString(tab + 1); //$NON-NLS-1$ } } } s += "\n" + tabString(tab) + "}"; //$NON-NLS-2$ //$NON-NLS-1$ return s; } public String toStringHeader() { String s = ""; //$NON-NLS-1$ if (modifiers != AccDefault) { s += modifiersString(modifiers); } s += (isInterface() ? "interface " : "class ") + new String(name);//$NON-NLS-1$ //$NON-NLS-2$ if (superclass != null) s += " extends " + superclass.toString(0); //$NON-NLS-1$ if (superInterfaces != null && superInterfaces.length > 0) { s += (isInterface() ? " extends " : " implements ");//$NON-NLS-2$ //$NON-NLS-1$ for (int i = 0; i < superInterfaces.length; i++) { s += superInterfaces[i].toString(0); if (i != superInterfaces.length - 1) s += ", "; //$NON-NLS-1$ } ; } ; return s; } /** * 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 } } /** * 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) { } } /** * 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 } } }