1/* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the Free 9 * Software Foundation; either version 2 of the License, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21package proguard.classfile.util; 22 23import proguard.classfile.*; 24import proguard.classfile.attribute.CodeAttribute; 25import proguard.classfile.attribute.visitor.AttributeVisitor; 26import proguard.classfile.constant.*; 27import proguard.classfile.constant.visitor.ConstantVisitor; 28import proguard.classfile.instruction.*; 29import proguard.classfile.instruction.visitor.InstructionVisitor; 30import proguard.classfile.visitor.*; 31import proguard.util.StringMatcher; 32 33/** 34 * This InstructionVisitor initializes any constant 35 * <code>Class.get[Declared]{Field,Method}</code> references of all instructions 36 * it visits. More specifically, it fills out the references of string constant 37 * pool entries that refer to a class member in the program class pool or in the 38 * library class pool. 39 * <p> 40 * It optionally prints notes if on usage of 41 * <code>(SomeClass)Class.forName(variable).newInstance()</code>. 42 * <p> 43 * The class hierarchy and references must be initialized before using this 44 * visitor. 45 * 46 * @see ClassSuperHierarchyInitializer 47 * @see ClassReferenceInitializer 48 * 49 * @author Eric Lafortune 50 */ 51public class DynamicMemberReferenceInitializer 52extends SimplifiedVisitor 53implements InstructionVisitor, 54 ConstantVisitor, 55 AttributeVisitor, 56 MemberVisitor 57{ 58 public static final int X = InstructionSequenceMatcher.X; 59 public static final int Y = InstructionSequenceMatcher.Y; 60 public static final int Z = InstructionSequenceMatcher.Z; 61 62 public static final int A = InstructionSequenceMatcher.A; 63 public static final int B = InstructionSequenceMatcher.B; 64 public static final int C = InstructionSequenceMatcher.C; 65 public static final int D = InstructionSequenceMatcher.D; 66 67 68 private final Constant[] GET_FIELD_CONSTANTS = new Constant[] 69 { 70 new MethodrefConstant(1, 2, null, null), 71 new ClassConstant(3, null), 72 new NameAndTypeConstant(4, 5), 73 new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS), 74 new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_FIELD), 75 new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_FIELD), 76 }; 77 78 private final Constant[] GET_DECLARED_FIELD_CONSTANTS = new Constant[] 79 { 80 new MethodrefConstant(1, 2, null, null), 81 new ClassConstant(3, null), 82 new NameAndTypeConstant(4, 5), 83 new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS), 84 new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_DECLARED_FIELD), 85 new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_DECLARED_FIELD), 86 }; 87 88 private final Constant[] GET_METHOD_CONSTANTS = new Constant[] 89 { 90 new MethodrefConstant(1, 2, null, null), 91 new ClassConstant(3, null), 92 new NameAndTypeConstant(4, 5), 93 new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS), 94 new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_METHOD), 95 new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_METHOD), 96 }; 97 98 private final Constant[] GET_DECLARED_METHOD_CONSTANTS = new Constant[] 99 { 100 new MethodrefConstant(1, 2, null, null), 101 new ClassConstant(3, null), 102 new NameAndTypeConstant(4, 5), 103 new Utf8Constant(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS), 104 new Utf8Constant(ClassConstants.INTERNAL_METHOD_NAME_CLASS_GET_DECLARED_METHOD), 105 new Utf8Constant(ClassConstants.INTERNAL_METHOD_TYPE_CLASS_GET_DECLARED_METHOD), 106 }; 107 108 // SomeClass.class.get[Declared]Field("someField"). 109 private final Instruction[] CONSTANT_GET_FIELD_INSTRUCTIONS = new Instruction[] 110 { 111 new ConstantInstruction(InstructionConstants.OP_LDC, X), 112 new ConstantInstruction(InstructionConstants.OP_LDC, Y), 113 new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), 114 }; 115 116 // SomeClass.class.get[Declared]Method("someMethod", new Class[] {}). 117 private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS0 = new Instruction[] 118 { 119 new ConstantInstruction(InstructionConstants.OP_LDC, X), 120 new ConstantInstruction(InstructionConstants.OP_LDC, Y), 121 new SimpleInstruction(InstructionConstants.OP_ICONST_0), 122 new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1), 123 new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), 124 }; 125 126 // SomeClass.class.get[Declared]Method("someMethod", new Class[] { A.class }). 127 private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS1 = new Instruction[] 128 { 129 new ConstantInstruction(InstructionConstants.OP_LDC, X), 130 new ConstantInstruction(InstructionConstants.OP_LDC, Y), 131 new SimpleInstruction(InstructionConstants.OP_ICONST_1), 132 new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1), 133 new SimpleInstruction(InstructionConstants.OP_DUP), 134 new SimpleInstruction(InstructionConstants.OP_ICONST_0), 135 new ConstantInstruction(InstructionConstants.OP_LDC, A), 136 new SimpleInstruction(InstructionConstants.OP_AASTORE), 137 new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), 138 }; 139 140 // SomeClass.class.get[Declared]Method("someMethod", new Class[] { A.class, B.class }). 141 private final Instruction[] CONSTANT_GET_METHOD_INSTRUCTIONS2 = new Instruction[] 142 { 143 new ConstantInstruction(InstructionConstants.OP_LDC, X), 144 new ConstantInstruction(InstructionConstants.OP_LDC, Y), 145 new SimpleInstruction(InstructionConstants.OP_ICONST_2), 146 new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1), 147 new SimpleInstruction(InstructionConstants.OP_DUP), 148 new SimpleInstruction(InstructionConstants.OP_ICONST_0), 149 new ConstantInstruction(InstructionConstants.OP_LDC, A), 150 new SimpleInstruction(InstructionConstants.OP_AASTORE), 151 new SimpleInstruction(InstructionConstants.OP_DUP), 152 new SimpleInstruction(InstructionConstants.OP_ICONST_1), 153 new ConstantInstruction(InstructionConstants.OP_LDC, B), 154 new SimpleInstruction(InstructionConstants.OP_AASTORE), 155 new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), 156 }; 157 158 // get[Declared]Field("someField"). 159 private final Instruction[] GET_FIELD_INSTRUCTIONS = new Instruction[] 160 { 161 new ConstantInstruction(InstructionConstants.OP_LDC, Y), 162 new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), 163 }; 164 165 // get[Declared]Method("someMethod", new Class[] {}). 166 private final Instruction[] GET_METHOD_INSTRUCTIONS0 = new Instruction[] 167 { 168 new ConstantInstruction(InstructionConstants.OP_LDC, Y), 169 new SimpleInstruction(InstructionConstants.OP_ICONST_0), 170 new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1), 171 new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), 172 }; 173 174 // get[Declared]Method("someMethod", new Class[] { A.class }). 175 private final Instruction[] GET_METHOD_INSTRUCTIONS1 = new Instruction[] 176 { 177 new ConstantInstruction(InstructionConstants.OP_LDC, Y), 178 new SimpleInstruction(InstructionConstants.OP_ICONST_1), 179 new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1), 180 new SimpleInstruction(InstructionConstants.OP_DUP), 181 new SimpleInstruction(InstructionConstants.OP_ICONST_0), 182 new ConstantInstruction(InstructionConstants.OP_LDC, A), 183 new SimpleInstruction(InstructionConstants.OP_AASTORE), 184 new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), 185 }; 186 187 // get[Declared]Method("someMethod", new Class[] { A.class, B.class }). 188 private final Instruction[] GET_METHOD_INSTRUCTIONS2 = new Instruction[] 189 { 190 new ConstantInstruction(InstructionConstants.OP_LDC, Y), 191 new SimpleInstruction(InstructionConstants.OP_ICONST_2), 192 new ConstantInstruction(InstructionConstants.OP_ANEWARRAY, 1), 193 new SimpleInstruction(InstructionConstants.OP_DUP), 194 new SimpleInstruction(InstructionConstants.OP_ICONST_0), 195 new ConstantInstruction(InstructionConstants.OP_LDC, A), 196 new SimpleInstruction(InstructionConstants.OP_AASTORE), 197 new SimpleInstruction(InstructionConstants.OP_DUP), 198 new SimpleInstruction(InstructionConstants.OP_ICONST_1), 199 new ConstantInstruction(InstructionConstants.OP_LDC, B), 200 new SimpleInstruction(InstructionConstants.OP_AASTORE), 201 new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 0), 202 }; 203 204 205 private final ClassPool programClassPool; 206 private final ClassPool libraryClassPool; 207 private final WarningPrinter notePrinter; 208 private final StringMatcher noteFieldExceptionMatcher; 209 private final StringMatcher noteMethodExceptionMatcher; 210 211 212 private final InstructionSequenceMatcher constantGetFieldMatcher = 213 new InstructionSequenceMatcher(GET_FIELD_CONSTANTS, 214 CONSTANT_GET_FIELD_INSTRUCTIONS); 215 216 private final InstructionSequenceMatcher constantGetDeclaredFieldMatcher = 217 new InstructionSequenceMatcher(GET_DECLARED_FIELD_CONSTANTS, 218 CONSTANT_GET_FIELD_INSTRUCTIONS); 219 220 private final InstructionSequenceMatcher constantGetMethodMatcher0 = 221 new InstructionSequenceMatcher(GET_METHOD_CONSTANTS, 222 CONSTANT_GET_METHOD_INSTRUCTIONS0); 223 224 private final InstructionSequenceMatcher constantGetDeclaredMethodMatcher0 = 225 new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS, 226 CONSTANT_GET_METHOD_INSTRUCTIONS0); 227 228 private final InstructionSequenceMatcher constantGetMethodMatcher1 = 229 new InstructionSequenceMatcher(GET_METHOD_CONSTANTS, 230 CONSTANT_GET_METHOD_INSTRUCTIONS1); 231 232 private final InstructionSequenceMatcher constantGetDeclaredMethodMatcher1 = 233 new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS, 234 CONSTANT_GET_METHOD_INSTRUCTIONS1); 235 236 private final InstructionSequenceMatcher constantGetMethodMatcher2 = 237 new InstructionSequenceMatcher(GET_METHOD_CONSTANTS, 238 CONSTANT_GET_METHOD_INSTRUCTIONS2); 239 240 private final InstructionSequenceMatcher constantGetDeclaredMethodMatcher2 = 241 new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS, 242 CONSTANT_GET_METHOD_INSTRUCTIONS2); 243 244 private final InstructionSequenceMatcher getFieldMatcher = 245 new InstructionSequenceMatcher(GET_FIELD_CONSTANTS, 246 GET_FIELD_INSTRUCTIONS); 247 248 private final InstructionSequenceMatcher getDeclaredFieldMatcher = 249 new InstructionSequenceMatcher(GET_DECLARED_FIELD_CONSTANTS, 250 GET_FIELD_INSTRUCTIONS); 251 252 private final InstructionSequenceMatcher getMethodMatcher0 = 253 new InstructionSequenceMatcher(GET_METHOD_CONSTANTS, 254 GET_METHOD_INSTRUCTIONS0); 255 256 private final InstructionSequenceMatcher getDeclaredMethodMatcher0 = 257 new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS, 258 GET_METHOD_INSTRUCTIONS0); 259 260 private final InstructionSequenceMatcher getMethodMatcher1 = 261 new InstructionSequenceMatcher(GET_METHOD_CONSTANTS, 262 GET_METHOD_INSTRUCTIONS1); 263 264 private final InstructionSequenceMatcher getDeclaredMethodMatcher1 = 265 new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS, 266 GET_METHOD_INSTRUCTIONS1); 267 268 private final InstructionSequenceMatcher getMethodMatcher2 = 269 new InstructionSequenceMatcher(GET_METHOD_CONSTANTS, 270 GET_METHOD_INSTRUCTIONS2); 271 272 private final InstructionSequenceMatcher getDeclaredMethodMatcher2 = 273 new InstructionSequenceMatcher(GET_DECLARED_METHOD_CONSTANTS, 274 GET_METHOD_INSTRUCTIONS2); 275 276 private final MemberFinder memberFinder = new MemberFinder(); 277 278 279 // Fields acting as parameters for the visitors. 280 private Clazz referencedClass; 281 private boolean isDeclared; 282 private boolean isField; 283 284 285 286 /** 287 * Creates a new DynamicMemberReferenceInitializer. 288 */ 289 public DynamicMemberReferenceInitializer(ClassPool programClassPool, 290 ClassPool libraryClassPool, 291 WarningPrinter notePrinter, 292 StringMatcher noteFieldExceptionMatcher, 293 StringMatcher noteMethodExceptionMatcher) 294 { 295 this.programClassPool = programClassPool; 296 this.libraryClassPool = libraryClassPool; 297 this.notePrinter = notePrinter; 298 this.noteFieldExceptionMatcher = noteFieldExceptionMatcher; 299 this.noteMethodExceptionMatcher = noteMethodExceptionMatcher; 300 } 301 302 303 // Implementations for InstructionVisitor. 304 305 public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) 306 { 307 // Try to match the SomeClass.class.getField("someField") construct. 308 matchGetMember(clazz, method, codeAttribute, offset, instruction, 309 constantGetFieldMatcher, 310 getFieldMatcher, true, false); 311 312 // Try to match the SomeClass.class.getDeclaredField("someField") construct. 313 matchGetMember(clazz, method, codeAttribute, offset, instruction, 314 constantGetDeclaredFieldMatcher, 315 getDeclaredFieldMatcher, true, true); 316 317 // Try to match the SomeClass.class.getMethod("someMethod", new Class[] 318 // {}) construct. 319 matchGetMember(clazz, method, codeAttribute, offset, instruction, 320 constantGetMethodMatcher0, 321 getMethodMatcher0, false, false); 322 323 // Try to match the SomeClass.class.getDeclaredMethod("someMethod", 324 // new Class[] {}) construct. 325 matchGetMember(clazz, method, codeAttribute, offset, instruction, 326 constantGetDeclaredMethodMatcher0, 327 getDeclaredMethodMatcher0, false, true); 328 329 // Try to match the SomeClass.class.getMethod("someMethod", new Class[] 330 // { A.class }) construct. 331 matchGetMember(clazz, method, codeAttribute, offset, instruction, 332 constantGetMethodMatcher1, 333 getMethodMatcher1, false, false); 334 335 // Try to match the SomeClass.class.getDeclaredMethod("someMethod", 336 // new Class[] { A.class }) construct. 337 matchGetMember(clazz, method, codeAttribute, offset, instruction, 338 constantGetDeclaredMethodMatcher1, 339 getDeclaredMethodMatcher1, false, true); 340 341 // Try to match the SomeClass.class.getMethod("someMethod", new Class[] 342 // { A.class, B.class }) construct. 343 matchGetMember(clazz, method, codeAttribute, offset, instruction, 344 constantGetMethodMatcher2, 345 getMethodMatcher2, false, false); 346 347 // Try to match the SomeClass.class.getDeclaredMethod("someMethod", 348 // new Class[] { A.class, B.class }) construct. 349 matchGetMember(clazz, method, codeAttribute, offset, instruction, 350 constantGetDeclaredMethodMatcher2, 351 getDeclaredMethodMatcher2, false, true); 352 } 353 354 355 /** 356 * Tries to match the next instruction and fills out the string constant 357 * or prints out a note accordingly. 358 */ 359 private void matchGetMember(Clazz clazz, 360 Method method, 361 CodeAttribute codeAttribute, 362 int offset, 363 Instruction instruction, 364 InstructionSequenceMatcher constantSequenceMatcher, 365 InstructionSequenceMatcher variableSequenceMatcher, 366 boolean isField, 367 boolean isDeclared) 368 { 369 // Try to match the next instruction in the constant sequence. 370 instruction.accept(clazz, method, codeAttribute, offset, 371 constantSequenceMatcher); 372 373 // Did we find a match to fill out the string constant? 374 if (constantSequenceMatcher.isMatching()) 375 { 376 this.isField = isField; 377 this.isDeclared = isDeclared; 378 379 // Get the member's class. 380 clazz.constantPoolEntryAccept(constantSequenceMatcher.matchedConstantIndex(X), this); 381 382 // Fill out the matched string constant. 383 clazz.constantPoolEntryAccept(constantSequenceMatcher.matchedConstantIndex(Y), this); 384 385 // Don't look for the dynamic construct. 386 variableSequenceMatcher.reset(); 387 } 388 389 // Try to match the next instruction in the variable sequence. 390 instruction.accept(clazz, method, codeAttribute, offset, 391 variableSequenceMatcher); 392 393 // Did we find a match to print out a note? 394 if (variableSequenceMatcher.isMatching()) 395 { 396 // Print out a note about the dynamic invocation. 397 printDynamicInvocationNote(clazz, 398 variableSequenceMatcher, 399 isField, 400 isDeclared); 401 } 402 } 403 404 405 // Implementations for ConstantVisitor. 406 407 /** 408 * Remembers the referenced class. 409 */ 410 public void visitClassConstant(Clazz clazz, ClassConstant classConstant) 411 { 412 // Remember the referenced class. 413 referencedClass = ClassUtil.isInternalArrayType(classConstant.getName(clazz)) ? 414 null : 415 classConstant.referencedClass; 416 } 417 418 419 /** 420 * Fills out the link to the referenced class member. 421 */ 422 public void visitStringConstant(Clazz clazz, StringConstant stringConstant) 423 { 424 if (referencedClass != null) 425 { 426 String name = stringConstant.getString(clazz); 427 428 // See if we can find the referenced class member locally, or 429 // somewhere in the hierarchy. 430 Member referencedMember = isDeclared ? isField ? 431 (Member)referencedClass.findField(name, null) : 432 (Member)referencedClass.findMethod(name, null) : 433 (Member)memberFinder.findMember(clazz, 434 referencedClass, 435 name, 436 null, 437 isField); 438 if (referencedMember != null) 439 { 440 stringConstant.referencedMember = referencedMember; 441 stringConstant.referencedClass = isDeclared ? 442 referencedClass : 443 memberFinder.correspondingClass(); 444 } 445 } 446 } 447 448 449 // Small utility methods. 450 451 /** 452 * Prints out a note on the matched dynamic invocation, if necessary. 453 */ 454 private void printDynamicInvocationNote(Clazz clazz, 455 InstructionSequenceMatcher noteSequenceMatcher, 456 boolean isField, 457 boolean isDeclared) 458 { 459 // Print out a note about the dynamic invocation. 460 if (notePrinter != null && 461 notePrinter.accepts(clazz.getName())) 462 { 463 // Is the class member name in the list of exceptions? 464 StringMatcher noteExceptionMatcher = isField ? 465 noteFieldExceptionMatcher : 466 noteMethodExceptionMatcher; 467 468 int memberNameIndex = noteSequenceMatcher.matchedConstantIndex(Y); 469 String memberName = clazz.getStringString(memberNameIndex); 470 471 if (noteExceptionMatcher == null || 472 !noteExceptionMatcher.matches(memberName)) 473 { 474 // Compose the external member name and partial descriptor. 475 String externalMemberDescription = memberName; 476 477 if (!isField) 478 { 479 externalMemberDescription += '('; 480 for (int count = 0; count < 2; count++) 481 { 482 int memberArgumentIndex = noteSequenceMatcher.matchedConstantIndex(A + count); 483 if (memberArgumentIndex > 0) 484 { 485 if (count > 0) 486 { 487 externalMemberDescription += ','; 488 } 489 String className = clazz.getClassName(memberArgumentIndex); 490 externalMemberDescription += ClassUtil.isInternalArrayType(className) ? 491 ClassUtil.externalType(className) : 492 ClassUtil.externalClassName(className); 493 } 494 } 495 externalMemberDescription += ')'; 496 } 497 498 // Print out the actual note. 499 notePrinter.print(clazz.getName(), 500 "Note: " + 501 ClassUtil.externalClassName(clazz.getName()) + 502 " accesses a " + 503 (isDeclared ? "declared " : "") + 504 (isField ? "field" : "method") + 505 " '" + 506 externalMemberDescription + 507 "' dynamically"); 508 509 // Print out notes about potential candidates. 510 ClassVisitor classVisitor; 511 512 if (isField) 513 { 514 classVisitor = 515 new AllFieldVisitor( 516 new MemberNameFilter(memberName, this)); 517 } 518 else 519 { 520 // Compose the partial method descriptor. 521 String methodDescriptor = "("; 522 for (int count = 0; count < 2; count++) 523 { 524 int memberArgumentIndex = noteSequenceMatcher.matchedConstantIndex(A + count); 525 if (memberArgumentIndex > 0) 526 { 527 if (count > 0) 528 { 529 methodDescriptor += ','; 530 } 531 String className = clazz.getClassName(memberArgumentIndex); 532 methodDescriptor += ClassUtil.isInternalArrayType(className) ? 533 className : 534 ClassUtil.internalTypeFromClassName(className); 535 } 536 } 537 methodDescriptor += ")L///;"; 538 539 classVisitor = 540 new AllMethodVisitor( 541 new MemberNameFilter(memberName, 542 new MemberDescriptorFilter(methodDescriptor, this))); 543 } 544 545 programClassPool.classesAcceptAlphabetically(classVisitor); 546 libraryClassPool.classesAcceptAlphabetically(classVisitor); 547 } 548 } 549 } 550 551 552 // Implementations for MemberVisitor. 553 554 public void visitProgramField(ProgramClass programClass, ProgramField programField) 555 { 556 if (notePrinter.accepts(programClass.getName())) 557 { 558 System.out.println(" Maybe this is program field '" + 559 ClassUtil.externalFullClassDescription(0, programClass.getName()) + 560 " { " + 561 ClassUtil.externalFullFieldDescription(0, programField.getName(programClass), programField.getDescriptor(programClass)) + 562 "; }'"); 563 } 564 } 565 566 567 public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) 568 { 569 if (notePrinter.accepts(programClass.getName())) 570 { 571 System.out.println(" Maybe this is program method '" + 572 ClassUtil.externalFullClassDescription(0, programClass.getName()) + 573 " { " + 574 ClassUtil.externalFullMethodDescription(null, 0, programMethod.getName(programClass), programMethod.getDescriptor(programClass)) + 575 "; }'"); 576 } 577 } 578 579 580 public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) 581 { 582 if (notePrinter.accepts(libraryClass.getName())) 583 { 584 System.out.println(" Maybe this is library field '" + 585 ClassUtil.externalFullClassDescription(0, libraryClass.getName()) + 586 " { " + 587 ClassUtil.externalFullFieldDescription(0, libraryField.getName(libraryClass), libraryField.getDescriptor(libraryClass)) + 588 "; }'"); 589 } 590 } 591 592 593 public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) 594 { 595 if (notePrinter.accepts(libraryClass.getName())) 596 { 597 System.out.println(" Maybe this is library method '" + 598 ClassUtil.externalFullClassDescription(0, libraryClass.getName()) + 599 " { " + 600 ClassUtil.externalFullMethodDescription(null, 0, libraryMethod.getName(libraryClass), libraryMethod.getDescriptor(libraryClass)) + 601 "; }'"); 602 } 603 } 604}