1 /*** 2 * ASM: a very small and fast Java bytecode manipulation framework 3 * Copyright (c) 2000-2007 INRIA, France Telecom 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the copyright holders nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28 * THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 package org.mockito.asm; 31 32 import java.lang.reflect.Constructor; 33 import java.lang.reflect.Method; 34 35 /** 36 * A Java type. This class can be used to make it easier to manipulate type and 37 * method descriptors. 38 * 39 * @author Eric Bruneton 40 * @author Chris Nokleberg 41 */ 42 public class Type { 43 44 /** 45 * The sort of the <tt>void</tt> type. See {@link #getSort getSort}. 46 */ 47 public static final int VOID = 0; 48 49 /** 50 * The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}. 51 */ 52 public static final int BOOLEAN = 1; 53 54 /** 55 * The sort of the <tt>char</tt> type. See {@link #getSort getSort}. 56 */ 57 public static final int CHAR = 2; 58 59 /** 60 * The sort of the <tt>byte</tt> type. See {@link #getSort getSort}. 61 */ 62 public static final int BYTE = 3; 63 64 /** 65 * The sort of the <tt>short</tt> type. See {@link #getSort getSort}. 66 */ 67 public static final int SHORT = 4; 68 69 /** 70 * The sort of the <tt>int</tt> type. See {@link #getSort getSort}. 71 */ 72 public static final int INT = 5; 73 74 /** 75 * The sort of the <tt>float</tt> type. See {@link #getSort getSort}. 76 */ 77 public static final int FLOAT = 6; 78 79 /** 80 * The sort of the <tt>long</tt> type. See {@link #getSort getSort}. 81 */ 82 public static final int LONG = 7; 83 84 /** 85 * The sort of the <tt>double</tt> type. See {@link #getSort getSort}. 86 */ 87 public static final int DOUBLE = 8; 88 89 /** 90 * The sort of array reference types. See {@link #getSort getSort}. 91 */ 92 public static final int ARRAY = 9; 93 94 /** 95 * The sort of object reference type. See {@link #getSort getSort}. 96 */ 97 public static final int OBJECT = 10; 98 99 /** 100 * The <tt>void</tt> type. 101 */ 102 public static final Type VOID_TYPE = new Type(VOID); 103 104 /** 105 * The <tt>boolean</tt> type. 106 */ 107 public static final Type BOOLEAN_TYPE = new Type(BOOLEAN); 108 109 /** 110 * The <tt>char</tt> type. 111 */ 112 public static final Type CHAR_TYPE = new Type(CHAR); 113 114 /** 115 * The <tt>byte</tt> type. 116 */ 117 public static final Type BYTE_TYPE = new Type(BYTE); 118 119 /** 120 * The <tt>short</tt> type. 121 */ 122 public static final Type SHORT_TYPE = new Type(SHORT); 123 124 /** 125 * The <tt>int</tt> type. 126 */ 127 public static final Type INT_TYPE = new Type(INT); 128 129 /** 130 * The <tt>float</tt> type. 131 */ 132 public static final Type FLOAT_TYPE = new Type(FLOAT); 133 134 /** 135 * The <tt>long</tt> type. 136 */ 137 public static final Type LONG_TYPE = new Type(LONG); 138 139 /** 140 * The <tt>double</tt> type. 141 */ 142 public static final Type DOUBLE_TYPE = new Type(DOUBLE); 143 144 // ------------------------------------------------------------------------ 145 // Fields 146 // ------------------------------------------------------------------------ 147 148 /** 149 * The sort of this Java type. 150 */ 151 private final int sort; 152 153 /** 154 * A buffer containing the internal name of this Java type. This field is 155 * only used for reference types. 156 */ 157 private final char[] buf; 158 159 /** 160 * The offset of the internal name of this Java type in {@link #buf buf}. 161 * This field is only used for reference types. 162 */ 163 private final int off; 164 165 /** 166 * The length of the internal name of this Java type. This field is only 167 * used for reference types. 168 */ 169 private final int len; 170 171 // ------------------------------------------------------------------------ 172 // Constructors 173 // ------------------------------------------------------------------------ 174 175 /** 176 * Constructs a primitive type. 177 * 178 * @param sort the sort of the primitive type to be constructed. 179 */ Type(final int sort)180 private Type(final int sort) { 181 this(sort, null, 0, 1); 182 } 183 184 /** 185 * Constructs a reference type. 186 * 187 * @param sort the sort of the reference type to be constructed. 188 * @param buf a buffer containing the descriptor of the previous type. 189 * @param off the offset of this descriptor in the previous buffer. 190 * @param len the length of this descriptor. 191 */ Type(final int sort, final char[] buf, final int off, final int len)192 private Type(final int sort, final char[] buf, final int off, final int len) 193 { 194 this.sort = sort; 195 this.buf = buf; 196 this.off = off; 197 this.len = len; 198 } 199 200 /** 201 * Returns the Java type corresponding to the given type descriptor. 202 * 203 * @param typeDescriptor a type descriptor. 204 * @return the Java type corresponding to the given type descriptor. 205 */ getType(final String typeDescriptor)206 public static Type getType(final String typeDescriptor) { 207 return getType(typeDescriptor.toCharArray(), 0); 208 } 209 210 /** 211 * Returns the Java type corresponding to the given internal name. 212 * 213 * @param internalName an internal name. 214 * @return the Java type corresponding to the given internal name. 215 */ getObjectType(final String internalName)216 public static Type getObjectType(final String internalName) { 217 char[] buf = internalName.toCharArray(); 218 return new Type(buf[0] == '[' ? ARRAY : OBJECT, buf, 0, buf.length); 219 } 220 221 /** 222 * Returns the Java type corresponding to the given class. 223 * 224 * @param c a class. 225 * @return the Java type corresponding to the given class. 226 */ getType(final Class c)227 public static Type getType(final Class c) { 228 if (c.isPrimitive()) { 229 if (c == Integer.TYPE) { 230 return INT_TYPE; 231 } else if (c == Void.TYPE) { 232 return VOID_TYPE; 233 } else if (c == Boolean.TYPE) { 234 return BOOLEAN_TYPE; 235 } else if (c == Byte.TYPE) { 236 return BYTE_TYPE; 237 } else if (c == Character.TYPE) { 238 return CHAR_TYPE; 239 } else if (c == Short.TYPE) { 240 return SHORT_TYPE; 241 } else if (c == Double.TYPE) { 242 return DOUBLE_TYPE; 243 } else if (c == Float.TYPE) { 244 return FLOAT_TYPE; 245 } else /* if (c == Long.TYPE) */{ 246 return LONG_TYPE; 247 } 248 } else { 249 return getType(getDescriptor(c)); 250 } 251 } 252 253 /** 254 * Returns the Java types corresponding to the argument types of the given 255 * method descriptor. 256 * 257 * @param methodDescriptor a method descriptor. 258 * @return the Java types corresponding to the argument types of the given 259 * method descriptor. 260 */ getArgumentTypes(final String methodDescriptor)261 public static Type[] getArgumentTypes(final String methodDescriptor) { 262 char[] buf = methodDescriptor.toCharArray(); 263 int off = 1; 264 int size = 0; 265 while (true) { 266 char car = buf[off++]; 267 if (car == ')') { 268 break; 269 } else if (car == 'L') { 270 while (buf[off++] != ';') { 271 } 272 ++size; 273 } else if (car != '[') { 274 ++size; 275 } 276 } 277 Type[] args = new Type[size]; 278 off = 1; 279 size = 0; 280 while (buf[off] != ')') { 281 args[size] = getType(buf, off); 282 off += args[size].len + (args[size].sort == OBJECT ? 2 : 0); 283 size += 1; 284 } 285 return args; 286 } 287 288 /** 289 * Returns the Java types corresponding to the argument types of the given 290 * method. 291 * 292 * @param method a method. 293 * @return the Java types corresponding to the argument types of the given 294 * method. 295 */ getArgumentTypes(final Method method)296 public static Type[] getArgumentTypes(final Method method) { 297 Class[] classes = method.getParameterTypes(); 298 Type[] types = new Type[classes.length]; 299 for (int i = classes.length - 1; i >= 0; --i) { 300 types[i] = getType(classes[i]); 301 } 302 return types; 303 } 304 305 /** 306 * Returns the Java type corresponding to the return type of the given 307 * method descriptor. 308 * 309 * @param methodDescriptor a method descriptor. 310 * @return the Java type corresponding to the return type of the given 311 * method descriptor. 312 */ getReturnType(final String methodDescriptor)313 public static Type getReturnType(final String methodDescriptor) { 314 char[] buf = methodDescriptor.toCharArray(); 315 return getType(buf, methodDescriptor.indexOf(')') + 1); 316 } 317 318 /** 319 * Returns the Java type corresponding to the return type of the given 320 * method. 321 * 322 * @param method a method. 323 * @return the Java type corresponding to the return type of the given 324 * method. 325 */ getReturnType(final Method method)326 public static Type getReturnType(final Method method) { 327 return getType(method.getReturnType()); 328 } 329 330 /** 331 * Returns the Java type corresponding to the given type descriptor. 332 * 333 * @param buf a buffer containing a type descriptor. 334 * @param off the offset of this descriptor in the previous buffer. 335 * @return the Java type corresponding to the given type descriptor. 336 */ getType(final char[] buf, final int off)337 private static Type getType(final char[] buf, final int off) { 338 int len; 339 switch (buf[off]) { 340 case 'V': 341 return VOID_TYPE; 342 case 'Z': 343 return BOOLEAN_TYPE; 344 case 'C': 345 return CHAR_TYPE; 346 case 'B': 347 return BYTE_TYPE; 348 case 'S': 349 return SHORT_TYPE; 350 case 'I': 351 return INT_TYPE; 352 case 'F': 353 return FLOAT_TYPE; 354 case 'J': 355 return LONG_TYPE; 356 case 'D': 357 return DOUBLE_TYPE; 358 case '[': 359 len = 1; 360 while (buf[off + len] == '[') { 361 ++len; 362 } 363 if (buf[off + len] == 'L') { 364 ++len; 365 while (buf[off + len] != ';') { 366 ++len; 367 } 368 } 369 return new Type(ARRAY, buf, off, len + 1); 370 // case 'L': 371 default: 372 len = 1; 373 while (buf[off + len] != ';') { 374 ++len; 375 } 376 return new Type(OBJECT, buf, off + 1, len - 1); 377 } 378 } 379 380 // ------------------------------------------------------------------------ 381 // Accessors 382 // ------------------------------------------------------------------------ 383 384 /** 385 * Returns the sort of this Java type. 386 * 387 * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, 388 * {@link #CHAR CHAR}, {@link #BYTE BYTE}, {@link #SHORT SHORT}, 389 * {@link #INT INT}, {@link #FLOAT FLOAT}, {@link #LONG LONG}, 390 * {@link #DOUBLE DOUBLE}, {@link #ARRAY ARRAY} or 391 * {@link #OBJECT OBJECT}. 392 */ getSort()393 public int getSort() { 394 return sort; 395 } 396 397 /** 398 * Returns the number of dimensions of this array type. This method should 399 * only be used for an array type. 400 * 401 * @return the number of dimensions of this array type. 402 */ getDimensions()403 public int getDimensions() { 404 int i = 1; 405 while (buf[off + i] == '[') { 406 ++i; 407 } 408 return i; 409 } 410 411 /** 412 * Returns the type of the elements of this array type. This method should 413 * only be used for an array type. 414 * 415 * @return Returns the type of the elements of this array type. 416 */ getElementType()417 public Type getElementType() { 418 return getType(buf, off + getDimensions()); 419 } 420 421 /** 422 * Returns the name of the class corresponding to this type. 423 * 424 * @return the fully qualified name of the class corresponding to this type. 425 */ getClassName()426 public String getClassName() { 427 switch (sort) { 428 case VOID: 429 return "void"; 430 case BOOLEAN: 431 return "boolean"; 432 case CHAR: 433 return "char"; 434 case BYTE: 435 return "byte"; 436 case SHORT: 437 return "short"; 438 case INT: 439 return "int"; 440 case FLOAT: 441 return "float"; 442 case LONG: 443 return "long"; 444 case DOUBLE: 445 return "double"; 446 case ARRAY: 447 StringBuffer b = new StringBuffer(getElementType().getClassName()); 448 for (int i = getDimensions(); i > 0; --i) { 449 b.append("[]"); 450 } 451 return b.toString(); 452 // case OBJECT: 453 default: 454 return new String(buf, off, len).replace('/', '.'); 455 } 456 } 457 458 /** 459 * Returns the internal name of the class corresponding to this object or 460 * array type. The internal name of a class is its fully qualified name (as 461 * returned by Class.getName(), where '.' are replaced by '/'. This method 462 * should only be used for an object or array type. 463 * 464 * @return the internal name of the class corresponding to this object type. 465 */ getInternalName()466 public String getInternalName() { 467 return new String(buf, off, len); 468 } 469 470 // ------------------------------------------------------------------------ 471 // Conversion to type descriptors 472 // ------------------------------------------------------------------------ 473 474 /** 475 * Returns the descriptor corresponding to this Java type. 476 * 477 * @return the descriptor corresponding to this Java type. 478 */ getDescriptor()479 public String getDescriptor() { 480 StringBuffer buf = new StringBuffer(); 481 getDescriptor(buf); 482 return buf.toString(); 483 } 484 485 /** 486 * Returns the descriptor corresponding to the given argument and return 487 * types. 488 * 489 * @param returnType the return type of the method. 490 * @param argumentTypes the argument types of the method. 491 * @return the descriptor corresponding to the given argument and return 492 * types. 493 */ getMethodDescriptor( final Type returnType, final Type[] argumentTypes)494 public static String getMethodDescriptor( 495 final Type returnType, 496 final Type[] argumentTypes) 497 { 498 StringBuffer buf = new StringBuffer(); 499 buf.append('('); 500 for (int i = 0; i < argumentTypes.length; ++i) { 501 argumentTypes[i].getDescriptor(buf); 502 } 503 buf.append(')'); 504 returnType.getDescriptor(buf); 505 return buf.toString(); 506 } 507 508 /** 509 * Appends the descriptor corresponding to this Java type to the given 510 * string buffer. 511 * 512 * @param buf the string buffer to which the descriptor must be appended. 513 */ getDescriptor(final StringBuffer buf)514 private void getDescriptor(final StringBuffer buf) { 515 switch (sort) { 516 case VOID: 517 buf.append('V'); 518 return; 519 case BOOLEAN: 520 buf.append('Z'); 521 return; 522 case CHAR: 523 buf.append('C'); 524 return; 525 case BYTE: 526 buf.append('B'); 527 return; 528 case SHORT: 529 buf.append('S'); 530 return; 531 case INT: 532 buf.append('I'); 533 return; 534 case FLOAT: 535 buf.append('F'); 536 return; 537 case LONG: 538 buf.append('J'); 539 return; 540 case DOUBLE: 541 buf.append('D'); 542 return; 543 case ARRAY: 544 buf.append(this.buf, off, len); 545 return; 546 // case OBJECT: 547 default: 548 buf.append('L'); 549 buf.append(this.buf, off, len); 550 buf.append(';'); 551 } 552 } 553 554 // ------------------------------------------------------------------------ 555 // Direct conversion from classes to type descriptors, 556 // without intermediate Type objects 557 // ------------------------------------------------------------------------ 558 559 /** 560 * Returns the internal name of the given class. The internal name of a 561 * class is its fully qualified name, as returned by Class.getName(), where 562 * '.' are replaced by '/'. 563 * 564 * @param c an object or array class. 565 * @return the internal name of the given class. 566 */ getInternalName(final Class c)567 public static String getInternalName(final Class c) { 568 return c.getName().replace('.', '/'); 569 } 570 571 /** 572 * Returns the descriptor corresponding to the given Java type. 573 * 574 * @param c an object class, a primitive class or an array class. 575 * @return the descriptor corresponding to the given class. 576 */ getDescriptor(final Class c)577 public static String getDescriptor(final Class c) { 578 StringBuffer buf = new StringBuffer(); 579 getDescriptor(buf, c); 580 return buf.toString(); 581 } 582 583 /** 584 * Returns the descriptor corresponding to the given constructor. 585 * 586 * @param c a {@link Constructor Constructor} object. 587 * @return the descriptor of the given constructor. 588 */ getConstructorDescriptor(final Constructor c)589 public static String getConstructorDescriptor(final Constructor c) { 590 Class[] parameters = c.getParameterTypes(); 591 StringBuffer buf = new StringBuffer(); 592 buf.append('('); 593 for (int i = 0; i < parameters.length; ++i) { 594 getDescriptor(buf, parameters[i]); 595 } 596 return buf.append(")V").toString(); 597 } 598 599 /** 600 * Returns the descriptor corresponding to the given method. 601 * 602 * @param m a {@link Method Method} object. 603 * @return the descriptor of the given method. 604 */ getMethodDescriptor(final Method m)605 public static String getMethodDescriptor(final Method m) { 606 Class[] parameters = m.getParameterTypes(); 607 StringBuffer buf = new StringBuffer(); 608 buf.append('('); 609 for (int i = 0; i < parameters.length; ++i) { 610 getDescriptor(buf, parameters[i]); 611 } 612 buf.append(')'); 613 getDescriptor(buf, m.getReturnType()); 614 return buf.toString(); 615 } 616 617 /** 618 * Appends the descriptor of the given class to the given string buffer. 619 * 620 * @param buf the string buffer to which the descriptor must be appended. 621 * @param c the class whose descriptor must be computed. 622 */ getDescriptor(final StringBuffer buf, final Class c)623 private static void getDescriptor(final StringBuffer buf, final Class c) { 624 Class d = c; 625 while (true) { 626 if (d.isPrimitive()) { 627 char car; 628 if (d == Integer.TYPE) { 629 car = 'I'; 630 } else if (d == Void.TYPE) { 631 car = 'V'; 632 } else if (d == Boolean.TYPE) { 633 car = 'Z'; 634 } else if (d == Byte.TYPE) { 635 car = 'B'; 636 } else if (d == Character.TYPE) { 637 car = 'C'; 638 } else if (d == Short.TYPE) { 639 car = 'S'; 640 } else if (d == Double.TYPE) { 641 car = 'D'; 642 } else if (d == Float.TYPE) { 643 car = 'F'; 644 } else /* if (d == Long.TYPE) */{ 645 car = 'J'; 646 } 647 buf.append(car); 648 return; 649 } else if (d.isArray()) { 650 buf.append('['); 651 d = d.getComponentType(); 652 } else { 653 buf.append('L'); 654 String name = d.getName(); 655 int len = name.length(); 656 for (int i = 0; i < len; ++i) { 657 char car = name.charAt(i); 658 buf.append(car == '.' ? '/' : car); 659 } 660 buf.append(';'); 661 return; 662 } 663 } 664 } 665 666 // ------------------------------------------------------------------------ 667 // Corresponding size and opcodes 668 // ------------------------------------------------------------------------ 669 670 /** 671 * Returns the size of values of this type. 672 * 673 * @return the size of values of this type, i.e., 2 for <tt>long</tt> and 674 * <tt>double</tt>, and 1 otherwise. 675 */ getSize()676 public int getSize() { 677 return sort == LONG || sort == DOUBLE ? 2 : 1; 678 } 679 680 /** 681 * Returns a JVM instruction opcode adapted to this Java type. 682 * 683 * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD, 684 * ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL, 685 * ISHR, IUSHR, IAND, IOR, IXOR and IRETURN. 686 * @return an opcode that is similar to the given opcode, but adapted to 687 * this Java type. For example, if this type is <tt>float</tt> and 688 * <tt>opcode</tt> is IRETURN, this method returns FRETURN. 689 */ getOpcode(final int opcode)690 public int getOpcode(final int opcode) { 691 if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) { 692 switch (sort) { 693 case BOOLEAN: 694 case BYTE: 695 return opcode + 5; 696 case CHAR: 697 return opcode + 6; 698 case SHORT: 699 return opcode + 7; 700 case INT: 701 return opcode; 702 case FLOAT: 703 return opcode + 2; 704 case LONG: 705 return opcode + 1; 706 case DOUBLE: 707 return opcode + 3; 708 // case ARRAY: 709 // case OBJECT: 710 default: 711 return opcode + 4; 712 } 713 } else { 714 switch (sort) { 715 case VOID: 716 return opcode + 5; 717 case BOOLEAN: 718 case CHAR: 719 case BYTE: 720 case SHORT: 721 case INT: 722 return opcode; 723 case FLOAT: 724 return opcode + 2; 725 case LONG: 726 return opcode + 1; 727 case DOUBLE: 728 return opcode + 3; 729 // case ARRAY: 730 // case OBJECT: 731 default: 732 return opcode + 4; 733 } 734 } 735 } 736 737 // ------------------------------------------------------------------------ 738 // Equals, hashCode and toString 739 // ------------------------------------------------------------------------ 740 741 /** 742 * Tests if the given object is equal to this type. 743 * 744 * @param o the object to be compared to this type. 745 * @return <tt>true</tt> if the given object is equal to this type. 746 */ equals(final Object o)747 public boolean equals(final Object o) { 748 if (this == o) { 749 return true; 750 } 751 if (!(o instanceof Type)) { 752 return false; 753 } 754 Type t = (Type) o; 755 if (sort != t.sort) { 756 return false; 757 } 758 if (sort == OBJECT || sort == ARRAY) { 759 if (len != t.len) { 760 return false; 761 } 762 for (int i = off, j = t.off, end = i + len; i < end; i++, j++) { 763 if (buf[i] != t.buf[j]) { 764 return false; 765 } 766 } 767 } 768 return true; 769 } 770 771 /** 772 * Returns a hash code value for this type. 773 * 774 * @return a hash code value for this type. 775 */ hashCode()776 public int hashCode() { 777 int hc = 13 * sort; 778 if (sort == OBJECT || sort == ARRAY) { 779 for (int i = off, end = i + len; i < end; i++) { 780 hc = 17 * (hc + buf[i]); 781 } 782 } 783 return hc; 784 } 785 786 /** 787 * Returns a string representation of this type. 788 * 789 * @return the descriptor of this type. 790 */ toString()791 public String toString() { 792 return getDescriptor(); 793 } 794 } 795