1 /*******************************************************************************
 
   2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
 
   3  * All rights reserved. This program and the accompanying materials 
 
   4  * are made available under the terms of the Common Public License v0.5 
 
   5  * which accompanies this distribution, and is available at
 
   6  * http://www.eclipse.org/legal/cpl-v05.html
 
   9  *     IBM Corporation - initial API and implementation
 
  10  ******************************************************************************/
 
  11 package net.sourceforge.phpdt.internal.compiler.lookup;
 
  13 import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration;
 
  14 import net.sourceforge.phpdt.internal.compiler.ast.ConstructorDeclaration;
 
  16 public class MethodBinding extends Binding implements BaseTypes, TypeConstants {
 
  18         public char[] selector;
 
  19         public TypeBinding returnType;
 
  20         public TypeBinding[] parameters;
 
  21         public ReferenceBinding[] thrownExceptions;
 
  22         public ReferenceBinding declaringClass;
 
  25 protected MethodBinding() {
 
  27 public MethodBinding(int modifiers, char[] selector, TypeBinding returnType, TypeBinding[] args, ReferenceBinding[] exceptions, ReferenceBinding declaringClass) {
 
  28         this.modifiers = modifiers;
 
  29         this.selector = selector;
 
  30         this.returnType = returnType;
 
  31         this.parameters = (args == null || args.length == 0) ? NoParameters : args;
 
  32         this.thrownExceptions = (exceptions == null || exceptions.length == 0) ? NoExceptions : exceptions;
 
  33         this.declaringClass = declaringClass;
 
  35         // propagate the strictfp & deprecated modifiers
 
  36         if (this.declaringClass != null) {
 
  37                 if (this.declaringClass.isStrictfp())
 
  38                         if (!(isNative() || isAbstract()))
 
  39                                 this.modifiers |= AccStrictfp;
 
  40                 if (this.declaringClass.isViewedAsDeprecated() && !isDeprecated())
 
  41                         this.modifiers |= AccDeprecatedImplicitly;
 
  44 public MethodBinding(int modifiers, TypeBinding[] args, ReferenceBinding[] exceptions, ReferenceBinding declaringClass) {
 
  45         this(modifiers, ConstructorDeclaration.ConstantPoolName, VoidBinding, args, exceptions, declaringClass);
 
  47 // special API used to change method declaring class for runtime visibility check
 
  48 public MethodBinding(MethodBinding initialMethodBinding, ReferenceBinding declaringClass) {
 
  49         this.modifiers = initialMethodBinding.modifiers;
 
  50         this.selector = initialMethodBinding.selector;
 
  51         this.returnType = initialMethodBinding.returnType;
 
  52         this.parameters = initialMethodBinding.parameters;
 
  53         this.thrownExceptions = initialMethodBinding.thrownExceptions;
 
  54         this.declaringClass = declaringClass;
 
  56 /* Answer true if the argument types & the receiver's parameters are equal
 
  59 public final boolean areParametersEqual(MethodBinding method) {
 
  60         TypeBinding[] args = method.parameters;
 
  61         if (parameters == args)
 
  64         int length = parameters.length;
 
  65         if (length != args.length)
 
  68         for (int i = 0; i < length; i++)
 
  69                 if (parameters[i] != args[i])
 
  74 * Answer the receiver's binding type from Binding.BindingID.
 
  77 public final int bindingType() {
 
  80 /* Answer true if the receiver is visible to the type provided by the scope.
 
  81 * InvocationSite implements isSuperAccess() to provide additional information
 
  82 * if the receiver is protected.
 
  84 * NOTE: This method should ONLY be sent if the receiver is a constructor.
 
  86 * NOTE: Cannot invoke this method with a compilation unit scope.
 
  89 public final boolean canBeSeenBy(InvocationSite invocationSite, Scope scope) {
 
  90         if (isPublic()) return true;
 
  92         SourceTypeBinding invocationType = scope.enclosingSourceType();
 
  93         if (invocationType == declaringClass) return true;
 
  96                 // answer true if the receiver is in the same package as the invocationType
 
  97                 if (invocationType.fPackage == declaringClass.fPackage) return true;
 
  98                 return invocationSite.isSuperAccess();
 
 102                 // answer true if the invocationType and the declaringClass have a common enclosingType
 
 103                 // already know they are not the identical type
 
 104                 ReferenceBinding outerInvocationType = invocationType;
 
 105                 ReferenceBinding temp = outerInvocationType.enclosingType();
 
 106                 while (temp != null) {
 
 107                         outerInvocationType = temp;
 
 108                         temp = temp.enclosingType();
 
 111                 ReferenceBinding outerDeclaringClass = declaringClass;
 
 112                 temp = outerDeclaringClass.enclosingType();
 
 113                 while (temp != null) {
 
 114                         outerDeclaringClass = temp;
 
 115                         temp = temp.enclosingType();
 
 117                 return outerInvocationType == outerDeclaringClass;
 
 121         return invocationType.fPackage == declaringClass.fPackage;
 
 123 /* Answer true if the receiver is visible to the type provided by the scope.
 
 124 * InvocationSite implements isSuperAccess() to provide additional information
 
 125 * if the receiver is protected.
 
 127 * NOTE: Cannot invoke this method with a compilation unit scope.
 
 129 public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invocationSite, Scope scope) {
 
 130         if (isPublic()) return true;
 
 132         SourceTypeBinding invocationType = scope.enclosingSourceType();
 
 133         if (invocationType == declaringClass && invocationType == receiverType) return true;
 
 136                 // answer true if the invocationType is the declaringClass or they are in the same package
 
 137                 // OR the invocationType is a subclass of the declaringClass
 
 138                 //    AND the receiverType is the invocationType or its subclass
 
 139                 //    OR the method is a static method accessed directly through a type
 
 140                 //    OR previous assertions are true for one of the enclosing type
 
 141                 if (invocationType == declaringClass) return true;
 
 142                 if (invocationType.fPackage == declaringClass.fPackage) return true;
 
 144                 ReferenceBinding currentType = invocationType;
 
 147                         if (declaringClass.isSuperclassOf(currentType)) {
 
 148                                 if (invocationSite.isSuperAccess()){
 
 151                                 // receiverType can be an array binding in one case... see if you can change it
 
 152                                 if (receiverType instanceof ArrayBinding){
 
 156                                         return true; // see 1FMEPDL - return invocationSite.isTypeAccess();
 
 158                                 if (currentType == receiverType || currentType.isSuperclassOf((ReferenceBinding) receiverType)){
 
 159                                         if (depth > 0) invocationSite.setDepth(depth);
 
 164                         currentType = currentType.enclosingType();
 
 165                 } while (currentType != null);
 
 170                 // answer true if the receiverType is the declaringClass
 
 171                 // AND the invocationType and the declaringClass have a common enclosingType
 
 172                 if (receiverType != declaringClass) return false;
 
 174                 if (invocationType != declaringClass) {
 
 175                         ReferenceBinding outerInvocationType = invocationType;
 
 176                         ReferenceBinding temp = outerInvocationType.enclosingType();
 
 177                         while (temp != null) {
 
 178                                 outerInvocationType = temp;
 
 179                                 temp = temp.enclosingType();
 
 182                         ReferenceBinding outerDeclaringClass = declaringClass;
 
 183                         temp = outerDeclaringClass.enclosingType();
 
 184                         while (temp != null) {
 
 185                                 outerDeclaringClass = temp;
 
 186                                 temp = temp.enclosingType();
 
 188                         if (outerInvocationType != outerDeclaringClass) return false;
 
 194         if (invocationType.fPackage != declaringClass.fPackage) return false;
 
 196         // receiverType can be an array binding in one case... see if you can change it
 
 197         if (receiverType instanceof ArrayBinding)
 
 199         ReferenceBinding type = (ReferenceBinding) receiverType;
 
 200         PackageBinding declaringPackage = declaringClass.fPackage;
 
 202                 if (declaringClass == type) return true;
 
 203                 if (declaringPackage != type.fPackage) return false;
 
 204         } while ((type = type.superclass()) != null);
 
 207 /* Answer the receiver's constant pool name.
 
 209 * <init> for constructors
 
 210 * <clinit> for clinit methods
 
 211 * or the source name of the method
 
 214 public final char[] constantPoolName() {
 
 217 public final int getAccessFlags() {
 
 218         return modifiers & AccJustFlag;
 
 220 /* Answer true if the receiver is an abstract method
 
 223 public final boolean isAbstract() {
 
 224         return (modifiers & AccAbstract) != 0;
 
 226 /* Answer true if the receiver is a constructor
 
 229 public final boolean isConstructor() {
 
 230         return selector == ConstructorDeclaration.ConstantPoolName;
 
 232 protected boolean isConstructorRelated() {
 
 233         return isConstructor();
 
 235 /* Answer true if the receiver has default visibility
 
 238 public final boolean isDefault() {
 
 239         return !isPublic() && !isProtected() && !isPrivate();
 
 241 /* Answer true if the receiver is a system generated default abstract method
 
 244 public final boolean isDefaultAbstract() {
 
 245         return (modifiers & AccDefaultAbstract) != 0;
 
 247 /* Answer true if the receiver is a deprecated method
 
 250 public final boolean isDeprecated() {
 
 251         return (modifiers & AccDeprecated) != 0;
 
 253 /* Answer true if the receiver is final and cannot be overridden
 
 256 public final boolean isFinal() {
 
 257         return (modifiers & AccFinal) != 0;
 
 259 /* Answer true if the receiver is a native method
 
 262 public final boolean isNative() {
 
 263         return (modifiers & AccNative) != 0;
 
 265 /* Answer true if the receiver has private visibility
 
 268 public final boolean isPrivate() {
 
 269         return (modifiers & AccPrivate) != 0;
 
 271 /* Answer true if the receiver has protected visibility
 
 274 public final boolean isProtected() {
 
 275         return (modifiers & AccProtected) != 0;
 
 277 /* Answer true if the receiver has public visibility
 
 280 public final boolean isPublic() {
 
 281         return (modifiers & AccPublic) != 0;
 
 283 /* Answer true if the receiver got requested to clear the private modifier
 
 284  * during private access emulation.
 
 287 public final boolean isRequiredToClearPrivateModifier() {
 
 288         return (modifiers & AccClearPrivateModifier) != 0;
 
 290 /* Answer true if the receiver is a static method
 
 293 public final boolean isStatic() {
 
 294         return (modifiers & AccStatic) != 0;
 
 296 /* Answer true if all float operations must adher to IEEE 754 float/double rules
 
 299 public final boolean isStrictfp() {
 
 300         return (modifiers & AccStrictfp) != 0;
 
 302 /* Answer true if the receiver is a synchronized method
 
 305 public final boolean isSynchronized() {
 
 306         return (modifiers & AccSynchronized) != 0;
 
 308 /* Answer true if the receiver has public visibility
 
 311 public final boolean isSynthetic() {
 
 312         return (modifiers & AccSynthetic) != 0;
 
 314 /* Answer true if the receiver's declaring type is deprecated (or any of its enclosing types)
 
 317 public final boolean isViewedAsDeprecated() {
 
 318         return (modifiers & AccDeprecated) != 0 ||
 
 319                 (modifiers & AccDeprecatedImplicitly) != 0;
 
 321 public char[] readableName() /* foo(int, Thread) */ {
 
 322         StringBuffer buffer = new StringBuffer(parameters.length + 1 * 20);
 
 324                 buffer.append(declaringClass.sourceName());
 
 326                 buffer.append(selector);
 
 328         if (parameters != NoParameters) {
 
 329                 for (int i = 0, length = parameters.length; i < length; i++) {
 
 331                                 buffer.append(", "); //$NON-NLS-1$
 
 332                         buffer.append(parameters[i].sourceName());
 
 336         return buffer.toString().toCharArray();
 
 338 protected final void selector(char[] selector) {
 
 339         this.selector = selector;
 
 340         this.signature = null;
 
 342 /* Answer the receiver's signature.
 
 344 * NOTE: This method should only be used during/after code gen.
 
 345 * The signature is cached so if the signature of the return type or any parameter
 
 346 * type changes, the cached state is invalid.
 
 349 public final char[] signature() /* (ILjava/lang/Thread;)Ljava/lang/Object; */ {
 
 350         if (signature != null)
 
 353         StringBuffer buffer = new StringBuffer(parameters.length + 1 * 20);
 
 355         if (isConstructorRelated() && declaringClass.isNestedType()) {
 
 356                 // take into account the synthetic argument type signatures as well
 
 357                 ReferenceBinding[] syntheticArgumentTypes = declaringClass.syntheticEnclosingInstanceTypes();
 
 358                 int count = syntheticArgumentTypes == null ? 0 : syntheticArgumentTypes.length;
 
 359                 for (int i = 0; i < count; i++)
 
 360                         buffer.append(syntheticArgumentTypes[i].signature());
 
 361                 SyntheticArgumentBinding[] syntheticArguments = declaringClass.syntheticOuterLocalVariables();
 
 362                 count = syntheticArguments == null ? 0 : syntheticArguments.length;
 
 363                 for (int i = 0; i < count; i++)
 
 364                         buffer.append(syntheticArguments[i].type.signature());
 
 366         if (parameters != NoParameters)
 
 367                 for (int i = 0, length = parameters.length; i < length; i++)
 
 368                         buffer.append(parameters[i].signature());
 
 370         buffer.append(returnType.signature());
 
 371         return signature = buffer.toString().toCharArray();
 
 373 public final int sourceEnd() {
 
 374         AbstractMethodDeclaration method = sourceMethod();
 
 378                 return method.sourceEnd;
 
 380 AbstractMethodDeclaration sourceMethod() {
 
 381         SourceTypeBinding sourceType;
 
 383                 sourceType = (SourceTypeBinding) declaringClass;
 
 384         } catch (ClassCastException e) {
 
 388         AbstractMethodDeclaration[] methods = sourceType.scope.referenceContext.methods;
 
 389         for (int i = methods.length; --i >= 0;)
 
 390                 if (this == methods[i].binding)
 
 394 public final int sourceStart() {
 
 395         AbstractMethodDeclaration method = sourceMethod();
 
 399                 return method.sourceStart;
 
 401 /* During private access emulation, the binding can be requested to loose its
 
 402  * private visibility when the class file is dumped.
 
 405 public final void tagForClearingPrivateModifier() {
 
 406         modifiers |= AccClearPrivateModifier;
 
 408 public String toString() {
 
 409         String s = (returnType != null) ? returnType.debugName() : "NULL TYPE"; //$NON-NLS-1$
 
 410         s += " "; //$NON-NLS-1$
 
 411         s += (selector != null) ? new String(selector) : "UNNAMED METHOD"; //$NON-NLS-1$
 
 413         s += "("; //$NON-NLS-1$
 
 414         if (parameters != null) {
 
 415                 if (parameters != NoParameters) {
 
 416                         for (int i = 0, length = parameters.length; i < length; i++) {
 
 418                                         s += ", "; //$NON-NLS-1$
 
 419                                 s += (parameters[i] != null) ? parameters[i].debugName() : "NULL TYPE"; //$NON-NLS-1$
 
 423                 s += "NULL PARAMETERS"; //$NON-NLS-1$
 
 425         s += ") "; //$NON-NLS-1$
 
 427         if (thrownExceptions != null) {
 
 428                 if (thrownExceptions != NoExceptions) {
 
 429                         s += "throws "; //$NON-NLS-1$
 
 430                         for (int i = 0, length = thrownExceptions.length; i < length; i++) {
 
 432                                         s += ", "; //$NON-NLS-1$
 
 433                                 s += (thrownExceptions[i] != null) ? thrownExceptions[i].debugName() : "NULL TYPE"; //$NON-NLS-1$
 
 437                 s += "NULL THROWN EXCEPTIONS"; //$NON-NLS-1$