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