X-Git-Url: http://secure.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ConstructorDeclaration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ConstructorDeclaration.java index d6a9244..0bf4ad0 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ConstructorDeclaration.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/ConstructorDeclaration.java @@ -1,25 +1,29 @@ /******************************************************************************* - * 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.*; -import net.sourceforge.phpdt.internal.compiler.*; -import net.sourceforge.phpdt.internal.compiler.codegen.*; -import net.sourceforge.phpdt.internal.compiler.flow.*; -import net.sourceforge.phpdt.internal.compiler.lookup.*; -import net.sourceforge.phpdt.internal.compiler.parser.*; -import net.sourceforge.phpdt.internal.compiler.problem.*; -import net.sourceforge.phpdt.internal.compiler.util.*; +import net.sourceforge.phpdt.core.compiler.CharOperation; +import net.sourceforge.phpdt.internal.compiler.ASTVisitor; +import net.sourceforge.phpdt.internal.compiler.CompilationResult; +import net.sourceforge.phpdt.internal.compiler.flow.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.ReferenceBinding; +import net.sourceforge.phpdt.internal.compiler.parser.UnitParser; +import net.sourceforge.phpdt.internal.compiler.problem.AbortMethod; + public class ConstructorDeclaration extends AbstractMethodDeclaration { @@ -27,9 +31,6 @@ public class ConstructorDeclaration extends AbstractMethodDeclaration { public final static char[] ConstantPoolName = "".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 ConstructorDeclaration(CompilationResult compilationResult){ super(compilationResult); } @@ -41,6 +42,18 @@ public class ConstructorDeclaration extends AbstractMethodDeclaration { 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( @@ -48,7 +61,7 @@ public class ConstructorDeclaration extends AbstractMethodDeclaration { this, binding.thrownExceptions, scope, - FlowInfo.DeadEnd); + FlowInfo.DEAD_END); initializerFlowContext.checkInitializerExceptions( scope, constructorContext, @@ -84,21 +97,23 @@ public class ConstructorDeclaration extends AbstractMethodDeclaration { } // 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)) { + 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); + flowInfo = flowInfo.mergedWith(constructorContext.initsOnReturn); FieldBinding[] fields = binding.declaringClass.fields(); for (int i = 0, count = fields.length; i < count; i++) { FieldBinding field; @@ -107,7 +122,7 @@ public class ConstructorDeclaration extends AbstractMethodDeclaration { && (!flowInfo.isDefinitelyAssigned(fields[i]))) { scope.problemReporter().uninitializedBlankFinalField( field, - isDefaultConstructor ? (AstNode) scope.referenceType() : this); + isDefaultConstructor ? (ASTNode) scope.referenceType() : this); } } } @@ -119,157 +134,183 @@ 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() { @@ -286,14 +327,43 @@ 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 if (ignoreFurtherInvestigation) return; if (isDefaultConstructor){ - constructorCall = - new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); + constructorCall = SuperReference.implicitSuperConstructorCall(); constructorCall.sourceStart = sourceStart; constructorCall.sourceEnd = sourceEnd; return; @@ -306,45 +376,28 @@ public class ConstructorDeclaration extends AbstractMethodDeclaration { * 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; - } -*/ + 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); + 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); } - constructorCall = null; + this.constructorCall = null; } else { - constructorCall.resolve(scope); + this.constructorCall.resolve(this.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++; - } - } + super.resolveStatements(); } public String toStringStatements(int tab) { @@ -367,7 +420,7 @@ public class ConstructorDeclaration extends AbstractMethodDeclaration { } public void traverse( - IAbstractSyntaxTreeVisitor visitor, + ASTVisitor visitor, ClassScope classScope) { if (visitor.visit(this, classScope)) { @@ -391,4 +444,4 @@ public class ConstructorDeclaration extends AbstractMethodDeclaration { } visitor.endVisit(this, classScope); } -} \ No newline at end of file +}