• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.doclava;
18 
19 import com.google.clearsilver.jsilver.data.Data;
20 
21 import java.util.*;
22 
23 public class TypeInfo implements Resolvable {
24   public static final Set<String> PRIMITIVE_TYPES = Collections.unmodifiableSet(
25       new HashSet<String>(Arrays.asList("boolean", "byte", "char", "double", "float", "int",
26       "long", "short", "void")));
27 
TypeInfo(boolean isPrimitive, String dimension, String simpleTypeName, String qualifiedTypeName, ClassInfo cl)28   public TypeInfo(boolean isPrimitive, String dimension, String simpleTypeName,
29       String qualifiedTypeName, ClassInfo cl) {
30     mIsPrimitive = isPrimitive;
31     mDimension = dimension;
32     mSimpleTypeName = simpleTypeName;
33     mQualifiedTypeName = qualifiedTypeName;
34     mClass = cl;
35   }
36 
TypeInfo(String typeString)37   public TypeInfo(String typeString) {
38     // VarArgs
39     if (typeString.endsWith("...")) {
40       typeString = typeString.substring(0, typeString.length() - 3);
41     }
42 
43     // Generic parameters
44     int paramStartPos = typeString.indexOf('<');
45     if (paramStartPos > -1) {
46       ArrayList<TypeInfo> generics = new ArrayList<TypeInfo>();
47       int paramEndPos = typeString.lastIndexOf('>');
48 
49       int entryStartPos = paramStartPos + 1;
50       int bracketNesting = 0;
51       for (int i = entryStartPos; i < paramEndPos; i++) {
52         char c = typeString.charAt(i);
53         if (c == ',' && bracketNesting == 0) {
54           String entry = typeString.substring(entryStartPos, i).trim();
55           TypeInfo info = new TypeInfo(entry);
56           generics.add(info);
57           entryStartPos = i + 1;
58         } else if (c == '<') {
59           bracketNesting++;
60         } else if (c == '>') {
61           bracketNesting--;
62         }
63       }
64 
65       TypeInfo info = new TypeInfo(typeString.substring(entryStartPos, paramEndPos).trim());
66       generics.add(info);
67 
68       mTypeArguments = generics;
69 
70       if (paramEndPos < typeString.length() - 1) {
71         typeString = typeString.substring(0,paramStartPos) + typeString.substring(paramEndPos + 1);
72       } else {
73         typeString = typeString.substring(0,paramStartPos);
74       }
75     }
76 
77     // Dimensions
78     int pos = typeString.indexOf('[');
79     if (pos > -1) {
80       mDimension = typeString.substring(pos);
81       typeString = typeString.substring(0, pos);
82     } else {
83       mDimension = "";
84     }
85 
86     if (PRIMITIVE_TYPES.contains(typeString)) {
87       mIsPrimitive = true;
88       mSimpleTypeName = typeString;
89       mQualifiedTypeName = typeString;
90     } else {
91       mQualifiedTypeName = typeString;
92       pos = typeString.lastIndexOf('.');
93       if (pos > -1) {
94         mSimpleTypeName = typeString.substring(pos + 1);
95       } else {
96         mSimpleTypeName = typeString;
97       }
98     }
99   }
100 
asClassInfo()101   public ClassInfo asClassInfo() {
102     return mClass;
103   }
104 
isPrimitive()105   public boolean isPrimitive() {
106     return mIsPrimitive;
107   }
108 
dimension()109   public String dimension() {
110     return mDimension;
111   }
112 
setDimension(String dimension)113   public void setDimension(String dimension) {
114       mDimension = dimension;
115   }
116 
simpleTypeName()117   public String simpleTypeName() {
118     return mSimpleTypeName;
119   }
120 
qualifiedTypeName()121   public String qualifiedTypeName() {
122     return mQualifiedTypeName;
123   }
124 
fullName()125   public String fullName() {
126     if (mFullName != null) {
127       return mFullName;
128     } else {
129       return fullName(new HashSet<String>());
130     }
131   }
132 
typeArgumentsName(ArrayList<TypeInfo> args, HashSet<String> typeVars)133   public static String typeArgumentsName(ArrayList<TypeInfo> args, HashSet<String> typeVars) {
134     String result = "<";
135 
136     int i = 0;
137     for (TypeInfo arg : args) {
138       result += arg.fullName(typeVars);
139       if (i != (args.size()-1)) {
140         result += ", ";
141       }
142       i++;
143     }
144     result += ">";
145     return result;
146   }
147 
fullName(HashSet<String> typeVars)148   public String fullName(HashSet<String> typeVars) {
149     mFullName = fullNameNoDimension(typeVars) + mDimension;
150     return mFullName;
151   }
152 
fullNameNoDimension(HashSet<String> typeVars)153   public String fullNameNoDimension(HashSet<String> typeVars) {
154     String fullName = null;
155     if (mIsTypeVariable) {
156       if (typeVars.contains(mQualifiedTypeName)) {
157         // don't recurse forever with the parameters. This handles
158         // Enum<K extends Enum<K>>
159         return mQualifiedTypeName;
160       }
161       typeVars.add(mQualifiedTypeName);
162     }
163     /*
164      * if (fullName != null) { return fullName; }
165      */
166     fullName = mQualifiedTypeName;
167     if (mTypeArguments != null && !mTypeArguments.isEmpty()) {
168       fullName += typeArgumentsName(mTypeArguments, typeVars);
169     } else if (mSuperBounds != null && !mSuperBounds.isEmpty()) {
170         for (TypeInfo superBound : mSuperBounds) {
171             if (superBound == mSuperBounds.get(0)) {
172                 fullName += " super " + superBound.fullName(typeVars);
173             } else {
174                 fullName += " & " + superBound.fullName(typeVars);
175             }
176         }
177     } else if (mExtendsBounds != null && !mExtendsBounds.isEmpty()) {
178         for (TypeInfo extendsBound : mExtendsBounds) {
179             if (extendsBound == mExtendsBounds.get(0)) {
180                 fullName += " extends " + extendsBound.fullName(typeVars);
181             } else {
182                 fullName += " & " + extendsBound.fullName(typeVars);
183             }
184         }
185     }
186     return fullName;
187   }
188 
typeArguments()189   public ArrayList<TypeInfo> typeArguments() {
190     return mTypeArguments;
191   }
192 
makeHDF(Data data, String base)193   public void makeHDF(Data data, String base) {
194     makeHDFRecursive(data, base, false, false, new HashSet<String>());
195   }
196 
makeQualifiedHDF(Data data, String base)197   public void makeQualifiedHDF(Data data, String base) {
198     makeHDFRecursive(data, base, true, false, new HashSet<String>());
199   }
200 
makeHDF(Data data, String base, boolean isLastVararg, HashSet<String> typeVariables)201   public void makeHDF(Data data, String base, boolean isLastVararg, HashSet<String> typeVariables) {
202     makeHDFRecursive(data, base, false, isLastVararg, typeVariables);
203   }
204 
makeQualifiedHDF(Data data, String base, HashSet<String> typeVariables)205   public void makeQualifiedHDF(Data data, String base, HashSet<String> typeVariables) {
206     makeHDFRecursive(data, base, true, false, typeVariables);
207   }
208 
makeHDFRecursive(Data data, String base, boolean qualified, boolean isLastVararg, HashSet<String> typeVars)209   private void makeHDFRecursive(Data data, String base, boolean qualified, boolean isLastVararg,
210       HashSet<String> typeVars) {
211     String label = qualified ? qualifiedTypeName() : simpleTypeName();
212     label += (isLastVararg) ? "..." : dimension();
213     data.setValue(base + ".label", label);
214     if (mIsTypeVariable || mIsWildcard) {
215       // could link to an @param tag on the class to describe this
216       // but for now, just don't make it a link
217     } else if (!isPrimitive() && mClass != null) {
218       if (mClass.isIncluded()) {
219         data.setValue(base + ".link", mClass.htmlPage());
220         data.setValue(base + ".since", mClass.getSince());
221       } else {
222         Doclava.federationTagger.tag(mClass);
223         if (!mClass.getFederatedReferences().isEmpty()) {
224           FederatedSite site = mClass.getFederatedReferences().iterator().next();
225           data.setValue(base + ".link", site.linkFor(mClass.htmlPage()));
226           data.setValue(base + ".federated", site.name());
227         }
228       }
229     }
230 
231     if (mIsTypeVariable) {
232       if (typeVars.contains(qualifiedTypeName())) {
233         // don't recurse forever with the parameters. This handles
234         // Enum<K extends Enum<K>>
235         return;
236       }
237       typeVars.add(qualifiedTypeName());
238     }
239     if (mTypeArguments != null) {
240       TypeInfo.makeHDF(data, base + ".typeArguments", mTypeArguments, qualified, typeVars);
241     }
242     if (mSuperBounds != null) {
243       TypeInfo.makeHDF(data, base + ".superBounds", mSuperBounds, qualified, typeVars);
244     }
245     if (mExtendsBounds != null) {
246       TypeInfo.makeHDF(data, base + ".extendsBounds", mExtendsBounds, qualified, typeVars);
247     }
248   }
249 
makeHDF(Data data, String base, ArrayList<TypeInfo> types, boolean qualified, HashSet<String> typeVariables)250   public static void makeHDF(Data data, String base, ArrayList<TypeInfo> types, boolean qualified,
251       HashSet<String> typeVariables) {
252     int i = 0;
253     for (TypeInfo type : types) {
254       type.makeHDFRecursive(data, base + "." + i++, qualified, false, typeVariables);
255     }
256   }
257 
makeHDF(Data data, String base, ArrayList<TypeInfo> types, boolean qualified)258   public static void makeHDF(Data data, String base, ArrayList<TypeInfo> types, boolean qualified) {
259     makeHDF(data, base, types, qualified, new HashSet<String>());
260   }
261 
setTypeArguments(ArrayList<TypeInfo> args)262   void setTypeArguments(ArrayList<TypeInfo> args) {
263     mTypeArguments = args;
264   }
265 
addTypeArgument(TypeInfo arg)266   public void addTypeArgument(TypeInfo arg) {
267       if (mTypeArguments == null) {
268           mTypeArguments = new ArrayList<TypeInfo>();
269       }
270 
271       mTypeArguments.add(arg);
272   }
273 
setBounds(ArrayList<TypeInfo> superBounds, ArrayList<TypeInfo> extendsBounds)274   void setBounds(ArrayList<TypeInfo> superBounds, ArrayList<TypeInfo> extendsBounds) {
275     mSuperBounds = superBounds;
276     mExtendsBounds = extendsBounds;
277   }
278 
superBounds()279   public ArrayList<TypeInfo> superBounds() {
280       return mSuperBounds;
281   }
282 
extendsBounds()283   public ArrayList<TypeInfo> extendsBounds() {
284       return mExtendsBounds;
285   }
286 
setIsTypeVariable(boolean b)287   void setIsTypeVariable(boolean b) {
288     mIsTypeVariable = b;
289   }
290 
setIsWildcard(boolean b)291   void setIsWildcard(boolean b) {
292     mIsWildcard = b;
293   }
294 
isWildcard()295   public boolean isWildcard() {
296       return mIsWildcard;
297   }
298 
typeVariables(ArrayList<TypeInfo> params)299   static HashSet<String> typeVariables(ArrayList<TypeInfo> params) {
300     return typeVariables(params, new HashSet<String>());
301   }
302 
typeVariables(ArrayList<TypeInfo> params, HashSet<String> result)303   static HashSet<String> typeVariables(ArrayList<TypeInfo> params, HashSet<String> result) {
304     if (params != null) {
305         for (TypeInfo t : params) {
306             if (t.mIsTypeVariable) {
307                 result.add(t.mQualifiedTypeName);
308             }
309         }
310     }
311     return result;
312   }
313 
314 
isTypeVariable()315   public boolean isTypeVariable() {
316     return mIsTypeVariable;
317   }
318 
defaultValue()319   public String defaultValue() {
320     if (mIsPrimitive) {
321       if ("boolean".equals(mSimpleTypeName)) {
322         return "false";
323       } else {
324         return "0";
325       }
326     } else {
327       return "null";
328     }
329   }
330 
331   @Override
toString()332   public String toString() {
333     String returnString = "";
334     returnString +=
335         "Primitive?: " + mIsPrimitive + " TypeVariable?: " + mIsTypeVariable + " Wildcard?: "
336             + mIsWildcard + " Dimension: " + mDimension + " QualifedTypeName: "
337             + mQualifiedTypeName;
338 
339     if (mTypeArguments != null) {
340       returnString += "\nTypeArguments: ";
341       for (TypeInfo tA : mTypeArguments) {
342         returnString += tA.qualifiedTypeName() + "(" + tA + ") ";
343       }
344     }
345     if (mSuperBounds != null) {
346       returnString += "\nSuperBounds: ";
347       for (TypeInfo tA : mSuperBounds) {
348         returnString += tA.qualifiedTypeName() + "(" + tA + ") ";
349       }
350     }
351     if (mExtendsBounds != null) {
352       returnString += "\nExtendsBounds: ";
353       for (TypeInfo tA : mExtendsBounds) {
354         returnString += tA.qualifiedTypeName() + "(" + tA + ") ";
355       }
356     }
357     return returnString;
358   }
359 
addResolution(Resolution resolution)360   public void addResolution(Resolution resolution) {
361       if (mResolutions == null) {
362           mResolutions = new ArrayList<Resolution>();
363       }
364 
365       mResolutions.add(resolution);
366   }
367 
printResolutions()368   public void printResolutions() {
369       if (mResolutions == null || mResolutions.isEmpty()) {
370           return;
371       }
372 
373       System.out.println("Resolutions for Type " + mSimpleTypeName + ":");
374       for (Resolution r : mResolutions) {
375           System.out.println(r);
376       }
377   }
378 
resolveResolutions()379   public boolean resolveResolutions() {
380       ArrayList<Resolution> resolutions = mResolutions;
381       mResolutions = new ArrayList<Resolution>();
382 
383       boolean allResolved = true;
384       for (Resolution resolution : resolutions) {
385           if ("class".equals(resolution.getVariable())) {
386               StringBuilder qualifiedClassName = new StringBuilder();
387               InfoBuilder.resolveQualifiedName(resolution.getValue(), qualifiedClassName,
388                       resolution.getInfoBuilder());
389 
390               // if we still couldn't resolve it, save it for the next pass
391               if ("".equals(qualifiedClassName.toString())) {
392                   mResolutions.add(resolution);
393                   allResolved = false;
394               } else {
395                   mClass = InfoBuilder.Caches.obtainClass(qualifiedClassName.toString());
396               }
397           }
398       }
399 
400       return allResolved;
401   }
402 
403   private ArrayList<Resolution> mResolutions;
404 
405   private boolean mIsPrimitive;
406   private boolean mIsTypeVariable;
407   private boolean mIsWildcard;
408   private String mDimension;
409   private String mSimpleTypeName;
410   private String mQualifiedTypeName;
411   private ClassInfo mClass;
412   private ArrayList<TypeInfo> mTypeArguments;
413   private ArrayList<TypeInfo> mSuperBounds;
414   private ArrayList<TypeInfo> mExtendsBounds;
415   private String mFullName;
416 }
417