A massive organize imports and formatting of the sources using default Eclipse code...
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / ConstructorDeclaration.java
index a47678b..e43ddcb 100644 (file)
@@ -1,87 +1,89 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
+ * 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 v0.5 
+ * 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-v05.html
+ * http://www.eclipse.org/legal/cpl-v10.html
  * 
  * Contributors:
  *     IBM Corporation - initial API and implementation
- ******************************************************************************/
+ *******************************************************************************/
 package net.sourceforge.phpdt.internal.compiler.ast;
 
 import java.util.ArrayList;
 
-import net.sourceforge.phpdt.core.compiler.IProblem;
-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.ExceptionHandlingFlowContext;
 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
 import net.sourceforge.phpdt.internal.compiler.flow.InitializationFlowContext;
 import net.sourceforge.phpdt.internal.compiler.lookup.ClassScope;
 import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding;
-import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
-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.SyntheticArgumentBinding;
-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.AbortMethod;
-import net.sourceforge.phpdt.internal.compiler.util.CharOperation;
 
 public class ConstructorDeclaration extends AbstractMethodDeclaration {
 
        public ExplicitConstructorCall constructorCall;
+
        public final static char[] ConstantPoolName = "<init>".toCharArray(); //$NON-NLS-1$
-       public boolean isDefaultConstructor = false;
 
-       public int referenceCount = 0;
-       // count how many times this constructor is referenced from other local constructors
+       public boolean isDefaultConstructor = false;
 
-       public ConstructorDeclaration(CompilationResult compilationResult){
+       public ConstructorDeclaration(CompilationResult compilationResult) {
                super(compilationResult);
        }
-       
-       public void analyseCode(
-               ClassScope classScope,
-               InitializationFlowContext initializerFlowContext,
-               FlowInfo flowInfo) {
+
+       public void analyseCode(ClassScope classScope,
+                       InitializationFlowContext initializerFlowContext, FlowInfo flowInfo) {
 
                if (ignoreFurtherInvestigation)
                        return;
+
+               if (this.binding != null && this.binding.isPrivate()
+                               && !this.binding.isPrivateUsed()) {
+                       if (!classScope.referenceCompilationUnit().compilationResult
+                                       .hasSyntaxError()) {
+                               scope.problemReporter().unusedPrivateConstructor(this);
+                       }
+               }
+
+               // check constructor recursion, once all constructor got resolved
+               if (isRecursive(null /* lazy initialized visited list */)) {
+                       this.scope.problemReporter().recursiveConstructorInvocation(
+                                       this.constructorCall);
+               }
+
                try {
-                       ExceptionHandlingFlowContext constructorContext =
-                               new ExceptionHandlingFlowContext(
-                                       initializerFlowContext.parent,
-                                       this,
-                                       binding.thrownExceptions,
-                                       scope,
-                                       FlowInfo.DeadEnd);
-                       initializerFlowContext.checkInitializerExceptions(
-                               scope,
-                               constructorContext,
-                               flowInfo);
-
-                       // anonymous constructor can gain extra thrown exceptions from unhandled ones
+                       ExceptionHandlingFlowContext constructorContext = new ExceptionHandlingFlowContext(
+                                       initializerFlowContext.parent, this,
+                                       binding.thrownExceptions, scope, FlowInfo.DEAD_END);
+                       initializerFlowContext.checkInitializerExceptions(scope,
+                                       constructorContext, flowInfo);
+
+                       // anonymous constructor can gain extra thrown exceptions from
+                       // unhandled ones
                        if (binding.declaringClass.isAnonymousType()) {
                                ArrayList computedExceptions = constructorContext.extendedExceptions;
-                               if (computedExceptions != null){
+                               if (computedExceptions != null) {
                                        int size;
-                                       if ((size = computedExceptions.size()) > 0){
+                                       if ((size = computedExceptions.size()) > 0) {
                                                ReferenceBinding[] actuallyThrownExceptions;
-                                               computedExceptions.toArray(actuallyThrownExceptions = new ReferenceBinding[size]);
+                                               computedExceptions
+                                                               .toArray(actuallyThrownExceptions = new ReferenceBinding[size]);
                                                binding.thrownExceptions = actuallyThrownExceptions;
                                        }
                                }
                        }
-                       
+
                        // propagate to constructor call
                        if (constructorCall != null) {
-                               // if calling 'this(...)', then flag all non-static fields as definitely
-                               // set since they are supposed to be set inside other local constructor
+                               // if calling 'this(...)', then flag all non-static fields as
+                               // definitely
+                               // set since they are supposed to be set inside other local
+                               // constructor
                                if (constructorCall.accessMode == ExplicitConstructorCall.This) {
                                        FieldBinding[] fields = binding.declaringClass.fields();
                                        for (int i = 0, count = fields.length; i < count; i++) {
@@ -91,34 +93,40 @@ public class ConstructorDeclaration extends AbstractMethodDeclaration {
                                                }
                                        }
                                }
-                               flowInfo = constructorCall.analyseCode(scope, constructorContext, flowInfo);
+                               flowInfo = constructorCall.analyseCode(scope,
+                                               constructorContext, flowInfo);
                        }
                        // propagate to statements
                        if (statements != null) {
+                               boolean didAlreadyComplain = false;
                                for (int i = 0, count = statements.length; i < count; i++) {
                                        Statement stat;
-                                       if (!flowInfo.complainIfUnreachable((stat = statements[i]), scope)) {
-                                               flowInfo = stat.analyseCode(scope, constructorContext, flowInfo);
+                                       if (!flowInfo.complainIfUnreachable(stat = statements[i],
+                                                       scope, didAlreadyComplain)) {
+                                               flowInfo = stat.analyseCode(scope, constructorContext,
+                                                               flowInfo);
+                                       } else {
+                                               didAlreadyComplain = true;
                                        }
                                }
                        }
                        // check for missing returning path
-                       needFreeReturn =
-                               !((flowInfo == FlowInfo.DeadEnd) || flowInfo.isFakeReachable());
+                       this.needFreeReturn = flowInfo.isReachable();
 
                        // check missing blank final field initializations
                        if ((constructorCall != null)
-                               && (constructorCall.accessMode != ExplicitConstructorCall.This)) {
-                               flowInfo = flowInfo.mergedWith(initializerFlowContext.initsOnReturn);
+                                       && (constructorCall.accessMode != ExplicitConstructorCall.This)) {
+                               flowInfo = flowInfo
+                                               .mergedWith(constructorContext.initsOnReturn);
                                FieldBinding[] fields = binding.declaringClass.fields();
                                for (int i = 0, count = fields.length; i < count; i++) {
                                        FieldBinding field;
-                                       if ((!(field = fields[i]).isStatic())
-                                               && field.isFinal()
-                                               && (!flowInfo.isDefinitelyAssigned(fields[i]))) {
+                                       if ((!(field = fields[i]).isStatic()) && field.isFinal()
+                                                       && (!flowInfo.isDefinitelyAssigned(fields[i]))) {
                                                scope.problemReporter().uninitializedBlankFinalField(
-                                                       field,
-                                                       isDefaultConstructor ? (AstNode) scope.referenceType() : this);
+                                                               field,
+                                                               isDefaultConstructor ? (ASTNode) scope
+                                                                               .referenceType() : this);
                                        }
                                }
                        }
@@ -129,159 +137,205 @@ public class ConstructorDeclaration extends AbstractMethodDeclaration {
 
        /**
         * Bytecode generation for a constructor
-        *
-        * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope
-        * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile
+        * 
+        * @param classScope
+        *            net.sourceforge.phpdt.internal.compiler.lookup.ClassScope
+        * @param classFile
+        *            net.sourceforge.phpdt.internal.compiler.codegen.ClassFile
         */
-       public void generateCode(ClassScope classScope, ClassFile classFile) {
-               int problemResetPC = 0;
-               if (ignoreFurtherInvestigation) {
-                       if (this.binding == null)
-                               return; // Handle methods with invalid signature or duplicates
-                       int problemsLength;
-                       IProblem[] problems =
-                               scope.referenceCompilationUnit().compilationResult.getProblems();
-                       IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
-                       System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
-                       classFile.addProblemConstructor(this, binding, problemsCopy);
-                       return;
-               }
-               try {
-                       problemResetPC = classFile.contentsOffset;
-                       this.internalGenerateCode(classScope, classFile);
-               } catch (AbortMethod e) {
-                       if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) {
-                               // a branch target required a goto_w, restart code gen in wide mode.
-                               try {
-                                       if (statements != null) {
-                                               for (int i = 0, max = statements.length; i < max; i++)
-                                                       statements[i].resetStateForCodeGeneration();
-                                       }
-                                       classFile.contentsOffset = problemResetPC;
-                                       classFile.methodCount--;
-                                       classFile.codeStream.wideMode = true; // request wide mode 
-                                       this.internalGenerateCode(classScope, classFile); // restart method generation
-                               } catch (AbortMethod e2) {
-                                       int problemsLength;
-                                       IProblem[] problems =
-                                               scope.referenceCompilationUnit().compilationResult.getProblems();
-                                       IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
-                                       System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
-                                       classFile.addProblemConstructor(this, binding, problemsCopy, problemResetPC);
-                               }
-                       } else {
-                               int problemsLength;
-                               IProblem[] problems =
-                                       scope.referenceCompilationUnit().compilationResult.getProblems();
-                               IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
-                               System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
-                               classFile.addProblemConstructor(this, binding, problemsCopy, problemResetPC);
-                       }
-               }
-       }
-
-       private void internalGenerateCode(ClassScope classScope, ClassFile classFile) {
-               classFile.generateMethodInfoHeader(binding);
-               int methodAttributeOffset = classFile.contentsOffset;
-               int attributeNumber = classFile.generateMethodInfoAttribute(binding);
-               if ((!binding.isNative()) && (!binding.isAbstract())) {
-                       TypeDeclaration declaringType = classScope.referenceContext;
-                       int codeAttributeOffset = classFile.contentsOffset;
-                       classFile.generateCodeAttributeHeader();
-                       CodeStream codeStream = classFile.codeStream;
-                       codeStream.reset(this, classFile);
-                       // initialize local positions - including initializer scope.
-                       ReferenceBinding declaringClass = binding.declaringClass;
-                       int argSize = 0;
-                       scope.computeLocalVariablePositions(// consider synthetic arguments if any
-                       argSize =
-                               declaringClass.isNestedType()
-                                       ? ((NestedTypeBinding) declaringClass).syntheticArgumentsOffset
-                                       : 1,
-                               codeStream);
-                       if (arguments != null) {
-                               for (int i = 0, max = arguments.length; i < max; i++) {
-                                       // arguments initialization for local variable debug attributes
-                                       LocalVariableBinding argBinding;
-                                       codeStream.addVisibleLocalVariable(argBinding = arguments[i].binding);
-                                       argBinding.recordInitializationStartPC(0);
-                                       TypeBinding argType;
-                                       if ((argType = argBinding.type) == LongBinding || (argType == DoubleBinding)) {
-                                               argSize += 2;
-                                       } else {
-                                               argSize++;
-                                       }
-                               }
-                       }
-                       MethodScope initializerScope = declaringType.initializerScope;
-                       initializerScope.computeLocalVariablePositions(argSize, codeStream);
-                       // offset by the argument size (since not linked to method scope)
-
-                       // generate constructor call
-                       if (constructorCall != null) {
-                               constructorCall.generateCode(scope, codeStream);
-                       }
-                       // generate field initialization - only if not invoking another constructor call of the same class
-                       if ((constructorCall != null)
-                               && (constructorCall.accessMode != ExplicitConstructorCall.This)) {
-                               // generate synthetic fields initialization
-                               if (declaringClass.isNestedType()) {
-                                       NestedTypeBinding nestedType = (NestedTypeBinding) declaringClass;
-                                       SyntheticArgumentBinding[] syntheticArgs =
-                                               nestedType.syntheticEnclosingInstances();
-                                       for (int i = 0, max = syntheticArgs == null ? 0 : syntheticArgs.length;
-                                               i < max;
-                                               i++) {
-                                               if (syntheticArgs[i].matchingField != null) {
-                                                       codeStream.aload_0();
-                                                       codeStream.load(syntheticArgs[i]);
-                                                       codeStream.putfield(syntheticArgs[i].matchingField);
-                                               }
-                                       }
-                                       syntheticArgs = nestedType.syntheticOuterLocalVariables();
-                                       for (int i = 0, max = syntheticArgs == null ? 0 : syntheticArgs.length;
-                                               i < max;
-                                               i++) {
-                                               if (syntheticArgs[i].matchingField != null) {
-                                                       codeStream.aload_0();
-                                                       codeStream.load(syntheticArgs[i]);
-                                                       codeStream.putfield(syntheticArgs[i].matchingField);
-                                               }
-                                       }
-                               }
-                               // generate user field initialization
-                               if (declaringType.fields != null) {
-                                       for (int i = 0, max = declaringType.fields.length; i < max; i++) {
-                                               FieldDeclaration fieldDecl;
-                                               if (!(fieldDecl = declaringType.fields[i]).isStatic()) {
-                                                       fieldDecl.generateCode(initializerScope, codeStream);
-                                               }
-                                       }
-                               }
-                       }
-                       // generate statements
-                       if (statements != null) {
-                               for (int i = 0, max = statements.length; i < max; i++) {
-                                       statements[i].generateCode(scope, codeStream);
-                               }
-                       }
-                       if (needFreeReturn) {
-                               codeStream.return_();
-                       }
-                       // local variable attributes
-                       codeStream.exitUserScope(scope);
-                       codeStream.recordPositionsFrom(0, this.bodyEnd);
-                       classFile.completeCodeAttribute(codeAttributeOffset);
-                       attributeNumber++;
-               }
-               classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
-
-               // if a problem got reported during code gen, then trigger problem method creation
-               if (ignoreFurtherInvestigation) {
-                       throw new AbortMethod(scope.referenceCompilationUnit().compilationResult);
-               }
-       }
-
+       // public void generateCode(ClassScope classScope, ClassFile classFile) {
+       //              
+       // int problemResetPC = 0;
+       // if (ignoreFurtherInvestigation) {
+       // if (this.binding == null)
+       // return; // Handle methods with invalid signature or duplicates
+       // int problemsLength;
+       // IProblem[] problems =
+       // scope.referenceCompilationUnit().compilationResult.getProblems();
+       // IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
+       // System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
+       // classFile.addProblemConstructor(this, binding, problemsCopy);
+       // return;
+       // }
+       // try {
+       // problemResetPC = classFile.contentsOffset;
+       // this.internalGenerateCode(classScope, classFile);
+       // } catch (AbortMethod e) {
+       // if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) {
+       // // a branch target required a goto_w, restart code gen in wide mode.
+       // try {
+       // if (statements != null) {
+       // for (int i = 0, max = statements.length; i < max; i++)
+       // statements[i].resetStateForCodeGeneration();
+       // }
+       // classFile.contentsOffset = problemResetPC;
+       // classFile.methodCount--;
+       // classFile.codeStream.wideMode = true; // request wide mode
+       // this.internalGenerateCode(classScope, classFile); // restart method
+       // generation
+       // } catch (AbortMethod e2) {
+       // int problemsLength;
+       // IProblem[] problems =
+       // scope.referenceCompilationUnit().compilationResult.getAllProblems();
+       // IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
+       // System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
+       // classFile.addProblemConstructor(this, binding, problemsCopy,
+       // problemResetPC);
+       // }
+       // } else {
+       // int problemsLength;
+       // IProblem[] problems =
+       // scope.referenceCompilationUnit().compilationResult.getAllProblems();
+       // IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
+       // System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
+       // classFile.addProblemConstructor(this, binding, problemsCopy,
+       // problemResetPC);
+       // }
+       // }
+       // }
+       //
+       // public void generateSyntheticFieldInitializationsIfNecessary(
+       // MethodScope scope,
+       // CodeStream codeStream,
+       // ReferenceBinding declaringClass) {
+       //                      
+       // if (!declaringClass.isNestedType()) return;
+       //              
+       // NestedTypeBinding nestedType = (NestedTypeBinding) declaringClass;
+       //
+       // SyntheticArgumentBinding[] syntheticArgs =
+       // nestedType.syntheticEnclosingInstances();
+       // for (int i = 0, max = syntheticArgs == null ? 0 : syntheticArgs.length; i
+       // < max; i++) {
+       // SyntheticArgumentBinding syntheticArg;
+       // if ((syntheticArg = syntheticArgs[i]).matchingField != null) {
+       // codeStream.aload_0();
+       // codeStream.load(syntheticArg);
+       // codeStream.putfield(syntheticArg.matchingField);
+       // }
+       // }
+       // syntheticArgs = nestedType.syntheticOuterLocalVariables();
+       // for (int i = 0, max = syntheticArgs == null ? 0 : syntheticArgs.length; i
+       // < max; i++) {
+       // SyntheticArgumentBinding syntheticArg;
+       // if ((syntheticArg = syntheticArgs[i]).matchingField != null) {
+       // codeStream.aload_0();
+       // codeStream.load(syntheticArg);
+       // codeStream.putfield(syntheticArg.matchingField);
+       // }
+       // }
+       // }
+       //
+       // private void internalGenerateCode(ClassScope classScope, ClassFile
+       // classFile) {
+       //              
+       // classFile.generateMethodInfoHeader(binding);
+       // int methodAttributeOffset = classFile.contentsOffset;
+       // int attributeNumber = classFile.generateMethodInfoAttribute(binding);
+       // if ((!binding.isNative()) && (!binding.isAbstract())) {
+       //                      
+       // TypeDeclaration declaringType = classScope.referenceContext;
+       // int codeAttributeOffset = classFile.contentsOffset;
+       // classFile.generateCodeAttributeHeader();
+       // CodeStream codeStream = classFile.codeStream;
+       // codeStream.reset(this, classFile);
+       //
+       // // initialize local positions - including initializer scope.
+       // ReferenceBinding declaringClass = binding.declaringClass;
+       //
+       // int argSlotSize = 1; // this==aload0
+       //                      
+       // if (declaringClass.isNestedType()){
+       // NestedTypeBinding nestedType = (NestedTypeBinding) declaringClass;
+       // this.scope.extraSyntheticArguments =
+       // nestedType.syntheticOuterLocalVariables();
+       // scope.computeLocalVariablePositions(// consider synthetic arguments if
+       // any
+       // nestedType.enclosingInstancesSlotSize + 1,
+       // codeStream);
+       // argSlotSize += nestedType.enclosingInstancesSlotSize;
+       // argSlotSize += nestedType.outerLocalVariablesSlotSize;
+       // } else {
+       // scope.computeLocalVariablePositions(1, codeStream);
+       // }
+       //                              
+       // if (arguments != null) {
+       // for (int i = 0, max = arguments.length; i < max; i++) {
+       // // arguments initialization for local variable debug attributes
+       // LocalVariableBinding argBinding;
+       // codeStream.addVisibleLocalVariable(argBinding = arguments[i].binding);
+       // argBinding.recordInitializationStartPC(0);
+       // TypeBinding argType;
+       // if ((argType = argBinding.type) == LongBinding || (argType ==
+       // DoubleBinding)) {
+       // argSlotSize += 2;
+       // } else {
+       // argSlotSize++;
+       // }
+       // }
+       // }
+       //                      
+       // MethodScope initializerScope = declaringType.initializerScope;
+       // initializerScope.computeLocalVariablePositions(argSlotSize, codeStream);
+       // // offset by the argument size (since not linked to method scope)
+       //
+       // boolean needFieldInitializations = constructorCall == null ||
+       // constructorCall.accessMode != ExplicitConstructorCall.This;
+       //
+       // // post 1.4 source level, synthetic initializations occur prior to
+       // explicit constructor call
+       // boolean preInitSyntheticFields = scope.environment().options.targetJDK >=
+       // CompilerOptions.JDK1_4;
+       //
+       // if (needFieldInitializations && preInitSyntheticFields){
+       // generateSyntheticFieldInitializationsIfNecessary(scope, codeStream,
+       // declaringClass);
+       // }
+       // // generate constructor call
+       // if (constructorCall != null) {
+       // constructorCall.generateCode(scope, codeStream);
+       // }
+       // // generate field initialization - only if not invoking another
+       // constructor call of the same class
+       // if (needFieldInitializations) {
+       // if (!preInitSyntheticFields){
+       // generateSyntheticFieldInitializationsIfNecessary(scope, codeStream,
+       // declaringClass);
+       // }
+       // // generate user field initialization
+       // if (declaringType.fields != null) {
+       // for (int i = 0, max = declaringType.fields.length; i < max; i++) {
+       // FieldDeclaration fieldDecl;
+       // if (!(fieldDecl = declaringType.fields[i]).isStatic()) {
+       // fieldDecl.generateCode(initializerScope, codeStream);
+       // }
+       // }
+       // }
+       // }
+       // // generate statements
+       // if (statements != null) {
+       // for (int i = 0, max = statements.length; i < max; i++) {
+       // statements[i].generateCode(scope, codeStream);
+       // }
+       // }
+       // if (this.needFreeReturn) {
+       // codeStream.return_();
+       // }
+       // // local variable attributes
+       // codeStream.exitUserScope(scope);
+       // codeStream.recordPositionsFrom(0, this.bodyEnd);
+       // classFile.completeCodeAttribute(codeAttributeOffset);
+       // attributeNumber++;
+       // }
+       // classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
+       //
+       // // if a problem got reported during code gen, then trigger problem method
+       // creation
+       // if (ignoreFurtherInvestigation) {
+       // throw new
+       // AbortMethod(scope.referenceCompilationUnit().compilationResult);
+       // }
+       // }
        public boolean isConstructor() {
 
                return true;
@@ -297,16 +351,46 @@ public class ConstructorDeclaration extends AbstractMethodDeclaration {
                return true;
        }
 
-       public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
+       /**
+        * Returns true if the constructor is directly involved in a cycle. Given
+        * most constructors aren't, we only allocate the visited list lazily.
+        */
+       public boolean isRecursive(ArrayList visited) {
+
+               if (this.binding == null || this.constructorCall == null
+                               || this.constructorCall.binding == null
+                               || this.constructorCall.isSuperAccess()
+                               || !this.constructorCall.binding.isValidBinding()) {
+                       return false;
+               }
+
+               ConstructorDeclaration targetConstructor = ((ConstructorDeclaration) this.scope
+                               .referenceType().declarationOf(constructorCall.binding));
+               if (this == targetConstructor)
+                       return true; // direct case
+
+               if (visited == null) { // lazy allocation
+                       visited = new ArrayList(1);
+               } else {
+                       int index = visited.indexOf(this);
+                       if (index >= 0)
+                               return index == 0; // only blame if directly part of the cycle
+               }
+               visited.add(this);
+
+               return targetConstructor.isRecursive(visited);
+       }
+
+       public void parseStatements(UnitParser parser,
+                       CompilationUnitDeclaration unit) {
 
-               //fill up the constructor body with its statements
+               // fill up the constructor body with its statements
                if (ignoreFurtherInvestigation)
                        return;
-               if (isDefaultConstructor){
-                       constructorCall =
-                               new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper);
+               if (isDefaultConstructor) {
+                       constructorCall = SuperReference.implicitSuperConstructorCall();
                        constructorCall.sourceStart = sourceStart;
-                       constructorCall.sourceEnd = sourceEnd; 
+                       constructorCall.sourceEnd = sourceEnd;
                        return;
                }
                parser.parse(this, unit);
@@ -314,48 +398,33 @@ public class ConstructorDeclaration extends AbstractMethodDeclaration {
        }
 
        /*
-        * Type checking for constructor, just another method, except for special check
-        * for recursive constructor invocations.
+        * Type checking for constructor, just another method, except for special
+        * check for recursive constructor invocations.
         */
-       public void resolveStatements(ClassScope upperScope) {
-/*
-               // checking for recursive constructor call (protection)
-               if (!ignoreFurtherInvestigation && constructorCall == null){
-                       constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper);
-                       constructorCall.sourceStart = sourceStart;
-                       constructorCall.sourceEnd = sourceEnd;
-               }
-*/
-               if (!CharOperation.equals(scope.enclosingSourceType().sourceName, selector)){
+       public void resolveStatements() {
+
+               if (!CharOperation.equals(scope.enclosingSourceType().sourceName,
+                               selector)) {
                        scope.problemReporter().missingReturnType(this);
                }
 
                // if null ==> an error has occurs at parsing time ....
-               if (constructorCall != null) {
+               if (this.constructorCall != null) {
                        // e.g. using super() in java.lang.Object
-                       if (binding != null
-                               && binding.declaringClass.id == T_Object
-                               && constructorCall.accessMode != ExplicitConstructorCall.This) {
-                                       if (constructorCall.accessMode == ExplicitConstructorCall.Super) {
-                                               scope.problemReporter().cannotUseSuperInJavaLangObject(constructorCall);
-                                       }
-                                       constructorCall = null;
+                       if (this.binding != null
+                                       && this.binding.declaringClass.id == T_Object
+                                       && this.constructorCall.accessMode != ExplicitConstructorCall.This) {
+                               if (this.constructorCall.accessMode == ExplicitConstructorCall.Super) {
+                                       scope.problemReporter().cannotUseSuperInJavaLangObject(
+                                                       this.constructorCall);
+                               }
+                               this.constructorCall = null;
                        } else {
-                               constructorCall.resolve(scope);
-                       }
-               }
-               
-               super.resolveStatements(upperScope);
-
-               // indirect reference: increment target constructor reference count
-               if (constructorCall != null){
-                       if (constructorCall.binding != null
-                               && !constructorCall.isSuperAccess()
-                               && constructorCall.binding.isValidBinding()) {
-                               ((ConstructorDeclaration)
-                                               (upperScope.referenceContext.declarationOf(constructorCall.binding))).referenceCount++;
+                               this.constructorCall.resolve(this.scope);
                        }
                }
+
+               super.resolveStatements();
        }
 
        public String toStringStatements(int tab) {
@@ -377,9 +446,7 @@ public class ConstructorDeclaration extends AbstractMethodDeclaration {
                return s;
        }
 
-       public void traverse(
-               IAbstractSyntaxTreeVisitor visitor,
-               ClassScope classScope) {
+       public void traverse(ASTVisitor visitor, ClassScope classScope) {
 
                if (visitor.visit(this, classScope)) {
                        if (arguments != null) {
@@ -402,4 +469,4 @@ public class ConstructorDeclaration extends AbstractMethodDeclaration {
                }
                visitor.endVisit(this, classScope);
        }
-}
\ No newline at end of file
+}