TypeSignature.java revision 3170:dc017a37aac5
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
26package com.sun.tools.javah;
27
28import java.util.*;
29import javax.lang.model.element.Name;
30import javax.lang.model.element.TypeElement;
31import javax.lang.model.type.ArrayType;
32import javax.lang.model.type.DeclaredType;
33import javax.lang.model.type.NoType;
34import javax.lang.model.type.PrimitiveType;
35import javax.lang.model.type.TypeKind;
36import javax.lang.model.type.TypeMirror;
37import javax.lang.model.type.TypeVariable;
38import javax.lang.model.type.TypeVisitor;
39import javax.lang.model.util.Elements;
40import javax.lang.model.util.SimpleTypeVisitor9;
41
42import com.sun.tools.javac.util.DefinedBy;
43import com.sun.tools.javac.util.DefinedBy.Api;
44
45/**
46 * Returns internal type signature.
47 *
48 * <p><b>This is NOT part of any supported API.
49 * If you write code that depends on this, you do so at your own
50 * risk.  This code and its internal interfaces are subject to change
51 * or deletion without notice.</b></p>
52 *
53 * @author Sucheta Dambalkar
54 */
55
56public class TypeSignature {
57    static class SignatureException extends Exception {
58        private static final long serialVersionUID = 1L;
59        SignatureException(String reason) {
60            super(reason);
61        }
62    }
63
64    Elements elems;
65
66    /* Signature Characters */
67
68    private static final String SIG_VOID                   = "V";
69    private static final String SIG_BOOLEAN                = "Z";
70    private static final String SIG_BYTE                   = "B";
71    private static final String SIG_CHAR                   = "C";
72    private static final String SIG_SHORT                  = "S";
73    private static final String SIG_INT                    = "I";
74    private static final String SIG_LONG                   = "J";
75    private static final String SIG_FLOAT                  = "F";
76    private static final String SIG_DOUBLE                 = "D";
77    private static final String SIG_ARRAY                  = "[";
78    private static final String SIG_CLASS                  = "L";
79
80
81
82    public TypeSignature(Elements elems){
83        this.elems = elems;
84    }
85
86    /*
87     * Returns the type signature of a field according to JVM specs
88     */
89    public String getTypeSignature(String javasignature) throws SignatureException {
90        return getParamJVMSignature(javasignature);
91    }
92
93    /*
94     * Returns the type signature of a method according to JVM specs
95     */
96    public String getTypeSignature(String javasignature, TypeMirror returnType)
97            throws SignatureException {
98        String signature = null; //Java type signature.
99        String typeSignature = null; //Internal type signature.
100        List<String> params = new ArrayList<>(); //List of parameters.
101        String paramsig = null; //Java parameter signature.
102        String paramJVMSig = null; //Internal parameter signature.
103        String returnSig = null; //Java return type signature.
104        String returnJVMType = null; //Internal return type signature.
105        int dimensions = 0; //Array dimension.
106
107        int startIndex = -1;
108        int endIndex = -1;
109        StringTokenizer st = null;
110        int i = 0;
111
112        // Gets the actual java signature without parentheses.
113        if (javasignature != null) {
114            startIndex = javasignature.indexOf("(");
115            endIndex = javasignature.indexOf(")");
116        }
117
118        if (((startIndex != -1) && (endIndex != -1))
119            &&(startIndex+1 < javasignature.length())
120            &&(endIndex < javasignature.length())) {
121            signature = javasignature.substring(startIndex+1, endIndex);
122        }
123
124        // Separates parameters.
125        if (signature != null) {
126            if (signature.contains(",")) {
127                st = new StringTokenizer(signature, ",");
128                if (st != null) {
129                    while (st.hasMoreTokens()) {
130                        params.add(st.nextToken());
131                    }
132                }
133            } else {
134                params.add(signature);
135            }
136        }
137
138        /* JVM type signature. */
139        typeSignature = "(";
140
141        // Gets indivisual internal parameter signature.
142        while (params.isEmpty() != true) {
143            paramsig = params.remove(i).trim();
144            paramJVMSig  = getParamJVMSignature(paramsig);
145            if (paramJVMSig != null) {
146                typeSignature += paramJVMSig;
147            }
148        }
149
150        typeSignature += ")";
151
152        // Get internal return type signature.
153
154        returnJVMType = "";
155        if (returnType != null) {
156            dimensions = dimensions(returnType);
157        }
158
159        //Gets array dimension of return type.
160        while (dimensions-- > 0) {
161            returnJVMType += "[";
162        }
163        if (returnType != null) {
164            returnSig = qualifiedTypeName(returnType);
165            returnJVMType += getComponentType(returnSig);
166        } else {
167            System.out.println("Invalid return type.");
168        }
169
170        typeSignature += returnJVMType;
171
172        return typeSignature;
173    }
174
175    /*
176     * Returns internal signature of a parameter.
177     */
178    private String getParamJVMSignature(String paramsig) throws SignatureException {
179        String paramJVMSig = "";
180        String componentType ="";
181
182        if(paramsig != null){
183
184            if(paramsig.contains("[]")) {
185                // Gets array dimension.
186                int endindex = paramsig.indexOf("[]");
187                componentType = paramsig.substring(0, endindex);
188                String dimensionString =  paramsig.substring(endindex);
189                if(dimensionString != null){
190                    while(dimensionString.contains("[]")){
191                        paramJVMSig += "[";
192                        int beginindex = dimensionString.indexOf("]") + 1;
193                        if(beginindex < dimensionString.length()){
194                            dimensionString = dimensionString.substring(beginindex);
195                        }else
196                            dimensionString = "";
197                    }
198                }
199            } else componentType = paramsig;
200
201            paramJVMSig += getComponentType(componentType);
202        }
203        return paramJVMSig;
204    }
205
206    /*
207     * Returns internal signature of a component.
208     */
209    private String getComponentType(String componentType) throws SignatureException {
210
211        String JVMSig = "";
212
213        if(componentType != null){
214            switch (componentType) {
215                case "void":    JVMSig += SIG_VOID;    break;
216                case "boolean": JVMSig += SIG_BOOLEAN; break;
217                case "byte":    JVMSig += SIG_BYTE;    break;
218                case "char":    JVMSig += SIG_CHAR;    break;
219                case "short":   JVMSig += SIG_SHORT;   break;
220                case "int":     JVMSig += SIG_INT;     break;
221                case "long":    JVMSig += SIG_LONG;    break;
222                case "float":   JVMSig += SIG_FLOAT;   break;
223                case "double":  JVMSig += SIG_DOUBLE;  break;
224                default:
225                    if (!componentType.equals("")) {
226                        TypeElement classNameDoc = elems.getTypeElement(componentType);
227
228                        if (classNameDoc == null) {
229                            throw new SignatureException(componentType);
230                        }
231                        else {
232                            String classname = classNameDoc.getQualifiedName().toString();
233                            String newclassname = classname.replace('.', '/');
234                            JVMSig += "L";
235                            JVMSig += newclassname;
236                            JVMSig += ";";
237                        }
238                    }
239                    break;
240            }
241        }
242        return JVMSig;
243    }
244
245    int dimensions(TypeMirror t) {
246        if (t.getKind() != TypeKind.ARRAY)
247            return 0;
248        return 1 + dimensions(((ArrayType) t).getComponentType());
249    }
250
251
252    String qualifiedTypeName(TypeMirror type) {
253        TypeVisitor<Name, Void> v = new SimpleTypeVisitor9<Name, Void>() {
254            @Override @DefinedBy(Api.LANGUAGE_MODEL)
255            public Name visitArray(ArrayType t, Void p) {
256                return t.getComponentType().accept(this, p);
257            }
258
259            @Override @DefinedBy(Api.LANGUAGE_MODEL)
260            public Name visitDeclared(DeclaredType t, Void p) {
261                return ((TypeElement) t.asElement()).getQualifiedName();
262            }
263
264            @Override @DefinedBy(Api.LANGUAGE_MODEL)
265            public Name visitPrimitive(PrimitiveType t, Void p) {
266                return elems.getName(t.toString());
267            }
268
269            @Override @DefinedBy(Api.LANGUAGE_MODEL)
270            public Name visitNoType(NoType t, Void p) {
271                if (t.getKind() == TypeKind.VOID)
272                    return elems.getName("void");
273                return defaultAction(t, p);
274            }
275
276            @Override @DefinedBy(Api.LANGUAGE_MODEL)
277            public Name visitTypeVariable(TypeVariable t, Void p) {
278                return t.getUpperBound().accept(this, p);
279            }
280        };
281        return v.visit(type).toString();
282    }
283}
284