TypeSignature.java revision 2601:8e638f046bf0
1/*
2 * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26
27package com.sun.tools.javah;
28
29import java.util.*;
30import javax.lang.model.element.Name;
31import javax.lang.model.element.TypeElement;
32import javax.lang.model.type.ArrayType;
33import javax.lang.model.type.DeclaredType;
34import javax.lang.model.type.NoType;
35import javax.lang.model.type.PrimitiveType;
36import javax.lang.model.type.TypeKind;
37import javax.lang.model.type.TypeMirror;
38import javax.lang.model.type.TypeVariable;
39import javax.lang.model.type.TypeVisitor;
40import javax.lang.model.util.Elements;
41import javax.lang.model.util.SimpleTypeVisitor9;
42
43import com.sun.tools.javac.util.DefinedBy;
44import com.sun.tools.javac.util.DefinedBy.Api;
45
46/**
47 * Returns internal type signature.
48 *
49 * <p><b>This is NOT part of any supported API.
50 * If you write code that depends on this, you do so at your own
51 * risk.  This code and its internal interfaces are subject to change
52 * or deletion without notice.</b></p>
53 *
54 * @author Sucheta Dambalkar
55 */
56
57public class TypeSignature {
58    static class SignatureException extends Exception {
59        private static final long serialVersionUID = 1L;
60        SignatureException(String reason) {
61            super(reason);
62        }
63    }
64
65    Elements elems;
66
67    /* Signature Characters */
68
69    private static final String SIG_VOID                   = "V";
70    private static final String SIG_BOOLEAN                = "Z";
71    private static final String SIG_BYTE                   = "B";
72    private static final String SIG_CHAR                   = "C";
73    private static final String SIG_SHORT                  = "S";
74    private static final String SIG_INT                    = "I";
75    private static final String SIG_LONG                   = "J";
76    private static final String SIG_FLOAT                  = "F";
77    private static final String SIG_DOUBLE                 = "D";
78    private static final String SIG_ARRAY                  = "[";
79    private static final String SIG_CLASS                  = "L";
80
81
82
83    public TypeSignature(Elements elems){
84        this.elems = elems;
85    }
86
87    /*
88     * Returns the type signature of a field according to JVM specs
89     */
90    public String getTypeSignature(String javasignature) throws SignatureException {
91        return getParamJVMSignature(javasignature);
92    }
93
94    /*
95     * Returns the type signature of a method according to JVM specs
96     */
97    public String getTypeSignature(String javasignature, TypeMirror returnType)
98            throws SignatureException {
99        String signature = null; //Java type signature.
100        String typeSignature = null; //Internal type signature.
101        List<String> params = new ArrayList<>(); //List of parameters.
102        String paramsig = null; //Java parameter signature.
103        String paramJVMSig = null; //Internal parameter signature.
104        String returnSig = null; //Java return type signature.
105        String returnJVMType = null; //Internal return type signature.
106        int dimensions = 0; //Array dimension.
107
108        int startIndex = -1;
109        int endIndex = -1;
110        StringTokenizer st = null;
111        int i = 0;
112
113        // Gets the actual java signature without parentheses.
114        if (javasignature != null) {
115            startIndex = javasignature.indexOf("(");
116            endIndex = javasignature.indexOf(")");
117        }
118
119        if (((startIndex != -1) && (endIndex != -1))
120            &&(startIndex+1 < javasignature.length())
121            &&(endIndex < javasignature.length())) {
122            signature = javasignature.substring(startIndex+1, endIndex);
123        }
124
125        // Separates parameters.
126        if (signature != null) {
127            if (signature.contains(",")) {
128                st = new StringTokenizer(signature, ",");
129                if (st != null) {
130                    while (st.hasMoreTokens()) {
131                        params.add(st.nextToken());
132                    }
133                }
134            } else {
135                params.add(signature);
136            }
137        }
138
139        /* JVM type signature. */
140        typeSignature = "(";
141
142        // Gets indivisual internal parameter signature.
143        while (params.isEmpty() != true) {
144            paramsig = params.remove(i).trim();
145            paramJVMSig  = getParamJVMSignature(paramsig);
146            if (paramJVMSig != null) {
147                typeSignature += paramJVMSig;
148            }
149        }
150
151        typeSignature += ")";
152
153        // Get internal return type signature.
154
155        returnJVMType = "";
156        if (returnType != null) {
157            dimensions = dimensions(returnType);
158        }
159
160        //Gets array dimension of return type.
161        while (dimensions-- > 0) {
162            returnJVMType += "[";
163        }
164        if (returnType != null) {
165            returnSig = qualifiedTypeName(returnType);
166            returnJVMType += getComponentType(returnSig);
167        } else {
168            System.out.println("Invalid return type.");
169        }
170
171        typeSignature += returnJVMType;
172
173        return typeSignature;
174    }
175
176    /*
177     * Returns internal signature of a parameter.
178     */
179    private String getParamJVMSignature(String paramsig) throws SignatureException {
180        String paramJVMSig = "";
181        String componentType ="";
182
183        if(paramsig != null){
184
185            if(paramsig.contains("[]")) {
186                // Gets array dimension.
187                int endindex = paramsig.indexOf("[]");
188                componentType = paramsig.substring(0, endindex);
189                String dimensionString =  paramsig.substring(endindex);
190                if(dimensionString != null){
191                    while(dimensionString.contains("[]")){
192                        paramJVMSig += "[";
193                        int beginindex = dimensionString.indexOf("]") + 1;
194                        if(beginindex < dimensionString.length()){
195                            dimensionString = dimensionString.substring(beginindex);
196                        }else
197                            dimensionString = "";
198                    }
199                }
200            } else componentType = paramsig;
201
202            paramJVMSig += getComponentType(componentType);
203        }
204        return paramJVMSig;
205    }
206
207    /*
208     * Returns internal signature of a component.
209     */
210    private String getComponentType(String componentType) throws SignatureException {
211
212        String JVMSig = "";
213
214        if(componentType != null){
215            switch (componentType) {
216                case "void":    JVMSig += SIG_VOID;    break;
217                case "boolean": JVMSig += SIG_BOOLEAN; break;
218                case "byte":    JVMSig += SIG_BYTE;    break;
219                case "char":    JVMSig += SIG_CHAR;    break;
220                case "short":   JVMSig += SIG_SHORT;   break;
221                case "int":     JVMSig += SIG_INT;     break;
222                case "long":    JVMSig += SIG_LONG;    break;
223                case "float":   JVMSig += SIG_FLOAT;   break;
224                case "double":  JVMSig += SIG_DOUBLE;  break;
225                default:
226                    if (!componentType.equals("")) {
227                        TypeElement classNameDoc = elems.getTypeElement(componentType);
228
229                        if (classNameDoc == null) {
230                            throw new SignatureException(componentType);
231                        }
232                        else {
233                            String classname = classNameDoc.getQualifiedName().toString();
234                            String newclassname = classname.replace('.', '/');
235                            JVMSig += "L";
236                            JVMSig += newclassname;
237                            JVMSig += ";";
238                        }
239                    }
240                    break;
241            }
242        }
243        return JVMSig;
244    }
245
246    int dimensions(TypeMirror t) {
247        if (t.getKind() != TypeKind.ARRAY)
248            return 0;
249        return 1 + dimensions(((ArrayType) t).getComponentType());
250    }
251
252
253    String qualifiedTypeName(TypeMirror type) {
254        TypeVisitor<Name, Void> v = new SimpleTypeVisitor9<Name, Void>() {
255            @Override @DefinedBy(Api.LANGUAGE_MODEL)
256            public Name visitArray(ArrayType t, Void p) {
257                return t.getComponentType().accept(this, p);
258            }
259
260            @Override @DefinedBy(Api.LANGUAGE_MODEL)
261            public Name visitDeclared(DeclaredType t, Void p) {
262                return ((TypeElement) t.asElement()).getQualifiedName();
263            }
264
265            @Override @DefinedBy(Api.LANGUAGE_MODEL)
266            public Name visitPrimitive(PrimitiveType t, Void p) {
267                return elems.getName(t.toString());
268            }
269
270            @Override @DefinedBy(Api.LANGUAGE_MODEL)
271            public Name visitNoType(NoType t, Void p) {
272                if (t.getKind() == TypeKind.VOID)
273                    return elems.getName("void");
274                return defaultAction(t, p);
275            }
276
277            @Override @DefinedBy(Api.LANGUAGE_MODEL)
278            public Name visitTypeVariable(TypeVariable t, Void p) {
279                return t.getUpperBound().accept(this, p);
280            }
281        };
282        return v.visit(type).toString();
283    }
284}
285