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