001/*
002 * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025package org.jdrupes.mdoclet.internal.doclets.toolkit.util;
026
027import static org.jdrupes.mdoclet.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*;
028
029import java.util.*;
030
031import javax.lang.model.element.AnnotationMirror;
032import javax.lang.model.element.Element;
033import javax.lang.model.element.ExecutableElement;
034import javax.lang.model.element.PackageElement;
035import javax.lang.model.element.TypeElement;
036import javax.lang.model.element.TypeParameterElement;
037import javax.lang.model.element.VariableElement;
038import javax.lang.model.type.ArrayType;
039import javax.lang.model.type.DeclaredType;
040import javax.lang.model.type.ErrorType;
041import javax.lang.model.type.TypeMirror;
042import javax.lang.model.type.TypeVariable;
043import javax.lang.model.type.WildcardType;
044import javax.lang.model.util.ElementFilter;
045import javax.lang.model.util.Elements;
046import javax.lang.model.util.SimpleElementVisitor14;
047import javax.lang.model.util.SimpleTypeVisitor9;
048import javax.lang.model.util.Types;
049
050import org.jdrupes.mdoclet.internal.doclets.toolkit.BaseConfiguration;
051
052import jdk.javadoc.doclet.DocletEnvironment;
053
054/**
055 * Map all class uses for a given class.
056 *
057 * <p>
058 * <b>This is NOT part of any supported API. If you write code that depends on this, you do so at
059 * your own risk. This code and its internal interfaces are subject to change or deletion without
060 * notice.</b>
061 */
062public class ClassUseMapper {
063
064    private final ClassTree classTree;
065
066    /**
067     * Mapping of TypeElements to set of PackageElements used by that class.
068     */
069    public final Map<TypeElement, Set<PackageElement>> classToPackage;
070
071    /**
072     * Mapping of TypeElements representing annotations to a set of PackageElements that use the annotation.
073     */
074    public final Map<TypeElement,
075            List<PackageElement>> classToPackageAnnotations = new HashMap<>();
076
077    /**
078     * Mapping of TypeElements to a set of TypeElements used by that class.
079     */
080    public final Map<TypeElement, Set<TypeElement>> classToClass
081        = new HashMap<>();
082
083    /**
084     * Mapping of TypeElements to a list of TypeElements which are direct or indirect subClasses of
085     * that class.
086     */
087    public final Map<TypeElement, List<TypeElement>> classToSubclass
088        = new HashMap<>();
089
090    /**
091     * Mapping of TypeElements to list of TypeElements which are direct or indirect subInterfaces of
092     * that interface.
093     */
094    public final Map<TypeElement, List<TypeElement>> classToSubinterface
095        = new HashMap<>();
096
097    /**
098     * Mapping of TypeElements to list of TypeElements which implement this interface.
099     */
100    public Map<TypeElement, List<TypeElement>> classToImplementingClass
101        = new HashMap<>();
102
103    /**
104     * Mapping of TypeElements to list of VariableElements declared as that class.
105     */
106    public final Map<TypeElement, List<VariableElement>> classToField
107        = new HashMap<>();
108
109    /**
110     * Mapping of TypeElements to list of ExecutableElements returning that class.
111     */
112    public final Map<TypeElement, List<ExecutableElement>> classToMethodReturn
113        = new HashMap<>();
114
115    /**
116     * Mapping of TypeElements to list of ExecutableElements having that class as an arg.
117     */
118    public final Map<TypeElement, List<ExecutableElement>> classToMethodArgs
119        = new HashMap<>();
120
121    /**
122     * Mapping of TypeElements to list of ExecutableElements which throws that class.
123     */
124    public final Map<TypeElement, List<ExecutableElement>> classToMethodThrows
125        = new HashMap<>();
126
127    /**
128     * Mapping of TypeElements to list of ExecutableElements (constructors) having that
129     * class as an arg.
130     */
131    public final Map<TypeElement,
132            List<ExecutableElement>> classToConstructorArgs = new HashMap<>();
133
134    /**
135     * Mapping of TypeElements to list of constructors which throws that class.
136     */
137    public final Map<TypeElement,
138            List<ExecutableElement>> classToConstructorThrows = new HashMap<>();
139
140    /**
141     * The mapping of TypeElements representing annotations to constructors that use them.
142     */
143    public final Map<TypeElement,
144            List<ExecutableElement>> classToConstructorAnnotations
145                = new HashMap<>();
146
147    /**
148     * The mapping of TypeElement representing annotations to constructor parameters that use them.
149     */
150    public final Map<TypeElement,
151            List<ExecutableElement>> classToConstructorParamAnnotation
152                = new HashMap<>();
153
154    /**
155     * The mapping of TypeElements to constructor arguments that use them as type parameters.
156     */
157    public final Map<TypeElement,
158            List<ExecutableElement>> classToConstructorArgTypeParam
159                = new HashMap<>();
160
161    /**
162     * The mapping of TypeElement to TypeElement that use them as type parameters.
163     */
164    public final Map<TypeElement, List<TypeElement>> classToClassTypeParam
165        = new HashMap<>();
166
167    /**
168     * The mapping of TypeElement representing annotation to TypeElements that use them.
169     */
170    public final Map<TypeElement, List<TypeElement>> classToClassAnnotations
171        = new HashMap<>();
172
173    /**
174     * The mapping of TypeElement to methods that use them as type parameters.
175     */
176    public final Map<TypeElement,
177            List<ExecutableElement>> classToMethodTypeParam = new HashMap<>();
178
179    /**
180     * The mapping of TypeElement to method arguments that use them as type parameters.
181     */
182    public final Map<TypeElement,
183            List<ExecutableElement>> classToMethodArgTypeParam
184                = new HashMap<>();
185
186    /**
187     * The mapping of TypeElement representing annotation to methods that use them.
188     */
189    public final Map<TypeElement,
190            List<ExecutableElement>> classToMethodAnnotations = new HashMap<>();
191
192    /**
193     * The mapping of TypeElements to methods that have return type with type parameters
194     * of that class.
195     */
196    public final Map<TypeElement,
197            List<ExecutableElement>> classToMethodReturnTypeParam
198                = new HashMap<>();
199
200    /**
201     * The mapping of TypeElements representing annotations to method parameters that use them.
202     */
203    public final Map<TypeElement,
204            List<ExecutableElement>> classToMethodParamAnnotation
205                = new HashMap<>();
206
207    /**
208     * The mapping of TypeElements to fields that use them as type parameters.
209     */
210    public final Map<TypeElement, List<VariableElement>> classToFieldTypeParam
211        = new HashMap<>();
212
213    /**
214     * The mapping of TypeElements representing annotation to fields that use them.
215     */
216    public final Map<TypeElement, List<VariableElement>> annotationToField
217        = new HashMap<>();
218
219    private final DocletEnvironment docEnv;
220    private final Elements elementUtils;
221    private final Types typeUtils;
222    private final Utils utils;
223    private final Comparators comparators;
224
225    public ClassUseMapper(BaseConfiguration configuration,
226            ClassTree classTree) {
227        docEnv = configuration.docEnv;
228        elementUtils = docEnv.getElementUtils();
229        typeUtils = docEnv.getTypeUtils();
230        utils = configuration.utils;
231        comparators = utils.comparators;
232        this.classTree = classTree;
233        classToPackage = new TreeMap<>(comparators.makeClassUseComparator());
234        // Map subclassing, subinterfacing implementing, ...
235        for (TypeElement te : classTree.classes().roots()) {
236            subclasses(te);
237        }
238        for (TypeElement intfc : classTree.interfaces().roots()) {
239            // does subinterfacing as a side-effect
240            implementingClasses(intfc);
241        }
242        // Map methods, fields, constructors using a class.
243        Set<TypeElement> classes = configuration.getIncludedTypeElements();
244        for (TypeElement aClass : classes) {
245            PackageElement pkg = elementUtils.getPackageOf(aClass);
246            mapAnnotations(classToPackageAnnotations, pkg, pkg);
247            mapTypeParameters(classToClassTypeParam, aClass, aClass);
248            mapAnnotations(classToClassAnnotations, aClass, aClass);
249            VisibleMemberTable vmt
250                = configuration.getVisibleMemberTable(aClass);
251
252            List<VariableElement> fields
253                = ElementFilter.fieldsIn(vmt.getVisibleMembers(FIELDS));
254            for (VariableElement fd : fields) {
255                mapTypeParameters(classToFieldTypeParam, fd, fd);
256                mapAnnotations(annotationToField, fd, fd);
257                var stv = new SimpleTypeVisitor9<Void, VariableElement>() {
258                    @Override
259                    public Void visitArray(ArrayType t, VariableElement p) {
260                        return visit(t.getComponentType(), p);
261                    }
262
263                    @Override
264                    public Void visitDeclared(DeclaredType t,
265                            VariableElement p) {
266                        add(classToField, (TypeElement) t.asElement(), p);
267                        return null;
268                    }
269
270                    @Override
271                    public Void visitTypeVariable(TypeVariable t,
272                            VariableElement p) {
273                        return visit(typeUtils.erasure(t), p);
274                    }
275                };
276                stv.visit(fd.asType(), fd);
277            }
278
279            List<ExecutableElement> ctors
280                = ElementFilter.constructorsIn(vmt.getMembers(CONSTRUCTORS));
281            for (ExecutableElement ctor : ctors) {
282                mapAnnotations(classToConstructorAnnotations, ctor, ctor);
283                mapExecutable(ctor);
284            }
285
286            List<ExecutableElement> methods
287                = ElementFilter.methodsIn(vmt.getMembers(METHODS));
288
289            for (ExecutableElement method : methods) {
290                mapExecutable(method);
291                mapTypeParameters(classToMethodTypeParam, method, method);
292                mapAnnotations(classToMethodAnnotations, method, method);
293                var stv = new SimpleTypeVisitor9<Void, ExecutableElement>() {
294                    @Override
295                    public Void visitArray(ArrayType t, ExecutableElement p) {
296                        TypeMirror componentType = t.getComponentType();
297                        return visit(utils.isTypeVariable(componentType)
298                            ? typeUtils.erasure(componentType)
299                            : componentType, p);
300                    }
301
302                    @Override
303                    public Void visitDeclared(DeclaredType t,
304                            ExecutableElement p) {
305                        mapTypeParameters(classToMethodReturnTypeParam, t, p);
306                        add(classToMethodReturn, (TypeElement) t.asElement(),
307                            p);
308                        return null;
309                    }
310
311                    @Override
312                    protected Void defaultAction(TypeMirror e,
313                            ExecutableElement p) {
314                        return null;
315                    }
316                };
317                stv.visit(method.getReturnType(), method);
318            }
319        }
320    }
321
322    /**
323     * Return all subClasses of a class AND fill-in classToSubclass map.
324     */
325    private Collection<TypeElement> subclasses(TypeElement te) {
326        Collection<TypeElement> ret = classToSubclass.get(te);
327        if (ret == null) {
328            ret = new TreeSet<>(comparators.makeClassUseComparator());
329            Set<TypeElement> subs = classTree.subClasses(te);
330            if (subs != null) {
331                ret.addAll(subs);
332                for (TypeElement sub : subs) {
333                    ret.addAll(subclasses(sub));
334                }
335            }
336            addAll(classToSubclass, te, ret);
337        }
338        return ret;
339    }
340
341    /**
342     * Return all subInterfaces of an interface AND fill-in classToSubinterface map.
343     */
344    private Collection<TypeElement> subinterfaces(TypeElement te) {
345        Collection<TypeElement> ret = classToSubinterface.get(te);
346        if (ret == null) {
347            ret = new TreeSet<>(comparators.makeClassUseComparator());
348            Set<TypeElement> subs = classTree.subInterfaces(te);
349            if (subs != null) {
350                ret.addAll(subs);
351                for (TypeElement sub : subs) {
352                    ret.addAll(subinterfaces(sub));
353                }
354            }
355            addAll(classToSubinterface, te, ret);
356        }
357        return ret;
358    }
359
360    /**
361     * Return all implementing classes of an interface (including all subClasses of implementing
362     * classes and all classes implementing subInterfaces) AND fill-in both classToImplementingClass
363     * and classToSubinterface maps.
364     */
365    private Collection<TypeElement> implementingClasses(TypeElement te) {
366        Collection<TypeElement> ret = classToImplementingClass.get(te);
367        if (ret == null) {
368            ret = new TreeSet<>(comparators.makeClassUseComparator());
369            Set<TypeElement> impl = classTree.implementingClasses(te);
370            if (impl != null) {
371                ret.addAll(impl);
372                for (TypeElement anImpl : impl) {
373                    ret.addAll(subclasses(anImpl));
374                }
375            }
376            for (TypeElement intfc : subinterfaces(te)) {
377                ret.addAll(implementingClasses(intfc));
378            }
379            addAll(classToImplementingClass, te, ret);
380        }
381        return ret;
382    }
383
384    /**
385     * Determine classes used by a method or constructor, so they can be inverse mapped.
386     */
387    private void mapExecutable(ExecutableElement ee) {
388        final boolean isConstructor = utils.isConstructor(ee);
389        Set<TypeMirror> classArgs
390            = new TreeSet<>(comparators.makeTypeMirrorClassUseComparator());
391        for (VariableElement param : ee.getParameters()) {
392            TypeMirror pType = param.asType();
393            // primitives don't get mapped and type variables are mapped
394            // elsewhere
395            if (!pType.getKind().isPrimitive()
396                && !utils.isTypeVariable(pType)) {
397                // no duplicates please
398                if (classArgs.add(pType)) {
399                    new SimpleTypeVisitor9<Void, ExecutableElement>() {
400                        @Override
401                        public Void visitArray(ArrayType t,
402                                ExecutableElement p) {
403                            return visit(t.getComponentType(), p);
404                        }
405
406                        @Override
407                        public Void visitDeclared(DeclaredType t,
408                                ExecutableElement p) {
409                            add(isConstructor
410                                ? classToConstructorArgs
411                                : classToMethodArgs,
412                                (TypeElement) t.asElement(), p);
413                            return null;
414                        }
415
416                        @Override
417                        public Void visitTypeVariable(TypeVariable t,
418                                ExecutableElement p) {
419                            visit(typeUtils.erasure(t), p);
420                            return null;
421                        }
422                    }.visit(pType, ee);
423                    mapTypeParameters(isConstructor
424                        ? classToConstructorArgTypeParam
425                        : classToMethodArgTypeParam,
426                        pType, ee);
427                }
428            }
429            mapAnnotations(isConstructor
430                ? classToConstructorParamAnnotation
431                : classToMethodParamAnnotation,
432                param, ee);
433
434        }
435        for (TypeMirror anException : ee.getThrownTypes()) {
436            var stv = new SimpleTypeVisitor9<Void, ExecutableElement>() {
437
438                @Override
439                public Void visitArray(ArrayType t, ExecutableElement p) {
440                    super.visit(t.getComponentType(), p);
441                    return null;
442                }
443
444                @Override
445                public Void visitDeclared(DeclaredType t, ExecutableElement p) {
446                    add(isConstructor ? classToConstructorThrows
447                        : classToMethodThrows,
448                        (TypeElement) t.asElement(), p);
449                    return null;
450                }
451
452                @Override
453                public Void visitError(ErrorType t, ExecutableElement p) {
454                    add(isConstructor ? classToConstructorThrows
455                        : classToMethodThrows,
456                        (TypeElement) t.asElement(), p);
457                    return null;
458                }
459
460                @Override
461                protected Void defaultAction(TypeMirror e,
462                        ExecutableElement p) {
463                    throw new AssertionError("this should not happen");
464                }
465            };
466
467            stv.visit(typeUtils.erasure(anException), ee);
468        }
469    }
470
471    private <T> List<T> refList(Map<TypeElement, List<T>> map,
472            TypeElement element) {
473        return map.computeIfAbsent(element, k -> new ArrayList<>());
474    }
475
476    private Set<PackageElement> packageSet(TypeElement te) {
477        Set<PackageElement> pkgSet = classToPackage.get(te);
478        if (pkgSet == null) {
479            pkgSet = new TreeSet<>(comparators.makeClassUseComparator());
480            classToPackage.put(te, pkgSet);
481        }
482        return pkgSet;
483    }
484
485    private Set<TypeElement> classSet(TypeElement te) {
486        Set<TypeElement> clsSet = classToClass.get(te);
487        if (clsSet == null) {
488            clsSet = new TreeSet<>(comparators.makeClassUseComparator());
489            classToClass.put(te, clsSet);
490        }
491        return clsSet;
492    }
493
494    private <T extends Element> void add(Map<TypeElement, List<T>> map,
495            TypeElement te, T ref) {
496        // add to specified map
497        refList(map, te).add(ref);
498        // add ref's package to package map and class map
499        packageSet(te).add(elementUtils.getPackageOf(ref));
500        TypeElement entry = (utils.isField(ref)
501            || utils.isConstructor(ref)
502            || utils.isMethod(ref))
503                ? (TypeElement) ref.getEnclosingElement()
504                : (TypeElement) ref;
505        classSet(te).add(entry);
506    }
507
508    private void addAll(Map<TypeElement, List<TypeElement>> map, TypeElement te,
509            Collection<TypeElement> refs) {
510        if (refs == null) {
511            return;
512        }
513        // add to specified map
514        refList(map, te).addAll(refs);
515
516        Set<PackageElement> pkgSet = packageSet(te);
517        Set<TypeElement> clsSet = classSet(te);
518        // add ref's package to package map and class map
519        for (TypeElement cls : refs) {
520            pkgSet.add(utils.containingPackage(cls));
521            clsSet.add(cls);
522        }
523    }
524
525    /**
526     * Map the TypeElements to the members that use them as type parameters.
527     *
528     * @param map the map the insert the information into.
529     * @param element the te whose type parameters are being checked.
530     * @param holder the holder that owns the type parameters.
531     */
532    private <T extends Element> void mapTypeParameters(
533            final Map<TypeElement, List<T>> map,
534            Element element, final T holder) {
535
536        var elementVisitor = new SimpleElementVisitor14<Void, Void>() {
537
538            private void addParameters(TypeParameterElement e) {
539                for (TypeMirror type : utils.getBounds(e)) {
540                    addTypeParameterToMap(map, type, holder);
541                }
542            }
543
544            @Override
545            public Void visitType(TypeElement e, Void p) {
546                for (TypeParameterElement param : e.getTypeParameters()) {
547                    addParameters(param);
548                }
549                return null;
550            }
551
552            @Override
553            public Void visitExecutable(ExecutableElement e, Void p) {
554                for (TypeParameterElement param : e.getTypeParameters()) {
555                    addParameters(param);
556                }
557                return null;
558            }
559
560            @Override
561            protected Void defaultAction(Element e, Void p) {
562                mapTypeParameters(map, e.asType(), holder);
563                return null;
564            }
565
566            @Override
567            public Void visitTypeParameter(TypeParameterElement e, Void p) {
568                addParameters(e);
569                return null;
570            }
571        };
572        elementVisitor.visit(element);
573    }
574
575    private <T extends Element> void mapTypeParameters(
576            final Map<TypeElement, List<T>> map,
577            TypeMirror aType, final T holder) {
578
579        var tv = new SimpleTypeVisitor9<Void, Void>() {
580
581            @Override
582            public Void visitWildcard(WildcardType t, Void p) {
583                TypeMirror bound = t.getExtendsBound();
584                if (bound != null) {
585                    addTypeParameterToMap(map, bound, holder);
586                }
587                bound = t.getSuperBound();
588                if (bound != null) {
589                    addTypeParameterToMap(map, bound, holder);
590                }
591                return null;
592            }
593
594            // ParameterizedType
595            @Override
596            public Void visitDeclared(DeclaredType t, Void p) {
597                for (TypeMirror targ : t.getTypeArguments()) {
598                    addTypeParameterToMap(map, targ, holder);
599                }
600                return null;
601            }
602        };
603        tv.visit(aType);
604    }
605
606    /**
607     * Map the AnnotationType to the members that use them as type parameters.
608     *
609     * @param map the map the insert the information into.
610     * @param e whose type parameters are being checked.
611     * @param holder owning the type parameters.
612     */
613    private <T extends Element> void mapAnnotations(
614            final Map<TypeElement, List<T>> map,
615            Element e, final T holder) {
616        new SimpleElementVisitor14<Void, Void>() {
617
618            void addAnnotations(Element e) {
619                for (AnnotationMirror a : e.getAnnotationMirrors()) {
620                    add(map, (TypeElement) a.getAnnotationType().asElement(),
621                        holder);
622                }
623            }
624
625            @Override
626            public Void visitPackage(PackageElement e, Void p) {
627                for (AnnotationMirror a : e.getAnnotationMirrors()) {
628                    refList(map,
629                        (TypeElement) a.getAnnotationType().asElement())
630                            .add(holder);
631                }
632                return null;
633            }
634
635            @Override
636            protected Void defaultAction(Element e, Void p) {
637                addAnnotations(e);
638                return null;
639            }
640        }.visit(e);
641    }
642
643    private <T extends Element> void addTypeParameterToMap(
644            final Map<TypeElement, List<T>> map,
645            TypeMirror type, final T holder) {
646        new SimpleTypeVisitor9<Void, Void>() {
647
648            @Override
649            protected Void defaultAction(TypeMirror e, Void p) {
650                return super.defaultAction(e, p);
651            }
652
653            @Override
654            public Void visitDeclared(DeclaredType t, Void p) {
655                add(map, (TypeElement) t.asElement(), holder);
656                return null;
657            }
658
659        }.visit(type);
660        mapTypeParameters(map, type, holder);
661    }
662}