KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > ast > ExplicitConstructorCall


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-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.classfmt.ClassFileConstants;
15 import org.eclipse.jdt.internal.compiler.codegen.*;
16 import org.eclipse.jdt.internal.compiler.flow.*;
17 import org.eclipse.jdt.internal.compiler.lookup.*;
18
19 public class ExplicitConstructorCall extends Statement implements InvocationSite {
20         
21     public Expression[] arguments;
22     public Expression qualification;
23     public MethodBinding binding; // exact binding resulting from lookup
24
protected MethodBinding codegenBinding; // actual binding used for code generation (if no synthetic accessor)
25
MethodBinding syntheticAccessor; // synthetic accessor for inner-emulation
26
public int accessMode;
27     public TypeReference[] typeArguments;
28     public TypeBinding[] genericTypeArguments;
29     
30     public final static int ImplicitSuper = 1;
31     public final static int Super = 2;
32     public final static int This = 3;
33
34     public VariableBinding[][] implicitArguments;
35     
36     // TODO Remove once DOMParser is activated
37
public int typeArgumentsSourceStart;
38
39     public ExplicitConstructorCall(int accessMode) {
40         this.accessMode = accessMode;
41     }
42
43     public FlowInfo analyseCode(
44         BlockScope currentScope,
45         FlowContext flowContext,
46         FlowInfo flowInfo) {
47
48         // must verify that exceptions potentially thrown by this expression are caught in the method.
49

50         try {
51             ((MethodScope) currentScope).isConstructorCall = true;
52
53             // process enclosing instance
54
if (qualification != null) {
55                 flowInfo =
56                     qualification
57                         .analyseCode(currentScope, flowContext, flowInfo)
58                         .unconditionalInits();
59             }
60             // process arguments
61
if (arguments != null) {
62                 for (int i = 0, max = arguments.length; i < max; i++) {
63                     flowInfo =
64                         arguments[i]
65                             .analyseCode(currentScope, flowContext, flowInfo)
66                             .unconditionalInits();
67                 }
68             }
69
70             ReferenceBinding[] thrownExceptions;
71             if ((thrownExceptions = binding.thrownExceptions) != Binding.NO_EXCEPTIONS) {
72                 // check exceptions
73
flowContext.checkExceptionHandlers(
74                     thrownExceptions,
75                     (accessMode == ImplicitSuper)
76                         ? (ASTNode) currentScope.methodScope().referenceContext
77                         : (ASTNode) this,
78                     flowInfo,
79                     currentScope);
80             }
81             manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
82             manageSyntheticAccessIfNecessary(currentScope, flowInfo);
83             return flowInfo;
84         } finally {
85             ((MethodScope) currentScope).isConstructorCall = false;
86         }
87     }
88
89     /**
90      * Constructor call code generation
91      *
92      * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
93      * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
94      */

95     public void generateCode(BlockScope currentScope, CodeStream codeStream) {
96
97         if ((bits & IsReachable) == 0) {
98             return;
99         }
100         try {
101             ((MethodScope) currentScope).isConstructorCall = true;
102
103             int pc = codeStream.position;
104             codeStream.aload_0();
105
106             ReferenceBinding targetType = this.codegenBinding.declaringClass;
107             
108             // special name&ordinal argument generation for enum constructors
109
if (targetType.erasure().id == T_JavaLangEnum || targetType.isEnum()) {
110                 codeStream.aload_1(); // pass along name param as name arg
111
codeStream.iload_2(); // pass along ordinal param as ordinal arg
112
}
113             // handling innerclass constructor invocation
114
// handling innerclass instance allocation - enclosing instance arguments
115
if (targetType.isNestedType()) {
116                 codeStream.generateSyntheticEnclosingInstanceValues(
117                     currentScope,
118                     targetType,
119                     (this.bits & ASTNode.DiscardEnclosingInstance) != 0 ? null : qualification,
120                     this);
121             }
122             // generate arguments
123
generateArguments(binding, arguments, currentScope, codeStream);
124             
125             // handling innerclass instance allocation - outer local arguments
126
if (targetType.isNestedType()) {
127                 codeStream.generateSyntheticOuterArgumentValues(
128                     currentScope,
129                     targetType,
130                     this);
131             }
132             if (syntheticAccessor != null) {
133                 // synthetic accessor got some extra arguments appended to its signature, which need values
134
for (int i = 0,
135                     max = syntheticAccessor.parameters.length - this.codegenBinding.parameters.length;
136                     i < max;
137                     i++) {
138                     codeStream.aconst_null();
139                 }
140                 codeStream.invokespecial(syntheticAccessor);
141             } else {
142                 codeStream.invokespecial(this.codegenBinding);
143             }
144             codeStream.recordPositionsFrom(pc, this.sourceStart);
145         } finally {
146             ((MethodScope) currentScope).isConstructorCall = false;
147         }
148     }
149     /**
150      * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments()
151      */

152     public TypeBinding[] genericTypeArguments() {
153         return this.genericTypeArguments;
154     }
155     public boolean isImplicitSuper() {
156         //return true if I'm of these compiler added statement super();
157

158         return (accessMode == ImplicitSuper);
159     }
160
161     public boolean isSuperAccess() {
162
163         return accessMode != This;
164     }
165
166     public boolean isTypeAccess() {
167
168         return true;
169     }
170
171     /* Inner emulation consists in either recording a dependency
172      * link only, or performing one level of propagation.
173      *
174      * Dependency mechanism is used whenever dealing with source target
175      * types, since by the time we reach them, we might not yet know their
176      * exact need.
177      */

178     void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
179         ReferenceBinding superTypeErasure = (ReferenceBinding) binding.declaringClass.erasure();
180
181         if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
182         // perform some emulation work in case there is some and we are inside a local type only
183
if (superTypeErasure.isNestedType()
184             && currentScope.enclosingSourceType().isLocalType()) {
185
186             if (superTypeErasure.isLocalType()) {
187                 ((LocalTypeBinding) superTypeErasure).addInnerEmulationDependent(currentScope, qualification != null);
188             } else {
189                 // locally propagate, since we already now the desired shape for sure
190
currentScope.propagateInnerEmulation(superTypeErasure, qualification != null);
191             }
192         }
193         }
194     }
195
196     public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
197
198         if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
199         // if constructor from parameterized type got found, use the original constructor at codegen time
200
this.codegenBinding = this.binding.original();
201         
202         // perform some emulation work in case there is some and we are inside a local type only
203
if (binding.isPrivate() && accessMode != This) {
204             ReferenceBinding declaringClass = this.codegenBinding.declaringClass;
205             // from 1.4 on, local type constructor can lose their private flag to ease emulation
206
if ((declaringClass.tagBits & TagBits.IsLocalType) != 0 && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) {
207                 // constructor will not be dumped as private, no emulation required thus
208
this.codegenBinding.tagBits |= TagBits.ClearPrivateModifier;
209             } else {
210                 syntheticAccessor = ((SourceTypeBinding) declaringClass).addSyntheticMethod(this.codegenBinding, isSuperAccess());
211                 currentScope.problemReporter().needToEmulateMethodAccess(this.codegenBinding, this);
212             }
213         }
214         }
215     }
216
217     public StringBuffer JavaDoc printStatement(int indent, StringBuffer JavaDoc output) {
218
219         printIndent(indent, output);
220         if (qualification != null) qualification.printExpression(0, output).append('.');
221         if (typeArguments != null) {
222             output.append('<');
223             int max = typeArguments.length - 1;
224             for (int j = 0; j < max; j++) {
225                 typeArguments[j].print(0, output);
226                 output.append(", ");//$NON-NLS-1$
227
}
228             typeArguments[max].print(0, output);
229             output.append('>');
230         }
231         if (accessMode == This) {
232             output.append("this("); //$NON-NLS-1$
233
} else {
234             output.append("super("); //$NON-NLS-1$
235
}
236         if (arguments != null) {
237             for (int i = 0; i < arguments.length; i++) {
238                 if (i > 0) output.append(", "); //$NON-NLS-1$
239
arguments[i].printExpression(0, output);
240             }
241         }
242         return output.append(");"); //$NON-NLS-1$
243
}
244     
245     public void resolve(BlockScope scope) {
246         // the return type should be void for a constructor.
247
// the test is made into getConstructor
248

249         // mark the fact that we are in a constructor call.....
250
// unmark at all returns
251
MethodScope methodScope = scope.methodScope();
252         try {
253             AbstractMethodDeclaration methodDeclaration = methodScope.referenceMethod();
254             if (methodDeclaration == null
255                     || !methodDeclaration.isConstructor()
256                     || ((ConstructorDeclaration) methodDeclaration).constructorCall != this) {
257                 scope.problemReporter().invalidExplicitConstructorCall(this);
258                 // fault-tolerance
259
if (this.qualification != null) {
260                     this.qualification.resolveType(scope);
261                 }
262                 if (this.typeArguments != null) {
263                     for (int i = 0, max = this.typeArguments.length; i < max; i++) {
264                         this.typeArguments[i].resolveType(scope, true /* check bounds*/);
265                     }
266                 }
267                 if (this.arguments != null) {
268                     for (int i = 0, max = this.arguments.length; i < max; i++) {
269                         this.arguments[i].resolveType(scope);
270                     }
271                 }
272                 return;
273             }
274             methodScope.isConstructorCall = true;
275             ReferenceBinding receiverType = scope.enclosingReceiverType();
276             if (accessMode != This)
277                 receiverType = receiverType.superclass();
278
279             if (receiverType == null) {
280                 return;
281             }
282             // prevent (explicit) super constructor invocation from within enum
283
if (this.accessMode == Super && receiverType.erasure().id == T_JavaLangEnum) {
284                 scope.problemReporter().cannotInvokeSuperConstructorInEnum(this, methodScope.referenceMethod().binding);
285             }
286             // qualification should be from the type of the enclosingType
287
if (qualification != null) {
288                 if (accessMode != Super) {
289                     scope.problemReporter().unnecessaryEnclosingInstanceSpecification(
290                         qualification,
291                         receiverType);
292                 }
293                 ReferenceBinding enclosingType = receiverType.enclosingType();
294                 if (enclosingType == null) {
295                     scope.problemReporter().unnecessaryEnclosingInstanceSpecification(
296                         qualification,
297                         receiverType);
298                     this.bits |= ASTNode.DiscardEnclosingInstance;
299                 } else {
300                     TypeBinding qTb = qualification.resolveTypeExpecting(scope, enclosingType);
301                     qualification.computeConversion(scope, qTb, qTb);
302                 }
303             }
304             // resolve type arguments (for generic constructor call)
305
if (this.typeArguments != null) {
306                 int length = this.typeArguments.length;
307                 boolean argHasError = false; // typeChecks all arguments
308
this.genericTypeArguments = new TypeBinding[length];
309                 for (int i = 0; i < length; i++) {
310                     TypeReference typeReference = this.typeArguments[i];
311                     if ((this.genericTypeArguments[i] = typeReference.resolveType(scope, true /* check bounds*/)) == null) {
312                         argHasError = true;
313                     }
314                     if (argHasError && typeReference instanceof Wildcard) {
315                         scope.problemReporter().illegalUsageOfWildcard(typeReference);
316                     }
317                 }
318                 if (argHasError) {
319                     return;
320                 }
321             }
322     
323             // arguments buffering for the method lookup
324
TypeBinding[] argumentTypes = Binding.NO_PARAMETERS;
325             boolean argsContainCast = false;
326             if (arguments != null) {
327                 boolean argHasError = false; // typeChecks all arguments
328
int length = arguments.length;
329                 argumentTypes = new TypeBinding[length];
330                 for (int i = 0; i < length; i++) {
331                     Expression argument = this.arguments[i];
332                     if (argument instanceof CastExpression) {
333                         argument.bits |= DisableUnnecessaryCastCheck; // will check later on
334
argsContainCast = true;
335                     }
336                     if ((argumentTypes[i] = argument.resolveType(scope)) == null) {
337                         argHasError = true;
338                     }
339                 }
340                 if (argHasError) {
341                     // record a best guess, for clients who need hint about possible contructor match
342
TypeBinding[] pseudoArgs = new TypeBinding[length];
343                     for (int i = length; --i >= 0;) {
344                         pseudoArgs[i] = argumentTypes[i] == null ? TypeBinding.NULL : argumentTypes[i]; // replace args with errors with null type
345
}
346                     this.binding = scope.findMethod(receiverType, TypeConstants.INIT, pseudoArgs, this);
347                     if (this.binding != null && !this.binding.isValidBinding()) {
348                         MethodBinding closestMatch = ((ProblemMethodBinding)this.binding).closestMatch;
349                         // record the closest match, for clients who may still need hint about possible method match
350
if (closestMatch != null) {
351                             if (closestMatch.original().typeVariables != Binding.NO_TYPE_VARIABLES) { // generic method
352
// shouldn't return generic method outside its context, rather convert it to raw method (175409)
353
closestMatch = scope.environment().createParameterizedGenericMethod(closestMatch.original(), (RawTypeBinding)null);
354                             }
355                             this.binding = closestMatch;
356                             MethodBinding closestMatchOriginal = closestMatch.original();
357                             if ((closestMatchOriginal.isPrivate() || closestMatchOriginal.declaringClass.isLocalType()) && !scope.isDefinedInMethod(closestMatchOriginal)) {
358                                 // ignore cases where method is used from within inside itself (e.g. direct recursions)
359
closestMatchOriginal.modifiers |= ExtraCompilerModifiers.AccLocallyUsed;
360                             }
361                         }
362                     }
363                     return;
364                 }
365             } else if (receiverType.erasure().id == T_JavaLangEnum) {
366                 // TODO (philippe) get rid of once well-known binding is available
367
argumentTypes = new TypeBinding[] { scope.getJavaLangString(), TypeBinding.INT };
368             }
369             if ((binding = scope.getConstructor(receiverType, argumentTypes, this)).isValidBinding()) {
370                 if (isMethodUseDeprecated(this.binding, scope, this.accessMode != ImplicitSuper))
371                     scope.problemReporter().deprecatedMethod(binding, this);
372                 checkInvocationArguments(scope, null, receiverType, binding, this.arguments, argumentTypes, argsContainCast, this);
373                 if (binding.isPrivate() || receiverType.isLocalType()) {
374                     binding.original().modifiers |= ExtraCompilerModifiers.AccLocallyUsed;
375                 }
376             } else {
377                 if (binding.declaringClass == null)
378                     binding.declaringClass = receiverType;
379                 scope.problemReporter().invalidConstructor(this, binding);
380             }
381         } finally {
382             methodScope.isConstructorCall = false;
383         }
384     }
385
386     public void setActualReceiverType(ReferenceBinding receiverType) {
387         // ignored
388
}
389
390     public void setDepth(int depth) {
391         // ignore for here
392
}
393
394     public void setFieldIndex(int depth) {
395         // ignore for here
396
}
397
398     public void traverse(ASTVisitor visitor, BlockScope scope) {
399
400         if (visitor.visit(this, scope)) {
401             if (this.qualification != null) {
402                 this.qualification.traverse(visitor, scope);
403             }
404             if (this.typeArguments != null) {
405                 for (int i = 0, typeArgumentsLength = this.typeArguments.length; i < typeArgumentsLength; i++) {
406                     this.typeArguments[i].traverse(visitor, scope);
407                 }
408             }
409             if (this.arguments != null) {
410                 for (int i = 0, argumentLength = this.arguments.length; i < argumentLength; i++)
411                     this.arguments[i].traverse(visitor, scope);
412             }
413         }
414         visitor.endVisit(this, scope);
415     }
416 }
417
Popular Tags