001    /*
002     * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.tools.classfile;
027    
028    import java.util.ArrayList;
029    import java.util.List;
030    
031    /**
032     * See JVMS3 4.4.4.
033     *
034     *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
035     *  you write code that depends on this, you do so at your own risk.
036     *  This code and its internal interfaces are subject to change or
037     *  deletion without notice.</b>
038     */
039    public class Signature extends Descriptor {
040    
041        public Signature(int index) {
042            super(index);
043        }
044    
045        public Type getType(ConstantPool constant_pool) throws ConstantPoolException {
046            if (type == null)
047                type = parse(getValue(constant_pool));
048            return type;
049        }
050    
051        @Override
052        public int getParameterCount(ConstantPool constant_pool) throws ConstantPoolException {
053            Type.MethodType m = (Type.MethodType) getType(constant_pool);
054            return m.argTypes.size();
055        }
056    
057        @Override
058        public String getParameterTypes(ConstantPool constant_pool) throws ConstantPoolException {
059            Type.MethodType m = (Type.MethodType) getType(constant_pool);
060            StringBuilder sb = new StringBuilder();
061            sb.append("(");
062            String sep = "";
063            for (Type argType: m.argTypes) {
064                sb.append(sep);
065                sb.append(argType);
066                sep = ", ";
067            }
068            sb.append(")");
069            return sb.toString();
070        }
071    
072        @Override
073        public String getReturnType(ConstantPool constant_pool) throws ConstantPoolException {
074            Type.MethodType m = (Type.MethodType) getType(constant_pool);
075            return m.returnType.toString();
076        }
077    
078        @Override
079        public String getFieldType(ConstantPool constant_pool) throws ConstantPoolException {
080            return getType(constant_pool).toString();
081        }
082    
083        private Type parse(String sig) {
084            this.sig = sig;
085            sigp = 0;
086    
087            List<Type> typeArgTypes = null;
088            if (sig.charAt(sigp) == '<')
089                typeArgTypes = parseTypeArgTypes();
090    
091            if (sig.charAt(sigp) == '(') {
092                List<Type> argTypes = parseTypeSignatures(')');
093                Type returnType = parseTypeSignature();
094                List<Type> throwsTypes = null;
095                while (sigp < sig.length() && sig.charAt(sigp) == '^') {
096                    sigp++;
097                    if (throwsTypes == null)
098                        throwsTypes = new ArrayList<Type>();
099                    throwsTypes.add(parseTypeSignature());
100                }
101                return new Type.MethodType(typeArgTypes, argTypes, returnType, throwsTypes);
102            } else {
103                Type t = parseTypeSignature();
104                if (typeArgTypes == null && sigp == sig.length())
105                    return t;
106                Type superclass = t;
107                List<Type> superinterfaces = new ArrayList<Type>();
108                while (sigp < sig.length())
109                    superinterfaces.add(parseTypeSignature());
110                return new Type.ClassSigType(typeArgTypes, superclass, superinterfaces);
111    
112            }
113        }
114    
115        private Type parseTypeSignature() {
116            switch (sig.charAt(sigp)) {
117                case 'B':
118                    sigp++;
119                    return new Type.SimpleType("byte");
120    
121                case 'C':
122                    sigp++;
123                    return new Type.SimpleType("char");
124    
125                case 'D':
126                    sigp++;
127                    return new Type.SimpleType("double");
128    
129                case 'F':
130                    sigp++;
131                    return new Type.SimpleType("float");
132    
133                case 'I':
134                    sigp++;
135                    return new Type.SimpleType("int");
136    
137                case 'J':
138                    sigp++;
139                    return new Type.SimpleType("long");
140    
141                case 'L':
142                    return parseClassTypeSignature();
143    
144                case 'S':
145                    sigp++;
146                    return new Type.SimpleType("short");
147    
148                case 'T':
149                    return parseTypeVariableSignature();
150    
151                case 'V':
152                    sigp++;
153                    return new Type.SimpleType("void");
154    
155                case 'Z':
156                    sigp++;
157                    return new Type.SimpleType("boolean");
158    
159                case '[':
160                    sigp++;
161                    return new Type.ArrayType(parseTypeSignature());
162    
163                case '*':
164                    sigp++;
165                    return new Type.WildcardType();
166    
167                case '+':
168                    sigp++;
169                    return new Type.WildcardType("extends", parseTypeSignature());
170    
171                case '-':
172                    sigp++;
173                    return new Type.WildcardType("super", parseTypeSignature());
174    
175                default:
176                    throw new IllegalStateException(debugInfo());
177            }
178        }
179    
180        private List<Type> parseTypeSignatures(char term) {
181            sigp++;
182            List<Type> types = new ArrayList<Type>();
183            while (sig.charAt(sigp) != term)
184                types.add(parseTypeSignature());
185            sigp++;
186            return types;
187        }
188    
189        private Type parseClassTypeSignature() {
190            assert sig.charAt(sigp) == 'L';
191            sigp++;
192            return parseClassTypeSignatureRest();
193        }
194    
195        private Type parseClassTypeSignatureRest() {
196            StringBuilder sb = new StringBuilder();
197            Type t = null;
198            char sigch;
199            while (true) {
200                switch  (sigch = sig.charAt(sigp)) {
201                    case '/':
202                        sigp++;
203                        sb.append(".");
204                        break;
205    
206                    case '.':
207                        sigp++;
208                        if (t == null)
209                            t = new Type.SimpleType(sb.toString());
210                        return new Type.InnerClassType(t, parseClassTypeSignatureRest());
211    
212                    case ';':
213                        sigp++;
214                        if (t == null)
215                            t = new Type.SimpleType(sb.toString());
216                        return t;
217    
218                    case '<':
219                        List<Type> argTypes = parseTypeSignatures('>');
220                        t = new Type.ClassType(sb.toString(), argTypes);
221                        break;
222    
223                    default:
224                        sigp++;
225                        sb.append(sigch);
226                        break;
227                }
228            }
229        }
230    
231        private List<Type> parseTypeArgTypes() {
232            assert sig.charAt(sigp) == '<';
233            sigp++;
234            List<Type> types = null;
235            types = new ArrayList<Type>();
236            while (sig.charAt(sigp) != '>')
237                types.add(parseTypeArgType());
238            sigp++;
239            return types;
240        }
241    
242        private Type parseTypeArgType() {
243            int sep = sig.indexOf(":", sigp);
244            String name = sig.substring(sigp, sep);
245            Type classBound = null;
246            List<Type> interfaceBounds = null;
247            sigp = sep + 1;
248            if (sig.charAt(sigp) != ':')
249                classBound = parseTypeSignature();
250            while (sig.charAt(sigp) == ':') {
251                sigp++;
252                if (interfaceBounds == null)
253                    interfaceBounds = new ArrayList<Type>();
254                interfaceBounds.add(parseTypeSignature());
255            }
256            return new Type.TypeArgType(name, classBound, interfaceBounds);
257        }
258    
259        private Type parseTypeVariableSignature() {
260            sigp++;
261            int sep = sig.indexOf(';', sigp);
262            Type t = new Type.SimpleType(sig.substring(sigp, sep));
263            sigp = sep + 1;
264            return t;
265        }
266    
267        private String debugInfo() {
268            return sig.substring(0, sigp) + "!" + sig.charAt(sigp) + "!" + sig.substring(sigp+1);
269        }
270    
271        private String sig;
272        private int sigp;
273    
274        private Type type;
275    }