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 7c80680..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 @@ -1,22 +1,19 @@ -/******************************************************************************* - * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Common Public License v0.5 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v05.html +/*********************************************************************************************************************************** + * 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.phpdt.internal.compiler.ast; -import net.sourceforge.phpdt.internal.compiler.ClassFile; +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.codegen.CodeStream; import net.sourceforge.phpdt.internal.compiler.flow.FlowContext; import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo; import net.sourceforge.phpdt.internal.compiler.flow.InitializationFlowContext; +import net.sourceforge.phpdt.internal.compiler.flow.UnconditionalFlowInfo; import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext; import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; import net.sourceforge.phpdt.internal.compiler.lookup.ClassScope; @@ -27,48 +24,68 @@ import net.sourceforge.phpdt.internal.compiler.lookup.MemberTypeBinding; import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding; import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope; import net.sourceforge.phpdt.internal.compiler.lookup.NestedTypeBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding; import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding; import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; import net.sourceforge.phpdt.internal.compiler.parser.Parser; +import net.sourceforge.phpdt.internal.compiler.parser.UnitParser; import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilation; import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilationUnit; import net.sourceforge.phpdt.internal.compiler.problem.AbortMethod; import net.sourceforge.phpdt.internal.compiler.problem.AbortType; import net.sourceforge.phpdt.internal.compiler.problem.ProblemSeverities; -import net.sourceforge.phpdt.internal.compiler.util.CharOperation; -public class TypeDeclaration - extends Statement - implements ProblemSeverities, ReferenceContext { +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 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){ + public TypeDeclaration(CompilationResult compilationResult) { this.compilationResult = compilationResult; } - + /* - * We cause the compilation task to abort to a given extent. + * We cause the compilation task to abort to a given extent. */ public void abort(int abortLevel) { @@ -76,33 +93,36 @@ public class TypeDeclaration throw new AbortCompilation(); // cannot do better } - CompilationResult compilationResult = - scope.referenceCompilationUnit().compilationResult; + 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); + 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. + * 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) + * @see net.sourceforge.phpdt.internal.compiler.codegen.ConstantPool#resetForClinit(int, + * int) */ public final void addClinit() { - //see comment on needClassInitMethod + // see comment on needClassInitMethod if (needClassInitMethod()) { int length; AbstractMethodDeclaration[] methods; @@ -111,16 +131,14 @@ public class TypeDeclaration methods = new AbstractMethodDeclaration[1]; } else { length = methods.length; - System.arraycopy( - methods, - 0, - (methods = new AbstractMethodDeclaration[length + 1]), - 1, - 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 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; @@ -129,75 +147,24 @@ public class TypeDeclaration } /** - * Flow analysis for a local innertype - * + * Flow analysis for a local innertype + * */ - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { + public FlowInfo analyseCode(BlockScope currentScope, + FlowContext flowContext, FlowInfo flowInfo) { if (ignoreFurtherInvestigation) return flowInfo; try { - // remember local types binding for innerclass emulation propagation - currentScope.referenceCompilationUnit().record((LocalTypeBinding) binding); + bits |= IsReachableMASK; + LocalTypeBinding localType = (LocalTypeBinding) binding; - InitializationFlowContext initializerContext = - new InitializationFlowContext(null, this, initializerScope); - // propagate down the max field count - updateMaxFieldCount(); - FlowInfo fieldInfo = flowInfo.copy(); - // so as not to propagate changes outside this type - if (fields != null) { - for (int i = 0, count = fields.length; i < count; i++) { - fieldInfo = - fields[i].analyseCode(initializerScope, initializerContext, fieldInfo); - if (fieldInfo == FlowInfo.DeadEnd) { - // 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. - initializerScope.problemReporter().initializerMustCompleteNormally(fields[i]); - fieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true); - } - } - } - if (memberTypes != null) { - for (int i = 0, count = memberTypes.length; i < count; i++) { - memberTypes[i].analyseCode(scope, flowContext, fieldInfo.copy()); - } - } - if (methods != null) { - int recursionBalance = 0; // check constructor recursions - for (int i = 0, count = methods.length; i < count; i++) { - AbstractMethodDeclaration method = methods[i]; - if (method.ignoreFurtherInvestigation) - continue; - if (method.isConstructor()) { // constructor - ConstructorDeclaration constructor = (ConstructorDeclaration) method; - constructor.analyseCode(scope, initializerContext, fieldInfo.copy()); - // compute the recursive invocation balance: - // how many thisReferences vs. superReferences to constructors - int refCount; - if ((refCount = constructor.referenceCount) > 0) { - if ((constructor.constructorCall == null) - || constructor.constructorCall.isSuperAccess() - || !constructor.constructorCall.binding.isValidBinding()) { - recursionBalance -= refCount; - constructor.referenceCount = -1; - // for error reporting propagation - } else { - recursionBalance += refCount; - } - } - } else { // regular method - method.analyseCode(scope, null, flowInfo.copy()); - } - } - if (recursionBalance > 0) { - // there is one or more cycle(s) amongst constructor invocations - scope.problemReporter().recursiveConstructorInvocation(this); - } - } + localType.setConstantPoolName(currentScope.compilationUnitScope() + .computeConstantPoolName(localType)); + manageEnclosingInstanceAccessIfNecessary(currentScope); + + updateMaxFieldCount(); // propagate down the max field count + internalAnalyseCode(flowContext, flowInfo); } catch (AbortType e) { this.ignoreFurtherInvestigation = true; } @@ -205,288 +172,85 @@ public class TypeDeclaration } /** - * Flow analysis for a member innertype - * + * Flow analysis for a member innertype + * */ - public void analyseCode(ClassScope classScope1) { + public void analyseCode(ClassScope enclosingClassScope) { if (ignoreFurtherInvestigation) return; try { // propagate down the max field count updateMaxFieldCount(); - FlowInfo flowInfo = FlowInfo.initial(maxFieldCount); // start fresh init info - InitializationFlowContext initializerContext = - new InitializationFlowContext(null, this, initializerScope); - InitializationFlowContext staticInitializerContext = - new InitializationFlowContext(null, this, staticInitializerScope); - FlowInfo nonStaticFieldInfo = flowInfo.copy(), - staticFieldInfo = flowInfo.copy(); - if (fields != null) { - for (int i = 0, count = fields.length; i < count; i++) { - if (fields[i].isStatic()) { - staticFieldInfo = - fields[i].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.DeadEnd) { - staticInitializerScope.problemReporter().initializerMustCompleteNormally( - fields[i]); - staticFieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true); - } - } else { - nonStaticFieldInfo = - fields[i].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.DeadEnd) { - initializerScope.problemReporter().initializerMustCompleteNormally(fields[i]); - nonStaticFieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true); - } - } - } - } - if (memberTypes != null) { - for (int i = 0, count = memberTypes.length; i < count; i++) { - memberTypes[i].analyseCode(scope); - } - } - if (methods != null) { - int recursionBalance = 0; // check constructor recursions - for (int i = 0, count = methods.length; i < count; i++) { - AbstractMethodDeclaration method = methods[i]; - if (method.ignoreFurtherInvestigation) - continue; - if (method.isInitializationMethod()) { - if (method.isStatic()) { // - ((Clinit) method).analyseCode(scope, staticInitializerContext, staticFieldInfo); - } else { // constructor - ConstructorDeclaration constructor = (ConstructorDeclaration) method; - constructor.analyseCode(scope, initializerContext, nonStaticFieldInfo.copy()); - // compute the recursive invocation balance: - // how many thisReferences vs. superReferences to constructors - int refCount; - if ((refCount = constructor.referenceCount) > 0) { - if ((constructor.constructorCall == null) - || constructor.constructorCall.isSuperAccess() - || !constructor.constructorCall.binding.isValidBinding()) { - recursionBalance -= refCount; - constructor.referenceCount = -1; // for error reporting propagation - } else { - recursionBalance += refCount; - } - } - } - } else { // regular method - method.analyseCode(scope, null, FlowInfo.initial(maxFieldCount)); - } - } - if (recursionBalance > 0) { - // there is one or more cycle(s) amongst constructor invocations - scope.problemReporter().recursiveConstructorInvocation(this); - } - } + internalAnalyseCode(null, FlowInfo.initial(maxFieldCount)); } catch (AbortType e) { this.ignoreFurtherInvestigation = true; - }; + } } /** - * Flow analysis for a local member innertype - * + * Flow analysis for a local member innertype + * */ - public void analyseCode( - ClassScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { + public void analyseCode(ClassScope currentScope, FlowContext flowContext, + FlowInfo flowInfo) { if (ignoreFurtherInvestigation) return; try { - // remember local types binding for innerclass emulation propagation - currentScope.referenceCompilationUnit().record((LocalTypeBinding) binding); - - /* force to emulation of access to direct enclosing instance: only for local members. - * 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. - */ - initializerScope.emulateOuterAccess( - (SourceTypeBinding) binding.enclosingType(), - false); - - InitializationFlowContext initializerContext = - new InitializationFlowContext(null, this, initializerScope); - // propagate down the max field count - updateMaxFieldCount(); - FlowInfo fieldInfo = flowInfo.copy(); - // so as not to propagate changes outside this type - if (fields != null) { - for (int i = 0, count = fields.length; i < count; i++) { - if (!fields[i].isStatic()) { - fieldInfo = - fields[i].analyseCode(initializerScope, initializerContext, fieldInfo); - if (fieldInfo == FlowInfo.DeadEnd) { - // 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. - initializerScope.problemReporter().initializerMustCompleteNormally(fields[i]); - fieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true); - } - } - } - } - if (memberTypes != null) { - for (int i = 0, count = memberTypes.length; i < count; i++) { - memberTypes[i].analyseCode(scope, flowContext, fieldInfo.copy()); - } - } - if (methods != null) { - int recursionBalance = 0; // check constructor recursions - for (int i = 0, count = methods.length; i < count; i++) { - AbstractMethodDeclaration method = methods[i]; - if (method.ignoreFurtherInvestigation) - continue; - if (method.isConstructor()) { // constructor - ConstructorDeclaration constructor = (ConstructorDeclaration) method; - constructor.analyseCode(scope, initializerContext, fieldInfo.copy()); - // compute the recursive invocation balance: - // how many thisReferences vs. superReferences to constructors - int refCount; - if ((refCount = constructor.referenceCount) > 0) { - if ((constructor.constructorCall == null) - || constructor.constructorCall.isSuperAccess() - || !constructor.constructorCall.binding.isValidBinding()) { - recursionBalance -= refCount; - constructor.referenceCount = -1; // for error reporting propagation - } else { - recursionBalance += refCount; - } - } - } else { // regular method - method.analyseCode(scope, null, flowInfo.copy()); - } - } - if (recursionBalance > 0) { - // there is one or more cycle(s) amongst constructor invocations - scope.problemReporter().recursiveConstructorInvocation(this); - } - } + 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 - * + * Flow analysis for a package member type + * */ public void analyseCode(CompilationUnitScope unitScope) { if (ignoreFurtherInvestigation) return; try { - FlowInfo flowInfo = FlowInfo.initial(maxFieldCount); // start fresh init info - InitializationFlowContext initializerContext = - new InitializationFlowContext(null, this, initializerScope); - InitializationFlowContext staticInitializerContext = - new InitializationFlowContext(null, this, staticInitializerScope); - FlowInfo nonStaticFieldInfo = flowInfo.copy(), - staticFieldInfo = flowInfo.copy(); - if (fields != null) { - for (int i = 0, count = fields.length; i < count; i++) { - if (fields[i].isStatic()) { - staticFieldInfo = - fields[i].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.DeadEnd) { - staticInitializerScope.problemReporter().initializerMustCompleteNormally( - fields[i]); - staticFieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true); - } - } else { - nonStaticFieldInfo = - fields[i].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.DeadEnd) { - initializerScope.problemReporter().initializerMustCompleteNormally(fields[i]); - nonStaticFieldInfo = FlowInfo.initial(maxFieldCount).markAsFakeReachable(true); - } - } - } - } - if (memberTypes != null) { - for (int i = 0, count = memberTypes.length; i < count; i++) { - memberTypes[i].analyseCode(scope); - } - } - if (methods != null) { - int recursionBalance = 0; // check constructor recursions - for (int i = 0, count = methods.length; i < count; i++) { - AbstractMethodDeclaration method = methods[i]; - if (method.ignoreFurtherInvestigation) - continue; - if (method.isInitializationMethod()) { - if (method.isStatic()) { // - ((Clinit) method).analyseCode(scope, staticInitializerContext, staticFieldInfo); - } else { // constructor - ConstructorDeclaration constructor = (ConstructorDeclaration) method; - constructor.analyseCode(scope, initializerContext, nonStaticFieldInfo.copy()); - // compute the recursive invocation balance: - // how many thisReferences vs. superReferences to constructors - int refCount; - if ((refCount = constructor.referenceCount) > 0) { - if ((constructor.constructorCall == null) - || constructor.constructorCall.isSuperAccess() - || !constructor.constructorCall.binding.isValidBinding()) { - recursionBalance -= refCount; - constructor.referenceCount = -1; // for error reporting propagation - } else { - recursionBalance += refCount; - } - } - } - } else { // regular method - method.analyseCode(scope, null, FlowInfo.initial(maxFieldCount)); - } - } - if (recursionBalance > 0) { - // there is one or more cycle(s) amongst constructor invocations - scope.problemReporter().recursiveConstructorInvocation(this); - } - } + 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 + * 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 + // 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 + // 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); + || (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; @@ -505,8 +269,9 @@ public class TypeDeclaration } else { if (this.isInterface()) { // report the problem and continue the parsing - parser.problemReporter().interfaceCannotHaveConstructors( - (ConstructorDeclaration) am); + parser.problemReporter() + .interfaceCannotHaveConstructors( + (ConstructorDeclaration) am); } hasConstructor = true; } @@ -522,51 +287,48 @@ public class TypeDeclaration } public ConstructorDeclaration createsInternalConstructor( - boolean needExplicitConstructorCall, - boolean needToInsert) { + 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) + // 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); + // 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 + constructor.modifiers = ((this instanceof MemberTypeDeclaration) && (modifiers & AccPrivate) != 0) ? AccDefault : modifiers & AccVisibilityMASK; } - //if you change this setting, please update the - //SourceIndexer2.buildTypeDeclaration(TypeDeclaration,char[]) method + // 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; + constructor.declarationSourceEnd = constructor.sourceEnd = constructor.bodyEnd = sourceEnd; - //the super call inside the constructor + // the super call inside the constructor if (needExplicitConstructorCall) { - constructor.constructorCall = - new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); + constructor.constructorCall = SuperReference + .implicitSuperConstructorCall(); constructor.constructorCall.sourceStart = sourceStart; constructor.constructorCall.sourceEnd = sourceEnd; } - //adding the constructor in the methods list + // 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); + System + .arraycopy( + methods, + 0, + newMethods = new AbstractMethodDeclaration[methods.length + 1], + 1, methods.length); newMethods[0] = constructor; methods = newMethods; } @@ -575,72 +337,72 @@ public class TypeDeclaration } /** - * INTERNAL USE ONLY - Creates a fake method declaration for the corresponding binding. - * It is used to report errors for missing abstract methods. + * 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) { + public MethodDeclaration addMissingAbstractMethodFor( + MethodBinding methodBinding) { TypeBinding[] argumentTypes = methodBinding.parameters; int argumentsLength = argumentTypes.length; - //the constructor - MethodDeclaration methodDeclaration = new MethodDeclaration(this.compilationResult); + // the constructor + MethodDeclaration methodDeclaration = new MethodDeclaration( + this.compilationResult); methodDeclaration.selector = methodBinding.selector; methodDeclaration.sourceStart = sourceStart; methodDeclaration.sourceEnd = sourceEnd; - methodDeclaration.modifiers = methodBinding.getAccessFlags() & ~AccAbstract; + 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); + arguments[i] = new Argument((baseName + i).toCharArray(), 0L, + null /* type ref */, AccDefault); } } - //adding the constructor in the methods list + // 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); + System + .arraycopy( + this.missingAbstractMethods, + 0, + newMethods = new MethodDeclaration[this.missingAbstractMethods.length + 1], + 1, this.missingAbstractMethods.length); newMethods[0] = methodDeclaration; this.missingAbstractMethods = newMethods; } - //============BINDING UPDATE========================== + // ============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.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; - }*/ - //=================================================== - + /* + * 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 */ @@ -688,11 +450,10 @@ public class TypeDeclaration } /* - * 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} + * 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) { @@ -706,7 +467,8 @@ public class TypeDeclaration 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); + TypeDeclaration typeDecl = this.memberTypes[i] + .declarationOfType(subTypeName); if (typeDecl != null) { return typeDecl; } @@ -717,118 +479,281 @@ public class TypeDeclaration /** * Generic bytecode generation for type */ - public void generateCode(ClassFile enclosingClassFile) { + // 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; + } - 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); + /** + * 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); } - 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); + } + + 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); + } } } - // generate all methods - classFile.setForMethodInfos(); - if (methods != null) { - for (int i = 0, max = methods.length; i < max; i++) { - methods[i].generateCode(scope, classFile); + } + 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); } } - - 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); + } + 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()); + } } - - // 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) { + public boolean isInterface() { - if (hasBeenGenerated) - return; - int pc = codeStream.position; - if (binding != null) { - ((NestedTypeBinding) binding).computeSyntheticArgumentsOffset(); - } - generateCode(codeStream.classFile); - codeStream.recordPositionsFrom(pc, this.sourceStart); + return (modifiers & AccInterface) != 0; } - /** - * Bytecode generation for a member inner type + /* + * 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 generateCode(ClassScope classScope, ClassFile enclosingClassFile) { + public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) { - if (hasBeenGenerated) - return; - ((NestedTypeBinding) binding).computeSyntheticArgumentsOffset(); - generateCode(enclosingClassFile); - } + NestedTypeBinding nestedType = (NestedTypeBinding) binding; - /** - * Bytecode generation for a package member - */ - public void generateCode(CompilationUnitScope unitScope) { + MethodScope methodScope = currentScope.methodScope(); + if (!methodScope.isStatic && !methodScope.isConstructorCall) { - generateCode((ClassFile) null); + 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()); + } + } + } } - public boolean isInterface() { - - return (modifiers & AccInterface) != 0; - } + /* + * 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) { - public boolean hasErrors() { - return this.ignoreFurtherInvestigation; + 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. + * 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() { @@ -841,40 +766,44 @@ public class TypeDeclaration 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 + // need to test the modifier directly while there is no binding yet if ((field.modifiers & AccStatic) != 0) return true; } return false; } - public void parseMethod(Parser parser, CompilationUnitDeclaration unit) { + public void parseMethod(UnitParser parser, CompilationUnitDeclaration unit) { - //connect method bodies + // connect method bodies if (unit.ignoreMethodBodies) return; // no scope were created, so cannot report further errors -// if (binding == null) -// return; + // if (binding == null) + // return; - //members + // members if (memberTypes != null) { - for (int i = memberTypes.length; --i >= 0;) + int length = memberTypes.length; + for (int i = 0; i < length; i++) memberTypes[i].parseMethod(parser, unit); } - //methods + // methods if (methods != null) { - for (int i = methods.length; --i >= 0;) + int length = methods.length; + for (int i = 0; i < length; i++) methods[i].parseStatements(parser, unit); } - //initializers + // initializers if (fields != null) { - for (int i = fields.length; --i >= 0;) { + int length = fields.length; + for (int i = 0; i < length; i++) { if (fields[i] instanceof Initializer) { - ((Initializer) fields[i]).parseStatements(parser, this, unit); + ((Initializer) fields[i]).parseStatements(parser, this, + unit); } } } @@ -889,16 +818,19 @@ public class TypeDeclaration try { // check superclass & interfaces - if (binding.superclass != null) // watch out for Object ! (and other roots) + if (binding.superclass != null) // watch out for Object ! (and other + // roots) if (isTypeUseDeprecated(binding.superclass, scope)) - scope.problemReporter().deprecatedType(binding.superclass, superclass); + scope.problemReporter().deprecatedType(binding.superclass, + superclass); if (superInterfaces != null) for (int i = superInterfaces.length; --i >= 0;) - if (superInterfaces[i].binding != null) - if (isTypeUseDeprecated(superInterfaces[i].binding, scope)) + if (superInterfaces[i].resolvedType != null) + if (isTypeUseDeprecated( + superInterfaces[i].resolvedType, scope)) scope.problemReporter().deprecatedType( - superInterfaces[i].binding, - superInterfaces[i]); + superInterfaces[i].resolvedType, + superInterfaces[i]); maxFieldCount = 0; int lastFieldID = -1; if (fields != null) { @@ -906,27 +838,45 @@ public class TypeDeclaration 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; + ((Initializer) field).lastFieldID = lastFieldID + 1; } - field.resolve(field.isStatic() ? staticInitializerScope : initializerScope); + field.resolve(field.isStatic() ? staticInitializerScope + : initializerScope); } } - if (memberTypes != null) - for (int i = 0, count = memberTypes.length; i < count; i++) + if (memberTypes != null) { + for (int i = 0, count = memberTypes.length; i < count; i++) { memberTypes[i].resolve(scope); - if (methods != null) - for (int i = 0, count = methods.length; i < count; i++) + } + } + 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) { @@ -937,6 +887,10 @@ public class TypeDeclaration // 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(); @@ -947,6 +901,11 @@ public class TypeDeclaration // 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(); } @@ -962,6 +921,70 @@ public class TypeDeclaration 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); @@ -1012,18 +1035,106 @@ public class TypeDeclaration s += superInterfaces[i].toString(0); if (i != superInterfaces.length - 1) s += ", "; //$NON-NLS-1$ - }; - }; + } + ; + } + ; return s; } /** - * Iteration for a package member type - * + * Iteration for a local innertype + * */ - public void traverse( - IAbstractSyntaxTreeVisitor visitor, - CompilationUnitScope unitScope) { + 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; @@ -1058,25 +1169,28 @@ public class TypeDeclaration 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. - * + * 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(); + TypeDeclaration outerMostType = scope.outerMostClassScope() + .referenceType(); if (maxFieldCount > outerMostType.maxFieldCount) { outerMostType.maxFieldCount = maxFieldCount; // up } else {