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 }