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.IProblem;
16 import net.sourceforge.phpdt.internal.compiler.ClassFile;
17 import net.sourceforge.phpdt.internal.compiler.CompilationResult;
18 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
19 import net.sourceforge.phpdt.internal.compiler.codegen.CodeStream;
20 import net.sourceforge.phpdt.internal.compiler.flow.ExceptionHandlingFlowContext;
21 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
22 import net.sourceforge.phpdt.internal.compiler.flow.InitializationFlowContext;
23 import net.sourceforge.phpdt.internal.compiler.lookup.ClassScope;
24 import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding;
25 import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
26 import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope;
27 import net.sourceforge.phpdt.internal.compiler.lookup.NestedTypeBinding;
28 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
29 import net.sourceforge.phpdt.internal.compiler.lookup.SyntheticArgumentBinding;
30 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
31 import net.sourceforge.phpdt.internal.compiler.parser.Parser;
32 import net.sourceforge.phpdt.internal.compiler.problem.AbortMethod;
33 import net.sourceforge.phpdt.internal.compiler.util.CharOperation;
35 public class ConstructorDeclaration extends AbstractMethodDeclaration {
37 public ExplicitConstructorCall constructorCall;
38 public final static char[] ConstantPoolName = "<init>".toCharArray(); //$NON-NLS-1$
39 public boolean isDefaultConstructor = false;
41 public int referenceCount = 0;
42 // count how many times this constructor is referenced from other local constructors
44 public ConstructorDeclaration(CompilationResult compilationResult){
45 super(compilationResult);
48 public void analyseCode(
49 ClassScope classScope,
50 InitializationFlowContext initializerFlowContext,
53 if (ignoreFurtherInvestigation)
56 ExceptionHandlingFlowContext constructorContext =
57 new ExceptionHandlingFlowContext(
58 initializerFlowContext.parent,
60 binding.thrownExceptions,
63 initializerFlowContext.checkInitializerExceptions(
68 // anonymous constructor can gain extra thrown exceptions from unhandled ones
69 if (binding.declaringClass.isAnonymousType()) {
70 ArrayList computedExceptions = constructorContext.extendedExceptions;
71 if (computedExceptions != null){
73 if ((size = computedExceptions.size()) > 0){
74 ReferenceBinding[] actuallyThrownExceptions;
75 computedExceptions.toArray(actuallyThrownExceptions = new ReferenceBinding[size]);
76 binding.thrownExceptions = actuallyThrownExceptions;
81 // propagate to constructor call
82 if (constructorCall != null) {
83 // if calling 'this(...)', then flag all non-static fields as definitely
84 // set since they are supposed to be set inside other local constructor
85 if (constructorCall.accessMode == ExplicitConstructorCall.This) {
86 FieldBinding[] fields = binding.declaringClass.fields();
87 for (int i = 0, count = fields.length; i < count; i++) {
89 if (!(field = fields[i]).isStatic()) {
90 flowInfo.markAsDefinitelyAssigned(field);
94 flowInfo = constructorCall.analyseCode(scope, constructorContext, flowInfo);
96 // propagate to statements
97 if (statements != null) {
98 for (int i = 0, count = statements.length; i < count; i++) {
100 if (!flowInfo.complainIfUnreachable((stat = statements[i]), scope)) {
101 flowInfo = stat.analyseCode(scope, constructorContext, flowInfo);
105 // check for missing returning path
107 !((flowInfo == FlowInfo.DeadEnd) || flowInfo.isFakeReachable());
109 // check missing blank final field initializations
110 if ((constructorCall != null)
111 && (constructorCall.accessMode != ExplicitConstructorCall.This)) {
112 flowInfo = flowInfo.mergedWith(initializerFlowContext.initsOnReturn);
113 FieldBinding[] fields = binding.declaringClass.fields();
114 for (int i = 0, count = fields.length; i < count; i++) {
116 if ((!(field = fields[i]).isStatic())
118 && (!flowInfo.isDefinitelyAssigned(fields[i]))) {
119 scope.problemReporter().uninitializedBlankFinalField(
121 isDefaultConstructor ? (AstNode) scope.referenceType() : this);
125 } catch (AbortMethod e) {
126 this.ignoreFurtherInvestigation = true;
131 * Bytecode generation for a constructor
133 * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope
134 * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile
136 public void generateCode(ClassScope classScope, ClassFile classFile) {
137 int problemResetPC = 0;
138 if (ignoreFurtherInvestigation) {
139 if (this.binding == null)
140 return; // Handle methods with invalid signature or duplicates
142 IProblem[] problems =
143 scope.referenceCompilationUnit().compilationResult.getProblems();
144 IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
145 System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
146 classFile.addProblemConstructor(this, binding, problemsCopy);
150 problemResetPC = classFile.contentsOffset;
151 this.internalGenerateCode(classScope, classFile);
152 } catch (AbortMethod e) {
153 if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) {
154 // a branch target required a goto_w, restart code gen in wide mode.
156 if (statements != null) {
157 for (int i = 0, max = statements.length; i < max; i++)
158 statements[i].resetStateForCodeGeneration();
160 classFile.contentsOffset = problemResetPC;
161 classFile.methodCount--;
162 classFile.codeStream.wideMode = true; // request wide mode
163 this.internalGenerateCode(classScope, classFile); // restart method generation
164 } catch (AbortMethod e2) {
166 IProblem[] problems =
167 scope.referenceCompilationUnit().compilationResult.getProblems();
168 IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
169 System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
170 classFile.addProblemConstructor(this, binding, problemsCopy, problemResetPC);
174 IProblem[] problems =
175 scope.referenceCompilationUnit().compilationResult.getProblems();
176 IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
177 System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
178 classFile.addProblemConstructor(this, binding, problemsCopy, problemResetPC);
183 private void internalGenerateCode(ClassScope classScope, ClassFile classFile) {
184 classFile.generateMethodInfoHeader(binding);
185 int methodAttributeOffset = classFile.contentsOffset;
186 int attributeNumber = classFile.generateMethodInfoAttribute(binding);
187 if ((!binding.isNative()) && (!binding.isAbstract())) {
188 TypeDeclaration declaringType = classScope.referenceContext;
189 int codeAttributeOffset = classFile.contentsOffset;
190 classFile.generateCodeAttributeHeader();
191 CodeStream codeStream = classFile.codeStream;
192 codeStream.reset(this, classFile);
193 // initialize local positions - including initializer scope.
194 ReferenceBinding declaringClass = binding.declaringClass;
196 scope.computeLocalVariablePositions(// consider synthetic arguments if any
198 declaringClass.isNestedType()
199 ? ((NestedTypeBinding) declaringClass).syntheticArgumentsOffset
202 if (arguments != null) {
203 for (int i = 0, max = arguments.length; i < max; i++) {
204 // arguments initialization for local variable debug attributes
205 LocalVariableBinding argBinding;
206 codeStream.addVisibleLocalVariable(argBinding = arguments[i].binding);
207 argBinding.recordInitializationStartPC(0);
209 if ((argType = argBinding.type) == LongBinding || (argType == DoubleBinding)) {
216 MethodScope initializerScope = declaringType.initializerScope;
217 initializerScope.computeLocalVariablePositions(argSize, codeStream);
218 // offset by the argument size (since not linked to method scope)
220 // generate constructor call
221 if (constructorCall != null) {
222 constructorCall.generateCode(scope, codeStream);
224 // generate field initialization - only if not invoking another constructor call of the same class
225 if ((constructorCall != null)
226 && (constructorCall.accessMode != ExplicitConstructorCall.This)) {
227 // generate synthetic fields initialization
228 if (declaringClass.isNestedType()) {
229 NestedTypeBinding nestedType = (NestedTypeBinding) declaringClass;
230 SyntheticArgumentBinding[] syntheticArgs =
231 nestedType.syntheticEnclosingInstances();
232 for (int i = 0, max = syntheticArgs == null ? 0 : syntheticArgs.length;
235 if (syntheticArgs[i].matchingField != null) {
236 codeStream.aload_0();
237 codeStream.load(syntheticArgs[i]);
238 codeStream.putfield(syntheticArgs[i].matchingField);
241 syntheticArgs = nestedType.syntheticOuterLocalVariables();
242 for (int i = 0, max = syntheticArgs == null ? 0 : syntheticArgs.length;
245 if (syntheticArgs[i].matchingField != null) {
246 codeStream.aload_0();
247 codeStream.load(syntheticArgs[i]);
248 codeStream.putfield(syntheticArgs[i].matchingField);
252 // generate user field initialization
253 if (declaringType.fields != null) {
254 for (int i = 0, max = declaringType.fields.length; i < max; i++) {
255 FieldDeclaration fieldDecl;
256 if (!(fieldDecl = declaringType.fields[i]).isStatic()) {
257 fieldDecl.generateCode(initializerScope, codeStream);
262 // generate statements
263 if (statements != null) {
264 for (int i = 0, max = statements.length; i < max; i++) {
265 statements[i].generateCode(scope, codeStream);
268 if (needFreeReturn) {
269 codeStream.return_();
271 // local variable attributes
272 codeStream.exitUserScope(scope);
273 codeStream.recordPositionsFrom(0, this.bodyEnd);
274 classFile.completeCodeAttribute(codeAttributeOffset);
277 classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
279 // if a problem got reported during code gen, then trigger problem method creation
280 if (ignoreFurtherInvestigation) {
281 throw new AbortMethod(scope.referenceCompilationUnit().compilationResult);
285 public boolean isConstructor() {
290 public boolean isDefaultConstructor() {
292 return isDefaultConstructor;
295 public boolean isInitializationMethod() {
300 public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
302 //fill up the constructor body with its statements
303 if (ignoreFurtherInvestigation)
305 if (isDefaultConstructor){
307 new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper);
308 constructorCall.sourceStart = sourceStart;
309 constructorCall.sourceEnd = sourceEnd;
312 parser.parse(this, unit);
317 * Type checking for constructor, just another method, except for special check
318 * for recursive constructor invocations.
320 public void resolveStatements(ClassScope upperScope) {
322 // checking for recursive constructor call (protection)
323 if (!ignoreFurtherInvestigation && constructorCall == null){
324 constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper);
325 constructorCall.sourceStart = sourceStart;
326 constructorCall.sourceEnd = sourceEnd;
329 if (!CharOperation.equals(scope.enclosingSourceType().sourceName, selector)){
330 scope.problemReporter().missingReturnType(this);
333 // if null ==> an error has occurs at parsing time ....
334 if (constructorCall != null) {
335 // e.g. using super() in java.lang.Object
337 && binding.declaringClass.id == T_Object
338 && constructorCall.accessMode != ExplicitConstructorCall.This) {
339 if (constructorCall.accessMode == ExplicitConstructorCall.Super) {
340 scope.problemReporter().cannotUseSuperInJavaLangObject(constructorCall);
342 constructorCall = null;
344 constructorCall.resolve(scope);
348 super.resolveStatements(upperScope);
350 // indirect reference: increment target constructor reference count
351 if (constructorCall != null){
352 if (constructorCall.binding != null
353 && !constructorCall.isSuperAccess()
354 && constructorCall.binding.isValidBinding()) {
355 ((ConstructorDeclaration)
356 (upperScope.referenceContext.declarationOf(constructorCall.binding))).referenceCount++;
361 public String toStringStatements(int tab) {
363 String s = " {"; //$NON-NLS-1$
364 if (constructorCall != null) {
365 s = s + "\n" + constructorCall.toString(tab) + ";"; //$NON-NLS-1$ //$NON-NLS-2$
367 if (statements != null) {
368 for (int i = 0; i < statements.length; i++) {
369 s = s + "\n" + statements[i].toString(tab); //$NON-NLS-1$
370 if (!(statements[i] instanceof Block)) {
371 s += ";"; //$NON-NLS-1$
375 s += "\n" + tabString(tab == 0 ? 0 : tab - 1) + "}"; //$NON-NLS-1$ //$NON-NLS-2$
376 //$NON-NLS-2$ //$NON-NLS-1$
380 public void traverse(
381 IAbstractSyntaxTreeVisitor visitor,
382 ClassScope classScope) {
384 if (visitor.visit(this, classScope)) {
385 if (arguments != null) {
386 int argumentLength = arguments.length;
387 for (int i = 0; i < argumentLength; i++)
388 arguments[i].traverse(visitor, scope);
390 if (thrownExceptions != null) {
391 int thrownExceptionsLength = thrownExceptions.length;
392 for (int i = 0; i < thrownExceptionsLength; i++)
393 thrownExceptions[i].traverse(visitor, scope);
395 if (constructorCall != null)
396 constructorCall.traverse(visitor, scope);
397 if (statements != null) {
398 int statementsLength = statements.length;
399 for (int i = 0; i < statementsLength; i++)
400 statements[i].traverse(visitor, scope);
403 visitor.endVisit(this, classScope);