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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
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.*;
18 public class ExplicitConstructorCall
20 implements InvocationSite {
22 public Expression[] arguments;
23 public Expression qualification;
24 public MethodBinding binding;
26 public int accessMode;
28 public final static int ImplicitSuper = 1;
29 public final static int Super = 2;
30 public final static int This = 3;
32 public VariableBinding[][] implicitArguments;
33 boolean discardEnclosingInstance;
35 MethodBinding syntheticAccessor;
37 public ExplicitConstructorCall(int accessMode) {
38 this.accessMode = accessMode;
41 public FlowInfo analyseCode(
42 BlockScope currentScope,
43 FlowContext flowContext,
46 // must verify that exceptions potentially thrown by this expression are caught in the method.
49 ((MethodScope) currentScope).isConstructorCall = true;
51 // process enclosing instance
52 if (qualification != null) {
55 .analyseCode(currentScope, flowContext, flowInfo)
56 .unconditionalInits();
59 if (arguments != null) {
60 for (int i = 0, max = arguments.length; i < max; i++) {
63 .analyseCode(currentScope, flowContext, flowInfo)
64 .unconditionalInits();
68 ReferenceBinding[] thrownExceptions;
69 if ((thrownExceptions = binding.thrownExceptions) != NoExceptions) {
71 flowContext.checkExceptionHandlers(
73 (accessMode == ImplicitSuper)
74 ? (ASTNode) currentScope.methodScope().referenceContext
79 manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
80 manageSyntheticAccessIfNecessary(currentScope, flowInfo);
83 ((MethodScope) currentScope).isConstructorCall = false;
88 * Constructor call code generation
90 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
91 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
93 public void generateCode(BlockScope currentScope, CodeStream codeStream) {
95 if ((bits & IsReachableMASK) == 0) {
99 ((MethodScope) currentScope).isConstructorCall = true;
101 int pc = codeStream.position;
102 codeStream.aload_0();
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(
111 discardEnclosingInstance ? null : qualification,
115 if (arguments != null) {
116 for (int i = 0, max = arguments.length; i < max; i++) {
117 arguments[i].generateCode(currentScope, codeStream, true);
120 // handling innerclass instance allocation - outer local arguments
121 if (targetType.isNestedType()) {
122 codeStream.generateSyntheticOuterArgumentValues(
127 if (syntheticAccessor != null) {
128 // synthetic accessor got some extra arguments appended to its signature, which need values
130 max = syntheticAccessor.parameters.length - binding.parameters.length;
133 codeStream.aconst_null();
135 codeStream.invokespecial(syntheticAccessor);
137 codeStream.invokespecial(binding);
139 codeStream.recordPositionsFrom(pc, this.sourceStart);
141 ((MethodScope) currentScope).isConstructorCall = false;
145 public boolean isImplicitSuper() {
146 //return true if I'm of these compiler added statement super();
148 return (accessMode == ImplicitSuper);
151 public boolean isSuperAccess() {
153 return accessMode != This;
156 public boolean isTypeAccess() {
161 /* Inner emulation consists in either recording a dependency
162 * link only, or performing one level of propagation.
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
168 void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
169 ReferenceBinding superType;
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()) {
176 if (superType.isLocalType()) {
177 ((LocalTypeBinding) superType).addInnerEmulationDependent(currentScope, qualification != null);
179 // locally propagate, since we already now the desired shape for sure
180 currentScope.propagateInnerEmulation(superType, qualification != null);
185 public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
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)) {
194 .isPrivateConstructorAccessChangingVisibility) {
195 binding.tagForClearingPrivateModifier();
196 // constructor will not be dumped as private, no emulation required thus
199 ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding, isSuperAccess());
200 currentScope.problemReporter().needToEmulateMethodAccess(binding, this);
205 public StringBuffer printStatement(int indent, StringBuffer output) {
207 printIndent(indent, output);
208 if (qualification != null) qualification.printExpression(0, output).append('.');
209 if (accessMode == This) {
210 output.append("this("); //$NON-NLS-1$
212 output.append("super("); //$NON-NLS-1$
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);
220 return output.append(");"); //$NON-NLS-1$
223 public void resolve(BlockScope scope) {
224 // the return type should be void for a constructor.
225 // the test is made into getConstructor
227 // mark the fact that we are in a constructor call.....
228 // unmark at all returns
229 MethodScope methodScope = scope.methodScope();
231 AbstractMethodDeclaration methodDeclaration = methodScope.referenceMethod();
232 if (methodDeclaration == null
233 || !methodDeclaration.isConstructor()
234 || ((ConstructorDeclaration) methodDeclaration).constructorCall != this) {
235 scope.problemReporter().invalidExplicitConstructorCall(this);
238 methodScope.isConstructorCall = true;
239 ReferenceBinding receiverType = scope.enclosingSourceType();
240 if (accessMode != This)
241 receiverType = receiverType.superclass();
243 if (receiverType == null) {
247 // qualification should be from the type of the enclosingType
248 if (qualification != null) {
249 if (accessMode != Super) {
250 scope.problemReporter().unnecessaryEnclosingInstanceSpecification(
254 ReferenceBinding enclosingType = receiverType.enclosingType();
255 if (enclosingType == null) {
256 scope.problemReporter().unnecessaryEnclosingInstanceSpecification(
259 discardEnclosingInstance = true;
261 TypeBinding qTb = qualification.resolveTypeExpecting(scope, enclosingType);
262 qualification.implicitWidening(qTb, qTb);
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;
279 if ((argumentTypes[i] = argument.resolveType(scope)) == null) {
287 if ((binding = scope.getConstructor(receiverType, argumentTypes, this)).isValidBinding()) {
288 if (isMethodUseDeprecated(binding, scope))
289 scope.problemReporter().deprecatedMethod(binding, this);
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]);
298 if (argsContainCast) {
299 CastExpression.checkNeedForArgumentCasts(scope, null, receiverType, binding, this.arguments, argumentTypes, this);
302 if (binding.isPrivate()) {
303 binding.modifiers |= AccPrivateUsed;
306 if (binding.declaringClass == null)
307 binding.declaringClass = receiverType;
308 scope.problemReporter().invalidConstructor(this, binding);
311 methodScope.isConstructorCall = false;
315 public void setActualReceiverType(ReferenceBinding receiverType) {
319 public void setDepth(int depth) {
323 public void setFieldIndex(int depth) {
327 public void traverse(ASTVisitor visitor, BlockScope scope) {
329 if (visitor.visit(this, scope)) {
330 if (this.qualification != null) {
331 this.qualification.traverse(visitor, scope);
333 if (this.arguments != null) {
334 for (int i = 0, argumentLength = this.arguments.length; i < argumentLength; i++)
335 this.arguments[i].traverse(visitor, scope);
338 visitor.endVisit(this, scope);