• 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 
20 import com.sun.javadoc.AnnotationDesc;
21 import com.sun.javadoc.AnnotationTypeDoc;
22 import com.sun.javadoc.AnnotationTypeElementDoc;
23 import com.sun.javadoc.AnnotationValue;
24 import com.sun.javadoc.ClassDoc;
25 import com.sun.javadoc.ConstructorDoc;
26 import com.sun.javadoc.ExecutableMemberDoc;
27 import com.sun.javadoc.FieldDoc;
28 import com.sun.javadoc.MemberDoc;
29 import com.sun.javadoc.MethodDoc;
30 import com.sun.javadoc.PackageDoc;
31 import com.sun.javadoc.ParamTag;
32 import com.sun.javadoc.Parameter;
33 import com.sun.javadoc.RootDoc;
34 import com.sun.javadoc.SeeTag;
35 import com.sun.javadoc.SourcePosition;
36 import com.sun.javadoc.Tag;
37 import com.sun.javadoc.ThrowsTag;
38 import com.sun.javadoc.Type;
39 
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.HashMap;
43 import java.util.HashSet;
44 import java.util.List;
45 
46 public class Converter {
47   private static RootDoc root;
48 
makeInfo(RootDoc r)49   public static void makeInfo(RootDoc r) {
50     root = r;
51 
52     // create the objects
53     ClassDoc[] classes = getClasses(r);
54     for (ClassDoc c : classes) {
55       Converter.obtainClass(c);
56     }
57 
58     ArrayList<ClassInfo> classesNeedingInit2 = new ArrayList<ClassInfo>();
59 
60     int i;
61     // fill in the fields that reference other classes
62     while (mClassesNeedingInit.size() > 0) {
63       i = mClassesNeedingInit.size() - 1;
64       ClassNeedingInit clni = mClassesNeedingInit.get(i);
65       mClassesNeedingInit.remove(i);
66 
67       initClass(clni.c, clni.cl);
68       classesNeedingInit2.add(clni.cl);
69     }
70     mClassesNeedingInit = null;
71     for (ClassInfo cl : classesNeedingInit2) {
72       cl.init2();
73     }
74 
75     finishAnnotationValueInit();
76 
77     // fill in the "root" stuff
78     mRootClasses = Converter.convertClasses(classes);
79   }
80 
getClasses(RootDoc r)81   private static ClassDoc[] getClasses(RootDoc r) {
82     ClassDoc[] classDocs = r.classes();
83     ArrayList<ClassDoc> filtered = new ArrayList<ClassDoc>(classDocs.length);
84     for (ClassDoc c : classDocs) {
85       if (c.position() != null) {
86         // Work around a javadoc bug in Java 7: We sometimes spuriously
87         // receive duplicate top level ClassDocs with null positions and no type
88         // information. Ignore them, since every ClassDoc must have a non null
89         // position.
90 
91         filtered.add(c);
92       }
93     }
94 
95     ClassDoc[] filteredArray = new ClassDoc[filtered.size()];
96     filtered.toArray(filteredArray);
97     return filteredArray;
98   }
99 
100   private static ClassInfo[] mRootClasses;
101 
rootClasses()102   public static ClassInfo[] rootClasses() {
103     return mRootClasses;
104   }
105 
allClasses()106   public static ClassInfo[] allClasses() {
107     return (ClassInfo[]) mClasses.all();
108   }
109 
initClass(ClassDoc c, ClassInfo cl)110   private static void initClass(ClassDoc c, ClassInfo cl) {
111     MethodDoc[] annotationElements;
112     if (c instanceof AnnotationTypeDoc) {
113       annotationElements = ((AnnotationTypeDoc) c).elements();
114     } else {
115       annotationElements = new MethodDoc[0];
116     }
117     cl.init(Converter.obtainType(c),
118             new ArrayList<ClassInfo>(Arrays.asList(Converter.convertClasses(c.interfaces()))),
119             new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes(c.interfaceTypes()))),
120             new ArrayList<ClassInfo>(Arrays.asList(Converter.convertClasses(c.innerClasses()))),
121             new ArrayList<MethodInfo>(Arrays.asList(
122                     Converter.convertMethods(c.constructors(false)))),
123             new ArrayList<MethodInfo>(Arrays.asList(Converter.convertMethods(c.methods(false)))),
124             new ArrayList<MethodInfo>(Arrays.asList(Converter.convertMethods(annotationElements))),
125             new ArrayList<FieldInfo>(Arrays.asList(Converter.convertFields(c.fields(false)))),
126             new ArrayList<FieldInfo>(Arrays.asList(Converter.convertFields(c.enumConstants()))),
127             Converter.obtainPackage(c.containingPackage()),
128             Converter.obtainClass(c.containingClass()),
129             Converter.obtainClass(c.superclass()), Converter.obtainType(c.superclassType()),
130             new ArrayList<AnnotationInstanceInfo>(Arrays.asList(
131                     Converter.convertAnnotationInstances(c.annotations()))));
132 
133     cl.setHiddenMethods(
134             new ArrayList<MethodInfo>(Arrays.asList(Converter.getHiddenMethods(c.methods(false)))));
135     cl.setRemovedMethods(
136             new ArrayList<MethodInfo>(Arrays.asList(Converter.getRemovedMethods(c.methods(false)))));
137 
138     cl.setRemovedSelfMethods(
139         new ArrayList<MethodInfo>(Converter.convertAllMethods(c.methods(false))));
140     cl.setRemovedConstructors(
141         new ArrayList<MethodInfo>(Converter.convertAllMethods(c.constructors(false))));
142     cl.setRemovedSelfFields(
143         new ArrayList<FieldInfo>(Converter.convertAllFields(c.fields(false))));
144     cl.setRemovedEnumConstants(
145         new ArrayList<FieldInfo>(Converter.convertAllFields(c.enumConstants())));
146 
147     cl.setNonWrittenConstructors(
148             new ArrayList<MethodInfo>(Arrays.asList(Converter.convertNonWrittenConstructors(
149                     c.constructors(false)))));
150     cl.init3(
151             new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes(c.typeParameters()))),
152             new ArrayList<ClassInfo>(Arrays.asList(
153                     Converter.convertClasses(c.innerClasses(false)))));
154   }
155 
obtainClass(String className)156   public static ClassInfo obtainClass(String className) {
157     return Converter.obtainClass(root.classNamed(className));
158   }
159 
obtainPackage(String packageName)160   public static PackageInfo obtainPackage(String packageName) {
161     return Converter.obtainPackage(root.packageNamed(packageName));
162   }
163 
convertTag(Tag tag)164   private static TagInfo convertTag(Tag tag) {
165     return new TextTagInfo(tag.name(), tag.kind(), tag.text(),
166             Converter.convertSourcePosition(tag.position()));
167   }
168 
convertThrowsTag(ThrowsTag tag, ContainerInfo base)169   private static ThrowsTagInfo convertThrowsTag(ThrowsTag tag, ContainerInfo base) {
170     return new ThrowsTagInfo(tag.name(), tag.text(), tag.kind(), Converter.obtainClass(tag
171         .exception()), tag.exceptionComment(), base, Converter
172         .convertSourcePosition(tag.position()));
173   }
174 
convertParamTag(ParamTag tag, ContainerInfo base)175   private static ParamTagInfo convertParamTag(ParamTag tag, ContainerInfo base) {
176     return new ParamTagInfo(tag.name(), tag.kind(), tag.text(), tag.isTypeParameter(), tag
177         .parameterComment(), tag.parameterName(), base, Converter.convertSourcePosition(tag
178         .position()));
179   }
180 
convertSeeTag(SeeTag tag, ContainerInfo base)181   private static SeeTagInfo convertSeeTag(SeeTag tag, ContainerInfo base) {
182     return new SeeTagInfo(tag.name(), tag.kind(), tag.text(), base, Converter
183         .convertSourcePosition(tag.position()));
184   }
185 
convertSourcePosition(SourcePosition sp)186   private static SourcePositionInfo convertSourcePosition(SourcePosition sp) {
187     if (sp == null) {
188       return null;
189     }
190     return new SourcePositionInfo(sp.file().toString(), sp.line(), sp.column());
191   }
192 
convertTags(Tag[] tags, ContainerInfo base)193   public static TagInfo[] convertTags(Tag[] tags, ContainerInfo base) {
194     int len = tags.length;
195     TagInfo[] out = new TagInfo[len];
196     for (int i = 0; i < len; i++) {
197       Tag t = tags[i];
198       /*
199        * System.out.println("Tag name='" + t.name() + "' kind='" + t.kind() + "'");
200        */
201       if (t instanceof SeeTag) {
202         out[i] = Converter.convertSeeTag((SeeTag) t, base);
203       } else if (t instanceof ThrowsTag) {
204         out[i] = Converter.convertThrowsTag((ThrowsTag) t, base);
205       } else if (t instanceof ParamTag) {
206         out[i] = Converter.convertParamTag((ParamTag) t, base);
207       } else {
208         out[i] = Converter.convertTag(t);
209       }
210     }
211     return out;
212   }
213 
convertClasses(ClassDoc[] classes)214   public static ClassInfo[] convertClasses(ClassDoc[] classes) {
215     if (classes == null) return null;
216     int N = classes.length;
217     ClassInfo[] result = new ClassInfo[N];
218     for (int i = 0; i < N; i++) {
219       result[i] = Converter.obtainClass(classes[i]);
220     }
221     return result;
222   }
223 
convertParameter(Parameter p, SourcePosition pos, boolean isVarArg)224   private static ParameterInfo convertParameter(Parameter p, SourcePosition pos, boolean isVarArg) {
225     if (p == null) return null;
226     ParameterInfo pi =
227         new ParameterInfo(p.name(), p.typeName(), Converter.obtainType(p.type()), isVarArg,
228           Converter.convertSourcePosition(pos));
229     return pi;
230   }
231 
convertParameters(Parameter[] p, ExecutableMemberDoc m)232   private static ParameterInfo[] convertParameters(Parameter[] p, ExecutableMemberDoc m) {
233     SourcePosition pos = m.position();
234     int len = p.length;
235     ParameterInfo[] q = new ParameterInfo[len];
236     for (int i = 0; i < len; i++) {
237       boolean isVarArg = (m.isVarArgs() && i == len - 1);
238       q[i] = Converter.convertParameter(p[i], pos, isVarArg);
239     }
240     return q;
241   }
242 
convertTypes(Type[] p)243   private static TypeInfo[] convertTypes(Type[] p) {
244     if (p == null) return null;
245     int len = p.length;
246     TypeInfo[] q = new TypeInfo[len];
247     for (int i = 0; i < len; i++) {
248       q[i] = Converter.obtainType(p[i]);
249     }
250     return q;
251   }
252 
Converter()253   private Converter() {}
254 
255   private static class ClassNeedingInit {
ClassNeedingInit(ClassDoc c, ClassInfo cl)256     ClassNeedingInit(ClassDoc c, ClassInfo cl) {
257       this.c = c;
258       this.cl = cl;
259     }
260 
261     ClassDoc c;
262     ClassInfo cl;
263   }
264 
265   private static ArrayList<ClassNeedingInit> mClassesNeedingInit =
266       new ArrayList<ClassNeedingInit>();
267 
obtainClass(ClassDoc o)268   static ClassInfo obtainClass(ClassDoc o) {
269     return (ClassInfo) mClasses.obtain(o);
270   }
271 
272   private static Cache mClasses = new Cache() {
273     @Override
274     protected Object make(Object o) {
275       ClassDoc c = (ClassDoc) o;
276       ClassInfo cl =
277           new ClassInfo(c, c.getRawCommentText(), Converter.convertSourcePosition(c.position()), c
278               .isPublic(), c.isProtected(), c.isPackagePrivate(), c.isPrivate(), c.isStatic(), c
279               .isInterface(), c.isAbstract(), c.isOrdinaryClass(), c.isException(), c.isError(), c
280               .isEnum(), (c instanceof AnnotationTypeDoc), c.isFinal(), c.isIncluded(), c.name(), c
281               .qualifiedName(), c.qualifiedTypeName(), c.isPrimitive());
282       if (mClassesNeedingInit != null) {
283         mClassesNeedingInit.add(new ClassNeedingInit(c, cl));
284       }
285       return cl;
286     }
287 
288     @Override
289     protected void made(Object o, Object r) {
290       if (mClassesNeedingInit == null) {
291         initClass((ClassDoc) o, (ClassInfo) r);
292         ((ClassInfo) r).init2();
293       }
294     }
295 
296     @Override
297     ClassInfo[] all() {
298       return mCache.values().toArray(new ClassInfo[mCache.size()]);
299     }
300   };
301 
getHiddenMethods(MethodDoc[] methods)302   private static MethodInfo[] getHiddenMethods(MethodDoc[] methods) {
303     if (methods == null) return null;
304     ArrayList<MethodInfo> hiddenMethods = new ArrayList<MethodInfo>();
305     for (MethodDoc method : methods) {
306       MethodInfo methodInfo = Converter.obtainMethod(method);
307       if (methodInfo.isHidden()) {
308         hiddenMethods.add(methodInfo);
309       }
310     }
311 
312     return hiddenMethods.toArray(new MethodInfo[hiddenMethods.size()]);
313   }
314 
315   // Gets the removed methods regardless of access levels
getRemovedMethods(MethodDoc[] methods)316   private static MethodInfo[] getRemovedMethods(MethodDoc[] methods) {
317     if (methods == null) return null;
318     ArrayList<MethodInfo> removedMethods = new ArrayList<MethodInfo>();
319     for (MethodDoc method : methods) {
320       MethodInfo methodInfo = Converter.obtainMethod(method);
321       if (methodInfo.isRemoved()) {
322         removedMethods.add(methodInfo);
323       }
324     }
325 
326     return removedMethods.toArray(new MethodInfo[removedMethods.size()]);
327   }
328 
329   /**
330    * Converts FieldDoc[] into List<FieldInfo>. No filtering is done.
331    */
convertAllFields(FieldDoc[] fields)332   private static List<FieldInfo> convertAllFields(FieldDoc[] fields) {
333     if (fields == null) return null;
334     List<FieldInfo> allFields = new ArrayList<FieldInfo>();
335 
336     for (FieldDoc field : fields) {
337       FieldInfo fieldInfo = Converter.obtainField(field);
338       allFields.add(fieldInfo);
339     }
340 
341     return allFields;
342   }
343 
344   /**
345    * Converts ExecutableMemberDoc[] into List<MethodInfo>. No filtering is done.
346    */
convertAllMethods(ExecutableMemberDoc[] methods)347   private static List<MethodInfo> convertAllMethods(ExecutableMemberDoc[] methods) {
348     if (methods == null) return null;
349     List<MethodInfo> allMethods = new ArrayList<MethodInfo>();
350     for (ExecutableMemberDoc method : methods) {
351       MethodInfo methodInfo = Converter.obtainMethod(method);
352       allMethods.add(methodInfo);
353     }
354     return allMethods;
355   }
356 
357   /**
358    * Convert MethodDoc[] or ConstructorDoc[] into MethodInfo[].
359    * Also filters according to the -private, -public option,
360    * because the filtering doesn't seem to be working in the ClassDoc.constructors(boolean) call.
361    */
convertMethods(ExecutableMemberDoc[] methods)362   private static MethodInfo[] convertMethods(ExecutableMemberDoc[] methods) {
363     if (methods == null) return null;
364     List<MethodInfo> filteredMethods = new ArrayList<MethodInfo>();
365     for (ExecutableMemberDoc method : methods) {
366       MethodInfo methodInfo = Converter.obtainMethod(method);
367       if (methodInfo.checkLevel()) {
368         filteredMethods.add(methodInfo);
369       }
370     }
371 
372     return filteredMethods.toArray(new MethodInfo[filteredMethods.size()]);
373   }
374 
convertNonWrittenConstructors(ConstructorDoc[] methods)375   private static MethodInfo[] convertNonWrittenConstructors(ConstructorDoc[] methods) {
376     if (methods == null) return null;
377     ArrayList<MethodInfo> ctors = new ArrayList<MethodInfo>();
378     for (ConstructorDoc method : methods) {
379       MethodInfo methodInfo = Converter.obtainMethod(method);
380       if (!methodInfo.checkLevel()) {
381         ctors.add(methodInfo);
382       }
383     }
384 
385     return ctors.toArray(new MethodInfo[ctors.size()]);
386   }
387 
obtainMethod(E o)388   private static <E extends ExecutableMemberDoc> MethodInfo obtainMethod(E o) {
389     return (MethodInfo) mMethods.obtain(o);
390   }
391 
392   private static Cache mMethods = new Cache() {
393     @Override
394     protected Object make(Object o) {
395       if (o instanceof AnnotationTypeElementDoc) {
396         AnnotationTypeElementDoc m = (AnnotationTypeElementDoc) o;
397         MethodInfo result =
398             new MethodInfo(m.getRawCommentText(),
399                     new ArrayList<TypeInfo>(Arrays.asList(
400                             Converter.convertTypes(m.typeParameters()))),
401                     m.name(), m.signature(), Converter.obtainClass(m.containingClass()),
402                     Converter.obtainClass(m.containingClass()), m.isPublic(), m.isProtected(), m
403                     .isPackagePrivate(), m.isPrivate(), m.isFinal(), m.isStatic(), m.isSynthetic(),
404                     m.isAbstract(), m.isSynchronized(), m.isNative(), true, "annotationElement",
405                     m.flatSignature(), Converter.obtainMethod(m.overriddenMethod()),
406                     Converter.obtainType(m.returnType()),
407                     new ArrayList<ParameterInfo>(Arrays.asList(
408                             Converter.convertParameters(m.parameters(), m))),
409                     new ArrayList<ClassInfo>(Arrays.asList(Converter.convertClasses(
410                             m.thrownExceptions()))), Converter.convertSourcePosition(m.position()),
411                     new ArrayList<AnnotationInstanceInfo>(Arrays.asList(
412                             Converter.convertAnnotationInstances(m.annotations()))));
413         result.setVarargs(m.isVarArgs());
414         result.init(Converter.obtainAnnotationValue(m.defaultValue(), result));
415         return result;
416       } else if (o instanceof MethodDoc) {
417         MethodDoc m = (MethodDoc) o;
418         MethodInfo result =
419             new MethodInfo(m.getRawCommentText(),
420                     new ArrayList<TypeInfo>(Arrays.asList(
421                             Converter.convertTypes(m.typeParameters()))), m.name(), m.signature(),
422                     Converter.obtainClass(m.containingClass()),
423                     Converter.obtainClass(m.containingClass()), m.isPublic(), m.isProtected(),
424                     m.isPackagePrivate(), m.isPrivate(), m.isFinal(), m.isStatic(), m.isSynthetic(),
425                     m.isAbstract(), m.isSynchronized(), m.isNative(), false, "method",
426                     m.flatSignature(), Converter.obtainMethod(m.overriddenMethod()),
427                     Converter.obtainType(m.returnType()),
428                     new ArrayList<ParameterInfo>(Arrays.asList(
429                             Converter.convertParameters(m.parameters(), m))),
430                     new ArrayList<ClassInfo>(Arrays.asList(
431                             Converter.convertClasses(m.thrownExceptions()))),
432                     Converter.convertSourcePosition(m.position()),
433                     new ArrayList<AnnotationInstanceInfo>(Arrays.asList(
434                             Converter.convertAnnotationInstances(m.annotations()))));
435         result.setVarargs(m.isVarArgs());
436         result.init(null);
437         return result;
438       } else {
439         ConstructorDoc m = (ConstructorDoc) o;
440         MethodInfo result =
441             new MethodInfo(m.getRawCommentText(), new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes(m.typeParameters()))), m
442                 .name(), m.signature(), Converter.obtainClass(m.containingClass()), Converter
443                 .obtainClass(m.containingClass()), m.isPublic(), m.isProtected(), m
444                 .isPackagePrivate(), m.isPrivate(), m.isFinal(), m.isStatic(), m.isSynthetic(),
445                 false, m.isSynchronized(), m.isNative(), false, "constructor", m.flatSignature(),
446                 null, null, new ArrayList<ParameterInfo>(Arrays.asList(Converter.convertParameters(m.parameters(), m))),
447                 new ArrayList<ClassInfo>(Arrays.asList(Converter.convertClasses(m.thrownExceptions()))), Converter.convertSourcePosition(m
448                     .position()), new ArrayList<AnnotationInstanceInfo>(Arrays.asList(Converter.convertAnnotationInstances(m.annotations()))));
449         result.setVarargs(m.isVarArgs());
450         result.init(null);
451         return result;
452       }
453     }
454   };
455 
456 
convertFields(FieldDoc[] fields)457   private static FieldInfo[] convertFields(FieldDoc[] fields) {
458     if (fields == null) return null;
459     ArrayList<FieldInfo> out = new ArrayList<FieldInfo>();
460     int N = fields.length;
461     for (int i = 0; i < N; i++) {
462       FieldInfo f = Converter.obtainField(fields[i]);
463       if (f.checkLevel()) {
464         out.add(f);
465       }
466     }
467     return out.toArray(new FieldInfo[out.size()]);
468   }
469 
obtainField(FieldDoc o)470   private static FieldInfo obtainField(FieldDoc o) {
471     return (FieldInfo) mFields.obtain(o);
472   }
473 
obtainField(ConstructorDoc o)474   private static FieldInfo obtainField(ConstructorDoc o) {
475     return (FieldInfo) mFields.obtain(o);
476   }
477 
478   private static Cache mFields = new Cache() {
479     @Override
480     protected Object make(Object o) {
481       FieldDoc f = (FieldDoc) o;
482       return new FieldInfo(f.name(), Converter.obtainClass(f.containingClass()), Converter
483           .obtainClass(f.containingClass()), f.isPublic(), f.isProtected(), f.isPackagePrivate(), f
484           .isPrivate(), f.isFinal(), f.isStatic(), f.isTransient(), f.isVolatile(),
485           f.isSynthetic(), Converter.obtainType(f.type()), f.getRawCommentText(),
486           f.constantValue(), Converter.convertSourcePosition(f.position()),
487           new ArrayList<AnnotationInstanceInfo>(Arrays.asList(Converter
488               .convertAnnotationInstances(f.annotations()))));
489     }
490   };
491 
obtainPackage(PackageDoc o)492   private static PackageInfo obtainPackage(PackageDoc o) {
493     return (PackageInfo) mPackagees.obtain(o);
494   }
495 
496   private static Cache mPackagees = new Cache() {
497     @Override
498     protected Object make(Object o) {
499       PackageDoc p = (PackageDoc) o;
500       return new PackageInfo(p, p.name(), Converter.convertSourcePosition(p.position()));
501     }
502   };
503 
obtainType(Type o)504   private static TypeInfo obtainType(Type o) {
505     return (TypeInfo) mTypes.obtain(o);
506   }
507 
508   private static Cache mTypes = new Cache() {
509     @Override
510     protected Object make(Object o) {
511       Type t = (Type) o;
512       String simpleTypeName;
513       if (t instanceof ClassDoc) {
514         simpleTypeName = ((ClassDoc) t).name();
515       } else {
516         simpleTypeName = t.simpleTypeName();
517       }
518       TypeInfo ti =
519           new TypeInfo(t.isPrimitive(), t.dimension(), simpleTypeName, t.qualifiedTypeName(),
520               Converter.obtainClass(t.asClassDoc()));
521       return ti;
522     }
523 
524     @Override
525     protected void made(Object o, Object r) {
526       Type t = (Type) o;
527       TypeInfo ti = (TypeInfo) r;
528       if (t.asParameterizedType() != null) {
529         ti.setTypeArguments(new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes(t.asParameterizedType().typeArguments()))));
530       } else if (t instanceof ClassDoc) {
531         ti.setTypeArguments(new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes(((ClassDoc) t).typeParameters()))));
532       } else if (t.asTypeVariable() != null) {
533         ti.setBounds(null, new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes((t.asTypeVariable().bounds())))));
534         ti.setIsTypeVariable(true);
535       } else if (t.asWildcardType() != null) {
536         ti.setIsWildcard(true);
537         ti.setBounds(new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes(t.asWildcardType().superBounds()))),
538                 new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes(t.asWildcardType().extendsBounds()))));
539       }
540     }
541 
542     @Override
543     protected Object keyFor(Object o) {
544       Type t = (Type) o;
545       String keyString = o.getClass().getName() + "/" + o.toString() + "/";
546       if (t.asParameterizedType() != null) {
547         keyString += t.asParameterizedType().toString() + "/";
548         if (t.asParameterizedType().typeArguments() != null) {
549           for (Type ty : t.asParameterizedType().typeArguments()) {
550             keyString += ty.toString() + "/";
551           }
552         }
553       } else {
554         keyString += "NoParameterizedType//";
555       }
556       if (t.asTypeVariable() != null) {
557         keyString += t.asTypeVariable().toString() + "/";
558         if (t.asTypeVariable().bounds() != null) {
559           for (Type ty : t.asTypeVariable().bounds()) {
560             keyString += ty.toString() + "/";
561           }
562         }
563       } else {
564         keyString += "NoTypeVariable//";
565       }
566       if (t.asWildcardType() != null) {
567         keyString += t.asWildcardType().toString() + "/";
568         if (t.asWildcardType().superBounds() != null) {
569           for (Type ty : t.asWildcardType().superBounds()) {
570             keyString += ty.toString() + "/";
571           }
572         }
573         if (t.asWildcardType().extendsBounds() != null) {
574           for (Type ty : t.asWildcardType().extendsBounds()) {
575             keyString += ty.toString() + "/";
576           }
577         }
578       } else {
579         keyString += "NoWildCardType//";
580       }
581 
582       return keyString;
583     }
584   };
585 
obtainTypeFromString(String type)586   public static TypeInfo obtainTypeFromString(String type) {
587     return (TypeInfo) mTypesFromString.obtain(type);
588   }
589 
590   private static final Cache mTypesFromString = new Cache() {
591     @Override
592     protected Object make(Object o) {
593       String name = (String) o;
594       return new TypeInfo(name);
595     }
596 
597     @Override
598     protected void made(Object o, Object r) {
599 
600     }
601 
602     @Override
603     protected Object keyFor(Object o) {
604       return o;
605     }
606   };
607 
obtainMember(MemberDoc o)608   private static MemberInfo obtainMember(MemberDoc o) {
609     return (MemberInfo) mMembers.obtain(o);
610   }
611 
612   private static Cache mMembers = new Cache() {
613     @Override
614     protected Object make(Object o) {
615       if (o instanceof MethodDoc) {
616         return Converter.obtainMethod((MethodDoc) o);
617       } else if (o instanceof ConstructorDoc) {
618         return Converter.obtainMethod((ConstructorDoc) o);
619       } else if (o instanceof FieldDoc) {
620         return Converter.obtainField((FieldDoc) o);
621       } else {
622         return null;
623       }
624     }
625   };
626 
convertAnnotationInstances(AnnotationDesc[] orig)627   private static AnnotationInstanceInfo[] convertAnnotationInstances(AnnotationDesc[] orig) {
628     int len = orig.length;
629     AnnotationInstanceInfo[] out = new AnnotationInstanceInfo[len];
630     for (int i = 0; i < len; i++) {
631       out[i] = Converter.obtainAnnotationInstance(orig[i]);
632     }
633     return out;
634   }
635 
636 
obtainAnnotationInstance(AnnotationDesc o)637   private static AnnotationInstanceInfo obtainAnnotationInstance(AnnotationDesc o) {
638     return (AnnotationInstanceInfo) mAnnotationInstances.obtain(o);
639   }
640 
641   private static Cache mAnnotationInstances = new Cache() {
642     @Override
643     protected Object make(Object o) {
644       AnnotationDesc a = (AnnotationDesc) o;
645       ClassInfo annotationType = Converter.obtainClass(a.annotationType());
646       AnnotationDesc.ElementValuePair[] ev = a.elementValues();
647       AnnotationValueInfo[] elementValues = new AnnotationValueInfo[ev.length];
648       for (int i = 0; i < ev.length; i++) {
649         elementValues[i] =
650             obtainAnnotationValue(ev[i].value(), Converter.obtainMethod(ev[i].element()));
651       }
652       return new AnnotationInstanceInfo(annotationType, elementValues);
653     }
654   };
655 
656 
657   private abstract static class Cache {
put(Object key, Object value)658     void put(Object key, Object value) {
659       mCache.put(key, value);
660     }
661 
obtain(Object o)662     Object obtain(Object o) {
663       if (o == null) {
664         return null;
665       }
666       Object k = keyFor(o);
667       Object r = mCache.get(k);
668       if (r == null) {
669         r = make(o);
670         mCache.put(k, r);
671         made(o, r);
672       }
673       return r;
674     }
675 
676     protected HashMap<Object, Object> mCache = new HashMap<Object, Object>();
677 
make(Object o)678     protected abstract Object make(Object o);
679 
made(Object o, Object r)680     protected void made(Object o, Object r) {}
681 
keyFor(Object o)682     protected Object keyFor(Object o) {
683       return o;
684     }
685 
all()686     Object[] all() {
687       return null;
688     }
689   }
690 
691   // annotation values
692   private static HashMap<AnnotationValue, AnnotationValueInfo> mAnnotationValues =
693       new HashMap<AnnotationValue, AnnotationValueInfo>();
694   private static HashSet<AnnotationValue> mAnnotationValuesNeedingInit =
695       new HashSet<AnnotationValue>();
696 
obtainAnnotationValue(AnnotationValue o, MethodInfo element)697   private static AnnotationValueInfo obtainAnnotationValue(AnnotationValue o, MethodInfo element) {
698     if (o == null) {
699       return null;
700     }
701     AnnotationValueInfo v = mAnnotationValues.get(o);
702     if (v != null) return v;
703     v = new AnnotationValueInfo(element);
704     mAnnotationValues.put(o, v);
705     if (mAnnotationValuesNeedingInit != null) {
706       mAnnotationValuesNeedingInit.add(o);
707     } else {
708       initAnnotationValue(o, v);
709     }
710     return v;
711   }
712 
initAnnotationValue(AnnotationValue o, AnnotationValueInfo v)713   private static void initAnnotationValue(AnnotationValue o, AnnotationValueInfo v) {
714     Object orig = o.value();
715     Object converted;
716     if (orig instanceof Type) {
717       // class literal
718       converted = Converter.obtainType((Type) orig);
719     } else if (orig instanceof FieldDoc) {
720       // enum constant
721       converted = Converter.obtainField((FieldDoc) orig);
722     } else if (orig instanceof AnnotationDesc) {
723       // annotation instance
724       converted = Converter.obtainAnnotationInstance((AnnotationDesc) orig);
725     } else if (orig instanceof AnnotationValue[]) {
726       AnnotationValue[] old = (AnnotationValue[]) orig;
727       ArrayList<AnnotationValueInfo> values = new ArrayList<AnnotationValueInfo>();
728       for (int i = 0; i < old.length; i++) {
729         values.add(Converter.obtainAnnotationValue(old[i], null));
730       }
731       converted = values;
732     } else {
733       converted = orig;
734     }
735     v.init(converted);
736   }
737 
finishAnnotationValueInit()738   private static void finishAnnotationValueInit() {
739     int depth = 0;
740     while (mAnnotationValuesNeedingInit.size() > 0) {
741       HashSet<AnnotationValue> set = mAnnotationValuesNeedingInit;
742       mAnnotationValuesNeedingInit = new HashSet<AnnotationValue>();
743       for (AnnotationValue o : set) {
744         AnnotationValueInfo v = mAnnotationValues.get(o);
745         initAnnotationValue(o, v);
746       }
747       depth++;
748     }
749     mAnnotationValuesNeedingInit = null;
750   }
751 }
752