X-Git-Url: http://secure.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/TypeDeclaration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/TypeDeclaration.java index ca49457..5312f66 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/TypeDeclaration.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/TypeDeclaration.java @@ -35,1055 +35,1166 @@ 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 class TypeDeclaration extends Statement implements ProblemSeverities, + ReferenceContext { - public int modifiers; + public int modifiers; - public int modifiersSourceStart; + public int modifiersSourceStart; - public char[] name; + public char[] name; - public TypeReference superclass; + public TypeReference superclass; - public TypeReference[] superInterfaces; + public TypeReference[] superInterfaces; - public FieldDeclaration[] fields; + public FieldDeclaration[] fields; - public AbstractMethodDeclaration[] methods; + public AbstractMethodDeclaration[] methods; - public TypeDeclaration[] memberTypes; + public TypeDeclaration[] memberTypes; - public SourceTypeBinding binding; + public SourceTypeBinding binding; - public ClassScope scope; + public ClassScope scope; - public MethodScope initializerScope; + public MethodScope initializerScope; - public MethodScope staticInitializerScope; + public MethodScope staticInitializerScope; - public boolean ignoreFurtherInvestigation = false; + public boolean ignoreFurtherInvestigation = false; - public int maxFieldCount; + 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 - } - } + 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 + } + } } \ No newline at end of file