1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpeclipse.internal.compiler.ast;
13 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
16 import net.sourceforge.phpdt.internal.compiler.lookup.BindingIds;
17 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
18 import net.sourceforge.phpdt.internal.compiler.lookup.InvocationSite;
19 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
20 import net.sourceforge.phpdt.internal.compiler.lookup.ProblemMethodBinding;
21 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
22 import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding;
23 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
25 public class MessageSend extends Expression implements InvocationSite {
26 public Expression receiver ;
27 public char[] selector ;
28 public Expression[] arguments ;
29 public MethodBinding binding, codegenBinding;
31 public long nameSourcePosition ; //(start<<32)+end
33 MethodBinding syntheticAccessor;
35 public TypeBinding receiverType, qualifyingType;
37 public MessageSend() {
40 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
42 flowInfo = receiver.analyseCode(currentScope, flowContext, flowInfo, !binding.isStatic()).unconditionalInits();
43 if (arguments != null) {
44 int length = arguments.length;
45 for (int i = 0; i < length; i++) {
46 flowInfo = arguments[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
49 ReferenceBinding[] thrownExceptions;
50 if ((thrownExceptions = binding.thrownExceptions) != NoExceptions) {
51 // must verify that exceptions potentially thrown by this expression are caught in the method
52 flowContext.checkExceptionHandlers(thrownExceptions, this, flowInfo, currentScope);
54 manageSyntheticAccessIfNecessary(currentScope);
58 * MessageSend code generation
60 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
61 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
62 * @param valueRequired boolean
64 //public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
66 // int pc = codeStream.position;
68 // // generate receiver/enclosing instance access
69 // boolean isStatic = codegenBinding.isStatic();
71 // if (!isStatic && ((bits & DepthMASK) != 0) && receiver.isImplicitThis()){
72 // // outer method can be reached through emulation if implicit access
73 // ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT);
74 // Object[] path = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/);
75 // codeStream.generateOuterAccess(path, this, targetType, currentScope);
77 // receiver.generateCode(currentScope, codeStream, !isStatic);
79 // // generate arguments
80 // if (arguments != null){
81 // for (int i = 0, max = arguments.length; i < max; i++){
82 // arguments[i].generateCode(currentScope, codeStream, true);
85 // // actual message invocation
86 // if (syntheticAccessor == null){
88 // codeStream.invokestatic(codegenBinding);
90 // if( (receiver.isSuper()) || codegenBinding.isPrivate()){
91 // codeStream.invokespecial(codegenBinding);
93 // if (codegenBinding.declaringClass.isInterface()){
94 // codeStream.invokeinterface(codegenBinding);
96 // codeStream.invokevirtual(codegenBinding);
101 // codeStream.invokestatic(syntheticAccessor);
103 // // operation on the returned value
104 // if (valueRequired){
105 // // implicit conversion if necessary
106 // codeStream.generateImplicitConversion(implicitConversion);
108 // // pop return value if any
109 // switch(binding.returnType.id){
112 // codeStream.pop2();
120 // codeStream.recordPositionsFrom(pc, (int)(this.nameSourcePosition >>> 32)); // highlight selector
122 public boolean isSuperAccess() {
123 return receiver.isSuper();
125 public boolean isTypeAccess() {
126 return receiver != null && receiver.isTypeReference();
128 public void manageSyntheticAccessIfNecessary(BlockScope currentScope){
130 if (binding.isPrivate()){
132 // depth is set for both implicit and explicit access (see MethodBinding#canBeSeenBy)
133 if (currentScope.enclosingSourceType() != binding.declaringClass){
135 syntheticAccessor = ((SourceTypeBinding)binding.declaringClass).addSyntheticMethod(binding, isSuperAccess());
136 currentScope.problemReporter().needToEmulateMethodAccess(binding, this);
140 } else if (receiver instanceof QualifiedSuperReference){ // qualified super
142 // qualified super need emulation always
143 SourceTypeBinding destinationType = (SourceTypeBinding)(((QualifiedSuperReference)receiver).currentCompatibleType);
144 syntheticAccessor = destinationType.addSyntheticMethod(binding, isSuperAccess());
145 currentScope.problemReporter().needToEmulateMethodAccess(binding, this);
148 } else if (binding.isProtected()){
150 SourceTypeBinding enclosingSourceType;
151 if (((bits & DepthMASK) != 0)
152 && binding.declaringClass.getPackage()
153 != (enclosingSourceType = currentScope.enclosingSourceType()).getPackage()){
155 SourceTypeBinding currentCompatibleType = (SourceTypeBinding)enclosingSourceType.enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT);
156 syntheticAccessor = currentCompatibleType.addSyntheticMethod(binding, isSuperAccess());
157 currentScope.problemReporter().needToEmulateMethodAccess(binding, this);
161 // if the binding declaring class is not visible, need special action
162 // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
163 // NOTE: from target 1.2 on, method's declaring class is touched if any different from receiver type
164 // and not from Object or implicit static method call.
165 // if (binding.declaringClass != this.qualifyingType
166 // && !this.qualifyingType.isArrayType()
167 // && ((currentScope.environment().options.targetJDK >= CompilerOptions.JDK1_2
168 // && (!receiver.isImplicitThis() || !binding.isStatic())
169 // && binding.declaringClass.id != T_Object) // no change for Object methods
170 // || !binding.declaringClass.canBeSeenBy(currentScope))) {
172 // this.codegenBinding = currentScope.enclosingSourceType().getUpdatedMethodBinding(binding, (ReferenceBinding) this.qualifyingType);
176 public TypeBinding resolveType(BlockScope scope) {
177 // Answer the signature return type
178 // Base type promotion
180 constant = NotAConstant;
181 this.qualifyingType = this.receiverType = receiver.resolveType(scope);
183 // will check for null after args are resolved
184 TypeBinding[] argumentTypes = NoParameters;
185 if (arguments != null) {
186 boolean argHasError = false; // typeChecks all arguments
187 int length = arguments.length;
188 argumentTypes = new TypeBinding[length];
189 for (int i = 0; i < length; i++){
190 if ((argumentTypes[i] = arguments[i].resolveType(scope)) == null){
195 if(receiverType instanceof ReferenceBinding) {
196 // record any selector match, for clients who may still need hint about possible method match
197 this.codegenBinding = this.binding = scope.findMethod((ReferenceBinding)receiverType, selector, new TypeBinding[]{}, this);
202 if (this.receiverType == null)
205 // base type cannot receive any message
206 if (this.receiverType.isBaseType()) {
207 scope.problemReporter().errorNoMethodFor(this, this.receiverType, argumentTypes);
211 this.codegenBinding = this.binding =
212 receiver.isImplicitThis()
213 ? scope.getImplicitMethod(selector, argumentTypes, this)
214 : scope.getMethod(this.receiverType, selector, argumentTypes, this);
215 if (!binding.isValidBinding()) {
216 if (binding.declaringClass == null) {
217 if (this.receiverType instanceof ReferenceBinding) {
218 binding.declaringClass = (ReferenceBinding) this.receiverType;
220 scope.problemReporter().errorNoMethodFor(this, this.receiverType, argumentTypes);
224 scope.problemReporter().invalidMethod(this, binding);
225 // record the closest match, for clients who may still need hint about possible method match
226 if (binding instanceof ProblemMethodBinding){
227 MethodBinding closestMatch = ((ProblemMethodBinding)binding).closestMatch;
228 if (closestMatch != null) this.codegenBinding = this.binding = closestMatch;
230 return binding == null ? null : binding.returnType;
232 if (!binding.isStatic()) {
233 // the "receiver" must not be a type, in other words, a NameReference that the TC has bound to a Type
234 if (receiver instanceof NameReference
235 && (((NameReference) receiver).bits & BindingIds.TYPE) != 0) {
236 scope.problemReporter().mustUseAStaticMethod(this, binding);
239 // static message invoked through receiver? legal but unoptimal (optional warning).
240 if (!(receiver.isImplicitThis()
241 || receiver.isSuper()
242 || (receiver instanceof NameReference
243 && (((NameReference) receiver).bits & BindingIds.TYPE) != 0))) {
244 scope.problemReporter().unnecessaryReceiverForStaticMethod(this, binding);
247 if (arguments != null)
248 for (int i = 0; i < arguments.length; i++)
249 arguments[i].implicitWidening(binding.parameters[i], argumentTypes[i]);
251 //-------message send that are known to fail at compile time-----------
252 if (binding.isAbstract()) {
253 if (receiver.isSuper()) {
254 scope.problemReporter().cannotDireclyInvokeAbstractMethod(this, binding);
256 // abstract private methods cannot occur nor abstract static............
258 if (isMethodUseDeprecated(binding, scope))
259 scope.problemReporter().deprecatedMethod(binding, this);
261 return this.resolvedType = binding.returnType;
263 public void setActualReceiverType(ReferenceBinding receiverType) {
264 this.qualifyingType = receiverType;
266 public void setDepth(int depth) {
267 bits &= ~DepthMASK; // flush previous depth if any
269 bits |= (depth & 0xFF) << DepthSHIFT; // encoded on 8 bits
272 public void setFieldIndex(int depth) {
276 public String toStringExpression(){
278 String s = ""; //$NON-NLS-1$
279 if (!receiver.isImplicitThis())
280 s = s + receiver.toStringExpression()+"."; //$NON-NLS-1$
281 s = s + new String(selector) + "(" ; //$NON-NLS-1$
282 if (arguments != null)
283 for (int i = 0; i < arguments.length ; i ++)
284 { s = s + arguments[i].toStringExpression();
285 if ( i != arguments.length -1 ) s = s + " , " ;};; //$NON-NLS-1$
286 s =s + ")" ; //$NON-NLS-1$
290 public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope blockScope) {
291 if (visitor.visit(this, blockScope)) {
292 receiver.traverse(visitor, blockScope);
293 if (arguments != null) {
294 int argumentsLength = arguments.length;
295 for (int i = 0; i < argumentsLength; i++)
296 arguments[i].traverse(visitor, blockScope);
299 visitor.endVisit(this, blockScope);