A massive organize imports and formatting of the sources using default Eclipse code...
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / ExplicitConstructorCall.java
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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
12
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;
25
26 public class ExplicitConstructorCall extends Statement implements
27                 InvocationSite {
28
29         public Expression[] arguments;
30
31         public Expression qualification;
32
33         public MethodBinding binding;
34
35         public int accessMode;
36
37         public final static int ImplicitSuper = 1;
38
39         public final static int Super = 2;
40
41         public final static int This = 3;
42
43         public VariableBinding[][] implicitArguments;
44
45         boolean discardEnclosingInstance;
46
47         MethodBinding syntheticAccessor;
48
49         public ExplicitConstructorCall(int accessMode) {
50                 this.accessMode = accessMode;
51         }
52
53         public FlowInfo analyseCode(BlockScope currentScope,
54                         FlowContext flowContext, FlowInfo flowInfo) {
55
56                 // must verify that exceptions potentially thrown by this expression are
57                 // caught in the method.
58
59                 try {
60                         ((MethodScope) currentScope).isConstructorCall = true;
61
62                         // process enclosing instance
63                         if (qualification != null) {
64                                 flowInfo = qualification.analyseCode(currentScope, flowContext,
65                                                 flowInfo).unconditionalInits();
66                         }
67                         // process arguments
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();
72                                 }
73                         }
74
75                         ReferenceBinding[] thrownExceptions;
76                         if ((thrownExceptions = binding.thrownExceptions) != NoExceptions) {
77                                 // check exceptions
78                                 flowContext.checkExceptionHandlers(thrownExceptions,
79                                                 (accessMode == ImplicitSuper) ? (ASTNode) currentScope
80                                                                 .methodScope().referenceContext
81                                                                 : (ASTNode) this, flowInfo, currentScope);
82                         }
83                         manageEnclosingInstanceAccessIfNecessary(currentScope);
84                         manageSyntheticAccessIfNecessary(currentScope);
85                         return flowInfo;
86                 } finally {
87                         ((MethodScope) currentScope).isConstructorCall = false;
88                 }
89         }
90
91         /**
92          * Constructor call code generation
93          * 
94          * @param currentScope
95          *            net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
96          * @param codeStream
97          *            net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
98          */
99         // public void generateCode(BlockScope currentScope, CodeStream codeStream)
100         // {
101         //
102         // if ((bits & IsReachableMASK) == 0) {
103         // return;
104         // }
105         // try {
106         // ((MethodScope) currentScope).isConstructorCall = true;
107         //
108         // int pc = codeStream.position;
109         // codeStream.aload_0();
110         //
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(
116         // currentScope,
117         // targetType,
118         // discardEnclosingInstance ? null : qualification,
119         // this);
120         // }
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);
125         // }
126         // }
127         // // handling innerclass instance allocation - outer local arguments
128         // if (targetType.isNestedType()) {
129         // codeStream.generateSyntheticOuterArgumentValues(
130         // currentScope,
131         // targetType,
132         // this);
133         // }
134         // if (syntheticAccessor != null) {
135         // // synthetic accessor got some extra arguments appended to its signature,
136         // which need values
137         // for (int i = 0,
138         // max = syntheticAccessor.parameters.length - binding.parameters.length;
139         // i < max;
140         // i++) {
141         // codeStream.aconst_null();
142         // }
143         // codeStream.invokespecial(syntheticAccessor);
144         // } else {
145         // codeStream.invokespecial(binding);
146         // }
147         // codeStream.recordPositionsFrom(pc, this.sourceStart);
148         // } finally {
149         // ((MethodScope) currentScope).isConstructorCall = false;
150         // }
151         // }
152         public boolean isImplicitSuper() {
153                 // return true if I'm of these compiler added statement super();
154
155                 return (accessMode == ImplicitSuper);
156         }
157
158         public boolean isSuperAccess() {
159
160                 return accessMode != This;
161         }
162
163         public boolean isTypeAccess() {
164
165                 return true;
166         }
167
168         /*
169          * Inner emulation consists in either recording a dependency link only, or
170          * performing one level of propagation.
171          * 
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.
174          */
175         void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
176                 ReferenceBinding superType;
177
178                 // perform some emulation work in case there is some and we are inside a
179                 // local type only
180                 if ((superType = binding.declaringClass).isNestedType()
181                                 && currentScope.enclosingSourceType().isLocalType()) {
182
183                         if (superType.isLocalType()) {
184                                 ((LocalTypeBinding) superType).addInnerEmulationDependent(
185                                                 currentScope, qualification != null);
186                         } else {
187                                 // locally propagate, since we already now the desired shape for
188                                 // sure
189                                 currentScope.propagateInnerEmulation(superType,
190                                                 qualification != null);
191                         }
192                 }
193         }
194
195         public void manageSyntheticAccessIfNecessary(BlockScope currentScope) {
196
197                 // perform some emulation work in case there is some and we are inside a
198                 // local type only
199                 if (binding.isPrivate() && (accessMode != This)) {
200
201                         // if (currentScope
202                         // .environment()
203                         // .options
204                         // .isPrivateConstructorAccessChangingVisibility) {
205                         // binding.tagForClearingPrivateModifier();
206                         // // constructor will not be dumped as private, no emulation
207                         // required thus
208                         // } else {
209                         syntheticAccessor = ((SourceTypeBinding) binding.declaringClass)
210                                         .addSyntheticMethod(binding, isSuperAccess());
211                         currentScope.problemReporter().needToEmulateMethodAccess(binding,
212                                         this);
213                         // }
214                 }
215         }
216
217         public void resolve(BlockScope scope) {
218                 // the return type should be void for a constructor.
219                 // the test is made into getConstructor
220
221                 // mark the fact that we are in a constructor call.....
222                 // unmark at all returns
223                 try {
224                         ((MethodScope) scope).isConstructorCall = true;
225                         ReferenceBinding receiverType = scope.enclosingSourceType();
226                         if (accessMode != This)
227                                 receiverType = receiverType.superclass();
228
229                         if (receiverType == null) {
230                                 return;
231                         }
232
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);
239                                 }
240                                 ReferenceBinding enclosingType = receiverType.enclosingType();
241                                 if (enclosingType == null) {
242                                         scope.problemReporter()
243                                                         .unnecessaryEnclosingInstanceSpecification(
244                                                                         qualification, receiverType);
245                                         discardEnclosingInstance = true;
246                                 } else {
247                                         TypeBinding qTb = qualification.resolveTypeExpecting(scope,
248                                                         enclosingType);
249                                         qualification.implicitWidening(qTb, qTb);
250                                 }
251                         }
252
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)
261                                                 argHasError = true;
262                                 if (argHasError)
263                                         return;
264                         }
265                         if ((binding = scope.getConstructor(receiverType, argTypes, this))
266                                         .isValidBinding()) {
267                                 if (isMethodUseDeprecated(binding, scope))
268                                         scope.problemReporter().deprecatedMethod(binding, this);
269
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],
276                                                                 argTypes[i]);
277                                 }
278                                 if (binding.isPrivate()) {
279                                         binding.modifiers |= AccPrivateUsed;
280                                 }
281                         } else {
282                                 if (binding.declaringClass == null)
283                                         binding.declaringClass = receiverType;
284                                 scope.problemReporter().invalidConstructor(this, binding);
285                         }
286                 } finally {
287                         ((MethodScope) scope).isConstructorCall = false;
288                 }
289         }
290
291         public void setActualReceiverType(ReferenceBinding receiverType) {
292                 // ignored
293         }
294
295         public void setDepth(int depth) {
296                 // ignore for here
297         }
298
299         public void setFieldIndex(int depth) {
300                 // ignore for here
301         }
302
303         public StringBuffer printStatement(int indent, StringBuffer output) {
304
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$
310                 } else {
311                         output.append("super("); //$NON-NLS-1$
312                 }
313                 if (arguments != null) {
314                         for (int i = 0; i < arguments.length; i++) {
315                                 if (i > 0)
316                                         output.append(", "); //$NON-NLS-1$
317                                 arguments[i].printExpression(0, output);
318                         }
319                 }
320                 return output.append(");"); //$NON-NLS-1$
321         }
322
323         public String toString(int tab) {
324
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$
330                 } else {
331                         s = s + "super("; //$NON-NLS-1$
332                 }
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$
338                         }
339                 s = s + ")"; //$NON-NLS-1$
340                 return s;
341         }
342
343         public void traverse(ASTVisitor visitor, BlockScope scope) {
344
345                 if (visitor.visit(this, scope)) {
346                         if (qualification != null) {
347                                 qualification.traverse(visitor, scope);
348                         }
349                         if (arguments != null) {
350                                 int argumentLength = arguments.length;
351                                 for (int i = 0; i < argumentLength; i++)
352                                         arguments[i].traverse(visitor, scope);
353                         }
354                 }
355                 visitor.endVisit(this, scope);
356         }
357 }