Committing missing change or PHPFileUtil
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / QualifiedAllocationExpression.java
index 05e4c75..8cc98e7 100644 (file)
@@ -1,17 +1,16 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v0.5 
+ * 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-v05.html
+ * http://www.eclipse.org/legal/cpl-v10.html
  * 
  * Contributors:
  *     IBM Corporation - initial API and implementation
- ******************************************************************************/
+ *******************************************************************************/
 package net.sourceforge.phpdt.internal.compiler.ast;
 
-import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
-import net.sourceforge.phpdt.internal.compiler.codegen.CodeStream;
+import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
@@ -20,12 +19,16 @@ import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
 
+/**
+ * Variation on allocation, where can be specified an enclosing instance and an anonymous type
+ */
 public class QualifiedAllocationExpression extends AllocationExpression {
        
        //qualification may be on both side
        public Expression enclosingInstance;
        public AnonymousLocalTypeDeclaration anonymousType;
-
+       public ReferenceBinding superTypeBinding;
+       
        public QualifiedAllocationExpression() {
        }
 
@@ -38,12 +41,17 @@ public class QualifiedAllocationExpression extends AllocationExpression {
                FlowContext flowContext,
                FlowInfo flowInfo) {
 
-               // variation on allocation, where can be specified an enclosing instance and an anonymous type
-
                // analyse the enclosing instance
                if (enclosingInstance != null) {
                        flowInfo = enclosingInstance.analyseCode(currentScope, flowContext, flowInfo);
                }
+               
+               // check captured variables are initialized in current context (26134)
+               checkCapturedLocalInitializationIfNecessary(
+                       this.superTypeBinding == null ? this.binding.declaringClass : this.superTypeBinding, 
+                       currentScope, 
+                       flowInfo);
+               
                // process arguments
                if (arguments != null) {
                        for (int i = 0, count = arguments.length; i < count; i++) {
@@ -76,59 +84,61 @@ public class QualifiedAllocationExpression extends AllocationExpression {
                return enclosingInstance;
        }
 
-       public void generateCode(
-               BlockScope currentScope,
-               CodeStream codeStream,
-               boolean valueRequired) {
-
-               int pc = codeStream.position;
-               ReferenceBinding allocatedType = binding.declaringClass;
-               if (allocatedType.isLocalType()) {
-                       LocalTypeBinding localType = (LocalTypeBinding) allocatedType;
-                       localType.constantPoolName(
-                               codeStream.classFile.outerMostEnclosingClassFile().computeConstantPoolName(
-                                       localType));
-               }
-               codeStream.new_(allocatedType);
-               if (valueRequired) {
-                       codeStream.dup();
-               }
-               // better highlight for allocation: display the type individually
-               codeStream.recordPositionsFrom(pc, type.sourceStart);
-
-               // handling innerclass instance allocation
-               if (allocatedType.isNestedType()) {
-                       // make sure its name is computed before arguments, since may be necessary for argument emulation
-                       codeStream.generateSyntheticArgumentValues(
-                               currentScope,
-                               allocatedType,
-                               enclosingInstance(),
-                               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);
-                       }
-               }
-               // invoke constructor
-               if (syntheticAccessor == null) {
-                       codeStream.invokespecial(binding);
-               } 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;
-                               i < max;
-                               i++) {
-                               codeStream.aconst_null();
-                       }
-                       codeStream.invokespecial(syntheticAccessor);
-               }
-               codeStream.recordPositionsFrom(pc, this.sourceStart);
-               if (anonymousType != null) {
-                       anonymousType.generateCode(currentScope, codeStream);
-               }
-       }
+//     public void generateCode(
+//             BlockScope currentScope,
+//             CodeStream codeStream,
+//             boolean valueRequired) {
+//
+//             int pc = codeStream.position;
+//             ReferenceBinding allocatedType = binding.declaringClass;
+//             codeStream.new_(allocatedType);
+//             if (valueRequired) {
+//                     codeStream.dup();
+//             }
+//             // better highlight for allocation: display the type individually
+//             codeStream.recordPositionsFrom(pc, type.sourceStart);
+//
+//             // handling innerclass instance allocation - enclosing instance arguments
+//             if (allocatedType.isNestedType()) {
+//                     codeStream.generateSyntheticEnclosingInstanceValues(
+//                             currentScope,
+//                             allocatedType,
+//                             enclosingInstance(),
+//                             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);
+//                     }
+//             }
+//             // handling innerclass instance allocation - outer local arguments
+//             if (allocatedType.isNestedType()) {
+//                     codeStream.generateSyntheticOuterArgumentValues(
+//                             currentScope,
+//                             allocatedType,
+//                             this);
+//             }
+//             
+//             // invoke constructor
+//             if (syntheticAccessor == null) {
+//                     codeStream.invokespecial(binding);
+//             } 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;
+//                             i < max;
+//                             i++) {
+//                             codeStream.aconst_null();
+//                     }
+//                     codeStream.invokespecial(syntheticAccessor);
+//             }
+//             codeStream.recordPositionsFrom(pc, this.sourceStart);
+//
+//             if (anonymousType != null) {
+//                     anonymousType.generateCode(currentScope, codeStream);
+//             }
+//     }
        
        public boolean isSuperAccess() {
 
@@ -152,30 +162,22 @@ public class QualifiedAllocationExpression extends AllocationExpression {
                        && currentScope.enclosingSourceType().isLocalType()) {
 
                        if (allocatedType.isLocalType()) {
-                               ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(
-                                       currentScope,
-                                       enclosingInstance != null,
-                                       false);
-                               // request cascade of accesses
+                               ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(currentScope, enclosingInstance != null);
                        } else {
                                // locally propagate, since we already now the desired shape for sure
-                               currentScope.propagateInnerEmulation(
-                                       allocatedType,
-                                       enclosingInstance != null,
-                                       false);
-                               // request cascade of accesses
+                               currentScope.propagateInnerEmulation(allocatedType, enclosingInstance != null);
                        }
                }
        }
 
        public TypeBinding resolveType(BlockScope scope) {
 
-               if (anonymousType == null && enclosingInstance == null)
+               // added for code assist...cannot occur with 'normal' code
+               if (anonymousType == null && enclosingInstance == null) {
                        return super.resolveType(scope);
-               // added for code assist... is not possible with 'normal' code
+               }
 
                // Propagate the type checking to the arguments, and checks if the constructor is defined.
-
                // ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
                // ClassInstanceCreationExpression ::= Name '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
                // ==> by construction, when there is an enclosing instance the typename may NOT be qualified
@@ -183,119 +185,118 @@ public class QualifiedAllocationExpression extends AllocationExpression {
                // sometime a SingleTypeReference and sometime a QualifedTypeReference
 
                constant = NotAConstant;
-               TypeBinding enclosingInstTb = null;
-               TypeBinding recType;
-               if (anonymousType == null) {
-                       //----------------no anonymous class------------------------    
-                       if ((enclosingInstTb = enclosingInstance.resolveType(scope)) == null)
-                               return null;
-                       if (enclosingInstTb.isBaseType() | enclosingInstTb.isArrayType()) {
+               TypeBinding enclosingInstanceType = null;
+               TypeBinding receiverType = null;
+               boolean hasError = false;
+               if (anonymousType == null) { //----------------no anonymous class------------------------       
+                       if ((enclosingInstanceType = enclosingInstance.resolveType(scope)) == null){
+                               hasError = true;
+                       } else if (enclosingInstanceType.isBaseType() || enclosingInstanceType.isArrayType()) {
                                scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
-                                       enclosingInstTb,
+                                       enclosingInstanceType,
                                        enclosingInstance);
-                               return null;
+                               hasError = true;
+                       } else if ((this.resolvedType = receiverType = ((SingleTypeReference) type).resolveTypeEnclosing(
+                                                       scope,
+                                                       (ReferenceBinding) enclosingInstanceType)) == null) {
+                               hasError = true;
                        }
-                       recType =
-                               ((SingleTypeReference) type).resolveTypeEnclosing(
-                                       scope,
-                                       (ReferenceBinding) enclosingInstTb);
                        // will check for null after args are resolved
                        TypeBinding[] argumentTypes = NoParameters;
                        if (arguments != null) {
-                               boolean argHasError = false;
                                int length = arguments.length;
                                argumentTypes = new TypeBinding[length];
                                for (int i = 0; i < length; i++)
-                                       if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null)
-                                               argHasError = true;
-                               if (argHasError)
-                                       return recType;
+                                       if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null){
+                                               hasError = true;
+                                       }
                        }
-                       if (recType == null)
-                               return null;
-                       if (!recType.canBeInstantiated()) {
-                               scope.problemReporter().cannotInstantiate(type, recType);
-                               return recType;
+                       // limit of fault-tolerance
+                       if (hasError) return receiverType;
+
+                       if (!receiverType.canBeInstantiated()) {
+                               scope.problemReporter().cannotInstantiate(type, receiverType);
+                               return receiverType;
                        }
-                       if ((binding =
-                               scope.getConstructor((ReferenceBinding) recType, argumentTypes, this))
-                               .isValidBinding()) {
+                       if ((this.binding = scope.getConstructor((ReferenceBinding) receiverType, argumentTypes, this))
+                                       .isValidBinding()) {
                                if (isMethodUseDeprecated(binding, scope))
-                                       scope.problemReporter().deprecatedMethod(binding, this);
+                                       scope.problemReporter().deprecatedMethod(this.binding, this);
 
                                if (arguments != null)
                                        for (int i = 0; i < arguments.length; i++)
-                                               arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]);
+                                               arguments[i].implicitWidening(this.binding.parameters[i], argumentTypes[i]);
                        } else {
-                               if (binding.declaringClass == null)
-                                       binding.declaringClass = (ReferenceBinding) recType;
-                               scope.problemReporter().invalidConstructor(this, binding);
-                               return recType;
+                               if (this.binding.declaringClass == null)
+                                       this.binding.declaringClass = (ReferenceBinding) receiverType;
+                               scope.problemReporter().invalidConstructor(this, this.binding);
+                               return receiverType;
                        }
 
                        // The enclosing instance must be compatible with the innermost enclosing type
-                       ReferenceBinding expectedType = binding.declaringClass.enclosingType();
-                       if (BlockScope.areTypesCompatible(enclosingInstTb, expectedType))
-                               return recType;
+                       ReferenceBinding expectedType = this.binding.declaringClass.enclosingType();
+                       if (enclosingInstanceType.isCompatibleWith(expectedType))
+                               return receiverType;
                        scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
-                               enclosingInstance,
-                               enclosingInstTb,
+                               this.enclosingInstance,
+                               enclosingInstanceType,
                                expectedType);
-                       return recType;
+                       return receiverType;
                }
 
                //--------------there is an anonymous type declaration-----------------
-               if (enclosingInstance != null) {
-                       if ((enclosingInstTb = enclosingInstance.resolveType(scope)) == null)
-                               return null;
-                       if (enclosingInstTb.isBaseType() | enclosingInstTb.isArrayType()) {
+               if (this.enclosingInstance != null) {
+                       if ((enclosingInstanceType = this.enclosingInstance.resolveType(scope)) == null) {
+                               hasError = true;
+                       } else if (enclosingInstanceType.isBaseType() || enclosingInstanceType.isArrayType()) {
                                scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
-                                       enclosingInstTb,
-                                       enclosingInstance);
-                               return null;
+                                       enclosingInstanceType,
+                                       this.enclosingInstance);
+                               hasError = true;
+                       } else {
+                               receiverType = ((SingleTypeReference) type).resolveTypeEnclosing(
+                                                                               scope,
+                                                                               (ReferenceBinding) enclosingInstanceType);                              
                        }
+               } else {
+                       receiverType = type.resolveType(scope);
                }
-               // due to syntax-construction, recType is a ReferenceBinding            
-               recType =
-                       (enclosingInstance == null)
-                               ? type.resolveType(scope)
-                               : ((SingleTypeReference) type).resolveTypeEnclosing(
-                                       scope,
-                                       (ReferenceBinding) enclosingInstTb);
-               if (recType == null)
-                       return null;
-               if (((ReferenceBinding) recType).isFinal()) {
-                       scope.problemReporter().anonymousClassCannotExtendFinalClass(type, recType);
-                       return null;
+               if (receiverType == null) {
+                       hasError = true;
+               } else if (((ReferenceBinding) receiverType).isFinal()) {
+                       scope.problemReporter().anonymousClassCannotExtendFinalClass(type, receiverType);
+                       hasError = true;
                }
                TypeBinding[] argumentTypes = NoParameters;
                if (arguments != null) {
                        int length = arguments.length;
                        argumentTypes = new TypeBinding[length];
                        for (int i = 0; i < length; i++)
-                               if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null)
-                                       return null;
+                               if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null) {
+                                       hasError = true;
+                               }
+               }
+               // limit of fault-tolerance
+               if (hasError) {
+                               return receiverType;
                }
 
                // an anonymous class inherits from java.lang.Object when declared "after" an interface
-               ReferenceBinding superBinding =
-                       recType.isInterface() ? scope.getJavaLangObject() : (ReferenceBinding) recType;
+               this.superTypeBinding =
+                       receiverType.isInterface() ? scope.getJavaLangObject() : (ReferenceBinding) receiverType;
                MethodBinding inheritedBinding =
-                       scope.getConstructor(superBinding, argumentTypes, this);
+                       scope.getConstructor(this.superTypeBinding, argumentTypes, this);
                if (!inheritedBinding.isValidBinding()) {
                        if (inheritedBinding.declaringClass == null)
-                               inheritedBinding.declaringClass = superBinding;
+                               inheritedBinding.declaringClass = this.superTypeBinding;
                        scope.problemReporter().invalidConstructor(this, inheritedBinding);
                        return null;
                }
                if (enclosingInstance != null) {
-                       if (!BlockScope
-                               .areTypesCompatible(
-                                       enclosingInstTb,
-                                       inheritedBinding.declaringClass.enclosingType())) {
+                       if (!enclosingInstanceType.isCompatibleWith(inheritedBinding.declaringClass.enclosingType())) {
                                scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
                                        enclosingInstance,
-                                       enclosingInstTb,
+                                       enclosingInstanceType,
                                        inheritedBinding.declaringClass.enclosingType());
                                return null;
                        }
@@ -308,25 +309,29 @@ public class QualifiedAllocationExpression extends AllocationExpression {
                                arguments[i].implicitWidening(inheritedBinding.parameters[i], argumentTypes[i]);
 
                // Update the anonymous inner class : superclass, interface  
-               scope.addAnonymousType(anonymousType, (ReferenceBinding) recType);
+               scope.addAnonymousType(anonymousType, (ReferenceBinding) receiverType);
                anonymousType.resolve(scope);
                binding = anonymousType.createsInternalConstructorWithBinding(inheritedBinding);
                return anonymousType.binding; // 1.2 change
        }
+       
+       public String toStringExpression() {
+               return this.toStringExpression(0);
+       }
 
        public String toStringExpression(int tab) {
 
                String s = ""; //$NON-NLS-1$
                if (enclosingInstance != null)
                        s += enclosingInstance.toString() + "."; //$NON-NLS-1$
-               s += super.toStringExpression(tab);
+               s += super.toStringExpression();
                if (anonymousType != null) {
                        s += anonymousType.toString(tab);
                } //allows to restart just after the } one line under ....
                return s;
        }
 
-       public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
+       public void traverse(ASTVisitor visitor, BlockScope scope) {
 
                if (visitor.visit(this, scope)) {
                        if (enclosingInstance != null)
@@ -342,4 +347,4 @@ public class QualifiedAllocationExpression extends AllocationExpression {
                }
                visitor.endVisit(this, scope);
        }
-}
\ No newline at end of file
+}