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 index cdb2f4b..0295099 100644 --- 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 @@ -23,290 +23,342 @@ 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 Expression receiver; + + public char[] selector; + + public Expression[] arguments; + public MethodBinding binding, codegenBinding; - public long nameSourcePosition ; //(start<<32)+end + 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(); + 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; } - 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); + + /** + * 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(); } - 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()){ + public boolean isTypeAccess() { + return receiver != null && receiver.isTypeReference(); + } - // 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; - } + public void manageSyntheticAccessIfNecessary(BlockScope currentScope) { - } else if (receiver instanceof QualifiedSuperReference){ // qualified super + if (binding.isPrivate()) { - // qualified super need emulation always - SourceTypeBinding destinationType = (SourceTypeBinding)(((QualifiedSuperReference)receiver).currentCompatibleType); - syntheticAccessor = destinationType.addSyntheticMethod(binding, isSuperAccess()); - currentScope.problemReporter().needToEmulateMethodAccess(binding, this); - return; + // depth is set for both implicit and explicit access (see + // MethodBinding#canBeSeenBy) + if (currentScope.enclosingSourceType() != binding.declaringClass) { - } else if (binding.isProtected()){ + syntheticAccessor = ((SourceTypeBinding) binding.declaringClass) + .addSyntheticMethod(binding, isSuperAccess()); + currentScope.problemReporter().needToEmulateMethodAccess( + binding, this); + return; + } - SourceTypeBinding enclosingSourceType; - if (((bits & DepthMASK) != 0) - && binding.declaringClass.getPackage() - != (enclosingSourceType = currentScope.enclosingSourceType()).getPackage()){ + } else if (receiver instanceof QualifiedSuperReference) { // qualified + // super - SourceTypeBinding currentCompatibleType = (SourceTypeBinding)enclosingSourceType.enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT); - syntheticAccessor = currentCompatibleType.addSyntheticMethod(binding, isSuperAccess()); - currentScope.problemReporter().needToEmulateMethodAccess(binding, this); + // 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); + // } } - // 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; + + 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); } } - 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; - } + return output.append(')'); } - 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; - } + public TypeBinding resolveType(BlockScope scope) { + // Answer the signature return type + // Base type promotion - 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); + 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; } } - 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; + 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; } - 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); + + 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; } - } 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 (!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; } - 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); + + public void setDepth(int depth) { + bits &= ~DepthMASK; // flush previous depth if any + if (depth > 0) { + bits |= (depth & 0xFF) << DepthSHIFT; // encoded on 8 bits } - // 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 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 String toStringExpression() { -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); + 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); } - visitor.endVisit(this, blockScope); -} }