30 import java.net.URI;
31 import java.text.CollationKey;
32 import java.text.Collator;
33 import java.text.ParseException;
34 import java.text.RuleBasedCollator;
35 import java.util.*;
36 import java.util.AbstractMap.SimpleEntry;
37 import java.util.Map.Entry;
38 import java.util.stream.Collectors;
39
40 import javax.lang.model.SourceVersion;
41 import javax.lang.model.element.AnnotationMirror;
42 import javax.lang.model.element.AnnotationValue;
43 import javax.lang.model.element.Element;
44 import javax.lang.model.element.ElementKind;
45 import javax.lang.model.element.ExecutableElement;
46 import javax.lang.model.element.Modifier;
47 import javax.lang.model.element.ModuleElement;
48 import javax.lang.model.element.ModuleElement.RequiresDirective;
49 import javax.lang.model.element.PackageElement;
50 import javax.lang.model.element.TypeElement;
51 import javax.lang.model.element.TypeParameterElement;
52 import javax.lang.model.element.VariableElement;
53 import javax.lang.model.type.ArrayType;
54 import javax.lang.model.type.DeclaredType;
55 import javax.lang.model.type.ErrorType;
56 import javax.lang.model.type.ExecutableType;
57 import javax.lang.model.type.NoType;
58 import javax.lang.model.type.PrimitiveType;
59 import javax.lang.model.type.TypeMirror;
60 import javax.lang.model.type.TypeVariable;
61 import javax.lang.model.type.WildcardType;
62 import javax.lang.model.util.ElementFilter;
63 import javax.lang.model.util.ElementKindVisitor9;
64 import javax.lang.model.util.Elements;
65 import javax.lang.model.util.SimpleElementVisitor9;
66 import javax.lang.model.util.SimpleTypeVisitor9;
67 import javax.lang.model.util.TypeKindVisitor9;
68 import javax.lang.model.util.Types;
69 import javax.tools.FileObject;
70 import javax.tools.JavaFileManager;
71 import javax.tools.JavaFileManager.Location;
72 import javax.tools.StandardLocation;
73
74 import com.sun.source.doctree.DocCommentTree;
75 import com.sun.source.doctree.DocTree;
76 import com.sun.source.doctree.DocTree.Kind;
77 import com.sun.source.doctree.ParamTree;
78 import com.sun.source.doctree.SerialFieldTree;
79 import com.sun.source.tree.CompilationUnitTree;
80 import com.sun.source.tree.LineMap;
81 import com.sun.source.util.DocSourcePositions;
82 import com.sun.source.util.DocTrees;
83 import com.sun.source.util.TreePath;
84 import com.sun.tools.javac.model.JavacTypes;
85 import jdk.javadoc.internal.doclets.formats.html.SearchIndexItem;
284 return loc;
285
286 return defaultLocation();
287 }
288
289 private Location defaultLocation() {
290 JavaFileManager fm = configuration.docEnv.getJavaFileManager();
291 return fm.hasLocation(StandardLocation.SOURCE_PATH)
292 ? StandardLocation.SOURCE_PATH
293 : StandardLocation.CLASS_PATH;
294 }
295
296 public boolean isAnnotated(TypeMirror e) {
297 return !e.getAnnotationMirrors().isEmpty();
298 }
299
300 public boolean isAnnotated(Element e) {
301 return !e.getAnnotationMirrors().isEmpty();
302 }
303
304 public boolean isAnnotationType(Element e) {
305 return new SimpleElementVisitor9<Boolean, Void>() {
306 @Override
307 public Boolean visitExecutable(ExecutableElement e, Void p) {
308 return visit(e.getEnclosingElement());
309 }
310
311 @Override
312 public Boolean visitUnknown(Element e, Void p) {
313 return false;
314 }
315
316 @Override
317 protected Boolean defaultAction(Element e, Void p) {
318 return e.getKind() == ANNOTATION_TYPE;
319 }
320 }.visit(e);
321 }
322
323 /**
324 * An Enum implementation is almost identical, thus this method returns if
325 * this element represents a CLASS or an ENUM
399 public String getPropertyLabel(String name) {
400 return name.substring(0, name.lastIndexOf("Property"));
401 }
402
403 public boolean isOverviewElement(Element e) {
404 return e.getKind() == ElementKind.OTHER;
405 }
406
407 public boolean isStatic(Element e) {
408 return e.getModifiers().contains(Modifier.STATIC);
409 }
410
411 public boolean isSerializable(TypeElement e) {
412 return typeUtils.isSubtype(e.asType(), getSerializableType());
413 }
414
415 public boolean isExternalizable(TypeElement e) {
416 return typeUtils.isSubtype(e.asType(), getExternalizableType());
417 }
418
419 public SortedSet<VariableElement> serializableFields(TypeElement aclass) {
420 return configuration.workArounds.getSerializableFields(aclass);
421 }
422
423 public SortedSet<ExecutableElement> serializationMethods(TypeElement aclass) {
424 return configuration.workArounds.getSerializationMethods(aclass);
425 }
426
427 public boolean definesSerializableFields(TypeElement aclass) {
428 return configuration.workArounds.definesSerializableFields( aclass);
429 }
430
431 public String modifiersToString(Element e, boolean trailingSpace) {
432 SortedSet<Modifier> set = new TreeSet<>(e.getModifiers());
433 set.remove(Modifier.NATIVE);
434 set.remove(Modifier.STRICTFP);
435 set.remove(Modifier.SYNCHRONIZED);
436
437 return new ElementKindVisitor9<String, SortedSet<Modifier>>() {
438 final StringBuilder sb = new StringBuilder();
439
440 void addVisibilityModifier(Set<Modifier> modifiers) {
441 if (modifiers.contains(PUBLIC)) {
442 sb.append("public").append(" ");
443 } else if (modifiers.contains(PROTECTED)) {
444 sb.append("protected").append(" ");
445 } else if (modifiers.contains(PRIVATE)) {
446 sb.append("private").append(" ");
447 }
448 }
449
450 void addStatic(Set<Modifier> modifiers) {
451 if (modifiers.contains(STATIC)) {
452 sb.append("static").append(" ");
453 }
454 }
455
456 void addModifers(Set<Modifier> modifiers) {
457 String s = set.stream().map(Modifier::toString).collect(Collectors.joining(" "));
458 sb.append(s);
459 if (!s.isEmpty())
460 sb.append(" ");
461 }
462
463 String finalString(String s) {
464 sb.append(s);
465 if (trailingSpace) {
466 if (sb.lastIndexOf(" ") == sb.length() - 1) {
467 return sb.toString();
468 } else {
469 return sb.append(" ").toString();
470 }
471 } else {
472 return sb.toString().trim();
473 }
474 }
475
476 @Override
477 public String visitTypeAsInterface(TypeElement e, SortedSet<Modifier> p) {
478 addVisibilityModifier(p);
479 addStatic(p);
480 return finalString("interface");
481 }
482
483 @Override
484 public String visitTypeAsEnum(TypeElement e, SortedSet<Modifier> p) {
485 addVisibilityModifier(p);
486 addStatic(p);
487 return finalString("enum");
488 }
489
490 @Override
491 public String visitTypeAsAnnotationType(TypeElement e, SortedSet<Modifier> p) {
492 addVisibilityModifier(p);
493 addStatic(p);
494 return finalString("@interface");
495 }
496
497 @Override
498 public String visitTypeAsClass(TypeElement e, SortedSet<Modifier> p) {
499 addModifers(p);
500 return finalString("class");
501 }
502
503 @Override
504 protected String defaultAction(Element e, SortedSet<Modifier> p) {
505 addModifers(p);
506 return sb.toString().trim();
507 }
508
509 }.visit(e, set);
510 }
511
512 public boolean isFunctionalInterface(AnnotationMirror amirror) {
513 return amirror.getAnnotationType().equals(getFunctionalInterface()) &&
514 configuration.docEnv.getSourceVersion()
515 .compareTo(SourceVersion.RELEASE_8) >= 0;
516 }
517
518 public boolean isNoType(TypeMirror t) {
519 return t.getKind() == NONE;
520 }
521
522 public boolean isOrdinaryClass(TypeElement te) {
523 if (isEnum(te) || isInterface(te) || isAnnotationType(te)) {
524 return false;
525 }
526 if (isError(te) || isException(te)) {
527 return false;
528 }
529 return true;
576 return true;
577 default:
578 return false;
579 }
580 }
581
582 public boolean isVariableElement(Element e) {
583 ElementKind kind = e.getKind();
584 switch(kind) {
585 case ENUM_CONSTANT: case EXCEPTION_PARAMETER: case FIELD:
586 case LOCAL_VARIABLE: case PARAMETER:
587 case RESOURCE_VARIABLE:
588 return true;
589 default:
590 return false;
591 }
592 }
593
594 public boolean isTypeElement(Element e) {
595 switch (e.getKind()) {
596 case CLASS: case ENUM: case INTERFACE: case ANNOTATION_TYPE:
597 return true;
598 default:
599 return false;
600 }
601 }
602
603 /**
604 * Get the signature. It is the parameter list, type is qualified.
605 * For instance, for a method {@code mymethod(String x, int y)},
606 * it will return {@code(java.lang.String,int)}.
607 *
608 * @param e
609 * @return String
610 */
611 public String signature(ExecutableElement e) {
612 return makeSignature(e, true);
613 }
614
615 /**
616 * Get flat signature. All types are not qualified.
1346 switch (ch) {
1347 case '\n':
1348 sb.append(text, pos, i);
1349 sb.append(NL);
1350 pos = i + 1;
1351 break;
1352 case '\r':
1353 sb.append(text, pos, i);
1354 sb.append(NL);
1355 if (i + 1 < textLength && text.charAt(i + 1) == '\n')
1356 i++;
1357 pos = i + 1;
1358 break;
1359 }
1360 }
1361 sb.append(text, pos, textLength);
1362 return sb;
1363 }
1364
1365 /**
1366 * The documentation for values() and valueOf() in Enums are set by the
1367 * doclet only iff the user or overridden methods are missing.
1368 * @param elem
1369 */
1370 public void setEnumDocumentation(TypeElement elem) {
1371 for (Element e : getMethods(elem)) {
1372 ExecutableElement ee = (ExecutableElement)e;
1373 if (!getFullBody(e).isEmpty()) // ignore if already set
1374 continue;
1375 if (ee.getSimpleName().contentEquals("values") && ee.getParameters().isEmpty()) {
1376 removeCommentHelper(ee); // purge previous entry
1377 configuration.cmtUtils.setEnumValuesTree(e);
1378 }
1379 if (ee.getSimpleName().contentEquals("valueOf") && ee.getParameters().size() == 1) {
1380 removeCommentHelper(ee); // purge previous entry
1381 configuration.cmtUtils.setEnumValueOfTree(e);
1382 }
1383 }
1384 }
1385
1386 /**
1387 * Returns a locale independent upper cased String. That is, it
1388 * always uses US locale, this is a clone of the one in StringUtils.
1389 * @param s to convert
1390 * @return converted String
1391 */
1392 public static String toUpperCase(String s) {
1393 return s.toUpperCase(Locale.US);
1394 }
1395
1396 /**
1397 * Returns a locale independent lower cased String. That is, it
1398 * always uses US locale, this is a clone of the one in StringUtils.
1399 * @param s to convert
1400 * @return converted String
1401 */
1402 public static String toLowerCase(String s) {
1403 return s.toLowerCase(Locale.US);
1404 }
1405
1406 /**
1743 */
1744 public Comparator<Element> makeOverrideUseComparator() {
1745 if (overrideUseComparator == null) {
1746 overrideUseComparator = new Utils.ElementComparator() {
1747 @Override
1748 public int compare(Element o1, Element o2) {
1749 int result = compareStrings(getSimpleName(o1), getSimpleName(o2));
1750 if (result != 0) {
1751 return result;
1752 }
1753 if (!isTypeElement(o1) && !isTypeElement(o2) && !isPackage(o1) && !isPackage(o2)) {
1754 TypeElement t1 = getEnclosingTypeElement(o1);
1755 TypeElement t2 = getEnclosingTypeElement(o2);
1756 result = compareStrings(getSimpleName(t1), getSimpleName(t2));
1757 if (result != 0)
1758 return result;
1759 }
1760 result = compareStrings(getFullyQualifiedName(o1), getFullyQualifiedName(o2));
1761 if (result != 0)
1762 return result;
1763 return compareElementTypeKinds(o1, o2);
1764 }
1765 };
1766 }
1767 return overrideUseComparator;
1768 }
1769
1770 private Comparator<Element> indexUseComparator = null;
1771 /**
1772 * Returns a Comparator for index file presentations, and are sorted as follows.
1773 * If comparing modules and/or packages then simply compare the qualified names,
1774 * if comparing a module or a package with a type/member then compare the
1775 * FullyQualifiedName of the module or a package with the SimpleName of the entity,
1776 * otherwise:
1777 * 1. compare the ElementKind ex: Module, Package, Interface etc.
1778 * 2a. if equal and if the type is of ExecutableElement(Constructor, Methods),
1779 * a case insensitive comparison of parameter the type signatures
1780 * 2b. if equal, case sensitive comparison of the type signatures
1781 * 3. finally, if equal, compare the FQNs of the entities
1782 * @return a comparator for index file use
1783 */
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;
1798 // first, compare names as appropriate
1799 if ((isModule(e1) || isPackage(e1)) && (isModule(e2) || isPackage(e2))) {
1800 result = compareFullyQualifiedNames(e1, e2);
1801 } else if (isModule(e1) || isPackage(e1)) {
1802 result = compareStrings(getFullyQualifiedName(e1), getSimpleName(e2));
1803 } else if (isModule(e2) || isPackage(e2)) {
1804 result = compareStrings(getSimpleName(e1), getFullyQualifiedName(e2));
1805 } else {
1806 result = compareNames(e1, e2);
1807 }
1808 if (result != 0) {
1809 return result;
1810 }
1811 // if names are the same, compare element kinds
1812 result = compareElementTypeKinds(e1, e2);
1813 if (result != 0) {
1814 return result;
1815 }
1816 // if element kinds are the same, and are methods,
1817 // compare the method parameters
1818 if (hasParameters(e1)) {
1819 List<? extends VariableElement> parameters1 = ((ExecutableElement)e1).getParameters();
1820 List<? extends VariableElement> parameters2 = ((ExecutableElement)e2).getParameters();
1821 result = compareParameters(false, parameters1, parameters2);
1822 if (result != 0) {
1823 return result;
1824 }
1825 result = compareParameters(true, parameters1, parameters2);
1826 if (result != 0) {
1827 return result;
1828 }
1829 }
1830 // else fall back on fully qualified names
1831 return compareFullyQualifiedNames(e1, e2);
1832 }
1900
1901 @Override
1902 protected String defaultAction(TypeMirror t, Void p) {
1903 return t.toString();
1904 }
1905
1906 }.visit(t);
1907 }
1908
1909 /**
1910 * A generic utility which returns the fully qualified names of an entity,
1911 * if the entity is not qualifiable then its enclosing entity, it is upto
1912 * the caller to add the elements name as required.
1913 * @param e the element to get FQN for.
1914 * @return the name
1915 */
1916 public String getFullyQualifiedName(Element e) {
1917 return getFullyQualifiedName(e, true);
1918 }
1919
1920 public String getFullyQualifiedName(Element e, final boolean outer) {
1921 return new SimpleElementVisitor9<String, Void>() {
1922 @Override
1923 public String visitModule(ModuleElement e, Void p) {
1924 return e.getQualifiedName().toString();
1925 }
1926
1927 @Override
1928 public String visitPackage(PackageElement e, Void p) {
1929 return e.getQualifiedName().toString();
1930 }
1931
1932 @Override
1933 public String visitType(TypeElement e, Void p) {
1934 return e.getQualifiedName().toString();
1935 }
1936
1937 @Override
1938 protected String defaultAction(Element e, Void p) {
1939 return outer ? visit(e.getEnclosingElement()) : e.getSimpleName().toString();
1940 }
1941 }.visit(e);
1968 return result;
1969 }
1970 result = compareFullyQualifiedNames(e1, e2);
1971 if (result != 0) {
1972 return result;
1973 }
1974 if (hasParameters(e1) && hasParameters(e2)) {
1975 @SuppressWarnings("unchecked")
1976 List<VariableElement> parameters1 = (List<VariableElement>)((ExecutableElement)e1).getParameters();
1977 @SuppressWarnings("unchecked")
1978 List<VariableElement> parameters2 = (List<VariableElement>)((ExecutableElement)e2).getParameters();
1979 result = compareParameters(false, parameters1, parameters2);
1980 if (result != 0) {
1981 return result;
1982 }
1983 result = compareParameters(true, parameters1, parameters2);
1984 }
1985 if (result != 0) {
1986 return result;
1987 }
1988 return compareElementTypeKinds(e1, e2);
1989 }
1990 };
1991 }
1992 return classUseComparator;
1993 }
1994
1995 /**
1996 * A general purpose comparator to sort Element entities, basically provides the building blocks
1997 * for creating specific comparators for an use-case.
1998 */
1999 private abstract class ElementComparator implements Comparator<Element> {
2000 /**
2001 * compares two parameter arrays by first comparing the length of the arrays, and
2002 * then each Type of the parameter in the array.
2003 * @param params1 the first parameter array.
2004 * @param params2 the first parameter array.
2005 * @return a negative integer, zero, or a positive integer as the first
2006 * argument is less than, equal to, or greater than the second.
2007 */
2008 final EnumMap<ElementKind, Integer> elementKindOrder;
2009 public ElementComparator() {
2010 elementKindOrder = new EnumMap<>(ElementKind.class);
2011 elementKindOrder.put(ElementKind.MODULE, 0);
2012 elementKindOrder.put(ElementKind.PACKAGE, 1);
2013 elementKindOrder.put(ElementKind.CLASS, 2);
2014 elementKindOrder.put(ElementKind.ENUM, 3);
2015 elementKindOrder.put(ElementKind.ENUM_CONSTANT, 4);
2016 elementKindOrder.put(ElementKind.INTERFACE, 5);
2017 elementKindOrder.put(ElementKind.ANNOTATION_TYPE, 6);
2018 elementKindOrder.put(ElementKind.FIELD, 7);
2019 elementKindOrder.put(ElementKind.CONSTRUCTOR, 8);
2020 elementKindOrder.put(ElementKind.METHOD, 9);
2021 }
2022
2023 protected int compareParameters(boolean caseSensitive, List<? extends VariableElement> params1,
2024 List<? extends VariableElement> params2) {
2025
2026 return compareStrings(caseSensitive, getParametersAsString(params1),
2027 getParametersAsString(params2));
2028 }
2029
2030 String getParametersAsString(List<? extends VariableElement> params) {
2031 StringBuilder sb = new StringBuilder();
2032 for (VariableElement param : params) {
2033 TypeMirror t = param.asType();
2034 // prefix P for primitive and R for reference types, thus items will
2035 // be ordered lexically and correctly.
2036 sb.append(getTypeCode(t)).append("-").append(t).append("-");
2037 }
2038 return sb.toString();
2039 }
2040
2041 private String getTypeCode(TypeMirror t) {
2042 return new SimpleTypeVisitor9<String, Void>() {
2065 * @return a negative integer, zero, or a positive integer as the first
2066 * argument is less than, equal to, or greater than the second.
2067 */
2068 protected int compareNames(Element e1, Element e2) {
2069 return compareStrings(getSimpleName(e1), getSimpleName(e2));
2070 }
2071
2072 /**
2073 * Compares the fully qualified names of the entities
2074 * @param e1 the first Element.
2075 * @param e2 the first Element.
2076 * @return a negative integer, zero, or a positive integer as the first
2077 * argument is less than, equal to, or greater than the second.
2078 */
2079 protected int compareFullyQualifiedNames(Element e1, Element e2) {
2080 // add simplename to be compatible
2081 String thisElement = getFullyQualifiedName(e1);
2082 String thatElement = getFullyQualifiedName(e2);
2083 return compareStrings(thisElement, thatElement);
2084 }
2085 protected int compareElementTypeKinds(Element e1, Element e2) {
2086 return Integer.compare(elementKindOrder.get(e1.getKind()),
2087 elementKindOrder.get(e2.getKind()));
2088 }
2089 boolean hasParameters(Element e) {
2090 return new SimpleElementVisitor9<Boolean, Void>() {
2091 @Override
2092 public Boolean visitExecutable(ExecutableElement e, Void p) {
2093 return true;
2094 }
2095
2096 @Override
2097 protected Boolean defaultAction(Element e, Void p) {
2098 return false;
2099 }
2100
2101 }.visit(e);
2102 }
2103
2104 /**
2105 * The fully qualified names of the entities, used solely by the comparator.
2106 *
2107 * @return a negative integer, zero, or a positive integer as the first argument is less
2108 * than, equal to, or greater than the second.
2109 */
2110 private String getFullyQualifiedName(Element e) {
2111 return new SimpleElementVisitor9<String, Void>() {
2112 @Override
2113 public String visitModule(ModuleElement e, Void p) {
2114 return e.getQualifiedName().toString();
2115 }
2116
2117 @Override
2118 public String visitPackage(PackageElement e, Void p) {
2119 return e.getQualifiedName().toString();
2120 }
2121
2122 @Override
2123 public String visitExecutable(ExecutableElement e, Void p) {
2124 // For backward compatibility
2125 return getFullyQualifiedName(e.getEnclosingElement())
2126 + "." + e.getSimpleName().toString();
2127 }
2128
2129 @Override
2130 public String visitType(TypeElement e, Void p) {
2131 return e.getQualifiedName().toString();
2170 public Comparator<SearchIndexItem> makeGenericSearchIndexComparator() {
2171 if (genericSearchIndexComparator == null) {
2172 genericSearchIndexComparator = (SearchIndexItem sii1, SearchIndexItem sii2) -> {
2173 int result = compareStrings(sii1.getLabel(), sii2.getLabel());
2174 if (result == 0) {
2175 // TreeSet needs this to be consistent with equal so we do
2176 // a plain comparison of string representations as fallback.
2177 result = sii1.toString().compareTo(sii2.toString());
2178 }
2179 return result;
2180 };
2181 }
2182 return genericSearchIndexComparator;
2183 }
2184
2185 public Iterable<TypeElement> getEnclosedTypeElements(PackageElement pkg) {
2186 List<TypeElement> out = getInterfaces(pkg);
2187 out.addAll(getClasses(pkg));
2188 out.addAll(getEnums(pkg));
2189 out.addAll(getAnnotationTypes(pkg));
2190 return out;
2191 }
2192
2193 // Element related methods
2194 public List<Element> getAnnotationMembers(TypeElement aClass) {
2195 List<Element> members = getAnnotationFields(aClass);
2196 members.addAll(getAnnotationMethods(aClass));
2197 return members;
2198 }
2199
2200 public List<Element> getAnnotationFields(TypeElement aClass) {
2201 return getItems0(aClass, true, FIELD);
2202 }
2203
2204 List<Element> getAnnotationFieldsUnfiltered(TypeElement aClass) {
2205 return getItems0(aClass, true, FIELD);
2206 }
2207
2208 public List<Element> getAnnotationMethods(TypeElement aClass) {
2209 return getItems0(aClass, true, METHOD);
2210 }
2211
2212 public List<TypeElement> getAnnotationTypes(Element e) {
2213 return convertToTypeElement(getItems(e, true, ANNOTATION_TYPE));
2214 }
2215
2216 public List<TypeElement> getAnnotationTypesUnfiltered(Element e) {
2217 return convertToTypeElement(getItems(e, false, ANNOTATION_TYPE));
2218 }
2219
2220 public List<VariableElement> getFields(Element e) {
2221 return convertToVariableElement(getItems(e, true, FIELD));
2222 }
2223
2224 public List<VariableElement> getFieldsUnfiltered(Element e) {
2225 return convertToVariableElement(getItems(e, false, FIELD));
2226 }
2227
2228 public List<TypeElement> getClasses(Element e) {
2229 return convertToTypeElement(getItems(e, true, CLASS));
2230 }
2231
2232 public List<TypeElement> getClassesUnfiltered(Element e) {
2233 return convertToTypeElement(getItems(e, false, CLASS));
2234 }
2235
2236 public List<ExecutableElement> getConstructors(Element e) {
2237 return convertToExecutableElement(getItems(e, true, CONSTRUCTOR));
2238 }
2239
2354 public List<TypeElement> getInterfacesUnfiltered(Element e) {
2355 return convertToTypeElement(getItems(e, false, INTERFACE));
2356 }
2357
2358 public List<Element> getEnumConstants(Element e) {
2359 return getItems(e, true, ENUM_CONSTANT);
2360 }
2361
2362 public List<TypeElement> getEnums(Element e) {
2363 return convertToTypeElement(getItems(e, true, ENUM));
2364 }
2365
2366 public List<TypeElement> getEnumsUnfiltered(Element e) {
2367 return convertToTypeElement(getItems(e, false, ENUM));
2368 }
2369
2370 public SortedSet<TypeElement> getAllClassesUnfiltered(Element e) {
2371 List<TypeElement> clist = getClassesUnfiltered(e);
2372 clist.addAll(getInterfacesUnfiltered(e));
2373 clist.addAll(getAnnotationTypesUnfiltered(e));
2374 SortedSet<TypeElement> oset = new TreeSet<>(makeGeneralPurposeComparator());
2375 oset.addAll(clist);
2376 return oset;
2377 }
2378
2379 private final HashMap<Element, SortedSet<TypeElement>> cachedClasses = new HashMap<>();
2380 /**
2381 * Returns a list containing classes and interfaces,
2382 * including annotation types.
2383 * @param e Element
2384 * @return List
2385 */
2386 public SortedSet<TypeElement> getAllClasses(Element e) {
2387 SortedSet<TypeElement> oset = cachedClasses.get(e);
2388 if (oset != null)
2389 return oset;
2390 List<TypeElement> clist = getClasses(e);
2391 clist.addAll(getInterfaces(e));
2392 clist.addAll(getAnnotationTypes(e));
2393 clist.addAll(getEnums(e));
2394 oset = new TreeSet<>(makeGeneralPurposeComparator());
2395 oset.addAll(clist);
2396 cachedClasses.put(e, oset);
2397 return oset;
2398 }
2399
2400 /*
2401 * Get all the elements unfiltered and filter them finally based
2402 * on its visibility, this works differently from the other getters.
2403 */
2404 private List<TypeElement> getInnerClasses(Element e, boolean filter) {
2405 List<TypeElement> olist = new ArrayList<>();
2406 for (TypeElement te : getClassesUnfiltered(e)) {
2407 if (!filter || configuration.docEnv.isSelected(te)) {
2408 olist.add(te);
2409 }
2410 }
2411 for (TypeElement te : getInterfacesUnfiltered(e)) {
2412 if (!filter || configuration.docEnv.isSelected(te)) {
2413 olist.add(te);
2442 public List<TypeElement> getOrdinaryClasses(Element e) {
2443 return getClasses(e).stream()
2444 .filter(te -> (!isException(te) && !isError(te)))
2445 .collect(Collectors.toList());
2446 }
2447
2448 public List<TypeElement> getErrors(Element e) {
2449 return getClasses(e)
2450 .stream()
2451 .filter(this::isError)
2452 .collect(Collectors.toList());
2453 }
2454
2455 public List<TypeElement> getExceptions(Element e) {
2456 return getClasses(e)
2457 .stream()
2458 .filter(this::isException)
2459 .collect(Collectors.toList());
2460 }
2461
2462 List<Element> getItems(Element e, boolean filter, ElementKind select) {
2463 List<Element> elements = new ArrayList<>();
2464 return new SimpleElementVisitor9<List<Element>, Void>() {
2465
2466 @Override
2467 public List<Element> visitPackage(PackageElement e, Void p) {
2468 recursiveGetItems(elements, e, filter, select);
2469 return elements;
2470 }
2471
2472 @Override
2473 protected List<Element> defaultAction(Element e0, Void p) {
2474 return getItems0(e0, filter, select);
2475 }
2476
2477 }.visit(e);
2478 }
2479
2480 EnumSet<ElementKind> nestedKinds = EnumSet.of(ANNOTATION_TYPE, CLASS, ENUM, INTERFACE);
2481 void recursiveGetItems(Collection<Element> list, Element e, boolean filter, ElementKind... select) {
2482 list.addAll(getItems0(e, filter, select));
2483 List<Element> classes = getItems0(e, filter, nestedKinds);
2484 for (Element c : classes) {
2489 }
2490 }
2491
2492 private List<Element> getItems0(Element te, boolean filter, ElementKind... select) {
2493 EnumSet<ElementKind> kinds = EnumSet.copyOf(Arrays.asList(select));
2494 return getItems0(te, filter, kinds);
2495 }
2496
2497 private List<Element> getItems0(Element te, boolean filter, Set<ElementKind> kinds) {
2498 List<Element> elements = new ArrayList<>();
2499 for (Element e : te.getEnclosedElements()) {
2500 if (kinds.contains(e.getKind())) {
2501 if (!filter || shouldDocument(e)) {
2502 elements.add(e);
2503 }
2504 }
2505 }
2506 return elements;
2507 }
2508
2509 private SimpleElementVisitor9<Boolean, Void> shouldDocumentVisitor = null;
2510
2511 protected boolean shouldDocument(Element e) {
2512 if (shouldDocumentVisitor == null) {
2513 shouldDocumentVisitor = new SimpleElementVisitor9<Boolean, Void>() {
2514 private boolean hasSource(TypeElement e) {
2515 return configuration.docEnv.getFileKind(e) ==
2516 javax.tools.JavaFileObject.Kind.SOURCE;
2517 }
2518
2519 // handle types
2520 @Override
2521 public Boolean visitType(TypeElement e, Void p) {
2522 // treat inner classes etc as members
2523 if (e.getNestingKind().isNested()) {
2524 return defaultAction(e, p);
2525 }
2526 return configuration.docEnv.isSelected(e) && hasSource(e);
2527 }
2528
2529 // handle everything else
2530 @Override
2531 protected Boolean defaultAction(Element e, Void p) {
2532 return configuration.docEnv.isSelected(e);
2533 }
2543
2544 /*
2545 * nameCache is maintained for improving the comparator
2546 * performance, noting that the Collator used by the comparators
2547 * use Strings, as of this writing.
2548 * TODO: when those APIs handle charSequences, the use of
2549 * this nameCache must be re-investigated and removed.
2550 */
2551 private final Map<Element, String> nameCache = new LinkedHashMap<>();
2552
2553 /**
2554 * Returns the name of the element after the last dot of the package name.
2555 * This emulates the behavior of the old doclet.
2556 * @param e an element whose name is required
2557 * @return the name
2558 */
2559 public String getSimpleName(Element e) {
2560 return nameCache.computeIfAbsent(e, this::getSimpleName0);
2561 }
2562
2563 private SimpleElementVisitor9<String, Void> snvisitor = null;
2564
2565 private String getSimpleName0(Element e) {
2566 if (snvisitor == null) {
2567 snvisitor = new SimpleElementVisitor9<String, Void>() {
2568 @Override
2569 public String visitModule(ModuleElement e, Void p) {
2570 return e.getQualifiedName().toString(); // temp fix for 8182736
2571 }
2572
2573 @Override
2574 public String visitType(TypeElement e, Void p) {
2575 StringBuilder sb = new StringBuilder(e.getSimpleName());
2576 Element enclosed = e.getEnclosingElement();
2577 while (enclosed != null
2578 && (enclosed.getKind().isClass() || enclosed.getKind().isInterface())) {
2579 sb.insert(0, enclosed.getSimpleName() + ".");
2580 enclosed = enclosed.getEnclosingElement();
2581 }
2582 return sb.toString();
2583 }
2584
2585 @Override
2586 public String visitExecutable(ExecutableElement e, Void p) {
2587 if (e.getKind() == CONSTRUCTOR || e.getKind() == STATIC_INIT) {
2728 final String chars = "0123456789abcdef";
2729 buf.append("\\u");
2730 buf.append(chars.charAt(15 & (c>>12)));
2731 buf.append(chars.charAt(15 & (c>>8)));
2732 buf.append(chars.charAt(15 & (c>>4)));
2733 buf.append(chars.charAt(15 & (c>>0)));
2734 }
2735 private boolean isPrintableAscii(char c) {
2736 return c >= ' ' && c <= '~';
2737 }
2738 }
2739
2740 public boolean isEnclosingPackageIncluded(TypeElement te) {
2741 return isIncluded(containingPackage(te));
2742 }
2743
2744 public boolean isIncluded(Element e) {
2745 return configuration.docEnv.isIncluded(e);
2746 }
2747
2748 private SimpleElementVisitor9<Boolean, Void> specifiedVisitor = null;
2749 public boolean isSpecified(Element e) {
2750 if (specifiedVisitor == null) {
2751 specifiedVisitor = new SimpleElementVisitor9<Boolean, Void>() {
2752 @Override
2753 public Boolean visitModule(ModuleElement e, Void p) {
2754 return configuration.getSpecifiedModuleElements().contains(e);
2755 }
2756
2757 @Override
2758 public Boolean visitPackage(PackageElement e, Void p) {
2759 return configuration.getSpecifiedPackageElements().contains(e);
2760 }
2761
2762 @Override
2763 public Boolean visitType(TypeElement e, Void p) {
2764 return configuration.getSpecifiedTypeElements().contains(e);
2765 }
2766
2767 @Override
2768 protected Boolean defaultAction(Element e, Void p) {
2769 return false;
2770 }
2771 };
3179 public List<? extends DocTree> getProvidesTrees(Element element) {
3180 return getBlockTags(element, PROVIDES);
3181 }
3182
3183 public List<? extends DocTree> getSeeTrees(Element element) {
3184 return getBlockTags(element, SEE);
3185 }
3186
3187 public List<? extends DocTree> getSerialTrees(Element element) {
3188 return getBlockTags(element, SERIAL);
3189 }
3190
3191 public List<? extends DocTree> getSerialFieldTrees(VariableElement field) {
3192 return getBlockTags(field, DocTree.Kind.SERIAL_FIELD);
3193 }
3194
3195 public List<? extends DocTree> getThrowsTrees(Element element) {
3196 return getBlockTags(element, DocTree.Kind.EXCEPTION, DocTree.Kind.THROWS);
3197 }
3198
3199 public List<? extends DocTree> getTypeParamTrees(Element element) {
3200 return getParamTrees(element, true);
3201 }
3202
3203 public List<? extends DocTree> getParamTrees(Element element) {
3204 return getParamTrees(element, false);
3205 }
3206
3207 private List<? extends DocTree> getParamTrees(Element element, boolean isTypeParameters) {
3208 List<DocTree> out = new ArrayList<>();
3209 for (DocTree dt : getBlockTags(element, PARAM)) {
3210 ParamTree pt = (ParamTree) dt;
3211 if (pt.isTypeParameter() == isTypeParameters) {
3212 out.add(dt);
3213 }
3214 }
3215 return out;
3216 }
3217
3218 public List<? extends DocTree> getReturnTrees(Element element) {
3219 List<DocTree> out = new ArrayList<>();
3220 for (DocTree dt : getBlockTags(element, RETURN)) {
3221 out.add(dt);
3222 }
3223 return out;
3224 }
3225
3226 public List<? extends DocTree> getUsesTrees(Element element) {
3227 return getBlockTags(element, USES);
3228 }
3229
3230 public List<? extends DocTree> getFirstSentenceTrees(Element element) {
3231 DocCommentTree dcTree = getDocCommentTree(element);
3232 if (dcTree == null) {
|
30 import java.net.URI;
31 import java.text.CollationKey;
32 import java.text.Collator;
33 import java.text.ParseException;
34 import java.text.RuleBasedCollator;
35 import java.util.*;
36 import java.util.AbstractMap.SimpleEntry;
37 import java.util.Map.Entry;
38 import java.util.stream.Collectors;
39
40 import javax.lang.model.SourceVersion;
41 import javax.lang.model.element.AnnotationMirror;
42 import javax.lang.model.element.AnnotationValue;
43 import javax.lang.model.element.Element;
44 import javax.lang.model.element.ElementKind;
45 import javax.lang.model.element.ExecutableElement;
46 import javax.lang.model.element.Modifier;
47 import javax.lang.model.element.ModuleElement;
48 import javax.lang.model.element.ModuleElement.RequiresDirective;
49 import javax.lang.model.element.PackageElement;
50 import javax.lang.model.element.RecordComponentElement;
51 import javax.lang.model.element.TypeElement;
52 import javax.lang.model.element.TypeParameterElement;
53 import javax.lang.model.element.VariableElement;
54 import javax.lang.model.type.ArrayType;
55 import javax.lang.model.type.DeclaredType;
56 import javax.lang.model.type.ErrorType;
57 import javax.lang.model.type.ExecutableType;
58 import javax.lang.model.type.NoType;
59 import javax.lang.model.type.PrimitiveType;
60 import javax.lang.model.type.TypeMirror;
61 import javax.lang.model.type.TypeVariable;
62 import javax.lang.model.type.WildcardType;
63 import javax.lang.model.util.ElementFilter;
64 import javax.lang.model.util.ElementKindVisitor14;
65 import javax.lang.model.util.Elements;
66 import javax.lang.model.util.SimpleElementVisitor14;
67 import javax.lang.model.util.SimpleTypeVisitor9;
68 import javax.lang.model.util.TypeKindVisitor9;
69 import javax.lang.model.util.Types;
70 import javax.tools.FileObject;
71 import javax.tools.JavaFileManager;
72 import javax.tools.JavaFileManager.Location;
73 import javax.tools.StandardLocation;
74
75 import com.sun.source.doctree.DocCommentTree;
76 import com.sun.source.doctree.DocTree;
77 import com.sun.source.doctree.DocTree.Kind;
78 import com.sun.source.doctree.ParamTree;
79 import com.sun.source.doctree.SerialFieldTree;
80 import com.sun.source.tree.CompilationUnitTree;
81 import com.sun.source.tree.LineMap;
82 import com.sun.source.util.DocSourcePositions;
83 import com.sun.source.util.DocTrees;
84 import com.sun.source.util.TreePath;
85 import com.sun.tools.javac.model.JavacTypes;
86 import jdk.javadoc.internal.doclets.formats.html.SearchIndexItem;
285 return loc;
286
287 return defaultLocation();
288 }
289
290 private Location defaultLocation() {
291 JavaFileManager fm = configuration.docEnv.getJavaFileManager();
292 return fm.hasLocation(StandardLocation.SOURCE_PATH)
293 ? StandardLocation.SOURCE_PATH
294 : StandardLocation.CLASS_PATH;
295 }
296
297 public boolean isAnnotated(TypeMirror e) {
298 return !e.getAnnotationMirrors().isEmpty();
299 }
300
301 public boolean isAnnotated(Element e) {
302 return !e.getAnnotationMirrors().isEmpty();
303 }
304
305 @SuppressWarnings("preview")
306 public boolean isAnnotationType(Element e) {
307 return new SimpleElementVisitor14<Boolean, Void>() {
308 @Override
309 public Boolean visitExecutable(ExecutableElement e, Void p) {
310 return visit(e.getEnclosingElement());
311 }
312
313 @Override
314 public Boolean visitUnknown(Element e, Void p) {
315 return false;
316 }
317
318 @Override
319 protected Boolean defaultAction(Element e, Void p) {
320 return e.getKind() == ANNOTATION_TYPE;
321 }
322 }.visit(e);
323 }
324
325 /**
326 * An Enum implementation is almost identical, thus this method returns if
327 * this element represents a CLASS or an ENUM
401 public String getPropertyLabel(String name) {
402 return name.substring(0, name.lastIndexOf("Property"));
403 }
404
405 public boolean isOverviewElement(Element e) {
406 return e.getKind() == ElementKind.OTHER;
407 }
408
409 public boolean isStatic(Element e) {
410 return e.getModifiers().contains(Modifier.STATIC);
411 }
412
413 public boolean isSerializable(TypeElement e) {
414 return typeUtils.isSubtype(e.asType(), getSerializableType());
415 }
416
417 public boolean isExternalizable(TypeElement e) {
418 return typeUtils.isSubtype(e.asType(), getExternalizableType());
419 }
420
421 @SuppressWarnings("preview")
422 public boolean isRecord(TypeElement e) {
423 return e.getKind() == ElementKind.RECORD;
424 }
425
426 @SuppressWarnings("preview")
427 public boolean isCanonicalRecordConstructor(ExecutableElement ee) {
428 TypeElement te = (TypeElement) ee.getEnclosingElement();
429 List<? extends RecordComponentElement> stateComps = te.getRecordComponents();
430 List<? extends VariableElement> params = ee.getParameters();
431 if (stateComps.size() != params.size()) {
432 return false;
433 }
434
435 Iterator<? extends RecordComponentElement> stateIter = stateComps.iterator();
436 Iterator<? extends VariableElement> paramIter = params.iterator();
437 while (paramIter.hasNext() && stateIter.hasNext()) {
438 VariableElement param = paramIter.next();
439 RecordComponentElement comp = stateIter.next();
440 if (!Objects.equals(param.getSimpleName(), comp.getSimpleName())
441 || !typeUtils.isSameType(param.asType(), comp.asType())) {
442 return false;
443 }
444 }
445
446 return true;
447 }
448
449 public SortedSet<VariableElement> serializableFields(TypeElement aclass) {
450 return configuration.workArounds.getSerializableFields(aclass);
451 }
452
453 public SortedSet<ExecutableElement> serializationMethods(TypeElement aclass) {
454 return configuration.workArounds.getSerializationMethods(aclass);
455 }
456
457 public boolean definesSerializableFields(TypeElement aclass) {
458 return configuration.workArounds.definesSerializableFields( aclass);
459 }
460
461 @SuppressWarnings("preview")
462 public String modifiersToString(Element e, boolean trailingSpace) {
463 SortedSet<Modifier> modifiers = new TreeSet<>(e.getModifiers());
464 modifiers.remove(NATIVE);
465 modifiers.remove(STRICTFP);
466 modifiers.remove(SYNCHRONIZED);
467
468 return new ElementKindVisitor14<String, SortedSet<Modifier>>() {
469 final StringBuilder sb = new StringBuilder();
470
471 void addVisibilityModifier(Set<Modifier> modifiers) {
472 if (modifiers.contains(PUBLIC)) {
473 append("public");
474 } else if (modifiers.contains(PROTECTED)) {
475 append("protected");
476 } else if (modifiers.contains(PRIVATE)) {
477 append("private");
478 }
479 }
480
481 void addStatic(Set<Modifier> modifiers) {
482 if (modifiers.contains(STATIC)) {
483 append("static");
484 }
485 }
486
487 void addModifiers(Set<Modifier> modifiers) {
488 modifiers.stream().map(Modifier::toString).forEach(this::append);
489 }
490
491 void append(String s) {
492 if (sb.length() > 0) {
493 sb.append(" ");
494 }
495 sb.append(s);
496 }
497
498 String finalString(String s) {
499 append(s);
500 if (trailingSpace) {
501 sb.append(" ");
502 }
503 return sb.toString();
504 }
505
506 @Override
507 public String visitTypeAsInterface(TypeElement e, SortedSet<Modifier> mods) {
508 addVisibilityModifier(mods);
509 addStatic(mods);
510 return finalString("interface");
511 }
512
513 @Override
514 public String visitTypeAsEnum(TypeElement e, SortedSet<Modifier> mods) {
515 addVisibilityModifier(mods);
516 addStatic(mods);
517 return finalString("enum");
518 }
519
520 @Override
521 public String visitTypeAsAnnotationType(TypeElement e, SortedSet<Modifier> mods) {
522 addVisibilityModifier(mods);
523 addStatic(mods);
524 return finalString("@interface");
525 }
526
527 @Override
528 public String visitTypeAsRecord(TypeElement e, SortedSet<Modifier> mods) {
529 mods.remove(FINAL); // suppress the implicit `final`
530 return visitTypeAsClass(e, mods);
531 }
532
533 @Override
534 @SuppressWarnings("preview")
535 public String visitTypeAsClass(TypeElement e, SortedSet<Modifier> mods) {
536 Set<Modifier> beforeSealed = EnumSet.noneOf(Modifier.class);
537 Set<Modifier> afterSealed = EnumSet.noneOf(Modifier.class);
538 Set<Modifier> set = beforeSealed;
539 for (Modifier m : Modifier.values()) {
540 if (mods.contains(m)) {
541 set.add(m);
542 }
543 }
544 addModifiers(beforeSealed);
545 addModifiers(afterSealed);
546 String keyword = e.getKind() == ElementKind.RECORD ? "record" : "class";
547 return finalString(keyword);
548 }
549
550 @Override
551 protected String defaultAction(Element e, SortedSet<Modifier> mods) {
552 addModifiers(mods);
553 return sb.toString().trim();
554 }
555
556 }.visit(e, modifiers);
557 }
558
559 public boolean isFunctionalInterface(AnnotationMirror amirror) {
560 return amirror.getAnnotationType().equals(getFunctionalInterface()) &&
561 configuration.docEnv.getSourceVersion()
562 .compareTo(SourceVersion.RELEASE_8) >= 0;
563 }
564
565 public boolean isNoType(TypeMirror t) {
566 return t.getKind() == NONE;
567 }
568
569 public boolean isOrdinaryClass(TypeElement te) {
570 if (isEnum(te) || isInterface(te) || isAnnotationType(te)) {
571 return false;
572 }
573 if (isError(te) || isException(te)) {
574 return false;
575 }
576 return true;
623 return true;
624 default:
625 return false;
626 }
627 }
628
629 public boolean isVariableElement(Element e) {
630 ElementKind kind = e.getKind();
631 switch(kind) {
632 case ENUM_CONSTANT: case EXCEPTION_PARAMETER: case FIELD:
633 case LOCAL_VARIABLE: case PARAMETER:
634 case RESOURCE_VARIABLE:
635 return true;
636 default:
637 return false;
638 }
639 }
640
641 public boolean isTypeElement(Element e) {
642 switch (e.getKind()) {
643 case CLASS: case ENUM: case INTERFACE: case ANNOTATION_TYPE: case RECORD:
644 return true;
645 default:
646 return false;
647 }
648 }
649
650 /**
651 * Get the signature. It is the parameter list, type is qualified.
652 * For instance, for a method {@code mymethod(String x, int y)},
653 * it will return {@code(java.lang.String,int)}.
654 *
655 * @param e
656 * @return String
657 */
658 public String signature(ExecutableElement e) {
659 return makeSignature(e, true);
660 }
661
662 /**
663 * Get flat signature. All types are not qualified.
1393 switch (ch) {
1394 case '\n':
1395 sb.append(text, pos, i);
1396 sb.append(NL);
1397 pos = i + 1;
1398 break;
1399 case '\r':
1400 sb.append(text, pos, i);
1401 sb.append(NL);
1402 if (i + 1 < textLength && text.charAt(i + 1) == '\n')
1403 i++;
1404 pos = i + 1;
1405 break;
1406 }
1407 }
1408 sb.append(text, pos, textLength);
1409 return sb;
1410 }
1411
1412 /**
1413 * Returns a locale independent upper cased String. That is, it
1414 * always uses US locale, this is a clone of the one in StringUtils.
1415 * @param s to convert
1416 * @return converted String
1417 */
1418 public static String toUpperCase(String s) {
1419 return s.toUpperCase(Locale.US);
1420 }
1421
1422 /**
1423 * Returns a locale independent lower cased String. That is, it
1424 * always uses US locale, this is a clone of the one in StringUtils.
1425 * @param s to convert
1426 * @return converted String
1427 */
1428 public static String toLowerCase(String s) {
1429 return s.toLowerCase(Locale.US);
1430 }
1431
1432 /**
1769 */
1770 public Comparator<Element> makeOverrideUseComparator() {
1771 if (overrideUseComparator == null) {
1772 overrideUseComparator = new Utils.ElementComparator() {
1773 @Override
1774 public int compare(Element o1, Element o2) {
1775 int result = compareStrings(getSimpleName(o1), getSimpleName(o2));
1776 if (result != 0) {
1777 return result;
1778 }
1779 if (!isTypeElement(o1) && !isTypeElement(o2) && !isPackage(o1) && !isPackage(o2)) {
1780 TypeElement t1 = getEnclosingTypeElement(o1);
1781 TypeElement t2 = getEnclosingTypeElement(o2);
1782 result = compareStrings(getSimpleName(t1), getSimpleName(t2));
1783 if (result != 0)
1784 return result;
1785 }
1786 result = compareStrings(getFullyQualifiedName(o1), getFullyQualifiedName(o2));
1787 if (result != 0)
1788 return result;
1789 return compareElementKinds(o1, o2);
1790 }
1791 };
1792 }
1793 return overrideUseComparator;
1794 }
1795
1796 private Comparator<Element> indexUseComparator = null;
1797 /**
1798 * Returns a Comparator for index file presentations, and are sorted as follows.
1799 * If comparing modules and/or packages then simply compare the qualified names,
1800 * if comparing a module or a package with a type/member then compare the
1801 * FullyQualifiedName of the module or a package with the SimpleName of the entity,
1802 * otherwise:
1803 * 1. compare the ElementKind ex: Module, Package, Interface etc.
1804 * 2a. if equal and if the type is of ExecutableElement(Constructor, Methods),
1805 * a case insensitive comparison of parameter the type signatures
1806 * 2b. if equal, case sensitive comparison of the type signatures
1807 * 3. finally, if equal, compare the FQNs of the entities
1808 * @return a comparator for index file use
1809 */
1818 * @return a negative integer, zero, or a positive integer as the first
1819 * argument is less than, equal to, or greater than the second.
1820 */
1821 @Override
1822 public int compare(Element e1, Element e2) {
1823 int result;
1824 // first, compare names as appropriate
1825 if ((isModule(e1) || isPackage(e1)) && (isModule(e2) || isPackage(e2))) {
1826 result = compareFullyQualifiedNames(e1, e2);
1827 } else if (isModule(e1) || isPackage(e1)) {
1828 result = compareStrings(getFullyQualifiedName(e1), getSimpleName(e2));
1829 } else if (isModule(e2) || isPackage(e2)) {
1830 result = compareStrings(getSimpleName(e1), getFullyQualifiedName(e2));
1831 } else {
1832 result = compareNames(e1, e2);
1833 }
1834 if (result != 0) {
1835 return result;
1836 }
1837 // if names are the same, compare element kinds
1838 result = compareElementKinds(e1, e2);
1839 if (result != 0) {
1840 return result;
1841 }
1842 // if element kinds are the same, and are methods,
1843 // compare the method parameters
1844 if (hasParameters(e1)) {
1845 List<? extends VariableElement> parameters1 = ((ExecutableElement)e1).getParameters();
1846 List<? extends VariableElement> parameters2 = ((ExecutableElement)e2).getParameters();
1847 result = compareParameters(false, parameters1, parameters2);
1848 if (result != 0) {
1849 return result;
1850 }
1851 result = compareParameters(true, parameters1, parameters2);
1852 if (result != 0) {
1853 return result;
1854 }
1855 }
1856 // else fall back on fully qualified names
1857 return compareFullyQualifiedNames(e1, e2);
1858 }
1926
1927 @Override
1928 protected String defaultAction(TypeMirror t, Void p) {
1929 return t.toString();
1930 }
1931
1932 }.visit(t);
1933 }
1934
1935 /**
1936 * A generic utility which returns the fully qualified names of an entity,
1937 * if the entity is not qualifiable then its enclosing entity, it is upto
1938 * the caller to add the elements name as required.
1939 * @param e the element to get FQN for.
1940 * @return the name
1941 */
1942 public String getFullyQualifiedName(Element e) {
1943 return getFullyQualifiedName(e, true);
1944 }
1945
1946 @SuppressWarnings("preview")
1947 public String getFullyQualifiedName(Element e, final boolean outer) {
1948 return new SimpleElementVisitor14<String, Void>() {
1949 @Override
1950 public String visitModule(ModuleElement e, Void p) {
1951 return e.getQualifiedName().toString();
1952 }
1953
1954 @Override
1955 public String visitPackage(PackageElement e, Void p) {
1956 return e.getQualifiedName().toString();
1957 }
1958
1959 @Override
1960 public String visitType(TypeElement e, Void p) {
1961 return e.getQualifiedName().toString();
1962 }
1963
1964 @Override
1965 protected String defaultAction(Element e, Void p) {
1966 return outer ? visit(e.getEnclosingElement()) : e.getSimpleName().toString();
1967 }
1968 }.visit(e);
1995 return result;
1996 }
1997 result = compareFullyQualifiedNames(e1, e2);
1998 if (result != 0) {
1999 return result;
2000 }
2001 if (hasParameters(e1) && hasParameters(e2)) {
2002 @SuppressWarnings("unchecked")
2003 List<VariableElement> parameters1 = (List<VariableElement>)((ExecutableElement)e1).getParameters();
2004 @SuppressWarnings("unchecked")
2005 List<VariableElement> parameters2 = (List<VariableElement>)((ExecutableElement)e2).getParameters();
2006 result = compareParameters(false, parameters1, parameters2);
2007 if (result != 0) {
2008 return result;
2009 }
2010 result = compareParameters(true, parameters1, parameters2);
2011 }
2012 if (result != 0) {
2013 return result;
2014 }
2015 return compareElementKinds(e1, e2);
2016 }
2017 };
2018 }
2019 return classUseComparator;
2020 }
2021
2022 /**
2023 * A general purpose comparator to sort Element entities, basically provides the building blocks
2024 * for creating specific comparators for an use-case.
2025 */
2026 private abstract class ElementComparator implements Comparator<Element> {
2027 public ElementComparator() { }
2028
2029 /**
2030 * compares two parameter arrays by first comparing the length of the arrays, and
2031 * then each Type of the parameter in the array.
2032 * @param params1 the first parameter array.
2033 * @param params2 the first parameter array.
2034 * @return a negative integer, zero, or a positive integer as the first
2035 * argument is less than, equal to, or greater than the second.
2036 */
2037 protected int compareParameters(boolean caseSensitive, List<? extends VariableElement> params1,
2038 List<? extends VariableElement> params2) {
2039
2040 return compareStrings(caseSensitive, getParametersAsString(params1),
2041 getParametersAsString(params2));
2042 }
2043
2044 String getParametersAsString(List<? extends VariableElement> params) {
2045 StringBuilder sb = new StringBuilder();
2046 for (VariableElement param : params) {
2047 TypeMirror t = param.asType();
2048 // prefix P for primitive and R for reference types, thus items will
2049 // be ordered lexically and correctly.
2050 sb.append(getTypeCode(t)).append("-").append(t).append("-");
2051 }
2052 return sb.toString();
2053 }
2054
2055 private String getTypeCode(TypeMirror t) {
2056 return new SimpleTypeVisitor9<String, Void>() {
2079 * @return a negative integer, zero, or a positive integer as the first
2080 * argument is less than, equal to, or greater than the second.
2081 */
2082 protected int compareNames(Element e1, Element e2) {
2083 return compareStrings(getSimpleName(e1), getSimpleName(e2));
2084 }
2085
2086 /**
2087 * Compares the fully qualified names of the entities
2088 * @param e1 the first Element.
2089 * @param e2 the first Element.
2090 * @return a negative integer, zero, or a positive integer as the first
2091 * argument is less than, equal to, or greater than the second.
2092 */
2093 protected int compareFullyQualifiedNames(Element e1, Element e2) {
2094 // add simplename to be compatible
2095 String thisElement = getFullyQualifiedName(e1);
2096 String thatElement = getFullyQualifiedName(e2);
2097 return compareStrings(thisElement, thatElement);
2098 }
2099
2100 protected int compareElementKinds(Element e1, Element e2) {
2101 return Integer.compare(getKindIndex(e1), getKindIndex(e2));
2102 }
2103
2104 private int getKindIndex(Element e) {
2105 switch (e.getKind()) {
2106 case MODULE: return 0;
2107 case PACKAGE: return 1;
2108 case CLASS: return 2;
2109 case ENUM: return 3;
2110 case ENUM_CONSTANT: return 4;
2111 case RECORD: return 5;
2112 case INTERFACE: return 6;
2113 case ANNOTATION_TYPE: return 7;
2114 case FIELD: return 8;
2115 case CONSTRUCTOR: return 9;
2116 case METHOD: return 10;
2117 default: throw new IllegalArgumentException(e.getKind().toString());
2118 }
2119 }
2120
2121 @SuppressWarnings("preview")
2122 boolean hasParameters(Element e) {
2123 return new SimpleElementVisitor14<Boolean, Void>() {
2124 @Override
2125 public Boolean visitExecutable(ExecutableElement e, Void p) {
2126 return true;
2127 }
2128
2129 @Override
2130 protected Boolean defaultAction(Element e, Void p) {
2131 return false;
2132 }
2133
2134 }.visit(e);
2135 }
2136
2137 /**
2138 * The fully qualified names of the entities, used solely by the comparator.
2139 *
2140 * @return a negative integer, zero, or a positive integer as the first argument is less
2141 * than, equal to, or greater than the second.
2142 */
2143 @SuppressWarnings("preview")
2144 private String getFullyQualifiedName(Element e) {
2145 return new SimpleElementVisitor14<String, Void>() {
2146 @Override
2147 public String visitModule(ModuleElement e, Void p) {
2148 return e.getQualifiedName().toString();
2149 }
2150
2151 @Override
2152 public String visitPackage(PackageElement e, Void p) {
2153 return e.getQualifiedName().toString();
2154 }
2155
2156 @Override
2157 public String visitExecutable(ExecutableElement e, Void p) {
2158 // For backward compatibility
2159 return getFullyQualifiedName(e.getEnclosingElement())
2160 + "." + e.getSimpleName().toString();
2161 }
2162
2163 @Override
2164 public String visitType(TypeElement e, Void p) {
2165 return e.getQualifiedName().toString();
2204 public Comparator<SearchIndexItem> makeGenericSearchIndexComparator() {
2205 if (genericSearchIndexComparator == null) {
2206 genericSearchIndexComparator = (SearchIndexItem sii1, SearchIndexItem sii2) -> {
2207 int result = compareStrings(sii1.getLabel(), sii2.getLabel());
2208 if (result == 0) {
2209 // TreeSet needs this to be consistent with equal so we do
2210 // a plain comparison of string representations as fallback.
2211 result = sii1.toString().compareTo(sii2.toString());
2212 }
2213 return result;
2214 };
2215 }
2216 return genericSearchIndexComparator;
2217 }
2218
2219 public Iterable<TypeElement> getEnclosedTypeElements(PackageElement pkg) {
2220 List<TypeElement> out = getInterfaces(pkg);
2221 out.addAll(getClasses(pkg));
2222 out.addAll(getEnums(pkg));
2223 out.addAll(getAnnotationTypes(pkg));
2224 out.addAll(getRecords(pkg));
2225 return out;
2226 }
2227
2228 // Element related methods
2229 public List<Element> getAnnotationMembers(TypeElement aClass) {
2230 List<Element> members = getAnnotationFields(aClass);
2231 members.addAll(getAnnotationMethods(aClass));
2232 return members;
2233 }
2234
2235 public List<Element> getAnnotationFields(TypeElement aClass) {
2236 return getItems0(aClass, true, FIELD);
2237 }
2238
2239 List<Element> getAnnotationFieldsUnfiltered(TypeElement aClass) {
2240 return getItems0(aClass, true, FIELD);
2241 }
2242
2243 public List<Element> getAnnotationMethods(TypeElement aClass) {
2244 return getItems0(aClass, true, METHOD);
2245 }
2246
2247 public List<TypeElement> getAnnotationTypes(Element e) {
2248 return convertToTypeElement(getItems(e, true, ANNOTATION_TYPE));
2249 }
2250
2251 public List<TypeElement> getAnnotationTypesUnfiltered(Element e) {
2252 return convertToTypeElement(getItems(e, false, ANNOTATION_TYPE));
2253 }
2254
2255 @SuppressWarnings("preview")
2256 public List<TypeElement> getRecords(Element e) {
2257 return convertToTypeElement(getItems(e, true, RECORD));
2258 }
2259
2260 @SuppressWarnings("preview")
2261 public List<TypeElement> getRecordsUnfiltered(Element e) {
2262 return convertToTypeElement(getItems(e, false, RECORD));
2263 }
2264
2265 public List<VariableElement> getFields(Element e) {
2266 return convertToVariableElement(getItems(e, true, FIELD));
2267 }
2268
2269 public List<VariableElement> getFieldsUnfiltered(Element e) {
2270 return convertToVariableElement(getItems(e, false, FIELD));
2271 }
2272
2273 public List<TypeElement> getClasses(Element e) {
2274 return convertToTypeElement(getItems(e, true, CLASS));
2275 }
2276
2277 public List<TypeElement> getClassesUnfiltered(Element e) {
2278 return convertToTypeElement(getItems(e, false, CLASS));
2279 }
2280
2281 public List<ExecutableElement> getConstructors(Element e) {
2282 return convertToExecutableElement(getItems(e, true, CONSTRUCTOR));
2283 }
2284
2399 public List<TypeElement> getInterfacesUnfiltered(Element e) {
2400 return convertToTypeElement(getItems(e, false, INTERFACE));
2401 }
2402
2403 public List<Element> getEnumConstants(Element e) {
2404 return getItems(e, true, ENUM_CONSTANT);
2405 }
2406
2407 public List<TypeElement> getEnums(Element e) {
2408 return convertToTypeElement(getItems(e, true, ENUM));
2409 }
2410
2411 public List<TypeElement> getEnumsUnfiltered(Element e) {
2412 return convertToTypeElement(getItems(e, false, ENUM));
2413 }
2414
2415 public SortedSet<TypeElement> getAllClassesUnfiltered(Element e) {
2416 List<TypeElement> clist = getClassesUnfiltered(e);
2417 clist.addAll(getInterfacesUnfiltered(e));
2418 clist.addAll(getAnnotationTypesUnfiltered(e));
2419 clist.addAll(getRecordsUnfiltered(e));
2420 SortedSet<TypeElement> oset = new TreeSet<>(makeGeneralPurposeComparator());
2421 oset.addAll(clist);
2422 return oset;
2423 }
2424
2425 private final HashMap<Element, SortedSet<TypeElement>> cachedClasses = new HashMap<>();
2426 /**
2427 * Returns a list containing classes and interfaces,
2428 * including annotation types.
2429 * @param e Element
2430 * @return List
2431 */
2432 public SortedSet<TypeElement> getAllClasses(Element e) {
2433 SortedSet<TypeElement> oset = cachedClasses.get(e);
2434 if (oset != null)
2435 return oset;
2436 List<TypeElement> clist = getClasses(e);
2437 clist.addAll(getInterfaces(e));
2438 clist.addAll(getAnnotationTypes(e));
2439 clist.addAll(getEnums(e));
2440 clist.addAll(getRecords(e));
2441 oset = new TreeSet<>(makeGeneralPurposeComparator());
2442 oset.addAll(clist);
2443 cachedClasses.put(e, oset);
2444 return oset;
2445 }
2446
2447 /*
2448 * Get all the elements unfiltered and filter them finally based
2449 * on its visibility, this works differently from the other getters.
2450 */
2451 private List<TypeElement> getInnerClasses(Element e, boolean filter) {
2452 List<TypeElement> olist = new ArrayList<>();
2453 for (TypeElement te : getClassesUnfiltered(e)) {
2454 if (!filter || configuration.docEnv.isSelected(te)) {
2455 olist.add(te);
2456 }
2457 }
2458 for (TypeElement te : getInterfacesUnfiltered(e)) {
2459 if (!filter || configuration.docEnv.isSelected(te)) {
2460 olist.add(te);
2489 public List<TypeElement> getOrdinaryClasses(Element e) {
2490 return getClasses(e).stream()
2491 .filter(te -> (!isException(te) && !isError(te)))
2492 .collect(Collectors.toList());
2493 }
2494
2495 public List<TypeElement> getErrors(Element e) {
2496 return getClasses(e)
2497 .stream()
2498 .filter(this::isError)
2499 .collect(Collectors.toList());
2500 }
2501
2502 public List<TypeElement> getExceptions(Element e) {
2503 return getClasses(e)
2504 .stream()
2505 .filter(this::isException)
2506 .collect(Collectors.toList());
2507 }
2508
2509 @SuppressWarnings("preview")
2510 List<Element> getItems(Element e, boolean filter, ElementKind select) {
2511 List<Element> elements = new ArrayList<>();
2512 return new SimpleElementVisitor14<List<Element>, Void>() {
2513
2514 @Override
2515 public List<Element> visitPackage(PackageElement e, Void p) {
2516 recursiveGetItems(elements, e, filter, select);
2517 return elements;
2518 }
2519
2520 @Override
2521 protected List<Element> defaultAction(Element e0, Void p) {
2522 return getItems0(e0, filter, select);
2523 }
2524
2525 }.visit(e);
2526 }
2527
2528 EnumSet<ElementKind> nestedKinds = EnumSet.of(ANNOTATION_TYPE, CLASS, ENUM, INTERFACE);
2529 void recursiveGetItems(Collection<Element> list, Element e, boolean filter, ElementKind... select) {
2530 list.addAll(getItems0(e, filter, select));
2531 List<Element> classes = getItems0(e, filter, nestedKinds);
2532 for (Element c : classes) {
2537 }
2538 }
2539
2540 private List<Element> getItems0(Element te, boolean filter, ElementKind... select) {
2541 EnumSet<ElementKind> kinds = EnumSet.copyOf(Arrays.asList(select));
2542 return getItems0(te, filter, kinds);
2543 }
2544
2545 private List<Element> getItems0(Element te, boolean filter, Set<ElementKind> kinds) {
2546 List<Element> elements = new ArrayList<>();
2547 for (Element e : te.getEnclosedElements()) {
2548 if (kinds.contains(e.getKind())) {
2549 if (!filter || shouldDocument(e)) {
2550 elements.add(e);
2551 }
2552 }
2553 }
2554 return elements;
2555 }
2556
2557 @SuppressWarnings("preview")
2558 private SimpleElementVisitor14<Boolean, Void> shouldDocumentVisitor = null;
2559
2560 @SuppressWarnings("preview")
2561 public boolean shouldDocument(Element e) {
2562 if (shouldDocumentVisitor == null) {
2563 shouldDocumentVisitor = new SimpleElementVisitor14<Boolean, Void>() {
2564 private boolean hasSource(TypeElement e) {
2565 return configuration.docEnv.getFileKind(e) ==
2566 javax.tools.JavaFileObject.Kind.SOURCE;
2567 }
2568
2569 // handle types
2570 @Override
2571 public Boolean visitType(TypeElement e, Void p) {
2572 // treat inner classes etc as members
2573 if (e.getNestingKind().isNested()) {
2574 return defaultAction(e, p);
2575 }
2576 return configuration.docEnv.isSelected(e) && hasSource(e);
2577 }
2578
2579 // handle everything else
2580 @Override
2581 protected Boolean defaultAction(Element e, Void p) {
2582 return configuration.docEnv.isSelected(e);
2583 }
2593
2594 /*
2595 * nameCache is maintained for improving the comparator
2596 * performance, noting that the Collator used by the comparators
2597 * use Strings, as of this writing.
2598 * TODO: when those APIs handle charSequences, the use of
2599 * this nameCache must be re-investigated and removed.
2600 */
2601 private final Map<Element, String> nameCache = new LinkedHashMap<>();
2602
2603 /**
2604 * Returns the name of the element after the last dot of the package name.
2605 * This emulates the behavior of the old doclet.
2606 * @param e an element whose name is required
2607 * @return the name
2608 */
2609 public String getSimpleName(Element e) {
2610 return nameCache.computeIfAbsent(e, this::getSimpleName0);
2611 }
2612
2613 @SuppressWarnings("preview")
2614 private SimpleElementVisitor14<String, Void> snvisitor = null;
2615
2616 @SuppressWarnings("preview")
2617 private String getSimpleName0(Element e) {
2618 if (snvisitor == null) {
2619 snvisitor = new SimpleElementVisitor14<String, Void>() {
2620 @Override
2621 public String visitModule(ModuleElement e, Void p) {
2622 return e.getQualifiedName().toString(); // temp fix for 8182736
2623 }
2624
2625 @Override
2626 public String visitType(TypeElement e, Void p) {
2627 StringBuilder sb = new StringBuilder(e.getSimpleName());
2628 Element enclosed = e.getEnclosingElement();
2629 while (enclosed != null
2630 && (enclosed.getKind().isClass() || enclosed.getKind().isInterface())) {
2631 sb.insert(0, enclosed.getSimpleName() + ".");
2632 enclosed = enclosed.getEnclosingElement();
2633 }
2634 return sb.toString();
2635 }
2636
2637 @Override
2638 public String visitExecutable(ExecutableElement e, Void p) {
2639 if (e.getKind() == CONSTRUCTOR || e.getKind() == STATIC_INIT) {
2780 final String chars = "0123456789abcdef";
2781 buf.append("\\u");
2782 buf.append(chars.charAt(15 & (c>>12)));
2783 buf.append(chars.charAt(15 & (c>>8)));
2784 buf.append(chars.charAt(15 & (c>>4)));
2785 buf.append(chars.charAt(15 & (c>>0)));
2786 }
2787 private boolean isPrintableAscii(char c) {
2788 return c >= ' ' && c <= '~';
2789 }
2790 }
2791
2792 public boolean isEnclosingPackageIncluded(TypeElement te) {
2793 return isIncluded(containingPackage(te));
2794 }
2795
2796 public boolean isIncluded(Element e) {
2797 return configuration.docEnv.isIncluded(e);
2798 }
2799
2800 @SuppressWarnings("preview")
2801 private SimpleElementVisitor14<Boolean, Void> specifiedVisitor = null;
2802 @SuppressWarnings("preview")
2803 public boolean isSpecified(Element e) {
2804 if (specifiedVisitor == null) {
2805 specifiedVisitor = new SimpleElementVisitor14<Boolean, Void>() {
2806 @Override
2807 public Boolean visitModule(ModuleElement e, Void p) {
2808 return configuration.getSpecifiedModuleElements().contains(e);
2809 }
2810
2811 @Override
2812 public Boolean visitPackage(PackageElement e, Void p) {
2813 return configuration.getSpecifiedPackageElements().contains(e);
2814 }
2815
2816 @Override
2817 public Boolean visitType(TypeElement e, Void p) {
2818 return configuration.getSpecifiedTypeElements().contains(e);
2819 }
2820
2821 @Override
2822 protected Boolean defaultAction(Element e, Void p) {
2823 return false;
2824 }
2825 };
3233 public List<? extends DocTree> getProvidesTrees(Element element) {
3234 return getBlockTags(element, PROVIDES);
3235 }
3236
3237 public List<? extends DocTree> getSeeTrees(Element element) {
3238 return getBlockTags(element, SEE);
3239 }
3240
3241 public List<? extends DocTree> getSerialTrees(Element element) {
3242 return getBlockTags(element, SERIAL);
3243 }
3244
3245 public List<? extends DocTree> getSerialFieldTrees(VariableElement field) {
3246 return getBlockTags(field, DocTree.Kind.SERIAL_FIELD);
3247 }
3248
3249 public List<? extends DocTree> getThrowsTrees(Element element) {
3250 return getBlockTags(element, DocTree.Kind.EXCEPTION, DocTree.Kind.THROWS);
3251 }
3252
3253 public List<? extends ParamTree> getTypeParamTrees(Element element) {
3254 return getParamTrees(element, true);
3255 }
3256
3257 public List<? extends ParamTree> getParamTrees(Element element) {
3258 return getParamTrees(element, false);
3259 }
3260
3261 private List<? extends ParamTree> getParamTrees(Element element, boolean isTypeParameters) {
3262 List<ParamTree> out = new ArrayList<>();
3263 for (DocTree dt : getBlockTags(element, PARAM)) {
3264 ParamTree pt = (ParamTree) dt;
3265 if (pt.isTypeParameter() == isTypeParameters) {
3266 out.add(pt);
3267 }
3268 }
3269 return out;
3270 }
3271
3272 public List<? extends DocTree> getReturnTrees(Element element) {
3273 List<DocTree> out = new ArrayList<>();
3274 for (DocTree dt : getBlockTags(element, RETURN)) {
3275 out.add(dt);
3276 }
3277 return out;
3278 }
3279
3280 public List<? extends DocTree> getUsesTrees(Element element) {
3281 return getBlockTags(element, USES);
3282 }
3283
3284 public List<? extends DocTree> getFirstSentenceTrees(Element element) {
3285 DocCommentTree dcTree = getDocCommentTree(element);
3286 if (dcTree == null) {
|