• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License.  Alternatively, the contents of this file may be used under
8  * the terms of the GNU Lesser General Public License Version 2.1 or later,
9  * or the Apache License Version 2.0.
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  */
16 
17 package javassist.bytecode;
18 
19 import java.io.DataInputStream;
20 import java.io.IOException;
21 import java.util.ArrayList;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25 
26 import javassist.CtClass;
27 
28 /**
29  * <code>Signature_attribute</code>.
30  */
31 public class SignatureAttribute extends AttributeInfo {
32     /**
33      * The name of this attribute <code>"Signature"</code>.
34      */
35     public static final String tag = "Signature";
36 
SignatureAttribute(ConstPool cp, int n, DataInputStream in)37     SignatureAttribute(ConstPool cp, int n, DataInputStream in)
38         throws IOException
39     {
40         super(cp, n, in);
41     }
42 
43     /**
44      * Constructs a <code>Signature</code> attribute.
45      *
46      * @param cp                a constant pool table.
47      * @param signature         the signature represented by this attribute.
48      */
SignatureAttribute(ConstPool cp, String signature)49     public SignatureAttribute(ConstPool cp, String signature) {
50         super(cp, tag);
51         int index = cp.addUtf8Info(signature);
52         byte[] bvalue = new byte[2];
53         bvalue[0] = (byte)(index >>> 8);
54         bvalue[1] = (byte)index;
55         set(bvalue);
56     }
57 
58     /**
59      * Returns the generic signature indicated by <code>signature_index</code>.
60      *
61      * @see #toClassSignature(String)
62      * @see #toMethodSignature(String)
63      * @see #toFieldSignature(String)
64      */
getSignature()65     public String getSignature() {
66         return getConstPool().getUtf8Info(ByteArray.readU16bit(get(), 0));
67     }
68 
69     /**
70      * Sets <code>signature_index</code> to the index of the given generic signature,
71      * which is added to a constant pool.
72      *
73      * @param sig       new signature.
74      * @since 3.11
75      */
setSignature(String sig)76     public void setSignature(String sig) {
77         int index = getConstPool().addUtf8Info(sig);
78         ByteArray.write16bit(index, info, 0);
79     }
80 
81     /**
82      * Makes a copy.  Class names are replaced according to the
83      * given <code>Map</code> object.
84      *
85      * @param newCp     the constant pool table used by the new copy.
86      * @param classnames        pairs of replaced and substituted
87      *                          class names.
88      */
89     @Override
copy(ConstPool newCp, Map<String,String> classnames)90     public AttributeInfo copy(ConstPool newCp, Map<String,String> classnames) {
91         return new SignatureAttribute(newCp, getSignature());
92     }
93 
94     @Override
renameClass(String oldname, String newname)95     void renameClass(String oldname, String newname) {
96         String sig = renameClass(getSignature(), oldname, newname);
97         setSignature(sig);
98     }
99 
100     @Override
renameClass(Map<String,String> classnames)101     void renameClass(Map<String,String> classnames) {
102         String sig = renameClass(getSignature(), classnames);
103         setSignature(sig);
104     }
105 
renameClass(String desc, String oldname, String newname)106     static String renameClass(String desc, String oldname, String newname) {
107         Map<String,String> map = new HashMap<String,String>();
108         map.put(oldname, newname);
109         return renameClass(desc, map);
110     }
111 
renameClass(String desc, Map<String,String> map)112     static String renameClass(String desc, Map<String,String> map) {
113         if (map == null)
114             return desc;
115 
116         StringBuilder newdesc = new StringBuilder();
117         int head = 0;
118         int i = 0;
119         for (;;) {
120             int j = desc.indexOf('L', i);
121             if (j < 0)
122                 break;
123 
124             StringBuilder nameBuf = new StringBuilder();
125             int k = j;
126             char c;
127             try {
128                 while ((c = desc.charAt(++k)) != ';') {
129                     nameBuf.append(c);
130                     if (c == '<') {
131                         while ((c = desc.charAt(++k)) != '>')
132                             nameBuf.append(c);
133 
134                         nameBuf.append(c);
135                     }
136                 }
137             }
138             catch (IndexOutOfBoundsException e) { break; }
139             i = k + 1;
140             String name = nameBuf.toString();
141             String name2 = map.get(name);
142             if (name2 != null) {
143                 newdesc.append(desc.substring(head, j));
144                 newdesc.append('L');
145                 newdesc.append(name2);
146                 newdesc.append(c);
147                 head = i;
148             }
149         }
150 
151         if (head == 0)
152             return desc;
153         int len = desc.length();
154         if (head < len)
155             newdesc.append(desc.substring(head, len));
156 
157         return newdesc.toString();
158     }
159 
160     @SuppressWarnings("unused")
isNamePart(int c)161     private static boolean isNamePart(int c) {
162         return c != ';' && c != '<';
163     }
164 
165     static private class Cursor {
166         int position = 0;
167 
indexOf(String s, int ch)168         int indexOf(String s, int ch) throws BadBytecode {
169             int i = s.indexOf(ch, position);
170             if (i < 0)
171                 throw error(s);
172             position = i + 1;
173             return i;
174         }
175     }
176 
177     /**
178      * Class signature.
179      */
180     public static class ClassSignature {
181         TypeParameter[] params;
182         ClassType superClass;
183         ClassType[] interfaces;
184 
185         /**
186          * Constructs a class signature.
187          *
188          * @param params             type parameters.
189          * @param superClass         the super class.
190          * @param interfaces         the interface types.
191          */
ClassSignature(TypeParameter[] params, ClassType superClass, ClassType[] interfaces)192         public ClassSignature(TypeParameter[] params, ClassType superClass, ClassType[] interfaces) {
193             this.params = params == null ? new TypeParameter[0] : params;
194             this.superClass = superClass == null ? ClassType.OBJECT : superClass;
195             this.interfaces = interfaces == null ? new ClassType[0] : interfaces;
196         }
197 
198         /**
199          * Constructs a class signature.
200          *
201          * @param p         type parameters.
202          */
ClassSignature(TypeParameter[] p)203         public ClassSignature(TypeParameter[] p) {
204             this(p, null, null);
205         }
206 
207         /**
208          * Returns the type parameters.
209          *
210          * @return a zero-length array if the type parameters are not specified.
211          */
getParameters()212         public TypeParameter[] getParameters() {
213             return params;
214         }
215 
216         /**
217          * Returns the super class.
218          */
getSuperClass()219         public ClassType getSuperClass() { return superClass; }
220 
221         /**
222          * Returns the super interfaces.
223          *
224          * @return a zero-length array if the super interfaces are not specified.
225          */
getInterfaces()226         public ClassType[] getInterfaces() { return interfaces; }
227 
228         /**
229          * Returns the string representation.
230          */
231         @Override
toString()232         public String toString() {
233             StringBuffer sbuf = new StringBuffer();
234 
235             TypeParameter.toString(sbuf, params);
236             sbuf.append(" extends ").append(superClass);
237             if (interfaces.length > 0) {
238                 sbuf.append(" implements ");
239                 Type.toString(sbuf, interfaces);
240             }
241 
242             return sbuf.toString();
243         }
244 
245         /**
246          * Returns the encoded string representing the method type signature.
247          */
encode()248         public String encode() {
249             StringBuffer sbuf = new StringBuffer();
250             if (params.length > 0) {
251                 sbuf.append('<');
252                 for (int i = 0; i < params.length; i++)
253                     params[i].encode(sbuf);
254 
255                 sbuf.append('>');
256             }
257 
258             superClass.encode(sbuf);
259             for (int i = 0; i < interfaces.length; i++)
260                 interfaces[i].encode(sbuf);
261 
262             return sbuf.toString();
263         }
264     }
265 
266     /**
267      * Method type signature.
268      */
269     public static class MethodSignature {
270         TypeParameter[] typeParams;
271         Type[] params;
272         Type retType;
273         ObjectType[] exceptions;
274 
275         /**
276          * Constructs a method type signature.  Any parameter can be null
277          * to represent <code>void</code> or nothing.
278          *
279          * @param tp        type parameters.
280          * @param params    parameter types.
281          * @param ret       a return type, or null if the return type is <code>void</code>.
282          * @param ex        exception types.
283          */
MethodSignature(TypeParameter[] tp, Type[] params, Type ret, ObjectType[] ex)284         public MethodSignature(TypeParameter[] tp, Type[] params, Type ret, ObjectType[] ex) {
285             typeParams = tp == null ? new TypeParameter[0] : tp;
286             this.params = params == null ? new Type[0] : params;
287             retType = ret == null ? new BaseType("void") : ret;
288             exceptions = ex == null ? new ObjectType[0] : ex;
289         }
290 
291         /**
292          * Returns the formal type parameters.
293          *
294          * @return a zero-length array if the type parameters are not specified.
295          */
getTypeParameters()296         public TypeParameter[] getTypeParameters() { return typeParams; }
297 
298         /**
299          * Returns the types of the formal parameters.
300          *
301          * @return a zero-length array if no formal parameter is taken.
302          */
getParameterTypes()303         public Type[] getParameterTypes() { return params; }
304 
305         /**
306          * Returns the type of the returned value.
307          */
getReturnType()308         public Type getReturnType() { return retType; }
309 
310         /**
311          * Returns the types of the exceptions that may be thrown.
312          *
313          * @return a zero-length array if exceptions are never thrown or
314          * the exception types are not parameterized types or type variables.
315          */
getExceptionTypes()316         public ObjectType[] getExceptionTypes() { return exceptions; }
317 
318         /**
319          * Returns the string representation.
320          */
321         @Override
toString()322         public String toString() {
323             StringBuffer sbuf = new StringBuffer();
324 
325             TypeParameter.toString(sbuf, typeParams);
326             sbuf.append(" (");
327             Type.toString(sbuf, params);
328             sbuf.append(") ");
329             sbuf.append(retType);
330             if (exceptions.length > 0) {
331                 sbuf.append(" throws ");
332                 Type.toString(sbuf, exceptions);
333             }
334 
335             return sbuf.toString();
336         }
337 
338         /**
339          * Returns the encoded string representing the method type signature.
340          */
encode()341         public String encode() {
342             StringBuffer sbuf = new StringBuffer();
343             if (typeParams.length > 0) {
344                 sbuf.append('<');
345                 for (int i = 0; i < typeParams.length; i++)
346                     typeParams[i].encode(sbuf);
347 
348                 sbuf.append('>');
349             }
350 
351             sbuf.append('(');
352             for (int i = 0; i < params.length; i++)
353                 params[i].encode(sbuf);
354 
355             sbuf.append(')');
356             retType.encode(sbuf);
357             if (exceptions.length > 0)
358                 for (int i = 0; i < exceptions.length; i++) {
359                     sbuf.append('^');
360                     exceptions[i].encode(sbuf);
361                 }
362 
363             return sbuf.toString();
364         }
365     }
366 
367     /**
368      * Formal type parameters.
369      *
370      * @see TypeArgument
371      */
372     public static class TypeParameter {
373         String name;
374         ObjectType superClass;
375         ObjectType[] superInterfaces;
376 
TypeParameter(String sig, int nb, int ne, ObjectType sc, ObjectType[] si)377         TypeParameter(String sig, int nb, int ne, ObjectType sc, ObjectType[] si) {
378             name = sig.substring(nb, ne);
379             superClass = sc;
380             superInterfaces = si;
381         }
382 
383         /**
384          * Constructs a <code>TypeParameter</code> representing a type parametre
385          * like <code>&lt;T extends ... &gt;</code>.
386          *
387          * @param name      parameter name.
388          * @param superClass    an upper bound class-type (or null).
389          * @param superInterfaces   an upper bound interface-type (or null).
390          */
TypeParameter(String name, ObjectType superClass, ObjectType[] superInterfaces)391         public TypeParameter(String name, ObjectType superClass, ObjectType[] superInterfaces) {
392             this.name = name;
393             this.superClass = superClass;
394             if (superInterfaces == null)
395                 this.superInterfaces = new ObjectType[0];
396             else
397                 this.superInterfaces = superInterfaces;
398         }
399 
400         /**
401          * Constructs a <code>TypeParameter</code> representing a type parameter
402          * like <code>&lt;T&gt;</code>.
403          *
404          * @param name          parameter name.
405          */
TypeParameter(String name)406         public TypeParameter(String name) {
407             this(name, null, null);
408         }
409 
410         /**
411          * Returns the name of the type parameter.
412          */
getName()413         public String getName() {
414             return name;
415         }
416 
417         /**
418          * Returns the class bound of this parameter.
419          */
getClassBound()420         public ObjectType getClassBound() { return superClass; }
421 
422         /**
423          * Returns the interface bound of this parameter.
424          *
425          * @return a zero-length array if the interface bound is not specified.
426          */
getInterfaceBound()427         public ObjectType[] getInterfaceBound() { return superInterfaces; }
428 
429         /**
430          * Returns the string representation.
431          */
432         @Override
toString()433         public String toString() {
434             StringBuffer sbuf = new StringBuffer(getName());
435             if (superClass != null)
436                 sbuf.append(" extends ").append(superClass.toString());
437 
438             int len = superInterfaces.length;
439             if (len > 0) {
440                 for (int i = 0; i < len; i++) {
441                     if (i > 0 || superClass != null)
442                         sbuf.append(" & ");
443                     else
444                         sbuf.append(" extends ");
445 
446                     sbuf.append(superInterfaces[i].toString());
447                 }
448             }
449 
450             return sbuf.toString();
451         }
452 
toString(StringBuffer sbuf, TypeParameter[] tp)453         static void toString(StringBuffer sbuf, TypeParameter[] tp) {
454             sbuf.append('<');
455             for (int i = 0; i < tp.length; i++) {
456                 if (i > 0)
457                     sbuf.append(", ");
458 
459                 sbuf.append(tp[i]);
460             }
461 
462             sbuf.append('>');
463         }
464 
encode(StringBuffer sb)465         void encode(StringBuffer sb) {
466             sb.append(name);
467             if (superClass == null)
468                 sb.append(":Ljava/lang/Object;");
469             else {
470                 sb.append(':');
471                 superClass.encode(sb);
472             }
473 
474             for (int i = 0; i < superInterfaces.length; i++) {
475                 sb.append(':');
476                 superInterfaces[i].encode(sb);
477             }
478         }
479     }
480 
481     /**
482      * Type argument.
483      *
484      * @see TypeParameter
485      */
486     public static class TypeArgument {
487         ObjectType arg;
488         char wildcard;
489 
TypeArgument(ObjectType a, char w)490         TypeArgument(ObjectType a, char w) {
491             arg = a;
492             wildcard = w;
493         }
494 
495         /**
496          * Constructs a <code>TypeArgument</code>.
497          * A type argument is <code>&lt;String&gt;</code>, <code>&lt;int[]&gt;</code>,
498          * or a type variable <code>&lt;T&gt;</code>, etc.
499          *
500          * @param t         a class type, an array type, or a type variable.
501          */
TypeArgument(ObjectType t)502         public TypeArgument(ObjectType t) {
503             this(t, ' ');
504         }
505 
506         /**
507          * Constructs a <code>TypeArgument</code> representing <code>&lt;?&gt;</code>.
508          */
TypeArgument()509         public TypeArgument() {
510             this(null, '*');
511         }
512 
513         /**
514          * A factory method constructing a <code>TypeArgument</code> with an upper bound.
515          * It represents <code>&lt;? extends ... &gt;</code>
516          *
517          * @param t     an upper bound type.
518          */
subclassOf(ObjectType t)519         public static TypeArgument subclassOf(ObjectType t) {
520             return new TypeArgument(t, '+');
521         }
522 
523         /**
524          * A factory method constructing a <code>TypeArgument</code> with an lower bound.
525          * It represents <code>&lt;? super ... &gt;</code>
526          *
527          * @param t     an lower bbound type.
528          */
superOf(ObjectType t)529         public static TypeArgument superOf(ObjectType t) {
530             return new TypeArgument(t, '-');
531         }
532 
533         /**
534          * Returns the kind of this type argument.
535          *
536          * @return <code>' '</code> (not-wildcard), <code>'*'</code> (wildcard), <code>'+'</code> (wildcard with
537          * upper bound), or <code>'-'</code> (wildcard with lower bound).
538          */
getKind()539         public char getKind() { return wildcard; }
540 
541         /**
542          * Returns true if this type argument is a wildcard type
543          * such as <code>?</code>, <code>? extends String</code>, or <code>? super Integer</code>.
544          */
isWildcard()545         public boolean isWildcard() { return wildcard != ' '; }
546 
547         /**
548          * Returns the type represented by this argument
549          * if the argument is not a wildcard type.  Otherwise, this method
550          * returns the upper bound (if the kind is '+'),
551          * the lower bound (if the kind is '-'), or null (if the upper or lower
552          * bound is not specified).
553          */
getType()554         public ObjectType getType() { return arg; }
555 
556         /**
557          * Returns the string representation.
558          */
559         @Override
toString()560         public String toString() {
561             if (wildcard == '*')
562                 return "?";
563 
564             String type = arg.toString();
565             if (wildcard == ' ')
566                 return type;
567             else if (wildcard == '+')
568                 return "? extends " + type;
569             else
570                 return "? super " + type;
571         }
572 
encode(StringBuffer sb, TypeArgument[] args)573         static void encode(StringBuffer sb, TypeArgument[] args) {
574             sb.append('<');
575             for (int i = 0; i < args.length; i++) {
576                 TypeArgument ta = args[i];
577                 if (ta.isWildcard())
578                     sb.append(ta.wildcard);
579 
580                 if (ta.getType() != null)
581                     ta.getType().encode(sb);
582             }
583 
584             sb.append('>');
585         }
586     }
587 
588     /**
589      * Primitive types and object types.
590      */
591     public static abstract class Type {
encode(StringBuffer sb)592         abstract void encode(StringBuffer sb);
toString(StringBuffer sbuf, Type[] ts)593         static void toString(StringBuffer sbuf, Type[] ts) {
594             for (int i = 0; i < ts.length; i++) {
595                 if (i > 0)
596                     sbuf.append(", ");
597 
598                 sbuf.append(ts[i]);
599             }
600         }
601 
602         /**
603          * Returns the type name in the JVM internal style.
604          * For example, if the type is a nested class {@code foo.Bar.Baz},
605          * then {@code foo.Bar$Baz} is returned.
606          */
jvmTypeName()607         public String jvmTypeName() { return toString(); }
608     }
609 
610     /**
611      * Primitive types.
612      */
613     public static class BaseType extends Type {
614         char descriptor;
BaseType(char c)615         BaseType(char c) { descriptor = c; }
616 
617         /**
618          * Constructs a <code>BaseType</code>.
619          *
620          * @param typeName      <code>void</code>, <code>int</code>, ...
621          */
BaseType(String typeName)622         public BaseType(String typeName) {
623             this(Descriptor.of(typeName).charAt(0));
624         }
625 
626         /**
627          * Returns the descriptor representing this primitive type.
628          *
629          * @see javassist.bytecode.Descriptor
630          */
getDescriptor()631         public char getDescriptor() { return descriptor; }
632 
633         /**
634          * Returns the <code>CtClass</code> representing this
635          * primitive type.
636          */
getCtlass()637         public CtClass getCtlass() {
638             return Descriptor.toPrimitiveClass(descriptor);
639         }
640 
641         /**
642          * Returns the string representation.
643          */
644         @Override
toString()645         public String toString() {
646             return Descriptor.toClassName(Character.toString(descriptor));
647         }
648 
649         @Override
encode(StringBuffer sb)650         void encode(StringBuffer sb) {
651             sb.append(descriptor);
652         }
653     }
654 
655     /**
656      * Class types, array types, and type variables.
657      * This class is also used for representing a field type.
658      */
659     public static abstract class ObjectType extends Type {
660         /**
661          * Returns the encoded string representing the object type signature.
662          */
encode()663         public String encode() {
664             StringBuffer sb = new StringBuffer();
665             encode(sb);
666             return sb.toString();
667         }
668     }
669 
670     /**
671      * Class types.
672      */
673     public static class ClassType extends ObjectType {
674         String name;
675         TypeArgument[] arguments;
676 
make(String s, int b, int e, TypeArgument[] targs, ClassType parent)677         static ClassType make(String s, int b, int e,
678                               TypeArgument[] targs, ClassType parent) {
679             if (parent == null)
680                 return new ClassType(s, b, e, targs);
681             return new NestedClassType(s, b, e, targs, parent);
682         }
683 
ClassType(String signature, int begin, int end, TypeArgument[] targs)684         ClassType(String signature, int begin, int end, TypeArgument[] targs) {
685             name = signature.substring(begin, end).replace('/', '.');
686             arguments = targs;
687         }
688 
689         /**
690          * A class type representing <code>java.lang.Object</code>.
691          */
692         public static ClassType OBJECT = new ClassType("java.lang.Object", null);
693 
694         /**
695          * Constructs a <code>ClassType</code>.  It represents
696          * the name of a non-nested class.
697          *
698          * @param className     a fully qualified class name.
699          * @param args          type arguments or null.
700          */
ClassType(String className, TypeArgument[] args)701         public ClassType(String className, TypeArgument[] args) {
702             name = className;
703             arguments = args;
704         }
705 
706         /**
707          * Constructs a <code>ClassType</code>.  It represents
708          * the name of a non-nested class.
709          *
710          * @param className     a fully qualified class name.
711          */
ClassType(String className)712         public ClassType(String className) {
713             this(className, null);
714         }
715 
716         /**
717          * Returns the class name.
718          */
getName()719         public String getName() {
720             return name;
721         }
722 
723         /**
724          * Returns the type arguments.
725          *
726          * @return null if no type arguments are given to this class.
727          */
getTypeArguments()728         public TypeArgument[] getTypeArguments() { return arguments; }
729 
730         /**
731          * If this class is a member of another class, returns the
732          * class in which this class is declared.
733          *
734          * @return null if this class is not a member of another class.
735          */
getDeclaringClass()736         public ClassType getDeclaringClass() { return null; }
737 
738         /**
739          * Returns the string representation.
740          */
741         @Override
toString()742         public String toString() {
743             StringBuffer sbuf = new StringBuffer();
744             ClassType parent = getDeclaringClass();
745             if (parent != null)
746                 sbuf.append(parent.toString()).append('.');
747 
748             return toString2(sbuf);
749         }
750 
toString2(StringBuffer sbuf)751         private String toString2(StringBuffer sbuf) {
752             sbuf.append(name);
753             if (arguments != null) {
754                 sbuf.append('<');
755                 int n = arguments.length;
756                 for (int i = 0; i < n; i++) {
757                     if (i > 0)
758                         sbuf.append(", ");
759 
760                     sbuf.append(arguments[i].toString());
761                 }
762 
763                 sbuf.append('>');
764             }
765 
766             return sbuf.toString();
767         }
768 
769         /**
770          * Returns the type name in the JVM internal style.
771          * For example, if the type is a nested class {@code foo.Bar.Baz},
772          * then {@code foo.Bar$Baz} is returned.
773          */
774         @Override
jvmTypeName()775         public String jvmTypeName() {
776             StringBuffer sbuf = new StringBuffer();
777             ClassType parent = getDeclaringClass();
778             if (parent != null)
779                 sbuf.append(parent.jvmTypeName()).append('$');
780 
781             return toString2(sbuf);
782         }
783 
784         @Override
encode(StringBuffer sb)785         void encode(StringBuffer sb) {
786             sb.append('L');
787             encode2(sb);
788             sb.append(';');
789         }
790 
encode2(StringBuffer sb)791         void encode2(StringBuffer sb) {
792             ClassType parent = getDeclaringClass();
793             if (parent != null) {
794                 parent.encode2(sb);
795                 sb.append('$');
796             }
797 
798             sb.append(name.replace('.', '/'));
799             if (arguments != null)
800                 TypeArgument.encode(sb, arguments);
801         }
802     }
803 
804     /**
805      * Nested class types.
806      */
807     public static class NestedClassType extends ClassType {
808         ClassType parent;
NestedClassType(String s, int b, int e, TypeArgument[] targs, ClassType p)809         NestedClassType(String s, int b, int e,
810                         TypeArgument[] targs, ClassType p) {
811             super(s, b, e, targs);
812             parent = p;
813         }
814 
815         /**
816          * Constructs a <code>NestedClassType</code>.
817          *
818          * @param parent        the class surrounding this class type.
819          * @param className     a simple class name.  It does not include
820          *                      a package name or a parent's class name.
821          * @param args          type parameters or null.
822          */
NestedClassType(ClassType parent, String className, TypeArgument[] args)823         public NestedClassType(ClassType parent, String className, TypeArgument[] args) {
824             super(className, args);
825             this.parent = parent;
826         }
827 
828         /**
829          * Returns the class that declares this nested class.
830          * This nested class is a member of that declaring class.
831          */
832         @Override
getDeclaringClass()833         public ClassType getDeclaringClass() { return parent; }
834     }
835 
836     /**
837      * Array types.
838      */
839     public static class ArrayType extends ObjectType {
840         int dim;
841         Type componentType;
842 
843         /**
844          * Constructs an <code>ArrayType</code>.
845          *
846          * @param d         dimension.
847          * @param comp      the component type.
848          */
ArrayType(int d, Type comp)849         public ArrayType(int d, Type comp) {
850             dim = d;
851             componentType = comp;
852         }
853 
854         /**
855          * Returns the dimension of the array.
856          */
getDimension()857         public int getDimension() { return dim; }
858 
859         /**
860          * Returns the component type.
861          */
getComponentType()862         public Type getComponentType() {
863             return componentType;
864         }
865 
866         /**
867          * Returns the string representation.
868          */
869         @Override
toString()870         public String toString() {
871             StringBuffer sbuf = new StringBuffer(componentType.toString());
872             for (int i = 0; i < dim; i++)
873                 sbuf.append("[]");
874 
875             return sbuf.toString();
876         }
877 
878         @Override
encode(StringBuffer sb)879         void encode(StringBuffer sb) {
880             for (int i = 0; i < dim; i++)
881                 sb.append('[');
882 
883             componentType.encode(sb);
884         }
885     }
886 
887     /**
888      * Type variables.
889      */
890     public static class TypeVariable extends ObjectType {
891         String name;
892 
TypeVariable(String sig, int begin, int end)893         TypeVariable(String sig, int begin, int end) {
894             name = sig.substring(begin, end);
895         }
896 
897         /**
898          * Constructs a <code>TypeVariable</code>.
899          *
900          * @param name      the name of a type variable.
901          */
TypeVariable(String name)902         public TypeVariable(String name) {
903             this.name = name;
904         }
905 
906         /**
907          * Returns the variable name.
908          */
getName()909         public String getName() {
910             return name;
911         }
912 
913         /**
914          * Returns the string representation.
915          */
916         @Override
toString()917         public String toString() {
918             return name;
919         }
920 
921         @Override
encode(StringBuffer sb)922         void encode(StringBuffer sb) {
923             sb.append('T').append(name).append(';');
924         }
925     }
926 
927     /**
928      * Parses the given signature string as a class signature.
929      *
930      * @param  sig                  the signature obtained from the <code>SignatureAttribute</code>
931      *                              of a <code>ClassFile</code>.
932      * @return  a tree-like data structure representing a class signature.  It provides
933      *          convenient accessor methods.
934      * @throws BadBytecode          thrown when a syntactical error is found.
935      * @see #getSignature()
936      * @since 3.5
937      */
toClassSignature(String sig)938     public static ClassSignature toClassSignature(String sig) throws BadBytecode {
939         try {
940             return parseSig(sig);
941         }
942         catch (IndexOutOfBoundsException e) {
943             throw error(sig);
944         }
945     }
946 
947     /**
948      * Parses the given signature string as a method type signature.
949      *
950      * @param  sig                  the signature obtained from the <code>SignatureAttribute</code>
951      *                              of a <code>MethodInfo</code>.
952      * @return  @return  a tree-like data structure representing a method signature.  It provides
953      *          convenient accessor methods.
954      * @throws BadBytecode          thrown when a syntactical error is found.
955      * @see #getSignature()
956      * @since 3.5
957      */
toMethodSignature(String sig)958     public static MethodSignature toMethodSignature(String sig) throws BadBytecode {
959         try {
960             return parseMethodSig(sig);
961         }
962         catch (IndexOutOfBoundsException e) {
963             throw error(sig);
964         }
965     }
966 
967     /**
968      * Parses the given signature string as a field type signature.
969      *
970      * @param  sig                  the signature string obtained from the <code>SignatureAttribute</code>
971      *                              of a <code>FieldInfo</code>.
972      * @return the field type signature.
973      * @throws BadBytecode          thrown when a syntactical error is found.
974      * @see #getSignature()
975      * @since 3.5
976      */
toFieldSignature(String sig)977     public static ObjectType toFieldSignature(String sig) throws BadBytecode {
978         try {
979             return parseObjectType(sig, new Cursor(), false);
980         }
981         catch (IndexOutOfBoundsException e) {
982             throw error(sig);
983         }
984     }
985 
986     /**
987      * Parses the given signature string as a type signature.
988      * The type signature is either the field type signature or a base type
989      * descriptor including <code>void</code> type.
990      *
991      * @throws BadBytecode		thrown when a syntactical error is found.
992      * @since 3.18
993      */
toTypeSignature(String sig)994     public static Type toTypeSignature(String sig) throws BadBytecode {
995     	try {
996     		return parseType(sig, new Cursor());
997     	}
998     	catch (IndexOutOfBoundsException e) {
999             throw error(sig);
1000         }
1001     }
1002 
parseSig(String sig)1003     private static ClassSignature parseSig(String sig)
1004         throws BadBytecode, IndexOutOfBoundsException
1005     {
1006         Cursor cur = new Cursor();
1007         TypeParameter[] tp = parseTypeParams(sig, cur);
1008         ClassType superClass = parseClassType(sig, cur);
1009         int sigLen = sig.length();
1010         List<ClassType> ifArray = new ArrayList<ClassType>();
1011         while (cur.position < sigLen && sig.charAt(cur.position) == 'L')
1012             ifArray.add(parseClassType(sig, cur));
1013 
1014         ClassType[] ifs
1015             = ifArray.toArray(new ClassType[ifArray.size()]);
1016         return new ClassSignature(tp, superClass, ifs);
1017     }
1018 
parseMethodSig(String sig)1019     private static MethodSignature parseMethodSig(String sig)
1020         throws BadBytecode
1021     {
1022         Cursor cur = new Cursor();
1023         TypeParameter[] tp = parseTypeParams(sig, cur);
1024         if (sig.charAt(cur.position++) != '(')
1025             throw error(sig);
1026 
1027         List<Type> params = new ArrayList<Type>();
1028         while (sig.charAt(cur.position) != ')') {
1029             Type t = parseType(sig, cur);
1030             params.add(t);
1031         }
1032 
1033         cur.position++;
1034         Type ret = parseType(sig, cur);
1035         int sigLen = sig.length();
1036         List<ObjectType> exceptions = new ArrayList<ObjectType>();
1037         while (cur.position < sigLen && sig.charAt(cur.position) == '^') {
1038             cur.position++;
1039             ObjectType t = parseObjectType(sig, cur, false);
1040             if (t instanceof ArrayType)
1041                 throw error(sig);
1042 
1043             exceptions.add(t);
1044         }
1045 
1046         Type[] p = params.toArray(new Type[params.size()]);
1047         ObjectType[] ex = exceptions.toArray(new ObjectType[exceptions.size()]);
1048         return new MethodSignature(tp, p, ret, ex);
1049     }
1050 
parseTypeParams(String sig, Cursor cur)1051     private static TypeParameter[] parseTypeParams(String sig, Cursor cur)
1052         throws BadBytecode
1053     {
1054         List<TypeParameter> typeParam = new ArrayList<TypeParameter>();
1055         if (sig.charAt(cur.position) == '<') {
1056             cur.position++;
1057             while (sig.charAt(cur.position) != '>') {
1058                 int nameBegin = cur.position;
1059                 int nameEnd = cur.indexOf(sig, ':');
1060                 ObjectType classBound = parseObjectType(sig, cur, true);
1061                 List<ObjectType> ifBound = new ArrayList<ObjectType>();
1062                 while (sig.charAt(cur.position) == ':') {
1063                     cur.position++;
1064                     ObjectType t = parseObjectType(sig, cur, false);
1065                     ifBound.add(t);
1066                 }
1067 
1068                 TypeParameter p = new TypeParameter(sig, nameBegin, nameEnd,
1069                         classBound, ifBound.toArray(new ObjectType[ifBound.size()]));
1070                 typeParam.add(p);
1071             }
1072 
1073             cur.position++;
1074         }
1075 
1076         return typeParam.toArray(new TypeParameter[typeParam.size()]);
1077     }
1078 
parseObjectType(String sig, Cursor c, boolean dontThrow)1079     private static ObjectType parseObjectType(String sig, Cursor c, boolean dontThrow)
1080         throws BadBytecode
1081     {
1082         int i;
1083         int begin = c.position;
1084         switch (sig.charAt(begin)) {
1085         case 'L' :
1086             return parseClassType2(sig, c, null);
1087         case 'T' :
1088             i = c.indexOf(sig, ';');
1089             return new TypeVariable(sig, begin + 1, i);
1090         case '[' :
1091             return parseArray(sig, c);
1092         default :
1093             if (dontThrow)
1094                 return null;
1095             throw error(sig);
1096         }
1097     }
1098 
parseClassType(String sig, Cursor c)1099     private static ClassType parseClassType(String sig, Cursor c)
1100         throws BadBytecode
1101     {
1102         if (sig.charAt(c.position) == 'L')
1103             return parseClassType2(sig, c, null);
1104         throw error(sig);
1105     }
1106 
parseClassType2(String sig, Cursor c, ClassType parent)1107     private static ClassType parseClassType2(String sig, Cursor c, ClassType parent)
1108         throws BadBytecode
1109     {
1110         int start = ++c.position;
1111         char t;
1112         do {
1113             t = sig.charAt(c.position++);
1114         } while (t != '$' && t != '<' && t != ';');
1115         int end = c.position - 1;
1116         TypeArgument[] targs;
1117         if (t == '<') {
1118             targs = parseTypeArgs(sig, c);
1119             t = sig.charAt(c.position++);
1120         }
1121         else
1122             targs = null;
1123 
1124         ClassType thisClass = ClassType.make(sig, start, end, targs, parent);
1125         if (t == '$' || t == '.') {
1126             c.position--;
1127             return parseClassType2(sig, c, thisClass);
1128         }
1129         return thisClass;
1130     }
1131 
parseTypeArgs(String sig, Cursor c)1132     private static TypeArgument[] parseTypeArgs(String sig, Cursor c) throws BadBytecode {
1133         List<TypeArgument> args = new ArrayList<TypeArgument>();
1134         char t;
1135         while ((t = sig.charAt(c.position++)) != '>') {
1136             TypeArgument ta;
1137             if (t == '*' )
1138                 ta = new TypeArgument(null, '*');
1139             else {
1140                 if (t != '+' && t != '-') {
1141                     t = ' ';
1142                     c.position--;
1143                 }
1144 
1145                 ta = new TypeArgument(parseObjectType(sig, c, false), t);
1146             }
1147 
1148             args.add(ta);
1149         }
1150 
1151         return args.toArray(new TypeArgument[args.size()]);
1152     }
1153 
parseArray(String sig, Cursor c)1154     private static ObjectType parseArray(String sig, Cursor c) throws BadBytecode {
1155         int dim = 1;
1156         while (sig.charAt(++c.position) == '[')
1157             dim++;
1158 
1159         return new ArrayType(dim, parseType(sig, c));
1160     }
1161 
parseType(String sig, Cursor c)1162     private static Type parseType(String sig, Cursor c) throws BadBytecode {
1163         Type t = parseObjectType(sig, c, true);
1164         if (t == null)
1165             t = new BaseType(sig.charAt(c.position++));
1166 
1167         return t;
1168     }
1169 
error(String sig)1170     private static BadBytecode error(String sig) {
1171         return new BadBytecode("bad signature: " + sig);
1172     }
1173 }
1174