1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 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 org.eclipse.jdt.internal.compiler.lookup;
13 import org.eclipse.jdt.core.compiler.CharOperation;
14 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
15 import org.eclipse.jdt.internal.compiler.codegen.ConstantPool;
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;
24 public TypeVariableBinding[] typeVariables = NoTypeVariables;
29 protected MethodBinding() {
30 // for creating problem or synthetic method
32 public MethodBinding(int modifiers, char[] selector, TypeBinding returnType, TypeBinding[] parameters, ReferenceBinding[] thrownExceptions, ReferenceBinding declaringClass) {
33 this.modifiers = modifiers;
34 this.selector = selector;
35 this.returnType = returnType;
36 this.parameters = (parameters == null || parameters.length == 0) ? NoParameters : parameters;
37 this.thrownExceptions = (thrownExceptions == null || thrownExceptions.length == 0) ? NoExceptions : thrownExceptions;
38 this.declaringClass = declaringClass;
40 // propagate the strictfp & deprecated modifiers
41 if (this.declaringClass != null) {
42 if (this.declaringClass.isStrictfp())
43 if (!(isNative() || isAbstract()))
44 this.modifiers |= AccStrictfp;
45 if (this.declaringClass.isViewedAsDeprecated() && !isDeprecated())
46 this.modifiers |= AccDeprecatedImplicitly;
49 public MethodBinding(int modifiers, TypeBinding[] parameters, ReferenceBinding[] thrownExceptions, ReferenceBinding declaringClass) {
50 this(modifiers, TypeConstants.INIT, VoidBinding, parameters, thrownExceptions, declaringClass);
52 // special API used to change method declaring class for runtime visibility check
53 public MethodBinding(MethodBinding initialMethodBinding, ReferenceBinding declaringClass) {
54 this.modifiers = initialMethodBinding.modifiers;
55 this.selector = initialMethodBinding.selector;
56 this.returnType = initialMethodBinding.returnType;
57 this.parameters = initialMethodBinding.parameters;
58 this.thrownExceptions = initialMethodBinding.thrownExceptions;
59 this.declaringClass = declaringClass;
61 /* Answer true if the argument types & the receiver's parameters are equal
63 public final boolean areParametersEqual(MethodBinding method) {
64 TypeBinding[] args = method.parameters;
65 if (parameters == args)
68 int length = parameters.length;
69 if (length != args.length)
72 for (int i = 0; i < length; i++)
73 if (parameters[i] != args[i])
77 public final boolean areParametersCompatibleWith(TypeBinding[] arguments) {
78 int paramLength = this.parameters.length;
79 int argLength = arguments.length;
80 int lastIndex = argLength;
82 lastIndex = paramLength - 1;
83 if (paramLength == argLength) { // accept X[] but not X or X[][]
84 TypeBinding varArgType = parameters[lastIndex]; // is an ArrayBinding by definition
85 TypeBinding lastArgument = arguments[lastIndex];
86 if (varArgType != lastArgument && !lastArgument.isCompatibleWith(varArgType))
88 } else if (paramLength < argLength) { // all remainig argument types must be compatible with the elementsType of varArgType
89 TypeBinding varArgType = ((ArrayBinding) parameters[lastIndex]).elementsType();
90 for (int i = lastIndex; i < argLength; i++)
91 if (varArgType != arguments[i] && !arguments[i].isCompatibleWith(varArgType))
93 } else if (lastIndex != argLength) { // can call foo(int i, X ... x) with foo(1) but NOT foo();
96 // now compare standard arguments from 0 to lastIndex
98 for (int i = 0; i < lastIndex; i++)
99 if (parameters[i] != arguments[i] && !arguments[i].isCompatibleWith(parameters[i]))
104 /* Answer true if the argument types & the receiver's parameters have the same erasure
106 public final boolean areParameterErasuresEqual(MethodBinding method) {
107 TypeBinding[] args = method.parameters;
108 if (parameters == args)
111 int length = parameters.length;
112 if (length != args.length)
115 for (int i = 0; i < length; i++)
116 if (parameters[i] != args[i] && parameters[i].erasure() != args[i].erasure())
121 * Answer the receiver's binding type from Binding.BindingID.
124 public final int kind() {
125 return Binding.METHOD;
127 /* Answer true if the receiver is visible to the invocationPackage.
130 public final boolean canBeSeenBy(PackageBinding invocationPackage) {
131 if (isPublic()) return true;
132 if (isPrivate()) return false;
134 // isProtected() or isDefault()
135 return invocationPackage == declaringClass.getPackage();
137 /* Answer true if the receiver is visible to the type provided by the scope.
138 * InvocationSite implements isSuperAccess() to provide additional information
139 * if the receiver is protected.
141 * NOTE: This method should ONLY be sent if the receiver is a constructor.
143 * NOTE: Cannot invoke this method with a compilation unit scope.
146 public final boolean canBeSeenBy(InvocationSite invocationSite, Scope scope) {
147 if (isPublic()) return true;
149 SourceTypeBinding invocationType = scope.enclosingSourceType();
150 if (invocationType == declaringClass) return true;
153 // answer true if the receiver is in the same package as the invocationType
154 if (invocationType.fPackage == declaringClass.fPackage) return true;
155 return invocationSite.isSuperAccess();
159 // answer true if the invocationType and the declaringClass have a common enclosingType
160 // already know they are not the identical type
161 ReferenceBinding outerInvocationType = invocationType;
162 ReferenceBinding temp = outerInvocationType.enclosingType();
163 while (temp != null) {
164 outerInvocationType = temp;
165 temp = temp.enclosingType();
168 ReferenceBinding outerDeclaringClass = (ReferenceBinding)declaringClass.erasure();
169 temp = outerDeclaringClass.enclosingType();
170 while (temp != null) {
171 outerDeclaringClass = temp;
172 temp = temp.enclosingType();
174 return outerInvocationType == outerDeclaringClass;
178 return invocationType.fPackage == declaringClass.fPackage;
180 /* Answer true if the receiver is visible to the type provided by the scope.
181 * InvocationSite implements isSuperAccess() to provide additional information
182 * if the receiver is protected.
184 * NOTE: Cannot invoke this method with a compilation unit scope.
186 public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invocationSite, Scope scope) {
187 if (isPublic()) return true;
189 SourceTypeBinding invocationType = scope.enclosingSourceType();
190 if (invocationType == declaringClass && invocationType == receiverType) return true;
193 // answer true if the invocationType is the declaringClass or they are in the same package
194 // OR the invocationType is a subclass of the declaringClass
195 // AND the receiverType is the invocationType or its subclass
196 // OR the method is a static method accessed directly through a type
197 // OR previous assertions are true for one of the enclosing type
198 if (invocationType == declaringClass) return true;
199 if (invocationType.fPackage == declaringClass.fPackage) return true;
201 ReferenceBinding currentType = invocationType;
204 if (declaringClass.isSuperclassOf(currentType)) {
205 if (invocationSite.isSuperAccess()){
208 // receiverType can be an array binding in one case... see if you can change it
209 if (receiverType instanceof ArrayBinding){
213 if (depth > 0) invocationSite.setDepth(depth);
214 return true; // see 1FMEPDL - return invocationSite.isTypeAccess();
216 if (currentType == receiverType || currentType.isSuperclassOf((ReferenceBinding) receiverType)){
217 if (depth > 0) invocationSite.setDepth(depth);
222 currentType = currentType.enclosingType();
223 } while (currentType != null);
228 // answer true if the receiverType is the declaringClass
229 // AND the invocationType and the declaringClass have a common enclosingType
231 if (receiverType != declaringClass) {
232 // special tolerance for type variable direct bounds
233 if (receiverType.isTypeVariable() && ((TypeVariableBinding) receiverType).isErasureBoundTo(declaringClass.erasure())) {
240 if (invocationType != declaringClass) {
241 ReferenceBinding outerInvocationType = invocationType;
242 ReferenceBinding temp = outerInvocationType.enclosingType();
243 while (temp != null) {
244 outerInvocationType = temp;
245 temp = temp.enclosingType();
248 ReferenceBinding outerDeclaringClass = (ReferenceBinding)declaringClass.erasure();
249 temp = outerDeclaringClass.enclosingType();
250 while (temp != null) {
251 outerDeclaringClass = temp;
252 temp = temp.enclosingType();
254 if (outerInvocationType != outerDeclaringClass) return false;
260 if (invocationType.fPackage != declaringClass.fPackage) return false;
262 // receiverType can be an array binding in one case... see if you can change it
263 if (receiverType instanceof ArrayBinding)
265 ReferenceBinding type = (ReferenceBinding) receiverType;
266 PackageBinding declaringPackage = declaringClass.fPackage;
268 if (declaringClass == type) return true;
269 if (declaringPackage != type.fPackage) return false;
270 } while ((type = type.superclass()) != null);
274 * declaringUniqueKey dot selector genericSignature
275 * p.X { <T> void bar(X<T> t) } --> Lp/X;.bar<T:Ljava/lang/Object;>(LX<TT;>;)V
277 public char[] computeUniqueKey() {
278 return computeUniqueKey(this);
280 protected char[] computeUniqueKey(MethodBinding methodBinding) {
282 char[] declaringKey = this.declaringClass.computeUniqueKey();
283 int declaringLength = declaringKey.length;
286 int selectorLength = this.selector == TypeConstants.INIT ? 0 : this.selector.length;
289 char[] sig = methodBinding.genericSignature();
290 if (sig == null) sig = methodBinding.signature();
291 int signatureLength = sig.length;
293 // compute unique key
294 char[] uniqueKey = new char[declaringLength + 1 + selectorLength + signatureLength];
295 System.arraycopy(declaringKey, 0, uniqueKey, 0, declaringLength);
296 uniqueKey[declaringLength] = '.';
297 System.arraycopy(this.selector, 0, uniqueKey, declaringLength+1, selectorLength);
298 System.arraycopy(sig, 0, uniqueKey, declaringLength + 1 + selectorLength, signatureLength);
302 * Answer the declaring class to use in the constant pool
303 * may not be a reference binding (see subtypes)
305 public TypeBinding constantPoolDeclaringClass() {
306 return this.declaringClass;
308 /* Answer the receiver's constant pool name.
310 * <init> for constructors
311 * <clinit> for clinit methods
312 * or the source name of the method
314 public final char[] constantPoolName() {
318 *<typeParam1 ... typeParamM>(param1 ... paramN)returnType thrownException1 ... thrownExceptionP
319 * T foo(T t) throws X<T> ---> (TT;)TT;LX<TT;>;
320 * void bar(X<T> t) --> (LX<TT;>;)V
321 * <T> void bar(X<T> t) --> <T:Ljava.lang.Object;>(LX<TT;>;)V
323 public char[] genericSignature() {
324 if ((this.modifiers & AccGenericSignature) == 0) return null;
325 StringBuffer sig = new StringBuffer(10);
326 if (this.typeVariables != NoTypeVariables) {
328 for (int i = 0, length = this.typeVariables.length; i < length; i++) {
329 sig.append(this.typeVariables[i].genericSignature());
334 for (int i = 0, length = this.parameters.length; i < length; i++) {
335 sig.append(this.parameters[i].genericTypeSignature());
338 if (this.returnType != null)
339 sig.append(this.returnType.genericTypeSignature());
341 // only append thrown exceptions if any is generic/parameterized
342 boolean needExceptionSignatures = false;
343 int length = this.thrownExceptions.length;
344 for (int i = 0; i < length; i++) {
345 if((this.thrownExceptions[i].modifiers & AccGenericSignature) != 0) {
346 needExceptionSignatures = true;
350 if (needExceptionSignatures) {
351 for (int i = 0; i < length; i++) {
352 sig.append(this.thrownExceptions[i].genericTypeSignature());
355 int sigLength = sig.length();
356 char[] genericSignature = new char[sigLength];
357 sig.getChars(0, sigLength, genericSignature, 0);
358 return genericSignature;
360 public final int getAccessFlags() {
361 return modifiers & AccJustFlag;
363 public TypeVariableBinding getTypeVariable(char[] variableName) {
364 for (int i = this.typeVariables.length; --i >= 0;)
365 if (CharOperation.equals(this.typeVariables[i].sourceName, variableName))
366 return this.typeVariables[i];
370 * Returns true if method got substituted parameter types
371 * (see ParameterizedMethodBinding)
373 public boolean hasSubstitutedParameters() {
377 /* Answer true if the return type got substituted.
379 public boolean hasSubstitutedReturnType() {
383 /* Answer true if the receiver is an abstract method
385 public final boolean isAbstract() {
386 return (modifiers & AccAbstract) != 0;
389 /* Answer true if the receiver is a bridge method
391 public final boolean isBridge() {
392 return (modifiers & AccBridge) != 0;
395 /* Answer true if the receiver is a constructor
397 public final boolean isConstructor() {
398 return selector == TypeConstants.INIT;
401 /* Answer true if the receiver has default visibility
403 public final boolean isDefault() {
404 return !isPublic() && !isProtected() && !isPrivate();
407 /* Answer true if the receiver is a system generated default abstract method
409 public final boolean isDefaultAbstract() {
410 return (modifiers & AccDefaultAbstract) != 0;
413 /* Answer true if the receiver is a deprecated method
415 public final boolean isDeprecated() {
416 return (modifiers & AccDeprecated) != 0;
419 /* Answer true if the receiver is final and cannot be overridden
421 public final boolean isFinal() {
422 return (modifiers & AccFinal) != 0;
425 /* Answer true if the receiver is implementing another method
426 * in other words, it is overriding and concrete, and overriden method is abstract
427 * Only set for source methods
429 public final boolean isImplementing() {
430 return (modifiers & AccImplementing) != 0;
433 /* Answer true if the receiver is a native method
435 public final boolean isNative() {
436 return (modifiers & AccNative) != 0;
439 /* Answer true if the receiver is overriding another method
440 * Only set for source methods
442 public final boolean isOverriding() {
443 return (modifiers & AccOverriding) != 0;
446 * Answer true if the receiver is a "public static void main(String[])" method
448 public final boolean isMain() {
449 if (this.selector.length == 4 && CharOperation.equals(this.selector, MAIN)
450 && ((this.modifiers & (AccPublic | AccStatic)) != 0)
451 && VoidBinding == this.returnType
452 && this.parameters.length == 1) {
453 TypeBinding paramType = this.parameters[0];
454 if (paramType.dimensions() == 1 && paramType.leafComponentType().id == TypeIds.T_JavaLangString) {
460 /* Answer true if the receiver has private visibility
462 public final boolean isPrivate() {
463 return (modifiers & AccPrivate) != 0;
466 /* Answer true if the receiver has private visibility and is used locally
468 public final boolean isPrivateUsed() {
469 return (modifiers & AccPrivateUsed) != 0;
472 /* Answer true if the receiver has protected visibility
474 public final boolean isProtected() {
475 return (modifiers & AccProtected) != 0;
478 /* Answer true if the receiver has public visibility
480 public final boolean isPublic() {
481 return (modifiers & AccPublic) != 0;
484 /* Answer true if the receiver got requested to clear the private modifier
485 * during private access emulation.
487 public final boolean isRequiredToClearPrivateModifier() {
488 return (modifiers & AccClearPrivateModifier) != 0;
491 /* Answer true if the receiver is a static method
493 public final boolean isStatic() {
494 return (modifiers & AccStatic) != 0;
497 /* Answer true if all float operations must adher to IEEE 754 float/double rules
499 public final boolean isStrictfp() {
500 return (modifiers & AccStrictfp) != 0;
503 /* Answer true if the receiver is a synchronized method
505 public final boolean isSynchronized() {
506 return (modifiers & AccSynchronized) != 0;
509 /* Answer true if the receiver has public visibility
511 public final boolean isSynthetic() {
512 return (modifiers & AccSynthetic) != 0;
515 /* Answer true if the receiver method has varargs
517 public final boolean isVarargs() {
518 return (modifiers & AccVarargs) != 0;
521 /* Answer true if the receiver's declaring type is deprecated (or any of its enclosing types)
523 public final boolean isViewedAsDeprecated() {
524 return (modifiers & AccDeprecated) != 0 ||
525 (modifiers & AccDeprecatedImplicitly) != 0;
529 * Returns the original method (as opposed to parameterized instances)
531 public MethodBinding original() {
535 public char[] readableName() /* foo(int, Thread) */ {
536 StringBuffer buffer = new StringBuffer(parameters.length + 1 * 20);
538 buffer.append(declaringClass.sourceName());
540 buffer.append(selector);
542 if (parameters != NoParameters) {
543 for (int i = 0, length = parameters.length; i < length; i++) {
545 buffer.append(", "); //$NON-NLS-1$
546 buffer.append(parameters[i].sourceName());
550 return buffer.toString().toCharArray();
554 * @see org.eclipse.jdt.internal.compiler.lookup.Binding#shortReadableName()
556 public char[] shortReadableName() {
557 StringBuffer buffer = new StringBuffer(parameters.length + 1 * 20);
559 buffer.append(declaringClass.shortReadableName());
561 buffer.append(selector);
563 if (parameters != NoParameters) {
564 for (int i = 0, length = parameters.length; i < length; i++) {
566 buffer.append(", "); //$NON-NLS-1$
567 buffer.append(parameters[i].shortReadableName());
571 int nameLength = buffer.length();
572 char[] shortReadableName = new char[nameLength];
573 buffer.getChars(0, nameLength, shortReadableName, 0);
574 return shortReadableName;
577 protected final void setSelector(char[] selector) {
578 this.selector = selector;
579 this.signature = null;
582 /* Answer the receiver's signature.
584 * NOTE: This method should only be used during/after code gen.
585 * The signature is cached so if the signature of the return type or any parameter
586 * type changes, the cached state is invalid.
588 public final char[] signature() /* (ILjava/lang/Thread;)Ljava/lang/Object; */ {
589 if (signature != null)
592 StringBuffer buffer = new StringBuffer(parameters.length + 1 * 20);
595 TypeBinding[] targetParameters = this.parameters;
596 boolean isConstructor = isConstructor();
597 if (isConstructor && declaringClass.isEnum()) { // insert String name,int ordinal
598 buffer.append(ConstantPool.JavaLangStringSignature);
599 buffer.append(BaseTypes.IntBinding.signature());
601 boolean needSynthetics = isConstructor && declaringClass.isNestedType();
602 if (needSynthetics) {
603 // take into account the synthetic argument type signatures as well
604 ReferenceBinding[] syntheticArgumentTypes = declaringClass.syntheticEnclosingInstanceTypes();
605 int count = syntheticArgumentTypes == null ? 0 : syntheticArgumentTypes.length;
606 for (int i = 0; i < count; i++) {
607 buffer.append(syntheticArgumentTypes[i].signature());
610 if (this instanceof SyntheticMethodBinding) {
611 targetParameters = ((SyntheticMethodBinding)this).targetMethod.parameters;
615 if (targetParameters != NoParameters) {
616 for (int i = 0; i < targetParameters.length; i++) {
617 buffer.append(targetParameters[i].signature());
620 if (needSynthetics) {
621 SyntheticArgumentBinding[] syntheticOuterArguments = declaringClass.syntheticOuterLocalVariables();
622 int count = syntheticOuterArguments == null ? 0 : syntheticOuterArguments.length;
623 for (int i = 0; i < count; i++) {
624 buffer.append(syntheticOuterArguments[i].type.signature());
626 // move the extra padding arguments of the synthetic constructor invocation to the end
627 for (int i = targetParameters.length, extraLength = parameters.length; i < extraLength; i++) {
628 buffer.append(parameters[i].signature());
632 if (this.returnType != null)
633 buffer.append(this.returnType.signature());
634 int nameLength = buffer.length();
635 signature = new char[nameLength];
636 buffer.getChars(0, nameLength, signature, 0);
640 public final int sourceEnd() {
641 AbstractMethodDeclaration method = sourceMethod();
644 return method.sourceEnd;
646 public AbstractMethodDeclaration sourceMethod() {
647 SourceTypeBinding sourceType;
649 sourceType = (SourceTypeBinding) declaringClass;
650 } catch (ClassCastException e) {
654 AbstractMethodDeclaration[] methods = sourceType.scope.referenceContext.methods;
655 for (int i = methods.length; --i >= 0;)
656 if (this == methods[i].binding)
660 public final int sourceStart() {
661 AbstractMethodDeclaration method = sourceMethod();
664 return method.sourceStart;
667 /* During private access emulation, the binding can be requested to loose its
668 * private visibility when the class file is dumped.
671 public final void tagForClearingPrivateModifier() {
672 modifiers |= AccClearPrivateModifier;
674 public String toString() {
675 String s = (returnType != null) ? returnType.debugName() : "NULL TYPE"; //$NON-NLS-1$
676 s += " "; //$NON-NLS-1$
677 s += (selector != null) ? new String(selector) : "UNNAMED METHOD"; //$NON-NLS-1$
679 s += "("; //$NON-NLS-1$
680 if (parameters != null) {
681 if (parameters != NoParameters) {
682 for (int i = 0, length = parameters.length; i < length; i++) {
684 s += ", "; //$NON-NLS-1$
685 s += (parameters[i] != null) ? parameters[i].debugName() : "NULL TYPE"; //$NON-NLS-1$
689 s += "NULL PARAMETERS"; //$NON-NLS-1$
691 s += ") "; //$NON-NLS-1$
693 if (thrownExceptions != null) {
694 if (thrownExceptions != NoExceptions) {
695 s += "throws "; //$NON-NLS-1$
696 for (int i = 0, length = thrownExceptions.length; i < length; i++) {
698 s += ", "; //$NON-NLS-1$
699 s += (thrownExceptions[i] != null) ? thrownExceptions[i].debugName() : "NULL TYPE"; //$NON-NLS-1$
703 s += "NULL THROWN EXCEPTIONS"; //$NON-NLS-1$
708 * Returns the method to use during tiebreak (usually the method itself).
709 * For generic method invocations, tiebreak needs to use generic method with erasure substitutes.
711 public MethodBinding tiebreakMethod() {
714 public TypeVariableBinding[] typeVariables() {
715 return this.typeVariables;