• 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 
fullNameNoBounds(HashSet<String> typeVars)153   public String fullNameNoBounds(HashSet<String> typeVars) {
154     return fullNameNoDimensionNoBounds(typeVars) + mDimension;
155   }
156 
157   // don't recurse forever with the parameters. This handles
158   // Enum<K extends Enum<K>>
checkRecurringTypeVar(HashSet<String> typeVars)159   private boolean checkRecurringTypeVar(HashSet<String> typeVars) {
160     if (mIsTypeVariable) {
161       if (typeVars.contains(mQualifiedTypeName)) {
162         return true;
163       }
164       typeVars.add(mQualifiedTypeName);
165     }
166     return false;
167   }
168 
fullNameNoDimensionNoBounds(HashSet<String> typeVars)169   private String fullNameNoDimensionNoBounds(HashSet<String> typeVars) {
170     String fullName = null;
171     if (checkRecurringTypeVar(typeVars)) {
172       return mQualifiedTypeName;
173     }
174     /*
175      * if (fullName != null) { return fullName; }
176      */
177     fullName = mQualifiedTypeName;
178     if (mTypeArguments != null && !mTypeArguments.isEmpty()) {
179       fullName += typeArgumentsName(mTypeArguments, typeVars);
180     }
181     return fullName;
182   }
183 
fullNameNoDimension(HashSet<String> typeVars)184   public String fullNameNoDimension(HashSet<String> typeVars) {
185     String fullName = null;
186     if (checkRecurringTypeVar(typeVars)) {
187       return mQualifiedTypeName;
188     }
189     fullName = fullNameNoDimensionNoBounds(typeVars);
190     if (mTypeArguments == null || mTypeArguments.isEmpty()) {
191        if (mSuperBounds != null && !mSuperBounds.isEmpty()) {
192         for (TypeInfo superBound : mSuperBounds) {
193             if (superBound == mSuperBounds.get(0)) {
194                 fullName += " super " + superBound.fullNameNoBounds(typeVars);
195             } else {
196                 fullName += " & " + superBound.fullNameNoBounds(typeVars);
197             }
198         }
199       } else if (mExtendsBounds != null && !mExtendsBounds.isEmpty()) {
200         for (TypeInfo extendsBound : mExtendsBounds) {
201             if (extendsBound == mExtendsBounds.get(0)) {
202                 fullName += " extends " + extendsBound.fullNameNoBounds(typeVars);
203             } else {
204                 fullName += " & " + extendsBound.fullNameNoBounds(typeVars);
205             }
206         }
207       }
208     }
209     return fullName;
210   }
211 
typeArguments()212   public ArrayList<TypeInfo> typeArguments() {
213     return mTypeArguments;
214   }
215 
makeHDF(Data data, String base)216   public void makeHDF(Data data, String base) {
217     makeHDFRecursive(data, base, false, false, new HashSet<String>());
218   }
219 
makeQualifiedHDF(Data data, String base)220   public void makeQualifiedHDF(Data data, String base) {
221     makeHDFRecursive(data, base, true, false, new HashSet<String>());
222   }
223 
makeHDF(Data data, String base, boolean isLastVararg, HashSet<String> typeVariables)224   public void makeHDF(Data data, String base, boolean isLastVararg, HashSet<String> typeVariables) {
225     makeHDFRecursive(data, base, false, isLastVararg, typeVariables);
226   }
227 
makeQualifiedHDF(Data data, String base, HashSet<String> typeVariables)228   public void makeQualifiedHDF(Data data, String base, HashSet<String> typeVariables) {
229     makeHDFRecursive(data, base, true, false, typeVariables);
230   }
231 
makeHDFRecursive(Data data, String base, boolean qualified, boolean isLastVararg, HashSet<String> typeVars)232   private void makeHDFRecursive(Data data, String base, boolean qualified, boolean isLastVararg,
233       HashSet<String> typeVars) {
234     String label = qualified ? qualifiedTypeName() : simpleTypeName();
235     label += (isLastVararg) ? "..." : dimension();
236     data.setValue(base + ".label", label);
237     if (mIsTypeVariable || mIsWildcard) {
238       // could link to an @param tag on the class to describe this
239       // but for now, just don't make it a link
240     } else if (!isPrimitive() && mClass != null) {
241       if (mClass.isIncluded()) {
242         data.setValue(base + ".link", mClass.htmlPage());
243         data.setValue(base + ".since", mClass.getSince());
244       } else {
245         Doclava.federationTagger.tag(mClass);
246         if (!mClass.getFederatedReferences().isEmpty()) {
247           FederatedSite site = mClass.getFederatedReferences().iterator().next();
248           data.setValue(base + ".link", site.linkFor(mClass.htmlPage()));
249           data.setValue(base + ".federated", site.name());
250         }
251       }
252     }
253 
254     if (mIsTypeVariable) {
255       if (typeVars.contains(qualifiedTypeName())) {
256         // don't recurse forever with the parameters. This handles
257         // Enum<K extends Enum<K>>
258         return;
259       }
260       typeVars.add(qualifiedTypeName());
261     }
262     if (mTypeArguments != null) {
263       TypeInfo.makeHDF(data, base + ".typeArguments", mTypeArguments, qualified, typeVars);
264     }
265     if (mSuperBounds != null) {
266       TypeInfo.makeHDF(data, base + ".superBounds", mSuperBounds, qualified, typeVars);
267     }
268     if (mExtendsBounds != null) {
269       TypeInfo.makeHDF(data, base + ".extendsBounds", mExtendsBounds, qualified, typeVars);
270     }
271   }
272 
makeHDF(Data data, String base, ArrayList<TypeInfo> types, boolean qualified, HashSet<String> typeVariables)273   public static void makeHDF(Data data, String base, ArrayList<TypeInfo> types, boolean qualified,
274       HashSet<String> typeVariables) {
275     int i = 0;
276     for (TypeInfo type : types) {
277       type.makeHDFRecursive(data, base + "." + i++, qualified, false, typeVariables);
278     }
279   }
280 
makeHDF(Data data, String base, ArrayList<TypeInfo> types, boolean qualified)281   public static void makeHDF(Data data, String base, ArrayList<TypeInfo> types, boolean qualified) {
282     makeHDF(data, base, types, qualified, new HashSet<String>());
283   }
284 
setTypeArguments(ArrayList<TypeInfo> args)285   void setTypeArguments(ArrayList<TypeInfo> args) {
286     mTypeArguments = args;
287   }
288 
addTypeArgument(TypeInfo arg)289   public void addTypeArgument(TypeInfo arg) {
290       if (mTypeArguments == null) {
291           mTypeArguments = new ArrayList<TypeInfo>();
292       }
293 
294       mTypeArguments.add(arg);
295   }
296 
setBounds(ArrayList<TypeInfo> superBounds, ArrayList<TypeInfo> extendsBounds)297   void setBounds(ArrayList<TypeInfo> superBounds, ArrayList<TypeInfo> extendsBounds) {
298     mSuperBounds = superBounds;
299     mExtendsBounds = extendsBounds;
300   }
301 
superBounds()302   public ArrayList<TypeInfo> superBounds() {
303       return mSuperBounds;
304   }
305 
extendsBounds()306   public ArrayList<TypeInfo> extendsBounds() {
307       return mExtendsBounds;
308   }
309 
setIsTypeVariable(boolean b)310   void setIsTypeVariable(boolean b) {
311     mIsTypeVariable = b;
312   }
313 
setIsWildcard(boolean b)314   void setIsWildcard(boolean b) {
315     mIsWildcard = b;
316   }
317 
isWildcard()318   public boolean isWildcard() {
319       return mIsWildcard;
320   }
321 
typeVariables(ArrayList<TypeInfo> params)322   static HashSet<String> typeVariables(ArrayList<TypeInfo> params) {
323     return typeVariables(params, new HashSet<String>());
324   }
325 
typeVariables(ArrayList<TypeInfo> params, HashSet<String> result)326   static HashSet<String> typeVariables(ArrayList<TypeInfo> params, HashSet<String> result) {
327     if (params != null) {
328         for (TypeInfo t : params) {
329             if (t.mIsTypeVariable) {
330                 result.add(t.mQualifiedTypeName);
331             }
332         }
333     }
334     return result;
335   }
336 
337 
isTypeVariable()338   public boolean isTypeVariable() {
339     return mIsTypeVariable;
340   }
341 
defaultValue()342   public String defaultValue() {
343     if (mIsPrimitive) {
344       if ("boolean".equals(mSimpleTypeName)) {
345         return "false";
346       } else {
347         return "0";
348       }
349     } else {
350       return "null";
351     }
352   }
353 
354   @Override
toString()355   public String toString() {
356     String returnString = "";
357     returnString +=
358         "Primitive?: " + mIsPrimitive + " TypeVariable?: " + mIsTypeVariable + " Wildcard?: "
359             + mIsWildcard + " Dimension: " + mDimension + " QualifedTypeName: "
360             + mQualifiedTypeName;
361 
362     if (mTypeArguments != null) {
363       returnString += "\nTypeArguments: ";
364       for (TypeInfo tA : mTypeArguments) {
365         returnString += tA.qualifiedTypeName() + "(" + tA + ") ";
366       }
367     }
368     if (mSuperBounds != null) {
369       returnString += "\nSuperBounds: ";
370       for (TypeInfo tA : mSuperBounds) {
371         returnString += tA.qualifiedTypeName() + "(" + tA + ") ";
372       }
373     }
374     if (mExtendsBounds != null) {
375       returnString += "\nExtendsBounds: ";
376       for (TypeInfo tA : mExtendsBounds) {
377         returnString += tA.qualifiedTypeName() + "(" + tA + ") ";
378       }
379     }
380     return returnString;
381   }
382 
addResolution(Resolution resolution)383   public void addResolution(Resolution resolution) {
384       if (mResolutions == null) {
385           mResolutions = new ArrayList<Resolution>();
386       }
387 
388       mResolutions.add(resolution);
389   }
390 
printResolutions()391   public void printResolutions() {
392       if (mResolutions == null || mResolutions.isEmpty()) {
393           return;
394       }
395 
396       System.out.println("Resolutions for Type " + mSimpleTypeName + ":");
397       for (Resolution r : mResolutions) {
398           System.out.println(r);
399       }
400   }
401 
resolveResolutions()402   public boolean resolveResolutions() {
403       ArrayList<Resolution> resolutions = mResolutions;
404       mResolutions = new ArrayList<Resolution>();
405 
406       boolean allResolved = true;
407       for (Resolution resolution : resolutions) {
408           if ("class".equals(resolution.getVariable())) {
409               StringBuilder qualifiedClassName = new StringBuilder();
410               InfoBuilder.resolveQualifiedName(resolution.getValue(), qualifiedClassName,
411                       resolution.getInfoBuilder());
412 
413               // if we still couldn't resolve it, save it for the next pass
414               if ("".equals(qualifiedClassName.toString())) {
415                   mResolutions.add(resolution);
416                   allResolved = false;
417               } else {
418                   mClass = InfoBuilder.Caches.obtainClass(qualifiedClassName.toString());
419               }
420           }
421       }
422 
423       return allResolved;
424   }
425 
426   private ArrayList<Resolution> mResolutions;
427 
428   private boolean mIsPrimitive;
429   private boolean mIsTypeVariable;
430   private boolean mIsWildcard;
431   private String mDimension;
432   private String mSimpleTypeName;
433   private String mQualifiedTypeName;
434   private ClassInfo mClass;
435   private ArrayList<TypeInfo> mTypeArguments;
436   private ArrayList<TypeInfo> mSuperBounds;
437   private ArrayList<TypeInfo> mExtendsBounds;
438   private String mFullName;
439 }
440