added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / lookup / MethodBinding.java
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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.lookup;
12
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;
16
17 public class MethodBinding extends Binding implements BaseTypes, TypeConstants {
18         public int modifiers;
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;
25
26         char[] signature;
27         public long tagBits;
28         
29 protected MethodBinding() {
30         // for creating problem or synthetic method
31 }
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;
39         
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;
47         }
48 }
49 public MethodBinding(int modifiers, TypeBinding[] parameters, ReferenceBinding[] thrownExceptions, ReferenceBinding declaringClass) {
50         this(modifiers, TypeConstants.INIT, VoidBinding, parameters, thrownExceptions, declaringClass);
51 }
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;
60 }
61 /* Answer true if the argument types & the receiver's parameters are equal
62 */
63 public final boolean areParametersEqual(MethodBinding method) {
64         TypeBinding[] args = method.parameters;
65         if (parameters == args)
66                 return true;
67
68         int length = parameters.length;
69         if (length != args.length)
70                 return false;
71         
72         for (int i = 0; i < length; i++)
73                 if (parameters[i] != args[i])
74                         return false;
75         return true;
76 }
77 public final boolean areParametersCompatibleWith(TypeBinding[] arguments) {
78         int paramLength = this.parameters.length;
79         int argLength = arguments.length;
80         int lastIndex = argLength;
81         if (isVarargs()) {
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))
87                                 return false;
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))
92                                         return false;
93                 } else if (lastIndex != argLength) { // can call foo(int i, X ... x) with foo(1) but NOT foo();
94                         return false;
95                 }
96                 // now compare standard arguments from 0 to lastIndex
97         }
98         for (int i = 0; i < lastIndex; i++)
99                 if (parameters[i] != arguments[i] && !arguments[i].isCompatibleWith(parameters[i]))
100                         return false;
101         return true;
102 }
103
104 /* Answer true if the argument types & the receiver's parameters have the same erasure
105 */
106 public final boolean areParameterErasuresEqual(MethodBinding method) {
107         TypeBinding[] args = method.parameters;
108         if (parameters == args)
109                 return true;
110
111         int length = parameters.length;
112         if (length != args.length)
113                 return false;
114
115         for (int i = 0; i < length; i++)
116                 if (parameters[i] != args[i] && parameters[i].erasure() != args[i].erasure())
117                         return false;
118         return true;
119 }
120 /* API
121 * Answer the receiver's binding type from Binding.BindingID.
122 */
123
124 public final int kind() {
125         return Binding.METHOD;
126 }
127 /* Answer true if the receiver is visible to the invocationPackage.
128 */
129
130 public final boolean canBeSeenBy(PackageBinding invocationPackage) {
131         if (isPublic()) return true;
132         if (isPrivate()) return false;
133
134         // isProtected() or isDefault()
135         return invocationPackage == declaringClass.getPackage();
136 }
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.
140 *
141 * NOTE: This method should ONLY be sent if the receiver is a constructor.
142 *
143 * NOTE: Cannot invoke this method with a compilation unit scope.
144 */
145
146 public final boolean canBeSeenBy(InvocationSite invocationSite, Scope scope) {
147         if (isPublic()) return true;
148
149         SourceTypeBinding invocationType = scope.enclosingSourceType();
150         if (invocationType == declaringClass) return true;
151
152         if (isProtected()) {
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();
156         }
157
158         if (isPrivate()) {
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();
166                 }
167
168                 ReferenceBinding outerDeclaringClass = (ReferenceBinding)declaringClass.erasure();
169                 temp = outerDeclaringClass.enclosingType();
170                 while (temp != null) {
171                         outerDeclaringClass = temp;
172                         temp = temp.enclosingType();
173                 }
174                 return outerInvocationType == outerDeclaringClass;
175         }
176
177         // isDefault()
178         return invocationType.fPackage == declaringClass.fPackage;
179 }
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.
183 *
184 * NOTE: Cannot invoke this method with a compilation unit scope.
185 */
186 public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invocationSite, Scope scope) {
187         if (isPublic()) return true;
188
189         SourceTypeBinding invocationType = scope.enclosingSourceType();
190         if (invocationType == declaringClass && invocationType == receiverType) return true;
191
192         if (isProtected()) {
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;
200                 
201                 ReferenceBinding currentType = invocationType;
202                 int depth = 0;
203                 do {
204                         if (declaringClass.isSuperclassOf(currentType)) {
205                                 if (invocationSite.isSuperAccess()){
206                                         return true;
207                                 }
208                                 // receiverType can be an array binding in one case... see if you can change it
209                                 if (receiverType instanceof ArrayBinding){
210                                         return false;
211                                 }
212                                 if (isStatic()){
213                                         if (depth > 0) invocationSite.setDepth(depth);
214                                         return true; // see 1FMEPDL - return invocationSite.isTypeAccess();
215                                 }
216                                 if (currentType == receiverType || currentType.isSuperclassOf((ReferenceBinding) receiverType)){
217                                         if (depth > 0) invocationSite.setDepth(depth);
218                                         return true;
219                                 }
220                         }
221                         depth++;
222                         currentType = currentType.enclosingType();
223                 } while (currentType != null);
224                 return false;
225         }
226
227         if (isPrivate()) {
228                 // answer true if the receiverType is the declaringClass
229                 // AND the invocationType and the declaringClass have a common enclosingType
230                 receiverCheck: {
231                         if (receiverType != declaringClass) {
232                                 // special tolerance for type variable direct bounds
233                                 if (receiverType.isTypeVariable() && ((TypeVariableBinding) receiverType).isErasureBoundTo(declaringClass.erasure())) {
234                                         break receiverCheck;
235                                 }
236                                 return false;
237                         }
238                 }
239
240                 if (invocationType != declaringClass) {
241                         ReferenceBinding outerInvocationType = invocationType;
242                         ReferenceBinding temp = outerInvocationType.enclosingType();
243                         while (temp != null) {
244                                 outerInvocationType = temp;
245                                 temp = temp.enclosingType();
246                         }
247
248                         ReferenceBinding outerDeclaringClass = (ReferenceBinding)declaringClass.erasure();
249                         temp = outerDeclaringClass.enclosingType();
250                         while (temp != null) {
251                                 outerDeclaringClass = temp;
252                                 temp = temp.enclosingType();
253                         }
254                         if (outerInvocationType != outerDeclaringClass) return false;
255                 }
256                 return true;
257         }
258
259         // isDefault()
260         if (invocationType.fPackage != declaringClass.fPackage) return false;
261
262         // receiverType can be an array binding in one case... see if you can change it
263         if (receiverType instanceof ArrayBinding)
264                 return false;
265         ReferenceBinding type = (ReferenceBinding) receiverType;
266         PackageBinding declaringPackage = declaringClass.fPackage;
267         do {
268                 if (declaringClass == type) return true;
269                 if (declaringPackage != type.fPackage) return false;
270         } while ((type = type.superclass()) != null);
271         return false;
272 }
273 /*
274  * declaringUniqueKey dot selector genericSignature
275  * p.X { <T> void bar(X<T> t) } --> Lp/X;.bar<T:Ljava/lang/Object;>(LX<TT;>;)V
276  */
277 public char[] computeUniqueKey() {
278         return computeUniqueKey(this);
279 }
280 protected char[] computeUniqueKey(MethodBinding methodBinding) {
281         // declaring class 
282         char[] declaringKey = this.declaringClass.computeUniqueKey();
283         int declaringLength = declaringKey.length;
284         
285         // selector
286         int selectorLength = this.selector == TypeConstants.INIT ? 0 : this.selector.length;
287         
288         // generic signature
289         char[] sig = methodBinding.genericSignature();
290         if (sig == null) sig = methodBinding.signature();
291         int signatureLength = sig.length;
292         
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);
299         return uniqueKey;
300 }
301 /* 
302  * Answer the declaring class to use in the constant pool
303  * may not be a reference binding (see subtypes)
304  */
305 public TypeBinding constantPoolDeclaringClass() {
306         return this.declaringClass;
307 }
308 /* Answer the receiver's constant pool name.
309 *
310 * <init> for constructors
311 * <clinit> for clinit methods
312 * or the source name of the method
313 */
314 public final char[] constantPoolName() {
315         return selector;
316 }
317 /**
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
322  */
323 public char[] genericSignature() {
324         if ((this.modifiers & AccGenericSignature) == 0) return null;
325         StringBuffer sig = new StringBuffer(10);
326         if (this.typeVariables != NoTypeVariables) {
327                 sig.append('<');
328                 for (int i = 0, length = this.typeVariables.length; i < length; i++) {
329                         sig.append(this.typeVariables[i].genericSignature());
330                 }
331                 sig.append('>');
332         }
333         sig.append('(');
334         for (int i = 0, length = this.parameters.length; i < length; i++) {
335                 sig.append(this.parameters[i].genericTypeSignature());
336         }
337         sig.append(')');
338         if (this.returnType != null)
339                 sig.append(this.returnType.genericTypeSignature());
340         
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;
347                         break;
348                 }
349         }
350         if (needExceptionSignatures) {
351                 for (int i = 0; i < length; i++) {
352                         sig.append(this.thrownExceptions[i].genericTypeSignature());
353                 }
354         }
355         int sigLength = sig.length();
356         char[] genericSignature = new char[sigLength];
357         sig.getChars(0, sigLength, genericSignature, 0);        
358         return genericSignature;
359 }
360 public final int getAccessFlags() {
361         return modifiers & AccJustFlag;
362 }
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];
367         return null;
368 }
369 /**
370  * Returns true if method got substituted parameter types
371  * (see ParameterizedMethodBinding)
372  */
373 public boolean hasSubstitutedParameters() {
374         return false;
375 }
376
377 /* Answer true if the return type got substituted.
378  */
379 public boolean hasSubstitutedReturnType() {
380         return false;
381 }
382
383 /* Answer true if the receiver is an abstract method
384 */
385 public final boolean isAbstract() {
386         return (modifiers & AccAbstract) != 0;
387 }
388
389 /* Answer true if the receiver is a bridge method
390 */
391 public final boolean isBridge() {
392         return (modifiers & AccBridge) != 0;
393 }
394
395 /* Answer true if the receiver is a constructor
396 */
397 public final boolean isConstructor() {
398         return selector == TypeConstants.INIT;
399 }
400
401 /* Answer true if the receiver has default visibility
402 */
403 public final boolean isDefault() {
404         return !isPublic() && !isProtected() && !isPrivate();
405 }
406
407 /* Answer true if the receiver is a system generated default abstract method
408 */
409 public final boolean isDefaultAbstract() {
410         return (modifiers & AccDefaultAbstract) != 0;
411 }
412
413 /* Answer true if the receiver is a deprecated method
414 */
415 public final boolean isDeprecated() {
416         return (modifiers & AccDeprecated) != 0;
417 }
418
419 /* Answer true if the receiver is final and cannot be overridden
420 */
421 public final boolean isFinal() {
422         return (modifiers & AccFinal) != 0;
423 }
424
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
428 */
429 public final boolean isImplementing() {
430         return (modifiers & AccImplementing) != 0;
431 }
432
433 /* Answer true if the receiver is a native method
434 */
435 public final boolean isNative() {
436         return (modifiers & AccNative) != 0;
437 }
438
439 /* Answer true if the receiver is overriding another method
440  * Only set for source methods
441 */
442 public final boolean isOverriding() {
443         return (modifiers & AccOverriding) != 0;
444 }
445 /*
446  * Answer true if the receiver is a "public static void main(String[])" method
447  */
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) {
455                         return true;
456                 }
457         }
458         return false;
459 }
460 /* Answer true if the receiver has private visibility
461 */
462 public final boolean isPrivate() {
463         return (modifiers & AccPrivate) != 0;
464 }
465
466 /* Answer true if the receiver has private visibility and is used locally
467 */
468 public final boolean isPrivateUsed() {
469         return (modifiers & AccPrivateUsed) != 0;
470 }
471
472 /* Answer true if the receiver has protected visibility
473 */
474 public final boolean isProtected() {
475         return (modifiers & AccProtected) != 0;
476 }
477
478 /* Answer true if the receiver has public visibility
479 */
480 public final boolean isPublic() {
481         return (modifiers & AccPublic) != 0;
482 }
483
484 /* Answer true if the receiver got requested to clear the private modifier
485  * during private access emulation.
486  */
487 public final boolean isRequiredToClearPrivateModifier() {
488         return (modifiers & AccClearPrivateModifier) != 0;
489 }
490
491 /* Answer true if the receiver is a static method
492 */
493 public final boolean isStatic() {
494         return (modifiers & AccStatic) != 0;
495 }
496
497 /* Answer true if all float operations must adher to IEEE 754 float/double rules
498 */
499 public final boolean isStrictfp() {
500         return (modifiers & AccStrictfp) != 0;
501 }
502
503 /* Answer true if the receiver is a synchronized method
504 */
505 public final boolean isSynchronized() {
506         return (modifiers & AccSynchronized) != 0;
507 }
508
509 /* Answer true if the receiver has public visibility
510 */
511 public final boolean isSynthetic() {
512         return (modifiers & AccSynthetic) != 0;
513 }
514
515 /* Answer true if the receiver method has varargs
516 */
517 public final boolean isVarargs() {
518         return (modifiers & AccVarargs) != 0;
519 }
520
521 /* Answer true if the receiver's declaring type is deprecated (or any of its enclosing types)
522 */
523 public final boolean isViewedAsDeprecated() {
524         return (modifiers & AccDeprecated) != 0 ||
525                 (modifiers & AccDeprecatedImplicitly) != 0;
526 }
527
528 /**
529  * Returns the original method (as opposed to parameterized instances)
530  */
531 public MethodBinding original() {
532         return this;
533 }
534
535 public char[] readableName() /* foo(int, Thread) */ {
536         StringBuffer buffer = new StringBuffer(parameters.length + 1 * 20);
537         if (isConstructor())
538                 buffer.append(declaringClass.sourceName());
539         else
540                 buffer.append(selector);
541         buffer.append('(');
542         if (parameters != NoParameters) {
543                 for (int i = 0, length = parameters.length; i < length; i++) {
544                         if (i > 0)
545                                 buffer.append(", "); //$NON-NLS-1$
546                         buffer.append(parameters[i].sourceName());
547                 }
548         }
549         buffer.append(')');
550         return buffer.toString().toCharArray();
551 }
552
553 /**
554  * @see org.eclipse.jdt.internal.compiler.lookup.Binding#shortReadableName()
555  */
556 public char[] shortReadableName() {
557         StringBuffer buffer = new StringBuffer(parameters.length + 1 * 20);
558         if (isConstructor())
559                 buffer.append(declaringClass.shortReadableName());
560         else
561                 buffer.append(selector);
562         buffer.append('(');
563         if (parameters != NoParameters) {
564                 for (int i = 0, length = parameters.length; i < length; i++) {
565                         if (i > 0)
566                                 buffer.append(", "); //$NON-NLS-1$
567                         buffer.append(parameters[i].shortReadableName());
568                 }
569         }
570         buffer.append(')');
571         int nameLength = buffer.length();
572         char[] shortReadableName = new char[nameLength];
573         buffer.getChars(0, nameLength, shortReadableName, 0);       
574         return shortReadableName;
575 }
576
577 protected final void setSelector(char[] selector) {
578         this.selector = selector;
579         this.signature = null;
580 }
581
582 /* Answer the receiver's signature.
583 *
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.
587 */
588 public final char[] signature() /* (ILjava/lang/Thread;)Ljava/lang/Object; */ {
589         if (signature != null)
590                 return signature;
591
592         StringBuffer buffer = new StringBuffer(parameters.length + 1 * 20);
593         buffer.append('(');
594         
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());
600         }
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());
608                 }
609                 
610                 if (this instanceof SyntheticMethodBinding) {
611                         targetParameters = ((SyntheticMethodBinding)this).targetMethod.parameters;
612                 }
613         }
614
615         if (targetParameters != NoParameters) {
616                 for (int i = 0; i < targetParameters.length; i++) {
617                         buffer.append(targetParameters[i].signature());
618                 }
619         }
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());
625                 }
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());
629                 }
630         }
631         buffer.append(')');
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);       
637         
638         return signature;
639 }
640 public final int sourceEnd() {
641         AbstractMethodDeclaration method = sourceMethod();
642         if (method == null)
643                 return 0;
644         return method.sourceEnd;
645 }
646 public AbstractMethodDeclaration sourceMethod() {
647         SourceTypeBinding sourceType;
648         try {
649                 sourceType = (SourceTypeBinding) declaringClass;
650         } catch (ClassCastException e) {
651                 return null;            
652         }
653
654         AbstractMethodDeclaration[] methods = sourceType.scope.referenceContext.methods;
655         for (int i = methods.length; --i >= 0;)
656                 if (this == methods[i].binding)
657                         return methods[i];
658         return null;            
659 }
660 public final int sourceStart() {
661         AbstractMethodDeclaration method = sourceMethod();
662         if (method == null)
663                 return 0;
664         return method.sourceStart;
665 }
666
667 /* During private access emulation, the binding can be requested to loose its
668  * private visibility when the class file is dumped.
669  */
670
671 public final void tagForClearingPrivateModifier() {
672         modifiers |= AccClearPrivateModifier;
673 }
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$
678
679         s += "("; //$NON-NLS-1$
680         if (parameters != null) {
681                 if (parameters != NoParameters) {
682                         for (int i = 0, length = parameters.length; i < length; i++) {
683                                 if (i  > 0)
684                                         s += ", "; //$NON-NLS-1$
685                                 s += (parameters[i] != null) ? parameters[i].debugName() : "NULL TYPE"; //$NON-NLS-1$
686                         }
687                 }
688         } else {
689                 s += "NULL PARAMETERS"; //$NON-NLS-1$
690         }
691         s += ") "; //$NON-NLS-1$
692
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++) {
697                                 if (i  > 0)
698                                         s += ", "; //$NON-NLS-1$
699                                 s += (thrownExceptions[i] != null) ? thrownExceptions[i].debugName() : "NULL TYPE"; //$NON-NLS-1$
700                         }
701                 }
702         } else {
703                 s += "NULL THROWN EXCEPTIONS"; //$NON-NLS-1$
704         }
705         return s;
706 }
707 /**
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.
710  */
711 public MethodBinding tiebreakMethod() {
712         return this;
713 }
714 public TypeVariableBinding[] typeVariables() {
715         return this.typeVariables;
716 }
717 }