All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.feilong.lib.javassist.bytecode.SignatureAttribute Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.0.8
Show newest version
/*
 * Javassist, a Java-bytecode translator toolkit.
 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License.  Alternatively, the contents of this file may be used under
 * the terms of the GNU Lesser General Public License Version 2.1 or later,
 * or the Apache License Version 2.0.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 */

package com.feilong.lib.javassist.bytecode;

import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.feilong.lib.javassist.CtClass;

/**
 * Signature_attribute.
 */
public class SignatureAttribute extends AttributeInfo{

    /**
     * The name of this attribute "Signature".
     */
    public static final String tag = "Signature";

    SignatureAttribute(ConstPool cp, int n, DataInputStream in) throws IOException{
        super(cp, n, in);
    }

    /**
     * Constructs a Signature attribute.
     *
     * @param cp
     *            a constant pool table.
     * @param signature
     *            the signature represented by this attribute.
     */
    public SignatureAttribute(ConstPool cp, String signature){
        super(cp, tag);
        int index = cp.addUtf8Info(signature);
        byte[] bvalue = new byte[2];
        bvalue[0] = (byte) (index >>> 8);
        bvalue[1] = (byte) index;
        set(bvalue);
    }

    /**
     * Returns the generic signature indicated by signature_index.
     *
     * @see #toClassSignature(String)
     * @see #toMethodSignature(String)
     * @see #toFieldSignature(String)
     */
    public String getSignature(){
        return getConstPool().getUtf8Info(ByteArray.readU16bit(get(), 0));
    }

    /**
     * Sets signature_index to the index of the given generic signature,
     * which is added to a constant pool.
     *
     * @param sig
     *            new signature.
     * @since 3.11
     */
    public void setSignature(String sig){
        int index = getConstPool().addUtf8Info(sig);
        ByteArray.write16bit(index, info, 0);
    }

    /**
     * Makes a copy. Class names are replaced according to the
     * given Map object.
     *
     * @param newCp
     *            the constant pool table used by the new copy.
     * @param classnames
     *            pairs of replaced and substituted
     *            class names.
     */
    @Override
    public AttributeInfo copy(ConstPool newCp,Map classnames){
        return new SignatureAttribute(newCp, getSignature());
    }

    @Override
    void renameClass(String oldname,String newname){
        String sig = renameClass(getSignature(), oldname, newname);
        setSignature(sig);
    }

    @Override
    void renameClass(Map classnames){
        String sig = renameClass(getSignature(), classnames);
        setSignature(sig);
    }

    static String renameClass(String desc,String oldname,String newname){
        Map map = new HashMap<>();
        map.put(oldname, newname);
        return renameClass(desc, map);
    }

    static String renameClass(String desc,Map map){
        if (map == null){
            return desc;
        }

        StringBuilder newdesc = new StringBuilder();
        int head = 0;
        int i = 0;
        for (;;){
            int j = desc.indexOf('L', i);
            if (j < 0){
                break;
            }

            StringBuilder nameBuf = new StringBuilder();
            int k = j;
            char c;
            try{
                while ((c = desc.charAt(++k)) != ';'){
                    nameBuf.append(c);
                    if (c == '<'){
                        while ((c = desc.charAt(++k)) != '>'){
                            nameBuf.append(c);
                        }

                        nameBuf.append(c);
                    }
                }
            }catch (IndexOutOfBoundsException e){
                break;
            }
            i = k + 1;
            String name = nameBuf.toString();
            String name2 = map.get(name);
            if (name2 != null){
                newdesc.append(desc.substring(head, j));
                newdesc.append('L');
                newdesc.append(name2);
                newdesc.append(c);
                head = i;
            }
        }

        if (head == 0){
            return desc;
        }
        int len = desc.length();
        if (head < len){
            newdesc.append(desc.substring(head, len));
        }

        return newdesc.toString();
    }

    @SuppressWarnings("unused")
    private static boolean isNamePart(int c){
        return c != ';' && c != '<';
    }

    static private class Cursor{

        int position = 0;

        int indexOf(String s,int ch) throws BadBytecode{
            int i = s.indexOf(ch, position);
            if (i < 0){
                throw error(s);
            }
            position = i + 1;
            return i;
        }
    }

    /**
     * Class signature.
     */
    public static class ClassSignature{

        TypeParameter[] params;

        ClassType       superClass;

        ClassType[]     interfaces;

        /**
         * Constructs a class signature.
         *
         * @param params
         *            type parameters.
         * @param superClass
         *            the super class.
         * @param interfaces
         *            the interface types.
         */
        public ClassSignature(TypeParameter[] params, ClassType superClass, ClassType[] interfaces){
            this.params = params == null ? new TypeParameter[0] : params;
            this.superClass = superClass == null ? ClassType.OBJECT : superClass;
            this.interfaces = interfaces == null ? new ClassType[0] : interfaces;
        }

        /**
         * Constructs a class signature.
         *
         * @param p
         *            type parameters.
         */
        public ClassSignature(TypeParameter[] p){
            this(p, null, null);
        }

        /**
         * Returns the type parameters.
         *
         * @return a zero-length array if the type parameters are not specified.
         */
        public TypeParameter[] getParameters(){
            return params;
        }

        /**
         * Returns the super class.
         */
        public ClassType getSuperClass(){
            return superClass;
        }

        /**
         * Returns the super interfaces.
         *
         * @return a zero-length array if the super interfaces are not specified.
         */
        public ClassType[] getInterfaces(){
            return interfaces;
        }

        /**
         * Returns the string representation.
         */
        @Override
        public String toString(){
            StringBuffer sbuf = new StringBuffer();

            TypeParameter.toString(sbuf, params);
            sbuf.append(" extends ").append(superClass);
            if (interfaces.length > 0){
                sbuf.append(" implements ");
                Type.toString(sbuf, interfaces);
            }

            return sbuf.toString();
        }

        /**
         * Returns the encoded string representing the method type signature.
         */
        public String encode(){
            StringBuffer sbuf = new StringBuffer();
            if (params.length > 0){
                sbuf.append('<');
                for (TypeParameter param : params){
                    param.encode(sbuf);
                }

                sbuf.append('>');
            }

            superClass.encode(sbuf);
            for (ClassType interface1 : interfaces){
                interface1.encode(sbuf);
            }

            return sbuf.toString();
        }
    }

    /**
     * Method type signature.
     */
    public static class MethodSignature{

        TypeParameter[] typeParams;

        Type[]          params;

        Type            retType;

        ObjectType[]    exceptions;

        /**
         * Constructs a method type signature. Any parameter can be null
         * to represent void or nothing.
         *
         * @param tp
         *            type parameters.
         * @param params
         *            parameter types.
         * @param ret
         *            a return type, or null if the return type is void.
         * @param ex
         *            exception types.
         */
        public MethodSignature(TypeParameter[] tp, Type[] params, Type ret, ObjectType[] ex){
            typeParams = tp == null ? new TypeParameter[0] : tp;
            this.params = params == null ? new Type[0] : params;
            retType = ret == null ? new BaseType("void") : ret;
            exceptions = ex == null ? new ObjectType[0] : ex;
        }

        /**
         * Returns the formal type parameters.
         *
         * @return a zero-length array if the type parameters are not specified.
         */
        public TypeParameter[] getTypeParameters(){
            return typeParams;
        }

        /**
         * Returns the types of the formal parameters.
         *
         * @return a zero-length array if no formal parameter is taken.
         */
        public Type[] getParameterTypes(){
            return params;
        }

        /**
         * Returns the type of the returned value.
         */
        public Type getReturnType(){
            return retType;
        }

        /**
         * Returns the types of the exceptions that may be thrown.
         *
         * @return a zero-length array if exceptions are never thrown or
         *         the exception types are not parameterized types or type variables.
         */
        public ObjectType[] getExceptionTypes(){
            return exceptions;
        }

        /**
         * Returns the string representation.
         */
        @Override
        public String toString(){
            StringBuffer sbuf = new StringBuffer();

            TypeParameter.toString(sbuf, typeParams);
            sbuf.append(" (");
            Type.toString(sbuf, params);
            sbuf.append(") ");
            sbuf.append(retType);
            if (exceptions.length > 0){
                sbuf.append(" throws ");
                Type.toString(sbuf, exceptions);
            }

            return sbuf.toString();
        }

        /**
         * Returns the encoded string representing the method type signature.
         */
        public String encode(){
            StringBuffer sbuf = new StringBuffer();
            if (typeParams.length > 0){
                sbuf.append('<');
                for (TypeParameter typeParam : typeParams){
                    typeParam.encode(sbuf);
                }

                sbuf.append('>');
            }

            sbuf.append('(');
            for (Type param : params){
                param.encode(sbuf);
            }

            sbuf.append(')');
            retType.encode(sbuf);
            if (exceptions.length > 0){
                for (ObjectType exception : exceptions){
                    sbuf.append('^');
                    exception.encode(sbuf);
                }
            }

            return sbuf.toString();
        }
    }

    /**
     * Formal type parameters.
     *
     * @see TypeArgument
     */
    public static class TypeParameter{

        String       name;

        ObjectType   superClass;

        ObjectType[] superInterfaces;

        TypeParameter(String sig, int nb, int ne, ObjectType sc, ObjectType[] si){
            name = sig.substring(nb, ne);
            superClass = sc;
            superInterfaces = si;
        }

        /**
         * Constructs a TypeParameter representing a type parametre
         * like <T extends ... >.
         *
         * @param name
         *            parameter name.
         * @param superClass
         *            an upper bound class-type (or null).
         * @param superInterfaces
         *            an upper bound interface-type (or null).
         */
        public TypeParameter(String name, ObjectType superClass, ObjectType[] superInterfaces){
            this.name = name;
            this.superClass = superClass;
            if (superInterfaces == null){
                this.superInterfaces = new ObjectType[0];
            }else{
                this.superInterfaces = superInterfaces;
            }
        }

        /**
         * Constructs a TypeParameter representing a type parameter
         * like <T>.
         *
         * @param name
         *            parameter name.
         */
        public TypeParameter(String name){
            this(name, null, null);
        }

        /**
         * Returns the name of the type parameter.
         */
        public String getName(){
            return name;
        }

        /**
         * Returns the class bound of this parameter.
         */
        public ObjectType getClassBound(){
            return superClass;
        }

        /**
         * Returns the interface bound of this parameter.
         *
         * @return a zero-length array if the interface bound is not specified.
         */
        public ObjectType[] getInterfaceBound(){
            return superInterfaces;
        }

        /**
         * Returns the string representation.
         */
        @Override
        public String toString(){
            StringBuffer sbuf = new StringBuffer(getName());
            if (superClass != null){
                sbuf.append(" extends ").append(superClass.toString());
            }

            int len = superInterfaces.length;
            if (len > 0){
                for (int i = 0; i < len; i++){
                    if (i > 0 || superClass != null){
                        sbuf.append(" & ");
                    }else{
                        sbuf.append(" extends ");
                    }

                    sbuf.append(superInterfaces[i].toString());
                }
            }

            return sbuf.toString();
        }

        static void toString(StringBuffer sbuf,TypeParameter[] tp){
            sbuf.append('<');
            for (int i = 0; i < tp.length; i++){
                if (i > 0){
                    sbuf.append(", ");
                }

                sbuf.append(tp[i]);
            }

            sbuf.append('>');
        }

        void encode(StringBuffer sb){
            sb.append(name);
            if (superClass == null){
                sb.append(":Ljava/lang/Object;");
            }else{
                sb.append(':');
                superClass.encode(sb);
            }

            for (ObjectType superInterface : superInterfaces){
                sb.append(':');
                superInterface.encode(sb);
            }
        }
    }

    /**
     * Type argument.
     *
     * @see TypeParameter
     */
    public static class TypeArgument{

        ObjectType arg;

        char       wildcard;

        TypeArgument(ObjectType a, char w){
            arg = a;
            wildcard = w;
        }

        /**
         * Constructs a TypeArgument.
         * A type argument is <String>, <int[]>,
         * or a type variable <T>, etc.
         *
         * @param t
         *            a class type, an array type, or a type variable.
         */
        public TypeArgument(ObjectType t){
            this(t, ' ');
        }

        /**
         * Constructs a TypeArgument representing <?>.
         */
        public TypeArgument(){
            this(null, '*');
        }

        /**
         * A factory method constructing a TypeArgument with an upper bound.
         * It represents <? extends ... >
         * 
         * @param t
         *            an upper bound type.
         */
        public static TypeArgument subclassOf(ObjectType t){
            return new TypeArgument(t, '+');
        }

        /**
         * A factory method constructing a TypeArgument with an lower bound.
         * It represents <? super ... >
         * 
         * @param t
         *            an lower bbound type.
         */
        public static TypeArgument superOf(ObjectType t){
            return new TypeArgument(t, '-');
        }

        /**
         * Returns the kind of this type argument.
         *
         * @return ' ' (not-wildcard), '*' (wildcard), '+' (wildcard with
         *         upper bound), or '-' (wildcard with lower bound).
         */
        public char getKind(){
            return wildcard;
        }

        /**
         * Returns true if this type argument is a wildcard type
         * such as ?, ? extends String, or ? super Integer.
         */
        public boolean isWildcard(){
            return wildcard != ' ';
        }

        /**
         * Returns the type represented by this argument
         * if the argument is not a wildcard type. Otherwise, this method
         * returns the upper bound (if the kind is '+'),
         * the lower bound (if the kind is '-'), or null (if the upper or lower
         * bound is not specified).
         */
        public ObjectType getType(){
            return arg;
        }

        /**
         * Returns the string representation.
         */
        @Override
        public String toString(){
            if (wildcard == '*'){
                return "?";
            }

            String type = arg.toString();
            if (wildcard == ' '){
                return type;
            }else if (wildcard == '+'){
                return "? extends " + type;
            }else{
                return "? super " + type;
            }
        }

        static void encode(StringBuffer sb,TypeArgument[] args){
            sb.append('<');
            for (TypeArgument ta : args){
                if (ta.isWildcard()){
                    sb.append(ta.wildcard);
                }

                if (ta.getType() != null){
                    ta.getType().encode(sb);
                }
            }

            sb.append('>');
        }
    }

    /**
     * Primitive types and object types.
     */
    public static abstract class Type{

        abstract void encode(StringBuffer sb);

        static void toString(StringBuffer sbuf,Type[] ts){
            for (int i = 0; i < ts.length; i++){
                if (i > 0){
                    sbuf.append(", ");
                }

                sbuf.append(ts[i]);
            }
        }

        /**
         * Returns the type name in the JVM internal style.
         * For example, if the type is a nested class {@code foo.Bar.Baz},
         * then {@code foo.Bar$Baz} is returned.
         */
        public String jvmTypeName(){
            return toString();
        }
    }

    /**
     * Primitive types.
     */
    public static class BaseType extends Type{

        char descriptor;

        BaseType(char c){
            descriptor = c;
        }

        /**
         * Constructs a BaseType.
         *
         * @param typeName
         *            void, int, ...
         */
        public BaseType(String typeName){
            this(Descriptor.of(typeName).charAt(0));
        }

        /**
         * Returns the descriptor representing this primitive type.
         *
         * @see com.feilong.lib.javassist.bytecode.Descriptor
         */
        public char getDescriptor(){
            return descriptor;
        }

        /**
         * Returns the CtClass representing this
         * primitive type.
         */
        public CtClass getCtlass(){
            return Descriptor.toPrimitiveClass(descriptor);
        }

        /**
         * Returns the string representation.
         */
        @Override
        public String toString(){
            return Descriptor.toClassName(Character.toString(descriptor));
        }

        @Override
        void encode(StringBuffer sb){
            sb.append(descriptor);
        }
    }

    /**
     * Class types, array types, and type variables.
     * This class is also used for representing a field type.
     */
    public static abstract class ObjectType extends Type{

        /**
         * Returns the encoded string representing the object type signature.
         */
        public String encode(){
            StringBuffer sb = new StringBuffer();
            encode(sb);
            return sb.toString();
        }
    }

    /**
     * Class types.
     */
    public static class ClassType extends ObjectType{

        String         name;

        TypeArgument[] arguments;

        static ClassType make(String s,int b,int e,TypeArgument[] targs,ClassType parent){
            if (parent == null){
                return new ClassType(s, b, e, targs);
            }
            return new NestedClassType(s, b, e, targs, parent);
        }

        ClassType(String signature, int begin, int end, TypeArgument[] targs){
            name = signature.substring(begin, end).replace('/', '.');
            arguments = targs;
        }

        /**
         * A class type representing java.lang.Object.
         */
        public static ClassType OBJECT = new ClassType("java.lang.Object", null);

        /**
         * Constructs a ClassType. It represents
         * the name of a non-nested class.
         *
         * @param className
         *            a fully qualified class name.
         * @param args
         *            type arguments or null.
         */
        public ClassType(String className, TypeArgument[] args){
            name = className;
            arguments = args;
        }

        /**
         * Constructs a ClassType. It represents
         * the name of a non-nested class.
         *
         * @param className
         *            a fully qualified class name.
         */
        public ClassType(String className){
            this(className, null);
        }

        /**
         * Returns the class name.
         */
        public String getName(){
            return name;
        }

        /**
         * Returns the type arguments.
         *
         * @return null if no type arguments are given to this class.
         */
        public TypeArgument[] getTypeArguments(){
            return arguments;
        }

        /**
         * If this class is a member of another class, returns the
         * class in which this class is declared.
         *
         * @return null if this class is not a member of another class.
         */
        public ClassType getDeclaringClass(){
            return null;
        }

        /**
         * Returns the string representation.
         */
        @Override
        public String toString(){
            StringBuffer sbuf = new StringBuffer();
            ClassType parent = getDeclaringClass();
            if (parent != null){
                sbuf.append(parent.toString()).append('.');
            }

            return toString2(sbuf);
        }

        private String toString2(StringBuffer sbuf){
            sbuf.append(name);
            if (arguments != null){
                sbuf.append('<');
                int n = arguments.length;
                for (int i = 0; i < n; i++){
                    if (i > 0){
                        sbuf.append(", ");
                    }

                    sbuf.append(arguments[i].toString());
                }

                sbuf.append('>');
            }

            return sbuf.toString();
        }

        /**
         * Returns the type name in the JVM internal style.
         * For example, if the type is a nested class {@code foo.Bar.Baz},
         * then {@code foo.Bar$Baz} is returned.
         */
        @Override
        public String jvmTypeName(){
            StringBuffer sbuf = new StringBuffer();
            ClassType parent = getDeclaringClass();
            if (parent != null){
                sbuf.append(parent.jvmTypeName()).append('$');
            }

            return toString2(sbuf);
        }

        @Override
        void encode(StringBuffer sb){
            sb.append('L');
            encode2(sb);
            sb.append(';');
        }

        void encode2(StringBuffer sb){
            ClassType parent = getDeclaringClass();
            if (parent != null){
                parent.encode2(sb);
                sb.append('$');
            }

            sb.append(name.replace('.', '/'));
            if (arguments != null){
                TypeArgument.encode(sb, arguments);
            }
        }
    }

    /**
     * Nested class types.
     */
    public static class NestedClassType extends ClassType{

        ClassType parent;

        NestedClassType(String s, int b, int e, TypeArgument[] targs, ClassType p){
            super(s, b, e, targs);
            parent = p;
        }

        /**
         * Constructs a NestedClassType.
         *
         * @param parent
         *            the class surrounding this class type.
         * @param className
         *            a simple class name. It does not include
         *            a package name or a parent's class name.
         * @param args
         *            type parameters or null.
         */
        public NestedClassType(ClassType parent, String className, TypeArgument[] args){
            super(className, args);
            this.parent = parent;
        }

        /**
         * Returns the class that declares this nested class.
         * This nested class is a member of that declaring class.
         */
        @Override
        public ClassType getDeclaringClass(){
            return parent;
        }
    }

    /**
     * Array types.
     */
    public static class ArrayType extends ObjectType{

        int  dim;

        Type componentType;

        /**
         * Constructs an ArrayType.
         *
         * @param d
         *            dimension.
         * @param comp
         *            the component type.
         */
        public ArrayType(int d, Type comp){
            dim = d;
            componentType = comp;
        }

        /**
         * Returns the dimension of the array.
         */
        public int getDimension(){
            return dim;
        }

        /**
         * Returns the component type.
         */
        public Type getComponentType(){
            return componentType;
        }

        /**
         * Returns the string representation.
         */
        @Override
        public String toString(){
            StringBuffer sbuf = new StringBuffer(componentType.toString());
            for (int i = 0; i < dim; i++){
                sbuf.append("[]");
            }

            return sbuf.toString();
        }

        @Override
        void encode(StringBuffer sb){
            for (int i = 0; i < dim; i++){
                sb.append('[');
            }

            componentType.encode(sb);
        }
    }

    /**
     * Type variables.
     */
    public static class TypeVariable extends ObjectType{

        String name;

        TypeVariable(String sig, int begin, int end){
            name = sig.substring(begin, end);
        }

        /**
         * Constructs a TypeVariable.
         *
         * @param name
         *            the name of a type variable.
         */
        public TypeVariable(String name){
            this.name = name;
        }

        /**
         * Returns the variable name.
         */
        public String getName(){
            return name;
        }

        /**
         * Returns the string representation.
         */
        @Override
        public String toString(){
            return name;
        }

        @Override
        void encode(StringBuffer sb){
            sb.append('T').append(name).append(';');
        }
    }

    /**
     * Parses the given signature string as a class signature.
     *
     * @param sig
     *            the signature obtained from the SignatureAttribute
     *            of a ClassFile.
     * @return a tree-like data structure representing a class signature. It provides
     *         convenient accessor methods.
     * @throws BadBytecode
     *             thrown when a syntactical error is found.
     * @see #getSignature()
     * @since 3.5
     */
    public static ClassSignature toClassSignature(String sig) throws BadBytecode{
        try{
            return parseSig(sig);
        }catch (IndexOutOfBoundsException e){
            throw error(sig);
        }
    }

    /**
     * Parses the given signature string as a method type signature.
     *
     * @param sig
     *            the signature obtained from the SignatureAttribute
     *            of a MethodInfo.
     * @return @return a tree-like data structure representing a method signature. It provides
     *         convenient accessor methods.
     * @throws BadBytecode
     *             thrown when a syntactical error is found.
     * @see #getSignature()
     * @since 3.5
     */
    public static MethodSignature toMethodSignature(String sig) throws BadBytecode{
        try{
            return parseMethodSig(sig);
        }catch (IndexOutOfBoundsException e){
            throw error(sig);
        }
    }

    /**
     * Parses the given signature string as a field type signature.
     *
     * @param sig
     *            the signature string obtained from the SignatureAttribute
     *            of a FieldInfo.
     * @return the field type signature.
     * @throws BadBytecode
     *             thrown when a syntactical error is found.
     * @see #getSignature()
     * @since 3.5
     */
    public static ObjectType toFieldSignature(String sig) throws BadBytecode{
        try{
            return parseObjectType(sig, new Cursor(), false);
        }catch (IndexOutOfBoundsException e){
            throw error(sig);
        }
    }

    /**
     * Parses the given signature string as a type signature.
     * The type signature is either the field type signature or a base type
     * descriptor including void type.
     *
     * @throws BadBytecode
     *             thrown when a syntactical error is found.
     * @since 3.18
     */
    public static Type toTypeSignature(String sig) throws BadBytecode{
        try{
            return parseType(sig, new Cursor());
        }catch (IndexOutOfBoundsException e){
            throw error(sig);
        }
    }

    private static ClassSignature parseSig(String sig) throws BadBytecode,IndexOutOfBoundsException{
        Cursor cur = new Cursor();
        TypeParameter[] tp = parseTypeParams(sig, cur);
        ClassType superClass = parseClassType(sig, cur);
        int sigLen = sig.length();
        List ifArray = new ArrayList<>();
        while (cur.position < sigLen && sig.charAt(cur.position) == 'L'){
            ifArray.add(parseClassType(sig, cur));
        }

        ClassType[] ifs = ifArray.toArray(new ClassType[ifArray.size()]);
        return new ClassSignature(tp, superClass, ifs);
    }

    private static MethodSignature parseMethodSig(String sig) throws BadBytecode{
        Cursor cur = new Cursor();
        TypeParameter[] tp = parseTypeParams(sig, cur);
        if (sig.charAt(cur.position++) != '('){
            throw error(sig);
        }

        List params = new ArrayList<>();
        while (sig.charAt(cur.position) != ')'){
            Type t = parseType(sig, cur);
            params.add(t);
        }

        cur.position++;
        Type ret = parseType(sig, cur);
        int sigLen = sig.length();
        List exceptions = new ArrayList<>();
        while (cur.position < sigLen && sig.charAt(cur.position) == '^'){
            cur.position++;
            ObjectType t = parseObjectType(sig, cur, false);
            if (t instanceof ArrayType){
                throw error(sig);
            }

            exceptions.add(t);
        }

        Type[] p = params.toArray(new Type[params.size()]);
        ObjectType[] ex = exceptions.toArray(new ObjectType[exceptions.size()]);
        return new MethodSignature(tp, p, ret, ex);
    }

    private static TypeParameter[] parseTypeParams(String sig,Cursor cur) throws BadBytecode{
        List typeParam = new ArrayList<>();
        if (sig.charAt(cur.position) == '<'){
            cur.position++;
            while (sig.charAt(cur.position) != '>'){
                int nameBegin = cur.position;
                int nameEnd = cur.indexOf(sig, ':');
                ObjectType classBound = parseObjectType(sig, cur, true);
                List ifBound = new ArrayList<>();
                while (sig.charAt(cur.position) == ':'){
                    cur.position++;
                    ObjectType t = parseObjectType(sig, cur, false);
                    ifBound.add(t);
                }

                TypeParameter p = new TypeParameter(sig, nameBegin, nameEnd, classBound, ifBound.toArray(new ObjectType[ifBound.size()]));
                typeParam.add(p);
            }

            cur.position++;
        }

        return typeParam.toArray(new TypeParameter[typeParam.size()]);
    }

    private static ObjectType parseObjectType(String sig,Cursor c,boolean dontThrow) throws BadBytecode{
        int i;
        int begin = c.position;
        switch (sig.charAt(begin)) {
            case 'L':
                return parseClassType2(sig, c, null);
            case 'T':
                i = c.indexOf(sig, ';');
                return new TypeVariable(sig, begin + 1, i);
            case '[':
                return parseArray(sig, c);
            default:
                if (dontThrow){
                    return null;
                }
                throw error(sig);
        }
    }

    private static ClassType parseClassType(String sig,Cursor c) throws BadBytecode{
        if (sig.charAt(c.position) == 'L'){
            return parseClassType2(sig, c, null);
        }
        throw error(sig);
    }

    private static ClassType parseClassType2(String sig,Cursor c,ClassType parent) throws BadBytecode{
        int start = ++c.position;
        char t;
        do{
            t = sig.charAt(c.position++);
        }while (t != '$' && t != '<' && t != ';');
        int end = c.position - 1;
        TypeArgument[] targs;
        if (t == '<'){
            targs = parseTypeArgs(sig, c);
            t = sig.charAt(c.position++);
        }else{
            targs = null;
        }

        ClassType thisClass = ClassType.make(sig, start, end, targs, parent);
        if (t == '$' || t == '.'){
            c.position--;
            return parseClassType2(sig, c, thisClass);
        }
        return thisClass;
    }

    private static TypeArgument[] parseTypeArgs(String sig,Cursor c) throws BadBytecode{
        List args = new ArrayList<>();
        char t;
        while ((t = sig.charAt(c.position++)) != '>'){
            TypeArgument ta;
            if (t == '*'){
                ta = new TypeArgument(null, '*');
            }else{
                if (t != '+' && t != '-'){
                    t = ' ';
                    c.position--;
                }

                ta = new TypeArgument(parseObjectType(sig, c, false), t);
            }

            args.add(ta);
        }

        return args.toArray(new TypeArgument[args.size()]);
    }

    private static ObjectType parseArray(String sig,Cursor c) throws BadBytecode{
        int dim = 1;
        while (sig.charAt(++c.position) == '['){
            dim++;
        }

        return new ArrayType(dim, parseType(sig, c));
    }

    private static Type parseType(String sig,Cursor c) throws BadBytecode{
        Type t = parseObjectType(sig, c, true);
        if (t == null){
            t = new BaseType(sig.charAt(c.position++));
        }

        return t;
    }

    private static BadBytecode error(String sig){
        return new BadBytecode("bad signature: " + sig);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy