1 /*******************************************************************************
 
   2  * Copyright (c) 2000, 2003 IBM Corporation and others.
 
   3  * All rights reserved. This program and the accompanying materials 
 
   4  * are made available under the terms of the Common Public License v1.0
 
   5  * which accompanies this distribution, and is available at
 
   6  * http://www.eclipse.org/legal/cpl-v10.html
 
   9  *     IBM Corporation - initial API and implementation
 
  10  *******************************************************************************/
 
  11 package net.sourceforge.phpdt.internal.compiler.ast;
 
  13 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
 
  14 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
 
  15 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
 
  16 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
 
  17 import net.sourceforge.phpdt.internal.compiler.lookup.LocalTypeBinding;
 
  18 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
 
  19 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
 
  20 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
 
  23  * Variation on allocation, where can be specified an enclosing instance and an anonymous type
 
  25 public class QualifiedAllocationExpression extends AllocationExpression {
 
  27         //qualification may be on both side
 
  28         public Expression enclosingInstance;
 
  29         public AnonymousLocalTypeDeclaration anonymousType;
 
  30         public ReferenceBinding superTypeBinding;
 
  32         public QualifiedAllocationExpression() {
 
  35         public QualifiedAllocationExpression(AnonymousLocalTypeDeclaration anonymousType) {
 
  36                 this.anonymousType = anonymousType;
 
  39         public FlowInfo analyseCode(
 
  40                 BlockScope currentScope,
 
  41                 FlowContext flowContext,
 
  44                 // analyse the enclosing instance
 
  45                 if (enclosingInstance != null) {
 
  46                         flowInfo = enclosingInstance.analyseCode(currentScope, flowContext, flowInfo);
 
  49                 // check captured variables are initialized in current context (26134)
 
  50                 checkCapturedLocalInitializationIfNecessary(
 
  51                         this.superTypeBinding == null ? this.binding.declaringClass : this.superTypeBinding, 
 
  56                 if (arguments != null) {
 
  57                         for (int i = 0, count = arguments.length; i < count; i++) {
 
  58                                 flowInfo = arguments[i].analyseCode(currentScope, flowContext, flowInfo);
 
  62                 // analyse the anonymous nested type
 
  63                 if (anonymousType != null) {
 
  64                         flowInfo = anonymousType.analyseCode(currentScope, flowContext, flowInfo);
 
  67                 // record some dependency information for exception types
 
  68                 ReferenceBinding[] thrownExceptions;
 
  69                 if (((thrownExceptions = binding.thrownExceptions).length) != 0) {
 
  70                         // check exception handling
 
  71                         flowContext.checkExceptionHandlers(
 
  77                 manageEnclosingInstanceAccessIfNecessary(currentScope);
 
  78                 manageSyntheticAccessIfNecessary(currentScope);
 
  82         public Expression enclosingInstance() {
 
  84                 return enclosingInstance;
 
  87 //      public void generateCode(
 
  88 //              BlockScope currentScope,
 
  89 //              CodeStream codeStream,
 
  90 //              boolean valueRequired) {
 
  92 //              int pc = codeStream.position;
 
  93 //              ReferenceBinding allocatedType = binding.declaringClass;
 
  94 //              codeStream.new_(allocatedType);
 
  95 //              if (valueRequired) {
 
  98 //              // better highlight for allocation: display the type individually
 
  99 //              codeStream.recordPositionsFrom(pc, type.sourceStart);
 
 101 //              // handling innerclass instance allocation - enclosing instance arguments
 
 102 //              if (allocatedType.isNestedType()) {
 
 103 //                      codeStream.generateSyntheticEnclosingInstanceValues(
 
 106 //                              enclosingInstance(),
 
 109 //              // generate the arguments for constructor
 
 110 //              if (arguments != null) {
 
 111 //                      for (int i = 0, count = arguments.length; i < count; i++) {
 
 112 //                              arguments[i].generateCode(currentScope, codeStream, true);
 
 115 //              // handling innerclass instance allocation - outer local arguments
 
 116 //              if (allocatedType.isNestedType()) {
 
 117 //                      codeStream.generateSyntheticOuterArgumentValues(
 
 123 //              // invoke constructor
 
 124 //              if (syntheticAccessor == null) {
 
 125 //                      codeStream.invokespecial(binding);
 
 127 //                      // synthetic accessor got some extra arguments appended to its signature, which need values
 
 129 //                              max = syntheticAccessor.parameters.length - binding.parameters.length;
 
 132 //                              codeStream.aconst_null();
 
 134 //                      codeStream.invokespecial(syntheticAccessor);
 
 136 //              codeStream.recordPositionsFrom(pc, this.sourceStart);
 
 138 //              if (anonymousType != null) {
 
 139 //                      anonymousType.generateCode(currentScope, codeStream);
 
 143         public boolean isSuperAccess() {
 
 145                 // necessary to lookup super constructor of anonymous type
 
 146                 return anonymousType != null;
 
 149         /* Inner emulation consists in either recording a dependency 
 
 150          * link only, or performing one level of propagation.
 
 152          * Dependency mechanism is used whenever dealing with source target
 
 153          * types, since by the time we reach them, we might not yet know their
 
 156         public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
 
 158                 ReferenceBinding allocatedType;
 
 160                 // perform some emulation work in case there is some and we are inside a local type only
 
 161                 if ((allocatedType = binding.declaringClass).isNestedType()
 
 162                         && currentScope.enclosingSourceType().isLocalType()) {
 
 164                         if (allocatedType.isLocalType()) {
 
 165                                 ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(currentScope, enclosingInstance != null);
 
 167                                 // locally propagate, since we already now the desired shape for sure
 
 168                                 currentScope.propagateInnerEmulation(allocatedType, enclosingInstance != null);
 
 173         public TypeBinding resolveType(BlockScope scope) {
 
 175                 // added for code assist...cannot occur with 'normal' code
 
 176                 if (anonymousType == null && enclosingInstance == null) {
 
 177                         return super.resolveType(scope);
 
 180                 // Propagate the type checking to the arguments, and checks if the constructor is defined.
 
 181                 // ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
 
 182                 // ClassInstanceCreationExpression ::= Name '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
 
 183                 // ==> by construction, when there is an enclosing instance the typename may NOT be qualified
 
 184                 // ==> therefore by construction the type is always a SingleTypeReferenceType instead of being either 
 
 185                 // sometime a SingleTypeReference and sometime a QualifedTypeReference
 
 187                 constant = NotAConstant;
 
 188                 TypeBinding enclosingInstanceType = null;
 
 189                 TypeBinding receiverType = null;
 
 190                 boolean hasError = false;
 
 191                 if (anonymousType == null) { //----------------no anonymous class------------------------       
 
 192                         if ((enclosingInstanceType = enclosingInstance.resolveType(scope)) == null){
 
 194                         } else if (enclosingInstanceType.isBaseType() || enclosingInstanceType.isArrayType()) {
 
 195                                 scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
 
 196                                         enclosingInstanceType,
 
 199                         } else if ((this.resolvedType = receiverType = ((SingleTypeReference) type).resolveTypeEnclosing(
 
 201                                                         (ReferenceBinding) enclosingInstanceType)) == null) {
 
 204                         // will check for null after args are resolved
 
 205                         TypeBinding[] argumentTypes = NoParameters;
 
 206                         if (arguments != null) {
 
 207                                 int length = arguments.length;
 
 208                                 argumentTypes = new TypeBinding[length];
 
 209                                 for (int i = 0; i < length; i++)
 
 210                                         if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null){
 
 214                         // limit of fault-tolerance
 
 215                         if (hasError) return receiverType;
 
 217                         if (!receiverType.canBeInstantiated()) {
 
 218                                 scope.problemReporter().cannotInstantiate(type, receiverType);
 
 221                         if ((this.binding = scope.getConstructor((ReferenceBinding) receiverType, argumentTypes, this))
 
 223                                 if (isMethodUseDeprecated(binding, scope))
 
 224                                         scope.problemReporter().deprecatedMethod(this.binding, this);
 
 226                                 if (arguments != null)
 
 227                                         for (int i = 0; i < arguments.length; i++)
 
 228                                                 arguments[i].implicitWidening(this.binding.parameters[i], argumentTypes[i]);
 
 230                                 if (this.binding.declaringClass == null)
 
 231                                         this.binding.declaringClass = (ReferenceBinding) receiverType;
 
 232                                 scope.problemReporter().invalidConstructor(this, this.binding);
 
 236                         // The enclosing instance must be compatible with the innermost enclosing type
 
 237                         ReferenceBinding expectedType = this.binding.declaringClass.enclosingType();
 
 238                         if (enclosingInstanceType.isCompatibleWith(expectedType))
 
 240                         scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
 
 241                                 this.enclosingInstance,
 
 242                                 enclosingInstanceType,
 
 247                 //--------------there is an anonymous type declaration-----------------
 
 248                 if (this.enclosingInstance != null) {
 
 249                         if ((enclosingInstanceType = this.enclosingInstance.resolveType(scope)) == null) {
 
 251                         } else if (enclosingInstanceType.isBaseType() || enclosingInstanceType.isArrayType()) {
 
 252                                 scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
 
 253                                         enclosingInstanceType,
 
 254                                         this.enclosingInstance);
 
 257                                 receiverType = ((SingleTypeReference) type).resolveTypeEnclosing(
 
 259                                                                                 (ReferenceBinding) enclosingInstanceType);                              
 
 262                         receiverType = type.resolveType(scope);
 
 264                 if (receiverType == null) {
 
 266                 } else if (((ReferenceBinding) receiverType).isFinal()) {
 
 267                         scope.problemReporter().anonymousClassCannotExtendFinalClass(type, receiverType);
 
 270                 TypeBinding[] argumentTypes = NoParameters;
 
 271                 if (arguments != null) {
 
 272                         int length = arguments.length;
 
 273                         argumentTypes = new TypeBinding[length];
 
 274                         for (int i = 0; i < length; i++)
 
 275                                 if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null) {
 
 279                 // limit of fault-tolerance
 
 284                 // an anonymous class inherits from java.lang.Object when declared "after" an interface
 
 285                 this.superTypeBinding =
 
 286                         receiverType.isInterface() ? scope.getJavaLangObject() : (ReferenceBinding) receiverType;
 
 287                 MethodBinding inheritedBinding =
 
 288                         scope.getConstructor(this.superTypeBinding, argumentTypes, this);
 
 289                 if (!inheritedBinding.isValidBinding()) {
 
 290                         if (inheritedBinding.declaringClass == null)
 
 291                                 inheritedBinding.declaringClass = this.superTypeBinding;
 
 292                         scope.problemReporter().invalidConstructor(this, inheritedBinding);
 
 295                 if (enclosingInstance != null) {
 
 296                         if (!enclosingInstanceType.isCompatibleWith(inheritedBinding.declaringClass.enclosingType())) {
 
 297                                 scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
 
 299                                         enclosingInstanceType,
 
 300                                         inheritedBinding.declaringClass.enclosingType());
 
 305                 // this promotion has to be done somewhere: here or inside the constructor of the
 
 306                 // anonymous class. We do it here while the constructor of the inner is then easier.
 
 307                 if (arguments != null)
 
 308                         for (int i = 0; i < arguments.length; i++)
 
 309                                 arguments[i].implicitWidening(inheritedBinding.parameters[i], argumentTypes[i]);
 
 311                 // Update the anonymous inner class : superclass, interface  
 
 312                 scope.addAnonymousType(anonymousType, (ReferenceBinding) receiverType);
 
 313                 anonymousType.resolve(scope);
 
 314                 binding = anonymousType.createsInternalConstructorWithBinding(inheritedBinding);
 
 315                 return anonymousType.binding; // 1.2 change
 
 318         public String toStringExpression() {
 
 319                 return this.toStringExpression(0);
 
 322         public String toStringExpression(int tab) {
 
 324                 String s = ""; //$NON-NLS-1$
 
 325                 if (enclosingInstance != null)
 
 326                         s += enclosingInstance.toString() + "."; //$NON-NLS-1$
 
 327                 s += super.toStringExpression();
 
 328                 if (anonymousType != null) {
 
 329                         s += anonymousType.toString(tab);
 
 330                 } //allows to restart just after the } one line under ....
 
 334         public void traverse(ASTVisitor visitor, BlockScope scope) {
 
 336                 if (visitor.visit(this, scope)) {
 
 337                         if (enclosingInstance != null)
 
 338                                 enclosingInstance.traverse(visitor, scope);
 
 339                         type.traverse(visitor, scope);
 
 340                         if (arguments != null) {
 
 341                                 int argumentsLength = arguments.length;
 
 342                                 for (int i = 0; i < argumentsLength; i++)
 
 343                                         arguments[i].traverse(visitor, scope);
 
 345                         if (anonymousType != null)
 
 346                                 anonymousType.traverse(visitor, scope);
 
 348                 visitor.endVisit(this, scope);