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