Refactory: smarty.ui plugin.
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / QualifiedAllocationExpression.java
index da1555d..fe67cc9 100644 (file)
@@ -1,65 +1,79 @@
 /*******************************************************************************
- * 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.*;
-import net.sourceforge.phpdt.internal.compiler.flow.*;
-import net.sourceforge.phpdt.internal.compiler.lookup.*;
-
+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;
+import net.sourceforge.phpdt.internal.compiler.lookup.LocalTypeBinding;
+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
+
+       // qualification may be on both side
        public Expression enclosingInstance;
+
        public AnonymousLocalTypeDeclaration anonymousType;
 
+       public ReferenceBinding superTypeBinding;
+
        public QualifiedAllocationExpression() {
        }
 
-       public QualifiedAllocationExpression(AnonymousLocalTypeDeclaration anonymousType) {
+       public QualifiedAllocationExpression(
+                       AnonymousLocalTypeDeclaration anonymousType) {
                this.anonymousType = anonymousType;
        }
 
-       public FlowInfo analyseCode(
-               BlockScope currentScope,
-               FlowContext flowContext,
-               FlowInfo flowInfo) {
-
-               // variation on allocation, where can be specified an enclosing instance and an anonymous type
+       public FlowInfo analyseCode(BlockScope currentScope,
+                       FlowContext flowContext, FlowInfo flowInfo) {
 
                // analyse the enclosing instance
                if (enclosingInstance != null) {
-                       flowInfo = enclosingInstance.analyseCode(currentScope, flowContext, flowInfo);
+                       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++) {
-                               flowInfo = arguments[i].analyseCode(currentScope, flowContext, flowInfo);
+                               flowInfo = arguments[i].analyseCode(currentScope, flowContext,
+                                               flowInfo);
                        }
                }
 
                // analyse the anonymous nested type
                if (anonymousType != null) {
-                       flowInfo = anonymousType.analyseCode(currentScope, flowContext, flowInfo);
+                       flowInfo = anonymousType.analyseCode(currentScope, flowContext,
+                                       flowInfo);
                }
 
                // record some dependency information for exception types
                ReferenceBinding[] thrownExceptions;
                if (((thrownExceptions = binding.thrownExceptions).length) != 0) {
                        // check exception handling
-                       flowContext.checkExceptionHandlers(
-                               thrownExceptions,
-                               this,
-                               flowInfo,
-                               currentScope);
+                       flowContext.checkExceptionHandlers(thrownExceptions, this,
+                                       flowInfo, currentScope);
                }
                manageEnclosingInstanceAccessIfNecessary(currentScope);
                manageSyntheticAccessIfNecessary(currentScope);
@@ -71,257 +85,283 @@ 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() {
 
                // necessary to lookup super constructor of anonymous type
                return anonymousType != null;
        }
-       
-       /* 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.
+
+       /*
+        * 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.
         */
        public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
 
                ReferenceBinding allocatedType;
 
-               // perform some emulation work in case there is some and we are inside a local type only
+               // perform some emulation work in case there is some and we are inside a
+               // local type only
                if ((allocatedType = binding.declaringClass).isNestedType()
-                       && currentScope.enclosingSourceType().isLocalType()) {
+                               && currentScope.enclosingSourceType().isLocalType()) {
 
                        if (allocatedType.isLocalType()) {
                                ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(
-                                       currentScope,
-                                       enclosingInstance != null,
-                                       false);
-                               // request cascade of accesses
+                                               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
+                               // locally propagate, since we already now the desired shape for
+                               // sure
+                               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
-               // ==> therefore by construction the type is always a SingleTypeReferenceType instead of being either 
+               // 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
+               // ==> therefore by construction the type is always a
+               // SingleTypeReferenceType instead of being either
                // 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()) {
-                               scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
-                                       enclosingInstTb,
-                                       enclosingInstance);
-                               return null;
+               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(
+                                                               enclosingInstanceType, enclosingInstance);
+                               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 (scope.areTypesCompatible(enclosingInstTb, expectedType))
-                               return recType;
-                       scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
-                               enclosingInstance,
-                               enclosingInstTb,
-                               expectedType);
-                       return recType;
+                       // The enclosing instance must be compatible with the innermost
+                       // enclosing type
+                       ReferenceBinding expectedType = this.binding.declaringClass
+                                       .enclosingType();
+                       if (enclosingInstanceType.isCompatibleWith(expectedType))
+                               return receiverType;
+                       scope.problemReporter()
+                                       .typeMismatchErrorActualTypeExpectedType(
+                                                       this.enclosingInstance, enclosingInstanceType,
+                                                       expectedType);
+                       return receiverType;
                }
 
-               //--------------there is an anonymous type declaration-----------------
-               if (enclosingInstance != null) {
-                       if ((enclosingInstTb = enclosingInstance.resolveType(scope)) == null)
-                               return null;
-                       if (enclosingInstTb.isBaseType() | enclosingInstTb.isArrayType()) {
-                               scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
-                                       enclosingInstTb,
-                                       enclosingInstance);
-                               return null;
+               // --------------there is an anonymous type declaration-----------------
+               if (this.enclosingInstance != null) {
+                       if ((enclosingInstanceType = this.enclosingInstance
+                                       .resolveType(scope)) == null) {
+                               hasError = true;
+                       } else if (enclosingInstanceType.isBaseType()
+                                       || enclosingInstanceType.isArrayType()) {
+                               scope.problemReporter()
+                                               .illegalPrimitiveOrArrayTypeForEnclosingInstance(
+                                                               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;
-               MethodBinding inheritedBinding =
-                       scope.getConstructor(superBinding, argumentTypes, this);
+               // an anonymous class inherits from java.lang.Object when declared
+               // "after" an interface
+               this.superTypeBinding = receiverType.isInterface() ? scope
+                               .getJavaLangObject() : (ReferenceBinding) receiverType;
+               MethodBinding inheritedBinding = 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 (!scope
-                               .areTypesCompatible(
-                                       enclosingInstTb,
-                                       inheritedBinding.declaringClass.enclosingType())) {
-                               scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
-                                       enclosingInstance,
-                                       enclosingInstTb,
-                                       inheritedBinding.declaringClass.enclosingType());
+                       if (!enclosingInstanceType
+                                       .isCompatibleWith(inheritedBinding.declaringClass
+                                                       .enclosingType())) {
+                               scope
+                                               .problemReporter()
+                                               .typeMismatchErrorActualTypeExpectedType(
+                                                               enclosingInstance, enclosingInstanceType,
+                                                               inheritedBinding.declaringClass.enclosingType());
                                return null;
                        }
                }
 
-               // this promotion has to be done somewhere: here or inside the constructor of the
-               // anonymous class. We do it here while the constructor of the inner is then easier.
+               // this promotion has to be done somewhere: here or inside the
+               // constructor of the
+               // anonymous class. We do it here while the constructor of the inner is
+               // then easier.
                if (arguments != null)
                        for (int i = 0; i < arguments.length; i++)
-                               arguments[i].implicitWidening(inheritedBinding.parameters[i], argumentTypes[i]);
+                               arguments[i].implicitWidening(inheritedBinding.parameters[i],
+                                               argumentTypes[i]);
 
-               // Update the anonymous inner class : superclass, interface  
-               scope.addAnonymousType(anonymousType, (ReferenceBinding) recType);
+               // Update the anonymous inner class : superclass, interface
+               scope.addAnonymousType(anonymousType, (ReferenceBinding) receiverType);
                anonymousType.resolve(scope);
-               binding = anonymousType.createsInternalConstructorWithBinding(inheritedBinding);
+               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 ....
+               } // 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)
@@ -337,4 +377,4 @@ public class QualifiedAllocationExpression extends AllocationExpression {
                }
                visitor.endVisit(this, scope);
        }
-}
\ No newline at end of file
+}