1 /*
2  * Copyright (c) 1997, 2018, 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 package com.sun.tools.javadoc.main;
27 
28 import com.sun.javadoc.*;
29 import com.sun.tools.javac.code.Symbol;
30 import com.sun.tools.javac.code.Symbol.ClassSymbol;
31 import com.sun.tools.javac.code.Symbol.CompletionFailure;
32 import com.sun.tools.javac.code.Type;
33 import com.sun.tools.javac.code.Type.ArrayType;
34 import com.sun.tools.javac.code.Type.ClassType;
35 import com.sun.tools.javac.code.Type.TypeVar;
36 import com.sun.tools.javac.util.List;
37 import static com.sun.tools.javac.code.TypeTag.ARRAY;
38 
39 /**
40  *  <p><b>This is NOT part of any supported API.
41  *  If you write code that depends on this, you do so at your own risk.
42  *  This code and its internal interfaces are subject to change or
43  *  deletion without notice.</b>
44  */
45 @Deprecated(since="9", forRemoval=true)
46 @SuppressWarnings("removal")
47 public class TypeMaker {
48 
getType(DocEnv env, Type t)49     public static com.sun.javadoc.Type getType(DocEnv env, Type t) {
50         return getType(env, t, true);
51     }
52 
53     /**
54      * @param errToClassDoc  if true, ERROR type results in a ClassDoc;
55      *          false preserves legacy behavior
56      */
getType(DocEnv env, Type t, boolean errorToClassDoc)57     public static com.sun.javadoc.Type getType(DocEnv env, Type t,
58             boolean errorToClassDoc) {
59         return getType(env, t, errorToClassDoc, true);
60     }
61 
getType(DocEnv env, Type t, boolean errToClassDoc, boolean considerAnnotations)62     public static com.sun.javadoc.Type getType(DocEnv env, Type t,
63             boolean errToClassDoc, boolean considerAnnotations) {
64         try {
65             return getTypeImpl(env, t, errToClassDoc, considerAnnotations);
66         } catch (CompletionFailure cf) {
67             /* Quietly ignore completion failures and try again - the type
68              * for which the CompletionFailure was thrown shouldn't be completed
69              * again by the completer that threw the CompletionFailure.
70              */
71             return getType(env, t, errToClassDoc, considerAnnotations);
72         }
73     }
74 
75     @SuppressWarnings("fallthrough")
getTypeImpl(DocEnv env, Type t, boolean errToClassDoc, boolean considerAnnotations)76     private static com.sun.javadoc.Type getTypeImpl(DocEnv env, Type t,
77             boolean errToClassDoc, boolean considerAnnotations) {
78         if (env.legacyDoclet) {
79             t = env.types.erasure(t);
80         }
81 
82         if (considerAnnotations && t.isAnnotated()) {
83             return new AnnotatedTypeImpl(env, t);
84         }
85 
86         switch (t.getTag()) {
87         case CLASS:
88             if (ClassDocImpl.isGeneric((ClassSymbol)t.tsym)) {
89                 return env.getParameterizedType((ClassType)t);
90             } else {
91                 return env.getClassDoc((ClassSymbol)t.tsym);
92             }
93         case WILDCARD:
94             Type.WildcardType a = (Type.WildcardType)t;
95             return new WildcardTypeImpl(env, a);
96         case TYPEVAR: return new TypeVariableImpl(env, (TypeVar)t);
97         case ARRAY: return new ArrayTypeImpl(env, t);
98         case BYTE: return PrimitiveType.byteType;
99         case CHAR: return PrimitiveType.charType;
100         case SHORT: return PrimitiveType.shortType;
101         case INT: return PrimitiveType.intType;
102         case LONG: return PrimitiveType.longType;
103         case FLOAT: return PrimitiveType.floatType;
104         case DOUBLE: return PrimitiveType.doubleType;
105         case BOOLEAN: return PrimitiveType.booleanType;
106         case VOID: return PrimitiveType.voidType;
107         case ERROR:
108             if (errToClassDoc)
109                 return env.getClassDoc((ClassSymbol)t.tsym);
110             // FALLTHRU
111         default:
112             return new PrimitiveType(t.tsym.getQualifiedName().toString());
113         }
114     }
115 
116     /**
117      * Convert a list of javac types into an array of javadoc types.
118      */
getTypes(DocEnv env, List<Type> ts)119     public static com.sun.javadoc.Type[] getTypes(DocEnv env, List<Type> ts) {
120         return getTypes(env, ts, new com.sun.javadoc.Type[ts.length()]);
121     }
122 
123     /**
124      * Like the above version, but use and return the array given.
125      */
getTypes(DocEnv env, List<Type> ts, com.sun.javadoc.Type res[])126     public static com.sun.javadoc.Type[] getTypes(DocEnv env, List<Type> ts,
127                                                   com.sun.javadoc.Type res[]) {
128         int i = 0;
129         for (Type t : ts) {
130             res[i++] = getType(env, t);
131         }
132         return res;
133     }
134 
getTypeName(Type t, boolean full)135     public static String getTypeName(Type t, boolean full) {
136         switch (t.getTag()) {
137         case ARRAY:
138             StringBuilder s = new StringBuilder();
139             while (t.hasTag(ARRAY)) {
140                 s.append("[]");
141                 t = ((ArrayType)t).elemtype;
142             }
143             s.insert(0, getTypeName(t, full));
144             return s.toString();
145         case CLASS:
146             return ClassDocImpl.getClassName((ClassSymbol)t.tsym, full);
147         default:
148             return t.tsym.getQualifiedName().toString();
149         }
150     }
151 
152     /**
153      * Return the string representation of a type use.  Bounds of type
154      * variables are not included; bounds of wildcard types are.
155      * Class names are qualified if "full" is true.
156      */
getTypeString(DocEnv env, Type t, boolean full)157     static String getTypeString(DocEnv env, Type t, boolean full) {
158         // TODO: should annotations be included here?
159         switch (t.getTag()) {
160         case ARRAY:
161             StringBuilder s = new StringBuilder();
162             while (t.hasTag(ARRAY)) {
163                 s.append("[]");
164                 t = env.types.elemtype(t);
165             }
166             s.insert(0, getTypeString(env, t, full));
167             return s.toString();
168         case CLASS:
169             return ParameterizedTypeImpl.
170                         parameterizedTypeToString(env, (ClassType)t, full);
171         case WILDCARD:
172             Type.WildcardType a = (Type.WildcardType)t;
173             return WildcardTypeImpl.wildcardTypeToString(env, a, full);
174         default:
175             return t.tsym.getQualifiedName().toString();
176         }
177     }
178 
179     /**
180      * Return the formal type parameters of a class or method as an
181      * angle-bracketed string.  Each parameter is a type variable with
182      * optional bounds.  Class names are qualified if "full" is true.
183      * Return "" if there are no type parameters or we're hiding generics.
184      */
typeParametersString(DocEnv env, Symbol sym, boolean full)185     static String typeParametersString(DocEnv env, Symbol sym, boolean full) {
186         if (env.legacyDoclet || sym.type.getTypeArguments().isEmpty()) {
187             return "";
188         }
189         StringBuilder s = new StringBuilder();
190         for (Type t : sym.type.getTypeArguments()) {
191             s.append(s.length() == 0 ? "<" : ", ");
192             s.append(TypeVariableImpl.typeVarToString(env, (TypeVar)t, full));
193         }
194         s.append(">");
195         return s.toString();
196     }
197 
198     /**
199      * Return the actual type arguments of a parameterized type as an
200      * angle-bracketed string.  Class name are qualified if "full" is true.
201      * Return "" if there are no type arguments or we're hiding generics.
202      */
typeArgumentsString(DocEnv env, ClassType cl, boolean full)203     static String typeArgumentsString(DocEnv env, ClassType cl, boolean full) {
204         if (env.legacyDoclet || cl.getTypeArguments().isEmpty()) {
205             return "";
206         }
207         StringBuilder s = new StringBuilder();
208         for (Type t : cl.getTypeArguments()) {
209             s.append(s.length() == 0 ? "<" : ", ");
210             s.append(getTypeString(env, t, full));
211         }
212         s.append(">");
213         return s.toString();
214     }
215 
216 
217     private static class ArrayTypeImpl implements com.sun.javadoc.Type {
218 
219         Type arrayType;
220 
221         DocEnv env;
222 
ArrayTypeImpl(DocEnv env, Type arrayType)223         ArrayTypeImpl(DocEnv env, Type arrayType) {
224             this.env = env;
225             this.arrayType = arrayType;
226         }
227 
228         private com.sun.javadoc.Type skipArraysCache = null;
229 
getElementType()230         public com.sun.javadoc.Type getElementType() {
231             return TypeMaker.getType(env, env.types.elemtype(arrayType));
232         }
233 
skipArrays()234         private com.sun.javadoc.Type skipArrays() {
235             if (skipArraysCache == null) {
236                 Type t;
237                 for (t = arrayType; t.hasTag(ARRAY); t = env.types.elemtype(t)) { }
238                 skipArraysCache = TypeMaker.getType(env, t);
239             }
240             return skipArraysCache;
241         }
242 
243         /**
244          * Return the type's dimension information, as a string.
245          * <p>
246          * For example, a two dimensional array of String returns '[][]'.
247          */
dimension()248         public String dimension() {
249             StringBuilder dimension = new StringBuilder();
250             for (Type t = arrayType; t.hasTag(ARRAY); t = env.types.elemtype(t)) {
251                 dimension.append("[]");
252             }
253             return dimension.toString();
254         }
255 
256         /**
257          * Return unqualified name of type excluding any dimension information.
258          * <p>
259          * For example, a two dimensional array of String returns 'String'.
260          */
typeName()261         public String typeName() {
262             return skipArrays().typeName();
263         }
264 
265         /**
266          * Return qualified name of type excluding any dimension information.
267          *<p>
268          * For example, a two dimensional array of String
269          * returns 'java.lang.String'.
270          */
qualifiedTypeName()271         public String qualifiedTypeName() {
272             return skipArrays().qualifiedTypeName();
273         }
274 
275         /**
276          * Return the simple name of this type excluding any dimension information.
277          */
simpleTypeName()278         public String simpleTypeName() {
279             return skipArrays().simpleTypeName();
280         }
281 
282         /**
283          * Return this type as a class.  Array dimensions are ignored.
284          *
285          * @return a ClassDocImpl if the type is a Class.
286          * Return null if it is a primitive type..
287          */
asClassDoc()288         public ClassDoc asClassDoc() {
289             return skipArrays().asClassDoc();
290         }
291 
292         /**
293          * Return this type as a <code>ParameterizedType</code> if it
294          * represents a parameterized type.  Array dimensions are ignored.
295          */
asParameterizedType()296         public ParameterizedType asParameterizedType() {
297             return skipArrays().asParameterizedType();
298         }
299 
300         /**
301          * Return this type as a <code>TypeVariable</code> if it represents
302          * a type variable.  Array dimensions are ignored.
303          */
asTypeVariable()304         public TypeVariable asTypeVariable() {
305             return skipArrays().asTypeVariable();
306         }
307 
308         /**
309          * Return null, as there are no arrays of wildcard types.
310          */
asWildcardType()311         public WildcardType asWildcardType() {
312             return null;
313         }
314 
315         /**
316          * Return null, as there are no annotations of the type
317          */
asAnnotatedType()318         public AnnotatedType asAnnotatedType() {
319             return null;
320         }
321 
322         /**
323          * Return this type as an <code>AnnotationTypeDoc</code> if it
324          * represents an annotation type.  Array dimensions are ignored.
325          */
asAnnotationTypeDoc()326         public AnnotationTypeDoc asAnnotationTypeDoc() {
327             return skipArrays().asAnnotationTypeDoc();
328         }
329 
330         /**
331          * Return true if this is an array of a primitive type.
332          */
isPrimitive()333         public boolean isPrimitive() {
334             return skipArrays().isPrimitive();
335         }
336 
337         /**
338          * Return a string representation of the type.
339          *
340          * Return name of type including any dimension information.
341          * <p>
342          * For example, a two dimensional array of String returns
343          * <code>String[][]</code>.
344          *
345          * @return name of type including any dimension information.
346          */
347         @Override
toString()348         public String toString() {
349             return qualifiedTypeName() + dimension();
350         }
351     }
352 }
353