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