X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/QualifiedAllocationExpression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/QualifiedAllocationExpression.java new file mode 100644 index 0000000..8cc98e7 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/QualifiedAllocationExpression.java @@ -0,0 +1,350 @@ +/******************************************************************************* + * 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 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 net.sourceforge.phpdt.internal.compiler.ast; + +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 + public Expression enclosingInstance; + public AnonymousLocalTypeDeclaration anonymousType; + public ReferenceBinding superTypeBinding; + + public QualifiedAllocationExpression() { + } + + public QualifiedAllocationExpression(AnonymousLocalTypeDeclaration 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); + manageSyntheticAccessIfNecessary(currentScope); + 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) { + + 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 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; + 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; + } + // 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++) + if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null){ + hasError = true; + } + } + // limit of fault-tolerance + if (hasError) return receiverType; + + if (!receiverType.canBeInstantiated()) { + scope.problemReporter().cannotInstantiate(type, receiverType); + return receiverType; + } + if ((this.binding = scope.getConstructor((ReferenceBinding) receiverType, 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]); + } else { + 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 = 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 (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); + } + 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) { + hasError = true; + } + } + // limit of fault-tolerance + if (hasError) { + return receiverType; + } + + // 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 = this.superTypeBinding; + scope.problemReporter().invalidConstructor(this, inheritedBinding); + return null; + } + if (enclosingInstance != null) { + 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. + if (arguments != null) + for (int i = 0; i < arguments.length; i++) + arguments[i].implicitWidening(inheritedBinding.parameters[i], argumentTypes[i]); + + // Update the anonymous inner class : superclass, interface + 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(); + if (anonymousType != null) { + s += anonymousType.toString(tab); + } //allows to restart just after the } one line under .... + return s; + } + + 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); + } +}