1 /*******************************************************************************
2 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v0.5
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v05.html
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
13 import java.util.ArrayList;
15 import net.sourceforge.phpdt.core.compiler.*;
16 import net.sourceforge.phpdt.internal.compiler.*;
17 import net.sourceforge.phpdt.internal.compiler.codegen.*;
18 import net.sourceforge.phpdt.internal.compiler.flow.*;
19 import net.sourceforge.phpdt.internal.compiler.lookup.*;
20 import net.sourceforge.phpdt.internal.compiler.parser.*;
21 import net.sourceforge.phpdt.internal.compiler.problem.*;
22 import net.sourceforge.phpdt.internal.compiler.util.*;
24 public class ConstructorDeclaration extends AbstractMethodDeclaration {
26 public ExplicitConstructorCall constructorCall;
27 public final static char[] ConstantPoolName = "<init>".toCharArray(); //$NON-NLS-1$
28 public boolean isDefaultConstructor = false;
30 public int referenceCount = 0;
31 // count how many times this constructor is referenced from other local constructors
33 public ConstructorDeclaration(CompilationResult compilationResult){
34 super(compilationResult);
37 public void analyseCode(
38 ClassScope classScope,
39 InitializationFlowContext initializerFlowContext,
42 if (ignoreFurtherInvestigation)
45 ExceptionHandlingFlowContext constructorContext =
46 new ExceptionHandlingFlowContext(
47 initializerFlowContext.parent,
49 binding.thrownExceptions,
52 initializerFlowContext.checkInitializerExceptions(
57 // anonymous constructor can gain extra thrown exceptions from unhandled ones
58 if (binding.declaringClass.isAnonymousType()) {
59 ArrayList computedExceptions = constructorContext.extendedExceptions;
60 if (computedExceptions != null){
62 if ((size = computedExceptions.size()) > 0){
63 ReferenceBinding[] actuallyThrownExceptions;
64 computedExceptions.toArray(actuallyThrownExceptions = new ReferenceBinding[size]);
65 binding.thrownExceptions = actuallyThrownExceptions;
70 // propagate to constructor call
71 if (constructorCall != null) {
72 // if calling 'this(...)', then flag all non-static fields as definitely
73 // set since they are supposed to be set inside other local constructor
74 if (constructorCall.accessMode == ExplicitConstructorCall.This) {
75 FieldBinding[] fields = binding.declaringClass.fields();
76 for (int i = 0, count = fields.length; i < count; i++) {
78 if (!(field = fields[i]).isStatic()) {
79 flowInfo.markAsDefinitelyAssigned(field);
83 flowInfo = constructorCall.analyseCode(scope, constructorContext, flowInfo);
85 // propagate to statements
86 if (statements != null) {
87 for (int i = 0, count = statements.length; i < count; i++) {
89 if (!flowInfo.complainIfUnreachable((stat = statements[i]), scope)) {
90 flowInfo = stat.analyseCode(scope, constructorContext, flowInfo);
94 // check for missing returning path
96 !((flowInfo == FlowInfo.DeadEnd) || flowInfo.isFakeReachable());
98 // check missing blank final field initializations
99 if ((constructorCall != null)
100 && (constructorCall.accessMode != ExplicitConstructorCall.This)) {
101 flowInfo = flowInfo.mergedWith(initializerFlowContext.initsOnReturn);
102 FieldBinding[] fields = binding.declaringClass.fields();
103 for (int i = 0, count = fields.length; i < count; i++) {
105 if ((!(field = fields[i]).isStatic())
107 && (!flowInfo.isDefinitelyAssigned(fields[i]))) {
108 scope.problemReporter().uninitializedBlankFinalField(
110 isDefaultConstructor ? (AstNode) scope.referenceType() : this);
114 } catch (AbortMethod e) {
115 this.ignoreFurtherInvestigation = true;
120 * Bytecode generation for a constructor
122 * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope
123 * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile
125 public void generateCode(ClassScope classScope, ClassFile classFile) {
126 int problemResetPC = 0;
127 if (ignoreFurtherInvestigation) {
128 if (this.binding == null)
129 return; // Handle methods with invalid signature or duplicates
131 IProblem[] problems =
132 scope.referenceCompilationUnit().compilationResult.getProblems();
133 IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
134 System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
135 classFile.addProblemConstructor(this, binding, problemsCopy);
139 problemResetPC = classFile.contentsOffset;
140 this.internalGenerateCode(classScope, classFile);
141 } catch (AbortMethod e) {
142 if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) {
143 // a branch target required a goto_w, restart code gen in wide mode.
145 if (statements != null) {
146 for (int i = 0, max = statements.length; i < max; i++)
147 statements[i].resetStateForCodeGeneration();
149 classFile.contentsOffset = problemResetPC;
150 classFile.methodCount--;
151 classFile.codeStream.wideMode = true; // request wide mode
152 this.internalGenerateCode(classScope, classFile); // restart method generation
153 } catch (AbortMethod e2) {
155 IProblem[] problems =
156 scope.referenceCompilationUnit().compilationResult.getProblems();
157 IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
158 System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
159 classFile.addProblemConstructor(this, binding, problemsCopy, problemResetPC);
163 IProblem[] problems =
164 scope.referenceCompilationUnit().compilationResult.getProblems();
165 IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
166 System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
167 classFile.addProblemConstructor(this, binding, problemsCopy, problemResetPC);
172 private void internalGenerateCode(ClassScope classScope, ClassFile classFile) {
173 classFile.generateMethodInfoHeader(binding);
174 int methodAttributeOffset = classFile.contentsOffset;
175 int attributeNumber = classFile.generateMethodInfoAttribute(binding);
176 if ((!binding.isNative()) && (!binding.isAbstract())) {
177 TypeDeclaration declaringType = classScope.referenceContext;
178 int codeAttributeOffset = classFile.contentsOffset;
179 classFile.generateCodeAttributeHeader();
180 CodeStream codeStream = classFile.codeStream;
181 codeStream.reset(this, classFile);
182 // initialize local positions - including initializer scope.
183 ReferenceBinding declaringClass = binding.declaringClass;
185 scope.computeLocalVariablePositions(// consider synthetic arguments if any
187 declaringClass.isNestedType()
188 ? ((NestedTypeBinding) declaringClass).syntheticArgumentsOffset
191 if (arguments != null) {
192 for (int i = 0, max = arguments.length; i < max; i++) {
193 // arguments initialization for local variable debug attributes
194 LocalVariableBinding argBinding;
195 codeStream.addVisibleLocalVariable(argBinding = arguments[i].binding);
196 argBinding.recordInitializationStartPC(0);
198 if ((argType = argBinding.type) == LongBinding || (argType == DoubleBinding)) {
205 MethodScope initializerScope = declaringType.initializerScope;
206 initializerScope.computeLocalVariablePositions(argSize, codeStream);
207 // offset by the argument size (since not linked to method scope)
209 // generate constructor call
210 if (constructorCall != null) {
211 constructorCall.generateCode(scope, codeStream);
213 // generate field initialization - only if not invoking another constructor call of the same class
214 if ((constructorCall != null)
215 && (constructorCall.accessMode != ExplicitConstructorCall.This)) {
216 // generate synthetic fields initialization
217 if (declaringClass.isNestedType()) {
218 NestedTypeBinding nestedType = (NestedTypeBinding) declaringClass;
219 SyntheticArgumentBinding[] syntheticArgs =
220 nestedType.syntheticEnclosingInstances();
221 for (int i = 0, max = syntheticArgs == null ? 0 : syntheticArgs.length;
224 if (syntheticArgs[i].matchingField != null) {
225 codeStream.aload_0();
226 codeStream.load(syntheticArgs[i]);
227 codeStream.putfield(syntheticArgs[i].matchingField);
230 syntheticArgs = nestedType.syntheticOuterLocalVariables();
231 for (int i = 0, max = syntheticArgs == null ? 0 : syntheticArgs.length;
234 if (syntheticArgs[i].matchingField != null) {
235 codeStream.aload_0();
236 codeStream.load(syntheticArgs[i]);
237 codeStream.putfield(syntheticArgs[i].matchingField);
241 // generate user field initialization
242 if (declaringType.fields != null) {
243 for (int i = 0, max = declaringType.fields.length; i < max; i++) {
244 FieldDeclaration fieldDecl;
245 if (!(fieldDecl = declaringType.fields[i]).isStatic()) {
246 fieldDecl.generateCode(initializerScope, codeStream);
251 // generate statements
252 if (statements != null) {
253 for (int i = 0, max = statements.length; i < max; i++) {
254 statements[i].generateCode(scope, codeStream);
257 if (needFreeReturn) {
258 codeStream.return_();
260 // local variable attributes
261 codeStream.exitUserScope(scope);
262 codeStream.recordPositionsFrom(0, this.bodyEnd);
263 classFile.completeCodeAttribute(codeAttributeOffset);
266 classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
268 // if a problem got reported during code gen, then trigger problem method creation
269 if (ignoreFurtherInvestigation) {
270 throw new AbortMethod(scope.referenceCompilationUnit().compilationResult);
274 public boolean isConstructor() {
279 public boolean isDefaultConstructor() {
281 return isDefaultConstructor;
284 public boolean isInitializationMethod() {
289 public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
291 //fill up the constructor body with its statements
292 if (ignoreFurtherInvestigation)
294 if (isDefaultConstructor){
296 new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper);
297 constructorCall.sourceStart = sourceStart;
298 constructorCall.sourceEnd = sourceEnd;
301 parser.parse(this, unit);
306 * Type checking for constructor, just another method, except for special check
307 * for recursive constructor invocations.
309 public void resolveStatements(ClassScope upperScope) {
311 // checking for recursive constructor call (protection)
312 if (!ignoreFurtherInvestigation && constructorCall == null){
313 constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper);
314 constructorCall.sourceStart = sourceStart;
315 constructorCall.sourceEnd = sourceEnd;
318 if (!CharOperation.equals(scope.enclosingSourceType().sourceName, selector)){
319 scope.problemReporter().missingReturnType(this);
322 // if null ==> an error has occurs at parsing time ....
323 if (constructorCall != null) {
324 // e.g. using super() in java.lang.Object
326 && binding.declaringClass.id == T_Object
327 && constructorCall.accessMode != ExplicitConstructorCall.This) {
328 if (constructorCall.accessMode == ExplicitConstructorCall.Super) {
329 scope.problemReporter().cannotUseSuperInJavaLangObject(constructorCall);
331 constructorCall = null;
333 constructorCall.resolve(scope);
337 super.resolveStatements(upperScope);
339 // indirect reference: increment target constructor reference count
340 if (constructorCall != null){
341 if (constructorCall.binding != null
342 && !constructorCall.isSuperAccess()
343 && constructorCall.binding.isValidBinding()) {
344 ((ConstructorDeclaration)
345 (upperScope.referenceContext.declarationOf(constructorCall.binding))).referenceCount++;
350 public String toStringStatements(int tab) {
352 String s = " {"; //$NON-NLS-1$
353 if (constructorCall != null) {
354 s = s + "\n" + constructorCall.toString(tab) + ";"; //$NON-NLS-1$ //$NON-NLS-2$
356 if (statements != null) {
357 for (int i = 0; i < statements.length; i++) {
358 s = s + "\n" + statements[i].toString(tab); //$NON-NLS-1$
359 if (!(statements[i] instanceof Block)) {
360 s += ";"; //$NON-NLS-1$
364 s += "\n" + tabString(tab == 0 ? 0 : tab - 1) + "}"; //$NON-NLS-1$ //$NON-NLS-2$
365 //$NON-NLS-2$ //$NON-NLS-1$
369 public void traverse(
370 IAbstractSyntaxTreeVisitor visitor,
371 ClassScope classScope) {
373 if (visitor.visit(this, classScope)) {
374 if (arguments != null) {
375 int argumentLength = arguments.length;
376 for (int i = 0; i < argumentLength; i++)
377 arguments[i].traverse(visitor, scope);
379 if (thrownExceptions != null) {
380 int thrownExceptionsLength = thrownExceptions.length;
381 for (int i = 0; i < thrownExceptionsLength; i++)
382 thrownExceptions[i].traverse(visitor, scope);
384 if (constructorCall != null)
385 constructorCall.traverse(visitor, scope);
386 if (statements != null) {
387 int statementsLength = statements.length;
388 for (int i = 0; i < statementsLength; i++)
389 statements[i].traverse(visitor, scope);
392 visitor.endVisit(this, classScope);