*** empty log message ***
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / ExplicitConstructorCall.java
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
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.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.codegen.CodeStream;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
16 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
17 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
18 import net.sourceforge.phpdt.internal.compiler.lookup.InvocationSite;
19 import net.sourceforge.phpdt.internal.compiler.lookup.LocalTypeBinding;
20 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
21 import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope;
22 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
23 import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding;
24 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
25 import net.sourceforge.phpdt.internal.compiler.lookup.VariableBinding;
26
27 public class ExplicitConstructorCall
28         extends Statement
29         implements InvocationSite {
30                 
31         public Expression[] arguments;
32         public Expression qualification;
33         public MethodBinding binding;
34
35         public int accessMode;
36
37         public final static int ImplicitSuper = 1;
38         public final static int Super = 2;
39         public final static int This = 3;
40
41         public VariableBinding[][] implicitArguments;
42         boolean discardEnclosingInstance;
43
44         MethodBinding syntheticAccessor;
45
46         public ExplicitConstructorCall(int accessMode) {
47                 this.accessMode = accessMode;
48         }
49
50         public FlowInfo analyseCode(
51                 BlockScope currentScope,
52                 FlowContext flowContext,
53                 FlowInfo flowInfo) {
54
55                 // must verify that exceptions potentially thrown by this expression are caught in the method.
56
57                 try {
58                         ((MethodScope) currentScope).isConstructorCall = true;
59
60                         // process enclosing instance
61                         if (qualification != null) {
62                                 flowInfo =
63                                         qualification
64                                                 .analyseCode(currentScope, flowContext, flowInfo)
65                                                 .unconditionalInits();
66                         }
67                         // process arguments
68                         if (arguments != null) {
69                                 for (int i = 0, max = arguments.length; i < max; i++) {
70                                         flowInfo =
71                                                 arguments[i]
72                                                         .analyseCode(currentScope, flowContext, flowInfo)
73                                                         .unconditionalInits();
74                                 }
75                         }
76
77                         ReferenceBinding[] thrownExceptions;
78                         if ((thrownExceptions = binding.thrownExceptions) != NoExceptions) {
79                                 // check exceptions
80                                 flowContext.checkExceptionHandlers(
81                                         thrownExceptions,
82                                         (accessMode == ImplicitSuper)
83                                                 ? (AstNode) currentScope.methodScope().referenceContext
84                                                 : (AstNode) this,
85                                         flowInfo,
86                                         currentScope);
87                         }
88                         manageEnclosingInstanceAccessIfNecessary(currentScope);
89                         manageSyntheticAccessIfNecessary(currentScope);
90                         return flowInfo;
91                 } finally {
92                         ((MethodScope) currentScope).isConstructorCall = false;
93                 }
94         }
95
96         /**
97          * Constructor call code generation
98          *
99          * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
100          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
101          */
102         public void generateCode(BlockScope currentScope, CodeStream codeStream) {
103
104                 if ((bits & IsReachableMASK) == 0) {
105                         return;
106                 }
107                 try {
108                         ((MethodScope) currentScope).isConstructorCall = true;
109
110                         int pc = codeStream.position;
111                         codeStream.aload_0();
112
113                         // handling innerclass constructor invocation
114                         ReferenceBinding targetType;
115                         if ((targetType = binding.declaringClass).isNestedType()) {
116                                 codeStream.generateSyntheticArgumentValues(
117                                         currentScope,
118                                         targetType,
119                                         discardEnclosingInstance ? null : qualification,
120                                         this);
121                         }
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);
126                                 }
127                         }
128                         if (syntheticAccessor != null) {
129                                 // synthetic accessor got some extra arguments appended to its signature, which need values
130                                 for (int i = 0,
131                                         max = syntheticAccessor.parameters.length - binding.parameters.length;
132                                         i < max;
133                                         i++) {
134                                         codeStream.aconst_null();
135                                 }
136                                 codeStream.invokespecial(syntheticAccessor);
137                         } else {
138                                 codeStream.invokespecial(binding);
139                         }
140                         codeStream.recordPositionsFrom(pc, this.sourceStart);
141                 } finally {
142                         ((MethodScope) currentScope).isConstructorCall = false;
143                 }
144         }
145
146         public boolean isImplicitSuper() {
147                 //return true if I'm of these compiler added statement super();
148
149                 return (accessMode == ImplicitSuper);
150         }
151
152         public boolean isSuperAccess() {
153
154                 return accessMode != This;
155         }
156
157         public boolean isTypeAccess() {
158
159                 return true;
160         }
161
162         /* Inner emulation consists in either recording a dependency 
163          * link only, or performing one level of propagation.
164          *
165          * Dependency mechanism is used whenever dealing with source target
166          * types, since by the time we reach them, we might not yet know their
167          * exact need.
168          */
169         void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
170                 ReferenceBinding superType;
171
172                 // perform some emulation work in case there is some and we are inside a local type only
173                 if ((superType = binding.declaringClass).isNestedType()
174                         && currentScope.enclosingSourceType().isLocalType()) {
175
176                         if (superType.isLocalType()) {
177                                 ((LocalTypeBinding) superType).addInnerEmulationDependent(
178                                         currentScope,
179                                         qualification != null,
180                                         true);
181                                 // request direct access
182                         } else {
183                                 // locally propagate, since we already now the desired shape for sure
184                                 currentScope.propagateInnerEmulation(superType, qualification != null, true);
185                                 // request direct access
186
187                         }
188                 }
189         }
190
191         public void manageSyntheticAccessIfNecessary(BlockScope currentScope) {
192
193                 // perform some emulation work in case there is some and we are inside a local type only
194                 if (binding.isPrivate() && (accessMode != This)) {
195
196                         if (currentScope
197                                 .environment()
198                                 .options
199                                 .isPrivateConstructorAccessChangingVisibility) {
200                                 binding.tagForClearingPrivateModifier();
201                                 // constructor will not be dumped as private, no emulation required thus
202                         } else {
203                                 syntheticAccessor =
204                                         ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding);
205                                 currentScope.problemReporter().needToEmulateMethodAccess(binding, this);
206                         }
207                 }
208         }
209
210         public void resolve(BlockScope scope) {
211                 // the return type should be void for a constructor.
212                 // the test is made into getConstructor
213
214                 // mark the fact that we are in a constructor call.....
215                 // unmark at all returns
216                 try {
217                         ((MethodScope) scope).isConstructorCall = true;
218                         ReferenceBinding receiverType = scope.enclosingSourceType();
219                         if (accessMode != This)
220                                 receiverType = receiverType.superclass();
221
222                         if (receiverType == null) {
223                                 return;
224                         }
225
226                         // qualification should be from the type of the enclosingType
227                         if (qualification != null) {
228                                 if (accessMode != Super) {
229                                         scope.problemReporter().unnecessaryEnclosingInstanceSpecification(
230                                                 qualification,
231                                                 receiverType);
232                                 }
233                                 ReferenceBinding enclosingType = receiverType.enclosingType();
234                                 if (enclosingType == null) {
235                                         scope.problemReporter().unnecessaryEnclosingInstanceSpecification(
236                                                 qualification,
237                                                 receiverType);
238                                         discardEnclosingInstance = true;
239                                 } else {
240                                         TypeBinding qTb = qualification.resolveTypeExpecting(scope, enclosingType);
241                                         qualification.implicitWidening(qTb, qTb);
242                                 }
243                         }
244
245                         // arguments buffering for the method lookup
246                         TypeBinding[] argTypes = NoParameters;
247                         if (arguments != null) {
248                                 boolean argHasError = false; // typeChecks all arguments
249                                 int length = arguments.length;
250                                 argTypes = new TypeBinding[length];
251                                 for (int i = 0; i < length; i++)
252                                         if ((argTypes[i] = arguments[i].resolveType(scope)) == null)
253                                                 argHasError = true;
254                                 if (argHasError)
255                                         return;
256                         }
257                         if ((binding = scope.getConstructor(receiverType, argTypes, this))
258                                 .isValidBinding()) {
259                                 if (isMethodUseDeprecated(binding, scope))
260                                         scope.problemReporter().deprecatedMethod(binding, this);
261
262                                 // see for user-implicit widening conversion 
263                                 if (arguments != null) {
264                                         int length = arguments.length;
265                                         TypeBinding[] paramTypes = binding.parameters;
266                                         for (int i = 0; i < length; i++)
267                                                 arguments[i].implicitWidening(paramTypes[i], argTypes[i]);
268                                 }
269                         } else {
270                                 if (binding.declaringClass == null)
271                                         binding.declaringClass = receiverType;
272                                 scope.problemReporter().invalidConstructor(this, binding);
273                         }
274                 } finally {
275                         ((MethodScope) scope).isConstructorCall = false;
276                 }
277         }
278
279         public void setActualReceiverType(ReferenceBinding receiverType) {
280                 // ignored
281         }
282
283         public void setDepth(int depth) {
284                 // ignore for here
285         }
286
287         public void setFieldIndex(int depth) {
288                 // ignore for here
289         }
290
291         public String toString(int tab) {
292
293                 String s = tabString(tab);
294                 if (qualification != null)
295                         s = s + qualification.toStringExpression() + "."; //$NON-NLS-1$
296                 if (accessMode == This) {
297                         s = s + "this("; //$NON-NLS-1$
298                 } else {
299                         s = s + "super("; //$NON-NLS-1$
300                 }
301                 if (arguments != null)
302                         for (int i = 0; i < arguments.length; i++) {
303                                 s = s + arguments[i].toStringExpression();
304                                 if (i != arguments.length - 1)
305                                         s = s + ", "; //$NON-NLS-1$
306                         }
307                 s = s + ")"; //$NON-NLS-1$
308                 return s;
309         }
310
311         public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
312
313                 if (visitor.visit(this, scope)) {
314                         if (qualification != null) {
315                                 qualification.traverse(visitor, scope);
316                         }
317                         if (arguments != null) {
318                                 int argumentLength = arguments.length;
319                                 for (int i = 0; i < argumentLength; i++)
320                                         arguments[i].traverse(visitor, scope);
321                         }
322                 }
323                 visitor.endVisit(this, scope);
324         }
325 }