added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / lookup / MethodVerifier.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.internal.compiler.ast.MethodDeclaration;
14 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
15 import org.eclipse.jdt.internal.compiler.env.IConstants;
16 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
17 import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
18
19 public class MethodVerifier implements TagBits, TypeConstants {
20         SourceTypeBinding type;
21         HashtableOfObject inheritedMethods;
22         HashtableOfObject currentMethods;
23         ReferenceBinding runtimeException;
24         ReferenceBinding errorException;
25         LookupEnvironment environment;
26 /*
27 Binding creation is responsible for reporting all problems with types:
28         - all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations - abstract/final)
29                 - plus invalid modifiers given the context (the verifier did not do this before)
30         - qualified name collisions between a type and a package (types in default packages are excluded)
31         - all type hierarchy problems:
32                 - cycles in the superclass or superinterface hierarchy
33                 - an ambiguous, invisible or missing superclass or superinterface
34                 - extending a final class
35                 - extending an interface instead of a class
36                 - implementing a class instead of an interface
37                 - implementing the same interface more than once (ie. duplicate interfaces)
38         - with nested types:
39                 - shadowing an enclosing type's source name
40                 - defining a static class or interface inside a non-static nested class
41                 - defining an interface as a local type (local types can only be classes)
42 */
43 MethodVerifier(LookupEnvironment environment) {
44         this.type = null;  // Initialized with the public method verify(SourceTypeBinding)
45         this.inheritedMethods = null;
46         this.currentMethods = null;
47         this.runtimeException = null;
48         this.errorException = null;
49         this.environment = environment;
50 }
51 boolean areMethodsEqual(MethodBinding one, MethodBinding two) {
52         return areParametersEqual(one, two);
53 }
54 boolean areParametersEqual(MethodBinding one, MethodBinding two) {
55         TypeBinding[] oneArgs = one.parameters;
56         TypeBinding[] twoArgs = two.parameters;
57         if (oneArgs == twoArgs) return true;
58
59         int length = oneArgs.length;
60         if (length != twoArgs.length) return false;
61
62         for (int i = 0; i < length; i++)
63                 if (!areTypesEqual(oneArgs[i], twoArgs[i])) return false;
64         return true;
65 }
66 boolean areReturnTypesEqual(MethodBinding one, MethodBinding two) {
67         return areTypesEqual(one.returnType, two.returnType);
68 }
69 boolean canSkipInheritedMethods() {
70         if (this.type.superclass() != null && this.type.superclass().isAbstract())
71                 return false;
72         return this.type.superInterfaces() == NoSuperInterfaces;
73 }
74 boolean canSkipInheritedMethods(MethodBinding one, MethodBinding two) {
75         return two == null // already know one is not null
76                 || one.declaringClass == two.declaringClass;
77 }
78 boolean areTypesEqual(TypeBinding one, TypeBinding two) {
79         if (one == two) return true;
80
81         // its possible that an UnresolvedReferenceBinding can be compared to its resolved type
82         // when they're both UnresolvedReferenceBindings then they must be identical like all other types
83         // all wrappers of UnresolvedReferenceBindings are converted as soon as the type is resolved
84         // so its not possible to have 2 arrays where one is UnresolvedX[] and the other is X[]
85         if (one instanceof UnresolvedReferenceBinding)
86                 return ((UnresolvedReferenceBinding) one).resolvedType == two;
87         if (two instanceof UnresolvedReferenceBinding)
88                 return ((UnresolvedReferenceBinding) two).resolvedType == one;
89         return false; // all other type bindings are identical
90 }
91 void checkAbstractMethod(MethodBinding abstractMethod) {
92         if (mustImplementAbstractMethod(abstractMethod.declaringClass)) {
93                 TypeDeclaration typeDeclaration = this.type.scope.referenceContext;
94                 if (typeDeclaration != null) {
95                         MethodDeclaration missingAbstractMethod = typeDeclaration.addMissingAbstractMethodFor(abstractMethod);
96                         missingAbstractMethod.scope.problemReporter().abstractMethodMustBeImplemented(this.type, abstractMethod);
97                 } else {
98                         problemReporter().abstractMethodMustBeImplemented(this.type, abstractMethod);
99                 }
100         }
101 }
102 void checkAgainstInheritedMethods(MethodBinding currentMethod, MethodBinding[] methods, int length) {
103         boolean isAnnotationMember = this.type.isAnnotationType();
104         nextMethod : for (int i = length; --i >= 0;) {
105                 MethodBinding inheritedMethod = methods[i];
106                 if (currentMethod.isStatic() != inheritedMethod.isStatic()) {  // Cannot override a static method or hide an instance method
107                         problemReporter(currentMethod).staticAndInstanceConflict(currentMethod, inheritedMethod);
108                         continue nextMethod;
109                 }
110
111                 if (inheritedMethod.isAbstract()) {
112                         if (inheritedMethod.declaringClass.isInterface()) {
113                                 currentMethod.modifiers |= CompilerModifiers.AccImplementing;
114                         } else {
115                                 currentMethod.modifiers |= CompilerModifiers.AccImplementing | CompilerModifiers.AccOverriding;
116                         }
117 // with the above change an abstract method is tagged as implementing the inherited abstract method
118 //              if (!currentMethod.isAbstract() && inheritedMethod.isAbstract()) {
119 //                      if ((currentMethod.modifiers & CompilerModifiers.AccOverriding) == 0)
120 //                              currentMethod.modifiers |= CompilerModifiers.AccImplementing;
121                 } else {
122                         currentMethod.modifiers |= CompilerModifiers.AccOverriding;
123                 }
124
125                 if (isAnnotationMember) {
126                         // annotation cannot override any method
127                         problemReporter().annotationCannotOverrideMethod(currentMethod, inheritedMethod);
128                         return; // do not repoort against subsequent inherited methods
129                 }               
130                 if (!areReturnTypesEqual(currentMethod, inheritedMethod)) {
131                         problemReporter(currentMethod).incompatibleReturnType(currentMethod, inheritedMethod);
132                 } else {
133                         if (currentMethod.thrownExceptions != NoExceptions)
134                                 checkExceptions(currentMethod, inheritedMethod);
135                         if (inheritedMethod.isFinal())
136                                 problemReporter(currentMethod).finalMethodCannotBeOverridden(currentMethod, inheritedMethod);
137                         if (!isAsVisible(currentMethod, inheritedMethod))
138                                 problemReporter(currentMethod).visibilityConflict(currentMethod, inheritedMethod);
139                         if (environment.options.reportDeprecationWhenOverridingDeprecatedMethod && inheritedMethod.isViewedAsDeprecated()) {
140                                 if (!currentMethod.isViewedAsDeprecated() || environment.options.reportDeprecationInsideDeprecatedCode) {
141                                         // check against the other inherited methods to see if they hide this inheritedMethod
142                                         ReferenceBinding declaringClass = inheritedMethod.declaringClass;
143                                         if (declaringClass.isInterface())
144                                                 for (int j = length; --j >= 0;)
145                                                         if (i != j && methods[j].declaringClass.implementsInterface(declaringClass, false))
146                                                                 continue nextMethod;
147
148                                         problemReporter(currentMethod).overridesDeprecatedMethod(currentMethod, inheritedMethod);
149                                 }
150                         }
151                         checkForBridgeMethod(currentMethod, inheritedMethod);
152                 }
153         }
154 }
155 /*
156 "8.4.4"
157 Verify that newExceptions are all included in inheritedExceptions.
158 Assumes all exceptions are valid and throwable.
159 Unchecked exceptions (compatible with runtime & error) are ignored (see the spec on pg. 203).
160 */
161 void checkExceptions(MethodBinding newMethod, MethodBinding inheritedMethod) {
162         ReferenceBinding[] newExceptions = resolvedExceptionTypesFor(newMethod);
163         ReferenceBinding[] inheritedExceptions = resolvedExceptionTypesFor(inheritedMethod);
164         for (int i = newExceptions.length; --i >= 0;) {
165                 ReferenceBinding newException = newExceptions[i];
166                 int j = inheritedExceptions.length;
167                 while (--j > -1 && !isSameClassOrSubclassOf(newException, inheritedExceptions[j])){/*empty*/}
168                 if (j == -1)
169                         if (!(newException.isCompatibleWith(runtimeException()) || newException.isCompatibleWith(errorException())))
170                                 problemReporter(newMethod).incompatibleExceptionInThrowsClause(this.type, newMethod, inheritedMethod, newException);
171         }
172 }
173 void checkForBridgeMethod(MethodBinding currentMethod, MethodBinding inheritedMethod) {
174         // no op before 1.5
175 }
176 void checkInheritedMethods(MethodBinding[] methods, int length) {
177         MethodBinding first = methods[0];
178         int index = length;
179         while (--index > 0 && areReturnTypesEqual(first, methods[index])){/*empty*/}
180         if (index > 0) {  // All inherited methods do NOT have the same vmSignature
181                 problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(this.type, methods, length);
182                 return;
183         }
184
185         MethodBinding concreteMethod = null;
186         if (!type.isInterface()) {  // ignore concrete methods for interfaces
187                 for (int i = length; --i >= 0;) {  // Remember that only one of the methods can be non-abstract
188                         if (!methods[i].isAbstract()) {
189                                 concreteMethod = methods[i];
190                                 break;
191                         }
192                 }
193         }
194         if (concreteMethod == null) {
195                 if (this.type.isClass() && !this.type.isAbstract()) {
196                         for (int i = length; --i >= 0;) {
197                                 if (mustImplementAbstractMethod(methods[i].declaringClass)) {
198                                         TypeDeclaration typeDeclaration = this.type.scope.referenceContext;
199                                         if (typeDeclaration != null) {
200                                                 MethodDeclaration missingAbstractMethod = typeDeclaration.addMissingAbstractMethodFor(methods[0]);
201                                                 missingAbstractMethod.scope.problemReporter().abstractMethodMustBeImplemented(this.type, methods[0]);
202                                         } else {
203                                                 problemReporter().abstractMethodMustBeImplemented(this.type, methods[0]);
204                                         }
205                                         return;
206                                 }
207                         }
208                 }
209                 return;
210         }
211
212         MethodBinding[] abstractMethods = new MethodBinding[length - 1];
213         index = 0;
214         for (int i = length; --i >= 0;)
215                 if (methods[i] != concreteMethod)
216                         abstractMethods[index++] = methods[i];
217
218         // Remember that interfaces can only define public instance methods
219         if (concreteMethod.isStatic())
220                 // Cannot inherit a static method which is specified as an instance method by an interface
221                 problemReporter().staticInheritedMethodConflicts(type, concreteMethod, abstractMethods);        
222         if (!concreteMethod.isPublic())
223                 // Cannot reduce visibility of a public method specified by an interface
224                 problemReporter().inheritedMethodReducesVisibility(type, concreteMethod, abstractMethods);
225         if (concreteMethod.thrownExceptions != NoExceptions)
226                 for (int i = abstractMethods.length; --i >= 0;)
227                         checkExceptions(concreteMethod, abstractMethods[i]);
228 }
229 /*
230 For each inherited method identifier (message pattern - vm signature minus the return type)
231         if current method exists
232                 if current's vm signature does not match an inherited signature then complain 
233                 else compare current's exceptions & visibility against each inherited method
234         else
235                 if inherited methods = 1
236                         if inherited is abstract && type is NOT an interface or abstract, complain
237                 else
238                         if vm signatures do not match complain
239                         else
240                                 find the concrete implementation amongst the abstract methods (can only be 1)
241                                 if one exists then
242                                         it must be a public instance method
243                                         compare concrete's exceptions against each abstract method
244                                 else
245                                         complain about missing implementation only if type is NOT an interface or abstract
246 */
247 void checkMethods() {
248         boolean mustImplementAbstractMethods = ((this.type.modifiers & IConstants.AccInterface) == 0) && !this.type.isAbstract();
249         boolean skipInheritedMethods = mustImplementAbstractMethods && canSkipInheritedMethods(); // have a single concrete superclass so only check overridden methods
250         char[][] methodSelectors = this.inheritedMethods.keyTable;
251         nextSelector : for (int s = methodSelectors.length; --s >= 0;) {
252                 if (methodSelectors[s] == null) continue nextSelector;
253
254                 MethodBinding[] current = (MethodBinding[]) this.currentMethods.get(methodSelectors[s]);
255                 if (current == null && skipInheritedMethods)
256                         continue nextSelector;
257
258                 MethodBinding[] inherited = (MethodBinding[]) this.inheritedMethods.valueTable[s];
259                 if (inherited.length == 1 && current == null) { // handle the common case
260                         if (mustImplementAbstractMethods && inherited[0].isAbstract())
261                                 checkAbstractMethod(inherited[0]);
262                         continue nextSelector;
263                 }
264
265                 int index = -1;
266                 MethodBinding[] matchingInherited = new MethodBinding[inherited.length];
267                 if (current != null) {
268                         for (int i = 0, length1 = current.length; i < length1; i++) {
269                                 while (index >= 0) matchingInherited[index--] = null; // clear the previous contents of the matching methods
270                                 MethodBinding currentMethod = current[i];
271                                 for (int j = 0, length2 = inherited.length; j < length2; j++) {
272                                         MethodBinding inheritedMethod = inherited[j];
273                                         if (inheritedMethod != null) {
274                                                 inheritedMethod = computeSubstituteMethod(inheritedMethod, currentMethod);
275                                                 if (areMethodsEqual(currentMethod, inheritedMethod)) {
276                                                         matchingInherited[++index] = inheritedMethod;
277                                                         inherited[j] = null; // do not want to find it again
278                                                 }
279                                         }
280                                 }
281                                 if (index >= 0)
282                                         checkAgainstInheritedMethods(currentMethod, matchingInherited, index + 1); // pass in the length of matching
283                         }
284                 }
285
286                 for (int i = 0, length = inherited.length; i < length; i++) {
287                         while (index >= 0) matchingInherited[index--] = null; // clear the previous contents of the matching methods
288                         MethodBinding inheritedMethod = inherited[i];
289                         if (inheritedMethod != null) {
290                                 matchingInherited[++index] = inheritedMethod;
291                                 for (int j = i + 1; j < length; j++) {
292                                         MethodBinding otherInheritedMethod = inherited[j];
293                                         if (canSkipInheritedMethods(inheritedMethod, otherInheritedMethod))
294                                                 continue;
295                                         otherInheritedMethod = computeSubstituteMethod(otherInheritedMethod, inheritedMethod);
296                                         if (areMethodsEqual(inheritedMethod, otherInheritedMethod)) {
297                                                 matchingInherited[++index] = otherInheritedMethod;
298                                                 inherited[j] = null; // do not want to find it again
299                                         }
300                                 }
301                         }
302                         if (index > 0)
303                                 checkInheritedMethods(matchingInherited, index + 1); // pass in the length of matching
304                         else if (mustImplementAbstractMethods && index == 0 && matchingInherited[0].isAbstract())
305                                 checkAbstractMethod(matchingInherited[0]);
306                 }
307         }
308 }
309 void checkPackagePrivateAbstractMethod(MethodBinding abstractMethod) {
310         // check that the inherited abstract method (package private visibility) is implemented within the same package
311         PackageBinding necessaryPackage = abstractMethod.declaringClass.fPackage;
312         if (necessaryPackage == this.type.fPackage) return; // not a problem
313
314         ReferenceBinding superType = this.type.superclass();
315         char[] selector = abstractMethod.selector;
316         do {
317                 if (!superType.isValidBinding()) return;
318                 if (!superType.isAbstract()) return; // closer non abstract super type will be flagged instead
319
320                 if (necessaryPackage == superType.fPackage) {
321                         MethodBinding[] methods = superType.getMethods(selector);
322                         nextMethod : for (int m = methods.length; --m >= 0;) {
323                                 MethodBinding method = methods[m];
324                                 if (method.isPrivate() || method.isConstructor() || method.isDefaultAbstract())
325                                         continue nextMethod;
326                                 if (doesMethodOverride(method, abstractMethod))
327                                         return; // found concrete implementation of abstract method in same package
328                         }
329                 }
330         } while ((superType = superType.superclass()) != abstractMethod.declaringClass);
331
332         // non visible abstract methods cannot be overridden so the type must be defined abstract
333         problemReporter().abstractMethodCannotBeOverridden(this.type, abstractMethod);
334 }
335 /*
336 Binding creation is responsible for reporting:
337         - all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations)
338                 - plus invalid modifiers given the context... examples:
339                         - interface methods can only be public
340                         - abstract methods can only be defined by abstract classes
341         - collisions... 2 methods with identical vmSelectors
342         - multiple methods with the same message pattern but different return types
343         - ambiguous, invisible or missing return/argument/exception types
344         - check the type of any array is not void
345         - check that each exception type is Throwable or a subclass of it
346 */
347 void computeInheritedMethods() {
348         // only want to remember inheritedMethods that can have an impact on the current type
349         // if an inheritedMethod has been 'replaced' by a supertype's method then skip it
350
351         this.inheritedMethods = new HashtableOfObject(51); // maps method selectors to an array of methods... must search to match paramaters & return type
352         ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[3][];
353         int lastPosition = -1;
354         ReferenceBinding[] itsInterfaces = type.superInterfaces();
355         if (itsInterfaces != NoSuperInterfaces)
356                 interfacesToVisit[++lastPosition] = itsInterfaces;
357
358         ReferenceBinding superType = (this.type.modifiers & IConstants.AccInterface) == 0
359                 ? this.type.superclass() // class or enum
360                 : this.type.scope.getJavaLangObject(); // check interface methods against Object
361         HashtableOfObject nonVisibleDefaultMethods = new HashtableOfObject(3); // maps method selectors to an array of methods
362         boolean allSuperclassesAreAbstract = true;
363
364         while (superType != null && superType.isValidBinding()) {
365             if (allSuperclassesAreAbstract) {
366                     if (superType.isAbstract()) {
367                                 // only need to include superinterfaces if immediate superclasses are abstract
368                                 if ((itsInterfaces = superType.superInterfaces()) != NoSuperInterfaces) {
369                                         if (++lastPosition == interfacesToVisit.length)
370                                                 System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
371                                         interfacesToVisit[lastPosition] = itsInterfaces;
372                                 }
373                         } else {
374                             allSuperclassesAreAbstract = false;
375                         }
376                 }
377
378                 MethodBinding[] methods = superType.unResolvedMethods();
379                 nextMethod : for (int m = methods.length; --m >= 0;) {
380                         MethodBinding inheritedMethod = methods[m];
381                         if (inheritedMethod.isPrivate() || inheritedMethod.isConstructor() || inheritedMethod.isDefaultAbstract())
382                                 continue nextMethod;
383                         MethodBinding[] existingMethods = (MethodBinding[]) this.inheritedMethods.get(inheritedMethod.selector);
384                         if (existingMethods != null) {
385                                 for (int i = 0, length = existingMethods.length; i < length; i++) {
386                                         if (existingMethods[i].declaringClass != inheritedMethod.declaringClass && doesMethodOverride(existingMethods[i], inheritedMethod)) {
387                                                 if (inheritedMethod.isDefault() && inheritedMethod.isAbstract())
388                                                         checkPackagePrivateAbstractMethod(inheritedMethod);
389                                                 continue nextMethod;
390                                         }
391                                 }
392                         }
393                         MethodBinding[] nonVisible = (MethodBinding[]) nonVisibleDefaultMethods.get(inheritedMethod.selector);
394                         if (nonVisible != null)
395                                 for (int i = 0, l = nonVisible.length; i < l; i++)
396                                         if (doesMethodOverride(nonVisible[i], inheritedMethod))
397                                                 continue nextMethod;
398
399                         if (!inheritedMethod.isDefault() || inheritedMethod.declaringClass.fPackage == type.fPackage) {
400                                 if (existingMethods == null) {
401                                         existingMethods = new MethodBinding[] {inheritedMethod};
402                                 } else {
403                                         int length = existingMethods.length;
404                                         System.arraycopy(existingMethods, 0, existingMethods = new MethodBinding[length + 1], 0, length);
405                                         existingMethods[length] = inheritedMethod;
406                                 }
407                                 this.inheritedMethods.put(inheritedMethod.selector, existingMethods);
408                         } else {
409                                 if (nonVisible == null) {
410                                         nonVisible = new MethodBinding[] {inheritedMethod};
411                                 } else {
412                                         int length = nonVisible.length;
413                                         System.arraycopy(nonVisible, 0, nonVisible = new MethodBinding[length + 1], 0, length);
414                                         nonVisible[length] = inheritedMethod;
415                                 }
416                                 nonVisibleDefaultMethods.put(inheritedMethod.selector, nonVisible);
417
418                                 if (inheritedMethod.isAbstract() && !this.type.isAbstract()) // non visible abstract methods cannot be overridden so the type must be defined abstract
419                                         problemReporter().abstractMethodCannotBeOverridden(this.type, inheritedMethod);
420
421                                 MethodBinding[] current = (MethodBinding[]) this.currentMethods.get(inheritedMethod.selector);
422                                 if (current != null) { // non visible methods cannot be overridden so a warning is issued
423                                         foundMatch : for (int i = 0, length = current.length; i < length; i++) {
424                                                 if (doesMethodOverride(current[i], inheritedMethod)) {
425                                                         problemReporter().overridesPackageDefaultMethod(current[i], inheritedMethod);
426                                                         break foundMatch;
427                                                 }
428                                         }
429                                 }
430                         }
431                 }
432                 superType = superType.superclass();
433         }
434
435         for (int i = 0; i <= lastPosition; i++) {
436                 ReferenceBinding[] interfaces = interfacesToVisit[i];
437                 for (int j = 0, l = interfaces.length; j < l; j++) {
438                         superType = interfaces[j];
439                         if ((superType.tagBits & InterfaceVisited) == 0) {
440                                 superType.tagBits |= InterfaceVisited;
441                                 if (superType.isValidBinding()) {
442                                         if ((itsInterfaces = superType.superInterfaces()) != NoSuperInterfaces) {
443                                                 if (++lastPosition == interfacesToVisit.length)
444                                                         System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
445                                                 interfacesToVisit[lastPosition] = itsInterfaces;
446                                         }
447
448                                         MethodBinding[] methods = superType.unResolvedMethods();
449                                         nextMethod : for (int m = methods.length; --m >= 0;) { // Interface methods are all abstract public
450                                                 MethodBinding inheritedMethod = methods[m];
451                                                 MethodBinding[] existingMethods = (MethodBinding[]) this.inheritedMethods.get(inheritedMethod.selector);
452                                                 if (existingMethods == null) {
453                                                         existingMethods = new MethodBinding[] {inheritedMethod};
454                                                 } else {
455                                                         int length = existingMethods.length;
456                                                         // look to see if any of the existingMethods implement this inheritedMethod
457                                                         for (int e = 0; e < length; e++)
458                                                                 if (isInterfaceMethodImplemented(inheritedMethod, existingMethods[e], superType))
459                                                                         continue nextMethod; // skip interface method with the same signature if visible to its declaringClass
460                                                         System.arraycopy(existingMethods, 0, existingMethods = new MethodBinding[length + 1], 0, length);
461                                                         existingMethods[length] = inheritedMethod;
462                                                 }
463                                                 this.inheritedMethods.put(inheritedMethod.selector, existingMethods);
464                                         }
465                                 }
466                         }
467                 }
468         }
469
470         // bit reinitialization
471         for (int i = 0; i <= lastPosition; i++) {
472                 ReferenceBinding[] interfaces = interfacesToVisit[i];
473                 for (int j = 0, length = interfaces.length; j < length; j++)
474                         interfaces[j].tagBits &= ~InterfaceVisited;
475         }
476 }
477 void computeMethods() {
478         MethodBinding[] methods = type.methods();
479         int size = methods.length;
480         this.currentMethods = new HashtableOfObject(size == 0 ? 1 : size); // maps method selectors to an array of methods... must search to match paramaters & return type
481         for (int m = size; --m >= 0;) {
482                 MethodBinding method = methods[m];
483                 if (!(method.isConstructor() || method.isDefaultAbstract())) { // keep all methods which are NOT constructors or default abstract
484                         MethodBinding[] existingMethods = (MethodBinding[]) this.currentMethods.get(method.selector);
485                         if (existingMethods == null)
486                                 existingMethods = new MethodBinding[1];
487                         else
488                                 System.arraycopy(existingMethods, 0,
489                                         (existingMethods = new MethodBinding[existingMethods.length + 1]), 0, existingMethods.length - 1);
490                         existingMethods[existingMethods.length - 1] = method;
491                         this.currentMethods.put(method.selector, existingMethods);
492                 }
493         }
494 }
495 MethodBinding computeSubstituteMethod(MethodBinding inheritedMethod, MethodBinding currentMethod) {
496         return inheritedMethod;
497 }
498 public boolean doesMethodOverride(MethodBinding method, MethodBinding inheritedMethod) {
499         return areReturnTypesEqual(method, inheritedMethod) && areParametersEqual(method, inheritedMethod);
500 }
501 ReferenceBinding errorException() {
502         if (errorException == null)
503                 this.errorException = this.type.scope.getJavaLangError();
504         return errorException;
505 }
506 boolean isAsVisible(MethodBinding newMethod, MethodBinding inheritedMethod) {
507         if (inheritedMethod.modifiers == newMethod.modifiers) return true;
508
509         if (newMethod.isPublic()) return true;          // Covers everything
510         if (inheritedMethod.isPublic()) return false;
511
512         if (newMethod.isProtected()) return true;
513         if (inheritedMethod.isProtected()) return false;
514
515         return !newMethod.isPrivate();          // The inheritedMethod cannot be private since it would not be visible
516 }
517 boolean isInterfaceMethodImplemented(MethodBinding inheritedMethod, MethodBinding existingMethod, ReferenceBinding superType) {
518         // skip interface method with the same signature if visible to its declaringClass
519         return areParametersEqual(existingMethod, inheritedMethod) && existingMethod.declaringClass.implementsInterface(superType, true);
520 }
521 boolean isSameClassOrSubclassOf(ReferenceBinding testClass, ReferenceBinding superclass) {
522         do {
523                 if (testClass == superclass) return true;
524         } while ((testClass = testClass.superclass()) != null);
525         return false;
526 }
527 boolean mustImplementAbstractMethod(ReferenceBinding declaringClass) {
528         // if the type's superclass is an abstract class, then all abstract methods must be implemented
529         // otherwise, skip it if the type's superclass must implement any of the inherited methods
530         ReferenceBinding superclass = this.type.superclass();
531         if (declaringClass.isClass()) {
532                 while (superclass.isAbstract() && superclass != declaringClass)
533                         superclass = superclass.superclass(); // find the first concrete superclass or the abstract declaringClass
534         } else {
535                 if (this.type.implementsInterface(declaringClass, false)) {
536                         if (this.type.isAbstract()) return false; // leave it for the subclasses
537                         if (!superclass.implementsInterface(declaringClass, true)) // only if a superclass does not also implement the interface
538                                 return true;
539                 }
540                 while (superclass.isAbstract() && !superclass.implementsInterface(declaringClass, false))
541                         superclass = superclass.superclass(); // find the first concrete superclass or the superclass which implements the interface
542         }
543         return superclass.isAbstract();         // if it is a concrete class then we have already reported problem against it
544 }
545 ProblemReporter problemReporter() {
546         return this.type.scope.problemReporter();
547 }
548 ProblemReporter problemReporter(MethodBinding currentMethod) {
549         ProblemReporter reporter = problemReporter();
550         if (currentMethod.declaringClass == type)       // only report against the currentMethod if its implemented by the type
551                 reporter.referenceContext = currentMethod.sourceMethod();
552         return reporter;
553 }
554 ReferenceBinding[] resolvedExceptionTypesFor(MethodBinding method) {
555         ReferenceBinding[] exceptions = method.thrownExceptions;
556         if ((method.modifiers & CompilerModifiers.AccUnresolved) == 0)
557                 return exceptions;
558
559         if (!(method.declaringClass instanceof BinaryTypeBinding))
560                 return TypeConstants.NoExceptions; // safety check
561
562         for (int i = exceptions.length; --i >= 0;)
563                 exceptions[i] = BinaryTypeBinding.resolveType(exceptions[i], this.environment, true);
564         return exceptions;
565 }
566 ReferenceBinding runtimeException() {
567         if (runtimeException == null)
568                 this.runtimeException = this.type.scope.getJavaLangRuntimeException();
569         return runtimeException;
570 }
571 void verify(SourceTypeBinding someType) {
572         this.type = someType;
573         computeMethods();
574         computeInheritedMethods();
575         checkMethods();
576 }
577 public String toString() {
578         StringBuffer buffer = new StringBuffer(10);
579         buffer.append("MethodVerifier for type: "); //$NON-NLS-1$
580         buffer.append(type.readableName());
581         buffer.append('\n');
582         buffer.append("\t-inherited methods: "); //$NON-NLS-1$
583         buffer.append(this.inheritedMethods);
584         return buffer.toString();
585 }
586 }