• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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