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