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