Utils.java revision 3233:b5d08bc0d224
1/* 2 * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package jdk.javadoc.internal.doclets.toolkit.util; 27 28import java.io.*; 29import java.lang.annotation.Documented; 30import java.lang.ref.SoftReference; 31import java.text.CollationKey; 32import java.text.Collator; 33import java.util.*; 34import java.util.AbstractMap.SimpleEntry; 35import java.util.Map.Entry; 36import java.util.stream.Collectors; 37 38import javax.lang.model.SourceVersion; 39import javax.lang.model.element.AnnotationMirror; 40import javax.lang.model.element.Element; 41import javax.lang.model.element.ElementKind; 42import javax.lang.model.element.ExecutableElement; 43import javax.lang.model.element.Modifier; 44import javax.lang.model.element.PackageElement; 45import javax.lang.model.element.TypeElement; 46import javax.lang.model.element.TypeParameterElement; 47import javax.lang.model.element.VariableElement; 48import javax.lang.model.type.ArrayType; 49import javax.lang.model.type.DeclaredType; 50import javax.lang.model.type.ErrorType; 51import javax.lang.model.type.ExecutableType; 52import javax.lang.model.type.NoType; 53import javax.lang.model.type.PrimitiveType; 54import javax.lang.model.type.TypeMirror; 55import javax.lang.model.util.ElementFilter; 56import javax.lang.model.util.ElementKindVisitor9; 57import javax.lang.model.util.Elements; 58import javax.lang.model.util.SimpleElementVisitor9; 59import javax.lang.model.util.SimpleTypeVisitor9; 60import javax.lang.model.util.TypeKindVisitor9; 61import javax.lang.model.util.Types; 62import javax.tools.FileObject; 63import javax.tools.StandardLocation; 64 65import com.sun.source.doctree.DocCommentTree; 66import com.sun.source.doctree.DocTree; 67import com.sun.source.doctree.DocTree.Kind; 68import com.sun.source.doctree.ParamTree; 69import com.sun.source.doctree.SerialFieldTree; 70import com.sun.source.tree.CompilationUnitTree; 71import com.sun.source.tree.LineMap; 72import com.sun.source.util.DocSourcePositions; 73import com.sun.source.util.DocTrees; 74import com.sun.source.util.TreePath; 75import com.sun.tools.javac.util.DefinedBy; 76import com.sun.tools.javac.util.DefinedBy.Api; 77import jdk.javadoc.internal.doclets.toolkit.CommentUtils.DocCommentDuo; 78import jdk.javadoc.internal.doclets.toolkit.Configuration; 79import jdk.javadoc.internal.doclets.toolkit.WorkArounds; 80 81import static javax.lang.model.element.ElementKind.*; 82import static javax.lang.model.element.Modifier.*; 83import static javax.lang.model.type.TypeKind.*; 84 85import static com.sun.source.doctree.DocTree.Kind.*; 86import static jdk.javadoc.internal.doclets.toolkit.builders.ConstantsSummaryBuilder.MAX_CONSTANT_VALUE_INDEX_LENGTH; 87 88 89/** 90 * Utilities Class for Doclets. 91 * 92 * <p><b>This is NOT part of any supported API. 93 * If you write code that depends on this, you do so at your own risk. 94 * This code and its internal interfaces are subject to change or 95 * deletion without notice.</b> 96 * 97 * @author Atul M Dambalkar 98 * @author Jamie Ho 99 */ 100public class Utils { 101 public final Configuration configuration; 102 public final DocTrees docTrees; 103 public final Elements elementUtils; 104 public final Types typeUtils; 105 106 public Utils(Configuration c) { 107 configuration = c; 108 elementUtils = c.root.getElementUtils(); 109 typeUtils = c.root.getTypeUtils(); 110 docTrees = c.root.getDocTrees(); 111 } 112 113 // our own little symbol table 114 private HashMap<String, TypeMirror> symtab = new HashMap<>(); 115 116 public TypeMirror getSymbol(String signature) { 117 TypeMirror type = symtab.get(signature); 118 if (type == null) { 119 TypeElement typeElement = elementUtils.getTypeElement(signature); 120 if (typeElement == null) 121 return null; 122 type = typeElement.asType(); 123 if (type == null) 124 return null; 125 symtab.put(signature, type); 126 } 127 return type; 128 } 129 130 public TypeMirror getObjectType() { 131 return getSymbol("java.lang.Object"); 132 } 133 134 public TypeMirror getExceptionType() { 135 return getSymbol("java.lang.Exception"); 136 } 137 138 public TypeMirror getErrorType() { 139 return getSymbol("java.lang.Error"); 140 } 141 142 public TypeMirror getSerializableType() { 143 return getSymbol("java.io.Serializable"); 144 } 145 146 public TypeMirror getExternalizableType() { 147 return getSymbol("java.io.Externalizable"); 148 } 149 150 public TypeMirror getIllegalArgumentExceptionType() { 151 return getSymbol("java.lang.IllegalArgumentException"); 152 } 153 154 public TypeMirror getNullPointerExceptionType() { 155 return getSymbol("java.lang.NullPointerException"); 156 } 157 158 public TypeMirror getDeprecatedType() { 159 return getSymbol("java.lang.Deprecated"); 160 } 161 162 public TypeMirror getFunctionalInterface() { 163 return getSymbol("java.lang.FunctionalInterface"); 164 } 165 166 /** 167 * Return array of class members whose documentation is to be generated. 168 * If the member is deprecated do not include such a member in the 169 * returned array. 170 * 171 * @param members Array of members to choose from. 172 * @return List List of eligible members for whom 173 * documentation is getting generated. 174 */ 175 public List<Element> excludeDeprecatedMembers(List<? extends Element> members) { 176 List<Element> excludeList = members.stream() 177 .filter((member) -> (!isDeprecated(member))) 178 .sorted(makeGeneralPurposeComparator()) 179 .collect(Collectors.toCollection(ArrayList::new)); 180 return excludeList; 181 } 182 183 /** 184 * Search for the given method in the given class. 185 * 186 * @param te Class to search into. 187 * @param method Method to be searched. 188 * @return ExecutableElement Method found, null otherwise. 189 */ 190 public ExecutableElement findMethod(TypeElement te, ExecutableElement method) { 191 for (Element m : getMethods(te)) { 192 if (executableMembersEqual(method, (ExecutableElement)m)) { 193 return (ExecutableElement)m; 194 } 195 } 196 return null; 197 } 198 199 /** 200 * Test whether a class is a subclass of another class. 201 * 202 * @param t1 the candidate superclass. 203 * @param t2 the target 204 * @return true if t1 is a superclass of t2. 205 */ 206 public boolean isSubclassOf(TypeElement t1, TypeElement t2) { 207 return typeUtils.isSubtype(t1.asType(), t2.asType()); 208 } 209 210 /** 211 * @param e1 the first method to compare. 212 * @param e2 the second method to compare. 213 * @return true if member1 overrides/hides or is overriden/hidden by member2. 214 */ 215 216 public boolean executableMembersEqual(ExecutableElement e1, ExecutableElement e2) { 217 // TODO: investigate if Elements.hides(..) will work here. 218 if (isStatic(e1) && isStatic(e2)) { 219 List<? extends VariableElement> parameters1 = e1.getParameters(); 220 List<? extends VariableElement> parameters2 = e2.getParameters(); 221 if (e1.getSimpleName().equals(e2.getSimpleName()) && 222 parameters1.size() == parameters2.size()) { 223 int j; 224 for (j = 0 ; j < parameters1.size(); j++) { 225 VariableElement v1 = parameters1.get(j); 226 VariableElement v2 = parameters2.get(j); 227 String t1 = getTypeName(v1.asType(), true); 228 String t2 = getTypeName(v2.asType(), true); 229 if (!(t1.equals(t2) || 230 isTypeVariable(v1.asType()) || isTypeVariable(v2.asType()))) { 231 break; 232 } 233 } 234 if (j == parameters1.size()) { 235 return true; 236 } 237 } 238 return false; 239 } else { 240 return elementUtils.overrides(e1, e2, getEnclosingTypeElement(e1)) || 241 elementUtils.overrides(e2, e1, getEnclosingTypeElement(e2)) || 242 e1.equals(e2); 243 } 244 } 245 246 /** 247 * According to 248 * <cite>The Java™ Language Specification</cite>, 249 * all the outer classes and static inner classes are core classes. 250 */ 251 public boolean isCoreClass(TypeElement e) { 252 return getEnclosingTypeElement(e) == null || isStatic(e); 253 } 254 255 public boolean matches(Element e1, Element e2) { 256 if (isExecutableElement(e1) && isExecutableElement(e1)) { 257 return executableMembersEqual((ExecutableElement)e1, (ExecutableElement)e2); 258 } else { 259 return e1.getSimpleName().equals(e2.getSimpleName()); 260 } 261 } 262 263 /** 264 * Copy the given directory contents from the source package directory 265 * to the generated documentation directory. For example for a package 266 * java.lang this method find out the source location of the package using 267 * {@link SourcePath} and if given directory is found in the source 268 * directory structure, copy the entire directory, to the generated 269 * documentation hierarchy. 270 * @param pe 271 */ 272 public void copyDocFiles(PackageElement pe) { 273 copyDocFiles(DocPath.forPackage(pe).resolve(DocPaths.DOC_FILES)); 274 } 275 276 public void copyDocFiles(DocPath dir) { 277 try { 278 boolean first = true; 279 for (DocFile f : DocFile.list(configuration, StandardLocation.SOURCE_PATH, dir)) { 280 if (!f.isDirectory()) { 281 continue; 282 } 283 DocFile srcdir = f; 284 DocFile destdir = DocFile.createFileForOutput(configuration, dir); 285 if (srcdir.isSameFile(destdir)) { 286 continue; 287 } 288 289 for (DocFile srcfile: srcdir.list()) { 290 DocFile destfile = destdir.resolve(srcfile.getName()); 291 if (srcfile.isFile()) { 292 if (destfile.exists() && !first) { 293 configuration.message.warning("doclet.Copy_Overwrite_warning", 294 srcfile.getPath(), destdir.getPath()); 295 } else { 296 configuration.message.notice( 297 "doclet.Copying_File_0_To_Dir_1", 298 srcfile.getPath(), destdir.getPath()); 299 destfile.copyFile(srcfile); 300 } 301 } else if (srcfile.isDirectory()) { 302 if (configuration.copydocfilesubdirs 303 && !configuration.shouldExcludeDocFileDir(srcfile.getName())) { 304 copyDocFiles(dir.resolve(srcfile.getName())); 305 } 306 } 307 } 308 309 first = false; 310 } 311 } catch (SecurityException | IOException exc) { 312 throw new DocletAbortException(exc); 313 } 314 } 315 316 public boolean isAnnotated(TypeMirror e) { 317 return !e.getAnnotationMirrors().isEmpty(); 318 } 319 320 public boolean isAnnotated(Element e) { 321 return !e.getAnnotationMirrors().isEmpty(); 322 } 323 324 public boolean isAnnotationType(Element e) { 325 return new SimpleElementVisitor9<Boolean, Void>() { 326 @Override @DefinedBy(Api.LANGUAGE_MODEL) 327 public Boolean visitExecutable(ExecutableElement e, Void p) { 328 return visit(e.getEnclosingElement()); 329 } 330 331 @Override @DefinedBy(Api.LANGUAGE_MODEL) 332 public Boolean visitUnknown(Element e, Void p) { 333 return false; 334 } 335 336 @Override @DefinedBy(Api.LANGUAGE_MODEL) 337 protected Boolean defaultAction(Element e, Void p) { 338 return e.getKind() == ANNOTATION_TYPE; 339 } 340 }.visit(e); 341 } 342 343 /** 344 * An Enum implementation is almost identical, thus this method returns if 345 * this element represents a CLASS or an ENUM 346 * @param e element 347 * @return true if class or enum 348 */ 349 public boolean isClass(Element e) { 350 return e.getKind().isClass(); 351 } 352 353 public boolean isConstructor(Element e) { 354 return e.getKind() == CONSTRUCTOR; 355 } 356 357 public boolean isEnum(Element e) { 358 return e.getKind() == ENUM; 359 } 360 361 boolean isEnumConstant(Element e) { 362 return e.getKind() == ENUM_CONSTANT; 363 } 364 365 public boolean isField(Element e) { 366 return e.getKind() == FIELD; 367 } 368 369 public boolean isInterface(Element e) { 370 return e.getKind() == INTERFACE; 371 } 372 373 public boolean isMethod(Element e) { 374 return e.getKind() == METHOD; 375 } 376 377 public boolean isPackage(Element e) { 378 return e.getKind() == ElementKind.PACKAGE; 379 } 380 381 public boolean isAbstract(Element e) { 382 return e.getModifiers().contains(Modifier.ABSTRACT); 383 } 384 385 public boolean isDefault(Element e) { 386 return e.getModifiers().contains(Modifier.DEFAULT); 387 } 388 389 public boolean isPackagePrivate(Element e) { 390 return !(isPublic(e) || isPrivate(e) || isProtected(e)); 391 } 392 393 public boolean isPrivate(Element e) { 394 return e.getModifiers().contains(Modifier.PRIVATE); 395 } 396 397 public boolean isProtected(Element e) { 398 return e.getModifiers().contains(Modifier.PROTECTED); 399 } 400 401 public boolean isPublic(Element e) { 402 return e.getModifiers().contains(Modifier.PUBLIC); 403 } 404 405 public boolean isProperty(String name) { 406 return configuration.javafx && name.endsWith("Property"); 407 } 408 409 public String getPropertyName(String name) { 410 return isProperty(name) 411 ? name.substring(0, name.length() - "Property".length()) 412 : name; 413 } 414 415 public String getPropertyLabel(String name) { 416 return name.substring(0, name.lastIndexOf("Property")); 417 } 418 419 public boolean isOverviewElement(Element e) { 420 return e.getKind() == ElementKind.OTHER; 421 } 422 423 public boolean isStatic(Element e) { 424 return e.getModifiers().contains(Modifier.STATIC); 425 } 426 427 public boolean isSerializable(TypeElement e) { 428 return typeUtils.isSubtype(e.asType(), getSerializableType()); 429 } 430 431 public boolean isExternalizable(TypeElement e) { 432 return typeUtils.isSubtype(e.asType(), getExternalizableType()); 433 } 434 435 public SortedSet<VariableElement> serializableFields(TypeElement aclass) { 436 return configuration.workArounds.getSerializableFields(this, aclass); 437 } 438 439 public SortedSet<ExecutableElement> serializationMethods(TypeElement aclass) { 440 return configuration.workArounds.getSerializationMethods(this, aclass); 441 } 442 443 public boolean definesSerializableFields(TypeElement aclass) { 444 return configuration.workArounds.definesSerializableFields(this, aclass); 445 } 446 447 public String modifiersToString(Element e, boolean trailingSpace) { 448 SortedSet<Modifier> set = new TreeSet<>(e.getModifiers()); 449 set.remove(Modifier.NATIVE); 450 set.remove(Modifier.STRICTFP); 451 set.remove(Modifier.SYNCHRONIZED); 452 453 return new ElementKindVisitor9<String, SortedSet<Modifier>>() { 454 final StringBuilder sb = new StringBuilder(); 455 456 void addVisibilityModifier(Set<Modifier> modifiers) { 457 if (modifiers.contains(PUBLIC)) { 458 sb.append("public").append(" "); 459 } else if (modifiers.contains(PROTECTED)) { 460 sb.append("protected").append(" "); 461 } else if (modifiers.contains(PRIVATE)) { 462 sb.append("private").append(" "); 463 } 464 } 465 466 void addStatic(Set<Modifier> modifiers) { 467 if (modifiers.contains(STATIC)) { 468 sb.append("static").append(" "); 469 } 470 } 471 472 void addModifers(Set<Modifier> modifiers) { 473 String s = set.stream().map(m -> m.toString()).collect(Collectors.joining(" ")); 474 sb.append(s); 475 if (!s.isEmpty()) 476 sb.append(" "); 477 } 478 479 String finalString(String s) { 480 sb.append(s); 481 if (trailingSpace) { 482 if (sb.lastIndexOf(" ") == sb.length() - 1) { 483 return sb.toString(); 484 } else { 485 return sb.append(" ").toString(); 486 } 487 } else { 488 return sb.toString().trim(); 489 } 490 } 491 492 @Override @DefinedBy(Api.LANGUAGE_MODEL) 493 public String visitTypeAsInterface(TypeElement e, SortedSet<Modifier> p) { 494 addVisibilityModifier(p); 495 addStatic(p); 496 return finalString("interface"); 497 } 498 499 @Override @DefinedBy(Api.LANGUAGE_MODEL) 500 public String visitTypeAsEnum(TypeElement e, SortedSet<Modifier> p) { 501 addVisibilityModifier(p); 502 addStatic(p); 503 return finalString("enum"); 504 } 505 506 @Override @DefinedBy(Api.LANGUAGE_MODEL) 507 public String visitTypeAsAnnotationType(TypeElement e, SortedSet<Modifier> p) { 508 addVisibilityModifier(p); 509 addStatic(p); 510 return finalString("@interface"); 511 } 512 513 @Override @DefinedBy(Api.LANGUAGE_MODEL) 514 public String visitTypeAsClass(TypeElement e, SortedSet<Modifier> p) { 515 addModifers(p); 516 return finalString("class"); 517 } 518 519 @Override @DefinedBy(Api.LANGUAGE_MODEL) 520 protected String defaultAction(Element e, SortedSet<Modifier> p) { 521 addModifers(p); 522 return sb.toString().trim(); 523 } 524 525 }.visit(e, set); 526 } 527 528 public boolean isFunctionalInterface(AnnotationMirror amirror) { 529 return amirror.getAnnotationType().equals(getFunctionalInterface()) && 530 configuration.root.getSourceVersion() 531 .compareTo(SourceVersion.RELEASE_8) >= 0; 532 } 533 534 public boolean isNoType(TypeMirror t) { 535 return t.getKind() == NONE; 536 } 537 538 public boolean isOrdinaryClass(TypeElement te) { 539 if (isEnum(te) || isInterface(te) || isAnnotationType(te)) { 540 return false; 541 } 542 if (isError(te) || isException(te)) { 543 return false; 544 } 545 return true; 546 } 547 548 public boolean isError(TypeElement te) { 549 if (isEnum(te) || isInterface(te) || isAnnotationType(te)) { 550 return false; 551 } 552 return typeUtils.isSubtype(te.asType(), getErrorType()); 553 } 554 555 public boolean isException(TypeElement te) { 556 if (isEnum(te) || isInterface(te) || isAnnotationType(te)) { 557 return false; 558 } 559 return typeUtils.isSubtype(te.asType(), getExceptionType()); 560 } 561 562 public boolean isPrimitive(TypeMirror t) { 563 return new SimpleTypeVisitor9<Boolean, Void>() { 564 565 @Override @DefinedBy(Api.LANGUAGE_MODEL) 566 public Boolean visitNoType(NoType t, Void p) { 567 return t.getKind() == VOID; 568 } 569 @Override @DefinedBy(Api.LANGUAGE_MODEL) 570 public Boolean visitPrimitive(PrimitiveType t, Void p) { 571 return true; 572 } 573 @Override @DefinedBy(Api.LANGUAGE_MODEL) 574 public Boolean visitArray(ArrayType t, Void p) { 575 return visit(t.getComponentType()); 576 } 577 @Override @DefinedBy(Api.LANGUAGE_MODEL) 578 protected Boolean defaultAction(TypeMirror e, Void p) { 579 return false; 580 } 581 }.visit(t); 582 } 583 584 public boolean isExecutableElement(Element e) { 585 ElementKind kind = e.getKind(); 586 switch (kind) { 587 case CONSTRUCTOR: case METHOD: case INSTANCE_INIT: 588 return true; 589 default: 590 return false; 591 } 592 } 593 594 public boolean isVariableElement(Element e) { 595 ElementKind kind = e.getKind(); 596 switch(kind) { 597 case ENUM_CONSTANT: case EXCEPTION_PARAMETER: case FIELD: 598 case LOCAL_VARIABLE: case PARAMETER: 599 case RESOURCE_VARIABLE: 600 return true; 601 default: 602 return false; 603 } 604 } 605 606 public boolean isTypeElement(Element e) { 607 switch (e.getKind()) { 608 case CLASS: case ENUM: case INTERFACE: case ANNOTATION_TYPE: 609 return true; 610 default: 611 return false; 612 } 613 } 614 615 /** 616 * Get the signature. It is the parameter list, type is qualified. 617 * For instance, for a method {@code mymethod(String x, int y)}, 618 * it will return {@code(java.lang.String,int)}. 619 * @param e 620 * @return String 621 */ 622 public String signature(ExecutableElement e) { 623 return makeSignature(e, true); 624 } 625 626 /** 627 * Get flat signature. All types are not qualified. 628 * Return a String, which is the flat signature of this member. 629 * It is the parameter list, type is not qualified. 630 * For instance, for a method {@code mymethod(String x, int y)}, 631 * it will return {@code (String, int)}. 632 */ 633 public String flatSignature(ExecutableElement e) { 634 return makeSignature(e, false); 635 } 636 637 public String makeSignature(ExecutableElement e, boolean full) { 638 return makeSignature(e, full, false); 639 } 640 641 public String makeSignature(ExecutableElement e, boolean full, boolean ignoreTypeParameters) { 642 StringBuilder result = new StringBuilder(); 643 result.append("("); 644 Iterator<? extends VariableElement> iterator = e.getParameters().iterator(); 645 while (iterator.hasNext()) { 646 VariableElement next = iterator.next(); 647 TypeMirror type = next.asType(); 648 result.append(getTypeSignature(type, full, ignoreTypeParameters)); 649 if (iterator.hasNext()) { 650 result.append(", "); 651 } 652 } 653 if (e.isVarArgs()) { 654 int len = result.length(); 655 result.replace(len - 2, len, "..."); 656 } 657 result.append(")"); 658 return result.toString(); 659 } 660 661 private String getTypeSignature(TypeMirror t, boolean qualifiedName, boolean noTypeParameters) { 662 return new SimpleTypeVisitor9<StringBuilder, Void>() { 663 final StringBuilder sb = new StringBuilder(); 664 665 @Override @DefinedBy(Api.LANGUAGE_MODEL) 666 public StringBuilder visitArray(ArrayType t, Void p) { 667 TypeMirror componentType = t.getComponentType(); 668 visit(componentType); 669 sb.append("[]"); 670 return sb; 671 } 672 673 @Override @DefinedBy(Api.LANGUAGE_MODEL) 674 public StringBuilder visitDeclared(DeclaredType t, Void p) { 675 Element e = t.asElement(); 676 sb.append(qualifiedName ? getFullyQualifiedName(e) : getSimpleName(e)); 677 List<? extends TypeMirror> typeArguments = t.getTypeArguments(); 678 if (typeArguments.isEmpty() || noTypeParameters) { 679 return sb; 680 } 681 sb.append("<"); 682 Iterator<? extends TypeMirror> iterator = typeArguments.iterator(); 683 while (iterator.hasNext()) { 684 TypeMirror ta = iterator.next(); 685 visit(ta); 686 if (iterator.hasNext()) { 687 sb.append(", "); 688 } 689 } 690 sb.append(">"); 691 return sb; 692 } 693 694 @Override @DefinedBy(Api.LANGUAGE_MODEL) 695 public StringBuilder visitTypeVariable(javax.lang.model.type.TypeVariable t, Void p) { 696 Element e = t.asElement(); 697 sb.append(qualifiedName ? getFullyQualifiedName(e, false) : getSimpleName(e)); 698 return sb; 699 } 700 701 @Override @DefinedBy(Api.LANGUAGE_MODEL) 702 public StringBuilder visitWildcard(javax.lang.model.type.WildcardType t, Void p) { 703 sb.append("?"); 704 TypeMirror upperBound = t.getExtendsBound(); 705 if (upperBound != null) { 706 sb.append(" extends "); 707 visit(upperBound); 708 } 709 TypeMirror superBound = t.getSuperBound(); 710 if (superBound != null) { 711 sb.append(" super "); 712 visit(superBound); 713 } 714 return sb; 715 } 716 717 @Override @DefinedBy(Api.LANGUAGE_MODEL) 718 protected StringBuilder defaultAction(TypeMirror e, Void p) { 719 return sb.append(e); 720 } 721 }.visit(t).toString(); 722 } 723 724 public boolean isArrayType(TypeMirror t) { 725 return t.getKind() == ARRAY; 726 } 727 728 public boolean isDeclaredType(TypeMirror t) { 729 return t.getKind() == DECLARED; 730 } 731 732 public boolean isErrorType(TypeMirror t) { 733 return t.getKind() == ERROR; 734 } 735 736 public boolean isIntersectionType(TypeMirror t) { 737 return t.getKind() == INTERSECTION; 738 } 739 740 public boolean isTypeParameterElement(Element e) { 741 return e.getKind() == TYPE_PARAMETER; 742 } 743 744 public boolean isTypeVariable(TypeMirror t) { 745 return t.getKind() == TYPEVAR; 746 } 747 748 public boolean isVoid(TypeMirror t) { 749 return t.getKind() == VOID; 750 } 751 752 public boolean isWildCard(TypeMirror t) { 753 return t.getKind() == WILDCARD; 754 } 755 756 public boolean ignoreBounds(TypeMirror bound) { 757 return bound.equals(getObjectType()) && !isAnnotated(bound); 758 } 759 760 /* 761 * a direct port of TypeVariable.getBounds 762 */ 763 public List<? extends TypeMirror> getBounds(TypeParameterElement tpe) { 764 List<? extends TypeMirror> bounds = tpe.getBounds(); 765 if (!bounds.isEmpty()) { 766 TypeMirror upperBound = bounds.get(bounds.size() - 1); 767 if (ignoreBounds(upperBound)) { 768 return Collections.emptyList(); 769 } 770 } 771 return bounds; 772 } 773 774 /** 775 * Returns the TypeMirror of the ExecutableElement for all methods, 776 * a null if constructor. 777 * @param ee the ExecutableElement 778 * @return 779 */ 780 public TypeMirror getReturnType(ExecutableElement ee) { 781 return ee.getKind() == CONSTRUCTOR ? null : ee.getReturnType(); 782 } 783 784 /** 785 * Return the type containing the method that this method overrides. 786 * It may be a {@code TypeElement} or a {@code TypeParameterElement}. 787 */ 788 public TypeMirror overriddenType(ExecutableElement method) { 789 return configuration.workArounds.overriddenType(method); 790 } 791 792 private TypeMirror getType(TypeMirror t) { 793 return (isNoType(t)) ? getObjectType() : t; 794 } 795 796 public TypeMirror getSuperType(TypeElement te) { 797 TypeMirror t = te.getSuperclass(); 798 return getType(t); 799 } 800 801 /** 802 * Return the class that originally defined the method that 803 * is overridden by the current definition, or null if no 804 * such class exists. 805 * 806 * @return a TypeElement representing the superclass that 807 * originally defined this method, null if this method does 808 * not override a definition in a superclass. 809 */ 810 public TypeElement overriddenClass(ExecutableElement ee) { 811 TypeMirror type = overriddenType(ee); 812 return (type != null) ? asTypeElement(type) : null; 813 } 814 815 public ExecutableElement overriddenMethod(ExecutableElement method) { 816 if (isStatic(method)) { 817 return null; 818 } 819 final TypeElement origin = getEnclosingTypeElement(method); 820 for (TypeMirror t = getSuperType(origin); 821 t.getKind() == DECLARED; 822 t = getSuperType(asTypeElement(t))) { 823 TypeElement te = asTypeElement(t); 824 if (te == null) { 825 return null; 826 } 827 List<? extends Element> methods = te.getEnclosedElements(); 828 for (ExecutableElement ee : ElementFilter.methodsIn(methods)) { 829 if (elementUtils.overrides(method, ee, origin)) { 830 return ee; 831 } 832 } 833 if (t.equals(getObjectType())) 834 return null; 835 } 836 return null; 837 } 838 839 public SortedSet<TypeElement> getTypeElementsAsSortedSet(Iterable<TypeElement> typeElements) { 840 SortedSet<TypeElement> set = new TreeSet<>(makeGeneralPurposeComparator()); 841 for (TypeElement te : typeElements) { 842 set.add(te); 843 } 844 return set; 845 } 846 847 public List<? extends DocTree> getSerialDataTrees(ExecutableElement member) { 848 return getBlockTags(member, SERIAL_DATA); 849 } 850 851 public FileObject getFileObject(TypeElement te) { 852 return docTrees.getPath(te).getCompilationUnit().getSourceFile(); 853 } 854 855 public TypeMirror getDeclaredType(TypeElement enclosing, TypeMirror target) { 856 return getDeclaredType(Collections.emptyList(), enclosing, target); 857 } 858 859 /** 860 * Finds the declaration of the enclosing's type parameter. 861 * 862 * @param values 863 * @param enclosing a TypeElement whose type arguments we desire 864 * @param target the TypeMirror of the type as described by the enclosing 865 * @return 866 */ 867 public TypeMirror getDeclaredType(Collection<TypeMirror> values, 868 TypeElement enclosing, TypeMirror target) { 869 TypeElement targetElement = asTypeElement(target); 870 List<? extends TypeParameterElement> targetTypeArgs = targetElement.getTypeParameters(); 871 if (targetTypeArgs.isEmpty()) { 872 return target; 873 } 874 875 List<? extends TypeParameterElement> enclosingTypeArgs = enclosing.getTypeParameters(); 876 List<TypeMirror> targetTypeArgTypes = new ArrayList<>(targetTypeArgs.size()); 877 878 if (enclosingTypeArgs.isEmpty()) { 879 for (TypeMirror te : values) { 880 List<? extends TypeMirror> typeArguments = ((DeclaredType)te).getTypeArguments(); 881 if (typeArguments.size() >= targetTypeArgs.size()) { 882 for (int i = 0 ; i < targetTypeArgs.size(); i++) { 883 targetTypeArgTypes.add(typeArguments.get(i)); 884 } 885 break; 886 } 887 } 888 // we found no matches in the hierarchy 889 if (targetTypeArgTypes.isEmpty()) { 890 return target; 891 } 892 } else { 893 if (targetTypeArgs.size() > enclosingTypeArgs.size()) { 894 return target; 895 } 896 for (int i = 0; i < targetTypeArgs.size(); i++) { 897 TypeParameterElement tpe = enclosingTypeArgs.get(i); 898 targetTypeArgTypes.add(tpe.asType()); 899 } 900 } 901 TypeMirror dt = typeUtils.getDeclaredType(targetElement, 902 targetTypeArgTypes.toArray(new TypeMirror[targetTypeArgTypes.size()])); 903 return dt; 904 } 905 906 /** 907 * For the class return all implemented interfaces including the 908 * superinterfaces of the implementing interfaces, also iterate over for 909 * all the superclasses. For interface return all the extended interfaces 910 * as well as superinterfaces for those extended interfaces. 911 * 912 * @param te the class to get the interfaces for 913 * @return List of all the required interfaces. 914 */ 915 public Set<TypeMirror> getAllInterfaces(TypeElement te) { 916 Set<TypeMirror> results = new LinkedHashSet<>(); 917 918 List<? extends TypeMirror> interfaceTypes = te.getInterfaces(); 919 920 for (TypeMirror interfaceType : interfaceTypes) { 921 TypeElement intfc = asTypeElement(interfaceType); 922 923 if (isPublic(intfc) || isLinkable(intfc)) { 924 results.add(interfaceType); 925 TypeElement klass = asTypeElement(interfaceType); 926 for (TypeMirror t : getAllInterfaces(klass)) { 927 t = getDeclaredType(results, te, t); 928 results.add(t); 929 } 930 } 931 } 932 // TypeMirror contains the modified TypeParameterElement's types represented 933 // in the local Class'es elements types. ex: Foo<E> implements Bar<V> and the 934 // class being considered is Foo then TypeParameters will be represented as <E> 935 // note that any conversion might revert back to the old signature. For this 936 // very reason we get the superType, and find its interfaces. 937 TypeMirror superType = getSuperType(te); 938 if (superType == getObjectType()) 939 return results; 940 // Try walking the tree 941 addAllInterfaceTypes(results, te, superType, 942 configuration.workArounds.interfaceTypesOf(superType)); 943 return results; 944 } 945 946 private void findAllInterfaceTypes(Set<TypeMirror> results, final TypeElement baseClass, 947 TypeMirror p) { 948 TypeMirror superType = getSuperType(asTypeElement(p)); 949 if (superType == p) { 950 return; 951 } 952 addAllInterfaceTypes(results, baseClass, superType, 953 configuration.workArounds.interfaceTypesOf(superType)); 954 } 955 956 private void addAllInterfaceTypes(Set<TypeMirror> results, 957 final TypeElement baseClass, TypeMirror type, 958 List<TypeMirror> interfaceTypes) { 959 for (TypeMirror interfaceType : interfaceTypes) { 960 TypeElement iElement = asTypeElement(interfaceType); 961 if (isPublic(iElement) && isLinkable(iElement)) { 962 interfaceType = getDeclaredType(results, baseClass, interfaceType); 963 results.add(interfaceType); 964 Set<TypeMirror> superInterfaces = getAllInterfaces(iElement); 965 for (TypeMirror superInterface : superInterfaces) { 966 superInterface = getDeclaredType(results, baseClass, superInterface); 967 results.add(superInterface); 968 } 969 } 970 } 971 findAllInterfaceTypes(results, baseClass, type); 972 } 973 974 /** 975 * Lookup for a class within this package. 976 * 977 * @return TypeElement of found class, or null if not found. 978 */ 979 public TypeElement findClassInPackageElement(PackageElement pkg, String className) { 980 for (TypeElement c : getAllClasses(pkg)) { 981 if (getSimpleName(c).equals(className)) { 982 return c; 983 } 984 } 985 return null; 986 } 987 988 /** 989 * TODO: FIXME: port to javax.lang.model 990 * Find a class within the context of this class. Search order: qualified name, in this class 991 * (inner), in this package, in the class imports, in the package imports. Return the 992 * TypeElement if found, null if not found. 993 */ 994 //### The specified search order is not the normal rule the 995 //### compiler would use. Leave as specified or change it? 996 public TypeElement findClass(Element element, String className) { 997 TypeElement encl = getEnclosingTypeElement(element); 998 TypeElement searchResult = configuration.workArounds.searchClass(encl, className); 999 if (searchResult == null) { 1000 encl = getEnclosingTypeElement(encl); 1001 //Expand search space to include enclosing class. 1002 while (encl != null && getEnclosingTypeElement(encl) != null) { 1003 encl = getEnclosingTypeElement(encl); 1004 } 1005 searchResult = encl == null 1006 ? null 1007 : configuration.workArounds.searchClass(encl, className); 1008 } 1009 return searchResult; 1010 } 1011 1012 /** 1013 * Enclose in quotes, used for paths and filenames that contains spaces 1014 */ 1015 public String quote(String filepath) { 1016 return ("\"" + filepath + "\""); 1017 } 1018 1019 /** 1020 * Parse the package name. We only want to display package name up to 1021 * 2 levels. 1022 */ 1023 public String parsePackageName(PackageElement p) { 1024 String pkgname = p.isUnnamed() ? "" : getPackageName(p); 1025 int index = -1; 1026 for (int j = 0; j < MAX_CONSTANT_VALUE_INDEX_LENGTH; j++) { 1027 index = pkgname.indexOf(".", index + 1); 1028 } 1029 if (index != -1) { 1030 pkgname = pkgname.substring(0, index); 1031 } 1032 return pkgname; 1033 } 1034 1035 /** 1036 * Given a string, replace all occurrences of 'newStr' with 'oldStr'. 1037 * @param originalStr the string to modify. 1038 * @param oldStr the string to replace. 1039 * @param newStr the string to insert in place of the old string. 1040 */ 1041 public String replaceText(String originalStr, String oldStr, 1042 String newStr) { 1043 if (oldStr == null || newStr == null || oldStr.equals(newStr)) { 1044 return originalStr; 1045 } 1046 return originalStr.replace(oldStr, newStr); 1047 } 1048 1049 /** 1050 * Given an annotation, return true if it should be documented and false 1051 * otherwise. 1052 * 1053 * @param annotation the annotation to check. 1054 * 1055 * @return true return true if it should be documented and false otherwise. 1056 */ 1057 public boolean isDocumentedAnnotation(TypeElement annotation) { 1058 for (AnnotationMirror anno : annotation.getAnnotationMirrors()) { 1059 if (getFullyQualifiedName(anno.getAnnotationType().asElement()).equals( 1060 Documented.class.getName())) { 1061 return true; 1062 } 1063 } 1064 return false; 1065 } 1066 1067 /** 1068 * Return true if this class is linkable and false if we can't link to the 1069 * desired class. 1070 * <br> 1071 * <b>NOTE:</b> You can only link to external classes if they are public or 1072 * protected. 1073 * 1074 * @return true if this class is linkable and false if we can't link to the 1075 * desired class. 1076 */ 1077 public boolean isLinkable(TypeElement typeElem) { 1078 return 1079 (typeElem != null && 1080 (isIncluded(typeElem) && configuration.isGeneratedDoc(typeElem))) || 1081 (configuration.extern.isExternal(typeElem) && 1082 (isPublic(typeElem) || isProtected(typeElem))); 1083 } 1084 1085 List<TypeMirror> asErasureTypes(Collection<TypeElement> inList) { 1086 List<TypeMirror> out = new ArrayList<>(inList.size()); 1087 inList.stream().forEach((te) -> { 1088 out.add(typeUtils.erasure(te.asType())); 1089 }); 1090 return out; 1091 } 1092 1093 List<TypeMirror> asTypes(Collection<TypeElement> inList) { 1094 List<TypeMirror> out = new ArrayList<>(inList.size()); 1095 inList.stream().forEach((te) -> { 1096 out.add(te.asType()); 1097 }); 1098 return out; 1099 } 1100 1101 /** 1102 * Return this type as a {@code TypeElement} if it represents a class 1103 * interface or annotation. Array dimensions are ignored. 1104 * If this type {@code ParameterizedType} or {@code WildcardType}, return 1105 * the {@code TypeElement} of the type's erasure. If this is an 1106 * annotation, return this as a {@code TypeElement}. 1107 * If this is a primitive type, return null. 1108 * 1109 * @return the {@code TypeElement} of this type, 1110 * or null if it is a primitive type. 1111 */ 1112 public TypeElement asTypeElement(TypeMirror t) { 1113 return new SimpleTypeVisitor9<TypeElement, Void>() { 1114 1115 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1116 public TypeElement visitDeclared(DeclaredType t, Void p) { 1117 return (TypeElement) t.asElement(); 1118 } 1119 1120 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1121 public TypeElement visitArray(ArrayType t, Void p) { 1122 return visit(t.getComponentType()); 1123 } 1124 1125 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1126 public TypeElement visitTypeVariable(javax.lang.model.type.TypeVariable t, Void p) { 1127 /* 1128 * TODO: Check with JJG. 1129 * if we have an annotated type @A $B T, then erasure returns a 1130 * none, in this case we use asElement instead. 1131 */ 1132 if (isAnnotated(t)) { 1133 return visit(typeUtils.asElement(t).asType()); 1134 } 1135 return visit(typeUtils.erasure(t)); 1136 } 1137 1138 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1139 public TypeElement visitWildcard(javax.lang.model.type.WildcardType t, Void p) { 1140 return visit(typeUtils.erasure(t)); 1141 } 1142 1143 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1144 public TypeElement visitError(ErrorType t, Void p) { 1145 return (TypeElement)t.asElement(); 1146 } 1147 1148 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1149 protected TypeElement defaultAction(TypeMirror e, Void p) { 1150 return super.defaultAction(e, p); 1151 } 1152 }.visit(t); 1153 } 1154 1155 public TypeMirror getComponentType(TypeMirror t) { 1156 while (isArrayType(t)) { 1157 t = ((ArrayType) t).getComponentType(); 1158 } 1159 return t; 1160 } 1161 1162 /** 1163 * Return the type's dimension information, as a string. 1164 * <p> 1165 * For example, a two dimensional array of String returns "{@code [][]}". 1166 * 1167 * @return the type's dimension information as a string. 1168 */ 1169 public String getDimension(TypeMirror t) { 1170 return new SimpleTypeVisitor9<String, Void>() { 1171 StringBuilder dimension = new StringBuilder(""); 1172 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1173 public String visitArray(ArrayType t, Void p) { 1174 dimension.append("[]"); 1175 return visit(t.getComponentType()); 1176 } 1177 1178 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1179 protected String defaultAction(TypeMirror e, Void p) { 1180 return dimension.toString(); 1181 } 1182 1183 }.visit(t); 1184 } 1185 1186 public TypeElement getSuperClass(TypeElement te) { 1187 if (isInterface(te) || isAnnotationType(te) || 1188 te.asType().equals(getObjectType())) { 1189 return null; 1190 } 1191 TypeMirror superclass = te.getSuperclass(); 1192 if (isNoType(superclass) && isClass(te)) { 1193 superclass = getObjectType(); 1194 } 1195 return asTypeElement(superclass); 1196 } 1197 1198 public TypeElement getFirstVisibleSuperClassAsTypeElement(TypeElement te) { 1199 if (isAnnotationType(te) || isInterface(te) || 1200 te.asType().equals(getObjectType())) { 1201 return null; 1202 } 1203 TypeMirror firstVisibleSuperClass = getFirstVisibleSuperClass(te); 1204 return firstVisibleSuperClass == null ? null : asTypeElement(firstVisibleSuperClass); 1205 } 1206 1207 /** 1208 * Given a class, return the closest visible super class. 1209 * @param type the TypeMirror to be interrogated 1210 * @return the closest visible super class. Return null if it cannot 1211 * be found. 1212 */ 1213 1214 public TypeMirror getFirstVisibleSuperClass(TypeMirror type) { 1215 return getFirstVisibleSuperClass(asTypeElement(type)); 1216 } 1217 1218 1219 /** 1220 * Given a class, return the closest visible super class. 1221 * 1222 * @param te the TypeElement to be interrogated 1223 * @return the closest visible super class. Return null if it cannot 1224 * be found.. 1225 */ 1226 public TypeMirror getFirstVisibleSuperClass(TypeElement te) { 1227 TypeMirror superType = te.getSuperclass(); 1228 if (isNoType(superType)) { 1229 superType = getObjectType(); 1230 } 1231 TypeElement superClass = asTypeElement(superType); 1232 1233 while (superClass != null && !isPublic(superClass) && !isLinkable(superClass)) { 1234 TypeMirror supersuperType = superClass.getSuperclass(); 1235 TypeElement supersuperClass = asTypeElement(supersuperType); 1236 if (supersuperClass == null 1237 || supersuperClass.getQualifiedName().equals(superClass.getQualifiedName())) { 1238 break; 1239 } 1240 superType = supersuperType; 1241 superClass = supersuperClass; 1242 } 1243 if (te.asType().equals(superType)) { 1244 return null; 1245 } 1246 return superType; 1247 } 1248 1249 /** 1250 * Given a TypeElement, return the name of its type (Class, Interface, etc.). 1251 * 1252 * @param te the TypeElement to check. 1253 * @param lowerCaseOnly true if you want the name returned in lower case. 1254 * If false, the first letter of the name is capitalized. 1255 * @return 1256 */ 1257 1258 public String getTypeElementName(TypeElement te, boolean lowerCaseOnly) { 1259 String typeName = ""; 1260 if (isInterface(te)) { 1261 typeName = "doclet.Interface"; 1262 } else if (isException(te)) { 1263 typeName = "doclet.Exception"; 1264 } else if (isError(te)) { 1265 typeName = "doclet.Error"; 1266 } else if (isAnnotationType(te)) { 1267 typeName = "doclet.AnnotationType"; 1268 } else if (isEnum(te)) { 1269 typeName = "doclet.Enum"; 1270 } else if (isOrdinaryClass(te)) { 1271 typeName = "doclet.Class"; 1272 } 1273 typeName = lowerCaseOnly ? toLowerCase(typeName) : typeName; 1274 return typeNameMap.computeIfAbsent(typeName, configuration :: getText); 1275 } 1276 1277 private final Map<String, String> typeNameMap = new HashMap<>(); 1278 1279 public String getTypeName(TypeMirror t, boolean fullyQualified) { 1280 return new SimpleTypeVisitor9<String, Void>() { 1281 1282 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1283 public String visitArray(ArrayType t, Void p) { 1284 return visit(t.getComponentType()); 1285 } 1286 1287 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1288 public String visitDeclared(DeclaredType t, Void p) { 1289 TypeElement te = asTypeElement(t); 1290 return fullyQualified 1291 ? te.getQualifiedName().toString() 1292 : getSimpleName(te); 1293 } 1294 1295 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1296 public String visitExecutable(ExecutableType t, Void p) { 1297 return t.toString(); 1298 } 1299 1300 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1301 public String visitPrimitive(PrimitiveType t, Void p) { 1302 return t.toString(); 1303 } 1304 1305 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1306 public String visitTypeVariable(javax.lang.model.type.TypeVariable t, Void p) { 1307 return getSimpleName(t.asElement()); 1308 } 1309 1310 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1311 public String visitWildcard(javax.lang.model.type.WildcardType t, Void p) { 1312 return t.toString(); 1313 } 1314 1315 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1316 protected String defaultAction(TypeMirror e, Void p) { 1317 return e.toString(); 1318 } 1319 }.visit(t); 1320 } 1321 1322 /** 1323 * Replace all tabs in a string with the appropriate number of spaces. 1324 * The string may be a multi-line string. 1325 * @param text the text for which the tabs should be expanded 1326 * @return the text with all tabs expanded 1327 */ 1328 public String replaceTabs(String text) { 1329 if (!text.contains("\t")) 1330 return text; 1331 1332 final int tabLength = configuration.sourcetab; 1333 final String whitespace = configuration.tabSpaces; 1334 final int textLength = text.length(); 1335 StringBuilder result = new StringBuilder(textLength); 1336 int pos = 0; 1337 int lineLength = 0; 1338 for (int i = 0; i < textLength; i++) { 1339 char ch = text.charAt(i); 1340 switch (ch) { 1341 case '\n': case '\r': 1342 lineLength = 0; 1343 break; 1344 case '\t': 1345 result.append(text, pos, i); 1346 int spaceCount = tabLength - lineLength % tabLength; 1347 result.append(whitespace, 0, spaceCount); 1348 lineLength += spaceCount; 1349 pos = i + 1; 1350 break; 1351 default: 1352 lineLength++; 1353 } 1354 } 1355 result.append(text, pos, textLength); 1356 return result.toString(); 1357 } 1358 1359 public String normalizeNewlines(String text) { 1360 StringBuilder sb = new StringBuilder(); 1361 final int textLength = text.length(); 1362 final String NL = DocletConstants.NL; 1363 int pos = 0; 1364 for (int i = 0; i < textLength; i++) { 1365 char ch = text.charAt(i); 1366 switch (ch) { 1367 case '\n': 1368 sb.append(text, pos, i); 1369 sb.append(NL); 1370 pos = i + 1; 1371 break; 1372 case '\r': 1373 sb.append(text, pos, i); 1374 sb.append(NL); 1375 if (i + 1 < textLength && text.charAt(i + 1) == '\n') 1376 i++; 1377 pos = i + 1; 1378 break; 1379 } 1380 } 1381 sb.append(text, pos, textLength); 1382 return sb.toString(); 1383 } 1384 1385 /** 1386 * The documentation for values() and valueOf() in Enums are set by the 1387 * doclet only iff the user or overridden methods are missing. 1388 * @param elem 1389 */ 1390 public void setEnumDocumentation(TypeElement elem) { 1391 for (Element e : getMethods(elem)) { 1392 ExecutableElement ee = (ExecutableElement)e; 1393 if (!getBody(e).isEmpty()) // if already set skip it please 1394 continue; 1395 if (ee.getSimpleName().contentEquals("values") && ee.getParameters().isEmpty()) { 1396 configuration.cmtUtils.setEnumValuesTree(configuration, e); 1397 } 1398 if (ee.getSimpleName().contentEquals("valueOf") && ee.getParameters().size() == 1) { 1399 configuration.cmtUtils.setEnumValueOfTree(configuration, e); 1400 } 1401 } 1402 } 1403 1404 /** 1405 * Returns a locale independent lower cased String. That is, it 1406 * always uses US locale, this is a clone of the one in StringUtils. 1407 * @param s to convert 1408 * @return converted String 1409 */ 1410 public static String toLowerCase(String s) { 1411 return s.toLowerCase(Locale.US); 1412 } 1413 1414 /** 1415 * Return true if the given Element is deprecated. 1416 * 1417 * @param e the Element to check. 1418 * @return true if the given Element is deprecated. 1419 */ 1420 public boolean isDeprecated(Element e) { 1421 if (isPackage(e)) { 1422 return configuration.workArounds.isDeprecated0(e); 1423 } 1424 return elementUtils.isDeprecated(e); 1425 } 1426 1427 /** 1428 * A convenience method to get property name from the name of the 1429 * getter or setter method. 1430 * @param e the input method. 1431 * @return the name of the property of the given setter of getter. 1432 */ 1433 public String propertyName(ExecutableElement e) { 1434 String name = getSimpleName(e); 1435 String propertyName = null; 1436 if (name.startsWith("get") || name.startsWith("set")) { 1437 propertyName = name.substring(3); 1438 } else if (name.startsWith("is")) { 1439 propertyName = name.substring(2); 1440 } 1441 if ((propertyName == null) || propertyName.isEmpty()){ 1442 return ""; 1443 } 1444 return propertyName.substring(0, 1).toLowerCase(configuration.getLocale()) 1445 + propertyName.substring(1); 1446 } 1447 1448 /** 1449 * In case of JavaFX mode on, filters out classes that are private, 1450 * package private or having the @treatAsPrivate annotation. Those are not 1451 * documented in JavaFX mode. 1452 * 1453 * @param classlist a collection of TypeElements 1454 * @param javafx set to true if in JavaFX mode. 1455 * @return list of filtered classes. 1456 */ 1457 public SortedSet<TypeElement> filterOutPrivateClasses(Iterable<TypeElement> classlist, 1458 boolean javafx) { 1459 SortedSet<TypeElement> filteredOutClasses = 1460 new TreeSet<>(makeGeneralPurposeComparator()); 1461 if (!javafx) { 1462 for (Element te : classlist) { 1463 filteredOutClasses.add((TypeElement)te); 1464 } 1465 return filteredOutClasses; 1466 } 1467 for (Element e : classlist) { 1468 if (isPrivate(e) || isPackagePrivate(e)) { 1469 continue; 1470 } 1471 List<? extends DocTree> aspTags = getBlockTags(e, "treatAsPrivate"); 1472 if (aspTags != null && !aspTags.isEmpty()) { 1473 continue; 1474 } 1475 filteredOutClasses.add((TypeElement)e); 1476 } 1477 return filteredOutClasses; 1478 } 1479 1480 /** 1481 * Compares two elements. 1482 * @param e1 first Element 1483 * @param e2 second Element 1484 * @return a true if they are the same, false otherwise. 1485 */ 1486 public boolean elementsEqual(Element e1, Element e2) { 1487 if (e1.getKind() != e2.getKind()) { 1488 return false; 1489 } 1490 String s1 = getSimpleName(e1); 1491 String s2 = getSimpleName(e2); 1492 if (compareStrings(s1, s2) == 0) { 1493 String f1 = getFullyQualifiedName(e1, true); 1494 String f2 = getFullyQualifiedName(e2, true); 1495 return compareStrings(f1, f2) == 0; 1496 } 1497 return false; 1498 } 1499 1500 /** 1501 * A general purpose case insensitive String comparator, which compares 1502 * two Strings using a Collator strength of "TERTIARY". 1503 * 1504 * @param s1 first String to compare. 1505 * @param s2 second String to compare. 1506 * @return a negative integer, zero, or a positive integer as the first 1507 * argument is less than, equal to, or greater than the second. 1508 */ 1509 public int compareStrings(String s1, String s2) { 1510 return compareStrings(true, s1, s2); 1511 } 1512 1513 /** 1514 * A general purpose case sensitive String comparator, which 1515 * compares two Strings using a Collator strength of "SECONDARY". 1516 * 1517 * @param s1 first String to compare. 1518 * @param s2 second String to compare. 1519 * @return a negative integer, zero, or a positive integer as the first 1520 * argument is less than, equal to, or greater than the second. 1521 */ 1522 public int compareCaseCompare(String s1, String s2) { 1523 return compareStrings(false, s1, s2); 1524 } 1525 1526 private DocCollator tertiaryCollator = null; 1527 private DocCollator secondaryCollator = null; 1528 1529 private int compareStrings(boolean caseSensitive, String s1, String s2) { 1530 if (caseSensitive) { 1531 if (tertiaryCollator == null) { 1532 tertiaryCollator = new DocCollator(configuration.locale, Collator.TERTIARY); 1533 } 1534 return tertiaryCollator.compare(s1, s2); 1535 } 1536 if (secondaryCollator == null) { 1537 secondaryCollator = new DocCollator(configuration.locale, Collator.SECONDARY); 1538 } 1539 return secondaryCollator.compare(s1, s2); 1540 } 1541 1542 1543 private static class DocCollator { 1544 private final Map<String, CollationKey> keys; 1545 private final Collator instance; 1546 private final int MAX_SIZE = 1000; 1547 private DocCollator(Locale locale, int strength) { 1548 instance = Collator.getInstance(locale); 1549 instance.setStrength(strength); 1550 1551 keys = new LinkedHashMap<String, CollationKey>(MAX_SIZE + 1, 0.75f, true) { 1552 private static final long serialVersionUID = 1L; 1553 @Override 1554 protected boolean removeEldestEntry(Entry<String, CollationKey> eldest) { 1555 return size() > MAX_SIZE; 1556 } 1557 }; 1558 } 1559 1560 CollationKey getKey(String s) { 1561 return keys.computeIfAbsent(s, instance :: getCollationKey); 1562 } 1563 1564 public int compare(String s1, String s2) { 1565 return getKey(s1).compareTo(getKey(s2)); 1566 } 1567 } 1568 1569 /** 1570 * Comparator for PackageElements, simply compares the fully qualified names 1571 */ 1572 public Comparator<Element> makePackageComparator() { 1573 return new Utils.ElementComparator<Element>() { 1574 @Override 1575 public int compare(Element pkg1, Element pkg2) { 1576 return compareFullyQualifiedNames(pkg1, pkg2); 1577 } 1578 }; 1579 } 1580 1581 public Comparator<SerialFieldTree> makeSerialFieldTreeComparator() { 1582 return (SerialFieldTree o1, SerialFieldTree o2) -> { 1583 String s1 = o1.getName().toString(); 1584 String s2 = o2.getName().toString(); 1585 return s1.compareTo(s2); 1586 }; 1587 } 1588 1589 /** 1590 * Comparator for General Purpose 1591 * @return a ElementComparatorForClassUse 1592 */ 1593 public Comparator<Element> makeGeneralPurposeComparator() { 1594 return makeClassUseComparator(); 1595 } 1596 1597 /** 1598 * A Comparator for Overrides and Implements use used on ExecutableElements 1599 * compares the name first, then compares the SimpleName of the enclosing 1600 * class and the FullyQualifiedName of the enclosing class. 1601 * @return 1602 */ 1603 public Comparator<Element> makeOverrideUseComparator() { 1604 return new Utils.ElementComparator<Element>() { 1605 @Override 1606 public int compare(Element o1, Element o2) { 1607 int result = compareStrings(getSimpleName(o1), getSimpleName(o2)); 1608 if (result != 0) { 1609 return result; 1610 } 1611 if (!isTypeElement(o1) && !isTypeElement(o2) && !isPackage(o1) && !isPackage(o2)) { 1612 TypeElement t1 = getEnclosingTypeElement(o1); 1613 TypeElement t2 = getEnclosingTypeElement(o2); 1614 result = compareStrings(getSimpleName(t1), getSimpleName(t2)); 1615 if (result != 0) 1616 return result; 1617 } 1618 result = compareStrings(getFullyQualifiedName(o1), getFullyQualifiedName(o2)); 1619 if (result != 0) 1620 return result; 1621 return compareElementTypeKinds(o1, o2); 1622 } 1623 }; 1624 } 1625 1626 /** 1627 * A comparator for index file presentations, and are sorted as follows: 1628 * 1. sort on simple names of entities 1629 * 2. if equal, then compare the ElementKind ex: Package, Interface etc. 1630 * 3a. if equal and if the type is of ExecutableElement(Constructor, Methods), 1631 * a case insensitive comparison of parameter the type signatures 1632 * 3b. if equal, case sensitive comparison of the type signatures 1633 * 4. finally, if equal, compare the FQNs of the entities 1634 * @return a comparator for index file use 1635 */ 1636 public Comparator<Element> makeIndexUseComparator() { 1637 return new Utils.ElementComparator<Element>() { 1638 /** 1639 * Compare two given elements, first sort on names, then on the kinds, 1640 * then on the parameters only if the type is an instance of ExecutableElement, 1641 * the parameters are compared and finally the fully qualified names. 1642 * 1643 * @param e1 - an element. 1644 * @param e2 - an element. 1645 * @return a negative integer, zero, or a positive integer as the first 1646 * argument is less than, equal to, or greater than the second. 1647 */ 1648 @Override 1649 public int compare(Element e1, Element e2) { 1650 int result = compareElementTypeKinds(e1, e2); 1651 if (result != 0) { 1652 return result; 1653 } 1654 if (isPackage(e1) && isPackage(e2)) { 1655 return compareFullyQualifiedNames(e1, e2); 1656 } 1657 result = compareNames(e1, e2); 1658 if (result != 0) { 1659 return result; 1660 } 1661 if (hasParameters(e1)) { 1662 List<? extends VariableElement> parameters1 = ((ExecutableElement)e1).getParameters(); 1663 List<? extends VariableElement> parameters2 = ((ExecutableElement)e2).getParameters(); 1664 result = compareParameters(false, parameters1, parameters2); 1665 if (result != 0) { 1666 return result; 1667 } 1668 result = compareParameters(true, parameters1, parameters2); 1669 if (result != 0) { 1670 return result; 1671 } 1672 } 1673 return compareFullyQualifiedNames(e1, e2); 1674 } 1675 }; 1676 } 1677 1678 /** 1679 * Compares the FullyQualifiedNames of two TypeMirrors 1680 * @return 1681 */ 1682 public Comparator<TypeMirror> makeTypeMirrorClassUseComparator() { 1683 return (TypeMirror type1, TypeMirror type2) -> { 1684 String s1 = getQualifiedTypeName(type1); 1685 String s2 = getQualifiedTypeName(type2); 1686 return compareStrings(s1, s2); 1687 }; 1688 } 1689 1690 /** 1691 * Compares the SimpleNames of TypeMirrors if equal then the 1692 * FullyQualifiedNames of TypeMirrors. 1693 * 1694 * @return 1695 */ 1696 public Comparator<TypeMirror> makeTypeMirrorIndexUseComparator() { 1697 return (TypeMirror t1, TypeMirror t2) -> { 1698 int result = compareStrings(getTypeName(t1, false), getTypeName(t2, false)); 1699 if (result != 0) 1700 return result; 1701 return compareStrings(getQualifiedTypeName(t1), getQualifiedTypeName(t2)); 1702 }; 1703 } 1704 1705 /** 1706 * Get the qualified type name of a TypeMiror compatible with the Element's 1707 * getQualified name, returns the qualified name of the Reference type 1708 * otherwise the primitive name. 1709 * @param t the type whose name is to be obtained. 1710 * @return the fully qualified name of Reference type or the primitive name 1711 */ 1712 public String getQualifiedTypeName(TypeMirror t) { 1713 return new SimpleTypeVisitor9<String, Void>() { 1714 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1715 public String visitDeclared(DeclaredType t, Void p) { 1716 return getFullyQualifiedName(t.asElement()); 1717 } 1718 1719 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1720 public String visitArray(ArrayType t, Void p) { 1721 return visit(t.getComponentType()); 1722 } 1723 1724 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1725 public String visitPrimitive(PrimitiveType t, Void p) { 1726 return t.toString(); 1727 } 1728 1729 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1730 public String visitTypeVariable(javax.lang.model.type.TypeVariable t, Void p) { 1731 // The knee jerk reaction is to do this but don't!, as we would like 1732 // it to be compatible with the old world, now if we decide to do so 1733 // care must be taken to avoid collisions. 1734 // return getFullyQualifiedName(t.asElement()); 1735 return t.toString(); 1736 } 1737 1738 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1739 protected String defaultAction(TypeMirror e, Void p) { 1740 throw new UnsupportedOperationException("should not happen"); 1741 } 1742 }.visit(t); 1743 } 1744 1745 /** 1746 * A generic utility which returns the fully qualified names of an entity, 1747 * if the entity is not qualifiable then its enclosing entity, it is upto 1748 * the caller to add the elements name as required. 1749 */ 1750 public String getFullyQualifiedName(Element e) { 1751 return getFullyQualifiedName(e, true); 1752 } 1753 1754 public String getFullyQualifiedName(Element e, final boolean outer) { 1755 return new SimpleElementVisitor9<String, Void>() { 1756 @Override 1757 @DefinedBy(Api.LANGUAGE_MODEL) 1758 public String visitPackage(PackageElement e, Void p) { 1759 return e.getQualifiedName().toString(); 1760 } 1761 1762 @Override 1763 @DefinedBy(Api.LANGUAGE_MODEL) 1764 public String visitType(TypeElement e, Void p) { 1765 return e.getQualifiedName().toString(); 1766 } 1767 1768 @Override 1769 @DefinedBy(Api.LANGUAGE_MODEL) 1770 protected String defaultAction(Element e, Void p) { 1771 return outer ? visit(e.getEnclosingElement()) : e.getSimpleName().toString(); 1772 } 1773 }.visit(e); 1774 } 1775 1776 /** 1777 * Comparator for ClassUse presentations, and sorts as follows: 1778 * 1. member names 1779 * 2. then fully qualified member names 1780 * 3. then parameter types if applicable 1781 * 4. finally the element kinds ie. package, class, interface etc. 1782 * @return a comparator to sort classes and members for class use 1783 */ 1784 public Comparator<Element> makeClassUseComparator() { 1785 return new Utils.ElementComparator<Element>() { 1786 /** 1787 * Compare two Elements, first sort on simple name, and if 1788 * applicable on the fully qualified name, and finally if applicable 1789 * on the parameter types. 1790 * @param e1 - an element. 1791 * @param e2 - an element. 1792 * @return a negative integer, zero, or a positive integer as the first 1793 * argument is less than, equal to, or greater than the second. 1794 */ 1795 @Override 1796 public int compare(Element e1, Element e2) { 1797 int result = compareNames(e1, e2); 1798 if (result != 0) { 1799 return result; 1800 } 1801 result = compareFullyQualifiedNames(e1, e2); 1802 if (result != 0) { 1803 return result; 1804 } 1805 if (hasParameters(e1) && hasParameters(e2)) { 1806 @SuppressWarnings("unchecked") 1807 List<VariableElement> parameters1 = (List<VariableElement>) ((ExecutableElement)e1).getParameters(); 1808 @SuppressWarnings("unchecked") 1809 List<VariableElement> parameters2 = (List<VariableElement>) ((ExecutableElement)e2).getParameters(); 1810 result = compareParameters(false, parameters1, parameters2); 1811 if (result != 0) { 1812 return result; 1813 } 1814 result = compareParameters(true, parameters1, parameters2); 1815 } 1816 if (result != 0) { 1817 return result; 1818 } 1819 return compareElementTypeKinds(e1, e2); 1820 } 1821 }; 1822 } 1823 1824 /** 1825 * A general purpose comparator to sort Element entities, basically provides the building blocks 1826 * for creating specific comparators for an use-case. 1827 * @param <T> an Element 1828 */ 1829 private abstract class ElementComparator<T extends Element> implements Comparator<Element> { 1830 /** 1831 * compares two parameter arrays by first comparing the length of the arrays, and 1832 * then each Type of the parameter in the array. 1833 * @param params1 the first parameter array. 1834 * @param params2 the first parameter array. 1835 * @return a negative integer, zero, or a positive integer as the first 1836 * argument is less than, equal to, or greater than the second. 1837 */ 1838 final EnumMap<ElementKind, Integer> elementKindOrder; 1839 public ElementComparator() { 1840 elementKindOrder = new EnumMap<>(ElementKind.class); 1841 elementKindOrder.put(ElementKind.PACKAGE, 0); 1842 elementKindOrder.put(ElementKind.CLASS, 1); 1843 elementKindOrder.put(ElementKind.ENUM, 2); 1844 elementKindOrder.put(ElementKind.ENUM_CONSTANT, 3); 1845 elementKindOrder.put(ElementKind.INTERFACE, 4); 1846 elementKindOrder.put(ElementKind.ANNOTATION_TYPE, 5); 1847 elementKindOrder.put(ElementKind.FIELD, 6); 1848 elementKindOrder.put(ElementKind.CONSTRUCTOR, 7); 1849 elementKindOrder.put(ElementKind.METHOD, 8); 1850 } 1851 1852 protected int compareParameters(boolean caseSensitive, List<? extends VariableElement> params1, 1853 List<? extends VariableElement> params2) { 1854 1855 return compareStrings(caseSensitive, getParametersAsString(params1), 1856 getParametersAsString(params2)); 1857 } 1858 1859 String getParametersAsString(List<? extends VariableElement> params) { 1860 StringBuilder sb = new StringBuilder(); 1861 for (VariableElement param : params) { 1862 TypeMirror t = param.asType(); 1863 // prefix P for primitive and R for reference types, thus items will 1864 // be ordered lexically and correctly. 1865 sb.append(getTypeCode(t)).append("-").append(t).append("-"); 1866 } 1867 return sb.toString(); 1868 } 1869 1870 private String getTypeCode(TypeMirror t) { 1871 return new SimpleTypeVisitor9<String, Void>() { 1872 1873 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1874 public String visitPrimitive(PrimitiveType t, Void p) { 1875 return "P"; 1876 } 1877 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1878 public String visitArray(ArrayType t, Void p) { 1879 return visit(t.getComponentType()); 1880 } 1881 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1882 protected String defaultAction(TypeMirror e, Void p) { 1883 return "R"; 1884 } 1885 1886 }.visit(t); 1887 } 1888 1889 /** 1890 * Compares two Elements, typically the name of a method, 1891 * field or constructor. 1892 * @param e1 the first Element. 1893 * @param e2 the second Element. 1894 * @return a negative integer, zero, or a positive integer as the first 1895 * argument is less than, equal to, or greater than the second. 1896 */ 1897 protected int compareNames(Element e1, Element e2) { 1898 return compareStrings(getSimpleName(e1), getSimpleName(e2)); 1899 } 1900 1901 /** 1902 * Compares the fully qualified names of the entities 1903 * @param e1 the first Element. 1904 * @param e2 the first Element. 1905 * @return a negative integer, zero, or a positive integer as the first 1906 * argument is less than, equal to, or greater than the second. 1907 */ 1908 protected int compareFullyQualifiedNames(Element e1, Element e2) { 1909 // add simplename to be compatible 1910 String thisElement = getFullyQualifiedName(e1); 1911 String thatElement = getFullyQualifiedName(e2); 1912 return compareStrings(thisElement, thatElement); 1913 } 1914 protected int compareElementTypeKinds(Element e1, Element e2) { 1915 return Integer.compare(elementKindOrder.get(e1.getKind()), 1916 elementKindOrder.get(e2.getKind())); 1917 } 1918 boolean hasParameters(Element e) { 1919 return new SimpleElementVisitor9<Boolean, Void>() { 1920 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1921 public Boolean visitExecutable(ExecutableElement e, Void p) { 1922 return true; 1923 } 1924 1925 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1926 protected Boolean defaultAction(Element e, Void p) { 1927 return false; 1928 } 1929 1930 }.visit(e); 1931 } 1932 1933 /** 1934 * The fully qualified names of the entities, used solely by the comparator. 1935 * 1936 * @param p1 the first Element. 1937 * @param p2 the first Element. 1938 * @return a negative integer, zero, or a positive integer as the first argument is less 1939 * than, equal to, or greater than the second. 1940 */ 1941 private String getFullyQualifiedName(Element e) { 1942 return new SimpleElementVisitor9<String, Void>() { 1943 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1944 public String visitPackage(PackageElement e, Void p) { 1945 return e.getQualifiedName().toString(); 1946 } 1947 1948 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1949 public String visitExecutable(ExecutableElement e, Void p) { 1950 // For backward compatibility 1951 return getFullyQualifiedName(e.getEnclosingElement()) 1952 + "." + e.getSimpleName().toString(); 1953 } 1954 1955 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1956 public String visitType(TypeElement e, Void p) { 1957 return e.getQualifiedName().toString(); 1958 } 1959 1960 @Override @DefinedBy(Api.LANGUAGE_MODEL) 1961 protected String defaultAction(Element e, Void p) { 1962 return getEnclosingTypeElement(e).getQualifiedName().toString() 1963 + "." + e.getSimpleName().toString(); 1964 } 1965 }.visit(e); 1966 } 1967 } 1968 1969 public Iterable<TypeElement> getEnclosedTypeElements(PackageElement pkg) { 1970 List<TypeElement> out = getInterfaces(pkg); 1971 out.addAll(getClasses(pkg)); 1972 out.addAll(getEnums(pkg)); 1973 out.addAll(getAnnotationTypes(pkg)); 1974 return out; 1975 } 1976 1977 // Element related methods 1978 public List<Element> getAnnotationMembers(TypeElement aClass) { 1979 List<Element> members = getAnnotationFields(aClass); 1980 members.addAll(getAnnotationMethods(aClass)); 1981 return members; 1982 } 1983 1984 public List<Element> getAnnotationFields(TypeElement aClass) { 1985 return getItems0(aClass, true, FIELD); 1986 } 1987 1988 List<Element> getAnnotationFieldsUnfiltered(TypeElement aClass) { 1989 return getItems0(aClass, true, FIELD); 1990 } 1991 1992 public List<Element> getAnnotationMethods(TypeElement aClass) { 1993 return getItems0(aClass, true, METHOD); 1994 } 1995 1996 public List<TypeElement> getAnnotationTypes(Element e) { 1997 return convertToTypeElement(getItems(e, true, ANNOTATION_TYPE)); 1998 } 1999 2000 public List<TypeElement> getAnnotationTypesUnfiltered(Element e) { 2001 return convertToTypeElement(getItems(e, false, ANNOTATION_TYPE)); 2002 } 2003 2004 public List<VariableElement> getFields(Element e) { 2005 return convertToVariableElement(getItems(e, true, FIELD)); 2006 } 2007 2008 public List<VariableElement> getFieldsUnfiltered(Element e) { 2009 return convertToVariableElement(getItems(e, false, FIELD)); 2010 } 2011 2012 public List<TypeElement> getClasses(Element e) { 2013 return convertToTypeElement(getItems(e, true, CLASS)); 2014 } 2015 2016 public List<TypeElement> getClassesUnfiltered(Element e) { 2017 return convertToTypeElement(getItems(e, false, CLASS)); 2018 } 2019 2020 public List<ExecutableElement> getConstructors(Element e) { 2021 return convertToExecutableElement(getItems(e, true, CONSTRUCTOR)); 2022 } 2023 2024 public List<ExecutableElement> getMethods(Element e) { 2025 return convertToExecutableElement(getItems(e, true, METHOD)); 2026 } 2027 2028 List<ExecutableElement> getMethodsUnfiltered(Element e) { 2029 return convertToExecutableElement(getItems(e, false, METHOD)); 2030 } 2031 2032 public long getLineNumber(Element e) { 2033 TreePath path = getTreePath(e); 2034 if (path == null) { // maybe null if synthesized 2035 TypeElement encl = getEnclosingTypeElement(e); 2036 path = getTreePath(encl); 2037 } 2038 CompilationUnitTree cu = path.getCompilationUnit(); 2039 LineMap lineMap = cu.getLineMap(); 2040 DocSourcePositions spos = docTrees.getSourcePositions(); 2041 long pos = spos.getStartPosition(cu, path.getLeaf()); 2042 return lineMap.getLineNumber(pos); 2043 } 2044 2045 public List<ExecutableElement> convertToExecutableElement(List<Element> list) { 2046 List<ExecutableElement> out = new ArrayList<>(list.size()); 2047 for (Element e : list) { 2048 out.add((ExecutableElement)e); 2049 } 2050 return out; 2051 } 2052 2053 public List<TypeElement> convertToTypeElement(List<Element> list) { 2054 List<TypeElement> out = new ArrayList<>(list.size()); 2055 for (Element e : list) { 2056 out.add((TypeElement)e); 2057 } 2058 return out; 2059 } 2060 2061 public List<VariableElement> convertToVariableElement(List<Element> list) { 2062 List<VariableElement> out = new ArrayList<>(list.size()); 2063 for (Element e : list) { 2064 out.add((VariableElement) e); 2065 } 2066 return out; 2067 } 2068 2069 public List<TypeElement> getInterfaces(Element e) { 2070 return convertToTypeElement(getItems(e, true, INTERFACE)); 2071 } 2072 2073 public List<TypeElement> getInterfacesUnfiltered(Element e) { 2074 return convertToTypeElement(getItems(e, false, INTERFACE)); 2075 } 2076 2077 List<Element> getNestedClasses(TypeElement e) { 2078 List<Element> result = new ArrayList<>(); 2079 recursiveGetItems(result, e, true, CLASS); 2080 return result; 2081 } 2082 2083 List<Element> getNestedClassesUnfiltered(TypeElement e) { 2084 List<Element> result = new ArrayList<>(); 2085 recursiveGetItems(result, e, false, CLASS); 2086 return result; 2087 } 2088 2089 public List<Element> getEnumConstants(Element e) { 2090 return getItems(e, true, ENUM_CONSTANT); 2091 } 2092 2093 public List<TypeElement> getEnums(Element e) { 2094 return convertToTypeElement(getItems(e, true, ENUM)); 2095 } 2096 2097 public List<TypeElement> getEnumsUnfiltered(Element e) { 2098 return convertToTypeElement(getItems(e, false, ENUM)); 2099 } 2100 2101 public SortedSet<TypeElement> getAllClassesUnfiltered(Element e) { 2102 List<TypeElement> clist = getClassesUnfiltered(e); 2103 clist.addAll(getInterfacesUnfiltered(e)); 2104 clist.addAll(getAnnotationTypesUnfiltered(e)); 2105 SortedSet<TypeElement> oset = new TreeSet<>(makeGeneralPurposeComparator()); 2106 oset.addAll(clist); 2107 return oset; 2108 } 2109 2110 // cache these two as they are repeatedly called. 2111 private Set<TypeElement> specifiedClasses = null; 2112 private Set<PackageElement> specifiedPackages = null; 2113 2114 private void initSpecifiedElements() { 2115 specifiedClasses = new LinkedHashSet<>( 2116 ElementFilter.typesIn(configuration.root.getSpecifiedElements())); 2117 specifiedPackages = new LinkedHashSet<>( 2118 ElementFilter.packagesIn(configuration.root.getSpecifiedElements())); 2119 } 2120 2121 public Set<TypeElement> getSpecifiedClasses() { 2122 if (specifiedClasses == null || specifiedPackages == null) { 2123 initSpecifiedElements(); 2124 } 2125 return specifiedClasses; 2126 } 2127 2128 public Set<PackageElement> getSpecifiedPackages() { 2129 if (specifiedClasses == null || specifiedPackages == null) { 2130 initSpecifiedElements(); 2131 } 2132 return specifiedPackages; 2133 } 2134 2135 private final HashMap<Element, SortedSet<TypeElement>> cachedClasses = new HashMap<>(); 2136 /** 2137 * Returns a list containing classes and interfaces, 2138 * including annotation types. 2139 * @param e Element 2140 * @return List 2141 */ 2142 public SortedSet<TypeElement> getAllClasses(Element e) { 2143 SortedSet<TypeElement> oset = cachedClasses.get(e); 2144 if (oset != null) 2145 return oset; 2146 List<TypeElement> clist = getClasses(e); 2147 clist.addAll(getInterfaces(e)); 2148 clist.addAll(getAnnotationTypes(e)); 2149 clist.addAll(getEnums(e)); 2150 oset = new TreeSet<>(makeGeneralPurposeComparator()); 2151 oset.addAll(clist); 2152 cachedClasses.put(e, oset); 2153 return oset; 2154 } 2155 2156 /* 2157 * Get all the elements unfiltered and filter them finally based 2158 * on its visibility, this works differently from the other getters. 2159 */ 2160 private List<TypeElement> getInnerClasses(Element e, boolean filter) { 2161 List<TypeElement> olist = new ArrayList<>(); 2162 for (TypeElement te : getClassesUnfiltered(e)) { 2163 if (!filter || configuration.workArounds.isVisible(te)) { 2164 olist.add(te); 2165 } 2166 } 2167 for (TypeElement te : getInterfacesUnfiltered(e)) { 2168 if (!filter || configuration.workArounds.isVisible(te)) { 2169 olist.add(te); 2170 } 2171 } 2172 for (TypeElement te : getAnnotationTypesUnfiltered(e)) { 2173 if (!filter || configuration.workArounds.isVisible(te)) { 2174 olist.add(te); 2175 } 2176 } 2177 for (TypeElement te : getEnumsUnfiltered(e)) { 2178 if (!filter || configuration.workArounds.isVisible(te)) { 2179 olist.add(te); 2180 } 2181 } 2182 return olist; 2183 } 2184 2185 public List<TypeElement> getInnerClasses(Element e) { 2186 return getInnerClasses(e, true); 2187 } 2188 2189 public List<TypeElement> getInnerClassesUnfiltered(Element e) { 2190 return getInnerClasses(e, false); 2191 } 2192 2193 /** 2194 * Returns a list of classes that are not errors or exceptions 2195 * @param e Element 2196 * @return List 2197 */ 2198 public List<TypeElement> getOrdinaryClasses(Element e) { 2199 return getClasses(e).stream() 2200 .filter(te -> (!isException(te) && !isError(te))) 2201 .collect(Collectors.toList()); 2202 } 2203 2204 public List<TypeElement> getErrors(Element e) { 2205 return getClasses(e) 2206 .stream() 2207 .filter(this::isError) 2208 .collect(Collectors.toList()); 2209 } 2210 2211 public List<TypeElement> getExceptions(Element e) { 2212 return getClasses(e) 2213 .stream() 2214 .filter(this::isException) 2215 .collect(Collectors.toList()); 2216 } 2217 2218 List<Element> getItems(Element e, boolean filter, ElementKind select) { 2219 List<Element> elements = new ArrayList<>(); 2220 // maintain backward compatibility by returning a null list, see AnnotationDocType.methods(). 2221 if (configuration.backwardCompatibility && e.getKind() == ANNOTATION_TYPE) 2222 return elements; 2223 return new SimpleElementVisitor9<List<Element>, Void>() { 2224 2225 @Override @DefinedBy(Api.LANGUAGE_MODEL) 2226 public List<Element> visitPackage(PackageElement e, Void p) { 2227 recursiveGetItems(elements, e, filter, select); 2228 return elements; 2229 } 2230 2231 @Override @DefinedBy(Api.LANGUAGE_MODEL) 2232 protected List<Element> defaultAction(Element e0, Void p) { 2233 return getItems0(e0, filter, select); 2234 } 2235 2236 }.visit(e); 2237 } 2238 2239 EnumSet<ElementKind> nestedKinds = EnumSet.of(ANNOTATION_TYPE, CLASS, ENUM, INTERFACE); 2240 2241 void recursiveGetItems(Collection<Element> list, Element e, boolean filter, ElementKind... select) { 2242 list.addAll(getItems0(e, filter, select)); 2243 List<Element> classes = getItems0(e, filter, nestedKinds); 2244 for (Element c : classes) { 2245 list.addAll(getItems0(c, filter, select)); 2246 if (isTypeElement(c)) { 2247 recursiveGetItems(list, c, filter, select); 2248 } 2249 } 2250 } 2251 2252 private List<Element> getItems0(Element te, boolean filter, ElementKind... select) { 2253 EnumSet<ElementKind> kinds = EnumSet.copyOf(Arrays.asList(select)); 2254 return getItems0(te, filter, kinds); 2255 } 2256 2257 private List<Element> getItems0(Element te, boolean filter, Set<ElementKind> kinds) { 2258 List<Element> elements = new ArrayList<>(); 2259 for (Element e : te.getEnclosedElements()) { 2260 if (kinds.contains(e.getKind())) { 2261 if (!filter || configuration.workArounds.shouldDocument(e)) { 2262 elements.add(e); 2263 } 2264 } 2265 } 2266 return elements; 2267 } 2268 2269 /* 2270 * nameCache is maintained for improving the comparator 2271 * performance, noting that the Collator used by the comparators 2272 * use Strings, as of this writing. 2273 * TODO: when those APIs handle charSequences, the use of 2274 * this nameCache must be re-investigated and removed. 2275 */ 2276 private final Map<Element, String> nameCache = new LinkedHashMap<>(); 2277 2278 /** 2279 * Returns the name of the element after the last dot of the package name. 2280 * This emulates the behavior of the old doclet. 2281 * @param e an element whose name is required 2282 * @return the name 2283 */ 2284 public String getSimpleName(Element e) { 2285 return nameCache.computeIfAbsent(e, this::getSimpleName0); 2286 } 2287 2288 private SimpleElementVisitor9<String, Void> snvisitor = null; 2289 2290 private String getSimpleName0(Element e) { 2291 if (snvisitor == null) { 2292 snvisitor = new SimpleElementVisitor9<String, Void>() { 2293 @Override @DefinedBy(Api.LANGUAGE_MODEL) 2294 public String visitType(TypeElement e, Void p) { 2295 StringBuilder sb = new StringBuilder(e.getSimpleName()); 2296 Element enclosed = e.getEnclosingElement(); 2297 while (enclosed != null 2298 && (enclosed.getKind().isClass() || enclosed.getKind().isInterface())) { 2299 sb.insert(0, enclosed.getSimpleName() + "."); 2300 enclosed = enclosed.getEnclosingElement(); 2301 } 2302 return sb.toString(); 2303 } 2304 2305 @Override @DefinedBy(Api.LANGUAGE_MODEL) 2306 public String visitExecutable(ExecutableElement e, Void p) { 2307 if (e.getKind() == CONSTRUCTOR || e.getKind() == STATIC_INIT) { 2308 return e.getEnclosingElement().getSimpleName().toString(); 2309 } 2310 return e.getSimpleName().toString(); 2311 } 2312 2313 @Override @DefinedBy(Api.LANGUAGE_MODEL) 2314 protected String defaultAction(Element e, Void p) { 2315 return e.getSimpleName().toString(); 2316 } 2317 }; 2318 } 2319 return snvisitor.visit(e); 2320 } 2321 2322 public TypeElement getEnclosingTypeElement(Element e) { 2323 if (e.getKind() == ElementKind.PACKAGE) 2324 return null; 2325 Element encl = e.getEnclosingElement(); 2326 ElementKind kind = encl.getKind(); 2327 if (kind == ElementKind.PACKAGE) 2328 return null; 2329 while (!(kind.isClass() || kind.isInterface())) { 2330 encl = encl.getEnclosingElement(); 2331 } 2332 return (TypeElement)encl; 2333 } 2334 2335 private ConstantValueExpression cve = null; 2336 2337 public String constantValueExpresion(VariableElement ve) { 2338 if (cve == null) 2339 cve = new ConstantValueExpression(); 2340 return cve.constantValueExpression(configuration.workArounds, ve); 2341 } 2342 2343 private static class ConstantValueExpression { 2344 public String constantValueExpression(WorkArounds workArounds, VariableElement ve) { 2345 return new TypeKindVisitor9<String, Object>() { 2346 /* TODO: we need to fix this correctly. 2347 * we have a discrepancy here, note the use of getConstValue 2348 * vs. getConstantValue, at some point we need to use 2349 * getConstantValue. 2350 * In the legacy world byte and char primitives appear as Integer values, 2351 * thus a byte value of 127 will appear as 127, but in the new world, 2352 * a byte value appears as Byte thus 0x7f will be printed, similarly 2353 * chars will be translated to \n, \r etc. however, in the new world, 2354 * they will be printed as decimal values. The new world is correct, 2355 * and we should fix this by using getConstantValue and the visitor to 2356 * address this in the future. 2357 */ 2358 @Override @DefinedBy(Api.LANGUAGE_MODEL) 2359 public String visitPrimitiveAsBoolean(PrimitiveType t, Object val) { 2360 return (int)val == 0 ? "false" : "true"; 2361 } 2362 2363 @Override @DefinedBy(Api.LANGUAGE_MODEL) 2364 public String visitPrimitiveAsDouble(PrimitiveType t, Object val) { 2365 return sourceForm(((Double)val), 'd'); 2366 } 2367 2368 @Override @DefinedBy(Api.LANGUAGE_MODEL) 2369 public String visitPrimitiveAsFloat(PrimitiveType t, Object val) { 2370 return sourceForm(((Float)val).doubleValue(), 'f'); 2371 } 2372 2373 @Override @DefinedBy(Api.LANGUAGE_MODEL) 2374 public String visitPrimitiveAsLong(PrimitiveType t, Object val) { 2375 return val + "L"; 2376 } 2377 2378 @Override @DefinedBy(Api.LANGUAGE_MODEL) 2379 protected String defaultAction(TypeMirror e, Object val) { 2380 if (val == null) 2381 return null; 2382 else if (val instanceof Character) 2383 return sourceForm(((Character)val)); 2384 else if (val instanceof Byte) 2385 return sourceForm(((Byte)val)); 2386 else if (val instanceof String) 2387 return sourceForm((String)val); 2388 return val.toString(); // covers int, short 2389 } 2390 }.visit(ve.asType(), workArounds.getConstValue(ve)); 2391 } 2392 2393 // where 2394 private String sourceForm(double v, char suffix) { 2395 if (Double.isNaN(v)) 2396 return "0" + suffix + "/0" + suffix; 2397 if (v == Double.POSITIVE_INFINITY) 2398 return "1" + suffix + "/0" + suffix; 2399 if (v == Double.NEGATIVE_INFINITY) 2400 return "-1" + suffix + "/0" + suffix; 2401 return v + (suffix == 'f' || suffix == 'F' ? "" + suffix : ""); 2402 } 2403 2404 private String sourceForm(char c) { 2405 StringBuilder buf = new StringBuilder(8); 2406 buf.append('\''); 2407 sourceChar(c, buf); 2408 buf.append('\''); 2409 return buf.toString(); 2410 } 2411 2412 private String sourceForm(byte c) { 2413 return "0x" + Integer.toString(c & 0xff, 16); 2414 } 2415 2416 private String sourceForm(String s) { 2417 StringBuilder buf = new StringBuilder(s.length() + 5); 2418 buf.append('\"'); 2419 for (int i=0; i<s.length(); i++) { 2420 char c = s.charAt(i); 2421 sourceChar(c, buf); 2422 } 2423 buf.append('\"'); 2424 return buf.toString(); 2425 } 2426 2427 private void sourceChar(char c, StringBuilder buf) { 2428 switch (c) { 2429 case '\b': buf.append("\\b"); return; 2430 case '\t': buf.append("\\t"); return; 2431 case '\n': buf.append("\\n"); return; 2432 case '\f': buf.append("\\f"); return; 2433 case '\r': buf.append("\\r"); return; 2434 case '\"': buf.append("\\\""); return; 2435 case '\'': buf.append("\\\'"); return; 2436 case '\\': buf.append("\\\\"); return; 2437 default: 2438 if (isPrintableAscii(c)) { 2439 buf.append(c); return; 2440 } 2441 unicodeEscape(c, buf); 2442 return; 2443 } 2444 } 2445 2446 private void unicodeEscape(char c, StringBuilder buf) { 2447 final String chars = "0123456789abcdef"; 2448 buf.append("\\u"); 2449 buf.append(chars.charAt(15 & (c>>12))); 2450 buf.append(chars.charAt(15 & (c>>8))); 2451 buf.append(chars.charAt(15 & (c>>4))); 2452 buf.append(chars.charAt(15 & (c>>0))); 2453 } 2454 private boolean isPrintableAscii(char c) { 2455 return c >= ' ' && c <= '~'; 2456 } 2457 } 2458 2459 public boolean isEnclosingPackageIncluded(TypeElement te) { 2460 return isIncluded(containingPackage(te)); 2461 } 2462 2463 public boolean isIncluded(Element e) { 2464 return configuration.root.isIncluded(e); 2465 } 2466 2467 /** 2468 * package name, an unnamed package is returned as <Unnamed> 2469 * @param pkg 2470 * @return 2471 */ 2472 public String getPackageName(PackageElement pkg) { 2473 if (pkg == null || pkg.isUnnamed()) { 2474 return DocletConstants.DEFAULT_PACKAGE_NAME; 2475 } 2476 return pkg.getQualifiedName().toString(); 2477 } 2478 2479 public boolean isAttribute(DocTree doctree) { 2480 return isKind(doctree, ATTRIBUTE); 2481 } 2482 2483 public boolean isAuthor(DocTree doctree) { 2484 return isKind(doctree, AUTHOR); 2485 } 2486 2487 public boolean isComment(DocTree doctree) { 2488 return isKind(doctree, COMMENT); 2489 } 2490 2491 public boolean isDeprecated(DocTree doctree) { 2492 return isKind(doctree, DEPRECATED); 2493 } 2494 2495 public boolean isDocComment(DocTree doctree) { 2496 return isKind(doctree, DOC_COMMENT); 2497 } 2498 2499 public boolean isDocRoot(DocTree doctree) { 2500 return isKind(doctree, DOC_ROOT); 2501 } 2502 2503 public boolean isEndElement(DocTree doctree) { 2504 return isKind(doctree, END_ELEMENT); 2505 } 2506 2507 public boolean isEntity(DocTree doctree) { 2508 return isKind(doctree, ENTITY); 2509 } 2510 2511 public boolean isErroneous(DocTree doctree) { 2512 return isKind(doctree, ERRONEOUS); 2513 } 2514 2515 public boolean isException(DocTree doctree) { 2516 return isKind(doctree, EXCEPTION); 2517 } 2518 2519 public boolean isIdentifier(DocTree doctree) { 2520 return isKind(doctree, IDENTIFIER); 2521 } 2522 2523 public boolean isInheritDoc(DocTree doctree) { 2524 return isKind(doctree, INHERIT_DOC); 2525 } 2526 2527 public boolean isLink(DocTree doctree) { 2528 return isKind(doctree, LINK); 2529 } 2530 2531 public boolean isLinkPlain(DocTree doctree) { 2532 return isKind(doctree, LINK_PLAIN); 2533 } 2534 2535 public boolean isLiteral(DocTree doctree) { 2536 return isKind(doctree, LITERAL); 2537 } 2538 2539 public boolean isOther(DocTree doctree) { 2540 return doctree.getKind() == DocTree.Kind.OTHER; 2541 } 2542 2543 public boolean isParam(DocTree doctree) { 2544 return isKind(doctree, PARAM); 2545 } 2546 2547 public boolean isReference(DocTree doctree) { 2548 return isKind(doctree, REFERENCE); 2549 } 2550 2551 public boolean isReturn(DocTree doctree) { 2552 return isKind(doctree, RETURN); 2553 } 2554 2555 public boolean isSee(DocTree doctree) { 2556 return isKind(doctree, SEE); 2557 } 2558 2559 public boolean isSerial(DocTree doctree) { 2560 return isKind(doctree, SERIAL); 2561 } 2562 2563 public boolean isSerialData(DocTree doctree) { 2564 return isKind(doctree, SERIAL_DATA); 2565 } 2566 2567 public boolean isSerialField(DocTree doctree) { 2568 return isKind(doctree, SERIAL_FIELD); 2569 } 2570 2571 public boolean isSince(DocTree doctree) { 2572 return isKind(doctree, SINCE); 2573 } 2574 2575 public boolean isStartElement(DocTree doctree) { 2576 return isKind(doctree, START_ELEMENT); 2577 } 2578 2579 public boolean isText(DocTree doctree) { 2580 return isKind(doctree, TEXT); 2581 } 2582 2583 public boolean isThrows(DocTree doctree) { 2584 return isKind(doctree, THROWS); 2585 } 2586 2587 public boolean isUnknownBlockTag(DocTree doctree) { 2588 return isKind(doctree, UNKNOWN_BLOCK_TAG); 2589 } 2590 2591 public boolean isUnknownInlineTag(DocTree doctree) { 2592 return isKind(doctree, UNKNOWN_INLINE_TAG); 2593 } 2594 2595 public boolean isValue(DocTree doctree) { 2596 return isKind(doctree, VALUE); 2597 } 2598 2599 public boolean isVersion(DocTree doctree) { 2600 return isKind(doctree, VERSION); 2601 } 2602 2603 private boolean isKind(DocTree doctree, DocTree.Kind match) { 2604 return doctree.getKind() == match; 2605 } 2606 2607 private final WeakSoftHashMap wksMap = new WeakSoftHashMap(this); 2608 2609 public CommentHelper getCommentHelper(Element element) { 2610 return wksMap.computeIfAbsent(element); 2611 } 2612 2613 public void removeCommentHelper(Element element) { 2614 wksMap.remove(element); 2615 } 2616 2617 public List<? extends DocTree> filteredList(List<? extends DocTree> dlist, DocTree.Kind... select) { 2618 List<DocTree> list = new ArrayList<>(dlist.size()); 2619 if (select == null) 2620 return dlist; 2621 for (DocTree dt : dlist) { 2622 if (dt.getKind() != ERRONEOUS) { 2623 for (DocTree.Kind kind : select) { 2624 if (dt.getKind() == kind) { 2625 list.add(dt); 2626 } 2627 } 2628 } 2629 } 2630 return list; 2631 } 2632 2633 private List<? extends DocTree> getBlockTags0(Element element, DocTree.Kind... kinds) { 2634 DocCommentTree dcTree = getDocCommentTree(element); 2635 if (dcTree == null) 2636 return Collections.emptyList(); 2637 2638 return filteredList(dcTree.getBlockTags(), kinds); 2639 } 2640 2641 public List<? extends DocTree> getBlockTags(Element element) { 2642 return getBlockTags0(element, (Kind[]) null); 2643 } 2644 2645 public List<? extends DocTree> getBlockTags(Element element, DocTree.Kind... kinds) { 2646 return getBlockTags0(element, kinds); 2647 } 2648 2649 public List<? extends DocTree> getBlockTags(Element element, String tagName) { 2650 DocTree.Kind kind = null; 2651 switch (tagName) { 2652 case "author": 2653 case "deprecated": 2654 case "param": 2655 case "return": 2656 case "see": 2657 case "serial": 2658 case "since": 2659 case "throws": 2660 case "exception": 2661 case "version": 2662 kind = DocTree.Kind.valueOf(tagName.toUpperCase()); 2663 return getBlockTags(element, kind); 2664 case "serialData": 2665 kind = SERIAL_DATA; 2666 return getBlockTags(element, kind); 2667 case "serialField": 2668 kind = SERIAL_FIELD; 2669 return getBlockTags(element, kind); 2670 default: 2671 kind = DocTree.Kind.UNKNOWN_BLOCK_TAG; 2672 break; 2673 } 2674 List<? extends DocTree> blockTags = getBlockTags(element, kind); 2675 List<DocTree> out = new ArrayList<>(); 2676 String tname = tagName.startsWith("@") ? tagName.substring(1) : tagName; 2677 CommentHelper ch = wksMap.get(element); 2678 for (DocTree dt : blockTags) { 2679 if (ch.getTagName(dt).equals(tname)) { 2680 out.add(dt); 2681 } 2682 } 2683 return out; 2684 } 2685 2686 /** 2687 * Gets a TreePath for an Element. Note this method is called very 2688 * frequently, care must be taken to ensure this method is lithe 2689 * and efficient. 2690 * @param e an Element 2691 * @return TreePath 2692 */ 2693 public TreePath getTreePath(Element e) { 2694 DocCommentDuo duo = dcTreeCache.get(e); 2695 if (isValidDuo(duo) && duo.treePath != null) { 2696 return duo.treePath; 2697 } 2698 duo = configuration.cmtUtils.getSyntheticCommentDuo(e); 2699 if (isValidDuo(duo) && duo.treePath != null) { 2700 return duo.treePath; 2701 } 2702 Map<Element, TreePath> elementToTreePath = configuration.workArounds.getElementToTreePath(); 2703 TreePath path = elementToTreePath.get(e); 2704 if (path != null || elementToTreePath.containsKey(e)) { 2705 // expedite the path and one that is a null 2706 return path; 2707 } 2708 return elementToTreePath.computeIfAbsent(e, docTrees::getPath); 2709 } 2710 2711 private final Map<Element, DocCommentDuo> dcTreeCache = new LinkedHashMap<>(); 2712 2713 /** 2714 * Retrieves the doc comments for a given element. 2715 * @param element 2716 * @return DocCommentTree for the Element 2717 */ 2718 public DocCommentTree getDocCommentTree0(Element element) { 2719 2720 DocCommentDuo duo = null; 2721 2722 ElementKind kind = element.getKind(); 2723 if (kind == ElementKind.PACKAGE || kind == ElementKind.OTHER) { 2724 duo = dcTreeCache.get(element); // local cache 2725 if (!isValidDuo(duo) && kind == ElementKind.PACKAGE) { 2726 // package-info.java 2727 duo = getDocCommentTuple(element); 2728 } 2729 if (!isValidDuo(duo)) { 2730 // package.html or overview.html 2731 duo = configuration.cmtUtils.getHtmlCommentDuo(element); // html source 2732 } 2733 } else { 2734 duo = configuration.cmtUtils.getSyntheticCommentDuo(element); 2735 if (!isValidDuo(duo)) { 2736 duo = dcTreeCache.get(element); // local cache 2737 } 2738 if (!isValidDuo(duo)) { 2739 duo = getDocCommentTuple(element); // get the real mccoy 2740 } 2741 } 2742 2743 DocCommentTree docCommentTree = isValidDuo(duo) ? duo.dcTree : null; 2744 TreePath path = isValidDuo(duo) ? duo.treePath : null; 2745 if (!dcTreeCache.containsKey(element)) { 2746 if (docCommentTree != null && path != null) { 2747 configuration.workArounds.runDocLint(path); 2748 } 2749 dcTreeCache.put(element, duo); 2750 } 2751 return docCommentTree; 2752 } 2753 2754 private DocCommentDuo getDocCommentTuple(Element element) { 2755 // prevent nasty things downstream with overview element 2756 if (element.getKind() != ElementKind.OTHER) { 2757 TreePath path = getTreePath(element); 2758 if (path != null) { 2759 DocCommentTree docCommentTree = docTrees.getDocCommentTree(path); 2760 return new DocCommentDuo(path, docCommentTree); 2761 } 2762 } 2763 return null; 2764 } 2765 2766 boolean isValidDuo(DocCommentDuo duo) { 2767 return duo != null && duo.dcTree != null; 2768 } 2769 2770 public DocCommentTree getDocCommentTree(Element element) { 2771 CommentHelper ch = wksMap.get(element); 2772 if (ch != null) { 2773 return ch.dctree; 2774 } 2775 DocCommentTree dcTree = getDocCommentTree0(element); 2776 if (dcTree != null) { 2777 wksMap.put(element, new CommentHelper(configuration, element, getTreePath(element), dcTree)); 2778 } 2779 return dcTree; 2780 } 2781 2782 public List<? extends DocTree> getBody(Element element) { 2783 DocCommentTree docCommentTree = getDocCommentTree(element); 2784 if (docCommentTree == null) 2785 return Collections.emptyList(); 2786 2787 return docCommentTree.getFullBody(); 2788 } 2789 2790 public List<? extends DocTree> getDeprecatedTrees(Element element) { 2791 return getBlockTags(element, DEPRECATED); 2792 } 2793 2794 public List<? extends DocTree> getSeeTrees(Element element) { 2795 return getBlockTags(element, SEE); 2796 } 2797 2798 public List<? extends DocTree> getSerialTrees(Element element) { 2799 return getBlockTags(element, SERIAL); 2800 } 2801 2802 public List<? extends DocTree> getSerialFieldTrees(VariableElement field) { 2803 return getBlockTags(field, DocTree.Kind.SERIAL_FIELD); 2804 } 2805 2806 public List<? extends DocTree> getThrowsTrees(Element element) { 2807 return getBlockTags(element, DocTree.Kind.EXCEPTION, DocTree.Kind.THROWS); 2808 } 2809 2810 public List<? extends DocTree> getTypeParamTrees(Element element) { 2811 return getParamTrees(element, true); 2812 } 2813 2814 public List<? extends DocTree> getParamTrees(Element element) { 2815 return getParamTrees(element, false); 2816 } 2817 2818 private List<? extends DocTree> getParamTrees(Element element, boolean isTypeParameters) { 2819 List<DocTree> out = new ArrayList<>(); 2820 for (DocTree dt : getBlockTags(element, PARAM)) { 2821 ParamTree pt = (ParamTree) dt; 2822 if (pt.isTypeParameter() == isTypeParameters) { 2823 out.add(dt); 2824 } 2825 } 2826 return out; 2827 } 2828 2829 public List<? extends DocTree> getReturnTrees(Element element) { 2830 List<DocTree> out = new ArrayList<>(); 2831 for (DocTree dt : getBlockTags(element, RETURN)) { 2832 out.add(dt); 2833 } 2834 return out; 2835 } 2836 2837 public List<? extends DocTree> getFirstSentenceTrees(Element element) { 2838 DocCommentTree dcTree = getDocCommentTree(element); 2839 if (dcTree == null) { 2840 return Collections.emptyList(); 2841 } 2842 List<DocTree> out = new ArrayList<>(); 2843 for (DocTree dt : dcTree.getFirstSentence()) { 2844 out.add(dt); 2845 } 2846 return out; 2847 } 2848 2849 public PackageElement containingPackage(Element e) { 2850 return elementUtils.getPackageOf(e); 2851 } 2852 2853 public TypeElement getTopMostContainingTypeElement(Element e) { 2854 if (isPackage(e)) { 2855 return null; 2856 } 2857 TypeElement outer = getEnclosingTypeElement(e); 2858 if (outer == null) 2859 return (TypeElement)e; 2860 while (outer != null && outer.getNestingKind().isNested()) { 2861 outer = getEnclosingTypeElement(outer); 2862 } 2863 return outer; 2864 } 2865 2866 static class WeakSoftHashMap implements Map<Element, CommentHelper> { 2867 2868 private final WeakHashMap<Element, SoftReference<CommentHelper>> wkMap; 2869 private final Utils utils; 2870 public WeakSoftHashMap(Utils utils) { 2871 wkMap = new WeakHashMap<>(); 2872 this.utils = utils; 2873 } 2874 2875 @Override 2876 public boolean containsKey(Object key) { 2877 return wkMap.containsKey(key); 2878 } 2879 2880 @Override 2881 public Collection<CommentHelper> values() { 2882 Set<CommentHelper> out = new LinkedHashSet<>(); 2883 for (SoftReference<CommentHelper> v : wkMap.values()) { 2884 out.add(v.get()); 2885 } 2886 return out; 2887 } 2888 2889 @Override 2890 public boolean containsValue(Object value) { 2891 return wkMap.containsValue(new SoftReference<>((CommentHelper)value)); 2892 } 2893 2894 @Override 2895 public CommentHelper remove(Object key) { 2896 SoftReference<CommentHelper> value = wkMap.remove(key); 2897 return value == null ? null : value.get(); 2898 } 2899 2900 2901 @Override 2902 public CommentHelper put(Element key, CommentHelper value) { 2903 SoftReference<CommentHelper> nvalue = wkMap.put(key, new SoftReference<>(value)); 2904 return nvalue == null ? null : nvalue.get(); 2905 } 2906 2907 @Override 2908 public CommentHelper get(Object key) { 2909 SoftReference<CommentHelper> value = wkMap.get(key); 2910 return value == null ? null : value.get(); 2911 } 2912 2913 @Override 2914 public int size() { 2915 return wkMap.size(); 2916 } 2917 2918 @Override 2919 public boolean isEmpty() { 2920 return wkMap.isEmpty(); 2921 } 2922 2923 @Override 2924 public void clear() { 2925 wkMap.clear(); 2926 } 2927 2928 public CommentHelper computeIfAbsent(Element key) { 2929 if (wkMap.containsKey(key)) { 2930 SoftReference<CommentHelper> value = wkMap.get(key); 2931 if (value != null) { 2932 CommentHelper cvalue = value.get(); 2933 if (cvalue != null) { 2934 return cvalue; 2935 } 2936 } 2937 } 2938 CommentHelper newValue = new CommentHelper(utils.configuration, key, utils.getTreePath(key), 2939 utils.getDocCommentTree(key)); 2940 wkMap.put(key, new SoftReference<>(newValue)); 2941 return newValue; 2942 } 2943 2944 2945 @Override 2946 public void putAll(Map<? extends Element, ? extends CommentHelper> map) { 2947 for (Map.Entry<? extends Element, ? extends CommentHelper> entry : map.entrySet()) { 2948 put(entry.getKey(), entry.getValue()); 2949 } 2950 } 2951 2952 @Override 2953 public Set<Element> keySet() { 2954 return wkMap.keySet(); 2955 } 2956 2957 @Override 2958 public Set<Entry<Element, CommentHelper>> entrySet() { 2959 Set<Entry<Element, CommentHelper>> out = new LinkedHashSet<>(); 2960 for (Element e : wkMap.keySet()) { 2961 SimpleEntry<Element, CommentHelper> n = new SimpleEntry<>(e, get(e)); 2962 out.add(n); 2963 } 2964 return out; 2965 } 2966 } 2967} 2968