1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpeclipse.internal.compiler.ast;
13 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
14 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
16 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
17 import net.sourceforge.phpdt.internal.compiler.lookup.InvocationSite;
18 import net.sourceforge.phpdt.internal.compiler.lookup.LocalTypeBinding;
19 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
20 import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope;
21 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
22 import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding;
23 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
24 import net.sourceforge.phpdt.internal.compiler.lookup.VariableBinding;
26 public class ExplicitConstructorCall
28 implements InvocationSite {
30 public Expression[] arguments;
31 public Expression qualification;
32 public MethodBinding binding;
34 public int accessMode;
36 public final static int ImplicitSuper = 1;
37 public final static int Super = 2;
38 public final static int This = 3;
40 public VariableBinding[][] implicitArguments;
41 boolean discardEnclosingInstance;
43 MethodBinding syntheticAccessor;
45 public ExplicitConstructorCall(int accessMode) {
46 this.accessMode = accessMode;
49 public FlowInfo analyseCode(
50 BlockScope currentScope,
51 FlowContext flowContext,
54 // must verify that exceptions potentially thrown by this expression are caught in the method.
57 ((MethodScope) currentScope).isConstructorCall = true;
59 // process enclosing instance
60 if (qualification != null) {
63 .analyseCode(currentScope, flowContext, flowInfo)
64 .unconditionalInits();
67 if (arguments != null) {
68 for (int i = 0, max = arguments.length; i < max; i++) {
71 .analyseCode(currentScope, flowContext, flowInfo)
72 .unconditionalInits();
76 ReferenceBinding[] thrownExceptions;
77 if ((thrownExceptions = binding.thrownExceptions) != NoExceptions) {
79 flowContext.checkExceptionHandlers(
81 (accessMode == ImplicitSuper)
82 ? (ASTNode) currentScope.methodScope().referenceContext
87 manageEnclosingInstanceAccessIfNecessary(currentScope);
88 manageSyntheticAccessIfNecessary(currentScope);
91 ((MethodScope) currentScope).isConstructorCall = false;
96 * Constructor call code generation
98 * @param currentScope net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
99 * @param codeStream net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
101 // public void generateCode(BlockScope currentScope, CodeStream codeStream) {
103 // if ((bits & IsReachableMASK) == 0) {
107 // ((MethodScope) currentScope).isConstructorCall = true;
109 // int pc = codeStream.position;
110 // codeStream.aload_0();
112 // // handling innerclass constructor invocation
113 // ReferenceBinding targetType = binding.declaringClass;
114 // // handling innerclass instance allocation - enclosing instance arguments
115 // if (targetType.isNestedType()) {
116 // codeStream.generateSyntheticEnclosingInstanceValues(
119 // discardEnclosingInstance ? null : qualification,
122 // // regular code gen
123 // if (arguments != null) {
124 // for (int i = 0, max = arguments.length; i < max; i++) {
125 // arguments[i].generateCode(currentScope, codeStream, true);
128 // // handling innerclass instance allocation - outer local arguments
129 // if (targetType.isNestedType()) {
130 // codeStream.generateSyntheticOuterArgumentValues(
135 // if (syntheticAccessor != null) {
136 // // synthetic accessor got some extra arguments appended to its signature, which need values
138 // max = syntheticAccessor.parameters.length - binding.parameters.length;
141 // codeStream.aconst_null();
143 // codeStream.invokespecial(syntheticAccessor);
145 // codeStream.invokespecial(binding);
147 // codeStream.recordPositionsFrom(pc, this.sourceStart);
149 // ((MethodScope) currentScope).isConstructorCall = false;
153 public boolean isImplicitSuper() {
154 //return true if I'm of these compiler added statement super();
156 return (accessMode == ImplicitSuper);
159 public boolean isSuperAccess() {
161 return accessMode != This;
164 public boolean isTypeAccess() {
169 /* Inner emulation consists in either recording a dependency
170 * link only, or performing one level of propagation.
172 * Dependency mechanism is used whenever dealing with source target
173 * types, since by the time we reach them, we might not yet know their
176 void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
177 ReferenceBinding superType;
179 // perform some emulation work in case there is some and we are inside a local type only
180 if ((superType = binding.declaringClass).isNestedType()
181 && currentScope.enclosingSourceType().isLocalType()) {
183 if (superType.isLocalType()) {
184 ((LocalTypeBinding) superType).addInnerEmulationDependent(currentScope, qualification != null);
186 // locally propagate, since we already now the desired shape for sure
187 currentScope.propagateInnerEmulation(superType, qualification != null);
192 public void manageSyntheticAccessIfNecessary(BlockScope currentScope) {
194 // perform some emulation work in case there is some and we are inside a local type only
195 if (binding.isPrivate() && (accessMode != This)) {
200 // .isPrivateConstructorAccessChangingVisibility) {
201 // binding.tagForClearingPrivateModifier();
202 // // constructor will not be dumped as private, no emulation required thus
205 ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding, isSuperAccess());
206 currentScope.problemReporter().needToEmulateMethodAccess(binding, this);
211 public void resolve(BlockScope scope) {
212 // the return type should be void for a constructor.
213 // the test is made into getConstructor
215 // mark the fact that we are in a constructor call.....
216 // unmark at all returns
218 ((MethodScope) scope).isConstructorCall = true;
219 ReferenceBinding receiverType = scope.enclosingSourceType();
220 if (accessMode != This)
221 receiverType = receiverType.superclass();
223 if (receiverType == null) {
227 // qualification should be from the type of the enclosingType
228 if (qualification != null) {
229 if (accessMode != Super) {
230 scope.problemReporter().unnecessaryEnclosingInstanceSpecification(
234 ReferenceBinding enclosingType = receiverType.enclosingType();
235 if (enclosingType == null) {
236 scope.problemReporter().unnecessaryEnclosingInstanceSpecification(
239 discardEnclosingInstance = true;
241 TypeBinding qTb = qualification.resolveTypeExpecting(scope, enclosingType);
242 qualification.implicitWidening(qTb, qTb);
246 // arguments buffering for the method lookup
247 TypeBinding[] argTypes = NoParameters;
248 if (arguments != null) {
249 boolean argHasError = false; // typeChecks all arguments
250 int length = arguments.length;
251 argTypes = new TypeBinding[length];
252 for (int i = 0; i < length; i++)
253 if ((argTypes[i] = arguments[i].resolveType(scope)) == null)
258 if ((binding = scope.getConstructor(receiverType, argTypes, this))
260 if (isMethodUseDeprecated(binding, scope))
261 scope.problemReporter().deprecatedMethod(binding, this);
263 // see for user-implicit widening conversion
264 if (arguments != null) {
265 int length = arguments.length;
266 TypeBinding[] paramTypes = binding.parameters;
267 for (int i = 0; i < length; i++)
268 arguments[i].implicitWidening(paramTypes[i], argTypes[i]);
270 if (binding.isPrivate()) {
271 binding.modifiers |= AccPrivateUsed;
274 if (binding.declaringClass == null)
275 binding.declaringClass = receiverType;
276 scope.problemReporter().invalidConstructor(this, binding);
279 ((MethodScope) scope).isConstructorCall = false;
283 public void setActualReceiverType(ReferenceBinding receiverType) {
287 public void setDepth(int depth) {
291 public void setFieldIndex(int depth) {
294 public StringBuffer printStatement(int indent, StringBuffer output) {
296 printIndent(indent, output);
297 if (qualification != null) qualification.printExpression(0, output).append('.');
298 if (accessMode == This) {
299 output.append("this("); //$NON-NLS-1$
301 output.append("super("); //$NON-NLS-1$
303 if (arguments != null) {
304 for (int i = 0; i < arguments.length; i++) {
305 if (i > 0) output.append(", "); //$NON-NLS-1$
306 arguments[i].printExpression(0, output);
309 return output.append(");"); //$NON-NLS-1$
311 public String toString(int tab) {
313 String s = tabString(tab);
314 if (qualification != null)
315 s = s + qualification.toStringExpression() + "."; //$NON-NLS-1$
316 if (accessMode == This) {
317 s = s + "this("; //$NON-NLS-1$
319 s = s + "super("; //$NON-NLS-1$
321 if (arguments != null)
322 for (int i = 0; i < arguments.length; i++) {
323 s = s + arguments[i].toStringExpression();
324 if (i != arguments.length - 1)
325 s = s + ", "; //$NON-NLS-1$
327 s = s + ")"; //$NON-NLS-1$
331 public void traverse(ASTVisitor visitor, BlockScope scope) {
333 if (visitor.visit(this, scope)) {
334 if (qualification != null) {
335 qualification.traverse(visitor, scope);
337 if (arguments != null) {
338 int argumentLength = arguments.length;
339 for (int i = 0; i < argumentLength; i++)
340 arguments[i].traverse(visitor, scope);
343 visitor.endVisit(this, scope);