001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.ast;
011:
012: import org.eclipse.jdt.internal.compiler.ASTVisitor;
013: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
014: import org.eclipse.jdt.internal.compiler.codegen.*;
015: import org.eclipse.jdt.internal.compiler.flow.*;
016: import org.eclipse.jdt.internal.compiler.lookup.*;
017:
018: public class ExplicitConstructorCall extends Statement implements
019: InvocationSite {
020:
021: public Expression[] arguments;
022: public Expression qualification;
023: public MethodBinding binding; // exact binding resulting from lookup
024: protected MethodBinding codegenBinding; // actual binding used for code generation (if no synthetic accessor)
025: MethodBinding syntheticAccessor; // synthetic accessor for inner-emulation
026: public int accessMode;
027: public TypeReference[] typeArguments;
028: public TypeBinding[] genericTypeArguments;
029:
030: public final static int ImplicitSuper = 1;
031: public final static int Super = 2;
032: public final static int This = 3;
033:
034: public VariableBinding[][] implicitArguments;
035:
036: // TODO Remove once DOMParser is activated
037: public int typeArgumentsSourceStart;
038:
039: public ExplicitConstructorCall(int accessMode) {
040: this .accessMode = accessMode;
041: }
042:
043: public FlowInfo analyseCode(BlockScope currentScope,
044: FlowContext flowContext, FlowInfo flowInfo) {
045:
046: // must verify that exceptions potentially thrown by this expression are caught in the method.
047:
048: try {
049: ((MethodScope) currentScope).isConstructorCall = true;
050:
051: // process enclosing instance
052: if (qualification != null) {
053: flowInfo = qualification.analyseCode(currentScope,
054: flowContext, flowInfo).unconditionalInits();
055: }
056: // process arguments
057: if (arguments != null) {
058: for (int i = 0, max = arguments.length; i < max; i++) {
059: flowInfo = arguments[i].analyseCode(currentScope,
060: flowContext, flowInfo).unconditionalInits();
061: }
062: }
063:
064: ReferenceBinding[] thrownExceptions;
065: if ((thrownExceptions = binding.thrownExceptions) != Binding.NO_EXCEPTIONS) {
066: // check exceptions
067: flowContext
068: .checkExceptionHandlers(
069: thrownExceptions,
070: (accessMode == ImplicitSuper) ? (ASTNode) currentScope
071: .methodScope().referenceContext
072: : (ASTNode) this , flowInfo,
073: currentScope);
074: }
075: manageEnclosingInstanceAccessIfNecessary(currentScope,
076: flowInfo);
077: manageSyntheticAccessIfNecessary(currentScope, flowInfo);
078: return flowInfo;
079: } finally {
080: ((MethodScope) currentScope).isConstructorCall = false;
081: }
082: }
083:
084: /**
085: * Constructor call code generation
086: *
087: * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
088: * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
089: */
090: public void generateCode(BlockScope currentScope,
091: CodeStream codeStream) {
092:
093: if ((bits & IsReachable) == 0) {
094: return;
095: }
096: try {
097: ((MethodScope) currentScope).isConstructorCall = true;
098:
099: int pc = codeStream.position;
100: codeStream.aload_0();
101:
102: ReferenceBinding targetType = this .codegenBinding.declaringClass;
103:
104: // special name&ordinal argument generation for enum constructors
105: if (targetType.erasure().id == T_JavaLangEnum
106: || targetType.isEnum()) {
107: codeStream.aload_1(); // pass along name param as name arg
108: codeStream.iload_2(); // pass along ordinal param as ordinal arg
109: }
110: // handling innerclass constructor invocation
111: // handling innerclass instance allocation - enclosing instance arguments
112: if (targetType.isNestedType()) {
113: codeStream
114: .generateSyntheticEnclosingInstanceValues(
115: currentScope,
116: targetType,
117: (this .bits & ASTNode.DiscardEnclosingInstance) != 0 ? null
118: : qualification, this );
119: }
120: // generate arguments
121: generateArguments(binding, arguments, currentScope,
122: codeStream);
123:
124: // handling innerclass instance allocation - outer local arguments
125: if (targetType.isNestedType()) {
126: codeStream.generateSyntheticOuterArgumentValues(
127: currentScope, targetType, this );
128: }
129: if (syntheticAccessor != null) {
130: // synthetic accessor got some extra arguments appended to its signature, which need values
131: for (int i = 0, max = syntheticAccessor.parameters.length
132: - this .codegenBinding.parameters.length; i < max; i++) {
133: codeStream.aconst_null();
134: }
135: codeStream.invokespecial(syntheticAccessor);
136: } else {
137: codeStream.invokespecial(this .codegenBinding);
138: }
139: codeStream.recordPositionsFrom(pc, this .sourceStart);
140: } finally {
141: ((MethodScope) currentScope).isConstructorCall = false;
142: }
143: }
144:
145: /**
146: * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments()
147: */
148: public TypeBinding[] genericTypeArguments() {
149: return this .genericTypeArguments;
150: }
151:
152: public boolean isImplicitSuper() {
153: //return true if I'm of these compiler added statement super();
154:
155: return (accessMode == ImplicitSuper);
156: }
157:
158: public boolean isSuperAccess() {
159:
160: return accessMode != This;
161: }
162:
163: public boolean isTypeAccess() {
164:
165: return true;
166: }
167:
168: /* Inner emulation consists in either recording a dependency
169: * link only, or performing one level of propagation.
170: *
171: * Dependency mechanism is used whenever dealing with source target
172: * types, since by the time we reach them, we might not yet know their
173: * exact need.
174: */
175: void manageEnclosingInstanceAccessIfNecessary(
176: BlockScope currentScope, FlowInfo flowInfo) {
177: ReferenceBinding super TypeErasure = (ReferenceBinding) binding.declaringClass
178: .erasure();
179:
180: if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
181: // perform some emulation work in case there is some and we are inside a local type only
182: if (super TypeErasure.isNestedType()
183: && currentScope.enclosingSourceType().isLocalType()) {
184:
185: if (super TypeErasure.isLocalType()) {
186: ((LocalTypeBinding) super TypeErasure)
187: .addInnerEmulationDependent(currentScope,
188: qualification != null);
189: } else {
190: // locally propagate, since we already now the desired shape for sure
191: currentScope.propagateInnerEmulation(
192: super TypeErasure, qualification != null);
193: }
194: }
195: }
196: }
197:
198: public void manageSyntheticAccessIfNecessary(
199: BlockScope currentScope, FlowInfo flowInfo) {
200:
201: if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
202: // if constructor from parameterized type got found, use the original constructor at codegen time
203: this .codegenBinding = this .binding.original();
204:
205: // perform some emulation work in case there is some and we are inside a local type only
206: if (binding.isPrivate() && accessMode != This) {
207: ReferenceBinding declaringClass = this .codegenBinding.declaringClass;
208: // from 1.4 on, local type constructor can lose their private flag to ease emulation
209: if ((declaringClass.tagBits & TagBits.IsLocalType) != 0
210: && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) {
211: // constructor will not be dumped as private, no emulation required thus
212: this .codegenBinding.tagBits |= TagBits.ClearPrivateModifier;
213: } else {
214: syntheticAccessor = ((SourceTypeBinding) declaringClass)
215: .addSyntheticMethod(this .codegenBinding,
216: isSuperAccess());
217: currentScope.problemReporter()
218: .needToEmulateMethodAccess(
219: this .codegenBinding, this );
220: }
221: }
222: }
223: }
224:
225: public StringBuffer printStatement(int indent, StringBuffer output) {
226:
227: printIndent(indent, output);
228: if (qualification != null)
229: qualification.printExpression(0, output).append('.');
230: if (typeArguments != null) {
231: output.append('<');
232: int max = typeArguments.length - 1;
233: for (int j = 0; j < max; j++) {
234: typeArguments[j].print(0, output);
235: output.append(", ");//$NON-NLS-1$
236: }
237: typeArguments[max].print(0, output);
238: output.append('>');
239: }
240: if (accessMode == This) {
241: output.append("this("); //$NON-NLS-1$
242: } else {
243: output.append("super("); //$NON-NLS-1$
244: }
245: if (arguments != null) {
246: for (int i = 0; i < arguments.length; i++) {
247: if (i > 0)
248: output.append(", "); //$NON-NLS-1$
249: arguments[i].printExpression(0, output);
250: }
251: }
252: return output.append(");"); //$NON-NLS-1$
253: }
254:
255: public void resolve(BlockScope scope) {
256: // the return type should be void for a constructor.
257: // the test is made into getConstructor
258:
259: // mark the fact that we are in a constructor call.....
260: // unmark at all returns
261: MethodScope methodScope = scope.methodScope();
262: try {
263: AbstractMethodDeclaration methodDeclaration = methodScope
264: .referenceMethod();
265: if (methodDeclaration == null
266: || !methodDeclaration.isConstructor()
267: || ((ConstructorDeclaration) methodDeclaration).constructorCall != this ) {
268: scope.problemReporter().invalidExplicitConstructorCall(
269: this );
270: // fault-tolerance
271: if (this .qualification != null) {
272: this .qualification.resolveType(scope);
273: }
274: if (this .typeArguments != null) {
275: for (int i = 0, max = this .typeArguments.length; i < max; i++) {
276: this .typeArguments[i]
277: .resolveType(scope, true /* check bounds*/);
278: }
279: }
280: if (this .arguments != null) {
281: for (int i = 0, max = this .arguments.length; i < max; i++) {
282: this .arguments[i].resolveType(scope);
283: }
284: }
285: return;
286: }
287: methodScope.isConstructorCall = true;
288: ReferenceBinding receiverType = scope
289: .enclosingReceiverType();
290: if (accessMode != This)
291: receiverType = receiverType.super class();
292:
293: if (receiverType == null) {
294: return;
295: }
296: // prevent (explicit) super constructor invocation from within enum
297: if (this .accessMode == Super
298: && receiverType.erasure().id == T_JavaLangEnum) {
299: scope.problemReporter()
300: .cannotInvokeSuperConstructorInEnum(this ,
301: methodScope.referenceMethod().binding);
302: }
303: // qualification should be from the type of the enclosingType
304: if (qualification != null) {
305: if (accessMode != Super) {
306: scope.problemReporter()
307: .unnecessaryEnclosingInstanceSpecification(
308: qualification, receiverType);
309: }
310: ReferenceBinding enclosingType = receiverType
311: .enclosingType();
312: if (enclosingType == null) {
313: scope.problemReporter()
314: .unnecessaryEnclosingInstanceSpecification(
315: qualification, receiverType);
316: this .bits |= ASTNode.DiscardEnclosingInstance;
317: } else {
318: TypeBinding qTb = qualification
319: .resolveTypeExpecting(scope, enclosingType);
320: qualification.computeConversion(scope, qTb, qTb);
321: }
322: }
323: // resolve type arguments (for generic constructor call)
324: if (this .typeArguments != null) {
325: int length = this .typeArguments.length;
326: boolean argHasError = false; // typeChecks all arguments
327: this .genericTypeArguments = new TypeBinding[length];
328: for (int i = 0; i < length; i++) {
329: TypeReference typeReference = this .typeArguments[i];
330: if ((this .genericTypeArguments[i] = typeReference
331: .resolveType(scope, true /* check bounds*/)) == null) {
332: argHasError = true;
333: }
334: if (argHasError
335: && typeReference instanceof Wildcard) {
336: scope.problemReporter().illegalUsageOfWildcard(
337: typeReference);
338: }
339: }
340: if (argHasError) {
341: return;
342: }
343: }
344:
345: // arguments buffering for the method lookup
346: TypeBinding[] argumentTypes = Binding.NO_PARAMETERS;
347: boolean argsContainCast = false;
348: if (arguments != null) {
349: boolean argHasError = false; // typeChecks all arguments
350: int length = arguments.length;
351: argumentTypes = new TypeBinding[length];
352: for (int i = 0; i < length; i++) {
353: Expression argument = this .arguments[i];
354: if (argument instanceof CastExpression) {
355: argument.bits |= DisableUnnecessaryCastCheck; // will check later on
356: argsContainCast = true;
357: }
358: if ((argumentTypes[i] = argument.resolveType(scope)) == null) {
359: argHasError = true;
360: }
361: }
362: if (argHasError) {
363: // record a best guess, for clients who need hint about possible contructor match
364: TypeBinding[] pseudoArgs = new TypeBinding[length];
365: for (int i = length; --i >= 0;) {
366: pseudoArgs[i] = argumentTypes[i] == null ? TypeBinding.NULL
367: : argumentTypes[i]; // replace args with errors with null type
368: }
369: this .binding = scope.findMethod(receiverType,
370: TypeConstants.INIT, pseudoArgs, this );
371: if (this .binding != null
372: && !this .binding.isValidBinding()) {
373: MethodBinding closestMatch = ((ProblemMethodBinding) this .binding).closestMatch;
374: // record the closest match, for clients who may still need hint about possible method match
375: if (closestMatch != null) {
376: if (closestMatch.original().typeVariables != Binding.NO_TYPE_VARIABLES) { // generic method
377: // shouldn't return generic method outside its context, rather convert it to raw method (175409)
378: closestMatch = scope
379: .environment()
380: .createParameterizedGenericMethod(
381: closestMatch.original(),
382: (RawTypeBinding) null);
383: }
384: this .binding = closestMatch;
385: MethodBinding closestMatchOriginal = closestMatch
386: .original();
387: if ((closestMatchOriginal.isPrivate() || closestMatchOriginal.declaringClass
388: .isLocalType())
389: && !scope
390: .isDefinedInMethod(closestMatchOriginal)) {
391: // ignore cases where method is used from within inside itself (e.g. direct recursions)
392: closestMatchOriginal.modifiers |= ExtraCompilerModifiers.AccLocallyUsed;
393: }
394: }
395: }
396: return;
397: }
398: } else if (receiverType.erasure().id == T_JavaLangEnum) {
399: // TODO (philippe) get rid of once well-known binding is available
400: argumentTypes = new TypeBinding[] {
401: scope.getJavaLangString(), TypeBinding.INT };
402: }
403: if ((binding = scope.getConstructor(receiverType,
404: argumentTypes, this )).isValidBinding()) {
405: if (isMethodUseDeprecated(this .binding, scope,
406: this .accessMode != ImplicitSuper))
407: scope.problemReporter().deprecatedMethod(binding,
408: this );
409: checkInvocationArguments(scope, null, receiverType,
410: binding, this .arguments, argumentTypes,
411: argsContainCast, this );
412: if (binding.isPrivate() || receiverType.isLocalType()) {
413: binding.original().modifiers |= ExtraCompilerModifiers.AccLocallyUsed;
414: }
415: } else {
416: if (binding.declaringClass == null)
417: binding.declaringClass = receiverType;
418: scope.problemReporter().invalidConstructor(this ,
419: binding);
420: }
421: } finally {
422: methodScope.isConstructorCall = false;
423: }
424: }
425:
426: public void setActualReceiverType(ReferenceBinding receiverType) {
427: // ignored
428: }
429:
430: public void setDepth(int depth) {
431: // ignore for here
432: }
433:
434: public void setFieldIndex(int depth) {
435: // ignore for here
436: }
437:
438: public void traverse(ASTVisitor visitor, BlockScope scope) {
439:
440: if (visitor.visit(this , scope)) {
441: if (this .qualification != null) {
442: this .qualification.traverse(visitor, scope);
443: }
444: if (this .typeArguments != null) {
445: for (int i = 0, typeArgumentsLength = this .typeArguments.length; i < typeArgumentsLength; i++) {
446: this .typeArguments[i].traverse(visitor, scope);
447: }
448: }
449: if (this .arguments != null) {
450: for (int i = 0, argumentLength = this.arguments.length; i < argumentLength; i++)
451: this.arguments[i].traverse(visitor, scope);
452: }
453: }
454: visitor.endVisit(this, scope);
455: }
456: }
|