blob: ad50bb57627f279941c7c5047c9d0053f55bc1b2 [file] [log] [blame]
Ben Dodson920dbbb2010-08-04 15:21:06 -07001/*
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
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -070023public class TypeInfo implements Resolvable {
Ben Dodson920dbbb2010-08-04 15:21:06 -070024 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
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -070068 mTypeArguments = generics;
Ben Dodson920dbbb2010-08-04 15:21:06 -070069
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
101 public ClassInfo asClassInfo() {
102 return mClass;
103 }
104
105 public boolean isPrimitive() {
106 return mIsPrimitive;
107 }
108
109 public String dimension() {
110 return mDimension;
111 }
112
Andrew Sapperstein6ba612e2011-06-20 18:41:24 -0700113 public void setDimension(String dimension) {
114 mDimension = dimension;
115 }
116
Ben Dodson920dbbb2010-08-04 15:21:06 -0700117 public String simpleTypeName() {
118 return mSimpleTypeName;
119 }
120
121 public String qualifiedTypeName() {
122 return mQualifiedTypeName;
123 }
124
125 public String fullName() {
126 if (mFullName != null) {
127 return mFullName;
128 } else {
129 return fullName(new HashSet<String>());
130 }
131 }
132
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700133 public static String typeArgumentsName(ArrayList<TypeInfo> args, HashSet<String> typeVars) {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700134 String result = "<";
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700135
136 int i = 0;
137 for (TypeInfo arg : args) {
138 result += arg.fullName(typeVars);
139 if (i != (args.size()-1)) {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700140 result += ", ";
141 }
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700142 i++;
Ben Dodson920dbbb2010-08-04 15:21:06 -0700143 }
144 result += ">";
145 return result;
146 }
147
148 public String fullName(HashSet<String> typeVars) {
149 mFullName = fullNameNoDimension(typeVars) + mDimension;
150 return mFullName;
151 }
152
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;
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700167 if (mTypeArguments != null && !mTypeArguments.isEmpty()) {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700168 fullName += typeArgumentsName(mTypeArguments, typeVars);
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700169 } 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 }
Ben Dodson920dbbb2010-08-04 15:21:06 -0700185 }
186 return fullName;
187 }
188
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700189 public ArrayList<TypeInfo> typeArguments() {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700190 return mTypeArguments;
191 }
192
193 public void makeHDF(Data data, String base) {
194 makeHDFRecursive(data, base, false, false, new HashSet<String>());
195 }
196
197 public void makeQualifiedHDF(Data data, String base) {
198 makeHDFRecursive(data, base, true, false, new HashSet<String>());
199 }
200
201 public void makeHDF(Data data, String base, boolean isLastVararg, HashSet<String> typeVariables) {
202 makeHDFRecursive(data, base, false, isLastVararg, typeVariables);
203 }
204
205 public void makeQualifiedHDF(Data data, String base, HashSet<String> typeVariables) {
206 makeHDFRecursive(data, base, true, false, typeVariables);
207 }
208
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.tagAll(new ClassInfo[] {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
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700250 public static void makeHDF(Data data, String base, ArrayList<TypeInfo> types, boolean qualified,
Ben Dodson920dbbb2010-08-04 15:21:06 -0700251 HashSet<String> typeVariables) {
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700252 int i = 0;
253 for (TypeInfo type : types) {
254 type.makeHDFRecursive(data, base + "." + i++, qualified, false, typeVariables);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700255 }
256 }
257
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700258 public static void makeHDF(Data data, String base, ArrayList<TypeInfo> types, boolean qualified) {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700259 makeHDF(data, base, types, qualified, new HashSet<String>());
260 }
261
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700262 void setTypeArguments(ArrayList<TypeInfo> args) {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700263 mTypeArguments = args;
264 }
265
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700266 public void addTypeArgument(TypeInfo arg) {
267 if (mTypeArguments == null) {
268 mTypeArguments = new ArrayList<TypeInfo>();
269 }
270
271 mTypeArguments.add(arg);
272 }
273
274 void setBounds(ArrayList<TypeInfo> superBounds, ArrayList<TypeInfo> extendsBounds) {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700275 mSuperBounds = superBounds;
276 mExtendsBounds = extendsBounds;
277 }
278
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700279 public ArrayList<TypeInfo> superBounds() {
280 return mSuperBounds;
281 }
282
283 public ArrayList<TypeInfo> extendsBounds() {
284 return mExtendsBounds;
285 }
286
Ben Dodson920dbbb2010-08-04 15:21:06 -0700287 void setIsTypeVariable(boolean b) {
288 mIsTypeVariable = b;
289 }
290
291 void setIsWildcard(boolean b) {
292 mIsWildcard = b;
293 }
294
Andrew Sapperstein6ba612e2011-06-20 18:41:24 -0700295 public boolean isWildcard() {
296 return mIsWildcard;
297 }
298
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700299 static HashSet<String> typeVariables(ArrayList<TypeInfo> params) {
Ben Dodson9ccd9e32010-08-06 17:18:52 -0700300 return typeVariables(params, new HashSet<String>());
Ben Dodson920dbbb2010-08-04 15:21:06 -0700301 }
302
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700303 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 }
Ben Dodson920dbbb2010-08-04 15:21:06 -0700310 }
311 return result;
312 }
313
314
315 public boolean isTypeVariable() {
316 return mIsTypeVariable;
317 }
318
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
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
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700360 public void addResolution(Resolution resolution) {
361 if (mResolutions == null) {
362 mResolutions = new ArrayList<Resolution>();
363 }
364
365 mResolutions.add(resolution);
366 }
367
368 public void printResolutions() {
Andrew Sapperstein6ba612e2011-06-20 18:41:24 -0700369 if (mResolutions == null || mResolutions.isEmpty()) {
370 return;
371 }
372
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700373 System.out.println("Resolutions for Type " + mSimpleTypeName + ":");
374 for (Resolution r : mResolutions) {
375 System.out.println(r);
376 }
377 }
378
Andrew Sapperstein6ba612e2011-06-20 18:41:24 -0700379 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
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700403 private ArrayList<Resolution> mResolutions;
404
Ben Dodson920dbbb2010-08-04 15:21:06 -0700405 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;
Andrew Sappersteind6eaacb2011-05-20 13:14:56 -0700412 private ArrayList<TypeInfo> mTypeArguments;
413 private ArrayList<TypeInfo> mSuperBounds;
414 private ArrayList<TypeInfo> mExtendsBounds;
Ben Dodson920dbbb2010-08-04 15:21:06 -0700415 private String mFullName;
416}