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