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.phpdt.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 extends Statement implements
29 public Expression[] arguments;
31 public Expression qualification;
33 public MethodBinding binding;
35 public int accessMode;
37 public final static int ImplicitSuper = 1;
39 public final static int Super = 2;
41 public final static int This = 3;
43 public VariableBinding[][] implicitArguments;
45 boolean discardEnclosingInstance;
47 MethodBinding syntheticAccessor;
49 public ExplicitConstructorCall(int accessMode) {
50 this.accessMode = accessMode;
53 public FlowInfo analyseCode(BlockScope currentScope,
54 FlowContext flowContext, FlowInfo flowInfo) {
56 // must verify that exceptions potentially thrown by this expression are
57 // caught in the method.
60 ((MethodScope) currentScope).isConstructorCall = true;
62 // process enclosing instance
63 if (qualification != null) {
64 flowInfo = qualification.analyseCode(currentScope, flowContext,
65 flowInfo).unconditionalInits();
68 if (arguments != null) {
69 for (int i = 0, max = arguments.length; i < max; i++) {
70 flowInfo = arguments[i].analyseCode(currentScope,
71 flowContext, flowInfo).unconditionalInits();
75 ReferenceBinding[] thrownExceptions;
76 if ((thrownExceptions = binding.thrownExceptions) != NoExceptions) {
78 flowContext.checkExceptionHandlers(thrownExceptions,
79 (accessMode == ImplicitSuper) ? (ASTNode) currentScope
80 .methodScope().referenceContext
81 : (ASTNode) this, flowInfo, currentScope);
83 manageEnclosingInstanceAccessIfNecessary(currentScope);
84 manageSyntheticAccessIfNecessary(currentScope);
87 ((MethodScope) currentScope).isConstructorCall = false;
92 * Constructor call code generation
95 * net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
97 * net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
99 // public void generateCode(BlockScope currentScope, CodeStream codeStream)
102 // if ((bits & IsReachableMASK) == 0) {
106 // ((MethodScope) currentScope).isConstructorCall = true;
108 // int pc = codeStream.position;
109 // codeStream.aload_0();
111 // // handling innerclass constructor invocation
112 // ReferenceBinding targetType = binding.declaringClass;
113 // // handling innerclass instance allocation - enclosing instance arguments
114 // if (targetType.isNestedType()) {
115 // codeStream.generateSyntheticEnclosingInstanceValues(
118 // discardEnclosingInstance ? null : qualification,
121 // // regular code gen
122 // if (arguments != null) {
123 // for (int i = 0, max = arguments.length; i < max; i++) {
124 // arguments[i].generateCode(currentScope, codeStream, true);
127 // // handling innerclass instance allocation - outer local arguments
128 // if (targetType.isNestedType()) {
129 // codeStream.generateSyntheticOuterArgumentValues(
134 // if (syntheticAccessor != null) {
135 // // synthetic accessor got some extra arguments appended to its signature,
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;
152 public boolean isImplicitSuper() {
153 // return true if I'm of these compiler added statement super();
155 return (accessMode == ImplicitSuper);
158 public boolean isSuperAccess() {
160 return accessMode != This;
163 public boolean isTypeAccess() {
169 * Inner emulation consists in either recording a dependency link only, or
170 * performing one level of propagation.
172 * Dependency mechanism is used whenever dealing with source target types,
173 * since by the time we reach them, we might not yet know their exact need.
175 void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
176 ReferenceBinding superType;
178 // perform some emulation work in case there is some and we are inside a
180 if ((superType = binding.declaringClass).isNestedType()
181 && currentScope.enclosingSourceType().isLocalType()) {
183 if (superType.isLocalType()) {
184 ((LocalTypeBinding) superType).addInnerEmulationDependent(
185 currentScope, qualification != null);
187 // locally propagate, since we already now the desired shape for
189 currentScope.propagateInnerEmulation(superType,
190 qualification != null);
195 public void manageSyntheticAccessIfNecessary(BlockScope currentScope) {
197 // perform some emulation work in case there is some and we are inside a
199 if (binding.isPrivate() && (accessMode != This)) {
204 // .isPrivateConstructorAccessChangingVisibility) {
205 // binding.tagForClearingPrivateModifier();
206 // // constructor will not be dumped as private, no emulation
209 syntheticAccessor = ((SourceTypeBinding) binding.declaringClass)
210 .addSyntheticMethod(binding, isSuperAccess());
211 currentScope.problemReporter().needToEmulateMethodAccess(binding,
217 public void resolve(BlockScope scope) {
218 // the return type should be void for a constructor.
219 // the test is made into getConstructor
221 // mark the fact that we are in a constructor call.....
222 // unmark at all returns
224 ((MethodScope) scope).isConstructorCall = true;
225 ReferenceBinding receiverType = scope.enclosingSourceType();
226 if (accessMode != This)
227 receiverType = receiverType.superclass();
229 if (receiverType == null) {
233 // qualification should be from the type of the enclosingType
234 if (qualification != null) {
235 if (accessMode != Super) {
236 scope.problemReporter()
237 .unnecessaryEnclosingInstanceSpecification(
238 qualification, receiverType);
240 ReferenceBinding enclosingType = receiverType.enclosingType();
241 if (enclosingType == null) {
242 scope.problemReporter()
243 .unnecessaryEnclosingInstanceSpecification(
244 qualification, receiverType);
245 discardEnclosingInstance = true;
247 TypeBinding qTb = qualification.resolveTypeExpecting(scope,
249 qualification.implicitWidening(qTb, qTb);
253 // arguments buffering for the method lookup
254 TypeBinding[] argTypes = NoParameters;
255 if (arguments != null) {
256 boolean argHasError = false; // typeChecks all arguments
257 int length = arguments.length;
258 argTypes = new TypeBinding[length];
259 for (int i = 0; i < length; i++)
260 if ((argTypes[i] = arguments[i].resolveType(scope)) == null)
265 if ((binding = scope.getConstructor(receiverType, argTypes, this))
267 if (isMethodUseDeprecated(binding, scope))
268 scope.problemReporter().deprecatedMethod(binding, this);
270 // see for user-implicit widening conversion
271 if (arguments != null) {
272 int length = arguments.length;
273 TypeBinding[] paramTypes = binding.parameters;
274 for (int i = 0; i < length; i++)
275 arguments[i].implicitWidening(paramTypes[i],
278 if (binding.isPrivate()) {
279 binding.modifiers |= AccPrivateUsed;
282 if (binding.declaringClass == null)
283 binding.declaringClass = receiverType;
284 scope.problemReporter().invalidConstructor(this, binding);
287 ((MethodScope) scope).isConstructorCall = false;
291 public void setActualReceiverType(ReferenceBinding receiverType) {
295 public void setDepth(int depth) {
299 public void setFieldIndex(int depth) {
303 public StringBuffer printStatement(int indent, StringBuffer output) {
305 printIndent(indent, output);
306 if (qualification != null)
307 qualification.printExpression(0, output).append('.');
308 if (accessMode == This) {
309 output.append("this("); //$NON-NLS-1$
311 output.append("super("); //$NON-NLS-1$
313 if (arguments != null) {
314 for (int i = 0; i < arguments.length; i++) {
316 output.append(", "); //$NON-NLS-1$
317 arguments[i].printExpression(0, output);
320 return output.append(");"); //$NON-NLS-1$
323 public String toString(int tab) {
325 String s = tabString(tab);
326 if (qualification != null)
327 s = s + qualification.toStringExpression() + "."; //$NON-NLS-1$
328 if (accessMode == This) {
329 s = s + "this("; //$NON-NLS-1$
331 s = s + "super("; //$NON-NLS-1$
333 if (arguments != null)
334 for (int i = 0; i < arguments.length; i++) {
335 s = s + arguments[i].toStringExpression();
336 if (i != arguments.length - 1)
337 s = s + ", "; //$NON-NLS-1$
339 s = s + ")"; //$NON-NLS-1$
343 public void traverse(ASTVisitor visitor, BlockScope scope) {
345 if (visitor.visit(this, scope)) {
346 if (qualification != null) {
347 qualification.traverse(visitor, scope);
349 if (arguments != null) {
350 int argumentLength = arguments.length;
351 for (int i = 0; i < argumentLength; i++)
352 arguments[i].traverse(visitor, scope);
355 visitor.endVisit(this, scope);