1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tools.layoutlib.create; 18 19 import org.objectweb.asm.AnnotationVisitor; 20 import org.objectweb.asm.Attribute; 21 import org.objectweb.asm.ClassReader; 22 import org.objectweb.asm.ClassVisitor; 23 import org.objectweb.asm.FieldVisitor; 24 import org.objectweb.asm.Label; 25 import org.objectweb.asm.MethodVisitor; 26 import org.objectweb.asm.Type; 27 import org.objectweb.asm.signature.SignatureReader; 28 import org.objectweb.asm.signature.SignatureVisitor; 29 30 import java.io.IOException; 31 import java.util.ArrayList; 32 import java.util.Enumeration; 33 import java.util.List; 34 import java.util.Map; 35 import java.util.TreeMap; 36 import java.util.Map.Entry; 37 import java.util.regex.Pattern; 38 import java.util.zip.ZipEntry; 39 import java.util.zip.ZipFile; 40 41 /** 42 * Analyzes the input JAR using the ASM java bytecode manipulation library 43 * to list the desired classes and their dependencies. 44 */ 45 public class AsmAnalyzer { 46 47 // Note: a bunch of stuff has package-level access for unit tests. Consider it private. 48 49 /** Output logger. */ 50 private final Log mLog; 51 /** The input source JAR to parse. */ 52 private final List<String> mOsSourceJar; 53 /** The generator to fill with the class list and dependency list. */ 54 private final AsmGenerator mGen; 55 /** Keep all classes that derive from these one (these included). */ 56 private final String[] mDeriveFrom; 57 /** Glob patterns of classes to keep, e.g. "com.foo.*" */ 58 private final String[] mIncludeGlobs; 59 60 /** 61 * Creates a new analyzer. 62 * 63 * @param log The log output. 64 * @param osJarPath The input source JARs to parse. 65 * @param gen The generator to fill with the class list and dependency list. 66 * @param deriveFrom Keep all classes that derive from these one (these included). 67 * @param includeGlobs Glob patterns of classes to keep, e.g. "com.foo.*" 68 * ("*" does not matches dots whilst "**" does, "." and "$" are interpreted as-is) 69 */ AsmAnalyzer(Log log, List<String> osJarPath, AsmGenerator gen, String[] deriveFrom, String[] includeGlobs)70 public AsmAnalyzer(Log log, List<String> osJarPath, AsmGenerator gen, 71 String[] deriveFrom, String[] includeGlobs) { 72 mLog = log; 73 mGen = gen; 74 mOsSourceJar = osJarPath != null ? osJarPath : new ArrayList<String>(); 75 mDeriveFrom = deriveFrom != null ? deriveFrom : new String[0]; 76 mIncludeGlobs = includeGlobs != null ? includeGlobs : new String[0]; 77 } 78 79 /** 80 * Starts the analysis using parameters from the constructor. 81 * Fills the generator with classes & dependencies found. 82 */ analyze()83 public void analyze() throws IOException, LogAbortException { 84 85 AsmAnalyzer visitor = this; 86 87 Map<String, ClassReader> zipClasses = parseZip(mOsSourceJar); 88 mLog.info("Found %d classes in input JAR%s.", zipClasses.size(), 89 mOsSourceJar.size() > 1 ? "s" : ""); 90 91 Map<String, ClassReader> found = findIncludes(zipClasses); 92 Map<String, ClassReader> deps = findDeps(zipClasses, found); 93 94 if (mGen != null) { 95 mGen.setKeep(found); 96 mGen.setDeps(deps); 97 } 98 } 99 100 /** 101 * Parses a JAR file and returns a list of all classes founds using a map 102 * class name => ASM ClassReader. Class names are in the form "android.view.View". 103 */ parseZip(List<String> jarPathList)104 Map<String,ClassReader> parseZip(List<String> jarPathList) throws IOException { 105 TreeMap<String, ClassReader> classes = new TreeMap<String, ClassReader>(); 106 107 for (String jarPath : jarPathList) { 108 ZipFile zip = new ZipFile(jarPath); 109 Enumeration<? extends ZipEntry> entries = zip.entries(); 110 ZipEntry entry; 111 while (entries.hasMoreElements()) { 112 entry = entries.nextElement(); 113 if (entry.getName().endsWith(".class")) { 114 ClassReader cr = new ClassReader(zip.getInputStream(entry)); 115 String className = classReaderToClassName(cr); 116 classes.put(className, cr); 117 } 118 } 119 } 120 121 return classes; 122 } 123 124 /** 125 * Utility that returns the fully qualified binary class name for a ClassReader. 126 * E.g. it returns something like android.view.View. 127 */ classReaderToClassName(ClassReader classReader)128 static String classReaderToClassName(ClassReader classReader) { 129 if (classReader == null) { 130 return null; 131 } else { 132 return classReader.getClassName().replace('/', '.'); 133 } 134 } 135 136 /** 137 * Utility that returns the fully qualified binary class name from a path-like FQCN. 138 * E.g. it returns android.view.View from android/view/View. 139 */ internalToBinaryClassName(String className)140 static String internalToBinaryClassName(String className) { 141 if (className == null) { 142 return null; 143 } else { 144 return className.replace('/', '.'); 145 } 146 } 147 148 /** 149 * Process the "includes" arrays. 150 * <p/> 151 * This updates the in_out_found map. 152 */ findIncludes(Map<String, ClassReader> zipClasses)153 Map<String, ClassReader> findIncludes(Map<String, ClassReader> zipClasses) 154 throws LogAbortException { 155 TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>(); 156 157 mLog.debug("Find classes to include."); 158 159 for (String s : mIncludeGlobs) { 160 findGlobs(s, zipClasses, found); 161 } 162 for (String s : mDeriveFrom) { 163 findClassesDerivingFrom(s, zipClasses, found); 164 } 165 166 return found; 167 } 168 169 170 /** 171 * Uses ASM to find the class reader for the given FQCN class name. 172 * If found, insert it in the in_out_found map. 173 * Returns the class reader object. 174 */ findClass(String className, Map<String, ClassReader> zipClasses, Map<String, ClassReader> inOutFound)175 ClassReader findClass(String className, Map<String, ClassReader> zipClasses, 176 Map<String, ClassReader> inOutFound) throws LogAbortException { 177 ClassReader classReader = zipClasses.get(className); 178 if (classReader == null) { 179 throw new LogAbortException("Class %s not found by ASM in %s", 180 className, mOsSourceJar); 181 } 182 183 inOutFound.put(className, classReader); 184 return classReader; 185 } 186 187 /** 188 * Insert in the inOutFound map all classes found in zipClasses that match the 189 * given glob pattern. 190 * <p/> 191 * The glob pattern is not a regexp. It only accepts the "*" keyword to mean 192 * "anything but a period". The "." and "$" characters match themselves. 193 * The "**" keyword means everything including ".". 194 * <p/> 195 * Examples: 196 * <ul> 197 * <li>com.foo.* matches all classes in the package com.foo but NOT sub-packages. 198 * <li>com.foo*.*$Event matches all internal Event classes in a com.foo*.* class. 199 * </ul> 200 */ findGlobs(String globPattern, Map<String, ClassReader> zipClasses, Map<String, ClassReader> inOutFound)201 void findGlobs(String globPattern, Map<String, ClassReader> zipClasses, 202 Map<String, ClassReader> inOutFound) throws LogAbortException { 203 // transforms the glob pattern in a regexp: 204 // - escape "." with "\." 205 // - replace "*" by "[^.]*" 206 // - escape "$" with "\$" 207 // - add end-of-line match $ 208 globPattern = globPattern.replaceAll("\\$", "\\\\\\$"); 209 globPattern = globPattern.replaceAll("\\.", "\\\\."); 210 // prevent ** from being altered by the next rule, then process the * rule and finally 211 // the real ** rule (which is now @) 212 globPattern = globPattern.replaceAll("\\*\\*", "@"); 213 globPattern = globPattern.replaceAll("\\*", "[^.]*"); 214 globPattern = globPattern.replaceAll("@", ".*"); 215 globPattern += "$"; 216 217 Pattern regexp = Pattern.compile(globPattern); 218 219 for (Entry<String, ClassReader> entry : zipClasses.entrySet()) { 220 String class_name = entry.getKey(); 221 if (regexp.matcher(class_name).matches()) { 222 findClass(class_name, zipClasses, inOutFound); 223 } 224 } 225 } 226 227 /** 228 * Checks all the classes defined in the JarClassName instance and uses BCEL to 229 * determine if they are derived from the given FQCN super class name. 230 * Inserts the super class and all the class objects found in the map. 231 */ findClassesDerivingFrom(String super_name, Map<String, ClassReader> zipClasses, Map<String, ClassReader> inOutFound)232 void findClassesDerivingFrom(String super_name, Map<String, ClassReader> zipClasses, 233 Map<String, ClassReader> inOutFound) throws LogAbortException { 234 ClassReader super_clazz = findClass(super_name, zipClasses, inOutFound); 235 236 for (Entry<String, ClassReader> entry : zipClasses.entrySet()) { 237 String className = entry.getKey(); 238 if (super_name.equals(className)) { 239 continue; 240 } 241 ClassReader classReader = entry.getValue(); 242 ClassReader parent_cr = classReader; 243 while (parent_cr != null) { 244 String parent_name = internalToBinaryClassName(parent_cr.getSuperName()); 245 if (parent_name == null) { 246 // not found 247 break; 248 } else if (super_name.equals(parent_name)) { 249 inOutFound.put(className, classReader); 250 break; 251 } 252 parent_cr = zipClasses.get(parent_name); 253 } 254 } 255 } 256 257 /** 258 * Instantiates a new DependencyVisitor. Useful for unit tests. 259 */ getVisitor(Map<String, ClassReader> zipClasses, Map<String, ClassReader> inKeep, Map<String, ClassReader> outKeep, Map<String, ClassReader> inDeps, Map<String, ClassReader> outDeps)260 DependencyVisitor getVisitor(Map<String, ClassReader> zipClasses, 261 Map<String, ClassReader> inKeep, 262 Map<String, ClassReader> outKeep, 263 Map<String, ClassReader> inDeps, 264 Map<String, ClassReader> outDeps) { 265 return new DependencyVisitor(zipClasses, inKeep, outKeep, inDeps, outDeps); 266 } 267 268 /** 269 * Finds all dependencies for all classes in keepClasses which are also 270 * listed in zipClasses. Returns a map of all the dependencies found. 271 */ findDeps(Map<String, ClassReader> zipClasses, Map<String, ClassReader> inOutKeepClasses)272 Map<String, ClassReader> findDeps(Map<String, ClassReader> zipClasses, 273 Map<String, ClassReader> inOutKeepClasses) { 274 275 TreeMap<String, ClassReader> deps = new TreeMap<String, ClassReader>(); 276 TreeMap<String, ClassReader> new_deps = new TreeMap<String, ClassReader>(); 277 TreeMap<String, ClassReader> new_keep = new TreeMap<String, ClassReader>(); 278 TreeMap<String, ClassReader> temp = new TreeMap<String, ClassReader>(); 279 280 DependencyVisitor visitor = getVisitor(zipClasses, 281 inOutKeepClasses, new_keep, 282 deps, new_deps); 283 284 for (ClassReader cr : inOutKeepClasses.values()) { 285 cr.accept(visitor, 0 /* flags */); 286 } 287 288 while (new_deps.size() > 0 || new_keep.size() > 0) { 289 deps.putAll(new_deps); 290 inOutKeepClasses.putAll(new_keep); 291 292 temp.clear(); 293 temp.putAll(new_deps); 294 temp.putAll(new_keep); 295 new_deps.clear(); 296 new_keep.clear(); 297 mLog.debug("Found %1$d to keep, %2$d dependencies.", 298 inOutKeepClasses.size(), deps.size()); 299 300 for (ClassReader cr : temp.values()) { 301 cr.accept(visitor, 0 /* flags */); 302 } 303 } 304 305 mLog.info("Found %1$d classes to keep, %2$d class dependencies.", 306 inOutKeepClasses.size(), deps.size()); 307 308 return deps; 309 } 310 311 312 313 // ---------------------------------- 314 315 /** 316 * Visitor to collect all the type dependencies from a class. 317 */ 318 public class DependencyVisitor 319 implements ClassVisitor, FieldVisitor, MethodVisitor, SignatureVisitor, AnnotationVisitor { 320 321 /** All classes found in the source JAR. */ 322 private final Map<String, ClassReader> mZipClasses; 323 /** Classes from which dependencies are to be found. */ 324 private final Map<String, ClassReader> mInKeep; 325 /** Dependencies already known. */ 326 private final Map<String, ClassReader> mInDeps; 327 /** New dependencies found by this visitor. */ 328 private final Map<String, ClassReader> mOutDeps; 329 /** New classes to keep as-is found by this visitor. */ 330 private final Map<String, ClassReader> mOutKeep; 331 332 /** 333 * Creates a new visitor that will find all the dependencies for the visited class. 334 * Types which are already in the zipClasses, keepClasses or inDeps are not marked. 335 * New dependencies are marked in outDeps. 336 * 337 * @param zipClasses All classes found in the source JAR. 338 * @param inKeep Classes from which dependencies are to be found. 339 * @param inDeps Dependencies already known. 340 * @param outDeps New dependencies found by this visitor. 341 */ DependencyVisitor(Map<String, ClassReader> zipClasses, Map<String, ClassReader> inKeep, Map<String, ClassReader> outKeep, Map<String,ClassReader> inDeps, Map<String,ClassReader> outDeps)342 public DependencyVisitor(Map<String, ClassReader> zipClasses, 343 Map<String, ClassReader> inKeep, 344 Map<String, ClassReader> outKeep, 345 Map<String,ClassReader> inDeps, 346 Map<String,ClassReader> outDeps) { 347 mZipClasses = zipClasses; 348 mInKeep = inKeep; 349 mOutKeep = outKeep; 350 mInDeps = inDeps; 351 mOutDeps = outDeps; 352 } 353 354 /** 355 * Considers the given class name as a dependency. 356 * If it does, add to the mOutDeps map. 357 */ considerName(String className)358 public void considerName(String className) { 359 if (className == null) { 360 return; 361 } 362 363 className = internalToBinaryClassName(className); 364 365 // exclude classes that have already been found 366 if (mInKeep.containsKey(className) || 367 mOutKeep.containsKey(className) || 368 mInDeps.containsKey(className) || 369 mOutDeps.containsKey(className)) { 370 return; 371 } 372 373 // exclude classes that are not part of the JAR file being examined 374 ClassReader cr = mZipClasses.get(className); 375 if (cr == null) { 376 return; 377 } 378 379 try { 380 // exclude classes that are part of the default JRE (the one executing this program) 381 if (getClass().getClassLoader().loadClass(className) != null) { 382 return; 383 } 384 } catch (ClassNotFoundException e) { 385 // ignore 386 } 387 388 // accept this class: 389 // - android classes are added to dependencies 390 // - non-android classes are added to the list of classes to keep as-is (they don't need 391 // to be stubbed). 392 if (className.indexOf("android") >= 0) { // TODO make configurable 393 mOutDeps.put(className, cr); 394 } else { 395 mOutKeep.put(className, cr); 396 } 397 } 398 399 /** 400 * Considers this array of names using considerName(). 401 */ considerNames(String[] classNames)402 public void considerNames(String[] classNames) { 403 if (classNames != null) { 404 for (String className : classNames) { 405 considerName(className); 406 } 407 } 408 } 409 410 /** 411 * Considers this signature or type signature by invoking the {@link SignatureVisitor} 412 * on it. 413 */ considerSignature(String signature)414 public void considerSignature(String signature) { 415 if (signature != null) { 416 SignatureReader sr = new SignatureReader(signature); 417 // SignatureReader.accept will call accessType so we don't really have 418 // to differentiate where the signature comes from. 419 sr.accept(this); 420 } 421 } 422 423 /** 424 * Considers this {@link Type}. For arrays, the element type is considered. 425 * If the type is an object, it's internal name is considered. 426 */ considerType(Type t)427 public void considerType(Type t) { 428 if (t != null) { 429 if (t.getSort() == Type.ARRAY) { 430 t = t.getElementType(); 431 } 432 if (t.getSort() == Type.OBJECT) { 433 considerName(t.getInternalName()); 434 } 435 } 436 } 437 438 /** 439 * Considers a descriptor string. The descriptor is converted to a {@link Type} 440 * and then considerType() is invoked. 441 */ considerDesc(String desc)442 public void considerDesc(String desc) { 443 if (desc != null) { 444 try { 445 Type t = Type.getType(desc); 446 considerType(t); 447 } catch (ArrayIndexOutOfBoundsException e) { 448 // ignore, not a valid type. 449 } 450 } 451 } 452 453 454 // --------------------------------------------------- 455 // --- ClassVisitor, FieldVisitor 456 // --------------------------------------------------- 457 458 // Visits a class header visit(int version, int access, String name, String signature, String superName, String[] interfaces)459 public void visit(int version, int access, String name, 460 String signature, String superName, String[] interfaces) { 461 // signature is the signature of this class. May be null if the class is not a generic 462 // one, and does not extend or implement generic classes or interfaces. 463 464 if (signature != null) { 465 considerSignature(signature); 466 } 467 468 // superName is the internal of name of the super class (see getInternalName). 469 // For interfaces, the super class is Object. May be null but only for the Object class. 470 considerName(superName); 471 472 // interfaces is the internal names of the class's interfaces (see getInternalName). 473 // May be null. 474 considerNames(interfaces); 475 } 476 visitAnnotation(String desc, boolean visible)477 public AnnotationVisitor visitAnnotation(String desc, boolean visible) { 478 // desc is the class descriptor of the annotation class. 479 considerDesc(desc); 480 return this; // return this to visit annotion values 481 } 482 visitAttribute(Attribute attr)483 public void visitAttribute(Attribute attr) { 484 // pass 485 } 486 487 // Visits the end of a class visitEnd()488 public void visitEnd() { 489 // pass 490 } 491 visitField(int access, String name, String desc, String signature, Object value)492 public FieldVisitor visitField(int access, String name, String desc, 493 String signature, Object value) { 494 // desc is the field's descriptor (see Type). 495 considerDesc(desc); 496 497 // signature is the field's signature. May be null if the field's type does not use 498 // generic types. 499 considerSignature(signature); 500 501 return this; // a visitor to visit field annotations and attributes 502 } 503 visitInnerClass(String name, String outerName, String innerName, int access)504 public void visitInnerClass(String name, String outerName, String innerName, int access) { 505 // name is the internal name of an inner class (see getInternalName). 506 considerName(name); 507 } 508 visitMethod(int access, String name, String desc, String signature, String[] exceptions)509 public MethodVisitor visitMethod(int access, String name, String desc, 510 String signature, String[] exceptions) { 511 // desc is the method's descriptor (see Type). 512 considerDesc(desc); 513 // signature is the method's signature. May be null if the method parameters, return 514 // type and exceptions do not use generic types. 515 considerSignature(signature); 516 517 return this; // returns this to visit the method 518 } 519 visitOuterClass(String owner, String name, String desc)520 public void visitOuterClass(String owner, String name, String desc) { 521 // pass 522 } 523 visitSource(String source, String debug)524 public void visitSource(String source, String debug) { 525 // pass 526 } 527 528 529 // --------------------------------------------------- 530 // --- MethodVisitor 531 // --------------------------------------------------- 532 visitAnnotationDefault()533 public AnnotationVisitor visitAnnotationDefault() { 534 return this; // returns this to visit the default value 535 } 536 537 visitCode()538 public void visitCode() { 539 // pass 540 } 541 542 // field instruction visitFieldInsn(int opcode, String owner, String name, String desc)543 public void visitFieldInsn(int opcode, String owner, String name, String desc) { 544 // name is the field's name. 545 considerName(name); 546 // desc is the field's descriptor (see Type). 547 considerDesc(desc); 548 } 549 visitFrame(int type, int local, Object[] local2, int stack, Object[] stack2)550 public void visitFrame(int type, int local, Object[] local2, int stack, Object[] stack2) { 551 // pass 552 } 553 visitIincInsn(int var, int increment)554 public void visitIincInsn(int var, int increment) { 555 // pass -- an IINC instruction 556 } 557 visitInsn(int opcode)558 public void visitInsn(int opcode) { 559 // pass -- a zero operand instruction 560 } 561 visitIntInsn(int opcode, int operand)562 public void visitIntInsn(int opcode, int operand) { 563 // pass -- a single int operand instruction 564 } 565 visitJumpInsn(int opcode, Label label)566 public void visitJumpInsn(int opcode, Label label) { 567 // pass -- a jump instruction 568 } 569 visitLabel(Label label)570 public void visitLabel(Label label) { 571 // pass -- a label target 572 } 573 574 // instruction to load a constant from the stack visitLdcInsn(Object cst)575 public void visitLdcInsn(Object cst) { 576 if (cst instanceof Type) { 577 considerType((Type) cst); 578 } 579 } 580 visitLineNumber(int line, Label start)581 public void visitLineNumber(int line, Label start) { 582 // pass 583 } 584 visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index)585 public void visitLocalVariable(String name, String desc, 586 String signature, Label start, Label end, int index) { 587 // desc is the type descriptor of this local variable. 588 considerDesc(desc); 589 // signature is the type signature of this local variable. May be null if the local 590 // variable type does not use generic types. 591 considerSignature(signature); 592 } 593 visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels)594 public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { 595 // pass -- a lookup switch instruction 596 } 597 visitMaxs(int maxStack, int maxLocals)598 public void visitMaxs(int maxStack, int maxLocals) { 599 // pass 600 } 601 602 // instruction that invokes a method visitMethodInsn(int opcode, String owner, String name, String desc)603 public void visitMethodInsn(int opcode, String owner, String name, String desc) { 604 605 // owner is the internal name of the method's owner class 606 considerName(owner); 607 // desc is the method's descriptor (see Type). 608 considerDesc(desc); 609 } 610 611 // instruction multianewarray, whatever that is visitMultiANewArrayInsn(String desc, int dims)612 public void visitMultiANewArrayInsn(String desc, int dims) { 613 614 // desc an array type descriptor. 615 considerDesc(desc); 616 } 617 visitParameterAnnotation(int parameter, String desc, boolean visible)618 public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, 619 boolean visible) { 620 // desc is the class descriptor of the annotation class. 621 considerDesc(desc); 622 return this; // return this to visit annotation values 623 } 624 visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels)625 public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) { 626 // pass -- table switch instruction 627 628 } 629 visitTryCatchBlock(Label start, Label end, Label handler, String type)630 public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { 631 // type is the internal name of the type of exceptions handled by the handler, 632 // or null to catch any exceptions (for "finally" blocks). 633 considerName(type); 634 } 635 636 // type instruction visitTypeInsn(int opcode, String type)637 public void visitTypeInsn(int opcode, String type) { 638 // type is the operand of the instruction to be visited. This operand must be the 639 // internal name of an object or array class. 640 considerName(type); 641 } 642 visitVarInsn(int opcode, int var)643 public void visitVarInsn(int opcode, int var) { 644 // pass -- local variable instruction 645 } 646 647 648 // --------------------------------------------------- 649 // --- SignatureVisitor 650 // --------------------------------------------------- 651 652 private String mCurrentSignatureClass = null; 653 654 // Starts the visit of a signature corresponding to a class or interface type visitClassType(String name)655 public void visitClassType(String name) { 656 mCurrentSignatureClass = name; 657 considerName(name); 658 } 659 660 // Visits an inner class visitInnerClassType(String name)661 public void visitInnerClassType(String name) { 662 if (mCurrentSignatureClass != null) { 663 mCurrentSignatureClass += "$" + name; 664 considerName(mCurrentSignatureClass); 665 } 666 } 667 visitArrayType()668 public SignatureVisitor visitArrayType() { 669 return this; // returns this to visit the signature of the array element type 670 } 671 visitBaseType(char descriptor)672 public void visitBaseType(char descriptor) { 673 // pass -- a primitive type, ignored 674 } 675 visitClassBound()676 public SignatureVisitor visitClassBound() { 677 return this; // returns this to visit the signature of the class bound 678 } 679 visitExceptionType()680 public SignatureVisitor visitExceptionType() { 681 return this; // return this to visit the signature of the exception type. 682 } 683 visitFormalTypeParameter(String name)684 public void visitFormalTypeParameter(String name) { 685 // pass 686 } 687 visitInterface()688 public SignatureVisitor visitInterface() { 689 return this; // returns this to visit the signature of the interface type 690 } 691 visitInterfaceBound()692 public SignatureVisitor visitInterfaceBound() { 693 return this; // returns this to visit the signature of the interface bound 694 } 695 visitParameterType()696 public SignatureVisitor visitParameterType() { 697 return this; // returns this to visit the signature of the parameter type 698 } 699 visitReturnType()700 public SignatureVisitor visitReturnType() { 701 return this; // returns this to visit the signature of the return type 702 } 703 visitSuperclass()704 public SignatureVisitor visitSuperclass() { 705 return this; // returns this to visit the signature of the super class type 706 } 707 visitTypeArgument(char wildcard)708 public SignatureVisitor visitTypeArgument(char wildcard) { 709 return this; // returns this to visit the signature of the type argument 710 } 711 visitTypeVariable(String name)712 public void visitTypeVariable(String name) { 713 // pass 714 } 715 visitTypeArgument()716 public void visitTypeArgument() { 717 // pass 718 } 719 720 721 // --------------------------------------------------- 722 // --- AnnotationVisitor 723 // --------------------------------------------------- 724 725 726 // Visits a primitive value of an annotation visit(String name, Object value)727 public void visit(String name, Object value) { 728 // value is the actual value, whose type must be Byte, Boolean, Character, Short, 729 // Integer, Long, Float, Double, String or Type 730 if (value instanceof Type) { 731 considerType((Type) value); 732 } 733 } 734 visitAnnotation(String name, String desc)735 public AnnotationVisitor visitAnnotation(String name, String desc) { 736 // desc is the class descriptor of the nested annotation class. 737 considerDesc(desc); 738 return this; // returns this to visit the actual nested annotation value 739 } 740 visitArray(String name)741 public AnnotationVisitor visitArray(String name) { 742 return this; // returns this to visit the actual array value elements 743 } 744 visitEnum(String name, String desc, String value)745 public void visitEnum(String name, String desc, String value) { 746 // desc is the class descriptor of the enumeration class. 747 considerDesc(desc); 748 } 749 750 } 751 } 752