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