/******************************************************************************* * 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.InvocationSite; import net.sourceforge.phpdt.internal.compiler.lookup.LocalTypeBinding; import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding; import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding; import net.sourceforge.phpdt.internal.compiler.lookup.NestedTypeBinding; import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding; import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding; import net.sourceforge.phpdt.internal.compiler.lookup.SyntheticArgumentBinding; import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; public class AllocationExpression extends Expression implements InvocationSite { public TypeReference type; public Expression[] arguments; public MethodBinding binding; MethodBinding syntheticAccessor; public AllocationExpression() { } public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { // check captured variables are initialized in current context (26134) checkCapturedLocalInitializationIfNecessary( this.binding.declaringClass, currentScope, flowInfo); // process arguments if (arguments != null) { for (int i = 0, count = arguments.length; i < count; i++) { flowInfo = arguments[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); } } // record some dependency information for exception types ReferenceBinding[] thrownExceptions; if (((thrownExceptions = this.binding.thrownExceptions).length) != 0) { // check exception handling flowContext.checkExceptionHandlers(thrownExceptions, this, flowInfo, currentScope); } manageEnclosingInstanceAccessIfNecessary(currentScope); manageSyntheticAccessIfNecessary(currentScope); return flowInfo; } public void checkCapturedLocalInitializationIfNecessary( ReferenceBinding checkedType, BlockScope currentScope, FlowInfo flowInfo) { if (checkedType.isLocalType() && !checkedType.isAnonymousType() && !currentScope.isDefinedInType(checkedType)) { // only // check // external // allocations NestedTypeBinding nestedType = (NestedTypeBinding) checkedType; SyntheticArgumentBinding[] syntheticArguments = nestedType .syntheticOuterLocalVariables(); if (syntheticArguments != null) for (int i = 0, count = syntheticArguments.length; i < count; i++) { SyntheticArgumentBinding syntheticArgument = syntheticArguments[i]; LocalVariableBinding targetLocal; if ((targetLocal = syntheticArgument.actualOuterLocalVariable) == null) continue; // if (targetLocal.declaration != null && // !flowInfo.isDefinitelyAssigned(targetLocal)){ // currentScope.problemReporter().uninitializedLocalVariable(targetLocal, // this); // } } } } public Expression enclosingInstance() { return null; } // 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); // } public boolean isSuperAccess() { return false; } public boolean isTypeAccess() { return true; } /* * 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, false); // request cascade of accesses } else { // locally propagate, since we already now the desired shape for // sure currentScope.propagateInnerEmulation(allocatedType, false); // request cascade of accesses } } } public void manageSyntheticAccessIfNecessary(BlockScope currentScope) { if (binding.isPrivate() && (currentScope.enclosingSourceType() != binding.declaringClass)) { // if (currentScope // .environment() // .options // .isPrivateConstructorAccessChangingVisibility) { // binding.tagForClearingPrivateModifier(); // // constructor will not be dumped as private, no emulation // required thus // } else { syntheticAccessor = ((SourceTypeBinding) binding.declaringClass) .addSyntheticMethod(binding, isSuperAccess()); currentScope.problemReporter().needToEmulateMethodAccess(binding, this); // } } } public StringBuffer printExpression(int indent, StringBuffer output) { output.append("new "); //$NON-NLS-1$ type.printExpression(0, output); output.append('('); if (arguments != null) { for (int i = 0; i < arguments.length; i++) { if (i > 0) output.append(", "); //$NON-NLS-1$ arguments[i].printExpression(0, output); } } return output.append(')'); } public TypeBinding resolveType(BlockScope scope) { // Propagate the type checking to the arguments, and check if the // constructor is defined. constant = NotAConstant; this.resolvedType = type.resolveType(scope); // will check for null after args are resolved // buffering the arguments' types 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 this.resolvedType; } if (this.resolvedType == null) return null; if (!this.resolvedType.canBeInstantiated()) { scope.problemReporter().cannotInstantiate(type, this.resolvedType); return this.resolvedType; } ReferenceBinding allocatedType = (ReferenceBinding) this.resolvedType; if (!(binding = scope .getConstructor(allocatedType, argumentTypes, this)) .isValidBinding()) { if (binding.declaringClass == null) binding.declaringClass = allocatedType; scope.problemReporter().invalidConstructor(this, binding); return this.resolvedType; } if (isMethodUseDeprecated(binding, scope)) scope.problemReporter().deprecatedMethod(binding, this); if (arguments != null) for (int i = 0; i < arguments.length; i++) arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]); return allocatedType; } public void setActualReceiverType(ReferenceBinding receiverType) { // ignored } public void setDepth(int i) { // ignored } public void setFieldIndex(int i) { // ignored } public String toStringExpression() { String s = "new " + type.toString(0); //$NON-NLS-1$ if (arguments == null) s = s + "()"; //$NON-NLS-1$ else { s = s + "("; //$NON-NLS-1$ for (int i = 0; i < arguments.length; i++) { s = s + arguments[i].toStringExpression(); if (i == (arguments.length - 1)) s = s + ")"; //$NON-NLS-1$ else s = s + ", "; //$NON-NLS-1$ } } return s; } public void traverse(ASTVisitor visitor, BlockScope scope) { if (visitor.visit(this, scope)) { int argumentsLength; type.traverse(visitor, scope); if (arguments != null) { argumentsLength = arguments.length; for (int i = 0; i < argumentsLength; i++) arguments[i].traverse(visitor, scope); } } visitor.endVisit(this, scope); } }