1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. Oracle designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Oracle in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 */ 24 25 /* 26 * This file is available under and governed by the GNU General Public 27 * License version 2 only, as published by the Free Software Foundation. 28 * However, the following notice accompanied the original version of this 29 * file: 30 * 31 * ASM: a very small and fast Java bytecode manipulation framework 32 * Copyright (c) 2000-2011 INRIA, France Telecom 33 * All rights reserved. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 3. Neither the name of the copyright holders nor the names of its 44 * contributors may be used to endorse or promote products derived from 45 * this software without specific prior written permission. 46 * 47 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 48 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 50 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 51 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 52 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 53 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 54 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 55 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 56 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 57 * THE POSSIBILITY OF SUCH DAMAGE. 58 */ 59 package jdk.internal.org.objectweb.asm.util; 60 61 import java.io.FileInputStream; 62 import java.io.PrintWriter; 63 import java.util.ArrayList; 64 import java.util.HashMap; 65 import java.util.Iterator; 66 import java.util.List; 67 import java.util.Map; 68 69 import jdk.internal.org.objectweb.asm.AnnotationVisitor; 70 import jdk.internal.org.objectweb.asm.Attribute; 71 import jdk.internal.org.objectweb.asm.ClassReader; 72 import jdk.internal.org.objectweb.asm.ClassVisitor; 73 import jdk.internal.org.objectweb.asm.FieldVisitor; 74 import jdk.internal.org.objectweb.asm.Label; 75 import jdk.internal.org.objectweb.asm.MethodVisitor; 76 import jdk.internal.org.objectweb.asm.ModuleVisitor; 77 import jdk.internal.org.objectweb.asm.Opcodes; 78 import jdk.internal.org.objectweb.asm.Type; 79 import jdk.internal.org.objectweb.asm.TypePath; 80 import jdk.internal.org.objectweb.asm.TypeReference; 81 import jdk.internal.org.objectweb.asm.tree.ClassNode; 82 import jdk.internal.org.objectweb.asm.tree.MethodNode; 83 import jdk.internal.org.objectweb.asm.tree.analysis.Analyzer; 84 import jdk.internal.org.objectweb.asm.tree.analysis.BasicValue; 85 import jdk.internal.org.objectweb.asm.tree.analysis.Frame; 86 import jdk.internal.org.objectweb.asm.tree.analysis.SimpleVerifier; 87 88 /** 89 * A {@link ClassVisitor} that checks that its methods are properly used. More 90 * precisely this class adapter checks each method call individually, based 91 * <i>only</i> on its arguments, but does <i>not</i> check the <i>sequence</i> 92 * of method calls. For example, the invalid sequence 93 * <tt>visitField(ACC_PUBLIC, "i", "I", null)</tt> <tt>visitField(ACC_PUBLIC, 94 * "i", "D", null)</tt> will <i>not</i> be detected by this class adapter. 95 * 96 * <p> 97 * <code>CheckClassAdapter</code> can be also used to verify bytecode 98 * transformations in order to make sure transformed bytecode is sane. For 99 * example: 100 * 101 * <pre> 102 * InputStream is = ...; // get bytes for the source class 103 * ClassReader cr = new ClassReader(is); 104 * ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS); 105 * ClassVisitor cv = new <b>MyClassAdapter</b>(new CheckClassAdapter(cw)); 106 * cr.accept(cv, 0); 107 * 108 * StringWriter sw = new StringWriter(); 109 * PrintWriter pw = new PrintWriter(sw); 110 * CheckClassAdapter.verify(new ClassReader(cw.toByteArray()), false, pw); 111 * assertTrue(sw.toString(), sw.toString().length()==0); 112 * </pre> 113 * 114 * Above code runs transformed bytecode trough the 115 * <code>CheckClassAdapter</code>. It won't be exactly the same verification as 116 * JVM does, but it run data flow analysis for the code of each method and 117 * checks that expectations are met for each method instruction. 118 * 119 * <p> 120 * If method bytecode has errors, assertion text will show the erroneous 121 * instruction number and dump of the failed method with information about 122 * locals and stack slot for each instruction. For example (format is - 123 * insnNumber locals : stack): 124 * 125 * <pre> 126 * jdk.internal.org.objectweb.asm.tree.analysis.AnalyzerException: Error at instruction 71: Expected I, but found . 127 * at jdk.internal.org.objectweb.asm.tree.analysis.Analyzer.analyze(Analyzer.java:289) 128 * at jdk.internal.org.objectweb.asm.util.CheckClassAdapter.verify(CheckClassAdapter.java:135) 129 * ... 130 * remove()V 131 * 00000 LinkedBlockingQueue$Itr . . . . . . . . : 132 * ICONST_0 133 * 00001 LinkedBlockingQueue$Itr . . . . . . . . : I 134 * ISTORE 2 135 * 00001 LinkedBlockingQueue$Itr <b>.</b> I . . . . . . : 136 * ... 137 * 138 * 00071 LinkedBlockingQueue$Itr <b>.</b> I . . . . . . : 139 * ILOAD 1 140 * 00072 <b>?</b> 141 * INVOKESPECIAL java/lang/Integer.<init> (I)V 142 * ... 143 * </pre> 144 * 145 * In the above output you can see that variable 1 loaded by 146 * <code>ILOAD 1</code> instruction at position <code>00071</code> is not 147 * initialized. You can also see that at the beginning of the method (code 148 * inserted by the transformation) variable 2 is initialized. 149 * 150 * <p> 151 * Note that when used like that, <code>CheckClassAdapter.verify()</code> can 152 * trigger additional class loading, because it is using 153 * <code>SimpleVerifier</code>. 154 * 155 * @author Eric Bruneton 156 */ 157 public class CheckClassAdapter extends ClassVisitor { 158 159 /** 160 * The class version number. 161 */ 162 private int version; 163 164 /** 165 * <tt>true</tt> if the visit method has been called. 166 */ 167 private boolean start; 168 169 /** 170 * <tt>true</tt> if the visitSource method has been called. 171 */ 172 private boolean source; 173 174 /** 175 * <tt>true</tt> if the visitOuterClass method has been called. 176 */ 177 private boolean outer; 178 179 /** 180 * <tt>true</tt> if the visitEnd method has been called. 181 */ 182 private boolean end; 183 184 /** 185 * <tt>true</tt> if the visitModule method has been called. 186 */ 187 private boolean module; 188 189 /** 190 * The already visited labels. This map associate Integer values to Label 191 * keys. 192 */ 193 private Map<Label, Integer> labels; 194 195 /** 196 * <tt>true</tt> if the method code must be checked with a BasicVerifier. 197 */ 198 private boolean checkDataFlow; 199 200 /** 201 * Checks a given class. 202 * <p> 203 * Usage: CheckClassAdapter <binary class name or class file name> 204 * 205 * @param args 206 * the command line arguments. 207 * 208 * @throws Exception 209 * if the class cannot be found, or if an IO exception occurs. 210 */ 211 public static void main(final String[] args) throws Exception { 212 if (args.length != 1) { 213 System.err.println("Verifies the given class."); 214 System.err.println("Usage: CheckClassAdapter " 215 + "<fully qualified class name or class file name>"); 216 return; 217 } 218 ClassReader cr; 219 if (args[0].endsWith(".class")) { 220 cr = new ClassReader(new FileInputStream(args[0])); 221 } else { 222 cr = new ClassReader(args[0]); 223 } 224 225 verify(cr, false, new PrintWriter(System.err)); 226 } 227 228 /** 229 * Checks a given class. 230 * 231 * @param cr 232 * a <code>ClassReader</code> that contains bytecode for the 233 * analysis. 234 * @param loader 235 * a <code>ClassLoader</code> which will be used to load 236 * referenced classes. This is useful if you are verifiying 237 * multiple interdependent classes. 238 * @param dump 239 * true if bytecode should be printed out not only when errors 240 * are found. 241 * @param pw 242 * write where results going to be printed 243 */ 244 public static void verify(final ClassReader cr, final ClassLoader loader, 245 final boolean dump, final PrintWriter pw) { 246 ClassNode cn = new ClassNode(); 247 cr.accept(new CheckClassAdapter(cn, false), ClassReader.SKIP_DEBUG); 248 249 Type syperType = cn.superName == null ? null : Type 250 .getObjectType(cn.superName); 251 List<MethodNode> methods = cn.methods; 252 253 List<Type> interfaces = new ArrayList<Type>(); 254 for (Iterator<String> i = cn.interfaces.iterator(); i.hasNext();) { 255 interfaces.add(Type.getObjectType(i.next())); 256 } 257 258 for (int i = 0; i < methods.size(); ++i) { 259 MethodNode method = methods.get(i); 260 SimpleVerifier verifier = new SimpleVerifier( 261 Type.getObjectType(cn.name), syperType, interfaces, 262 (cn.access & Opcodes.ACC_INTERFACE) != 0); 263 Analyzer<BasicValue> a = new Analyzer<BasicValue>(verifier); 264 if (loader != null) { 265 verifier.setClassLoader(loader); 266 } 267 try { 268 a.analyze(cn.name, method); 269 if (!dump) { 270 continue; 271 } 272 } catch (Exception e) { 273 e.printStackTrace(pw); 274 } 275 printAnalyzerResult(method, a, pw); 276 } 277 pw.flush(); 278 } 279 280 /** 281 * Checks a given class 282 * 283 * @param cr 284 * a <code>ClassReader</code> that contains bytecode for the 285 * analysis. 286 * @param dump 287 * true if bytecode should be printed out not only when errors 288 * are found. 289 * @param pw 290 * write where results going to be printed 291 */ 292 public static void verify(final ClassReader cr, final boolean dump, 293 final PrintWriter pw) { 294 verify(cr, null, dump, pw); 295 } 296 297 static void printAnalyzerResult(MethodNode method, Analyzer<BasicValue> a, 298 final PrintWriter pw) { 299 Frame<BasicValue>[] frames = a.getFrames(); 300 Textifier t = new Textifier(); 301 TraceMethodVisitor mv = new TraceMethodVisitor(t); 302 303 pw.println(method.name + method.desc); 304 for (int j = 0; j < method.instructions.size(); ++j) { 305 method.instructions.get(j).accept(mv); 306 307 StringBuilder sb = new StringBuilder(); 308 Frame<BasicValue> f = frames[j]; 309 if (f == null) { 310 sb.append('?'); 311 } else { 312 for (int k = 0; k < f.getLocals(); ++k) { 313 sb.append(getShortName(f.getLocal(k).toString())) 314 .append(' '); 315 } 316 sb.append(" : "); 317 for (int k = 0; k < f.getStackSize(); ++k) { 318 sb.append(getShortName(f.getStack(k).toString())) 319 .append(' '); 320 } 321 } 322 while (sb.length() < method.maxStack + method.maxLocals + 1) { 323 sb.append(' '); 324 } 325 pw.print(Integer.toString(j + 100000).substring(1)); 326 pw.print(" " + sb + " : " + t.text.get(t.text.size() - 1)); 327 } 328 for (int j = 0; j < method.tryCatchBlocks.size(); ++j) { 329 method.tryCatchBlocks.get(j).accept(mv); 330 pw.print(" " + t.text.get(t.text.size() - 1)); 331 } 332 pw.println(); 333 } 334 335 private static String getShortName(final String name) { 336 int n = name.lastIndexOf('/'); 337 int k = name.length(); 338 if (name.charAt(k - 1) == ';') { 339 k--; 340 } 341 return n == -1 ? name : name.substring(n + 1, k); 342 } 343 344 /** 345 * Constructs a new {@link CheckClassAdapter}. <i>Subclasses must not use 346 * this constructor</i>. Instead, they must use the 347 * {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version. 348 * 349 * @param cv 350 * the class visitor to which this adapter must delegate calls. 351 */ 352 public CheckClassAdapter(final ClassVisitor cv) { 353 this(cv, true); 354 } 355 356 /** 357 * Constructs a new {@link CheckClassAdapter}. <i>Subclasses must not use 358 * this constructor</i>. Instead, they must use the 359 * {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version. 360 * 361 * @param cv 362 * the class visitor to which this adapter must delegate calls. 363 * @param checkDataFlow 364 * <tt>true</tt> to perform basic data flow checks, or 365 * <tt>false</tt> to not perform any data flow check (see 366 * {@link CheckMethodAdapter}). This option requires valid 367 * maxLocals and maxStack values. 368 * @throws IllegalStateException 369 * If a subclass calls this constructor. 370 */ 371 public CheckClassAdapter(final ClassVisitor cv, final boolean checkDataFlow) { 372 this(Opcodes.ASM6, cv, checkDataFlow); 373 if (getClass() != CheckClassAdapter.class) { 374 throw new IllegalStateException(); 375 } 376 } 377 378 /** 379 * Constructs a new {@link CheckClassAdapter}. 380 * 381 * @param api 382 * the ASM API version implemented by this visitor. Must be one 383 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. 384 * @param cv 385 * the class visitor to which this adapter must delegate calls. 386 * @param checkDataFlow 387 * <tt>true</tt> to perform basic data flow checks, or 388 * <tt>false</tt> to not perform any data flow check (see 389 * {@link CheckMethodAdapter}). This option requires valid 390 * maxLocals and maxStack values. 391 */ 392 protected CheckClassAdapter(final int api, final ClassVisitor cv, 393 final boolean checkDataFlow) { 394 super(api, cv); 395 this.labels = new HashMap<Label, Integer>(); 396 this.checkDataFlow = checkDataFlow; 397 } 398 399 // ------------------------------------------------------------------------ 400 // Implementation of the ClassVisitor interface 401 // ------------------------------------------------------------------------ 402 403 @Override 404 public void visit(final int version, final int access, final String name, 405 final String signature, final String superName, 406 final String[] interfaces) { 407 if (start) { 408 throw new IllegalStateException("visit must be called only once"); 409 } 410 start = true; 411 checkState(); 412 checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL 413 + Opcodes.ACC_SUPER + Opcodes.ACC_INTERFACE 414 + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC 415 + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM 416 + Opcodes.ACC_DEPRECATED + Opcodes.ACC_MODULE 417 + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE 418 if (name == null) { 419 throw new IllegalArgumentException("Illegal class name (null)"); 420 } 421 if (!name.endsWith("package-info")) { 422 CheckMethodAdapter.checkInternalName(name, "class name"); 423 } 424 if ("java/lang/Object".equals(name)) { 425 if (superName != null) { 426 throw new IllegalArgumentException( 427 "The super class name of the Object class must be 'null'"); 428 } 429 } else { 430 CheckMethodAdapter.checkInternalName(superName, "super class name"); 431 } 432 if (signature != null) { 433 checkClassSignature(signature); 434 } 435 if ((access & Opcodes.ACC_INTERFACE) != 0) { 436 if (!"java/lang/Object".equals(superName)) { 437 throw new IllegalArgumentException( 438 "The super class name of interfaces must be 'java/lang/Object'"); 439 } 440 } 441 if (interfaces != null) { 442 for (int i = 0; i < interfaces.length; ++i) { 443 CheckMethodAdapter.checkInternalName(interfaces[i], 444 "interface name at index " + i); 445 } 446 } 447 this.version = version; 448 super.visit(version, access, name, signature, superName, interfaces); 449 } 450 451 @Override 452 public void visitSource(final String file, final String debug) { 453 checkState(); 454 if (source) { 455 throw new IllegalStateException( 456 "visitSource can be called only once."); 457 } 458 source = true; 459 super.visitSource(file, debug); 460 } 461 462 @Override 463 public ModuleVisitor visitModule(String name, int access, String version) { 464 checkState(); 465 if (module) { 466 throw new IllegalStateException( 467 "visitModule can be called only once."); 468 } 469 module = true; 470 if (name == null) { 471 throw new IllegalArgumentException("Illegal module name (null)"); 472 } 473 checkAccess(access, Opcodes.ACC_OPEN | Opcodes.ACC_SYNTHETIC); 474 return new CheckModuleAdapter(super.visitModule(name, access, version), 475 (access & Opcodes.ACC_OPEN) != 0); 476 } 477 478 @Override 479 public void visitOuterClass(final String owner, final String name, 480 final String desc) { 481 checkState(); 482 if (outer) { 483 throw new IllegalStateException( 484 "visitOuterClass can be called only once."); 485 } 486 outer = true; 487 if (owner == null) { 488 throw new IllegalArgumentException("Illegal outer class owner"); 489 } 490 if (desc != null) { 491 CheckMethodAdapter.checkMethodDesc(desc); 492 } 493 super.visitOuterClass(owner, name, desc); 494 } 495 496 @Override 497 public void visitInnerClass(final String name, final String outerName, 498 final String innerName, final int access) { 499 checkState(); 500 CheckMethodAdapter.checkInternalName(name, "class name"); 501 if (outerName != null) { 502 CheckMethodAdapter.checkInternalName(outerName, "outer class name"); 503 } 504 if (innerName != null) { 505 int start = 0; 506 while (start < innerName.length() 507 && Character.isDigit(innerName.charAt(start))) { 508 start++; 509 } 510 if (start == 0 || start < innerName.length()) { 511 CheckMethodAdapter.checkIdentifier(innerName, start, -1, 512 "inner class name"); 513 } 514 } 515 checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE 516 + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC 517 + Opcodes.ACC_FINAL + Opcodes.ACC_INTERFACE 518 + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC 519 + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM); 520 super.visitInnerClass(name, outerName, innerName, access); 521 } 522 523 @Override 524 public FieldVisitor visitField(final int access, final String name, 525 final String desc, final String signature, final Object value) { 526 checkState(); 527 checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE 528 + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC 529 + Opcodes.ACC_FINAL + Opcodes.ACC_VOLATILE 530 + Opcodes.ACC_TRANSIENT + Opcodes.ACC_SYNTHETIC 531 + Opcodes.ACC_ENUM + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE 532 CheckMethodAdapter.checkUnqualifiedName(version, name, "field name"); 533 CheckMethodAdapter.checkDesc(desc, false); 534 if (signature != null) { 535 checkFieldSignature(signature); 536 } 537 if (value != null) { 538 CheckMethodAdapter.checkConstant(value); 539 } 540 FieldVisitor av = super 541 .visitField(access, name, desc, signature, value); 542 return new CheckFieldAdapter(av); 543 } 544 545 @Override 546 public MethodVisitor visitMethod(final int access, final String name, 547 final String desc, final String signature, final String[] exceptions) { 548 checkState(); 549 checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE 550 + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC 551 + Opcodes.ACC_FINAL + Opcodes.ACC_SYNCHRONIZED 552 + Opcodes.ACC_BRIDGE + Opcodes.ACC_VARARGS + Opcodes.ACC_NATIVE 553 + Opcodes.ACC_ABSTRACT + Opcodes.ACC_STRICT 554 + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE 555 if (!"<init>".equals(name) && !"<clinit>".equals(name)) { 556 CheckMethodAdapter.checkMethodIdentifier(version, name, 557 "method name"); 558 } 559 CheckMethodAdapter.checkMethodDesc(desc); 560 if (signature != null) { 561 checkMethodSignature(signature); 562 } 563 if (exceptions != null) { 564 for (int i = 0; i < exceptions.length; ++i) { 565 CheckMethodAdapter.checkInternalName(exceptions[i], 566 "exception name at index " + i); 567 } 568 } 569 CheckMethodAdapter cma; 570 if (checkDataFlow) { 571 cma = new CheckMethodAdapter(access, name, desc, super.visitMethod( 572 access, name, desc, signature, exceptions), labels); 573 } else { 574 cma = new CheckMethodAdapter(super.visitMethod(access, name, desc, 575 signature, exceptions), labels); 576 } 577 cma.version = version; 578 return cma; 579 } 580 581 @Override 582 public AnnotationVisitor visitAnnotation(final String desc, 583 final boolean visible) { 584 checkState(); 585 CheckMethodAdapter.checkDesc(desc, false); 586 return new CheckAnnotationAdapter(super.visitAnnotation(desc, visible)); 587 } 588 589 @Override 590 public AnnotationVisitor visitTypeAnnotation(final int typeRef, 591 final TypePath typePath, final String desc, final boolean visible) { 592 checkState(); 593 int sort = typeRef >>> 24; 594 if (sort != TypeReference.CLASS_TYPE_PARAMETER 595 && sort != TypeReference.CLASS_TYPE_PARAMETER_BOUND 596 && sort != TypeReference.CLASS_EXTENDS) { 597 throw new IllegalArgumentException("Invalid type reference sort 0x" 598 + Integer.toHexString(sort)); 599 } 600 checkTypeRefAndPath(typeRef, typePath); 601 CheckMethodAdapter.checkDesc(desc, false); 602 return new CheckAnnotationAdapter(super.visitTypeAnnotation(typeRef, 603 typePath, desc, visible)); 604 } 605 606 @Override 607 public void visitAttribute(final Attribute attr) { 608 checkState(); 609 if (attr == null) { 610 throw new IllegalArgumentException( 611 "Invalid attribute (must not be null)"); 612 } 613 super.visitAttribute(attr); 614 } 615 616 @Override 617 public void visitEnd() { 618 checkState(); 619 end = true; 620 super.visitEnd(); 621 } 622 623 // ------------------------------------------------------------------------ 624 // Utility methods 625 // ------------------------------------------------------------------------ 626 627 /** 628 * Checks that the visit method has been called and that visitEnd has not 629 * been called. 630 */ 631 private void checkState() { 632 if (!start) { 633 throw new IllegalStateException( 634 "Cannot visit member before visit has been called."); 635 } 636 if (end) { 637 throw new IllegalStateException( 638 "Cannot visit member after visitEnd has been called."); 639 } 640 } 641 642 /** 643 * Checks that the given access flags do not contain invalid flags. This 644 * method also checks that mutually incompatible flags are not set 645 * simultaneously. 646 * 647 * @param access 648 * the access flags to be checked 649 * @param possibleAccess 650 * the valid access flags. 651 */ 652 static void checkAccess(final int access, final int possibleAccess) { 653 if ((access & ~possibleAccess) != 0) { 654 throw new IllegalArgumentException("Invalid access flags: " 655 + access); 656 } 657 int pub = (access & Opcodes.ACC_PUBLIC) == 0 ? 0 : 1; 658 int pri = (access & Opcodes.ACC_PRIVATE) == 0 ? 0 : 1; 659 int pro = (access & Opcodes.ACC_PROTECTED) == 0 ? 0 : 1; 660 if (pub + pri + pro > 1) { 661 throw new IllegalArgumentException( 662 "public private and protected are mutually exclusive: " 663 + access); 664 } 665 int fin = (access & Opcodes.ACC_FINAL) == 0 ? 0 : 1; 666 int abs = (access & Opcodes.ACC_ABSTRACT) == 0 ? 0 : 1; 667 if (fin + abs > 1) { 668 throw new IllegalArgumentException( 669 "final and abstract are mutually exclusive: " + access); 670 } 671 } 672 673 /** 674 * Checks a class signature. 675 * 676 * @param signature 677 * a string containing the signature that must be checked. 678 */ 679 public static void checkClassSignature(final String signature) { 680 // ClassSignature: 681 // FormalTypeParameters? ClassTypeSignature ClassTypeSignature* 682 683 int pos = 0; 684 if (getChar(signature, 0) == '<') { 685 pos = checkFormalTypeParameters(signature, pos); 686 } 687 pos = checkClassTypeSignature(signature, pos); 688 while (getChar(signature, pos) == 'L') { 689 pos = checkClassTypeSignature(signature, pos); 690 } 691 if (pos != signature.length()) { 692 throw new IllegalArgumentException(signature + ": error at index " 693 + pos); 694 } 695 } 696 697 /** 698 * Checks a method signature. 699 * 700 * @param signature 701 * a string containing the signature that must be checked. 702 */ 703 public static void checkMethodSignature(final String signature) { 704 // MethodTypeSignature: 705 // FormalTypeParameters? ( TypeSignature* ) ( TypeSignature | V ) ( 706 // ^ClassTypeSignature | ^TypeVariableSignature )* 707 708 int pos = 0; 709 if (getChar(signature, 0) == '<') { 710 pos = checkFormalTypeParameters(signature, pos); 711 } 712 pos = checkChar('(', signature, pos); 713 while ("ZCBSIFJDL[T".indexOf(getChar(signature, pos)) != -1) { 714 pos = checkTypeSignature(signature, pos); 715 } 716 pos = checkChar(')', signature, pos); 717 if (getChar(signature, pos) == 'V') { 718 ++pos; 719 } else { 720 pos = checkTypeSignature(signature, pos); 721 } 722 while (getChar(signature, pos) == '^') { 723 ++pos; 724 if (getChar(signature, pos) == 'L') { 725 pos = checkClassTypeSignature(signature, pos); 726 } else { 727 pos = checkTypeVariableSignature(signature, pos); 728 } 729 } 730 if (pos != signature.length()) { 731 throw new IllegalArgumentException(signature + ": error at index " 732 + pos); 733 } 734 } 735 736 /** 737 * Checks a field signature. 738 * 739 * @param signature 740 * a string containing the signature that must be checked. 741 */ 742 public static void checkFieldSignature(final String signature) { 743 int pos = checkFieldTypeSignature(signature, 0); 744 if (pos != signature.length()) { 745 throw new IllegalArgumentException(signature + ": error at index " 746 + pos); 747 } 748 } 749 750 /** 751 * Checks the reference to a type in a type annotation. 752 * 753 * @param typeRef 754 * a reference to an annotated type. 755 * @param typePath 756 * the path to the annotated type argument, wildcard bound, array 757 * element type, or static inner type within 'typeRef'. May be 758 * <tt>null</tt> if the annotation targets 'typeRef' as a whole. 759 */ 760 static void checkTypeRefAndPath(int typeRef, TypePath typePath) { 761 int mask = 0; 762 switch (typeRef >>> 24) { 763 case TypeReference.CLASS_TYPE_PARAMETER: 764 case TypeReference.METHOD_TYPE_PARAMETER: 765 case TypeReference.METHOD_FORMAL_PARAMETER: 766 mask = 0xFFFF0000; 767 break; 768 case TypeReference.FIELD: 769 case TypeReference.METHOD_RETURN: 770 case TypeReference.METHOD_RECEIVER: 771 case TypeReference.LOCAL_VARIABLE: 772 case TypeReference.RESOURCE_VARIABLE: 773 case TypeReference.INSTANCEOF: 774 case TypeReference.NEW: 775 case TypeReference.CONSTRUCTOR_REFERENCE: 776 case TypeReference.METHOD_REFERENCE: 777 mask = 0xFF000000; 778 break; 779 case TypeReference.CLASS_EXTENDS: 780 case TypeReference.CLASS_TYPE_PARAMETER_BOUND: 781 case TypeReference.METHOD_TYPE_PARAMETER_BOUND: 782 case TypeReference.THROWS: 783 case TypeReference.EXCEPTION_PARAMETER: 784 mask = 0xFFFFFF00; 785 break; 786 case TypeReference.CAST: 787 case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: 788 case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT: 789 case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: 790 case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT: 791 mask = 0xFF0000FF; 792 break; 793 default: 794 throw new IllegalArgumentException("Invalid type reference sort 0x" 795 + Integer.toHexString(typeRef >>> 24)); 796 } 797 if ((typeRef & ~mask) != 0) { 798 throw new IllegalArgumentException("Invalid type reference 0x" 799 + Integer.toHexString(typeRef)); 800 } 801 if (typePath != null) { 802 for (int i = 0; i < typePath.getLength(); ++i) { 803 int step = typePath.getStep(i); 804 if (step != TypePath.ARRAY_ELEMENT 805 && step != TypePath.INNER_TYPE 806 && step != TypePath.TYPE_ARGUMENT 807 && step != TypePath.WILDCARD_BOUND) { 808 throw new IllegalArgumentException( 809 "Invalid type path step " + i + " in " + typePath); 810 } 811 if (step != TypePath.TYPE_ARGUMENT 812 && typePath.getStepArgument(i) != 0) { 813 throw new IllegalArgumentException( 814 "Invalid type path step argument for step " + i 815 + " in " + typePath); 816 } 817 } 818 } 819 } 820 821 /** 822 * Checks the formal type parameters of a class or method signature. 823 * 824 * @param signature 825 * a string containing the signature that must be checked. 826 * @param pos 827 * index of first character to be checked. 828 * @return the index of the first character after the checked part. 829 */ 830 private static int checkFormalTypeParameters(final String signature, int pos) { 831 // FormalTypeParameters: 832 // < FormalTypeParameter+ > 833 834 pos = checkChar('<', signature, pos); 835 pos = checkFormalTypeParameter(signature, pos); 836 while (getChar(signature, pos) != '>') { 837 pos = checkFormalTypeParameter(signature, pos); 838 } 839 return pos + 1; 840 } 841 842 /** 843 * Checks a formal type parameter of a class or method signature. 844 * 845 * @param signature 846 * a string containing the signature that must be checked. 847 * @param pos 848 * index of first character to be checked. 849 * @return the index of the first character after the checked part. 850 */ 851 private static int checkFormalTypeParameter(final String signature, int pos) { 852 // FormalTypeParameter: 853 // Identifier : FieldTypeSignature? (: FieldTypeSignature)* 854 855 pos = checkIdentifier(signature, pos); 856 pos = checkChar(':', signature, pos); 857 if ("L[T".indexOf(getChar(signature, pos)) != -1) { 858 pos = checkFieldTypeSignature(signature, pos); 859 } 860 while (getChar(signature, pos) == ':') { 861 pos = checkFieldTypeSignature(signature, pos + 1); 862 } 863 return pos; 864 } 865 866 /** 867 * Checks a field type signature. 868 * 869 * @param signature 870 * a string containing the signature that must be checked. 871 * @param pos 872 * index of first character to be checked. 873 * @return the index of the first character after the checked part. 874 */ 875 private static int checkFieldTypeSignature(final String signature, int pos) { 876 // FieldTypeSignature: 877 // ClassTypeSignature | ArrayTypeSignature | TypeVariableSignature 878 // 879 // ArrayTypeSignature: 880 // [ TypeSignature 881 882 switch (getChar(signature, pos)) { 883 case 'L': 884 return checkClassTypeSignature(signature, pos); 885 case '[': 886 return checkTypeSignature(signature, pos + 1); 887 default: 888 return checkTypeVariableSignature(signature, pos); 889 } 890 } 891 892 /** 893 * Checks a class type signature. 894 * 895 * @param signature 896 * a string containing the signature that must be checked. 897 * @param pos 898 * index of first character to be checked. 899 * @return the index of the first character after the checked part. 900 */ 901 private static int checkClassTypeSignature(final String signature, int pos) { 902 // ClassTypeSignature: 903 // L Identifier ( / Identifier )* TypeArguments? ( . Identifier 904 // TypeArguments? )* ; 905 906 pos = checkChar('L', signature, pos); 907 pos = checkIdentifier(signature, pos); 908 while (getChar(signature, pos) == '/') { 909 pos = checkIdentifier(signature, pos + 1); 910 } 911 if (getChar(signature, pos) == '<') { 912 pos = checkTypeArguments(signature, pos); 913 } 914 while (getChar(signature, pos) == '.') { 915 pos = checkIdentifier(signature, pos + 1); 916 if (getChar(signature, pos) == '<') { 917 pos = checkTypeArguments(signature, pos); 918 } 919 } 920 return checkChar(';', signature, pos); 921 } 922 923 /** 924 * Checks the type arguments in a class type signature. 925 * 926 * @param signature 927 * a string containing the signature that must be checked. 928 * @param pos 929 * index of first character to be checked. 930 * @return the index of the first character after the checked part. 931 */ 932 private static int checkTypeArguments(final String signature, int pos) { 933 // TypeArguments: 934 // < TypeArgument+ > 935 936 pos = checkChar('<', signature, pos); 937 pos = checkTypeArgument(signature, pos); 938 while (getChar(signature, pos) != '>') { 939 pos = checkTypeArgument(signature, pos); 940 } 941 return pos + 1; 942 } 943 944 /** 945 * Checks a type argument in a class type signature. 946 * 947 * @param signature 948 * a string containing the signature that must be checked. 949 * @param pos 950 * index of first character to be checked. 951 * @return the index of the first character after the checked part. 952 */ 953 private static int checkTypeArgument(final String signature, int pos) { 954 // TypeArgument: 955 // * | ( ( + | - )? FieldTypeSignature ) 956 957 char c = getChar(signature, pos); 958 if (c == '*') { 959 return pos + 1; 960 } else if (c == '+' || c == '-') { 961 pos++; 962 } 963 return checkFieldTypeSignature(signature, pos); 964 } 965 966 /** 967 * Checks a type variable signature. 968 * 969 * @param signature 970 * a string containing the signature that must be checked. 971 * @param pos 972 * index of first character to be checked. 973 * @return the index of the first character after the checked part. 974 */ 975 private static int checkTypeVariableSignature(final String signature, 976 int pos) { 977 // TypeVariableSignature: 978 // T Identifier ; 979 980 pos = checkChar('T', signature, pos); 981 pos = checkIdentifier(signature, pos); 982 return checkChar(';', signature, pos); 983 } 984 985 /** 986 * Checks a type signature. 987 * 988 * @param signature 989 * a string containing the signature that must be checked. 990 * @param pos 991 * index of first character to be checked. 992 * @return the index of the first character after the checked part. 993 */ 994 private static int checkTypeSignature(final String signature, int pos) { 995 // TypeSignature: 996 // Z | C | B | S | I | F | J | D | FieldTypeSignature 997 998 switch (getChar(signature, pos)) { 999 case 'Z': 1000 case 'C': 1001 case 'B': 1002 case 'S': 1003 case 'I': 1004 case 'F': 1005 case 'J': 1006 case 'D': 1007 return pos + 1; 1008 default: 1009 return checkFieldTypeSignature(signature, pos); 1010 } 1011 } 1012 1013 /** 1014 * Checks an identifier. 1015 * 1016 * @param signature 1017 * a string containing the signature that must be checked. 1018 * @param pos 1019 * index of first character to be checked. 1020 * @return the index of the first character after the checked part. 1021 */ 1022 private static int checkIdentifier(final String signature, int pos) { 1023 if (!Character.isJavaIdentifierStart(getChar(signature, pos))) { 1024 throw new IllegalArgumentException(signature 1025 + ": identifier expected at index " + pos); 1026 } 1027 ++pos; 1028 while (Character.isJavaIdentifierPart(getChar(signature, pos))) { 1029 ++pos; 1030 } 1031 return pos; 1032 } 1033 1034 /** 1035 * Checks a single character. 1036 * 1037 * @param signature 1038 * a string containing the signature that must be checked. 1039 * @param pos 1040 * index of first character to be checked. 1041 * @return the index of the first character after the checked part. 1042 */ 1043 private static int checkChar(final char c, final String signature, int pos) { 1044 if (getChar(signature, pos) == c) { 1045 return pos + 1; 1046 } 1047 throw new IllegalArgumentException(signature + ": '" + c 1048 + "' expected at index " + pos); 1049 } 1050 1051 /** 1052 * Returns the signature car at the given index. 1053 * 1054 * @param signature 1055 * a signature. 1056 * @param pos 1057 * an index in signature. 1058 * @return the character at the given index, or 0 if there is no such 1059 * character. 1060 */ 1061 private static char getChar(final String signature, int pos) { 1062 return pos < signature.length() ? signature.charAt(pos) : (char) 0; 1063 } 1064 }