1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.lookup;
13 import org.eclipse.jdt.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;
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;
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)
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)
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;
51 boolean areMethodsEqual(MethodBinding one, MethodBinding two) {
52 return areParametersEqual(one, two);
54 boolean areParametersEqual(MethodBinding one, MethodBinding two) {
55 TypeBinding[] oneArgs = one.parameters;
56 TypeBinding[] twoArgs = two.parameters;
57 if (oneArgs == twoArgs) return true;
59 int length = oneArgs.length;
60 if (length != twoArgs.length) return false;
62 for (int i = 0; i < length; i++)
63 if (!areTypesEqual(oneArgs[i], twoArgs[i])) return false;
66 boolean areReturnTypesEqual(MethodBinding one, MethodBinding two) {
67 return areTypesEqual(one.returnType, two.returnType);
69 boolean canSkipInheritedMethods() {
70 if (this.type.superclass() != null && this.type.superclass().isAbstract())
72 return this.type.superInterfaces() == NoSuperInterfaces;
74 boolean canSkipInheritedMethods(MethodBinding one, MethodBinding two) {
75 return two == null // already know one is not null
76 || one.declaringClass == two.declaringClass;
78 boolean areTypesEqual(TypeBinding one, TypeBinding two) {
79 if (one == two) return true;
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
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);
98 problemReporter().abstractMethodMustBeImplemented(this.type, abstractMethod);
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);
111 if (inheritedMethod.isAbstract()) {
112 if (inheritedMethod.declaringClass.isInterface()) {
113 currentMethod.modifiers |= CompilerModifiers.AccImplementing;
115 currentMethod.modifiers |= CompilerModifiers.AccImplementing | CompilerModifiers.AccOverriding;
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;
122 currentMethod.modifiers |= CompilerModifiers.AccOverriding;
125 if (isAnnotationMember) {
126 // annotation cannot override any method
127 problemReporter().annotationCannotOverrideMethod(currentMethod, inheritedMethod);
128 return; // do not repoort against subsequent inherited methods
130 if (!areReturnTypesEqual(currentMethod, inheritedMethod)) {
131 problemReporter(currentMethod).incompatibleReturnType(currentMethod, inheritedMethod);
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))
148 problemReporter(currentMethod).overridesDeprecatedMethod(currentMethod, inheritedMethod);
151 checkForBridgeMethod(currentMethod, inheritedMethod);
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).
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*/}
169 if (!(newException.isCompatibleWith(runtimeException()) || newException.isCompatibleWith(errorException())))
170 problemReporter(newMethod).incompatibleExceptionInThrowsClause(this.type, newMethod, inheritedMethod, newException);
173 void checkForBridgeMethod(MethodBinding currentMethod, MethodBinding inheritedMethod) {
176 void checkInheritedMethods(MethodBinding[] methods, int length) {
177 MethodBinding first = methods[0];
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);
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];
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]);
203 problemReporter().abstractMethodMustBeImplemented(this.type, methods[0]);
212 MethodBinding[] abstractMethods = new MethodBinding[length - 1];
214 for (int i = length; --i >= 0;)
215 if (methods[i] != concreteMethod)
216 abstractMethods[index++] = methods[i];
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]);
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
235 if inherited methods = 1
236 if inherited is abstract && type is NOT an interface or abstract, complain
238 if vm signatures do not match complain
240 find the concrete implementation amongst the abstract methods (can only be 1)
242 it must be a public instance method
243 compare concrete's exceptions against each abstract method
245 complain about missing implementation only if type is NOT an interface or abstract
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;
254 MethodBinding[] current = (MethodBinding[]) this.currentMethods.get(methodSelectors[s]);
255 if (current == null && skipInheritedMethods)
256 continue nextSelector;
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;
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
282 checkAgainstInheritedMethods(currentMethod, matchingInherited, index + 1); // pass in the length of matching
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))
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
303 checkInheritedMethods(matchingInherited, index + 1); // pass in the length of matching
304 else if (mustImplementAbstractMethods && index == 0 && matchingInherited[0].isAbstract())
305 checkAbstractMethod(matchingInherited[0]);
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
314 ReferenceBinding superType = this.type.superclass();
315 char[] selector = abstractMethod.selector;
317 if (!superType.isValidBinding()) return;
318 if (!superType.isAbstract()) return; // closer non abstract super type will be flagged instead
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())
326 if (doesMethodOverride(method, abstractMethod))
327 return; // found concrete implementation of abstract method in same package
330 } while ((superType = superType.superclass()) != abstractMethod.declaringClass);
332 // non visible abstract methods cannot be overridden so the type must be defined abstract
333 problemReporter().abstractMethodCannotBeOverridden(this.type, abstractMethod);
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
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
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;
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;
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;
374 allSuperclassesAreAbstract = false;
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())
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);
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))
399 if (!inheritedMethod.isDefault() || inheritedMethod.declaringClass.fPackage == type.fPackage) {
400 if (existingMethods == null) {
401 existingMethods = new MethodBinding[] {inheritedMethod};
403 int length = existingMethods.length;
404 System.arraycopy(existingMethods, 0, existingMethods = new MethodBinding[length + 1], 0, length);
405 existingMethods[length] = inheritedMethod;
407 this.inheritedMethods.put(inheritedMethod.selector, existingMethods);
409 if (nonVisible == null) {
410 nonVisible = new MethodBinding[] {inheritedMethod};
412 int length = nonVisible.length;
413 System.arraycopy(nonVisible, 0, nonVisible = new MethodBinding[length + 1], 0, length);
414 nonVisible[length] = inheritedMethod;
416 nonVisibleDefaultMethods.put(inheritedMethod.selector, nonVisible);
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);
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);
432 superType = superType.superclass();
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;
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};
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;
463 this.inheritedMethods.put(inheritedMethod.selector, existingMethods);
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;
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];
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);
495 MethodBinding computeSubstituteMethod(MethodBinding inheritedMethod, MethodBinding currentMethod) {
496 return inheritedMethod;
498 public boolean doesMethodOverride(MethodBinding method, MethodBinding inheritedMethod) {
499 return areReturnTypesEqual(method, inheritedMethod) && areParametersEqual(method, inheritedMethod);
501 ReferenceBinding errorException() {
502 if (errorException == null)
503 this.errorException = this.type.scope.getJavaLangError();
504 return errorException;
506 boolean isAsVisible(MethodBinding newMethod, MethodBinding inheritedMethod) {
507 if (inheritedMethod.modifiers == newMethod.modifiers) return true;
509 if (newMethod.isPublic()) return true; // Covers everything
510 if (inheritedMethod.isPublic()) return false;
512 if (newMethod.isProtected()) return true;
513 if (inheritedMethod.isProtected()) return false;
515 return !newMethod.isPrivate(); // The inheritedMethod cannot be private since it would not be visible
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);
521 boolean isSameClassOrSubclassOf(ReferenceBinding testClass, ReferenceBinding superclass) {
523 if (testClass == superclass) return true;
524 } while ((testClass = testClass.superclass()) != null);
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
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
540 while (superclass.isAbstract() && !superclass.implementsInterface(declaringClass, false))
541 superclass = superclass.superclass(); // find the first concrete superclass or the superclass which implements the interface
543 return superclass.isAbstract(); // if it is a concrete class then we have already reported problem against it
545 ProblemReporter problemReporter() {
546 return this.type.scope.problemReporter();
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();
554 ReferenceBinding[] resolvedExceptionTypesFor(MethodBinding method) {
555 ReferenceBinding[] exceptions = method.thrownExceptions;
556 if ((method.modifiers & CompilerModifiers.AccUnresolved) == 0)
559 if (!(method.declaringClass instanceof BinaryTypeBinding))
560 return TypeConstants.NoExceptions; // safety check
562 for (int i = exceptions.length; --i >= 0;)
563 exceptions[i] = BinaryTypeBinding.resolveType(exceptions[i], this.environment, true);
566 ReferenceBinding runtimeException() {
567 if (runtimeException == null)
568 this.runtimeException = this.type.scope.getJavaLangRuntimeException();
569 return runtimeException;
571 void verify(SourceTypeBinding someType) {
572 this.type = someType;
574 computeInheritedMethods();
577 public String toString() {
578 StringBuffer buffer = new StringBuffer(10);
579 buffer.append("MethodVerifier for type: "); //$NON-NLS-1$
580 buffer.append(type.readableName());
582 buffer.append("\t-inherited methods: "); //$NON-NLS-1$
583 buffer.append(this.inheritedMethods);
584 return buffer.toString();