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