001    /*
002     * Copyright 1997-2005 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.javadoc;
027    
028    import com.sun.javadoc.*;
029    
030    import static com.sun.javadoc.LanguageVersion.*;
031    
032    import com.sun.tools.javac.code.Symbol;
033    import com.sun.tools.javac.code.Symbol.ClassSymbol;
034    import com.sun.tools.javac.code.Type;
035    import com.sun.tools.javac.code.Type.ClassType;
036    import com.sun.tools.javac.code.Type.TypeVar;
037    import com.sun.tools.javac.code.Type.ArrayType;
038    import com.sun.tools.javac.code.Types;
039    import com.sun.tools.javac.util.List;
040    
041    import static com.sun.tools.javac.code.TypeTags.*;
042    
043    
044    public class TypeMaker {
045    
046        public static com.sun.javadoc.Type getType(DocEnv env, Type t) {
047            return getType(env, t, true);
048        }
049    
050        /**
051         * @param errToClassDoc  if true, ERROR type results in a ClassDoc;
052         *          false preserves legacy behavior
053         */
054        @SuppressWarnings("fallthrough")
055        public static com.sun.javadoc.Type getType(DocEnv env, Type t,
056                                                   boolean errToClassDoc) {
057            if (env.legacyDoclet) {
058                t = env.types.erasure(t);
059            }
060            switch (t.tag) {
061            case CLASS:
062                if (ClassDocImpl.isGeneric((ClassSymbol)t.tsym)) {
063                    return env.getParameterizedType((ClassType)t);
064                } else {
065                    return env.getClassDoc((ClassSymbol)t.tsym);
066                }
067            case WILDCARD:
068                Type.WildcardType a = (Type.WildcardType)t;
069                return new WildcardTypeImpl(env, a);
070            case TYPEVAR: return new TypeVariableImpl(env, (TypeVar)t);
071            case ARRAY: return new ArrayTypeImpl(env, t);
072            case BYTE: return PrimitiveType.byteType;
073            case CHAR: return PrimitiveType.charType;
074            case SHORT: return PrimitiveType.shortType;
075            case INT: return PrimitiveType.intType;
076            case LONG: return PrimitiveType.longType;
077            case FLOAT: return PrimitiveType.floatType;
078            case DOUBLE: return PrimitiveType.doubleType;
079            case BOOLEAN: return PrimitiveType.booleanType;
080            case VOID: return PrimitiveType.voidType;
081            case ERROR:
082                if (errToClassDoc)
083                    return env.getClassDoc((ClassSymbol)t.tsym);
084                // FALLTHRU
085            default:
086                return new PrimitiveType(t.tsym.getQualifiedName().toString());
087            }
088        }
089    
090        /**
091         * Convert a list of javac types into an array of javadoc types.
092         */
093        public static com.sun.javadoc.Type[] getTypes(DocEnv env, List<Type> ts) {
094            return getTypes(env, ts, new com.sun.javadoc.Type[ts.length()]);
095        }
096    
097        /**
098         * Like the above version, but use and return the array given.
099         */
100        public static com.sun.javadoc.Type[] getTypes(DocEnv env, List<Type> ts,
101                                                      com.sun.javadoc.Type res[]) {
102            int i = 0;
103            for (Type t : ts) {
104                res[i++] = getType(env, t);
105            }
106            return res;
107        }
108    
109        public static String getTypeName(Type t, boolean full) {
110            switch (t.tag) {
111            case ARRAY:
112                StringBuffer dimension = new StringBuffer();
113                while (t.tag == ARRAY) {
114                    dimension = dimension.append("[]");
115                    t = ((ArrayType)t).elemtype;
116                }
117                return getTypeName(t, full) + dimension;
118            case CLASS:
119                return ClassDocImpl.getClassName((ClassSymbol)t.tsym, full);
120            default:
121                return t.tsym.getQualifiedName().toString();
122            }
123        }
124    
125        /**
126         * Return the string representation of a type use.  Bounds of type
127         * variables are not included; bounds of wildcard types are.
128         * Class names are qualified if "full" is true.
129         */
130        static String getTypeString(DocEnv env, Type t, boolean full) {
131            switch (t.tag) {
132            case ARRAY:
133                StringBuffer dimension = new StringBuffer();
134                while (t.tag == ARRAY) {
135                    dimension = dimension.append("[]");
136                    t = env.types.elemtype(t);
137                }
138                return getTypeString(env, t, full) + dimension;
139            case CLASS:
140                return ParameterizedTypeImpl.
141                            parameterizedTypeToString(env, (ClassType)t, full);
142            case WILDCARD:
143                Type.WildcardType a = (Type.WildcardType)t;
144                return WildcardTypeImpl.wildcardTypeToString(env, a, full);
145            default:
146                return t.tsym.getQualifiedName().toString();
147            }
148        }
149    
150        /**
151         * Return the formal type parameters of a class or method as an
152         * angle-bracketed string.  Each parameter is a type variable with
153         * optional bounds.  Class names are qualified if "full" is true.
154         * Return "" if there are no type parameters or we're hiding generics.
155         */
156        static String typeParametersString(DocEnv env, Symbol sym, boolean full) {
157            if (env.legacyDoclet || sym.type.getTypeArguments().isEmpty()) {
158                return "";
159            }
160            StringBuffer s = new StringBuffer();
161            for (Type t : sym.type.getTypeArguments()) {
162                s.append(s.length() == 0 ? "<" : ", ");
163                s.append(TypeVariableImpl.typeVarToString(env, (TypeVar)t, full));
164            }
165            s.append(">");
166            return s.toString();
167        }
168    
169        /**
170         * Return the actual type arguments of a parameterized type as an
171         * angle-bracketed string.  Class name are qualified if "full" is true.
172         * Return "" if there are no type arguments or we're hiding generics.
173         */
174        static String typeArgumentsString(DocEnv env, ClassType cl, boolean full) {
175            if (env.legacyDoclet || cl.getTypeArguments().isEmpty()) {
176                return "";
177            }
178            StringBuffer s = new StringBuffer();
179            for (Type t : cl.getTypeArguments()) {
180                s.append(s.length() == 0 ? "<" : ", ");
181                s.append(getTypeString(env, t, full));
182            }
183            s.append(">");
184            return s.toString();
185        }
186    
187    
188        private static class ArrayTypeImpl implements com.sun.javadoc.Type {
189    
190            Type arrayType;
191    
192            DocEnv env;
193    
194            ArrayTypeImpl(DocEnv env, Type arrayType) {
195                this.env = env;
196                this.arrayType = arrayType;
197            }
198    
199            private com.sun.javadoc.Type skipArraysCache = null;
200    
201            private com.sun.javadoc.Type skipArrays() {
202                if (skipArraysCache == null) {
203                    Type t;
204                    for (t = arrayType; t.tag == ARRAY; t = env.types.elemtype(t)) { }
205                    skipArraysCache = TypeMaker.getType(env, t);
206                }
207                return skipArraysCache;
208            }
209    
210            /**
211             * Return the type's dimension information, as a string.
212             * <p>
213             * For example, a two dimensional array of String returns '[][]'.
214             */
215            public String dimension() {
216                StringBuffer dimension = new StringBuffer();
217                for (Type t = arrayType; t.tag == ARRAY; t = env.types.elemtype(t)) {
218                    dimension = dimension.append("[]");
219                }
220                return dimension.toString();
221            }
222    
223            /**
224             * Return unqualified name of type excluding any dimension information.
225             * <p>
226             * For example, a two dimensional array of String returns 'String'.
227             */
228            public String typeName() {
229                return skipArrays().typeName();
230            }
231    
232            /**
233             * Return qualified name of type excluding any dimension information.
234             *<p>
235             * For example, a two dimensional array of String
236             * returns 'java.lang.String'.
237             */
238            public String qualifiedTypeName() {
239                return skipArrays().qualifiedTypeName();
240            }
241    
242            /**
243             * Return the simple name of this type excluding any dimension information.
244             */
245            public String simpleTypeName() {
246                return skipArrays().simpleTypeName();
247            }
248    
249            /**
250             * Return this type as a class.  Array dimensions are ignored.
251             *
252             * @return a ClassDocImpl if the type is a Class.
253             * Return null if it is a primitive type..
254             */
255            public ClassDoc asClassDoc() {
256                return skipArrays().asClassDoc();
257            }
258    
259            /**
260             * Return this type as a <code>ParameterizedType</code> if it
261             * represents a parameterized type.  Array dimensions are ignored.
262             */
263            public ParameterizedType asParameterizedType() {
264                return skipArrays().asParameterizedType();
265            }
266    
267            /**
268             * Return this type as a <code>TypeVariable</code> if it represents
269             * a type variable.  Array dimensions are ignored.
270             */
271            public TypeVariable asTypeVariable() {
272                return skipArrays().asTypeVariable();
273            }
274    
275            /**
276             * Return null, as there are no arrays of wildcard types.
277             */
278            public WildcardType asWildcardType() {
279                return null;
280            }
281    
282            /**
283             * Return this type as an <code>AnnotationTypeDoc</code> if it
284             * represents an annotation type.  Array dimensions are ignored.
285             */
286            public AnnotationTypeDoc asAnnotationTypeDoc() {
287                return skipArrays().asAnnotationTypeDoc();
288            }
289    
290            /**
291             * Return true if this is an array of a primitive type.
292             */
293            public boolean isPrimitive() {
294                return skipArrays().isPrimitive();
295            }
296    
297            /**
298             * Return a string representation of the type.
299             *
300             * Return name of type including any dimension information.
301             * <p>
302             * For example, a two dimensional array of String returns
303             * <code>String[][]</code>.
304             *
305             * @return name of type including any dimension information.
306             */
307            public String toString() {
308                return qualifiedTypeName() + dimension();
309            }
310        }
311    }