X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/MessageSend.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/MessageSend.java new file mode 100644 index 0000000..cdb2f4b --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/MessageSend.java @@ -0,0 +1,312 @@ +/******************************************************************************* + * 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.BindingIds; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.InvocationSite; +import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.ProblemMethodBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; + +public class MessageSend extends Expression implements InvocationSite { + public Expression receiver ; + public char[] selector ; + public Expression[] arguments ; + public MethodBinding binding, codegenBinding; + + public long nameSourcePosition ; //(start<<32)+end + + MethodBinding syntheticAccessor; + + public TypeBinding receiverType, qualifyingType; + +public MessageSend() { + +} +public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + + flowInfo = receiver.analyseCode(currentScope, flowContext, flowInfo, !binding.isStatic()).unconditionalInits(); + if (arguments != null) { + int length = arguments.length; + for (int i = 0; i < length; i++) { + flowInfo = arguments[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + } + } + ReferenceBinding[] thrownExceptions; + if ((thrownExceptions = binding.thrownExceptions) != NoExceptions) { + // must verify that exceptions potentially thrown by this expression are caught in the method + flowContext.checkExceptionHandlers(thrownExceptions, this, flowInfo, currentScope); + } + manageSyntheticAccessIfNecessary(currentScope); + return flowInfo; +} +/** + * MessageSend code generation + * + * @param currentScope net.sourceforge.phpdt.internal.compiler.lookup.BlockScope + * @param codeStream net.sourceforge.phpdt.internal.compiler.codegen.CodeStream + * @param valueRequired boolean + */ +//public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { +// +// int pc = codeStream.position; +// +// // generate receiver/enclosing instance access +// boolean isStatic = codegenBinding.isStatic(); +// // outer access ? +// if (!isStatic && ((bits & DepthMASK) != 0) && receiver.isImplicitThis()){ +// // outer method can be reached through emulation if implicit access +// ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT); +// Object[] path = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/); +// codeStream.generateOuterAccess(path, this, targetType, currentScope); +// } else { +// receiver.generateCode(currentScope, codeStream, !isStatic); +// } +// // generate arguments +// if (arguments != null){ +// for (int i = 0, max = arguments.length; i < max; i++){ +// arguments[i].generateCode(currentScope, codeStream, true); +// } +// } +// // actual message invocation +// if (syntheticAccessor == null){ +// if (isStatic){ +// codeStream.invokestatic(codegenBinding); +// } else { +// if( (receiver.isSuper()) || codegenBinding.isPrivate()){ +// codeStream.invokespecial(codegenBinding); +// } else { +// if (codegenBinding.declaringClass.isInterface()){ +// codeStream.invokeinterface(codegenBinding); +// } else { +// codeStream.invokevirtual(codegenBinding); +// } +// } +// } +// } else { +// codeStream.invokestatic(syntheticAccessor); +// } +// // operation on the returned value +// if (valueRequired){ +// // implicit conversion if necessary +// codeStream.generateImplicitConversion(implicitConversion); +// } else { +// // pop return value if any +// switch(binding.returnType.id){ +// case T_long : +// case T_double : +// codeStream.pop2(); +// break; +// case T_void : +// break; +// default: +// codeStream.pop(); +// } +// } +// codeStream.recordPositionsFrom(pc, (int)(this.nameSourcePosition >>> 32)); // highlight selector +//} +public boolean isSuperAccess() { + return receiver.isSuper(); +} +public boolean isTypeAccess() { + return receiver != null && receiver.isTypeReference(); +} +public void manageSyntheticAccessIfNecessary(BlockScope currentScope){ + + if (binding.isPrivate()){ + + // depth is set for both implicit and explicit access (see MethodBinding#canBeSeenBy) + if (currentScope.enclosingSourceType() != binding.declaringClass){ + + syntheticAccessor = ((SourceTypeBinding)binding.declaringClass).addSyntheticMethod(binding, isSuperAccess()); + currentScope.problemReporter().needToEmulateMethodAccess(binding, this); + return; + } + + } else if (receiver instanceof QualifiedSuperReference){ // qualified super + + // qualified super need emulation always + SourceTypeBinding destinationType = (SourceTypeBinding)(((QualifiedSuperReference)receiver).currentCompatibleType); + syntheticAccessor = destinationType.addSyntheticMethod(binding, isSuperAccess()); + currentScope.problemReporter().needToEmulateMethodAccess(binding, this); + return; + + } else if (binding.isProtected()){ + + SourceTypeBinding enclosingSourceType; + if (((bits & DepthMASK) != 0) + && binding.declaringClass.getPackage() + != (enclosingSourceType = currentScope.enclosingSourceType()).getPackage()){ + + SourceTypeBinding currentCompatibleType = (SourceTypeBinding)enclosingSourceType.enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT); + syntheticAccessor = currentCompatibleType.addSyntheticMethod(binding, isSuperAccess()); + currentScope.problemReporter().needToEmulateMethodAccess(binding, this); + return; + } + } + // if the binding declaring class is not visible, need special action + // for runtime compatibility on 1.2 VMs : change the declaring class of the binding + // NOTE: from target 1.2 on, method's declaring class is touched if any different from receiver type + // and not from Object or implicit static method call. +// if (binding.declaringClass != this.qualifyingType +// && !this.qualifyingType.isArrayType() +// && ((currentScope.environment().options.targetJDK >= CompilerOptions.JDK1_2 +// && (!receiver.isImplicitThis() || !binding.isStatic()) +// && binding.declaringClass.id != T_Object) // no change for Object methods +// || !binding.declaringClass.canBeSeenBy(currentScope))) { +// +// this.codegenBinding = currentScope.enclosingSourceType().getUpdatedMethodBinding(binding, (ReferenceBinding) this.qualifyingType); +// } +} +public StringBuffer printExpression(int indent, StringBuffer output){ + + if (!receiver.isImplicitThis()) receiver.printExpression(0, output).append('.'); + output.append(selector).append('(') ; //$NON-NLS-1$ + 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) { + // Answer the signature return type + // Base type promotion + + constant = NotAConstant; + this.qualifyingType = this.receiverType = receiver.resolveType(scope); + + // will check for null after args are resolved + TypeBinding[] argumentTypes = NoParameters; + if (arguments != null) { + boolean argHasError = false; // typeChecks all arguments + 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){ + if(receiverType instanceof ReferenceBinding) { + // record any selector match, for clients who may still need hint about possible method match + this.codegenBinding = this.binding = scope.findMethod((ReferenceBinding)receiverType, selector, new TypeBinding[]{}, this); + } + return null; + } + } + if (this.receiverType == null) + return null; + + // base type cannot receive any message + if (this.receiverType.isBaseType()) { + scope.problemReporter().errorNoMethodFor(this, this.receiverType, argumentTypes); + return null; + } + + this.codegenBinding = this.binding = + receiver.isImplicitThis() + ? scope.getImplicitMethod(selector, argumentTypes, this) + : scope.getMethod(this.receiverType, selector, argumentTypes, this); + if (!binding.isValidBinding()) { + if (binding.declaringClass == null) { + if (this.receiverType instanceof ReferenceBinding) { + binding.declaringClass = (ReferenceBinding) this.receiverType; + } else { + scope.problemReporter().errorNoMethodFor(this, this.receiverType, argumentTypes); + return null; + } + } + scope.problemReporter().invalidMethod(this, binding); + // record the closest match, for clients who may still need hint about possible method match + if (binding instanceof ProblemMethodBinding){ + MethodBinding closestMatch = ((ProblemMethodBinding)binding).closestMatch; + if (closestMatch != null) this.codegenBinding = this.binding = closestMatch; + } + return binding == null ? null : binding.returnType; + } + if (!binding.isStatic()) { + // the "receiver" must not be a type, in other words, a NameReference that the TC has bound to a Type + if (receiver instanceof NameReference + && (((NameReference) receiver).bits & BindingIds.TYPE) != 0) { + scope.problemReporter().mustUseAStaticMethod(this, binding); + } + } else { + // static message invoked through receiver? legal but unoptimal (optional warning). + if (!(receiver.isImplicitThis() + || receiver.isSuper() + || (receiver instanceof NameReference + && (((NameReference) receiver).bits & BindingIds.TYPE) != 0))) { + scope.problemReporter().unnecessaryReceiverForStaticMethod(this, binding); + } + } + if (arguments != null) + for (int i = 0; i < arguments.length; i++) + arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]); + + //-------message send that are known to fail at compile time----------- + if (binding.isAbstract()) { + if (receiver.isSuper()) { + scope.problemReporter().cannotDireclyInvokeAbstractMethod(this, binding); + } + // abstract private methods cannot occur nor abstract static............ + } + if (isMethodUseDeprecated(binding, scope)) + scope.problemReporter().deprecatedMethod(binding, this); + + return this.resolvedType = binding.returnType; +} +public void setActualReceiverType(ReferenceBinding receiverType) { + this.qualifyingType = receiverType; +} +public void setDepth(int depth) { + bits &= ~DepthMASK; // flush previous depth if any + if (depth > 0) { + bits |= (depth & 0xFF) << DepthSHIFT; // encoded on 8 bits + } +} +public void setFieldIndex(int depth) { + // ignore for here +} + +public String toStringExpression(){ + + String s = ""; //$NON-NLS-1$ + if (!receiver.isImplicitThis()) + s = s + receiver.toStringExpression()+"."; //$NON-NLS-1$ + s = s + new String(selector) + "(" ; //$NON-NLS-1$ + if (arguments != null) + for (int i = 0; i < arguments.length ; i ++) + { s = s + arguments[i].toStringExpression(); + if ( i != arguments.length -1 ) s = s + " , " ;};; //$NON-NLS-1$ + s =s + ")" ; //$NON-NLS-1$ + return s; +} + +public void traverse(ASTVisitor visitor, BlockScope blockScope) { + if (visitor.visit(this, blockScope)) { + receiver.traverse(visitor, blockScope); + if (arguments != null) { + int argumentsLength = arguments.length; + for (int i = 0; i < argumentsLength; i++) + arguments[i].traverse(visitor, blockScope); + } + } + visitor.endVisit(this, blockScope); +} +}