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.phpdt.internal.compiler.lookup;
13 import net.sourceforge.phpdt.core.compiler.CharOperation;
14 import net.sourceforge.phpeclipse.internal.compiler.ast.AbstractMethodDeclaration;
15 import net.sourceforge.phpeclipse.internal.compiler.ast.ConstructorDeclaration;
17 public class MethodBinding extends Binding implements BaseTypes, TypeConstants {
19 public char[] selector;
20 public TypeBinding returnType;
21 public TypeBinding[] parameters;
22 public ReferenceBinding[] thrownExceptions;
23 public ReferenceBinding declaringClass;
27 protected MethodBinding() {
29 public MethodBinding(int modifiers, char[] selector, TypeBinding returnType, TypeBinding[] args, ReferenceBinding[] exceptions, ReferenceBinding declaringClass) {
30 this.modifiers = modifiers;
31 this.selector = selector;
32 this.returnType = returnType;
33 this.parameters = (args == null || args.length == 0) ? NoParameters : args;
34 this.thrownExceptions = (exceptions == null || exceptions.length == 0) ? NoExceptions : exceptions;
35 this.declaringClass = declaringClass;
37 // propagate the strictfp & deprecated modifiers
38 if (this.declaringClass != null) {
39 // if (this.declaringClass.isStrictfp())
40 // if (!(isNative() || isAbstract()))
41 // this.modifiers |= AccStrictfp;
42 if (this.declaringClass.isViewedAsDeprecated() && !isDeprecated())
43 this.modifiers |= AccDeprecatedImplicitly;
46 public MethodBinding(int modifiers, TypeBinding[] args, ReferenceBinding[] exceptions, ReferenceBinding declaringClass) {
47 this(modifiers, ConstructorDeclaration.ConstantPoolName, VoidBinding, args, exceptions, declaringClass);
49 // special API used to change method declaring class for runtime visibility check
50 public MethodBinding(MethodBinding initialMethodBinding, ReferenceBinding declaringClass) {
51 this.modifiers = initialMethodBinding.modifiers;
52 this.selector = initialMethodBinding.selector;
53 this.returnType = initialMethodBinding.returnType;
54 this.parameters = initialMethodBinding.parameters;
55 this.thrownExceptions = initialMethodBinding.thrownExceptions;
56 this.declaringClass = declaringClass;
58 /* Answer true if the argument types & the receiver's parameters are equal
61 public final boolean areParametersEqual(MethodBinding method) {
62 TypeBinding[] args = method.parameters;
63 if (parameters == args)
66 int length = parameters.length;
67 if (length != args.length)
70 for (int i = 0; i < length; i++)
71 if (parameters[i] != args[i])
76 * Answer the receiver's binding type from Binding.BindingID.
79 public final int bindingType() {
82 /* Answer true if the receiver is visible to the type provided by the scope.
83 * InvocationSite implements isSuperAccess() to provide additional information
84 * if the receiver is protected.
86 * NOTE: This method should ONLY be sent if the receiver is a constructor.
88 * NOTE: Cannot invoke this method with a compilation unit scope.
91 public final boolean canBeSeenBy(InvocationSite invocationSite, Scope scope) {
92 if (isPublic()) return true;
94 SourceTypeBinding invocationType = scope.enclosingSourceType();
95 if (invocationType == declaringClass) return true;
98 // answer true if the receiver is in the same package as the invocationType
99 if (invocationType.fPackage == declaringClass.fPackage) return true;
100 return invocationSite.isSuperAccess();
104 // answer true if the invocationType and the declaringClass have a common enclosingType
105 // already know they are not the identical type
106 ReferenceBinding outerInvocationType = invocationType;
107 ReferenceBinding temp = outerInvocationType.enclosingType();
108 while (temp != null) {
109 outerInvocationType = temp;
110 temp = temp.enclosingType();
113 ReferenceBinding outerDeclaringClass = declaringClass;
114 temp = outerDeclaringClass.enclosingType();
115 while (temp != null) {
116 outerDeclaringClass = temp;
117 temp = temp.enclosingType();
119 return outerInvocationType == outerDeclaringClass;
123 return invocationType.fPackage == declaringClass.fPackage;
125 /* Answer true if the receiver is visible to the type provided by the scope.
126 * InvocationSite implements isSuperAccess() to provide additional information
127 * if the receiver is protected.
129 * NOTE: Cannot invoke this method with a compilation unit scope.
131 public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invocationSite, Scope scope) {
132 if (isPublic()) return true;
134 SourceTypeBinding invocationType = scope.enclosingSourceType();
135 if (invocationType == declaringClass && invocationType == receiverType) return true;
138 // answer true if the invocationType is the declaringClass or they are in the same package
139 // OR the invocationType is a subclass of the declaringClass
140 // AND the receiverType is the invocationType or its subclass
141 // OR the method is a static method accessed directly through a type
142 // OR previous assertions are true for one of the enclosing type
143 if (invocationType == declaringClass) return true;
144 if (invocationType.fPackage == declaringClass.fPackage) return true;
146 ReferenceBinding currentType = invocationType;
149 if (declaringClass.isSuperclassOf(currentType)) {
150 if (invocationSite.isSuperAccess()){
153 // receiverType can be an array binding in one case... see if you can change it
154 if (receiverType instanceof ArrayBinding){
158 return true; // see 1FMEPDL - return invocationSite.isTypeAccess();
160 if (currentType == receiverType || currentType.isSuperclassOf((ReferenceBinding) receiverType)){
161 if (depth > 0) invocationSite.setDepth(depth);
166 currentType = currentType.enclosingType();
167 } while (currentType != null);
172 // answer true if the receiverType is the declaringClass
173 // AND the invocationType and the declaringClass have a common enclosingType
174 if (receiverType != declaringClass) return false;
176 if (invocationType != declaringClass) {
177 ReferenceBinding outerInvocationType = invocationType;
178 ReferenceBinding temp = outerInvocationType.enclosingType();
179 while (temp != null) {
180 outerInvocationType = temp;
181 temp = temp.enclosingType();
184 ReferenceBinding outerDeclaringClass = declaringClass;
185 temp = outerDeclaringClass.enclosingType();
186 while (temp != null) {
187 outerDeclaringClass = temp;
188 temp = temp.enclosingType();
190 if (outerInvocationType != outerDeclaringClass) return false;
196 if (invocationType.fPackage != declaringClass.fPackage) return false;
198 // receiverType can be an array binding in one case... see if you can change it
199 if (receiverType instanceof ArrayBinding)
201 ReferenceBinding type = (ReferenceBinding) receiverType;
202 PackageBinding declaringPackage = declaringClass.fPackage;
204 if (declaringClass == type) return true;
205 if (declaringPackage != type.fPackage) return false;
206 } while ((type = type.superclass()) != null);
210 /* Answer the receiver's constant pool name.
212 * <init> for constructors
213 * <clinit> for clinit methods
214 * or the source name of the method
216 public final char[] constantPoolName() {
219 public final int getAccessFlags() {
220 return modifiers & AccJustFlag;
223 /* Answer true if the receiver is an abstract method
225 public final boolean isAbstract() {
226 return (modifiers & AccAbstract) != 0;
229 /* Answer true if the receiver is a constructor
231 public final boolean isConstructor() {
232 return selector == ConstructorDeclaration.ConstantPoolName;
234 protected boolean isConstructorRelated() {
235 return isConstructor();
238 /* Answer true if the receiver has default visibility
240 public final boolean isDefault() {
241 return !isPublic() && !isProtected() && !isPrivate();
244 /* Answer true if the receiver is a system generated default abstract method
246 public final boolean isDefaultAbstract() {
247 return (modifiers & AccDefaultAbstract) != 0;
250 /* Answer true if the receiver is a deprecated method
252 public final boolean isDeprecated() {
253 return (modifiers & AccDeprecated) != 0;
256 /* Answer true if the receiver is final and cannot be overridden
258 public final boolean isFinal() {
259 return (modifiers & AccFinal) != 0;
262 /* Answer true if the receiver is implementing another method
263 * in other words, it is overriding and concrete, and overriden method is abstract
264 * Only set for source methods
266 public final boolean isImplementing() {
267 return (modifiers & AccImplementing) != 0;
270 /* Answer true if the receiver is a native method
272 //public final boolean isNative() {
273 // return (modifiers & AccNative) != 0;
276 /* Answer true if the receiver is overriding another method
277 * Only set for source methods
279 public final boolean isOverriding() {
280 return (modifiers & AccOverriding) != 0;
283 * Answer true if the receiver is a "public static void main(String[])" method
285 public final boolean isMain() {
286 if (this.selector.length == 4 && CharOperation.equals(this.selector, MAIN)
287 && ((this.modifiers & (AccPublic | AccStatic)) != 0)
288 && VoidBinding == this.returnType
289 && this.parameters.length == 1) {
290 TypeBinding paramType = this.parameters[0];
291 if (paramType.dimensions() == 1 && paramType.leafComponentType().id == TypeIds.T_JavaLangString) {
297 /* Answer true if the receiver has private visibility
299 public final boolean isPrivate() {
300 return (modifiers & AccPrivate) != 0;
303 /* Answer true if the receiver has private visibility and is used locally
305 public final boolean isPrivateUsed() {
306 return (modifiers & AccPrivateUsed) != 0;
309 /* Answer true if the receiver has protected visibility
311 public final boolean isProtected() {
312 return (modifiers & AccProtected) != 0;
315 /* Answer true if the receiver has public visibility
317 public final boolean isPublic() {
318 return (modifiers & AccPublic) != 0;
321 /* Answer true if the receiver got requested to clear the private modifier
322 * during private access emulation.
324 public final boolean isRequiredToClearPrivateModifier() {
325 return (modifiers & AccClearPrivateModifier) != 0;
328 /* Answer true if the receiver is a static method
330 public final boolean isStatic() {
331 return (modifiers & AccStatic) != 0;
334 /* Answer true if all float operations must adher to IEEE 754 float/double rules
336 //public final boolean isStrictfp() {
337 // return (modifiers & AccStrictfp) != 0;
340 /* Answer true if the receiver is a synchronized method
342 //public final boolean isSynchronized() {
343 // return (modifiers & AccSynchronized) != 0;
346 /* Answer true if the receiver has public visibility
348 //public final boolean isSynthetic() {
349 // return (modifiers & AccSynthetic) != 0;
352 /* Answer true if the receiver's declaring type is deprecated (or any of its enclosing types)
354 public final boolean isViewedAsDeprecated() {
355 return (modifiers & AccDeprecated) != 0 ||
356 (modifiers & AccDeprecatedImplicitly) != 0;
359 public char[] readableName() /* foo(int, Thread) */ {
360 StringBuffer buffer = new StringBuffer(parameters.length + 1 * 20);
362 buffer.append(declaringClass.sourceName());
364 buffer.append(selector);
366 if (parameters != NoParameters) {
367 for (int i = 0, length = parameters.length; i < length; i++) {
369 buffer.append(", "); //$NON-NLS-1$
370 buffer.append(parameters[i].sourceName());
374 return buffer.toString().toCharArray();
378 * @see net.sourceforge.phpdt.internal.compiler.lookup.Binding#shortReadableName()
380 public char[] shortReadableName() {
381 StringBuffer buffer = new StringBuffer(parameters.length + 1 * 20);
383 buffer.append(declaringClass.shortReadableName());
385 buffer.append(selector);
387 if (parameters != NoParameters) {
388 for (int i = 0, length = parameters.length; i < length; i++) {
390 buffer.append(", "); //$NON-NLS-1$
391 buffer.append(parameters[i].shortReadableName());
395 return buffer.toString().toCharArray();
398 protected final void selector(char[] selector) {
399 this.selector = selector;
400 this.signature = null;
403 /* Answer the receiver's signature.
405 * NOTE: This method should only be used during/after code gen.
406 * The signature is cached so if the signature of the return type or any parameter
407 * type changes, the cached state is invalid.
409 public final char[] signature() /* (ILjava/lang/Thread;)Ljava/lang/Object; */ {
410 if (signature != null)
413 StringBuffer buffer = new StringBuffer(parameters.length + 1 * 20);
416 TypeBinding[] targetParameters = this.parameters;
417 boolean considerSynthetics = isConstructorRelated() && declaringClass.isNestedType();
418 if (considerSynthetics) {
420 // take into account the synthetic argument type signatures as well
421 ReferenceBinding[] syntheticArgumentTypes = declaringClass.syntheticEnclosingInstanceTypes();
422 int count = syntheticArgumentTypes == null ? 0 : syntheticArgumentTypes.length;
423 for (int i = 0; i < count; i++) {
424 buffer.append(syntheticArgumentTypes[i].signature());
427 if (this instanceof SyntheticAccessMethodBinding) {
428 targetParameters = ((SyntheticAccessMethodBinding)this).targetMethod.parameters;
432 if (targetParameters != NoParameters) {
433 for (int i = 0; i < targetParameters.length; i++) {
434 buffer.append(targetParameters[i].signature());
437 if (considerSynthetics) {
438 SyntheticArgumentBinding[] syntheticOuterArguments = declaringClass.syntheticOuterLocalVariables();
439 int count = syntheticOuterArguments == null ? 0 : syntheticOuterArguments.length;
440 for (int i = 0; i < count; i++) {
441 buffer.append(syntheticOuterArguments[i].type.signature());
443 // move the extra padding arguments of the synthetic constructor invocation to the end
444 for (int i = targetParameters.length, extraLength = parameters.length; i < extraLength; i++) {
445 buffer.append(parameters[i].signature());
449 buffer.append(returnType.signature());
450 return signature = buffer.toString().toCharArray();
452 public final int sourceEnd() {
453 AbstractMethodDeclaration method = sourceMethod();
457 return method.sourceEnd;
459 AbstractMethodDeclaration sourceMethod() {
460 SourceTypeBinding sourceType;
462 sourceType = (SourceTypeBinding) declaringClass;
463 } catch (ClassCastException e) {
467 AbstractMethodDeclaration[] methods = sourceType.scope.referenceContext.methods;
468 for (int i = methods.length; --i >= 0;)
469 if (this == methods[i].binding)
473 public final int sourceStart() {
474 AbstractMethodDeclaration method = sourceMethod();
478 return method.sourceStart;
480 /* During private access emulation, the binding can be requested to loose its
481 * private visibility when the class file is dumped.
484 public final void tagForClearingPrivateModifier() {
485 modifiers |= AccClearPrivateModifier;
487 public String toString() {
488 String s = (returnType != null) ? returnType.debugName() : "NULL TYPE"; //$NON-NLS-1$
489 s += " "; //$NON-NLS-1$
490 s += (selector != null) ? new String(selector) : "UNNAMED METHOD"; //$NON-NLS-1$
492 s += "("; //$NON-NLS-1$
493 if (parameters != null) {
494 if (parameters != NoParameters) {
495 for (int i = 0, length = parameters.length; i < length; i++) {
497 s += ", "; //$NON-NLS-1$
498 s += (parameters[i] != null) ? parameters[i].debugName() : "NULL TYPE"; //$NON-NLS-1$
502 s += "NULL PARAMETERS"; //$NON-NLS-1$
504 s += ") "; //$NON-NLS-1$
506 if (thrownExceptions != null) {
507 if (thrownExceptions != NoExceptions) {
508 s += "throws "; //$NON-NLS-1$
509 for (int i = 0, length = thrownExceptions.length; i < length; i++) {
511 s += ", "; //$NON-NLS-1$
512 s += (thrownExceptions[i] != null) ? thrownExceptions[i].debugName() : "NULL TYPE"; //$NON-NLS-1$
516 s += "NULL THROWN EXCEPTIONS"; //$NON-NLS-1$