TypeInfo.java revision 9ccd9e3a9df835dc134e7edd2e4236220aed401e
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
17package com.google.doclava;
18
19import com.google.clearsilver.jsilver.data.Data;
20
21import java.util.*;
22
23public class TypeInfo {
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
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
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 = new TypeInfo[generics.size()];
69      generics.toArray(mTypeArguments);
70
71      if (paramEndPos < typeString.length() - 1) {
72        typeString = typeString.substring(0,paramStartPos) + typeString.substring(paramEndPos + 1);
73      } else {
74        typeString = typeString.substring(0,paramStartPos);
75      }
76    }
77
78    // Dimensions
79    int pos = typeString.indexOf('[');
80    if (pos > -1) {
81      mDimension = typeString.substring(pos);
82      typeString = typeString.substring(0, pos);
83    } else {
84      mDimension = "";
85    }
86
87    if (PRIMITIVE_TYPES.contains(typeString)) {
88      mIsPrimitive = true;
89      mSimpleTypeName = typeString;
90      mQualifiedTypeName = typeString;
91    } else {
92      mQualifiedTypeName = typeString;
93      pos = typeString.lastIndexOf('.');
94      if (pos > -1) {
95        mSimpleTypeName = typeString.substring(pos + 1);
96      } else {
97        mSimpleTypeName = typeString;
98      }
99    }
100  }
101
102  public ClassInfo asClassInfo() {
103    return mClass;
104  }
105
106  public boolean isPrimitive() {
107    return mIsPrimitive;
108  }
109
110  public String dimension() {
111    return mDimension;
112  }
113
114  public String simpleTypeName() {
115    return mSimpleTypeName;
116  }
117
118  public String qualifiedTypeName() {
119    return mQualifiedTypeName;
120  }
121
122  public String fullName() {
123    if (mFullName != null) {
124      return mFullName;
125    } else {
126      return fullName(new HashSet<String>());
127    }
128  }
129
130  public static String typeArgumentsName(TypeInfo[] args, HashSet<String> typeVars) {
131    String result = "<";
132    for (int i = 0; i < args.length; i++) {
133      result += args[i].fullName(typeVars);
134      if (i != args.length - 1) {
135        result += ", ";
136      }
137    }
138    result += ">";
139    return result;
140  }
141
142  public String fullName(HashSet<String> typeVars) {
143    mFullName = fullNameNoDimension(typeVars) + mDimension;
144    return mFullName;
145  }
146
147  public String fullNameNoDimension(HashSet<String> typeVars) {
148    String fullName = null;
149    if (mIsTypeVariable) {
150      if (typeVars.contains(mQualifiedTypeName)) {
151        // don't recurse forever with the parameters. This handles
152        // Enum<K extends Enum<K>>
153        return mQualifiedTypeName;
154      }
155      typeVars.add(mQualifiedTypeName);
156    }
157    /*
158     * if (fullName != null) { return fullName; }
159     */
160    fullName = mQualifiedTypeName;
161    if (mTypeArguments != null && mTypeArguments.length > 0) {
162      fullName += typeArgumentsName(mTypeArguments, typeVars);
163    } else if (mSuperBounds != null && mSuperBounds.length > 0) {
164      fullName += " super " + mSuperBounds[0].fullName(typeVars);
165      for (int i = 1; i < mSuperBounds.length; i++) {
166        fullName += " & " + mSuperBounds[i].fullName(typeVars);
167      }
168    } else if (mExtendsBounds != null && mExtendsBounds.length > 0) {
169      fullName += " extends " + mExtendsBounds[0].fullName(typeVars);
170      for (int i = 1; i < mExtendsBounds.length; i++) {
171        fullName += " & " + mExtendsBounds[i].fullName(typeVars);
172      }
173    }
174    return fullName;
175  }
176
177  public TypeInfo[] typeArguments() {
178    return mTypeArguments;
179  }
180
181  public void makeHDF(Data data, String base) {
182    makeHDFRecursive(data, base, false, false, new HashSet<String>());
183  }
184
185  public void makeQualifiedHDF(Data data, String base) {
186    makeHDFRecursive(data, base, true, false, new HashSet<String>());
187  }
188
189  public void makeHDF(Data data, String base, boolean isLastVararg, HashSet<String> typeVariables) {
190    makeHDFRecursive(data, base, false, isLastVararg, typeVariables);
191  }
192
193  public void makeQualifiedHDF(Data data, String base, HashSet<String> typeVariables) {
194    makeHDFRecursive(data, base, true, false, typeVariables);
195  }
196
197  private void makeHDFRecursive(Data data, String base, boolean qualified, boolean isLastVararg,
198      HashSet<String> typeVars) {
199    String label = qualified ? qualifiedTypeName() : simpleTypeName();
200    label += (isLastVararg) ? "..." : dimension();
201    data.setValue(base + ".label", label);
202    if (mIsTypeVariable || mIsWildcard) {
203      // could link to an @param tag on the class to describe this
204      // but for now, just don't make it a link
205    } else if (!isPrimitive() && mClass != null) {
206      if (mClass.isIncluded()) {
207        data.setValue(base + ".link", mClass.htmlPage());
208        data.setValue(base + ".since", mClass.getSince());
209      } else {
210        Doclava.federationTagger.tagAll(new ClassInfo[] {mClass});
211        if (!mClass.getFederatedReferences().isEmpty()) {
212          FederatedSite site = mClass.getFederatedReferences().iterator().next();
213          data.setValue(base + ".link", site.linkFor(mClass.htmlPage()));
214          data.setValue(base + ".federated", site.name());
215        }
216      }
217    }
218
219    if (mIsTypeVariable) {
220      if (typeVars.contains(qualifiedTypeName())) {
221        // don't recurse forever with the parameters. This handles
222        // Enum<K extends Enum<K>>
223        return;
224      }
225      typeVars.add(qualifiedTypeName());
226    }
227    if (mTypeArguments != null) {
228      TypeInfo.makeHDF(data, base + ".typeArguments", mTypeArguments, qualified, typeVars);
229    }
230    if (mSuperBounds != null) {
231      TypeInfo.makeHDF(data, base + ".superBounds", mSuperBounds, qualified, typeVars);
232    }
233    if (mExtendsBounds != null) {
234      TypeInfo.makeHDF(data, base + ".extendsBounds", mExtendsBounds, qualified, typeVars);
235    }
236  }
237
238  public static void makeHDF(Data data, String base, TypeInfo[] types, boolean qualified,
239      HashSet<String> typeVariables) {
240    final int N = types.length;
241    for (int i = 0; i < N; i++) {
242      types[i].makeHDFRecursive(data, base + "." + i, qualified, false, typeVariables);
243    }
244  }
245
246  public static void makeHDF(Data data, String base, TypeInfo[] types, boolean qualified) {
247    makeHDF(data, base, types, qualified, new HashSet<String>());
248  }
249
250  void setTypeArguments(TypeInfo[] args) {
251    mTypeArguments = args;
252  }
253
254  void setBounds(TypeInfo[] superBounds, TypeInfo[] extendsBounds) {
255    mSuperBounds = superBounds;
256    mExtendsBounds = extendsBounds;
257  }
258
259  void setIsTypeVariable(boolean b) {
260    mIsTypeVariable = b;
261  }
262
263  void setIsWildcard(boolean b) {
264    mIsWildcard = b;
265  }
266
267  static HashSet<String> typeVariables(TypeInfo[] params) {
268    return typeVariables(params, new HashSet<String>());
269  }
270
271  static HashSet<String> typeVariables(TypeInfo[] params, HashSet<String> result) {
272    for (TypeInfo t : params) {
273      if (t.mIsTypeVariable) {
274        result.add(t.mQualifiedTypeName);
275      }
276    }
277    return result;
278  }
279
280
281  public boolean isTypeVariable() {
282    return mIsTypeVariable;
283  }
284
285  public String defaultValue() {
286    if (mIsPrimitive) {
287      if ("boolean".equals(mSimpleTypeName)) {
288        return "false";
289      } else {
290        return "0";
291      }
292    } else {
293      return "null";
294    }
295  }
296
297  @Override
298  public String toString() {
299    String returnString = "";
300    returnString +=
301        "Primitive?: " + mIsPrimitive + " TypeVariable?: " + mIsTypeVariable + " Wildcard?: "
302            + mIsWildcard + " Dimension: " + mDimension + " QualifedTypeName: "
303            + mQualifiedTypeName;
304
305    if (mTypeArguments != null) {
306      returnString += "\nTypeArguments: ";
307      for (TypeInfo tA : mTypeArguments) {
308        returnString += tA.qualifiedTypeName() + "(" + tA + ") ";
309      }
310    }
311    if (mSuperBounds != null) {
312      returnString += "\nSuperBounds: ";
313      for (TypeInfo tA : mSuperBounds) {
314        returnString += tA.qualifiedTypeName() + "(" + tA + ") ";
315      }
316    }
317    if (mExtendsBounds != null) {
318      returnString += "\nExtendsBounds: ";
319      for (TypeInfo tA : mExtendsBounds) {
320        returnString += tA.qualifiedTypeName() + "(" + tA + ") ";
321      }
322    }
323    return returnString;
324  }
325
326  private boolean mIsPrimitive;
327  private boolean mIsTypeVariable;
328  private boolean mIsWildcard;
329  private String mDimension;
330  private String mSimpleTypeName;
331  private String mQualifiedTypeName;
332  private ClassInfo mClass;
333  private TypeInfo[] mTypeArguments;
334  private TypeInfo[] mSuperBounds;
335  private TypeInfo[] mExtendsBounds;
336  private String mFullName;
337}
338