1 /* 2 * Copyright (c) 1998, 2019, 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 26 package jdk.javadoc.internal.doclets.toolkit.util; 27 28 29 import java.util.ArrayList; 30 import java.util.Collection; 31 import java.util.Collections; 32 import java.util.Comparator; 33 import java.util.HashMap; 34 import java.util.Iterator; 35 import java.util.List; 36 import java.util.Map; 37 import java.util.Set; 38 import java.util.SortedSet; 39 import java.util.TreeSet; 40 41 import javax.lang.model.element.Element; 42 import javax.lang.model.element.TypeElement; 43 import javax.lang.model.type.TypeMirror; 44 45 import jdk.javadoc.doclet.DocletEnvironment; 46 import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; 47 import jdk.javadoc.internal.doclets.toolkit.Messages; 48 49 /** 50 * Build Class Hierarchy for all the Classes. This class builds the Class 51 * Tree and the Interface Tree separately. 52 * 53 * <p><b>This is NOT part of any supported API. 54 * If you write code that depends on this, you do so at your own risk. 55 * This code and its internal interfaces are subject to change or 56 * deletion without notice.</b> 57 * 58 * @see java.util.HashMap 59 * @see java.util.List 60 */ 61 public class ClassTree { 62 63 /** 64 * List of base classes. Used to get the mapped listing of sub-classes. 65 */ 66 private final SortedSet<TypeElement> baseClasses; 67 68 /** 69 * Mapping for each Class with their sub classes 70 */ 71 private final Map<TypeElement, SortedSet<TypeElement>> subClasses = new HashMap<>(); 72 73 /** 74 * List of base-interfaces. Contains set of all the interfaces who do not 75 * have super-interfaces. Can be used to get the mapped listing of 76 * sub-interfaces. 77 */ 78 private final SortedSet<TypeElement> baseInterfaces; 79 80 /** 81 * Mapping for each Interface with their SubInterfaces 82 */ 83 private final Map<TypeElement, SortedSet<TypeElement>> subInterfaces = new HashMap<>(); 84 85 private final SortedSet<TypeElement> baseEnums; 86 private final Map<TypeElement, SortedSet<TypeElement>> subEnums = new HashMap<>(); 87 88 private final SortedSet<TypeElement> baseAnnotationTypes; 89 private final Map<TypeElement, SortedSet<TypeElement>> subAnnotationTypes = new HashMap<>(); 90 91 /** 92 * Mapping for each Interface with classes who implement it. 93 */ 94 private final Map<TypeElement, SortedSet<TypeElement>> implementingClasses = new HashMap<>(); 95 96 private final BaseConfiguration configuration; 97 private final Utils utils; 98 private final Comparator<Element> comparator; 99 100 /** 101 * Constructor. Build the Tree using the Root of this Javadoc run. 102 * 103 * @param configuration the configuration of the doclet. 104 * @param noDeprecated Don't add deprecated classes in the class tree, if 105 * true. 106 */ 107 public ClassTree(BaseConfiguration configuration, boolean noDeprecated) { 108 this.configuration = configuration; 109 this.utils = configuration.utils; 110 111 Messages messages = configuration.getMessages(); 112 messages.notice("doclet.Building_Tree"); 113 114 comparator = utils.makeClassUseComparator(); 115 baseAnnotationTypes = new TreeSet<>(comparator); 116 baseEnums = new TreeSet<>(comparator); 117 baseClasses = new TreeSet<>(comparator); 118 baseInterfaces = new TreeSet<>(comparator); 119 buildTree(configuration.getIncludedTypeElements()); 120 } 121 122 /** 123 * Constructor. Build the Tree using the Root of this Javadoc run. 124 * 125 * @param docEnv the DocletEnvironment. 126 * @param configuration The current configuration of the doclet. 127 */ 128 public ClassTree(DocletEnvironment docEnv, BaseConfiguration configuration) { 129 this.configuration = configuration; 130 this.utils = configuration.utils; 131 comparator = utils.makeClassUseComparator(); 132 baseAnnotationTypes = new TreeSet<>(comparator); 133 baseEnums = new TreeSet<>(comparator); 134 baseClasses = new TreeSet<>(comparator); 135 baseInterfaces = new TreeSet<>(comparator); 136 buildTree(configuration.getIncludedTypeElements()); 137 } 138 139 /** 140 * Constructor. Build the tree for the given array of classes. 141 * 142 * @param classesSet a set of classes 143 * @param configuration The current configuration of the doclet. 144 */ 145 public ClassTree(SortedSet<TypeElement>classesSet, BaseConfiguration configuration) { 146 this.configuration = configuration; 147 this.utils = configuration.utils; 148 comparator = utils.makeClassUseComparator(); 149 baseAnnotationTypes = new TreeSet<>(comparator); 150 baseEnums = new TreeSet<>(comparator); 151 baseClasses = new TreeSet<>(comparator); 152 baseInterfaces = new TreeSet<>(comparator); 153 buildTree(classesSet); 154 } 155 156 /** 157 * Generate mapping for the sub-classes for every class in this run. 158 * Return the sub-class set for java.lang.Object which will be having 159 * sub-class listing for itself and also for each sub-class itself will 160 * have their own sub-class lists. 161 * 162 * @param classes all the classes in this run. 163 */ 164 private void buildTree(Iterable<TypeElement> classes) { 165 for (TypeElement aClass : classes) { 166 // In the tree page (e.g overview-tree.html) do not include 167 // information of classes which are deprecated or are a part of a 168 // deprecated package. 169 if (configuration.getOptions().noDeprecated && 170 (utils.isDeprecated(aClass) || 171 utils.isDeprecated(utils.containingPackage(aClass)))) { 172 continue; 173 } 174 175 if (utils.hasHiddenTag(aClass)) { 176 continue; 177 } 178 179 if (utils.isEnum(aClass)) { 180 processType(aClass, configuration, baseEnums, subEnums); 181 } else if (utils.isClass(aClass)) { 182 processType(aClass, configuration, baseClasses, subClasses); 183 } else if (utils.isInterface(aClass)) { 184 processInterface(aClass); 185 } else if (utils.isAnnotationType(aClass)) { 186 processType(aClass, configuration, baseAnnotationTypes, 187 subAnnotationTypes); 188 } 189 } 190 } 191 192 /** 193 * For the class passed map it to its own sub-class listing. 194 * For the Class passed, get the super class, 195 * if superclass is non null, (it is not "java.lang.Object") 196 * get the "value" from the hashmap for this key Class 197 * if entry not found create one and get that. 198 * add this Class as a sub class in the set 199 * Recurse till hits java.lang.Object Null SuperClass. 200 * 201 * @param typeElement for which sub class mapping is to be generated. 202 * @param configuration the current configuration of the doclet. 203 */ 204 private void processType(TypeElement typeElement, BaseConfiguration configuration, 205 Collection<TypeElement> bases, Map<TypeElement, SortedSet<TypeElement>> subs) { 206 TypeElement superclass = utils.getFirstVisibleSuperClassAsTypeElement(typeElement); 207 if (superclass != null) { 208 if (!add(subs, superclass, typeElement)) { 209 return; 210 } else { 211 processType(superclass, configuration, bases, subs); 212 } 213 } else { // typeElement is java.lang.Object, add it once to the set 214 if (!bases.contains(typeElement)) { 215 bases.add(typeElement); 216 } 217 } 218 Set<TypeMirror> intfacs = utils.getAllInterfaces(typeElement); 219 for (TypeMirror intfac : intfacs) { 220 add(implementingClasses, utils.asTypeElement(intfac), typeElement); 221 } 222 } 223 224 /** 225 * For the interface passed get the interfaces which it extends, and then 226 * put this interface in the sub-interface set of those interfaces. Do it 227 * recursively. If a interface doesn't have super-interface just attach 228 * that interface in the set of all the baseInterfaces. 229 * 230 * @param typeElement Interface under consideration. 231 */ 232 private void processInterface(TypeElement typeElement) { 233 List<? extends TypeMirror> intfacs = typeElement.getInterfaces(); 234 if (!intfacs.isEmpty()) { 235 for (TypeMirror intfac : intfacs) { 236 if (!add(subInterfaces, utils.asTypeElement(intfac), typeElement)) { 237 return; 238 } else { 239 processInterface(utils.asTypeElement(intfac)); // Recurse 240 } 241 } 242 } else { 243 // we need to add all the interfaces who do not have 244 // super-interfaces to baseInterfaces set to traverse them 245 if (!baseInterfaces.contains(typeElement)) { 246 baseInterfaces.add(typeElement); 247 } 248 } 249 } 250 251 /** 252 * Adjust the Class Tree. Add the class interface in to it's super classes 253 * or super interface's sub-interface set. 254 * 255 * @param map the entire map. 256 * @param superclass java.lang.Object or the super-interface. 257 * @param typeElement sub-interface to be mapped. 258 * @returns boolean true if class added, false if class already processed. 259 */ 260 private boolean add(Map<TypeElement, SortedSet<TypeElement>> map, TypeElement superclass, TypeElement typeElement) { 261 SortedSet<TypeElement> sset = map.computeIfAbsent(superclass, s -> new TreeSet<>(comparator)); 262 if (sset.contains(typeElement)) { 263 return false; 264 } else { 265 sset.add(typeElement); 266 } 267 return true; 268 } 269 270 /** 271 * From the map return the set of sub-classes or sub-interfaces. If set 272 * is null create a new one and return it. 273 * 274 * @param map The entire map. 275 * @param typeElement class for which the sub-class set is requested. 276 * @returns a list of sub classes. 277 */ 278 private SortedSet<TypeElement> get(Map<TypeElement, SortedSet<TypeElement>> map, TypeElement typeElement) { 279 return map.computeIfAbsent(typeElement, t -> new TreeSet<>(comparator)); 280 } 281 282 /** 283 * Return the sub-class set for the class passed. 284 * 285 * @param typeElement class whose sub-class set is required. 286 */ 287 public SortedSet<TypeElement> subClasses(TypeElement typeElement) { 288 return get(subClasses, typeElement); 289 } 290 291 /** 292 * Return the sub-interface set for the interface passed. 293 * 294 * @param typeElement interface whose sub-interface set is required. 295 */ 296 public SortedSet<TypeElement> subInterfaces(TypeElement typeElement) { 297 return get(subInterfaces, typeElement); 298 } 299 300 /** 301 * Return the set of classes which implement the interface passed. 302 * 303 * @param typeElement interface whose implementing-classes set is required. 304 */ 305 public SortedSet<TypeElement> implementingClasses(TypeElement typeElement) { 306 SortedSet<TypeElement> result = get(implementingClasses, typeElement); 307 SortedSet<TypeElement> intfcs = allSubClasses(typeElement, false); 308 309 // If class x implements a subinterface of typeElement, then it follows 310 // that class x implements typeElement. 311 Iterator<TypeElement> subInterfacesIter = intfcs.iterator(); 312 while (subInterfacesIter.hasNext()) { 313 Iterator<TypeElement> implementingClassesIter 314 = implementingClasses(subInterfacesIter.next()).iterator(); 315 while (implementingClassesIter.hasNext()) { 316 TypeElement c = implementingClassesIter.next(); 317 if (!result.contains(c)) { 318 result.add(c); 319 } 320 } 321 } 322 return result; 323 } 324 325 /** 326 * Return the sub-class/interface set for the class/interface passed. 327 * 328 * @param typeElement class/interface whose sub-class/interface set is required. 329 * @param isEnum true if the subClasses should be forced to come from the 330 * enum tree. 331 */ 332 public SortedSet<TypeElement> directSubClasses(TypeElement typeElement, boolean isEnum) { 333 return directSubClasses0(typeElement, isEnum); 334 } 335 336 private SortedSet<TypeElement> directSubClasses0(TypeElement typeElement, boolean isEnum) { 337 if (isEnum) { 338 return get(subEnums, typeElement); 339 } else if (utils.isAnnotationType(typeElement)) { 340 return get(subAnnotationTypes, typeElement); 341 } else if (utils.isInterface(typeElement)) { 342 return get(subInterfaces, typeElement); 343 } else if (utils.isClass(typeElement)) { 344 return get(subClasses, typeElement); 345 } else { 346 return Collections.emptySortedSet(); 347 } 348 } 349 350 /** 351 * Return a set of all direct or indirect, sub-classes and subInterfaces 352 * of the TypeElement argument. 353 * 354 * @param typeElement TypeElement whose sub-classes or sub-interfaces are requested. 355 * @param isEnum true if the subClasses should be forced to come from the 356 * enum tree. 357 */ 358 public SortedSet<TypeElement> allSubClasses(TypeElement typeElement, boolean isEnum) { 359 // new entries added to the set are searched as well, this is 360 // really a work queue. 361 List<TypeElement> list = new ArrayList<>(directSubClasses(typeElement, isEnum)); 362 for (int i = 0; i < list.size(); i++) { 363 TypeElement te = list.get(i); 364 SortedSet<TypeElement> tset = directSubClasses0(te, isEnum); 365 for (TypeElement tte : tset) { 366 if (!list.contains(tte)) { 367 list.add(tte); 368 } 369 } 370 } 371 SortedSet<TypeElement> out = new TreeSet<>(comparator); 372 out.addAll(list); 373 return out; 374 } 375 376 /** 377 * Return a set of base classes. This will have only one element namely 378 * the TypeElement for java.lang.Object, since this is the base class for all 379 * classes. 380 */ 381 public SortedSet<TypeElement> baseClasses() { 382 return baseClasses; 383 } 384 385 /** 386 * Return the set of base interfaces. This is the set of interfaces 387 * which do not have super-interface. 388 */ 389 public SortedSet<TypeElement> baseInterfaces() { 390 return baseInterfaces; 391 } 392 393 /** 394 * Return the set of base enums. This is the set of enums 395 * which do not have super-enums. 396 */ 397 public SortedSet<TypeElement> baseEnums() { 398 return baseEnums; 399 } 400 401 /** 402 * Return the set of base annotation types. This is the set 403 * of annotation types which do not have super-annotation types. 404 */ 405 public SortedSet<TypeElement> baseAnnotationTypes() { 406 return baseAnnotationTypes; 407 } 408 }