removed Makefile; lifted repo/org.ibex.tool/src/ to src/
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / ExplicitConstructorCall.java
diff --git a/src/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java b/src/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java
new file mode 100644 (file)
index 0000000..ec709ff
--- /dev/null
@@ -0,0 +1,340 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.ast;
+
+import org.eclipse.jdt.internal.compiler.ASTVisitor;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class ExplicitConstructorCall
+       extends Statement
+       implements InvocationSite {
+               
+       public Expression[] arguments;
+       public Expression qualification;
+       public MethodBinding binding;
+
+       public int accessMode;
+
+       public final static int ImplicitSuper = 1;
+       public final static int Super = 2;
+       public final static int This = 3;
+
+       public VariableBinding[][] implicitArguments;
+       boolean discardEnclosingInstance;
+
+       MethodBinding syntheticAccessor;
+
+       public ExplicitConstructorCall(int accessMode) {
+               this.accessMode = accessMode;
+       }
+
+       public FlowInfo analyseCode(
+               BlockScope currentScope,
+               FlowContext flowContext,
+               FlowInfo flowInfo) {
+
+               // must verify that exceptions potentially thrown by this expression are caught in the method.
+
+               try {
+                       ((MethodScope) currentScope).isConstructorCall = true;
+
+                       // process enclosing instance
+                       if (qualification != null) {
+                               flowInfo =
+                                       qualification
+                                               .analyseCode(currentScope, flowContext, flowInfo)
+                                               .unconditionalInits();
+                       }
+                       // process arguments
+                       if (arguments != null) {
+                               for (int i = 0, max = arguments.length; i < max; i++) {
+                                       flowInfo =
+                                               arguments[i]
+                                                       .analyseCode(currentScope, flowContext, flowInfo)
+                                                       .unconditionalInits();
+                               }
+                       }
+
+                       ReferenceBinding[] thrownExceptions;
+                       if ((thrownExceptions = binding.thrownExceptions) != NoExceptions) {
+                               // check exceptions
+                               flowContext.checkExceptionHandlers(
+                                       thrownExceptions,
+                                       (accessMode == ImplicitSuper)
+                                               ? (ASTNode) currentScope.methodScope().referenceContext
+                                               : (ASTNode) this,
+                                       flowInfo,
+                                       currentScope);
+                       }
+                       manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
+                       manageSyntheticAccessIfNecessary(currentScope, flowInfo);
+                       return flowInfo;
+               } finally {
+                       ((MethodScope) currentScope).isConstructorCall = false;
+               }
+       }
+
+       /**
+        * Constructor call code generation
+        *
+        * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+        * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+        */
+       public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+
+               if ((bits & IsReachableMASK) == 0) {
+                       return;
+               }
+               try {
+                       ((MethodScope) currentScope).isConstructorCall = true;
+
+                       int pc = codeStream.position;
+                       codeStream.aload_0();
+
+                       // handling innerclass constructor invocation
+                       ReferenceBinding targetType = binding.declaringClass;
+                       // handling innerclass instance allocation - enclosing instance arguments
+                       if (targetType.isNestedType()) {
+                               codeStream.generateSyntheticEnclosingInstanceValues(
+                                       currentScope,
+                                       targetType,
+                                       discardEnclosingInstance ? null : qualification,
+                                       this);
+                       }
+                       // regular code gen
+                       if (arguments != null) {
+                               for (int i = 0, max = arguments.length; i < max; i++) {
+                                       arguments[i].generateCode(currentScope, codeStream, true);
+                               }
+                       }
+                       // handling innerclass instance allocation - outer local arguments
+                       if (targetType.isNestedType()) {
+                               codeStream.generateSyntheticOuterArgumentValues(
+                                       currentScope,
+                                       targetType,
+                                       this);
+                       }
+                       if (syntheticAccessor != null) {
+                               // synthetic accessor got some extra arguments appended to its signature, which need values
+                               for (int i = 0,
+                                       max = syntheticAccessor.parameters.length - binding.parameters.length;
+                                       i < max;
+                                       i++) {
+                                       codeStream.aconst_null();
+                               }
+                               codeStream.invokespecial(syntheticAccessor);
+                       } else {
+                               codeStream.invokespecial(binding);
+                       }
+                       codeStream.recordPositionsFrom(pc, this.sourceStart);
+               } finally {
+                       ((MethodScope) currentScope).isConstructorCall = false;
+               }
+       }
+
+       public boolean isImplicitSuper() {
+               //return true if I'm of these compiler added statement super();
+
+               return (accessMode == ImplicitSuper);
+       }
+
+       public boolean isSuperAccess() {
+
+               return accessMode != This;
+       }
+
+       public boolean isTypeAccess() {
+
+               return true;
+       }
+
+       /* Inner emulation consists in either recording a dependency 
+        * link only, or performing one level of propagation.
+        *
+        * Dependency mechanism is used whenever dealing with source target
+        * types, since by the time we reach them, we might not yet know their
+        * exact need.
+        */
+       void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
+               ReferenceBinding superType;
+
+               if (!flowInfo.isReachable()) return;
+               // perform some emulation work in case there is some and we are inside a local type only
+               if ((superType = binding.declaringClass).isNestedType()
+                       && currentScope.enclosingSourceType().isLocalType()) {
+
+                       if (superType.isLocalType()) {
+                               ((LocalTypeBinding) superType).addInnerEmulationDependent(currentScope, qualification != null);
+                       } else {
+                               // locally propagate, since we already now the desired shape for sure
+                               currentScope.propagateInnerEmulation(superType, qualification != null);
+                       }
+               }
+       }
+
+       public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
+
+               if (!flowInfo.isReachable()) return;
+               // perform some emulation work in case there is some and we are inside a local type only
+               if (binding.isPrivate() && (accessMode != This)) {
+
+                       if (currentScope
+                               .environment()
+                               .options
+                               .isPrivateConstructorAccessChangingVisibility) {
+                               binding.tagForClearingPrivateModifier();
+                               // constructor will not be dumped as private, no emulation required thus
+                       } else {
+                               syntheticAccessor =
+                                       ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding, isSuperAccess());
+                               currentScope.problemReporter().needToEmulateMethodAccess(binding, this);
+                       }
+               }
+       }
+
+       public StringBuffer printStatement(int indent, StringBuffer output) {
+
+               printIndent(indent, output);
+               if (qualification != null) qualification.printExpression(0, output).append('.');
+               if (accessMode == This) {
+                       output.append("this("); //$NON-NLS-1$
+               } else {
+                       output.append("super("); //$NON-NLS-1$
+               }
+               if (arguments != null) {
+                       for (int i = 0; i < arguments.length; i++) {
+                               if (i > 0) output.append(", "); //$NON-NLS-1$
+                               arguments[i].printExpression(0, output);
+                       }
+               }
+               return output.append(");"); //$NON-NLS-1$
+       }
+       
+       public void resolve(BlockScope scope) {
+               // the return type should be void for a constructor.
+               // the test is made into getConstructor
+
+               // mark the fact that we are in a constructor call.....
+               // unmark at all returns
+               MethodScope methodScope = scope.methodScope();
+               try {
+                       AbstractMethodDeclaration methodDeclaration = methodScope.referenceMethod();
+                       if (methodDeclaration == null 
+                                       || !methodDeclaration.isConstructor()
+                                       || ((ConstructorDeclaration) methodDeclaration).constructorCall != this) {
+                               scope.problemReporter().invalidExplicitConstructorCall(this);
+                               return;
+                       }
+                       methodScope.isConstructorCall = true;
+                       ReferenceBinding receiverType = scope.enclosingSourceType();
+                       if (accessMode != This)
+                               receiverType = receiverType.superclass();
+
+                       if (receiverType == null) {
+                               return;
+                       }
+
+                       // qualification should be from the type of the enclosingType
+                       if (qualification != null) {
+                               if (accessMode != Super) {
+                                       scope.problemReporter().unnecessaryEnclosingInstanceSpecification(
+                                               qualification,
+                                               receiverType);
+                               }
+                               ReferenceBinding enclosingType = receiverType.enclosingType();
+                               if (enclosingType == null) {
+                                       scope.problemReporter().unnecessaryEnclosingInstanceSpecification(
+                                               qualification,
+                                               receiverType);
+                                       discardEnclosingInstance = true;
+                               } else {
+                                       TypeBinding qTb = qualification.resolveTypeExpecting(scope, enclosingType);
+                                       qualification.implicitWidening(qTb, qTb);
+                               }
+                       }
+
+                       // arguments buffering for the method lookup
+                       TypeBinding[] argumentTypes = NoParameters;
+                       boolean argsContainCast = false;
+                       if (arguments != null) {
+                               boolean argHasError = false; // typeChecks all arguments
+                               int length = arguments.length;
+                               argumentTypes = new TypeBinding[length];
+                               for (int i = 0; i < length; i++) {
+                                       Expression argument = this.arguments[i];
+                                       if (argument instanceof CastExpression) {
+                                               argument.bits |= IgnoreNeedForCastCheckMASK; // will check later on
+                                               argsContainCast = true;
+                                       }
+                                       if ((argumentTypes[i] = argument.resolveType(scope)) == null) {
+                                               argHasError = true;
+                                       }
+                               }
+                               if (argHasError) {
+                                       return;
+                               }
+                       }
+                       if ((binding = scope.getConstructor(receiverType, argumentTypes, this)).isValidBinding()) {
+                               if (isMethodUseDeprecated(binding, scope))
+                                       scope.problemReporter().deprecatedMethod(binding, this);
+
+                               // see for user-implicit widening conversion 
+                               if (arguments != null) {
+                                       int length = arguments.length;
+                                       TypeBinding[] paramTypes = binding.parameters;
+                                       for (int i = 0; i < length; i++) {
+                                               arguments[i].implicitWidening(paramTypes[i], argumentTypes[i]);
+                                       }
+                                       if (argsContainCast) {
+                                               CastExpression.checkNeedForArgumentCasts(scope, null, receiverType, binding, this.arguments, argumentTypes, this);
+                                       }
+                               }
+                               if (binding.isPrivate()) {
+                                       binding.modifiers |= AccPrivateUsed;
+                               }                               
+                       } else {
+                               if (binding.declaringClass == null)
+                                       binding.declaringClass = receiverType;
+                               scope.problemReporter().invalidConstructor(this, binding);
+                       }
+               } finally {
+                       methodScope.isConstructorCall = false;
+               }
+       }
+
+       public void setActualReceiverType(ReferenceBinding receiverType) {
+               // ignored
+       }
+
+       public void setDepth(int depth) {
+               // ignore for here
+       }
+
+       public void setFieldIndex(int depth) {
+               // ignore for here
+       }
+
+       public void traverse(ASTVisitor visitor, BlockScope scope) {
+
+               if (visitor.visit(this, scope)) {
+                       if (this.qualification != null) {
+                               this.qualification.traverse(visitor, scope);
+                       }
+                       if (this.arguments != null) {
+                               for (int i = 0, argumentLength = this.arguments.length; i < argumentLength; i++)
+                                       this.arguments[i].traverse(visitor, scope);
+                       }
+               }
+               visitor.endVisit(this, scope);
+       }
+}