Makefile fixup
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / ExplicitConstructorCall.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 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 org.eclipse.jdt.internal.compiler.ast;
12
13 import org.eclipse.jdt.internal.compiler.ASTVisitor;
14 import org.eclipse.jdt.internal.compiler.codegen.*;
15 import org.eclipse.jdt.internal.compiler.flow.*;
16 import org.eclipse.jdt.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, flowInfo);
80                         manageSyntheticAccessIfNecessary(currentScope, flowInfo);
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 = binding.declaringClass;
106                         // handling innerclass instance allocation - enclosing instance arguments
107                         if (targetType.isNestedType()) {
108                                 codeStream.generateSyntheticEnclosingInstanceValues(
109                                         currentScope,
110                                         targetType,
111                                         discardEnclosingInstance ? null : qualification,
112                                         this);
113                         }
114                         // regular code gen
115                         if (arguments != null) {
116                                 for (int i = 0, max = arguments.length; i < max; i++) {
117                                         arguments[i].generateCode(currentScope, codeStream, true);
118                                 }
119                         }
120                         // handling innerclass instance allocation - outer local arguments
121                         if (targetType.isNestedType()) {
122                                 codeStream.generateSyntheticOuterArgumentValues(
123                                         currentScope,
124                                         targetType,
125                                         this);
126                         }
127                         if (syntheticAccessor != null) {
128                                 // synthetic accessor got some extra arguments appended to its signature, which need values
129                                 for (int i = 0,
130                                         max = syntheticAccessor.parameters.length - binding.parameters.length;
131                                         i < max;
132                                         i++) {
133                                         codeStream.aconst_null();
134                                 }
135                                 codeStream.invokespecial(syntheticAccessor);
136                         } else {
137                                 codeStream.invokespecial(binding);
138                         }
139                         codeStream.recordPositionsFrom(pc, this.sourceStart);
140                 } finally {
141                         ((MethodScope) currentScope).isConstructorCall = false;
142                 }
143         }
144
145         public boolean isImplicitSuper() {
146                 //return true if I'm of these compiler added statement super();
147
148                 return (accessMode == ImplicitSuper);
149         }
150
151         public boolean isSuperAccess() {
152
153                 return accessMode != This;
154         }
155
156         public boolean isTypeAccess() {
157
158                 return true;
159         }
160
161         /* Inner emulation consists in either recording a dependency 
162          * link only, or performing one level of propagation.
163          *
164          * Dependency mechanism is used whenever dealing with source target
165          * types, since by the time we reach them, we might not yet know their
166          * exact need.
167          */
168         void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
169                 ReferenceBinding superType;
170
171                 if (!flowInfo.isReachable()) return;
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(currentScope, qualification != null);
178                         } else {
179                                 // locally propagate, since we already now the desired shape for sure
180                                 currentScope.propagateInnerEmulation(superType, qualification != null);
181                         }
182                 }
183         }
184
185         public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
186
187                 if (!flowInfo.isReachable()) return;
188                 // perform some emulation work in case there is some and we are inside a local type only
189                 if (binding.isPrivate() && (accessMode != This)) {
190
191                         if (currentScope
192                                 .environment()
193                                 .options
194                                 .isPrivateConstructorAccessChangingVisibility) {
195                                 binding.tagForClearingPrivateModifier();
196                                 // constructor will not be dumped as private, no emulation required thus
197                         } else {
198                                 syntheticAccessor =
199                                         ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding, isSuperAccess());
200                                 currentScope.problemReporter().needToEmulateMethodAccess(binding, this);
201                         }
202                 }
203         }
204
205         public StringBuffer printStatement(int indent, StringBuffer output) {
206
207                 printIndent(indent, output);
208                 if (qualification != null) qualification.printExpression(0, output).append('.');
209                 if (accessMode == This) {
210                         output.append("this("); //$NON-NLS-1$
211                 } else {
212                         output.append("super("); //$NON-NLS-1$
213                 }
214                 if (arguments != null) {
215                         for (int i = 0; i < arguments.length; i++) {
216                                 if (i > 0) output.append(", "); //$NON-NLS-1$
217                                 arguments[i].printExpression(0, output);
218                         }
219                 }
220                 return output.append(");"); //$NON-NLS-1$
221         }
222         
223         public void resolve(BlockScope scope) {
224                 // the return type should be void for a constructor.
225                 // the test is made into getConstructor
226
227                 // mark the fact that we are in a constructor call.....
228                 // unmark at all returns
229                 MethodScope methodScope = scope.methodScope();
230                 try {
231                         AbstractMethodDeclaration methodDeclaration = methodScope.referenceMethod();
232                         if (methodDeclaration == null 
233                                         || !methodDeclaration.isConstructor()
234                                         || ((ConstructorDeclaration) methodDeclaration).constructorCall != this) {
235                                 scope.problemReporter().invalidExplicitConstructorCall(this);
236                                 return;
237                         }
238                         methodScope.isConstructorCall = true;
239                         ReferenceBinding receiverType = scope.enclosingSourceType();
240                         if (accessMode != This)
241                                 receiverType = receiverType.superclass();
242
243                         if (receiverType == null) {
244                                 return;
245                         }
246
247                         // qualification should be from the type of the enclosingType
248                         if (qualification != null) {
249                                 if (accessMode != Super) {
250                                         scope.problemReporter().unnecessaryEnclosingInstanceSpecification(
251                                                 qualification,
252                                                 receiverType);
253                                 }
254                                 ReferenceBinding enclosingType = receiverType.enclosingType();
255                                 if (enclosingType == null) {
256                                         scope.problemReporter().unnecessaryEnclosingInstanceSpecification(
257                                                 qualification,
258                                                 receiverType);
259                                         discardEnclosingInstance = true;
260                                 } else {
261                                         TypeBinding qTb = qualification.resolveTypeExpecting(scope, enclosingType);
262                                         qualification.implicitWidening(qTb, qTb);
263                                 }
264                         }
265
266                         // arguments buffering for the method lookup
267                         TypeBinding[] argumentTypes = NoParameters;
268                         boolean argsContainCast = false;
269                         if (arguments != null) {
270                                 boolean argHasError = false; // typeChecks all arguments
271                                 int length = arguments.length;
272                                 argumentTypes = new TypeBinding[length];
273                                 for (int i = 0; i < length; i++) {
274                                         Expression argument = this.arguments[i];
275                                         if (argument instanceof CastExpression) {
276                                                 argument.bits |= IgnoreNeedForCastCheckMASK; // will check later on
277                                                 argsContainCast = true;
278                                         }
279                                         if ((argumentTypes[i] = argument.resolveType(scope)) == null) {
280                                                 argHasError = true;
281                                         }
282                                 }
283                                 if (argHasError) {
284                                         return;
285                                 }
286                         }
287                         if ((binding = scope.getConstructor(receiverType, argumentTypes, this)).isValidBinding()) {
288                                 if (isMethodUseDeprecated(binding, scope))
289                                         scope.problemReporter().deprecatedMethod(binding, this);
290
291                                 // see for user-implicit widening conversion 
292                                 if (arguments != null) {
293                                         int length = arguments.length;
294                                         TypeBinding[] paramTypes = binding.parameters;
295                                         for (int i = 0; i < length; i++) {
296                                                 arguments[i].implicitWidening(paramTypes[i], argumentTypes[i]);
297                                         }
298                                         if (argsContainCast) {
299                                                 CastExpression.checkNeedForArgumentCasts(scope, null, receiverType, binding, this.arguments, argumentTypes, this);
300                                         }
301                                 }
302                                 if (binding.isPrivate()) {
303                                         binding.modifiers |= AccPrivateUsed;
304                                 }                               
305                         } else {
306                                 if (binding.declaringClass == null)
307                                         binding.declaringClass = receiverType;
308                                 scope.problemReporter().invalidConstructor(this, binding);
309                         }
310                 } finally {
311                         methodScope.isConstructorCall = false;
312                 }
313         }
314
315         public void setActualReceiverType(ReferenceBinding receiverType) {
316                 // ignored
317         }
318
319         public void setDepth(int depth) {
320                 // ignore for here
321         }
322
323         public void setFieldIndex(int depth) {
324                 // ignore for here
325         }
326
327         public void traverse(ASTVisitor visitor, BlockScope scope) {
328
329                 if (visitor.visit(this, scope)) {
330                         if (this.qualification != null) {
331                                 this.qualification.traverse(visitor, scope);
332                         }
333                         if (this.arguments != null) {
334                                 for (int i = 0, argumentLength = this.arguments.length; i < argumentLength; i++)
335                                         this.arguments[i].traverse(visitor, scope);
336                         }
337                 }
338                 visitor.endVisit(this, scope);
339         }
340 }