001/*
002 * Copyright (c) 2018, 2023, 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 */
025
026package org.jdrupes.mdoclet.internal.doclets.toolkit.util;
027
028import javax.lang.model.element.AnnotationMirror;
029import javax.lang.model.element.Element;
030import javax.lang.model.element.ElementKind;
031import javax.lang.model.element.ExecutableElement;
032import javax.lang.model.element.Modifier;
033import javax.lang.model.element.Name;
034import javax.lang.model.element.TypeElement;
035import javax.lang.model.element.VariableElement;
036import javax.lang.model.type.ArrayType;
037import javax.lang.model.type.DeclaredType;
038import javax.lang.model.type.ExecutableType;
039import javax.lang.model.type.TypeKind;
040import javax.lang.model.type.TypeMirror;
041import javax.lang.model.type.WildcardType;
042import javax.lang.model.util.Elements;
043import javax.lang.model.util.SimpleTypeVisitor14;
044
045import org.jdrupes.mdoclet.internal.doclets.toolkit.BaseConfiguration;
046import org.jdrupes.mdoclet.internal.doclets.toolkit.BaseOptions;
047import org.jdrupes.mdoclet.internal.doclets.toolkit.PropertyUtils;
048
049import java.lang.ref.SoftReference;
050import java.util.ArrayList;
051import java.util.Collection;
052import java.util.Collections;
053import java.util.EnumMap;
054import java.util.EnumSet;
055import java.util.HashMap;
056import java.util.HashSet;
057import java.util.LinkedHashMap;
058import java.util.LinkedHashSet;
059import java.util.List;
060import java.util.Map;
061import java.util.Objects;
062import java.util.Set;
063import java.util.function.Predicate;
064import java.util.stream.Collectors;
065import java.util.stream.Stream;
066
067/**
068 * This class computes the main data structure for the doclet's
069 * operations. Essentially, the implementation encapsulating the
070 * javax.lang.model's view of what can be documented about a
071 * type element's members.
072 * <p>
073 * The general operations are as follows:
074 * <p>
075 * Members: these are the members from j.l.m's view but
076 * are structured along the kinds of this class.
077 * <p>
078 * Extra Members: these are members enclosed in an undocumented
079 * package-private type element, and may not be linkable (or documented),
080 * however, the members of such a type element may be documented, as if
081 * declared in the subtype, only if the enclosing type is not being
082 * documented by a filter such as -public, -protected, etc.
083 * <p>
084 * Visible Members: these are the members that are "visible"
085 * and available and should be documented, in a type element.
086 * <p>
087 * The basic rule for computation: when considering a type element,
088 * besides its immediate direct types and interfaces, the computation
089 * should not expand to any other type in the inheritance hierarchy.
090 * <p>
091 * This table generates all the data structures it needs for each
092 * type, as its own view, and will present some form of this to the
093 * doclet as and when required to.
094 */
095public class VisibleMemberTable {
096
097    public enum Kind {
098        NESTED_CLASSES,
099        ENUM_CONSTANTS,
100        FIELDS,
101        CONSTRUCTORS,
102        METHODS,
103        ANNOTATION_TYPE_MEMBER,
104        ANNOTATION_TYPE_MEMBER_REQUIRED,
105        ANNOTATION_TYPE_MEMBER_OPTIONAL,
106        PROPERTIES;
107
108        private static final EnumSet<Kind> defaultSummarySet = EnumSet.of(
109            NESTED_CLASSES, FIELDS, CONSTRUCTORS, METHODS);
110        private static final EnumSet<Kind> enumSummarySet = EnumSet.of(
111            NESTED_CLASSES, ENUM_CONSTANTS, FIELDS, METHODS);
112        private static final EnumSet<Kind> annotationSummarySet = EnumSet.of(
113            FIELDS, ANNOTATION_TYPE_MEMBER_REQUIRED,
114            ANNOTATION_TYPE_MEMBER_OPTIONAL);
115        private static final EnumSet<Kind> defaultDetailSet = EnumSet.of(
116            FIELDS, CONSTRUCTORS, METHODS);
117        private static final EnumSet<Kind> enumDetailSet = EnumSet.of(
118            ENUM_CONSTANTS, FIELDS, METHODS);
119        private static final EnumSet<Kind> annotationDetailSet = EnumSet.of(
120            FIELDS, ANNOTATION_TYPE_MEMBER);
121
122        /**
123         * {@return the set of possible member kinds for the summaries section of a type element}
124         * @param kind the kind of type element being documented
125         */
126        public static Set<Kind> forSummariesOf(ElementKind kind) {
127            return switch (kind) {
128            case ANNOTATION_TYPE -> annotationSummarySet;
129            case ENUM -> enumSummarySet;
130            default -> defaultSummarySet;
131            };
132        }
133
134        /**
135         * {@return the set of possible member kinds for the details section of a type element}
136         * @param kind the kind of type element being documented
137         */
138        public static Set<Kind> forDetailsOf(ElementKind kind) {
139            return switch (kind) {
140            case ANNOTATION_TYPE -> annotationDetailSet;
141            case ENUM -> enumDetailSet;
142            default -> defaultDetailSet;
143            };
144        }
145    }
146
147    /** The class or interface described by this table. */
148    private final TypeElement te;
149    /**
150     * The superclass of {@link #te} or null if {@code te} is an
151     * interface or {@code java.lang.Object}.
152     */
153    private final TypeElement parent;
154
155    private final BaseConfiguration config;
156    private final BaseOptions options;
157    private final Utils utils;
158    private final VisibleMemberCache mcache;
159
160    /**
161     * Tables for direct and indirect superclasses.
162     *
163     * Tables for superclasses must be unique: no class can appear multiple
164     * times in the inheritance hierarchy for some other class.
165     */
166    private final Set<VisibleMemberTable> allSuperclasses;
167    /**
168     * Tables for direct and indirect superinterfaces.
169     *
170     * Tables for superinterfaces might not be unique (i.e. an interface
171     * may be added from different lineages).
172     */
173    private final List<VisibleMemberTable> allSuperinterfaces;
174    /**
175     * Tables for direct superclass and direct superinterfaces.
176     *
177     * The position of a table for the superclass in the list is unspecified.
178     */
179    private final Set<VisibleMemberTable> parents;
180
181    private Map<Kind, List<Element>> visibleMembers;
182    private final Map<ExecutableElement, PropertyMembers> propertyMap
183        = new HashMap<>();
184
185    // FIXME: Figure out why it is one-one and not one-to-many.
186    /**
187     * Maps a method m declared in {@code te} to a visible method m' in a
188     * {@code te}'s supertype such that m overrides m'.
189     */
190    private final Map<ExecutableElement, OverrideInfo> overriddenMethodTable
191        = new LinkedHashMap<>();
192
193    protected VisibleMemberTable(TypeElement typeElement,
194            BaseConfiguration configuration,
195            VisibleMemberCache mcache) {
196        config = configuration;
197        utils = configuration.utils;
198        options = configuration.getOptions();
199        te = typeElement;
200        parent = (TypeElement) utils.typeUtils.asElement(te.getSuperclass());
201        this.mcache = mcache;
202        allSuperclasses = new LinkedHashSet<>();
203        allSuperinterfaces = new ArrayList<>();
204        parents = new LinkedHashSet<>();
205    }
206
207    private void ensureInitialized() {
208        if (visibleMembers != null)
209            return;
210
211        visibleMembers = new EnumMap<>(Kind.class);
212        for (Kind kind : Kind.values()) {
213            visibleMembers.put(kind, new ArrayList<>());
214        }
215        computeParents();
216        computeVisibleMembers();
217    }
218
219    private Set<VisibleMemberTable> getAllSuperclasses() {
220        ensureInitialized();
221        return allSuperclasses;
222    }
223
224    private List<VisibleMemberTable> getAllSuperinterfaces() {
225        ensureInitialized();
226        return allSuperinterfaces;
227    }
228
229    /**
230     * Returns a list of all visible enclosed members of a type element,
231     * and inherited members.
232     * <p>
233     * Notes:
234     * a. The list may or may not contain simple overridden methods.
235     * A simple overridden method is one that overrides a super method
236     * with no specification changes as indicated by the existence of a
237     * sole {@code {@inheritDoc}} or devoid of any API comments.
238     * <p>
239     * b.The list may contain (extra) members, inherited by inaccessible
240     * supertypes, primarily package private types. These members are
241     * required to be documented in the subtype when the supertype is
242     * not documented.
243     *
244     * @param kind the member kind
245     * @return a list of all visible members
246     */
247    public List<Element> getAllVisibleMembers(Kind kind) {
248        ensureInitialized();
249        return visibleMembers.getOrDefault(kind, List.of());
250    }
251
252    /**
253     * Returns a list of visible enclosed members of a specified kind,
254     * filtered by the specified predicate.
255     * @param kind the member kind
256     * @param p the predicate used to filter the output
257     * @return a list of visible enclosed members
258     */
259    public List<Element> getVisibleMembers(Kind kind, Predicate<Element> p) {
260        ensureInitialized();
261        return visibleMembers.getOrDefault(kind, List.of()).stream()
262            .filter(p)
263            .toList();
264    }
265
266    /**
267     * Returns a list of all enclosed members including any extra members.
268     * Typically called by various builders.
269     *
270     * @param kind the member kind
271     * @return a list of visible enclosed members
272     */
273    public List<Element> getVisibleMembers(Kind kind) {
274        Predicate<Element> declaredAndLeafMembers = e -> {
275            TypeElement encl = utils.getEnclosingTypeElement(e);
276            return Objects.equals(encl, te)
277                || utils.isUndocumentedEnclosure(encl);
278        };
279        return getVisibleMembers(kind, declaredAndLeafMembers);
280    }
281
282    /**
283     * Returns a list of visible enclosed members of given kind,
284     * declared in this type element, and does not include
285     * any inherited members or extra members.
286     *
287     * @return a list of visible enclosed members in this type
288     */
289    public List<Element> getMembers(Kind kind) {
290        Predicate<Element> onlyLocallyDeclaredMembers
291            = e -> Objects.equals(utils.getEnclosingTypeElement(e), te);
292        return getVisibleMembers(kind, onlyLocallyDeclaredMembers);
293    }
294
295    /**
296     * Returns the method overridden by the provided method, or {@code null}.
297     *
298     * Sometimes it's not possible to link to a method that a link, linkplain,
299     * or see tag mentions. This is because the method is a "simple override"
300     * and, thus, has no useful documentation, or because the method is
301     * declared in a type that has package access and, thus, has no visible
302     * documentation.
303     *
304     * Call this method to determine if any of the above is the case. If the
305     * call returns a method element, link to that method element instead of
306     * the provided method.
307     *
308     * @param e the method to check
309     * @return the method found or {@code null}
310     */
311    public ExecutableElement getOverriddenMethod(ExecutableElement e) {
312        // TODO: consider possible ambiguities: multiple overridden methods
313        ensureInitialized();
314        assert !overriddenMethodTable.containsKey(null);
315        OverrideInfo found = overriddenMethodTable.get(e);
316        if (found != null
317            && (found.simpleOverride || utils
318                .isUndocumentedEnclosure(utils.getEnclosingTypeElement(e)))) {
319            return found.overriddenMethod;
320        }
321        return null;
322    }
323
324    /**
325     * {@return true if the specified method is NOT a simple override of some
326     * other method, otherwise false}
327     *
328     * @param e the method to check
329     */
330    private boolean isNotSimpleOverride(ExecutableElement e) {
331        ensureInitialized();
332
333        var info = overriddenMethodTable.get(e);
334        return info == null || !info.simpleOverride;
335    }
336
337    /**
338     * Returns a set of visible type elements in this type element's lineage.
339     * <p>
340     * This method returns the supertypes in the inheritance
341     * order C, B, A, j.l.O. The superinterfaces however are
342     * alpha sorted and appended to the resulting set.
343     *
344     * @return the set of visible classes in this map
345     */
346    public Set<TypeElement> getVisibleTypeElements() {
347        ensureInitialized();
348        Set<TypeElement> result = new LinkedHashSet<>();
349
350        // Add this type element first.
351        result.add(te);
352
353        // Add the superclasses.
354        allSuperclasses.stream()
355            .map(vmt -> vmt.te)
356            .forEach(result::add);
357
358        // ... and finally the sorted superinterfaces.
359        allSuperinterfaces.stream()
360            .map(vmt -> vmt.te)
361            .sorted(utils.comparators.makeGeneralPurposeComparator())
362            .forEach(result::add);
363
364        return result;
365    }
366
367    /**
368     * Returns true if this table contains visible members of
369     * any kind, including inherited members.
370     *
371     * @return true if visible members are present.
372     */
373    public boolean hasVisibleMembers() {
374        for (Kind kind : Kind.values()) {
375            if (hasVisibleMembers(kind))
376                return true;
377        }
378        return false;
379    }
380
381    /**
382     * Returns true if this table contains visible members of
383     * the specified kind, including inherited members.
384     *
385     * @return true if visible members are present.
386     */
387    public boolean hasVisibleMembers(Kind kind) {
388        ensureInitialized();
389        List<Element> elements = visibleMembers.get(kind);
390        return elements != null && !elements.isEmpty();
391    }
392
393    /**
394     * Returns the field for a property identified by any of the methods
395     * for that property.
396     *
397     * @param ee the method
398     * @return the field or null if absent
399     */
400    public VariableElement getPropertyField(ExecutableElement ee) {
401        ensureInitialized();
402        PropertyMembers pm = propertyMap.get(ee);
403        return pm == null ? null : pm.field;
404    }
405
406    /**
407     * Returns the getter method for a property identified by any of the methods
408     * for that property.
409     *
410     * @param ee the method
411     * @return the getter or null if absent
412     */
413    public ExecutableElement getPropertyGetter(ExecutableElement ee) {
414        ensureInitialized();
415        PropertyMembers pm = propertyMap.get(ee);
416        return pm == null ? null : pm.getter;
417    }
418
419    /**
420     * Returns the setter method for a property identified by any of the methods
421     * for that property.
422     *
423     * @param ee the method
424     * @return the setter or null if absent
425     */
426    public ExecutableElement getPropertySetter(ExecutableElement ee) {
427        ensureInitialized();
428        PropertyMembers pm = propertyMap.get(ee);
429        return pm == null ? null : pm.setter;
430    }
431
432    /**
433     * Returns the property method for a property identified by any of the methods
434     * for that property.
435     *
436     * @param ee the method
437     * @return the property method or null if absent
438     */
439    public ExecutableElement getPropertyMethod(ExecutableElement ee) {
440        ensureInitialized();
441        PropertyMembers pm = propertyMap.get(ee);
442        return pm == null ? null : pm.propertyMethod;
443    }
444
445    private void computeParents() {
446        // suppress parents of annotation interfaces
447        if (utils.isAnnotationInterface(te)) {
448            return;
449        }
450
451        for (TypeMirror intfType : te.getInterfaces()) {
452            TypeElement intfc = utils.asTypeElement(intfType);
453            if (intfc != null) {
454                VisibleMemberTable vmt = mcache.getVisibleMemberTable(intfc);
455                allSuperinterfaces.add(vmt);
456                boolean added = parents.add(vmt);
457                assert added; // no duplicates
458                allSuperinterfaces.addAll(vmt.getAllSuperinterfaces());
459            }
460        }
461
462        if (parent != null) {
463            VisibleMemberTable vmt = mcache.getVisibleMemberTable(parent);
464            allSuperclasses.add(vmt);
465            assert Collections.disjoint(allSuperclasses,
466                vmt.getAllSuperclasses()); // no duplicates
467            allSuperclasses.addAll(vmt.getAllSuperclasses());
468            // Add direct and indirect superinterfaces of a superclass.
469            allSuperinterfaces.addAll(vmt.getAllSuperinterfaces());
470            boolean added = parents.add(vmt);
471            assert added; // no duplicates
472        }
473    }
474
475    private void computeVisibleMembers() {
476
477        // Note: these have some baggage, and are redundant,
478        // allow this to be GC'ed.
479        LocalMemberTable lmt = new LocalMemberTable();
480
481        for (Kind k : Kind.values()) {
482            computeVisibleMembers(lmt, k);
483        }
484        // All members have been computed, compute properties.
485        computeVisibleProperties(lmt);
486    }
487
488    void computeVisibleMembers(LocalMemberTable lmt, Kind kind) {
489        switch (kind) {
490        case FIELDS:
491        case NESTED_CLASSES:
492            computeVisibleFieldsAndInnerClasses(lmt, kind);
493            return;
494
495        case METHODS:
496            computeVisibleMethods(lmt);
497            return;
498
499        // Defer properties related computations for later.
500        case PROPERTIES:
501            return;
502
503        default:
504            List<Element> list = lmt.getOrderedMembers(kind).stream()
505                .filter(this::mustDocument)
506                .toList();
507            visibleMembers.put(kind, list);
508            break;
509        }
510    }
511
512    private boolean mustDocument(Element e) {
513        // these checks are ordered in a particular way to avoid parsing unless
514        // absolutely necessary
515        return utils.shouldDocument(e) && !utils.hasHiddenTag(e);
516    }
517
518    private boolean allowInheritedMembers(Element e, Kind kind,
519            LocalMemberTable lmt) {
520        return isAccessible(e) && !isMemberHidden(e, kind, lmt);
521    }
522
523    private boolean isAccessible(Element e) {
524        if (utils.isPrivate(e))
525            return false;
526
527        if (utils.isPackagePrivate(e))
528            // Allowed iff this type-element is in the same package as the
529            // element
530            return utils.containingPackage(e)
531                .equals(utils.containingPackage(te));
532
533        return true;
534    }
535
536    private boolean isMemberHidden(Element inheritedMember, Kind kind,
537            LocalMemberTable lmt) {
538        Elements elementUtils = config.docEnv.getElementUtils();
539        switch (kind) {
540        default:
541            List<Element> list
542                = lmt.getMembers(inheritedMember.getSimpleName(), kind);
543            if (list.isEmpty())
544                return false;
545            return elementUtils.hides(list.get(0), inheritedMember);
546        case METHODS:
547        case CONSTRUCTORS: // Handled elsewhere.
548            throw new IllegalArgumentException("incorrect kind");
549        }
550    }
551
552    private void computeVisibleFieldsAndInnerClasses(LocalMemberTable lmt,
553            Kind kind) {
554        Set<Element> result = new LinkedHashSet<>();
555        for (VisibleMemberTable pvmt : parents) {
556            result.addAll(pvmt.getAllVisibleMembers(kind));
557        }
558
559        // Filter out members in the inherited list that are hidden
560        // by this type or should not be inherited at all.
561        Stream<Element> inheritedStream = result.stream()
562            .filter(e -> allowInheritedMembers(e, kind, lmt));
563
564        // Filter out elements that should not be documented
565        // Prefix local results first
566        List<Element> list = Stream
567            .concat(lmt.getOrderedMembers(kind).stream(), inheritedStream)
568            .filter(this::mustDocument)
569            .toList();
570
571        visibleMembers.put(kind, list);
572    }
573
574    // This method computes data structures related to method members
575    // of a class or an interface.
576    //
577    // TODO The computation is performed manually, by applying JLS rules.
578    // While jdk.javadoc does need custom and specialized data structures,
579    // this method does not feel DRY. It should be possible to improve
580    // it by delegating some, if not most, of the JLS wrestling to
581    // javax.lang.model. For example, while it cannot help us get the
582    // structures, such as overriddenMethodTable, javax.lang.model can
583    // help us get all method members of a class or an interface t by calling
584    // ElementFilter.methodsIn(Elements.getAllMembers(t)).
585    private void computeVisibleMethods(LocalMemberTable lmt) {
586        // parentMethods is a union of visible methods from all parents.
587        // It is used to figure out which methods this type should inherit.
588        // Inherited methods are those parent methods that remain after all
589        // methods that cannot be inherited are eliminated.
590        Set<Element> parentMethods = new LinkedHashSet<>();
591        for (var p : parents) {
592            // Lists of visible methods from different parents may share some
593            // methods. These are the methods that the parents inherited from
594            // their common ancestor.
595            //
596            // Such methods won't result in duplicates in parentMethods as we
597            // purposefully don't track duplicates.
598            // FIXME: add a test to assert the order (LinkedHashSet)
599            parentMethods.addAll(p.getAllVisibleMembers(Kind.METHODS));
600        }
601
602        // overriddenByTable maps an ancestor (grandparent and above) method
603        // to parent methods that override it:
604        //
605        // key
606        // : a method overridden by one or more parent methods
607        // value
608        // : a list of parent methods that override the key
609        Map<ExecutableElement, List<ExecutableElement>> overriddenByTable
610            = new HashMap<>();
611        for (var p : parents) {
612            // Merge the lineage overrides into local table
613            p.overriddenMethodTable.forEach((method, methodInfo) -> {
614                if (!methodInfo.simpleOverride) { // consider only real
615                                                  // overrides
616                    var list = overriddenByTable.computeIfAbsent(
617                        methodInfo.overriddenMethod,
618                        k -> new ArrayList<>());
619                    list.add(method);
620                }
621            });
622        }
623
624        // filter out methods that aren't inherited
625        //
626        // nb. This statement has side effects that can initialize
627        // members of the overriddenMethodTable field, so it must be
628        // evaluated eagerly with toList().
629        List<Element> inheritedMethods = parentMethods.stream()
630            .filter(e -> allowInheritedMethod((ExecutableElement) e,
631                overriddenByTable, lmt))
632            .toList();
633
634        // filter out "simple overrides" from local methods
635        Predicate<ExecutableElement> nonSimpleOverride = m -> {
636            OverrideInfo i = overriddenMethodTable.get(m);
637            return i == null || !i.simpleOverride;
638        };
639
640        Stream<ExecutableElement> localStream
641            = lmt.getOrderedMembers(Kind.METHODS)
642                .stream()
643                .map(m -> (ExecutableElement) m)
644                .filter(nonSimpleOverride);
645
646        // Merge the above list and stream, making sure the local methods
647        // precede the others
648        // Final filtration of elements
649        // FIXME add a test to assert the order or remove that part of the
650        // comment above ^
651        List<Element> list
652            = Stream.concat(localStream, inheritedMethods.stream())
653                .filter(this::mustDocument)
654                .toList();
655
656        visibleMembers.put(Kind.METHODS, list);
657
658        // copy over overridden tables from the lineage
659        for (VisibleMemberTable pvmt : parents) {
660            // a key in overriddenMethodTable is a method _declared_ in the
661            // respective parent;
662            // no two _different_ parents can share a declared method, by
663            // definition;
664            // if parents in the list are different (i.e. the list of parents
665            // doesn't contain duplicates),
666            // then no keys are equal and thus no replace happens
667            // if the list of parents contains duplicates, values for the equal
668            // keys are equal,
669            // so no harm if they are replaced in the map
670            assert putAllIsNonReplacing(overriddenMethodTable,
671                pvmt.overriddenMethodTable);
672            overriddenMethodTable.putAll(pvmt.overriddenMethodTable);
673        }
674    }
675
676    private static <K, V> boolean putAllIsNonReplacing(Map<K, V> dst,
677            Map<K, V> src) {
678        for (var e : src.entrySet()) {
679            if (dst.containsKey(e.getKey())
680                && !Objects.equals(dst.get(e.getKey()), e.getValue())) {
681                return false;
682            }
683        }
684        return true;
685    }
686
687    private boolean allowInheritedMethod(ExecutableElement inheritedMethod,
688            Map<ExecutableElement, List<ExecutableElement>> overriddenByTable,
689            LocalMemberTable lmt) {
690        // JLS 8.4.8: A class does not inherit private or static methods from
691        // its superinterface types.
692        //
693        // JLS 9.4.1: An interface does not inherit private or static methods
694        // from its superinterfaces.
695        //
696        // JLS 8.4.8: m is public, protected, or declared with package access
697        // in the same package as C
698        //
699        // JLS 9.4: A method in the body of an interface declaration may be
700        // declared public or private. If no access modifier is given, the
701        // method is implicitly public.
702        if (!isAccessible(inheritedMethod))
703            return false;
704
705        final boolean haveStatic = utils.isStatic(inheritedMethod);
706        final boolean inInterface = isDeclaredInInterface(inheritedMethod);
707
708        // Static interface methods are never inherited (JLS 8.4.8 and 9.1.3)
709        if (haveStatic && inInterface) {
710            return false;
711        }
712
713        // Multiple-Inheritance: remove the interface method that may have
714        // been overridden by another interface method in the hierarchy
715        //
716        // Note: The following approach is very simplistic and is compatible
717        // with old VMM. A future enhancement, may include a contention breaker,
718        // to correctly eliminate those methods that are merely definitions
719        // in favor of concrete overriding methods, for instance those that have
720        // API documentation and are not abstract OR default methods.
721        if (inInterface) {
722            List<ExecutableElement> list
723                = overriddenByTable.get(inheritedMethod);
724            if (list != null) {
725                boolean found = list.stream()
726                    .anyMatch(this::isDeclaredInInterface);
727                if (found)
728                    return false;
729            }
730        }
731
732        Elements elementUtils = config.docEnv.getElementUtils();
733
734        // Check the local methods in this type.
735        // List contains overloads and probably something else, but one match is
736        // enough, hence short-circuiting
737        List<Element> lMethods
738            = lmt.getMembers(inheritedMethod.getSimpleName(), Kind.METHODS);
739        for (Element le : lMethods) {
740            ExecutableElement lMethod = (ExecutableElement) le;
741            // Ignore private methods or those methods marked with
742            // a "hidden" tag. // FIXME I cannot see where @hidden is ignored
743            if (utils.isPrivate(lMethod))
744                continue;
745
746            // Remove methods that are "hidden", in JLS terms.
747            if (haveStatic && utils.isStatic(lMethod) &&
748                elementUtils.hides(lMethod, inheritedMethod)) {
749                return false;
750            }
751
752            // Check for overriding methods.
753            if (elementUtils.overrides(lMethod, inheritedMethod,
754                utils.getEnclosingTypeElement(lMethod))) {
755
756                assert utils.getEnclosingTypeElement(lMethod).equals(te);
757
758                // Disallow package-private super methods to leak in
759                TypeElement encl
760                    = utils.getEnclosingTypeElement(inheritedMethod);
761                if (utils.isUndocumentedEnclosure(encl)) {
762                    // FIXME
763                    // is simpleOverride=false here to force to be used because
764                    // it cannot be linked to, because package-private?
765                    overriddenMethodTable.computeIfAbsent(lMethod,
766                        l -> new OverrideInfo(inheritedMethod, false));
767                    return false;
768                }
769
770                // Even with --override-methods=summary we want to include
771                // details of
772                // overriding method if something noteworthy has been added or
773                // changed
774                // either in the local overriding method or an in-between
775                // overriding method
776                // (as evidenced by an entry in overriddenByTable).
777                boolean simpleOverride = utils.isSimpleOverride(lMethod)
778                    && !overridingSignatureChanged(lMethod, inheritedMethod)
779                    && !overriddenByTable.containsKey(inheritedMethod);
780                overriddenMethodTable.computeIfAbsent(lMethod,
781                    l -> new OverrideInfo(inheritedMethod, simpleOverride));
782                return simpleOverride;
783            }
784        }
785        return true;
786    }
787
788    private boolean isDeclaredInInterface(ExecutableElement e) {
789        return e.getEnclosingElement().getKind() == ElementKind.INTERFACE;
790    }
791
792    // Check whether the signature of an overriding method has any changes worth
793    // being documented compared to the overridden method.
794    private boolean overridingSignatureChanged(ExecutableElement method,
795            ExecutableElement overriddenMethod) {
796        // Covariant return type
797        TypeMirror overriddenMethodReturn = overriddenMethod.getReturnType();
798        TypeMirror methodReturn = method.getReturnType();
799        if (methodReturn.getKind() == TypeKind.DECLARED
800            && overriddenMethodReturn.getKind() == TypeKind.DECLARED
801            && !utils.typeUtils.isSameType(methodReturn, overriddenMethodReturn)
802            && utils.typeUtils.isSubtype(methodReturn,
803                overriddenMethodReturn)) {
804            return true;
805        }
806        // Modifiers changed from protected to public, non-final to final, or
807        // change in abstractness
808        Set<Modifier> modifiers = method.getModifiers();
809        Set<Modifier> overriddenModifiers = overriddenMethod.getModifiers();
810        if ((modifiers.contains(Modifier.PUBLIC)
811            && overriddenModifiers.contains(Modifier.PROTECTED))
812            || modifiers.contains(Modifier.FINAL)
813            || modifiers.contains(Modifier.ABSTRACT) != overriddenModifiers
814                .contains(Modifier.ABSTRACT)) {
815            return true;
816        }
817        // Change in thrown types
818        if (!method.getThrownTypes()
819            .equals(overriddenMethod.getThrownTypes())) {
820            return true;
821        }
822        // Documented annotations added anywhere in the method signature
823        return !getDocumentedAnnotations(method)
824            .equals(getDocumentedAnnotations(overriddenMethod));
825    }
826
827    private Set<AnnotationMirror>
828            getDocumentedAnnotations(ExecutableElement element) {
829        Set<AnnotationMirror> annotations = new HashSet<>();
830        addDocumentedAnnotations(annotations, element.getAnnotationMirrors());
831
832        new SimpleTypeVisitor14<Void, Void>() {
833            @Override
834            protected Void defaultAction(TypeMirror e, Void v) {
835                addDocumentedAnnotations(annotations, e.getAnnotationMirrors());
836                return null;
837            }
838
839            @Override
840            public Void visitArray(ArrayType t, Void unused) {
841                if (t.getComponentType() != null) {
842                    visit(t.getComponentType());
843                }
844                return super.visitArray(t, unused);
845            }
846
847            @Override
848            public Void visitDeclared(DeclaredType t, Void unused) {
849                t.getTypeArguments().forEach(this::visit);
850                return super.visitDeclared(t, unused);
851            }
852
853            @Override
854            public Void visitWildcard(WildcardType t, Void unused) {
855                if (t.getExtendsBound() != null) {
856                    visit(t.getExtendsBound());
857                }
858                if (t.getSuperBound() != null) {
859                    visit(t.getSuperBound());
860                }
861                return super.visitWildcard(t, unused);
862            }
863
864            @Override
865            public Void visitExecutable(ExecutableType t, Void unused) {
866                t.getParameterTypes().forEach(this::visit);
867                t.getTypeVariables().forEach(this::visit);
868                visit(t.getReturnType());
869                return super.visitExecutable(t, unused);
870            }
871        }.visit(element.asType());
872
873        return annotations;
874    }
875
876    private void addDocumentedAnnotations(Set<AnnotationMirror> annotations,
877            List<? extends AnnotationMirror> annotationMirrors) {
878        annotationMirrors.forEach(annotation -> {
879            if (utils.isDocumentedAnnotation(
880                (TypeElement) annotation.getAnnotationType().asElement())) {
881                annotations.add(annotation);
882            }
883        });
884    }
885
886    /*
887     * A container of members declared in this class or interface. Members of
888     * the same kind stored in declaration order. The container supports
889     * efficient lookup by a member's simple name.
890     */
891    private class LocalMemberTable {
892
893        final Map<Kind, List<Element>> orderedMembers
894            = new EnumMap<>(Kind.class);
895        final Map<Kind, Map<Name, List<Element>>> namedMembers
896            = new EnumMap<>(Kind.class);
897
898        LocalMemberTable() {
899            // elements directly declared by this class or interface,
900            // listed in declaration order
901            List<? extends Element> elements = te.getEnclosedElements();
902            for (Element e : elements) {
903                if (options.noDeprecated() && utils.isDeprecated(e)) {
904                    continue;
905                }
906                switch (e.getKind()) {
907                case CLASS:
908                case INTERFACE:
909                case ENUM:
910                case ANNOTATION_TYPE:
911                case RECORD:
912                    addMember(e, Kind.NESTED_CLASSES);
913                    break;
914                case FIELD:
915                    addMember(e, Kind.FIELDS);
916                    break;
917                case ENUM_CONSTANT:
918                    addMember(e, Kind.ENUM_CONSTANTS);
919                    break;
920                case METHOD:
921                    if (utils.isAnnotationInterface(te)) {
922                        addMember(e, Kind.ANNOTATION_TYPE_MEMBER);
923                        addMember(e,
924                            ((ExecutableElement) e).getDefaultValue() == null
925                                ? Kind.ANNOTATION_TYPE_MEMBER_REQUIRED
926                                : Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL);
927                    } else {
928                        addMember(e, Kind.METHODS);
929                    }
930                    break;
931                case CONSTRUCTOR:
932                    addMember(e, Kind.CONSTRUCTORS);
933                    break;
934                }
935            }
936
937            // protect element lists from unintended changes by clients
938            orderedMembers.replaceAll(this::sealList);
939            namedMembers.values().forEach(m -> m.replaceAll(this::sealList));
940        }
941
942        private <K, V> List<V> sealList(K unusedKey, List<V> v) {
943            return Collections.unmodifiableList(v);
944        }
945
946        void addMember(Element e, Kind kind) {
947            orderedMembers.computeIfAbsent(kind, k -> new ArrayList<>()).add(e);
948            namedMembers.computeIfAbsent(kind, k -> new HashMap<>())
949                .computeIfAbsent(e.getSimpleName(), l -> new ArrayList<>())
950                .add(e);
951        }
952
953        List<Element> getOrderedMembers(Kind kind) {
954            return orderedMembers.getOrDefault(kind, List.of());
955        }
956
957        List<Element> getMembers(Name simpleName, Kind kind) {
958            return namedMembers.getOrDefault(kind, Map.of())
959                .getOrDefault(simpleName, List.of());
960        }
961
962        <T extends Element> List<T> getMembers(Name simpleName, Kind kind,
963                Class<T> clazz) {
964            return getMembers(simpleName, kind)
965                .stream()
966                .map(clazz::cast)
967                .toList();
968        }
969
970        List<ExecutableElement> getPropertyMethods(Name simpleName) {
971            return getMembers(simpleName, Kind.METHODS).stream()
972                .filter(m -> (utils.isPublic(m) || utils.isProtected(m)))
973                .map(m -> (ExecutableElement) m)
974                .toList();
975        }
976    }
977
978    private record PropertyMembers(ExecutableElement propertyMethod,
979            VariableElement field,
980            ExecutableElement getter, ExecutableElement setter) {
981    }
982
983    /*
984     * JavaFX convention notes.
985     * A JavaFX property-method is a method, which ends with "Property" in
986     * its name, takes no parameters and typically returns a subtype of
987     * javafx.beans.
988     * ReadOnlyProperty, in the strictest sense. However, it may not always
989     * be possible for the doclet to have access to j.b.ReadOnlyProperty,
990     * for this reason the strict check is disabled via an undocumented flag.
991     *
992     * Note, a method should not be considered as a property-method,
993     * if it satisfied the previously stated conditions AND if the
994     * method begins with "set", "get" or "is".
995     *
996     * Supposing we have {@code BooleanProperty acmeProperty()}, then the
997     * property-name is "acme".
998     *
999     * Property field, one may or may not exist and could be private, and
1000     * should match the property-method.
1001     *
1002     * A property-setter is a method starting with "set", and the
1003     * first character of the upper-cased starting character of the property
1004     * name, the
1005     * method must take 1 argument and must return a <code>void</code>.
1006     *
1007     * Using the above example {@code void setAcme(Something s)} can be
1008     * considered as a property-setter of the property "acme".
1009     *
1010     * A property-getter is a method starting with "get" and the first character
1011     * upper-cased property-name, having no parameters. A method that does not
1012     * take any
1013     * parameters and starting with "is" and an upper-cased property-name,
1014     * returning a primitive type boolean or BooleanProperty can also be
1015     * considered as a getter, however there must be only one getter for every
1016     * property.
1017     *
1018     * For example {@code Object getAcme()} is a property-getter, and
1019     * {@code boolean isFoo()}
1020     */
1021    private void computeVisibleProperties(LocalMemberTable lmt) {
1022        if (!options.javafx())
1023            return;
1024
1025        PropertyUtils pUtils = config.propertyUtils;
1026        List<Element> list
1027            = visibleMembers.getOrDefault(Kind.METHODS, List.of())
1028                .stream()
1029                .filter(e -> pUtils.isPropertyMethod((ExecutableElement) e))
1030                .toList();
1031
1032        visibleMembers.put(Kind.PROPERTIES, list);
1033
1034        List<ExecutableElement> propertyMethods = list.stream()
1035            .map(e -> (ExecutableElement) e)
1036            .filter(e -> Objects.equals(utils.getEnclosingTypeElement(e), te))
1037            .toList();
1038
1039        // Compute additional properties related sundries.
1040        for (ExecutableElement propertyMethod : propertyMethods) {
1041            String baseName = pUtils.getBaseName(propertyMethod);
1042            List<VariableElement> flist
1043                = lmt.getMembers(utils.elementUtils.getName(baseName),
1044                    Kind.FIELDS, VariableElement.class);
1045            VariableElement field = flist.isEmpty() ? null : flist.get(0);
1046
1047            // TODO: this code does not seem to be covered by tests well
1048            // (JDK-8304170)
1049            ExecutableElement getter = null;
1050            var g = lmt
1051                .getPropertyMethods(utils.elementUtils
1052                    .getName(pUtils.getGetName(propertyMethod)))
1053                .stream()
1054                .filter(m -> m.getParameters().isEmpty()) // Getters have zero
1055                                                          // params, no
1056                                                          // overloads!
1057                .findAny();
1058            if (g.isPresent()) {
1059                getter = g.get();
1060            } else {
1061                // Check if isProperty methods are present ?
1062                var i = lmt
1063                    .getPropertyMethods(utils.elementUtils
1064                        .getName(pUtils.getIsName(propertyMethod)))
1065                    .stream()
1066                    .filter(m -> m.getParameters().isEmpty())
1067                    .findAny();
1068                if (i.isPresent()) {
1069                    // Check if the return type of property method matches an
1070                    // isProperty method.
1071                    if (pUtils.hasIsMethod(propertyMethod)) {
1072                        // Getters have zero params, no overloads!
1073                        getter = i.get();
1074                    }
1075                }
1076            }
1077
1078            var setter = lmt
1079                .getPropertyMethods(utils.elementUtils
1080                    .getName(pUtils.getSetName(propertyMethod)))
1081                .stream()
1082                // TODO: the number and the types of parameters a setter takes
1083                // is not tested (JDK-8304170)
1084                .filter(m -> m.getParameters().size() == 1
1085                    && pUtils.isValidSetterMethod(m))
1086                .findAny()
1087                .orElse(null);
1088
1089            PropertyMembers pm
1090                = new PropertyMembers(propertyMethod, field, getter, setter);
1091            propertyMap.put(propertyMethod, pm);
1092            if (getter != null) {
1093                propertyMap.put(getter, pm);
1094            }
1095            if (setter != null) {
1096                propertyMap.put(setter, pm);
1097            }
1098
1099            // Debugging purposes
1100            // System.out.println("te: " + te + ": " +
1101            // utils.getEnclosingTypeElement(propertyMethod) +
1102            // ":" + propertyMethod.toString() + "->" +
1103            // propertyMap.get(propertyMethod));
1104        }
1105    }
1106
1107    // Future cleanups
1108
1109    private final Map<ExecutableElement,
1110            SoftReference<ImplementedMethods>> implementMethodsFinders
1111                = new HashMap<>();
1112
1113    private ImplementedMethods
1114            getImplementedMethodsFinder(ExecutableElement method) {
1115        SoftReference<ImplementedMethods> ref
1116            = implementMethodsFinders.get(method);
1117        ImplementedMethods imf = ref == null ? null : ref.get();
1118        // imf does not exist or was gc'ed away?
1119        if (imf == null) {
1120            imf = new ImplementedMethods(method);
1121            implementMethodsFinders.put(method, new SoftReference<>(imf));
1122        }
1123        return imf;
1124    }
1125
1126    public List<ExecutableElement>
1127            getImplementedMethods(ExecutableElement method) {
1128        ImplementedMethods imf = getImplementedMethodsFinder(method);
1129        return imf.getImplementedMethods().stream()
1130            .filter(this::isNotSimpleOverride)
1131            .toList();
1132    }
1133
1134    public TypeMirror getImplementedMethodHolder(ExecutableElement method,
1135            ExecutableElement implementedMethod) {
1136        ImplementedMethods imf = getImplementedMethodsFinder(method);
1137        return imf.getMethodHolder(implementedMethod);
1138    }
1139
1140    private class ImplementedMethods {
1141
1142        private final Map<ExecutableElement, TypeMirror> interfaces
1143            = new LinkedHashMap<>();
1144
1145        public ImplementedMethods(ExecutableElement implementer) {
1146            var typeElement = (TypeElement) implementer.getEnclosingElement();
1147            for (TypeMirror i : utils.getAllInterfaces(typeElement)) {
1148                TypeElement dst = utils.asTypeElement(i); // a type element to
1149                                                          // look an implemented
1150                                                          // method in
1151                ExecutableElement implemented
1152                    = findImplementedMethod(dst, implementer);
1153                if (implemented == null) {
1154                    continue;
1155                }
1156                var prev = interfaces.put(implemented, i);
1157                // no two type elements declare the same method
1158                assert prev == null;
1159                // dst can be generic, while i might be parameterized; but they
1160                // must the same type element. For example, if dst is Set<T>,
1161                // then i is Set<String>
1162                assert Objects.equals(((DeclaredType) i).asElement(), dst);
1163            }
1164        }
1165
1166        private ExecutableElement findImplementedMethod(TypeElement te,
1167                ExecutableElement implementer) {
1168            var typeElement = (TypeElement) implementer.getEnclosingElement();
1169            for (var m : utils.getMethods(te)) {
1170                if (utils.elementUtils.overrides(implementer, m, typeElement)) {
1171                    return m;
1172                }
1173            }
1174            return null;
1175        }
1176
1177        /**
1178         * Returns a collection of interface methods which the method passed in the
1179         * constructor is implementing. The search/build order is as follows:
1180         * <pre>
1181         * 1. Search in all the immediate interfaces which this method's class is
1182         *    implementing. Do it recursively for the superinterfaces as well.
1183         * 2. Traverse all the superclasses and search recursively in the
1184         *    interfaces which those superclasses implement.
1185         * </pre>
1186         *
1187         * @return a collection of implemented methods
1188         */
1189        Collection<ExecutableElement> getImplementedMethods() {
1190            return interfaces.keySet();
1191        }
1192
1193        TypeMirror getMethodHolder(ExecutableElement ee) {
1194            return interfaces.get(ee);
1195        }
1196    }
1197
1198    /*
1199     * (Here "override" used as a noun, not a verb, for a short and descriptive
1200     * name. Sadly, we cannot use "Override" as a complete name because a clash
1201     * with @java.lang.Override would make it inconvenient.)
1202     *
1203     * Used to provide additional attributes to the otherwise boolean
1204     * "overrides(a, b)" relationship.
1205     *
1206     * Overriding method could be a key in a map and an instance of this
1207     * record could be the value.
1208     */
1209    private record OverrideInfo(ExecutableElement overriddenMethod,
1210            boolean simpleOverride) {
1211        @Override // for debugging
1212        public String toString() {
1213            return overriddenMethod.getEnclosingElement()
1214                + "::" + overriddenMethod + ", simple=" + simpleOverride;
1215        }
1216    }
1217
1218    @Override
1219    public int hashCode() {
1220        return te.hashCode();
1221    }
1222
1223    @Override
1224    public boolean equals(Object obj) {
1225        if (!(obj instanceof VisibleMemberTable other))
1226            return false;
1227        return te.equals(other.te);
1228    }
1229}