]> git.uio.no Git - ifi-stolz-refaktor.git/blob - case-study/jdt-before/core extension/org/eclipse/jdt/internal/corext/dom/Bindings.java
Some talks, mostly identical.
[ifi-stolz-refaktor.git] / case-study / jdt-before / core extension / org / eclipse / jdt / internal / corext / dom / Bindings.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2012 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *     Dmitry Stalnov (dstalnov@fusionone.com) - contributed fix for
11  *       bug "inline method - doesn't handle implicit cast" (see
12  *       https://bugs.eclipse.org/bugs/show_bug.cgi?id=24941).
13  *******************************************************************************/
14 package org.eclipse.jdt.internal.corext.dom;
15
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.HashSet;
19 import java.util.List;
20 import java.util.Set;
21
22 import org.eclipse.core.runtime.Assert;
23
24 import org.eclipse.jdt.core.ICompilationUnit;
25 import org.eclipse.jdt.core.IJavaElement;
26 import org.eclipse.jdt.core.IJavaProject;
27 import org.eclipse.jdt.core.IMethod;
28 import org.eclipse.jdt.core.IType;
29 import org.eclipse.jdt.core.JavaModelException;
30 import org.eclipse.jdt.core.Signature;
31 import org.eclipse.jdt.core.dom.AST;
32 import org.eclipse.jdt.core.dom.ASTNode;
33 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
34 import org.eclipse.jdt.core.dom.Annotation;
35 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
36 import org.eclipse.jdt.core.dom.ArrayAccess;
37 import org.eclipse.jdt.core.dom.Assignment;
38 import org.eclipse.jdt.core.dom.CastExpression;
39 import org.eclipse.jdt.core.dom.ClassInstanceCreation;
40 import org.eclipse.jdt.core.dom.EnumDeclaration;
41 import org.eclipse.jdt.core.dom.Expression;
42 import org.eclipse.jdt.core.dom.FieldAccess;
43 import org.eclipse.jdt.core.dom.IAnnotationBinding;
44 import org.eclipse.jdt.core.dom.IBinding;
45 import org.eclipse.jdt.core.dom.IMemberValuePairBinding;
46 import org.eclipse.jdt.core.dom.IMethodBinding;
47 import org.eclipse.jdt.core.dom.IPackageBinding;
48 import org.eclipse.jdt.core.dom.ITypeBinding;
49 import org.eclipse.jdt.core.dom.IVariableBinding;
50 import org.eclipse.jdt.core.dom.MethodInvocation;
51 import org.eclipse.jdt.core.dom.Modifier;
52 import org.eclipse.jdt.core.dom.Name;
53 import org.eclipse.jdt.core.dom.ParenthesizedExpression;
54 import org.eclipse.jdt.core.dom.PostfixExpression;
55 import org.eclipse.jdt.core.dom.PrefixExpression;
56 import org.eclipse.jdt.core.dom.QualifiedName;
57 import org.eclipse.jdt.core.dom.SimpleName;
58 import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
59 import org.eclipse.jdt.core.dom.SuperFieldAccess;
60 import org.eclipse.jdt.core.dom.SuperMethodInvocation;
61
62 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
63 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
64
65 public class Bindings {
66
67         public static final String ARRAY_LENGTH_FIELD_BINDING_STRING= "(array type):length";//$NON-NLS-1$
68         private Bindings() {
69                 // No instance
70         }
71
72         /**
73          * Checks if the two bindings are equals. Also works across binding environments.
74          * @param b1 first binding treated as <code>this</code>. So it must
75          *  not be <code>null</code>
76          * @param b2 the second binding.
77          * @return boolean
78          */
79         public static boolean equals(IBinding b1, IBinding b2) {
80                 return b1.isEqualTo(b2);
81         }
82
83
84         /**
85          * Checks if the declarations of two bindings are equals.
86          * Also works across binding environments.
87          * @param b1 first binding, must not be <code>null</code>
88          * @param b2 second binding, must not be <code>null</code>
89          * @return boolean
90          */
91         public static boolean equalDeclarations(IBinding b1, IBinding b2) {
92                 if (b1.getKind() != b2.getKind())
93                         return false;
94                 return getDeclaration(b1).isEqualTo(getDeclaration(b2));
95         }
96
97         /**
98          * Checks if the two arrays of bindings have the same length and
99          * their elements are equal. Uses
100          * <code>Bindings.equals(IBinding, IBinding)</code> to compare.
101          * @param b1 the first array of bindings. Must not be <code>null</code>.
102          * @param b2 the second array of bindings.
103          * @return boolean
104          */
105         public static boolean equals(IBinding[] b1, IBinding[] b2) {
106                 Assert.isNotNull(b1);
107                 if (b1 == b2)
108                         return true;
109                 if (b2 == null)
110                         return false;
111                 if (b1.length != b2.length)
112                         return false;
113                 for (int i= 0; i < b1.length; i++) {
114                         if (! Bindings.equals(b1[i], b2[i]))
115                                 return false;
116                 }
117                 return true;
118         }
119
120         public static int hashCode(IBinding binding){
121                 Assert.isNotNull(binding);
122                 String key= binding.getKey();
123                 if (key == null)
124                         return binding.hashCode();
125                 return key.hashCode();
126         }
127
128         /**
129          * Note: this method is for debugging and testing purposes only.
130          * There are tests whose pre-computed test results rely on the returned String's format.
131          * @param binding the binding
132          * @return a string representation of given binding
133          * @see org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider
134          */
135         public static String asString(IBinding binding) {
136                 if (binding instanceof IMethodBinding)
137                         return asString((IMethodBinding)binding);
138                 else if (binding instanceof ITypeBinding)
139                         return ((ITypeBinding)binding).getQualifiedName();
140                 else if (binding instanceof IVariableBinding)
141                         return asString((IVariableBinding)binding);
142                 return binding.toString();
143         }
144
145         private static String asString(IVariableBinding variableBinding) {
146                 if (! variableBinding.isField())
147                         return variableBinding.toString();
148                 if (variableBinding.getDeclaringClass() == null) {
149                         Assert.isTrue(variableBinding.getName().equals("length"));//$NON-NLS-1$
150                         return ARRAY_LENGTH_FIELD_BINDING_STRING;
151                 }
152                 StringBuffer result= new StringBuffer();
153                 result.append(variableBinding.getDeclaringClass().getName());
154                 result.append(':');
155                 result.append(variableBinding.getName());
156                 return result.toString();
157         }
158
159         private static String asString(IMethodBinding method) {
160                 StringBuffer result= new StringBuffer();
161                 result.append(method.getDeclaringClass().getName());
162                 result.append(':');
163                 result.append(method.getName());
164                 result.append('(');
165                 ITypeBinding[] parameters= method.getParameterTypes();
166                 int lastComma= parameters.length - 1;
167                 for (int i= 0; i < parameters.length; i++) {
168                         ITypeBinding parameter= parameters[i];
169                         result.append(parameter.getName());
170                         if (i < lastComma)
171                                 result.append(", "); //$NON-NLS-1$
172                 }
173                 result.append(')');
174                 return result.toString();
175         }
176
177         public static String getTypeQualifiedName(ITypeBinding type) {
178                 List<String> result= new ArrayList<String>(5);
179                 createName(type, false, result);
180
181                 StringBuffer buffer= new StringBuffer();
182                 for (int i= 0; i < result.size(); i++) {
183                         if (i > 0) {
184                                 buffer.append('.');
185                         }
186                         buffer.append(result.get(i));
187                 }
188                 return buffer.toString();
189         }
190
191         /**
192          * Returns the fully qualified name of the specified type binding.
193          * <p>
194          * If the binding resolves to a generic type, the fully qualified name of the raw type is returned.
195          *
196          * @param type the type binding to get its fully qualified name
197          * @return the fully qualified name
198          */
199         public static String getFullyQualifiedName(ITypeBinding type) {
200                 String name= type.getQualifiedName();
201                 final int index= name.indexOf('<');
202                 if (index > 0)
203                         name= name.substring(0, index);
204                 return name;
205         }
206
207         public static String getImportName(IBinding binding) {
208                 ITypeBinding declaring= null;
209                 switch (binding.getKind()) {
210                         case IBinding.TYPE:
211                                 return getRawQualifiedName((ITypeBinding) binding);
212                         case IBinding.PACKAGE:
213                                 return binding.getName() + ".*"; //$NON-NLS-1$
214                         case IBinding.METHOD:
215                                 declaring= ((IMethodBinding) binding).getDeclaringClass();
216                                 break;
217                         case IBinding.VARIABLE:
218                                 declaring= ((IVariableBinding) binding).getDeclaringClass();
219                                 if (declaring == null) {
220                                         return binding.getName(); // array.length
221                                 }
222
223                                 break;
224                         default:
225                                 return binding.getName();
226                 }
227                 return JavaModelUtil.concatenateName(getRawQualifiedName(declaring), binding.getName());
228         }
229
230
231         private static void createName(ITypeBinding type, boolean includePackage, List<String> list) {
232                 ITypeBinding baseType= type;
233                 if (type.isArray()) {
234                         baseType= type.getElementType();
235                 }
236                 if (!baseType.isPrimitive() && !baseType.isNullType()) {
237                         ITypeBinding declaringType= baseType.getDeclaringClass();
238                         if (declaringType != null) {
239                                 createName(declaringType, includePackage, list);
240                         } else if (includePackage && !baseType.getPackage().isUnnamed()) {
241                                 String[] components= baseType.getPackage().getNameComponents();
242                                 for (int i= 0; i < components.length; i++) {
243                                         list.add(components[i]);
244                                 }
245                         }
246                 }
247                 if (!baseType.isAnonymous()) {
248                         list.add(type.getName());
249                 } else {
250                         list.add("$local$"); //$NON-NLS-1$
251                 }
252         }
253
254
255         public static String[] getNameComponents(ITypeBinding type) {
256                 List<String> result= new ArrayList<String>(5);
257                 createName(type, false, result);
258                 return result.toArray(new String[result.size()]);
259         }
260
261         public static String[] getAllNameComponents(ITypeBinding type) {
262                 List<String> result= new ArrayList<String>(5);
263                 createName(type, true, result);
264                 return result.toArray(new String[result.size()]);
265         }
266
267         public static ITypeBinding getTopLevelType(ITypeBinding type) {
268                 ITypeBinding parent= type.getDeclaringClass();
269                 while (parent != null) {
270                         type= parent;
271                         parent= type.getDeclaringClass();
272                 }
273                 return type;
274         }
275
276         /**
277          * Checks whether the passed type binding is a runtime exception.
278          *
279          * @param thrownException the type binding
280          *
281          * @return <code>true</code> if the passed type binding is a runtime exception;
282          *      otherwise <code>false</code> is returned
283          */
284         public static boolean isRuntimeException(ITypeBinding thrownException) {
285                 if (thrownException == null || thrownException.isPrimitive() || thrownException.isArray())
286                         return false;
287                 return findTypeInHierarchy(thrownException, "java.lang.RuntimeException") != null; //$NON-NLS-1$
288         }
289
290         /**
291          * Finds the field specified by <code>fieldName<code> in
292          * the given <code>type</code>. Returns <code>null</code> if no such field exits.
293          * @param type the type to search the field in
294          * @param fieldName the field name
295          * @return the binding representing the field or <code>null</code>
296          */
297         public static IVariableBinding findFieldInType(ITypeBinding type, String fieldName) {
298                 if (type.isPrimitive())
299                         return null;
300                 IVariableBinding[] fields= type.getDeclaredFields();
301                 for (int i= 0; i < fields.length; i++) {
302                         IVariableBinding field= fields[i];
303                         if (field.getName().equals(fieldName))
304                                 return field;
305                 }
306                 return null;
307         }
308
309         /**
310          * Finds the field specified by <code>fieldName</code> in
311          * the type hierarchy denoted by the given type. Returns <code>null</code> if no such field
312          * exists. If the field is defined in more than one super type only the first match is
313          * returned. First the super class is examined and then the implemented interfaces.
314          * @param type The type to search the field in
315          * @param fieldName The name of the field to find
316          * @return the variable binding representing the field
317          */
318         public static IVariableBinding findFieldInHierarchy(ITypeBinding type, String fieldName) {
319                 IVariableBinding field= findFieldInType(type, fieldName);
320                 if (field != null)
321                         return field;
322                 ITypeBinding superClass= type.getSuperclass();
323                 if (superClass != null) {
324                         field= findFieldInHierarchy(superClass, fieldName);
325                         if (field != null)
326                                 return field;
327                 }
328                 ITypeBinding[] interfaces= type.getInterfaces();
329                 for (int i= 0; i < interfaces.length; i++) {
330                         field= findFieldInHierarchy(interfaces[i], fieldName);
331                         if (field != null) // no private fields in interfaces
332                                 return field;
333                 }
334                 return null;
335         }
336
337         /**
338          * Finds the method specified by <code>methodName<code> and </code>parameters</code> in
339          * the given <code>type</code>. Returns <code>null</code> if no such method exits.
340          * @param type The type to search the method in
341          * @param methodName The name of the method to find
342          * @param parameters The parameter types of the method to find. If <code>null</code> is passed, only
343          *  the name is matched and parameters are ignored.
344          * @return the method binding representing the method
345          */
346         public static IMethodBinding findMethodInType(ITypeBinding type, String methodName, ITypeBinding[] parameters) {
347                 if (type.isPrimitive())
348                         return null;
349                 IMethodBinding[] methods= type.getDeclaredMethods();
350                 for (int i= 0; i < methods.length; i++) {
351                         if (parameters == null) {
352                                 if (methodName.equals(methods[i].getName()))
353                                         return methods[i];
354                         } else {
355                                 if (isEqualMethod(methods[i], methodName, parameters))
356                                         return methods[i];
357                         }
358                 }
359                 return null;
360         }
361
362         /**
363          * Finds the method specified by <code>methodName</code> and </code>parameters</code> in
364          * the type hierarchy denoted by the given type. Returns <code>null</code> if no such method
365          * exists. If the method is defined in more than one super type only the first match is
366          * returned. First the super class is examined and then the implemented interfaces.
367          * 
368          * @param type The type to search the method in
369          * @param methodName The name of the method to find
370          * @param parameters The parameter types of the method to find. If <code>null</code> is passed, only the name is matched and parameters are ignored.
371          * @return the method binding representing the method
372          */
373         public static IMethodBinding findMethodInHierarchy(ITypeBinding type, String methodName, ITypeBinding[] parameters) {
374                 IMethodBinding method= findMethodInType(type, methodName, parameters);
375                 if (method != null)
376                         return method;
377                 ITypeBinding superClass= type.getSuperclass();
378                 if (superClass != null) {
379                         method= findMethodInHierarchy(superClass, methodName, parameters);
380                         if (method != null)
381                                 return method;
382                 }
383                 ITypeBinding[] interfaces= type.getInterfaces();
384                 for (int i= 0; i < interfaces.length; i++) {
385                         method= findMethodInHierarchy(interfaces[i], methodName, parameters);
386                         if (method != null)
387                                 return method;
388                 }
389                 return null;
390         }
391
392         /**
393          * Finds the method specified by <code>methodName<code> and </code>parameters</code> in
394          * the given <code>type</code>. Returns <code>null</code> if no such method exits.
395          * @param type The type to search the method in
396          * @param methodName The name of the method to find
397          * @param parameters The parameter types of the method to find. If <code>null</code> is passed, only the name is matched and parameters are ignored.
398          * @return the method binding representing the method
399          */
400         public static IMethodBinding findMethodInType(ITypeBinding type, String methodName, String[] parameters) {
401                 if (type.isPrimitive())
402                         return null;
403                 IMethodBinding[] methods= type.getDeclaredMethods();
404                 for (int i= 0; i < methods.length; i++) {
405                         if (parameters == null) {
406                                 if (methodName.equals(methods[i].getName()))
407                                         return methods[i];
408                         } else {
409                                 if (isEqualMethod(methods[i], methodName, parameters))
410                                         return methods[i];
411                         }
412                 }
413                 return null;
414         }
415
416         /**
417          * Finds the method specified by <code>methodName</code> and </code>parameters</code> in
418          * the type hierarchy denoted by the given type. Returns <code>null</code> if no such method
419          * exists. If the method is defined in more than one super type only the first match is
420          * returned. First the super class is examined and then the implemented interfaces.
421          * @param type the type to search the method in
422          * @param methodName The name of the method to find
423          * @param parameters The parameter types of the method to find. If <code>null</code> is passed, only the name is matched and parameters are ignored.
424          * @return the method binding representing the method
425          */
426         public static IMethodBinding findMethodInHierarchy(ITypeBinding type, String methodName, String[] parameters) {
427                 IMethodBinding method= findMethodInType(type, methodName, parameters);
428                 if (method != null)
429                         return method;
430                 ITypeBinding superClass= type.getSuperclass();
431                 if (superClass != null) {
432                         method= findMethodInHierarchy(superClass, methodName, parameters);
433                         if (method != null)
434                                 return method;
435                 }
436                 ITypeBinding[] interfaces= type.getInterfaces();
437                 for (int i= 0; i < interfaces.length; i++) {
438                         method= findMethodInHierarchy(interfaces[i], methodName, parameters);
439                         if (method != null)
440                                 return method;
441                 }
442                 return null;
443         }
444
445         /**
446          * Finds the method in the given <code>type</code> that is overridden by the specified <code>method<code>.
447          * Returns <code>null</code> if no such method exits.
448          * @param type The type to search the method in
449          * @param method The specified method that would override the result
450          * @return the method binding of the method that is overridden by the specified <code>method<code>, or <code>null</code>
451          */
452         public static IMethodBinding findOverriddenMethodInType(ITypeBinding type, IMethodBinding method) {
453                 IMethodBinding[] methods= type.getDeclaredMethods();
454                 for (int i= 0; i < methods.length; i++) {
455                         if (isSubsignature(method, methods[i]))
456                                 return methods[i];
457                 }
458                 return null;
459         }
460
461         /**
462          * Finds a method in the hierarchy of <code>type</code> that is overridden by </code>binding</code>.
463          * Returns <code>null</code> if no such method exists. If the method is defined in more than one super type only the first match is
464          * returned. First the super class is examined and then the implemented interfaces.
465          * @param type The type to search the method in
466          * @param binding The method that overrides
467          * @return the method binding overridden the method
468          */
469         public static IMethodBinding findOverriddenMethodInHierarchy(ITypeBinding type, IMethodBinding binding) {
470                 IMethodBinding method= findOverriddenMethodInType(type, binding);
471                 if (method != null)
472                         return method;
473                 ITypeBinding superClass= type.getSuperclass();
474                 if (superClass != null) {
475                         method= findOverriddenMethodInHierarchy(superClass, binding);
476                         if (method != null)
477                                 return method;
478                 }
479                 ITypeBinding[] interfaces= type.getInterfaces();
480                 for (int i= 0; i < interfaces.length; i++) {
481                         method= findOverriddenMethodInHierarchy(interfaces[i], binding);
482                         if (method != null)
483                                 return method;
484                 }
485                 return null;
486         }
487
488
489         /**
490          * Finds the method that is overridden by the given method. The search is bottom-up, so this
491          * returns the nearest defining/declaring method.
492          * @param overriding overriding method
493          * @param testVisibility If true the result is tested on visibility. Null is returned if the method is not visible.
494          * @return the method binding representing the method
495          */
496         public static IMethodBinding findOverriddenMethod(IMethodBinding overriding, boolean testVisibility) {
497                 int modifiers= overriding.getModifiers();
498                 if (Modifier.isPrivate(modifiers) || Modifier.isStatic(modifiers) || overriding.isConstructor()) {
499                         return null;
500                 }
501
502                 ITypeBinding type= overriding.getDeclaringClass();
503                 if (type.getSuperclass() != null) {
504                         IMethodBinding res= findOverriddenMethodInHierarchy(type.getSuperclass(), overriding);
505                         if (res != null && !Modifier.isPrivate(res.getModifiers())) {
506                                 if (!testVisibility || isVisibleInHierarchy(res, overriding.getDeclaringClass().getPackage())) {
507                                         return res;
508                                 }
509                         }
510                 }
511                 ITypeBinding[] interfaces= type.getInterfaces();
512                 for (int i= 0; i < interfaces.length; i++) {
513                         IMethodBinding res= findOverriddenMethodInHierarchy(interfaces[i], overriding);
514                         if (res != null) {
515                                 return res; // methods from interfaces are always public and therefore visible
516                         }
517                 }
518                 return null;
519         }
520
521
522         public static boolean isVisibleInHierarchy(IMethodBinding member, IPackageBinding pack) {
523                 int otherflags= member.getModifiers();
524                 ITypeBinding declaringType= member.getDeclaringClass();
525                 if (Modifier.isPublic(otherflags) || Modifier.isProtected(otherflags) || (declaringType != null && declaringType.isInterface())) {
526                         return true;
527                 } else if (Modifier.isPrivate(otherflags)) {
528                         return false;
529                 }
530                 return declaringType != null && pack == declaringType.getPackage();
531         }
532
533         /**
534          * Returns all super types (classes and interfaces) for the given type.
535          * @param type The type to get the supertypes of.
536          * @return all super types (excluding <code>type</code>)
537          */
538         public static ITypeBinding[] getAllSuperTypes(ITypeBinding type) {
539                 Set<ITypeBinding> result= new HashSet<ITypeBinding>();
540                 collectSuperTypes(type, result);
541                 result.remove(type);
542                 return result.toArray(new ITypeBinding[result.size()]);
543         }
544
545         private static void collectSuperTypes(ITypeBinding curr, Set<ITypeBinding> collection) {
546                 if (collection.add(curr)) {
547                         ITypeBinding[] interfaces= curr.getInterfaces();
548                         for (int i= 0; i < interfaces.length; i++) {
549                                 collectSuperTypes(interfaces[i], collection);
550                         }
551                         ITypeBinding superClass= curr.getSuperclass();
552                         if (superClass != null) {
553                                 collectSuperTypes(superClass, collection);
554                         }
555                 }
556         }
557
558         /**
559          * Method to visit a type hierarchy defined by a given type.
560          *
561          * @param type the type which hierarchy is to be visited
562          * @param visitor the visitor
563          * @return <code>false</code> if the visiting got interrupted
564          */
565         public static boolean visitHierarchy(ITypeBinding type, TypeBindingVisitor visitor) {
566                 boolean result= visitSuperclasses(type, visitor);
567                 if(result) {
568                         result= visitInterfaces(type, visitor);
569                 }
570                 return result;
571         }
572
573         /**
574          * Method to visit a interface hierarchy defined by a given type.
575          *
576          * @param type the type which interface hierarchy is to be visited
577          * @param visitor the visitor
578          * @return <code>false</code> if the visiting got interrupted
579          */
580         public static boolean visitInterfaces(ITypeBinding type, TypeBindingVisitor visitor) {
581                 ITypeBinding[] interfaces= type.getInterfaces();
582                 for (int i= 0; i < interfaces.length; i++) {
583                         if (!visitor.visit(interfaces[i])) {
584                                 return false;
585                         }
586                 }
587                 return true;
588         }
589
590         /**
591          * Method to visit a super class hierarchy defined by a given type.
592          *
593          * @param type the type which super class hierarchy is to be visited
594          * @param visitor the visitor
595          * @return <code>false</code> if the visiting got interrupted
596          */
597         public static boolean visitSuperclasses(ITypeBinding type, TypeBindingVisitor visitor) {
598                 while ((type= type.getSuperclass()) != null) {
599                         if (!visitor.visit(type)) {
600                                 return false;
601                         }
602                 }
603                 return true;
604         }
605
606         /**
607          * Tests whether the two methods are erasure-equivalent.
608          * @param method the first method
609          * @param methodName the name of the second method
610          * @param parameters the parameters of the second method
611          * @return return <code>true</code> if the two bindings are equal
612          * @deprecated use {@link #isSubsignature(IMethodBinding, IMethodBinding)}
613          */
614         //TODO: rename to isErasureEquivalentMethod and change to two IMethodBinding parameters
615         public static boolean isEqualMethod(IMethodBinding method, String methodName, ITypeBinding[] parameters) {
616                 if (!method.getName().equals(methodName))
617                         return false;
618
619                 ITypeBinding[] methodParameters= method.getParameterTypes();
620                 if (methodParameters.length != parameters.length)
621                         return false;
622                 for (int i= 0; i < parameters.length; i++) {
623                         if (!equals(methodParameters[i].getErasure(), parameters[i].getErasure()))
624                                 return false;
625                 }
626                 //Can't use this fix, since some clients assume that this method tests erasure equivalence:
627 //              if (method.getTypeParameters().length == 0) {
628 //                      //a method without type parameters cannot be overridden by one that declares type parameters -> can be exact here
629 //                      for (int i= 0; i < parameters.length; i++) {
630 //                              if ( ! (equals(methodParameters[i], parameters[i])
631 //                                              || equals(methodParameters[i].getErasure(), parameters[i]))) // subsignature
632 //                                      return false;
633 //                      }
634 //              } else {
635 //                      //this will find all overridden methods, but may generate false positives in some cases:
636 //                      for (int i= 0; i < parameters.length; i++) {
637 //                              if (!equals(methodParameters[i].getErasure(), parameters[i].getErasure()))
638 //                                      return false;
639 //                      }
640 //              }
641                 return true;
642         }
643
644         /**
645          * @param overriding overriding method (m1)
646          * @param overridden overridden method (m2)
647          * @return <code>true</code> iff the method <code>m1</code> is a subsignature of the method <code>m2</code>.
648          *              This is one of the requirements for m1 to override m2.
649          *              Accessibility and return types are not taken into account.
650          *              Note that subsignature is <em>not</em> symmetric!
651          */
652         public static boolean isSubsignature(IMethodBinding overriding, IMethodBinding overridden) {
653                 //TODO: use IMethodBinding#isSubsignature(..) once it is tested and fixed (only erasure of m1's parameter types, considering type variable counts, doing type variable substitution
654                 if (!overriding.getName().equals(overridden.getName()))
655                         return false;
656
657                 ITypeBinding[] m1Params= overriding.getParameterTypes();
658                 ITypeBinding[] m2Params= overridden.getParameterTypes();
659                 if (m1Params.length != m2Params.length)
660                         return false;
661
662                 ITypeBinding[] m1TypeParams= overriding.getTypeParameters();
663                 ITypeBinding[] m2TypeParams= overridden.getTypeParameters();
664                 if (m1TypeParams.length != m2TypeParams.length
665                                 && m1TypeParams.length != 0) //non-generic m1 can override a generic m2
666                         return false;
667
668                 //m1TypeParameters.length == (m2TypeParameters.length || 0)
669                 if (m2TypeParams.length != 0) {
670                         //Note: this branch does not 100% adhere to the spec and may report some false positives.
671                         // Full compliance would require major duplication of compiler code.
672
673                         //Compare type parameter bounds:
674                         for (int i= 0; i < m1TypeParams.length; i++) {
675                                 // loop over m1TypeParams, which is either empty, or equally long as m2TypeParams
676                                 Set<ITypeBinding> m1Bounds= getTypeBoundsForSubsignature(m1TypeParams[i]);
677                                 Set<ITypeBinding> m2Bounds= getTypeBoundsForSubsignature(m2TypeParams[i]);
678                                 if (! m1Bounds.equals(m2Bounds))
679                                         return false;
680                         }
681                         //Compare parameter types:
682                         if (equals(m2Params, m1Params))
683                                 return true;
684                         for (int i= 0; i < m1Params.length; i++) {
685                                 ITypeBinding m1Param= m1Params[i];
686                                 ITypeBinding m2Param= m2Params[i];
687                                 if (containsTypeVariables(m1Param) || m1Param.isRawType())
688                                         m1Param= m1Param.getErasure(); // try to achieve effect of "rename type variables"
689                                 if (! (equals(m1Param, m2Param) || equals(m1Param, m2Param.getErasure())))
690                                         return false;
691                         }
692                         return true;
693
694                 } else {
695                         // m1TypeParams.length == m2TypeParams.length == 0
696                         if (equals(m1Params, m2Params))
697                                 return true;
698                         for (int i= 0; i < m1Params.length; i++) {
699                                 ITypeBinding m1Param= m1Params[i];
700                                 ITypeBinding m2Param= m2Params[i];
701                                 if (m1Param.isRawType())
702                                         m1Param= m1Param.getTypeDeclaration();
703                                 if (! (equals(m1Param, m2Param) || equals(m1Param, m2Param.getErasure())))
704                                         return false;
705                         }
706                         return true;
707                 }
708         }
709
710         static boolean containsTypeVariables(ITypeBinding type) {
711                 if (type.isTypeVariable())
712                         return true;
713                 if (type.isArray())
714                         return containsTypeVariables(type.getElementType());
715                 if (type.isCapture())
716                         return containsTypeVariables(type.getWildcard());
717                 if (type.isParameterizedType())
718                         return containsTypeVariables(type.getTypeArguments());
719                 if (type.isTypeVariable())
720                         return containsTypeVariables(type.getTypeBounds());
721                 if (type.isWildcardType() && type.getBound() != null)
722                         return containsTypeVariables(type.getBound());
723                 return false;
724         }
725
726         private static boolean containsTypeVariables(ITypeBinding[] types) {
727                 for (int i= 0; i < types.length; i++)
728                         if (containsTypeVariables(types[i]))
729                                 return true;
730                 return false;
731         }
732
733         private static Set<ITypeBinding> getTypeBoundsForSubsignature(ITypeBinding typeParameter) {
734                 ITypeBinding[] typeBounds= typeParameter.getTypeBounds();
735                 int count= typeBounds.length;
736                 if (count == 0)
737                         return Collections.emptySet();
738
739                 Set<ITypeBinding> result= new HashSet<ITypeBinding>(typeBounds.length);
740                 for (int i= 0; i < typeBounds.length; i++) {
741                         ITypeBinding bound= typeBounds[i];
742                         if ("java.lang.Object".equals(typeBounds[0].getQualifiedName())) //$NON-NLS-1$
743                                 continue;
744                         else if (containsTypeVariables(bound))
745                                 result.add(bound.getErasure()); // try to achieve effect of "rename type variables"
746                         else if (bound.isRawType())
747                                 result.add(bound.getTypeDeclaration());
748                         else
749                                 result.add(bound);
750                 }
751                 return result;
752         }
753
754         /**
755          * Checks whether a method with the given name and parameter types
756          * is a subsignature of the given method binding.
757          * 
758          * @param method a method
759          * @param methodName method name to match
760          * @param parameters the parameter types of the method to find. If <code>null</code> is passed, only the name is matched and parameters are ignored.
761          * @return <code>true</code> iff the method
762          *              m1 (with name <code>methodName</code> and method parameters <code>parameters</code>)
763          *              is a subsignature of the method <code>m2</code>. Accessibility and return types are not taken into account.
764          */
765         public static boolean isEqualMethod(IMethodBinding method, String methodName, String[] parameters) {
766                 if (!method.getName().equals(methodName))
767                         return false;
768
769                 ITypeBinding[] methodParameters= method.getParameterTypes();
770                 if (methodParameters.length != parameters.length)
771                         return false;
772                 String first, second;
773                 int index;
774                 for (int i= 0; i < parameters.length; i++) {
775                         first= parameters[i];
776                         index= first.indexOf('<');
777                         if (index > 0){
778                                 int lastIndex= first.lastIndexOf('>');
779                                 StringBuffer buf= new StringBuffer();
780                                 buf.append(first.substring(0, index));
781                                 if (lastIndex < first.length() - 1)
782                                         buf.append(first.substring(lastIndex + 1, first.length()));
783                                 first= buf.toString();
784                         }
785                         second= methodParameters[i].getQualifiedName();
786                         if (!first.equals(second)) {
787                                 second= methodParameters[i].getErasure().getQualifiedName();
788                                 if (!first.equals(second))
789                                         return false;
790                         }
791                 }
792                 return true;
793         }
794
795         /**
796          * Finds a type binding for a given fully qualified type in the hierarchy of a type.
797          * Returns <code>null</code> if no type binding is found.
798          * @param hierarchyType the binding representing the hierarchy
799          * @param fullyQualifiedTypeName the fully qualified name to search for
800          * @return the type binding
801          */
802         public static ITypeBinding findTypeInHierarchy(ITypeBinding hierarchyType, String fullyQualifiedTypeName) {
803                 if (hierarchyType.isArray() || hierarchyType.isPrimitive()) {
804                         return null;
805                 }
806                 if (fullyQualifiedTypeName.equals(hierarchyType.getTypeDeclaration().getQualifiedName())) {
807                         return hierarchyType;
808                 }
809                 ITypeBinding superClass= hierarchyType.getSuperclass();
810                 if (superClass != null) {
811                         ITypeBinding res= findTypeInHierarchy(superClass, fullyQualifiedTypeName);
812                         if (res != null) {
813                                 return res;
814                         }
815                 }
816                 ITypeBinding[] superInterfaces= hierarchyType.getInterfaces();
817                 for (int i= 0; i < superInterfaces.length; i++) {
818                         ITypeBinding res= findTypeInHierarchy(superInterfaces[i], fullyQualifiedTypeName);
819                         if (res != null) {
820                                 return res;
821                         }
822                 }
823                 return null;
824         }
825
826         /**
827          * Returns the binding of the variable written in an Assignment.
828          * @param assignment The assignment
829          * @return The binding or <code>null</code> if no bindings are available.
830          */
831         public static IVariableBinding getAssignedVariable(Assignment assignment) {
832                 Expression leftHand = assignment.getLeftHandSide();
833                 switch (leftHand.getNodeType()) {
834                         case ASTNode.SIMPLE_NAME:
835                                 return (IVariableBinding) ((SimpleName) leftHand).resolveBinding();
836                         case ASTNode.QUALIFIED_NAME:
837                                 return (IVariableBinding) ((QualifiedName) leftHand).getName().resolveBinding();
838                         case ASTNode.FIELD_ACCESS:
839                                 return ((FieldAccess) leftHand).resolveFieldBinding();
840                         case ASTNode.SUPER_FIELD_ACCESS:
841                                 return ((SuperFieldAccess) leftHand).resolveFieldBinding();
842                         default:
843                                 return null;
844                 }
845         }
846
847         /**
848          * Returns <code>true</code> if the given type is a super type of a candidate.
849          * <code>true</code> is returned if the two type bindings are identical.
850          * 
851          * <p><b>Warning:</b> With the addition of generics, this method is valid in less
852          * cases than before. Consider using {@link TypeRules#canAssign(ITypeBinding, ITypeBinding)}
853          * if you're dealing with types of variables. The classical notion of supertypes
854          * only makes sense if you really need to walk the type hierarchy but don't need to play
855          * the assignment rules.</p>
856          * 
857          * @param possibleSuperType the type to inspect
858          * @param type the type whose super types are looked at
859          * @return <code>true</code> iff <code>possibleSuperType</code> is
860          *              a super type of <code>type</code> or is equal to it
861          */
862         public static boolean isSuperType(ITypeBinding possibleSuperType, ITypeBinding type) {
863                 return isSuperType(possibleSuperType, type, true);
864         }
865         
866         /**
867          * Returns <code>true</code> if the given type is a super type of a candidate.
868          * <code>true</code> is returned if the two type bindings are identical (TODO)
869          * @param possibleSuperType the type to inspect
870          * @param type the type whose super types are looked at
871          * @param considerTypeArguments if <code>true</code>, consider type arguments of <code>type</code>
872          * @return <code>true</code> iff <code>possibleSuperType</code> is
873          *              a super type of <code>type</code> or is equal to it
874          */
875         public static boolean isSuperType(ITypeBinding possibleSuperType, ITypeBinding type, boolean considerTypeArguments) {
876                 if (type.isArray() || type.isPrimitive()) {
877                         return false;
878                 }
879                 if (! considerTypeArguments) {
880                         type= type.getTypeDeclaration();
881                 }
882                 if (Bindings.equals(type, possibleSuperType)) {
883                         return true;
884                 }
885                 ITypeBinding superClass= type.getSuperclass();
886                 if (superClass != null) {
887                         if (isSuperType(possibleSuperType, superClass, considerTypeArguments)) {
888                                 return true;
889                         }
890                 }
891
892                 if (possibleSuperType.isInterface()) {
893                         ITypeBinding[] superInterfaces= type.getInterfaces();
894                         for (int i= 0; i < superInterfaces.length; i++) {
895                                 if (isSuperType(possibleSuperType, superInterfaces[i], considerTypeArguments)) {
896                                         return true;
897                                 }
898                         }
899                 }
900                 return false;
901         }
902
903         /**
904          * Finds the compilation unit where the type of the given <code>ITypeBinding</code> is defined,
905          * using the class path defined by the given Java project. Returns <code>null</code>
906          * if no compilation unit is found (e.g. type binding is from a binary type)
907          * @param typeBinding the type binding to search for
908          * @param project the project used as a scope
909          * @return the compilation unit containing the type
910          * @throws JavaModelException if an errors occurs in the Java model
911          */
912         public static ICompilationUnit findCompilationUnit(ITypeBinding typeBinding, IJavaProject project) throws JavaModelException {
913                 IJavaElement type= typeBinding.getJavaElement();
914                 if (type instanceof IType)
915                         return ((IType) type).getCompilationUnit();
916                 else
917                         return null;
918         }
919
920         /**
921          * Finds a method for the given <code>IMethodBinding</code>. Returns
922          * <code>null</code> if the type doesn't contain a corresponding method.
923          * @param method the method to find
924          * @param type the type to look in
925          * @return the corresponding IMethod or <code>null</code>
926          * @throws JavaModelException if an error occurs in the Java model
927          * @deprecated Use {@link #findMethodInHierarchy(ITypeBinding, String, String[])} or {@link JavaModelUtil}
928          */
929         public static IMethod findMethod(IMethodBinding method, IType type) throws JavaModelException {
930                 method= method.getMethodDeclaration();
931
932                 IMethod[] candidates= type.getMethods();
933                 for (int i= 0; i < candidates.length; i++) {
934                         IMethod candidate= candidates[i];
935                         if (candidate.getElementName().equals(method.getName()) && sameParameters(method, candidate)) {
936                                 return candidate;
937                         }
938                 }
939                 return null;
940         }
941
942         //---- Helper methods to convert a method ---------------------------------------------
943
944         private static boolean sameParameters(IMethodBinding method, IMethod candidate) throws JavaModelException {
945                 ITypeBinding[] methodParamters= method.getParameterTypes();
946                 String[] candidateParameters= candidate.getParameterTypes();
947                 if (methodParamters.length != candidateParameters.length)
948                         return false;
949                 IType scope= candidate.getDeclaringType();
950                 for (int i= 0; i < methodParamters.length; i++) {
951                         ITypeBinding methodParameter= methodParamters[i];
952                         String candidateParameter= candidateParameters[i];
953                         if (!sameParameter(methodParameter, candidateParameter, scope))
954                                 return false;
955                 }
956                 return true;
957         }
958
959         private static boolean sameParameter(ITypeBinding type, String candidate, IType scope) throws JavaModelException {
960                 if (type.getDimensions() != Signature.getArrayCount(candidate))
961                         return false;
962
963                 // Normalizes types
964                 if (type.isArray())
965                         type= type.getElementType();
966                 candidate= Signature.getElementType(candidate);
967
968                 if ((Signature.getTypeSignatureKind(candidate) == Signature.BASE_TYPE_SIGNATURE) != type.isPrimitive()) {
969                         return false;
970                 }
971
972                 if (type.isPrimitive() || type.isTypeVariable()) {
973                         return type.getName().equals(Signature.toString(candidate));
974                 } else {
975                         // normalize (quick hack until binding.getJavaElement works)
976                         candidate= Signature.getTypeErasure(candidate);
977                         type= type.getErasure();
978
979                         if (candidate.charAt(Signature.getArrayCount(candidate)) == Signature.C_RESOLVED) {
980                                 return Signature.toString(candidate).equals(Bindings.getFullyQualifiedName(type));
981                         } else {
982                                 String[][] qualifiedCandidates= scope.resolveType(Signature.toString(candidate));
983                                 if (qualifiedCandidates == null || qualifiedCandidates.length == 0)
984                                         return false;
985                                 String packageName= type.getPackage().isUnnamed() ? "" : type.getPackage().getName(); //$NON-NLS-1$
986                                 String typeName= getTypeQualifiedName(type);
987                                 for (int i= 0; i < qualifiedCandidates.length; i++) {
988                                         String[] qualifiedCandidate= qualifiedCandidates[i];
989                                         if (    qualifiedCandidate[0].equals(packageName) &&
990                                                         qualifiedCandidate[1].equals(typeName))
991                                                 return true;
992                                 }
993                         }
994                 }
995                 return false;
996         }
997
998         /**
999          * Normalizes a type binding received from an expression to a type binding that can be used inside a
1000          * declaration signature, but <em>not</em> as type of a declaration (use {@link #normalizeForDeclarationUse(ITypeBinding, AST)} for that).
1001          * <p>
1002          * Anonymous types are normalized to the super class or interface. For
1003          * null or void bindings, <code>null</code> is returned.
1004          * </p>
1005          * 
1006          * @param binding the binding to normalize
1007          * @return the normalized binding, can be <code>null</code>
1008          * 
1009          * @see #normalizeForDeclarationUse(ITypeBinding, AST)
1010          */
1011         public static ITypeBinding normalizeTypeBinding(ITypeBinding binding) {
1012                 if (binding != null && !binding.isNullType() && !isVoidType(binding)) {
1013                         if (binding.isAnonymous()) {
1014                                 ITypeBinding[] baseBindings= binding.getInterfaces();
1015                                 if (baseBindings.length > 0) {
1016                                         return baseBindings[0];
1017                                 }
1018                                 return binding.getSuperclass();
1019                         }
1020                         if (binding.isCapture()) {
1021                                 return binding.getWildcard();
1022                         }
1023                         return binding;
1024                 }
1025                 return null;
1026         }
1027
1028         public static boolean isVoidType(ITypeBinding binding) {
1029                 return "void".equals(binding.getName()); //$NON-NLS-1$
1030         }
1031
1032         /**
1033          * Normalizes the binding so that it can be used as a type inside a declaration (e.g. variable
1034          * declaration, method return type, parameter type, ...).
1035          * For null bindings, java.lang.Object is returned.
1036          * For void bindings, <code>null</code> is returned.
1037          * 
1038          * @param binding binding to normalize
1039          * @param ast current AST
1040          * @return the normalized type to be used in declarations, or <code>null</code>
1041          */
1042         public static ITypeBinding normalizeForDeclarationUse(ITypeBinding binding, AST ast) {
1043                 if (binding.isNullType())
1044                         return ast.resolveWellKnownType("java.lang.Object"); //$NON-NLS-1$
1045                 if (binding.isPrimitive())
1046                         return binding;
1047                 binding= normalizeTypeBinding(binding);
1048                 if (binding == null || !binding.isWildcardType())
1049                         return binding;
1050                 if (binding.isUpperbound()) {
1051                         return binding.getBound();
1052                 } else {
1053                         return ast.resolveWellKnownType("java.lang.Object"); //$NON-NLS-1$
1054                 }
1055         }
1056
1057         /**
1058          * Returns the type binding of the node's enclosing type declaration.
1059          * 
1060          * @param node an AST node
1061          * @return the type binding of the node's parent type declaration, or <code>null</code>
1062          */
1063         public static ITypeBinding getBindingOfParentType(ASTNode node) {
1064                 while (node != null) {
1065                         if (node instanceof AbstractTypeDeclaration) {
1066                                 return ((AbstractTypeDeclaration) node).resolveBinding();
1067                         } else if (node instanceof AnonymousClassDeclaration) {
1068                                 return ((AnonymousClassDeclaration) node).resolveBinding();
1069                         }
1070                         node= node.getParent();
1071                 }
1072                 return null;
1073         }
1074
1075         /**
1076          * Returns the type binding of the node's type context or null if the node is inside
1077          * an annotation, type parameter, super type declaration, or Javadoc of a top level type.
1078          * The result of this method is equal to the result of {@link #getBindingOfParentType(ASTNode)} for nodes in the type's body.
1079          * 
1080          * @param node an AST node
1081          * @return the type binding of the node's parent type context, or <code>null</code>
1082          */
1083         public static ITypeBinding getBindingOfParentTypeContext(ASTNode node) {
1084                 StructuralPropertyDescriptor lastLocation= null;
1085
1086                 while (node != null) {
1087                         if (node instanceof AbstractTypeDeclaration) {
1088                                 AbstractTypeDeclaration decl= (AbstractTypeDeclaration) node;
1089                                 if (lastLocation == decl.getBodyDeclarationsProperty()
1090                                                 || lastLocation == decl.getJavadocProperty()) {
1091                                         return decl.resolveBinding();
1092                                 } else if (decl instanceof EnumDeclaration && lastLocation == EnumDeclaration.ENUM_CONSTANTS_PROPERTY) {
1093                                         return decl.resolveBinding();
1094                                 }
1095                         } else if (node instanceof AnonymousClassDeclaration) {
1096                                 return ((AnonymousClassDeclaration) node).resolveBinding();
1097                         }
1098                         lastLocation= node.getLocationInParent();
1099                         node= node.getParent();
1100                 }
1101                 return null;
1102         }
1103
1104
1105         public static String getRawName(ITypeBinding binding) {
1106                 String name= binding.getName();
1107                 if (binding.isParameterizedType() || binding.isGenericType()) {
1108                         int idx= name.indexOf('<');
1109                         if (idx != -1) {
1110                                 return name.substring(0, idx);
1111                         }
1112                 }
1113                 return name;
1114         }
1115
1116
1117         public static String getRawQualifiedName(ITypeBinding binding) {
1118                 final String EMPTY= ""; //$NON-NLS-1$
1119
1120                 if (binding.isAnonymous() || binding.isLocal()) {
1121                         return EMPTY;
1122                 }
1123
1124                 if (binding.isPrimitive() || binding.isNullType() || binding.isTypeVariable()) {
1125                         return binding.getName();
1126                 }
1127
1128                 if (binding.isArray()) {
1129                         String elementTypeQualifiedName = getRawQualifiedName(binding.getElementType());
1130                         if (elementTypeQualifiedName.length() != 0) {
1131                                 StringBuffer stringBuffer= new StringBuffer(elementTypeQualifiedName);
1132                                 stringBuffer.append('[').append(']');
1133                                 return stringBuffer.toString();
1134                         } else {
1135                                 return EMPTY;
1136                         }
1137                 }
1138                 if (binding.isMember()) {
1139                         String outerName= getRawQualifiedName(binding.getDeclaringClass());
1140                         if (outerName.length() > 0) {
1141                                 StringBuffer buffer= new StringBuffer();
1142                                 buffer.append(outerName);
1143                                 buffer.append('.');
1144                                 buffer.append(getRawName(binding));
1145                                 return buffer.toString();
1146                         } else {
1147                                 return EMPTY;
1148                         }
1149
1150                 } else if (binding.isTopLevel()) {
1151                         IPackageBinding packageBinding= binding.getPackage();
1152                         StringBuffer buffer= new StringBuffer();
1153                         if (packageBinding != null && packageBinding.getName().length() > 0) {
1154                                 buffer.append(packageBinding.getName()).append('.');
1155                         }
1156                         buffer.append(getRawName(binding));
1157                         return buffer.toString();
1158                 }
1159                 return EMPTY;
1160         }
1161
1162
1163         /**
1164          * Tests if the given node is a declaration, not a instance of a generic type, method or field.
1165          * Declarations can be found in AST with CompilationUnit.findDeclaringNode
1166          * @param binding binding to test
1167          * @return returns <code>true</code> if the binding is a declaration binding
1168          */
1169         public static boolean isDeclarationBinding(IBinding binding) {
1170                 switch (binding.getKind()) {
1171                         case IBinding.TYPE:
1172                                 return ((ITypeBinding) binding).getTypeDeclaration() == binding;
1173                         case IBinding.VARIABLE:
1174                                 return ((IVariableBinding) binding).getVariableDeclaration() == binding;
1175                         case IBinding.METHOD:
1176                                 return ((IMethodBinding) binding).getMethodDeclaration() == binding;
1177                 }
1178                 return true;
1179         }
1180
1181
1182         public static IBinding getDeclaration(IBinding binding) {
1183                 switch (binding.getKind()) {
1184                         case IBinding.TYPE:
1185                                 return ((ITypeBinding) binding).getTypeDeclaration();
1186                         case IBinding.VARIABLE:
1187                                 return ((IVariableBinding) binding).getVariableDeclaration();
1188                         case IBinding.METHOD:
1189                                 return ((IMethodBinding) binding).getMethodDeclaration();
1190                 }
1191                 return binding;
1192         }
1193
1194
1195         /**
1196          * @param candidates the candidates
1197          * @param overridable the overriding method
1198          * @return returns <code>true></code> if the overriding method overrides a candidate
1199          * @deprecated Need to review: Use {@link #isSubsignature(IMethodBinding, IMethodBinding)} if the two bindings
1200          * are in the same hierarchy (directly overrides each other), or {@link #findMethodInHierarchy(ITypeBinding, String, ITypeBinding[])}
1201          * else.
1202          */
1203         public static boolean containsSignatureEquivalentConstructor(IMethodBinding[] candidates, IMethodBinding overridable) {
1204                 for (int index= 0; index < candidates.length; index++) {
1205                         if (isSignatureEquivalentConstructor(candidates[index], overridable))
1206                                 return true;
1207                 }
1208                 return false;
1209         }
1210
1211         private static boolean isSignatureEquivalentConstructor(IMethodBinding overridden, IMethodBinding overridable) {
1212
1213                 if (!overridden.isConstructor() || !overridable.isConstructor())
1214                         return false;
1215
1216                 if (overridden.isDefaultConstructor())
1217                         return false;
1218
1219                 return areSubTypeCompatible(overridden, overridable);
1220         }
1221
1222         /**
1223          * @param overridden the overridden method
1224          * @param overridable the overriding method
1225          * @return returns <code>true</code> if the overriding method overrrides the overridden
1226          * @deprecated Need to review: Use {@link #isSubsignature(IMethodBinding, IMethodBinding)} if the two bindings
1227          * are in the same hierarchy (directly overrides each other), or {@link #findMethodInHierarchy(ITypeBinding, String, ITypeBinding[])}
1228          * else.
1229          */
1230         public static boolean areOverriddenMethods(IMethodBinding overridden, IMethodBinding overridable) {
1231
1232                 if (!overridden.getName().equals(overridable.getName()))
1233                         return false;
1234
1235                 return areSubTypeCompatible(overridden, overridable);
1236         }
1237
1238         private static boolean areSubTypeCompatible(IMethodBinding overridden, IMethodBinding overridable) {
1239
1240                 if (overridden.getParameterTypes().length != overridable.getParameterTypes().length)
1241                         return false;
1242
1243                 ITypeBinding overriddenReturn= overridden.getReturnType();
1244                 ITypeBinding overridableReturn= overridable.getReturnType();
1245                 if (overriddenReturn == null || overridableReturn == null)
1246                         return false;
1247
1248                 if (!overriddenReturn.getErasure().isSubTypeCompatible(overridableReturn.getErasure()))
1249                         return false;
1250
1251                 ITypeBinding[] overriddenTypes= overridden.getParameterTypes();
1252                 ITypeBinding[] overridableTypes= overridable.getParameterTypes();
1253                 Assert.isTrue(overriddenTypes.length == overridableTypes.length);
1254                 for (int index= 0; index < overriddenTypes.length; index++) {
1255                         final ITypeBinding overridableErasure= overridableTypes[index].getErasure();
1256                         final ITypeBinding overriddenErasure= overriddenTypes[index].getErasure();
1257                         if (!overridableErasure.isSubTypeCompatible(overriddenErasure) || !overridableErasure.getKey().equals(overriddenErasure.getKey()))
1258                                 return false;
1259                 }
1260                 ITypeBinding[] overriddenExceptions= overridden.getExceptionTypes();
1261                 ITypeBinding[] overridableExceptions= overridable.getExceptionTypes();
1262                 boolean checked= false;
1263                 for (int index= 0; index < overriddenExceptions.length; index++) {
1264                         checked= false;
1265                         for (int offset= 0; offset < overridableExceptions.length; offset++) {
1266                                 if (overriddenExceptions[index].isSubTypeCompatible(overridableExceptions[offset]))
1267                                         checked= true;
1268                         }
1269                         if (!checked)
1270                                 return false;
1271                 }
1272                 return true;
1273         }
1274
1275         /**
1276          * Returns the boxed type binding according to JLS3 5.1.7, or the original binding if
1277          * the given type is not a primitive type.
1278          *
1279          * @param type a type binding
1280          * @param ast an AST to resolve the boxed type
1281          * @return the boxed type, or the original type if no boxed type found
1282          */
1283         public static ITypeBinding getBoxedTypeBinding(ITypeBinding type, AST ast) {
1284                 if (!type.isPrimitive())
1285                         return type;
1286                 String boxedTypeName= getBoxedTypeName(type.getName());
1287                 if (boxedTypeName == null)
1288                         return type;
1289                 ITypeBinding boxed= ast.resolveWellKnownType(boxedTypeName);
1290                 if (boxed == null)
1291                         return type;
1292                 return boxed;
1293         }
1294
1295         private static String getBoxedTypeName(String primitiveName) {
1296                 if ("long".equals(primitiveName)) //$NON-NLS-1$
1297                         return "java.lang.Long"; //$NON-NLS-1$
1298
1299                 else if ("int".equals(primitiveName)) //$NON-NLS-1$
1300                         return "java.lang.Integer"; //$NON-NLS-1$
1301
1302                 else if ("short".equals(primitiveName)) //$NON-NLS-1$
1303                         return "java.lang.Short"; //$NON-NLS-1$
1304
1305                 else if ("char".equals(primitiveName)) //$NON-NLS-1$
1306                         return "java.lang.Character"; //$NON-NLS-1$
1307
1308                 else if ("byte".equals(primitiveName)) //$NON-NLS-1$
1309                         return "java.lang.Byte"; //$NON-NLS-1$
1310
1311                 else if ("boolean".equals(primitiveName)) //$NON-NLS-1$
1312                         return "java.lang.Boolean"; //$NON-NLS-1$
1313
1314                 else if ("float".equals(primitiveName)) //$NON-NLS-1$
1315                         return "java.lang.Float"; //$NON-NLS-1$
1316
1317                 else if ("double".equals(primitiveName)) //$NON-NLS-1$
1318                         return "java.lang.Double"; //$NON-NLS-1$
1319
1320                 else
1321                         return null;
1322         }
1323
1324         /**
1325          * Returns the unboxed type binding according to JLS3 5.1.7, or the original binding if
1326          * the given type is not a boxed type.
1327          *
1328          * @param type a type binding
1329          * @param ast an AST to resolve the unboxed type
1330          * @return the unboxed type, or the original type if no unboxed type found
1331          */
1332         public static ITypeBinding getUnboxedTypeBinding(ITypeBinding type, AST ast) {
1333                 if (!type.isClass())
1334                         return type;
1335                 String unboxedTypeName= getUnboxedTypeName(type.getQualifiedName());
1336                 if (unboxedTypeName == null)
1337                         return type;
1338                 ITypeBinding unboxed= ast.resolveWellKnownType(unboxedTypeName);
1339                 if (unboxed == null)
1340                         return type;
1341                 return unboxed;
1342         }
1343         
1344         private static String getUnboxedTypeName(String boxedName) {
1345                 if ("java.lang.Long".equals(boxedName)) //$NON-NLS-1$
1346                         return "long"; //$NON-NLS-1$
1347                 
1348                 else if ("java.lang.Integer".equals(boxedName)) //$NON-NLS-1$
1349                         return "int"; //$NON-NLS-1$
1350                 
1351                 else if ("java.lang.Short".equals(boxedName)) //$NON-NLS-1$
1352                         return "short"; //$NON-NLS-1$
1353                 
1354                 else if ("java.lang.Character".equals(boxedName)) //$NON-NLS-1$
1355                         return "char"; //$NON-NLS-1$
1356                 
1357                 else if ("java.lang.Byte".equals(boxedName)) //$NON-NLS-1$
1358                         return "byte"; //$NON-NLS-1$
1359                 
1360                 else if ("java.lang.Boolean".equals(boxedName)) //$NON-NLS-1$
1361                         return "boolean"; //$NON-NLS-1$
1362                 
1363                 else if ("java.lang.Float".equals(boxedName)) //$NON-NLS-1$
1364                         return "float"; //$NON-NLS-1$
1365                 
1366                 else if ("java.lang.Double".equals(boxedName)) //$NON-NLS-1$
1367                         return "double"; //$NON-NLS-1$
1368                 
1369                 else
1370                         return null;
1371         }
1372         
1373         /**
1374          * Resolve the binding (<em>not</em> the type binding) for the expression or a nested expression
1375          * (e.g. nested in parentheses, cast, ...).
1376          * 
1377          * @param expression an expression node
1378          * @param goIntoCast iff <code>true</code>, go into a CastExpression's expression to resolve
1379          * @return the expression binding, or <code>null</code> if the expression has no binding or the
1380          *         binding could not be resolved
1381          * 
1382          * @see StubUtility#getVariableNameSuggestions(int, IJavaProject, ITypeBinding, Expression, java.util.Collection)
1383          * @since 3.5
1384          */
1385         public static IBinding resolveExpressionBinding(Expression expression, boolean goIntoCast) {
1386                 //TODO: search for callers of resolve*Binding() methods and replace with call to this method
1387                 
1388                 // similar to StubUtility#getVariableNameSuggestions(int, IJavaProject, ITypeBinding, Expression, Collection)
1389                 switch (expression.getNodeType()) {
1390                         case ASTNode.SIMPLE_NAME:
1391                         case ASTNode.QUALIFIED_NAME:
1392                                 return ((Name) expression).resolveBinding();
1393                                 
1394                         case ASTNode.FIELD_ACCESS:
1395                                 return ((FieldAccess) expression).resolveFieldBinding();
1396                         case ASTNode.SUPER_FIELD_ACCESS:
1397                                 return ((SuperFieldAccess) expression).resolveFieldBinding();
1398                                 
1399                         case ASTNode.METHOD_INVOCATION:
1400                                 return ((MethodInvocation) expression).resolveMethodBinding();
1401                         case ASTNode.SUPER_METHOD_INVOCATION:
1402                                 return ((SuperMethodInvocation) expression).resolveMethodBinding();
1403                         case ASTNode.CLASS_INSTANCE_CREATION:
1404                                 return ((ClassInstanceCreation) expression).resolveConstructorBinding();
1405                                 
1406                         case ASTNode.MARKER_ANNOTATION:
1407                         case ASTNode.SINGLE_MEMBER_ANNOTATION:
1408                         case ASTNode.NORMAL_ANNOTATION:
1409                                 return ((Annotation) expression).resolveAnnotationBinding();
1410                                 
1411                         case ASTNode.ARRAY_ACCESS:
1412                                 return resolveExpressionBinding(((ArrayAccess) expression).getArray(), goIntoCast);
1413                         case ASTNode.CAST_EXPRESSION:
1414                                 if (goIntoCast) {
1415                                         return resolveExpressionBinding(((CastExpression) expression).getExpression(), true);
1416                                 } else {
1417                                         return null;
1418                                 }
1419                         case ASTNode.PARENTHESIZED_EXPRESSION:
1420                                 return resolveExpressionBinding(((ParenthesizedExpression) expression).getExpression(), goIntoCast);
1421                         case ASTNode.PREFIX_EXPRESSION:
1422                                 return resolveExpressionBinding(((PrefixExpression) expression).getOperand(), goIntoCast);
1423                         case ASTNode.POSTFIX_EXPRESSION:
1424                                 return resolveExpressionBinding(((PostfixExpression) expression).getOperand(), goIntoCast);
1425                         default:
1426                                 return null;
1427                 }
1428         }
1429
1430         public static boolean isClassOrRuntimeAnnotation(ITypeBinding annotationType) {
1431                 IAnnotationBinding[] metaAnnotations= annotationType.getAnnotations();
1432                 for (IAnnotationBinding metaAnnotation : metaAnnotations) {
1433                         if ("java.lang.annotation.Retention".equals(metaAnnotation.getAnnotationType().getQualifiedName())) { //$NON-NLS-1$
1434                                 IMemberValuePairBinding[] mvps= metaAnnotation.getDeclaredMemberValuePairs();
1435                                 if (mvps.length == 1) {
1436                                         Object value= mvps[0].getValue();
1437                                         if (value instanceof IVariableBinding) {
1438                                                 String name= ((IVariableBinding) value).getName();
1439                                                 if ("RUNTIME".equals(name) || "CLASS".equals(name)) //$NON-NLS-1$ //$NON-NLS-2$
1440                                                         return true;
1441                                         }
1442                                 }
1443                         }
1444                 }
1445                 return false;
1446         }
1447
1448 }