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