import eclipse 3.1 M4 compiler
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / AllocationExpression.java
index 2a47d4d..e631f12 100644 (file)
@@ -15,15 +15,16 @@ import org.eclipse.jdt.internal.compiler.codegen.*;
 import org.eclipse.jdt.internal.compiler.flow.*;
 import org.eclipse.jdt.internal.compiler.lookup.*;
 
-public class AllocationExpression
-       extends Expression
-       implements InvocationSite {
+public class AllocationExpression extends Expression implements InvocationSite {
                
        public TypeReference type;
        public Expression[] arguments;
-       public MethodBinding binding;
-
-       MethodBinding syntheticAccessor;
+       public MethodBinding binding;                                                   // exact binding resulting from lookup
+       protected MethodBinding codegenBinding; // actual binding used for code generation (if no synthetic accessor)
+       MethodBinding syntheticAccessor;                                                // synthetic accessor for inner-emulation
+       public TypeReference[] typeArguments;   
+       public TypeBinding[] genericTypeArguments;
+       public FieldDeclaration enumConstant; // for enum constant initializations
 
        public FlowInfo analyseCode(
                BlockScope currentScope,
@@ -31,7 +32,7 @@ public class AllocationExpression
                FlowInfo flowInfo) {
 
                // check captured variables are initialized in current context (26134)
-               checkCapturedLocalInitializationIfNecessary(this.binding.declaringClass, currentScope, flowInfo);
+               checkCapturedLocalInitializationIfNecessary((ReferenceBinding)this.binding.declaringClass.erasure(), currentScope, flowInfo);
 
                // process arguments
                if (arguments != null) {
@@ -74,7 +75,6 @@ public class AllocationExpression
                                                currentScope.problemReporter().uninitializedLocalVariable(targetLocal, this);
                                        }
                                }
-                                               
                }
        }
        
@@ -88,14 +88,20 @@ public class AllocationExpression
                boolean valueRequired) {
 
                int pc = codeStream.position;
-               ReferenceBinding allocatedType = binding.declaringClass;
+               ReferenceBinding allocatedType = this.codegenBinding.declaringClass;
 
                codeStream.new_(allocatedType);
                if (valueRequired) {
                        codeStream.dup();
                }
                // better highlight for allocation: display the type individually
-               codeStream.recordPositionsFrom(pc, type.sourceStart);
+               if (this.type != null) { // null for enum constant body
+                       codeStream.recordPositionsFrom(pc, this.type.sourceStart);
+               } else {
+                       // push enum constant name and ordinal
+                       codeStream.ldc(String.valueOf(enumConstant.name));
+                       codeStream.generateInlinedValue(enumConstant.binding.id);
+               }
 
                // handling innerclass instance allocation - enclosing instance arguments
                if (allocatedType.isNestedType()) {
@@ -106,11 +112,7 @@ public class AllocationExpression
                                this);
                }
                // generate the arguments for constructor
-               if (arguments != null) {
-                       for (int i = 0, count = arguments.length; i < count; i++) {
-                               arguments[i].generateCode(currentScope, codeStream, true);
-                       }
-               }
+               generateArguments(binding, arguments, currentScope, codeStream);
                // handling innerclass instance allocation - outer local arguments
                if (allocatedType.isNestedType()) {
                        codeStream.generateSyntheticOuterArgumentValues(
@@ -120,20 +122,27 @@ public class AllocationExpression
                }
                // invoke constructor
                if (syntheticAccessor == null) {
-                       codeStream.invokespecial(binding);
+                       codeStream.invokespecial(this.codegenBinding);
                } else {
                        // synthetic accessor got some extra arguments appended to its signature, which need values
                        for (int i = 0,
-                               max = syntheticAccessor.parameters.length - binding.parameters.length;
+                               max = syntheticAccessor.parameters.length - this.codegenBinding.parameters.length;
                                i < max;
                                i++) {
                                codeStream.aconst_null();
                        }
                        codeStream.invokespecial(syntheticAccessor);
                }
+               codeStream.generateImplicitConversion(this.implicitConversion);
                codeStream.recordPositionsFrom(pc, this.sourceStart);
        }
-
+       /**
+        * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments()
+        */
+       public TypeBinding[] genericTypeArguments() {
+               return this.genericTypeArguments;
+       }
+       
        public boolean isSuperAccess() {
 
                return false;
@@ -154,18 +163,18 @@ public class AllocationExpression
        public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
 
                if (!flowInfo.isReachable()) return;
-               ReferenceBinding allocatedType;
+               ReferenceBinding allocatedTypeErasure = (ReferenceBinding) binding.declaringClass.erasure();
 
                // perform some emulation work in case there is some and we are inside a local type only
-               if ((allocatedType = binding.declaringClass).isNestedType()
+               if (allocatedTypeErasure.isNestedType()
                        && currentScope.enclosingSourceType().isLocalType()) {
 
-                       if (allocatedType.isLocalType()) {
-                               ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(currentScope, false);
+                       if (allocatedTypeErasure.isLocalType()) {
+                               ((LocalTypeBinding) allocatedTypeErasure).addInnerEmulationDependent(currentScope, false);
                                // request cascade of accesses
                        } else {
                                // locally propagate, since we already now the desired shape for sure
-                               currentScope.propagateInnerEmulation(allocatedType, false);
+                               currentScope.propagateInnerEmulation(allocatedTypeErasure, false);
                                // request cascade of accesses
                        }
                }
@@ -174,27 +183,42 @@ public class AllocationExpression
        public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
 
                if (!flowInfo.isReachable()) return;
-               if (binding.isPrivate()
-                       && (currentScope.enclosingSourceType() != binding.declaringClass)) {
-
-                       if (currentScope
-                               .environment()
-                               .options
-                               .isPrivateConstructorAccessChangingVisibility) {
-                               binding.tagForClearingPrivateModifier();
+
+               // if constructor from parameterized type got found, use the original constructor at codegen time
+               this.codegenBinding = this.binding.original();
+
+               if (this.codegenBinding.isPrivate()
+                       && (currentScope.enclosingSourceType() != this.codegenBinding.declaringClass)) {
+
+                       if (currentScope.environment().options.isPrivateConstructorAccessChangingVisibility) {
+                               this.codegenBinding.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);
+                                       ((SourceTypeBinding) this.codegenBinding.declaringClass).addSyntheticMethod(this.codegenBinding, isSuperAccess());
+                               currentScope.problemReporter().needToEmulateMethodAccess(this.codegenBinding, this);
                        }
                }
        }
 
        public StringBuffer printExpression(int indent, StringBuffer output) {
 
-               output.append("new "); //$NON-NLS-1$
-               type.printExpression(0, output); 
+               if (this.type != null) { // type null for enum constant initializations
+                       output.append("new "); //$NON-NLS-1$
+               }
+               if (typeArguments != null) {
+                       output.append('<');//$NON-NLS-1$
+                       int max = typeArguments.length - 1;
+                       for (int j = 0; j < max; j++) {
+                               typeArguments[j].print(0, output);
+                               output.append(", ");//$NON-NLS-1$
+                       }
+                       typeArguments[max].print(0, output);
+                       output.append('>');
+               }
+               if (type != null) { // type null for enum constant initializations
+                       type.printExpression(0, output); 
+               }
                output.append('(');
                if (arguments != null) {
                        for (int i = 0; i < arguments.length; i++) {
@@ -209,9 +233,29 @@ public class AllocationExpression
 
                // Propagate the type checking to the arguments, and check if the constructor is defined.
                constant = NotAConstant;
-               this.resolvedType = type.resolveType(scope);
+               if (this.type == null) {
+                       // initialization of an enum constant
+                       this.resolvedType = scope.enclosingSourceType();
+               } else {
+                       this.resolvedType = this.type.resolveType(scope, true /* check bounds*/);
+               }
                // will check for null after args are resolved
 
+               // resolve type arguments (for generic constructor call)
+               if (this.typeArguments != null) {
+                       int length = this.typeArguments.length;
+                       boolean argHasError = false; // typeChecks all arguments
+                       this.genericTypeArguments = new TypeBinding[length];
+                       for (int i = 0; i < length; i++) {
+                               if ((this.genericTypeArguments[i] = this.typeArguments[i].resolveType(scope, true /* check bounds*/)) == null) {
+                                       argHasError = true;
+                               }
+                       }
+                       if (argHasError) {
+                               return null;
+                       }
+               }
+               
                // buffering the arguments' types
                boolean argsContainCast = false;
                TypeBinding[] argumentTypes = NoParameters;
@@ -236,13 +280,13 @@ public class AllocationExpression
                if (this.resolvedType == null)
                        return null;
 
-               if (!this.resolvedType.canBeInstantiated()) {
+               // null type denotes fake allocation for enum constant inits
+               if (this.type != null && !this.resolvedType.canBeInstantiated()) {
                        scope.problemReporter().cannotInstantiate(type, this.resolvedType);
                        return this.resolvedType;
                }
                ReferenceBinding allocationType = (ReferenceBinding) this.resolvedType;
-               if (!(binding = scope.getConstructor(allocationType, argumentTypes, this))
-                       .isValidBinding()) {
+               if (!(binding = scope.getConstructor(allocationType, argumentTypes, this)).isValidBinding()) {
                        if (binding.declaringClass == null)
                                binding.declaringClass = allocationType;
                        scope.problemReporter().invalidConstructor(this, binding);
@@ -250,15 +294,9 @@ public class AllocationExpression
                }
                if (isMethodUseDeprecated(binding, scope))
                        scope.problemReporter().deprecatedMethod(binding, this);
+               if (this.arguments != null)
+                       checkInvocationArguments(scope, null, allocationType, this.binding, this.arguments, argumentTypes, argsContainCast, this);
 
-               if (arguments != null) {
-                       for (int i = 0; i < arguments.length; i++) {
-                               arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]);
-                       }
-                       if (argsContainCast) {
-                               CastExpression.checkNeedForArgumentCasts(scope, null, allocationType, binding, this.arguments, argumentTypes, this);
-                       }
-               }
                return allocationType;
        }
 
@@ -277,12 +315,17 @@ public class AllocationExpression
        public void traverse(ASTVisitor visitor, BlockScope scope) {
 
                if (visitor.visit(this, scope)) {
-                       int argumentsLength;
-                       type.traverse(visitor, scope);
-                       if (arguments != null) {
-                               argumentsLength = arguments.length;
-                               for (int i = 0; i < argumentsLength; i++)
-                                       arguments[i].traverse(visitor, scope);
+                       if (this.typeArguments != null) {
+                               for (int i = 0, typeArgumentsLength = this.typeArguments.length; i < typeArgumentsLength; i++) {
+                                       this.typeArguments[i].traverse(visitor, scope);
+                               }
+                       }
+                       if (this.type != null) { // enum constant scenario
+                               this.type.traverse(visitor, scope);
+                       }
+                       if (this.arguments != null) {
+                               for (int i = 0, argumentsLength = this.arguments.length; i < argumentsLength; i++)
+                                       this.arguments[i].traverse(visitor, scope);
                        }
                }
                visitor.endVisit(this, scope);