Signature.java revision 2942:08092deced3f
139665Smsmith/*
239665Smsmith * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
339665Smsmith * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
439665Smsmith *
539665Smsmith * This code is free software; you can redistribute it and/or modify it
639665Smsmith * under the terms of the GNU General Public License version 2 only, as
739665Smsmith * published by the Free Software Foundation.  Oracle designates this
839665Smsmith * particular file as subject to the "Classpath" exception as provided
939665Smsmith * by Oracle in the LICENSE file that accompanied this code.
1039665Smsmith *
1139665Smsmith * This code is distributed in the hope that it will be useful, but WITHOUT
1239665Smsmith * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1339665Smsmith * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1439665Smsmith * version 2 for more details (a copy is included in the LICENSE file that
1539665Smsmith * accompanied this code).
1639665Smsmith *
1739665Smsmith * You should have received a copy of the GNU General Public License version
1839665Smsmith * 2 along with this work; if not, write to the Free Software Foundation,
1939665Smsmith * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2039665Smsmith *
2139665Smsmith * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2239665Smsmith * or visit www.oracle.com if you need additional information or have any
2339665Smsmith * questions.
2439665Smsmith */
2539665Smsmith
2639665Smsmithpackage com.sun.tools.classfile;
2739665Smsmith
2839665Smsmithimport java.util.ArrayList;
2939863Smsmithimport java.util.List;
3039665Smsmithimport com.sun.tools.classfile.Type.*;
3139665Smsmith
3239665Smsmith/**
3339665Smsmith * See JVMS 4.4.4.
3439665Smsmith *
3539665Smsmith *  <p><b>This is NOT part of any supported API.
3639665Smsmith *  If you write code that depends on this, you do so at your own risk.
3739665Smsmith *  This code and its internal interfaces are subject to change or
3839863Smsmith *  deletion without notice.</b>
3939665Smsmith */
4039665Smsmithpublic class Signature extends Descriptor {
4139665Smsmith
4239665Smsmith    public Signature(int index) {
4339665Smsmith        super(index);
4439665Smsmith    }
4539665Smsmith
4639665Smsmith    public Type getType(ConstantPool constant_pool) throws ConstantPoolException {
4739672Sdfr        if (type == null)
4839672Sdfr            type = parse(getValue(constant_pool));
4939672Sdfr        return type;
5039672Sdfr    }
5139672Sdfr
5239665Smsmith    @Override
5339665Smsmith    public int getParameterCount(ConstantPool constant_pool) throws ConstantPoolException {
5439665Smsmith        MethodType m = (MethodType) getType(constant_pool);
5539665Smsmith        return m.paramTypes.size();
5639665Smsmith    }
5739665Smsmith
5839665Smsmith    @Override
5939665Smsmith    public String getParameterTypes(ConstantPool constant_pool) throws ConstantPoolException {
6039665Smsmith        MethodType m = (MethodType) getType(constant_pool);
6139665Smsmith        StringBuilder sb = new StringBuilder();
6239665Smsmith        sb.append("(");
6339665Smsmith        String sep = "";
6439665Smsmith        for (Type paramType: m.paramTypes) {
6539665Smsmith            sb.append(sep);
6639665Smsmith            sb.append(paramType);
6739665Smsmith            sep = ", ";
6839665Smsmith        }
6939665Smsmith        sb.append(")");
7039665Smsmith        return sb.toString();
7139665Smsmith    }
7239665Smsmith
7339665Smsmith    @Override
7439665Smsmith    public String getReturnType(ConstantPool constant_pool) throws ConstantPoolException {
7539665Smsmith        MethodType m = (MethodType) getType(constant_pool);
7639665Smsmith        return m.returnType.toString();
7739665Smsmith    }
7839665Smsmith
7939665Smsmith    @Override
8039665Smsmith    public String getFieldType(ConstantPool constant_pool) throws ConstantPoolException {
8139665Smsmith        return getType(constant_pool).toString();
8239665Smsmith    }
8339665Smsmith
8439665Smsmith    private Type parse(String sig) {
8539665Smsmith        this.sig = sig;
8639665Smsmith        sigp = 0;
8739665Smsmith
8839665Smsmith        List<TypeParamType> typeParamTypes = null;
8939665Smsmith        if (sig.charAt(sigp) == '<')
9039665Smsmith            typeParamTypes = parseTypeParamTypes();
9139665Smsmith
9239665Smsmith        if (sig.charAt(sigp) == '(') {
9339665Smsmith            List<Type> paramTypes = parseTypeSignatures(')');
9439665Smsmith            Type returnType = parseTypeSignature();
9539863Smsmith            List<Type> throwsTypes = null;
9639863Smsmith            while (sigp < sig.length() && sig.charAt(sigp) == '^') {
9739665Smsmith                sigp++;
9839665Smsmith                if (throwsTypes == null)
9939665Smsmith                    throwsTypes = new ArrayList<>();
10039863Smsmith                throwsTypes.add(parseTypeSignature());
10139863Smsmith            }
10239665Smsmith            return new MethodType(typeParamTypes, paramTypes, returnType, throwsTypes);
10339665Smsmith        } else {
10439665Smsmith            Type t = parseTypeSignature();
10539665Smsmith            if (typeParamTypes == null && sigp == sig.length())
10639665Smsmith                return t;
10739665Smsmith            Type superclass = t;
10839665Smsmith            List<Type> superinterfaces = null;
10939665Smsmith            while (sigp < sig.length()) {
11039665Smsmith                if (superinterfaces == null)
11139665Smsmith                    superinterfaces = new ArrayList<>();
11239665Smsmith                superinterfaces.add(parseTypeSignature());
11339665Smsmith            }
11439665Smsmith            return new ClassSigType(typeParamTypes, superclass, superinterfaces);
11539665Smsmith
11639665Smsmith        }
11739665Smsmith    }
11839665Smsmith
11939665Smsmith    private Type parseTypeSignature() {
12039665Smsmith        switch (sig.charAt(sigp)) {
12139665Smsmith            case 'B':
12239665Smsmith                sigp++;
12339665Smsmith                return new SimpleType("byte");
12439665Smsmith
12539665Smsmith            case 'C':
12639665Smsmith                sigp++;
12739665Smsmith                return new SimpleType("char");
12839665Smsmith
12939665Smsmith            case 'D':
13039665Smsmith                sigp++;
13139665Smsmith                return new SimpleType("double");
13239665Smsmith
13339665Smsmith            case 'F':
13439665Smsmith                sigp++;
13539665Smsmith                return new SimpleType("float");
13639665Smsmith
13739665Smsmith            case 'I':
13839665Smsmith                sigp++;
13939665Smsmith                return new SimpleType("int");
14039665Smsmith
14139665Smsmith            case 'J':
14239665Smsmith                sigp++;
14339665Smsmith                return new SimpleType("long");
14439665Smsmith
14539665Smsmith            case 'L':
14639665Smsmith                return parseClassTypeSignature();
14739665Smsmith
14839665Smsmith            case 'S':
14939665Smsmith                sigp++;
15039665Smsmith                return new SimpleType("short");
15139665Smsmith
15239665Smsmith            case 'T':
15339665Smsmith                return parseTypeVariableSignature();
15439665Smsmith
15539665Smsmith            case 'V':
15639665Smsmith                sigp++;
15739665Smsmith                return new SimpleType("void");
15839665Smsmith
15939665Smsmith            case 'Z':
16039665Smsmith                sigp++;
16139665Smsmith                return new SimpleType("boolean");
16239665Smsmith
16339665Smsmith            case '[':
16439665Smsmith                sigp++;
16539665Smsmith                return new ArrayType(parseTypeSignature());
16639665Smsmith
16739665Smsmith            case '*':
16839665Smsmith                sigp++;
16939665Smsmith                return new WildcardType();
17039665Smsmith
17139665Smsmith            case '+':
17239665Smsmith                sigp++;
17339665Smsmith                return new WildcardType(WildcardType.Kind.EXTENDS, parseTypeSignature());
17439665Smsmith
17539665Smsmith            case '-':
17639665Smsmith                sigp++;
17739665Smsmith                return new WildcardType(WildcardType.Kind.SUPER, parseTypeSignature());
17839665Smsmith
17939665Smsmith            default:
18039665Smsmith                throw new IllegalStateException(debugInfo());
18139665Smsmith        }
18239665Smsmith    }
18339665Smsmith
18439665Smsmith    private List<Type> parseTypeSignatures(char term) {
18539665Smsmith        sigp++;
18639665Smsmith        List<Type> types = new ArrayList<>();
18739665Smsmith        while (sig.charAt(sigp) != term)
18839665Smsmith            types.add(parseTypeSignature());
189        sigp++;
190        return types;
191    }
192
193    private Type parseClassTypeSignature() {
194        assert sig.charAt(sigp) == 'L';
195        sigp++;
196        return parseClassTypeSignatureRest();
197    }
198
199    private Type parseClassTypeSignatureRest() {
200        StringBuilder sb = new StringBuilder();
201        List<Type> argTypes = null;
202        ClassType t = null;
203        char sigch ;
204
205        do {
206            switch  (sigch = sig.charAt(sigp)) {
207                case '<':
208                    argTypes = parseTypeSignatures('>');
209                    break;
210
211                case '.':
212                case ';':
213                    sigp++;
214                    t = new ClassType(t, sb.toString(), argTypes);
215                    sb.setLength(0);
216                    argTypes = null;
217                    break;
218
219                default:
220                    sigp++;
221                    sb.append(sigch);
222                    break;
223            }
224        } while (sigch != ';');
225
226        return t;
227    }
228
229    private List<TypeParamType> parseTypeParamTypes() {
230        assert sig.charAt(sigp) == '<';
231        sigp++;
232        List<TypeParamType> types = new ArrayList<>();
233        while (sig.charAt(sigp) != '>')
234            types.add(parseTypeParamType());
235        sigp++;
236        return types;
237    }
238
239    private TypeParamType parseTypeParamType() {
240        int sep = sig.indexOf(":", sigp);
241        String name = sig.substring(sigp, sep);
242        Type classBound = null;
243        List<Type> interfaceBounds = null;
244        sigp = sep + 1;
245        if (sig.charAt(sigp) != ':')
246            classBound = parseTypeSignature();
247        while (sig.charAt(sigp) == ':') {
248            sigp++;
249            if (interfaceBounds == null)
250                interfaceBounds = new ArrayList<>();
251            interfaceBounds.add(parseTypeSignature());
252        }
253        return new TypeParamType(name, classBound, interfaceBounds);
254    }
255
256    private Type parseTypeVariableSignature() {
257        sigp++;
258        int sep = sig.indexOf(';', sigp);
259        Type t = new SimpleType(sig.substring(sigp, sep));
260        sigp = sep + 1;
261        return t;
262    }
263
264    private String debugInfo() {
265        return sig.substring(0, sigp) + "!" + sig.charAt(sigp) + "!" + sig.substring(sigp+1);
266    }
267
268    private String sig;
269    private int sigp;
270
271    private Type type;
272}
273