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 net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.codegen.*;
15 import net.sourceforge.phpdt.internal.compiler.flow.*;
16 import net.sourceforge.phpdt.internal.compiler.lookup.*;
18 public class ExplicitConstructorCall
20 implements InvocationSite {
22 public Expression[] arguments;
23 public Expression qualification;
24 public MethodBinding binding;
26 public int accessMode;
28 public final static int ImplicitSuper = 1;
29 public final static int Super = 2;
30 public final static int This = 3;
32 public VariableBinding[][] implicitArguments;
33 boolean discardEnclosingInstance;
35 MethodBinding syntheticAccessor;
37 public ExplicitConstructorCall(int accessMode) {
38 this.accessMode = accessMode;
41 public FlowInfo analyseCode(
42 BlockScope currentScope,
43 FlowContext flowContext,
46 // must verify that exceptions potentially thrown by this expression are caught in the method.
49 ((MethodScope) currentScope).isConstructorCall = true;
51 // process enclosing instance
52 if (qualification != null) {
55 .analyseCode(currentScope, flowContext, flowInfo)
56 .unconditionalInits();
59 if (arguments != null) {
60 for (int i = 0, max = arguments.length; i < max; i++) {
63 .analyseCode(currentScope, flowContext, flowInfo)
64 .unconditionalInits();
68 ReferenceBinding[] thrownExceptions;
69 if ((thrownExceptions = binding.thrownExceptions) != NoExceptions) {
71 flowContext.checkExceptionHandlers(
73 (accessMode == ImplicitSuper)
74 ? (AstNode) currentScope.methodScope().referenceContext
79 manageEnclosingInstanceAccessIfNecessary(currentScope);
80 manageSyntheticAccessIfNecessary(currentScope);
83 ((MethodScope) currentScope).isConstructorCall = false;
88 * Constructor call code generation
90 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
91 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
93 public void generateCode(BlockScope currentScope, CodeStream codeStream) {
95 if ((bits & IsReachableMASK) == 0) {
99 ((MethodScope) currentScope).isConstructorCall = true;
101 int pc = codeStream.position;
102 codeStream.aload_0();
104 // handling innerclass constructor invocation
105 ReferenceBinding targetType;
106 if ((targetType = binding.declaringClass).isNestedType()) {
107 codeStream.generateSyntheticArgumentValues(
110 discardEnclosingInstance ? null : qualification,
114 if (arguments != null) {
115 for (int i = 0, max = arguments.length; i < max; i++) {
116 arguments[i].generateCode(currentScope, codeStream, true);
119 if (syntheticAccessor != null) {
120 // synthetic accessor got some extra arguments appended to its signature, which need values
122 max = syntheticAccessor.parameters.length - binding.parameters.length;
125 codeStream.aconst_null();
127 codeStream.invokespecial(syntheticAccessor);
129 codeStream.invokespecial(binding);
131 codeStream.recordPositionsFrom(pc, this.sourceStart);
133 ((MethodScope) currentScope).isConstructorCall = false;
137 public boolean isImplicitSuper() {
138 //return true if I'm of these compiler added statement super();
140 return (accessMode == ImplicitSuper);
143 public boolean isSuperAccess() {
145 return accessMode != This;
148 public boolean isTypeAccess() {
153 /* Inner emulation consists in either recording a dependency
154 * link only, or performing one level of propagation.
156 * Dependency mechanism is used whenever dealing with source target
157 * types, since by the time we reach them, we might not yet know their
160 void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
161 ReferenceBinding superType;
163 // perform some emulation work in case there is some and we are inside a local type only
164 if ((superType = binding.declaringClass).isNestedType()
165 && currentScope.enclosingSourceType().isLocalType()) {
167 if (superType.isLocalType()) {
168 ((LocalTypeBinding) superType).addInnerEmulationDependent(
170 qualification != null,
172 // request direct access
174 // locally propagate, since we already now the desired shape for sure
175 currentScope.propagateInnerEmulation(superType, qualification != null, true);
176 // request direct access
182 public void manageSyntheticAccessIfNecessary(BlockScope currentScope) {
184 // perform some emulation work in case there is some and we are inside a local type only
185 if (binding.isPrivate() && (accessMode != This)) {
190 .isPrivateConstructorAccessChangingVisibility) {
191 binding.tagForClearingPrivateModifier();
192 // constructor will not be dumped as private, no emulation required thus
195 ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding);
196 currentScope.problemReporter().needToEmulateMethodAccess(binding, this);
201 public void resolve(BlockScope scope) {
202 // the return type should be void for a constructor.
203 // the test is made into getConstructor
205 // mark the fact that we are in a constructor call.....
206 // unmark at all returns
208 ((MethodScope) scope).isConstructorCall = true;
209 ReferenceBinding receiverType = scope.enclosingSourceType();
210 if (accessMode != This)
211 receiverType = receiverType.superclass();
213 if (receiverType == null) {
217 // qualification should be from the type of the enclosingType
218 if (qualification != null) {
219 if (accessMode != Super) {
220 scope.problemReporter().unnecessaryEnclosingInstanceSpecification(
224 ReferenceBinding enclosingType = receiverType.enclosingType();
225 if (enclosingType == null) {
226 scope.problemReporter().unnecessaryEnclosingInstanceSpecification(
229 discardEnclosingInstance = true;
231 TypeBinding qTb = qualification.resolveTypeExpecting(scope, enclosingType);
232 qualification.implicitWidening(qTb, qTb);
236 // arguments buffering for the method lookup
237 TypeBinding[] argTypes = NoParameters;
238 if (arguments != null) {
239 boolean argHasError = false; // typeChecks all arguments
240 int length = arguments.length;
241 argTypes = new TypeBinding[length];
242 for (int i = 0; i < length; i++)
243 if ((argTypes[i] = arguments[i].resolveType(scope)) == null)
248 if ((binding = scope.getConstructor(receiverType, argTypes, this))
250 if (isMethodUseDeprecated(binding, scope))
251 scope.problemReporter().deprecatedMethod(binding, this);
253 // see for user-implicit widening conversion
254 if (arguments != null) {
255 int length = arguments.length;
256 TypeBinding[] paramTypes = binding.parameters;
257 for (int i = 0; i < length; i++)
258 arguments[i].implicitWidening(paramTypes[i], argTypes[i]);
261 if (binding.declaringClass == null)
262 binding.declaringClass = receiverType;
263 scope.problemReporter().invalidConstructor(this, binding);
266 ((MethodScope) scope).isConstructorCall = false;
270 public void setActualReceiverType(ReferenceBinding receiverType) {
274 public void setDepth(int depth) {
278 public void setFieldIndex(int depth) {
282 public String toString(int tab) {
284 String s = tabString(tab);
285 if (qualification != null)
286 s = s + qualification.toStringExpression() + "."; //$NON-NLS-1$
287 if (accessMode == This) {
288 s = s + "this("; //$NON-NLS-1$
290 s = s + "super("; //$NON-NLS-1$
292 if (arguments != null)
293 for (int i = 0; i < arguments.length; i++) {
294 s = s + arguments[i].toStringExpression();
295 if (i != arguments.length - 1)
296 s = s + ", "; //$NON-NLS-1$
298 s = s + ")"; //$NON-NLS-1$
302 public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
304 if (visitor.visit(this, scope)) {
305 if (qualification != null) {
306 qualification.traverse(visitor, scope);
308 if (arguments != null) {
309 int argumentLength = arguments.length;
310 for (int i = 0; i < argumentLength; i++)
311 arguments[i].traverse(visitor, scope);
314 visitor.endVisit(this, scope);