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