removed Makefile; lifted repo/org.ibex.tool/src/ to src/
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / QualifiedAllocationExpression.java
diff --git a/src/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java b/src/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
new file mode 100644 (file)
index 0000000..af7dd02
--- /dev/null
@@ -0,0 +1,347 @@
+/*******************************************************************************
+ * 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.*;
+
+/**
+ * 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 TypeDeclaration anonymousType;
+       public ReferenceBinding superTypeBinding;
+       
+       public QualifiedAllocationExpression() {
+               // for subtypes
+       }
+
+       public QualifiedAllocationExpression(TypeDeclaration anonymousType) {
+               this.anonymousType = anonymousType;
+       }
+
+       public FlowInfo analyseCode(
+               BlockScope currentScope,
+               FlowContext flowContext,
+               FlowInfo flowInfo) {
+
+               // 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++) {
+                               flowInfo = arguments[i].analyseCode(currentScope, flowContext, flowInfo);
+                       }
+               }
+
+               // analyse the anonymous nested type
+               if (anonymousType != null) {
+                       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);
+               }
+               manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
+               manageSyntheticAccessIfNecessary(currentScope, flowInfo);
+               return flowInfo;
+       }
+
+       public Expression enclosingInstance() {
+
+               return enclosingInstance;
+       }
+
+       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.
+        */
+       public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
+
+               if (!flowInfo.isReachable()) return;
+               ReferenceBinding allocatedType;
+
+               // 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()) {
+
+                       if (allocatedType.isLocalType()) {
+                               ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(currentScope, enclosingInstance != null);
+                       } else {
+                               // locally propagate, since we already now the desired shape for sure
+                               currentScope.propagateInnerEmulation(allocatedType, enclosingInstance != null);
+                       }
+               }
+       }
+
+       public StringBuffer printExpression(int indent, StringBuffer output) {
+
+               if (enclosingInstance != null)
+                       enclosingInstance.printExpression(0, output).append('.'); 
+               super.printExpression(0, output);
+               if (anonymousType != null) {
+                       anonymousType.print(indent, output);
+               }
+               return output;
+       }
+       
+       public TypeBinding resolveType(BlockScope scope) {
+
+               // added for code assist...cannot occur with 'normal' code
+               if (anonymousType == null && enclosingInstance == null) {
+                       return super.resolveType(scope);
+               }
+
+               // 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 enclosingInstanceType = null;
+               TypeBinding receiverType = null;
+               boolean hasError = false;
+               boolean enclosingInstanceContainsCast = false;
+               boolean argsContainCast = false;
+               
+               if (enclosingInstance != null) {
+                       if (enclosingInstance instanceof CastExpression) {
+                               enclosingInstance.bits |= IgnoreNeedForCastCheckMASK; // will check later on
+                               enclosingInstanceContainsCast = true;
+                       }
+                       if ((enclosingInstanceType = enclosingInstance.resolveType(scope)) == null){
+                               hasError = true;
+                       } else if (enclosingInstanceType.isBaseType() || enclosingInstanceType.isArrayType()) {
+                               scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(
+                                       enclosingInstanceType,
+                                       enclosingInstance);
+                               hasError = true;
+                       } else {
+                               receiverType = ((SingleTypeReference) type).resolveTypeEnclosing(scope, (ReferenceBinding) enclosingInstanceType);
+                               if (receiverType != null && enclosingInstanceContainsCast) {
+                                               CastExpression.checkNeedForEnclosingInstanceCast(scope, enclosingInstance, enclosingInstanceType, receiverType);
+                               }
+                       }
+               } else {
+                       receiverType = type.resolveType(scope);
+               }
+               if (receiverType == null) {
+                       hasError = true;
+               } else if (((ReferenceBinding) receiverType).isFinal() && this.anonymousType != null) {
+                       scope.problemReporter().anonymousClassCannotExtendFinalClass(type, receiverType);
+                       hasError = true;
+               }
+
+               // will check for null after args are resolved
+               TypeBinding[] argumentTypes = NoParameters;
+               if (arguments != null) {
+                       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){
+                                       hasError = true;
+                               }
+                       }
+               }
+               // limit of fault-tolerance
+               if (hasError) return this.resolvedType = receiverType;
+               
+               if (this.anonymousType == null) {
+                       // qualified allocation with no anonymous type
+                       ReferenceBinding allocationType = (ReferenceBinding) receiverType;
+                       if (!receiverType.canBeInstantiated()) {
+                               scope.problemReporter().cannotInstantiate(type, receiverType);
+                               return this.resolvedType = receiverType;
+                       }
+                       if ((this.binding = scope.getConstructor(allocationType, argumentTypes, this)).isValidBinding()) {
+                               if (isMethodUseDeprecated(binding, scope)) {
+                                       scope.problemReporter().deprecatedMethod(this.binding, this);
+                               }
+                               if (arguments != null) {
+                                       for (int i = 0; i < arguments.length; i++) {
+                                               arguments[i].implicitWidening(this.binding.parameters[i], argumentTypes[i]);
+                                       }
+                                       if (argsContainCast) {
+                                               CastExpression.checkNeedForArgumentCasts(scope, null, allocationType, binding, this.arguments, argumentTypes, this);
+                                       }
+                               }
+                       } else {
+                               if (this.binding.declaringClass == null) {
+                                       this.binding.declaringClass = allocationType;
+                               }
+                               scope.problemReporter().invalidConstructor(this, this.binding);
+                               return this.resolvedType = receiverType;
+                       }
+
+                       // 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 this.resolvedType = receiverType;
+               }
+
+               // anonymous type scenario
+               // an anonymous class inherits from java.lang.Object when declared "after" an interface
+               this.superTypeBinding = receiverType.isInterface() ? scope.getJavaLangObject() : (ReferenceBinding) receiverType;
+               // insert anonymous type in scope
+               scope.addAnonymousType(this.anonymousType, (ReferenceBinding) receiverType);
+               this.anonymousType.resolve(scope);              
+               
+               // find anonymous super constructor
+               MethodBinding inheritedBinding = scope.getConstructor(this.superTypeBinding, argumentTypes, this);
+               if (!inheritedBinding.isValidBinding()) {
+                       if (inheritedBinding.declaringClass == null) {
+                               inheritedBinding.declaringClass = this.superTypeBinding;
+                       }
+                       scope.problemReporter().invalidConstructor(this, inheritedBinding);
+                       return this.resolvedType = anonymousType.binding;
+               }
+               if (enclosingInstance != null) {
+                       ReferenceBinding targetEnclosing = inheritedBinding.declaringClass.enclosingType();
+                       if (targetEnclosing == null) {
+                               scope.problemReporter().unnecessaryEnclosingInstanceSpecification(enclosingInstance, (ReferenceBinding)receiverType);
+                               return this.resolvedType = anonymousType.binding;
+                       } else  if (!enclosingInstanceType.isCompatibleWith(targetEnclosing)) {
+                               scope.problemReporter().typeMismatchErrorActualTypeExpectedType(enclosingInstance, enclosingInstanceType, targetEnclosing);
+                               return this.resolvedType = anonymousType.binding;
+                       }
+               }
+
+               // 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]);
+                       }
+                       if (argsContainCast) {
+                               CastExpression.checkNeedForArgumentCasts(scope, null, this.superTypeBinding, inheritedBinding, this.arguments, argumentTypes, this);
+                       }
+               }
+               // Update the anonymous inner class : superclass, interface  
+               binding = anonymousType.createsInternalConstructorWithBinding(inheritedBinding);
+               return this.resolvedType = anonymousType.binding; // 1.2 change
+       }
+       
+       public void traverse(ASTVisitor visitor, BlockScope scope) {
+
+               if (visitor.visit(this, scope)) {
+                       if (enclosingInstance != null)
+                               enclosingInstance.traverse(visitor, scope);
+                       type.traverse(visitor, scope);
+                       if (arguments != null) {
+                               int argumentsLength = arguments.length;
+                               for (int i = 0; i < argumentsLength; i++)
+                                       arguments[i].traverse(visitor, scope);
+                       }
+                       if (anonymousType != null)
+                               anonymousType.traverse(visitor, scope);
+               }
+               visitor.endVisit(this, scope);
+       }
+}