1 /*******************************************************************************
 
   2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
 
   3  * All rights reserved. This program and the accompanying materials 
 
   4  * are made available under the terms of the Common Public License v0.5 
 
   5  * which accompanies this distribution, and is available at
 
   6  * http://www.eclipse.org/legal/cpl-v05.html
 
   9  *     IBM Corporation - initial API and implementation
 
  10  ******************************************************************************/
 
  11 package net.sourceforge.phpdt.internal.compiler.ast;
 
  13 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
 
  14 import net.sourceforge.phpdt.internal.compiler.codegen.*;
 
  15 import net.sourceforge.phpdt.internal.compiler.flow.*;
 
  16 import net.sourceforge.phpdt.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);
 
  80                         manageSyntheticAccessIfNecessary(currentScope);
 
  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;
 
 106                         if ((targetType = binding.declaringClass).isNestedType()) {
 
 107                                 codeStream.generateSyntheticArgumentValues(
 
 110                                         discardEnclosingInstance ? null : qualification,
 
 114                         if (arguments != null) {
 
 115                                 for (int i = 0, max = arguments.length; i < max; i++) {
 
 116                                         arguments[i].generateCode(currentScope, codeStream, true);
 
 119                         if (syntheticAccessor != null) {
 
 120                                 // synthetic accessor got some extra arguments appended to its signature, which need values
 
 122                                         max = syntheticAccessor.parameters.length - binding.parameters.length;
 
 125                                         codeStream.aconst_null();
 
 127                                 codeStream.invokespecial(syntheticAccessor);
 
 129                                 codeStream.invokespecial(binding);
 
 131                         codeStream.recordPositionsFrom(pc, this.sourceStart);
 
 133                         ((MethodScope) currentScope).isConstructorCall = false;
 
 137         public boolean isImplicitSuper() {
 
 138                 //return true if I'm of these compiler added statement super();
 
 140                 return (accessMode == ImplicitSuper);
 
 143         public boolean isSuperAccess() {
 
 145                 return accessMode != This;
 
 148         public boolean isTypeAccess() {
 
 153         /* Inner emulation consists in either recording a dependency 
 
 154          * link only, or performing one level of propagation.
 
 156          * Dependency mechanism is used whenever dealing with source target
 
 157          * types, since by the time we reach them, we might not yet know their
 
 160         void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
 
 161                 ReferenceBinding superType;
 
 163                 // perform some emulation work in case there is some and we are inside a local type only
 
 164                 if ((superType = binding.declaringClass).isNestedType()
 
 165                         && currentScope.enclosingSourceType().isLocalType()) {
 
 167                         if (superType.isLocalType()) {
 
 168                                 ((LocalTypeBinding) superType).addInnerEmulationDependent(
 
 170                                         qualification != null,
 
 172                                 // request direct access
 
 174                                 // locally propagate, since we already now the desired shape for sure
 
 175                                 currentScope.propagateInnerEmulation(superType, qualification != null, true);
 
 176                                 // request direct access
 
 182         public void manageSyntheticAccessIfNecessary(BlockScope currentScope) {
 
 184                 // perform some emulation work in case there is some and we are inside a local type only
 
 185                 if (binding.isPrivate() && (accessMode != This)) {
 
 190                                 .isPrivateConstructorAccessChangingVisibility) {
 
 191                                 binding.tagForClearingPrivateModifier();
 
 192                                 // constructor will not be dumped as private, no emulation required thus
 
 195                                         ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding);
 
 196                                 currentScope.problemReporter().needToEmulateMethodAccess(binding, this);
 
 201         public void resolve(BlockScope scope) {
 
 202                 // the return type should be void for a constructor.
 
 203                 // the test is made into getConstructor
 
 205                 // mark the fact that we are in a constructor call.....
 
 206                 // unmark at all returns
 
 208                         ((MethodScope) scope).isConstructorCall = true;
 
 209                         ReferenceBinding receiverType = scope.enclosingSourceType();
 
 210                         if (accessMode != This)
 
 211                                 receiverType = receiverType.superclass();
 
 213                         if (receiverType == null) {
 
 217                         // qualification should be from the type of the enclosingType
 
 218                         if (qualification != null) {
 
 219                                 if (accessMode != Super) {
 
 220                                         scope.problemReporter().unnecessaryEnclosingInstanceSpecification(
 
 224                                 ReferenceBinding enclosingType = receiverType.enclosingType();
 
 225                                 if (enclosingType == null) {
 
 226                                         scope.problemReporter().unnecessaryEnclosingInstanceSpecification(
 
 229                                         discardEnclosingInstance = true;
 
 231                                         TypeBinding qTb = qualification.resolveTypeExpecting(scope, enclosingType);
 
 232                                         qualification.implicitWidening(qTb, qTb);
 
 236                         // arguments buffering for the method lookup
 
 237                         TypeBinding[] argTypes = NoParameters;
 
 238                         if (arguments != null) {
 
 239                                 boolean argHasError = false; // typeChecks all arguments
 
 240                                 int length = arguments.length;
 
 241                                 argTypes = new TypeBinding[length];
 
 242                                 for (int i = 0; i < length; i++)
 
 243                                         if ((argTypes[i] = arguments[i].resolveType(scope)) == null)
 
 248                         if ((binding = scope.getConstructor(receiverType, argTypes, this))
 
 250                                 if (isMethodUseDeprecated(binding, scope))
 
 251                                         scope.problemReporter().deprecatedMethod(binding, this);
 
 253                                 // see for user-implicit widening conversion 
 
 254                                 if (arguments != null) {
 
 255                                         int length = arguments.length;
 
 256                                         TypeBinding[] paramTypes = binding.parameters;
 
 257                                         for (int i = 0; i < length; i++)
 
 258                                                 arguments[i].implicitWidening(paramTypes[i], argTypes[i]);
 
 261                                 if (binding.declaringClass == null)
 
 262                                         binding.declaringClass = receiverType;
 
 263                                 scope.problemReporter().invalidConstructor(this, binding);
 
 266                         ((MethodScope) scope).isConstructorCall = false;
 
 270         public void setActualReceiverType(ReferenceBinding receiverType) {
 
 274         public void setDepth(int depth) {
 
 278         public void setFieldIndex(int depth) {
 
 282         public String toString(int tab) {
 
 284                 String s = tabString(tab);
 
 285                 if (qualification != null)
 
 286                         s = s + qualification.toStringExpression() + "."; //$NON-NLS-1$
 
 287                 if (accessMode == This) {
 
 288                         s = s + "this("; //$NON-NLS-1$
 
 290                         s = s + "super("; //$NON-NLS-1$
 
 292                 if (arguments != null)
 
 293                         for (int i = 0; i < arguments.length; i++) {
 
 294                                 s = s + arguments[i].toStringExpression();
 
 295                                 if (i != arguments.length - 1)
 
 296                                         s = s + ", "; //$NON-NLS-1$
 
 298                 s = s + ")"; //$NON-NLS-1$
 
 302         public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
 
 304                 if (visitor.visit(this, scope)) {
 
 305                         if (qualification != null) {
 
 306                                 qualification.traverse(visitor, scope);
 
 308                         if (arguments != null) {
 
 309                                 int argumentLength = arguments.length;
 
 310                                 for (int i = 0; i < argumentLength; i++)
 
 311                                         arguments[i].traverse(visitor, scope);
 
 314                 visitor.endVisit(this, scope);