X-Git-Url: http://secure.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/internal/compiler/ast/TypeDeclaration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/internal/compiler/ast/TypeDeclaration.java index 308f852..6bf3530 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/internal/compiler/ast/TypeDeclaration.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/internal/compiler/ast/TypeDeclaration.java @@ -1,18 +1,17 @@ -/******************************************************************************* - * 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 +/*********************************************************************************************************************************** + * 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 - *******************************************************************************/ + * Contributors: IBM Corporation - initial API and implementation + **********************************************************************************************************************************/ package net.sourceforge.phpeclipse.internal.compiler.ast; +import net.sourceforge.phpeclipse.internal.compiler.ast.FieldDeclaration; + 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.IAbstractSyntaxTreeVisitor; import net.sourceforge.phpdt.internal.compiler.flow.FlowContext; import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo; import net.sourceforge.phpdt.internal.compiler.flow.InitializationFlowContext; @@ -38,943 +37,1055 @@ 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 MemberTypeDeclaration[] 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 org.eclipse.jdt.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 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 package member type - * - */ - public void traverse( - IAbstractSyntaxTreeVisitor 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 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 + } + } +} \ No newline at end of file