src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberMap.java

Print this page

        

*** 21,41 **** * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ ! package com.sun.tools.doclets.internal.toolkit.util; import java.util.*; import java.util.regex.Pattern; ! import com.sun.javadoc.*; ! import com.sun.tools.doclets.internal.toolkit.*; /** * A data structure that encapsulates the visible members of a particular ! * type for a given class tree. To use this data structor, you must specify * the type of member you are interested in (nested class, field, constructor * or method) and the leaf of the class tree. The data structure will map * all visible members in the leaf and classes above the leaf in the tree. * * <p><b>This is NOT part of any supported API. --- 21,50 ---- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ ! package jdk.javadoc.internal.doclets.toolkit.util; import java.util.*; import java.util.regex.Pattern; ! import javax.lang.model.element.Element; ! import javax.lang.model.element.ExecutableElement; ! import javax.lang.model.element.TypeElement; ! import javax.lang.model.element.VariableElement; ! import javax.lang.model.type.TypeKind; ! import javax.lang.model.type.TypeMirror; + import com.sun.source.doctree.DocCommentTree; + import com.sun.source.doctree.DocTree; + + import jdk.javadoc.internal.doclets.toolkit.Configuration; + /** * A data structure that encapsulates the visible members of a particular ! * type for a given class tree. To use this data structure, you must specify * the type of member you are interested in (nested class, field, constructor * or method) and the leaf of the class tree. The data structure will map * all visible members in the leaf and classes above the leaf in the tree. * * <p><b>This is NOT part of any supported API.
*** 48,186 **** */ public class VisibleMemberMap { private boolean noVisibleMembers = true; ! public static final int INNERCLASSES = 0; ! public static final int ENUM_CONSTANTS = 1; ! public static final int FIELDS = 2; ! public static final int CONSTRUCTORS = 3; ! public static final int METHODS = 4; ! public static final int ANNOTATION_TYPE_FIELDS = 5; ! public static final int ANNOTATION_TYPE_MEMBER_OPTIONAL = 6; ! public static final int ANNOTATION_TYPE_MEMBER_REQUIRED = 7; ! public static final int PROPERTIES = 8; ! /** ! * The total number of member types is {@value}. ! */ ! public static final int NUM_MEMBER_TYPES = 9; public static final String STARTLEVEL = "start"; /** ! * List of ClassDoc objects for which ClassMembers objects are built. */ ! private final List<ClassDoc> visibleClasses = new ArrayList<>(); /** * Map for each member name on to a map which contains members with same * name-signature. The mapped map will contain mapping for each MemberDoc * onto it's respecive level string. */ ! private final Map<Object,Map<ProgramElementDoc,String>> memberNameMap = new HashMap<>(); /** * Map of class and it's ClassMembers object. */ ! private final Map<ClassDoc,ClassMembers> classMap = new HashMap<>(); /** * Type whose visible members are requested. This is the leaf of * the class tree being mapped. */ ! private final ClassDoc classdoc; /** * Member kind: InnerClasses/Fields/Methods? */ ! private final int kind; /** * The configuration this VisibleMemberMap was created with. */ private final Configuration configuration; private final Utils utils; ! private static final Map<ClassDoc, ProgramElementDoc[]> propertiesCache = new HashMap<>(); ! private static final Map<ProgramElementDoc, ProgramElementDoc> classPropertiesMap = new HashMap<>(); ! private static final Map<ProgramElementDoc, GetterSetter> getterSetterMap = new HashMap<>(); /** ! * Construct a VisibleMemberMap of the given type for the given ! * class. * ! * @param classdoc the class whose members are being mapped. * @param kind the kind of member that is being mapped. * @param configuration the configuration to use to construct this * VisibleMemberMap. If the field configuration.nodeprecated is true the * deprecated members are excluded from the map. If the field * configuration.javafx is true the JavaFX features are used. */ ! public VisibleMemberMap(ClassDoc classdoc, ! int kind, Configuration configuration) { ! this.classdoc = classdoc; this.kind = kind; this.configuration = configuration; this.utils = configuration.utils; ! new ClassMembers(classdoc, STARTLEVEL).build(); } /** * Return the list of visible classes in this map. * * @return the list of visible classes in this map. */ ! public List<ClassDoc> getVisibleClassesList() { ! sort(visibleClasses); ! return visibleClasses; } /** * Returns the property field documentation belonging to the given member. ! * @param ped the member for which the property documentation is needed. * @return the property field documentation, null if there is none. */ ! public ProgramElementDoc getPropertyMemberDoc(ProgramElementDoc ped) { ! return classPropertiesMap.get(ped); } /** * Returns the getter documentation belonging to the given property method. * @param propertyMethod the method for which the getter is needed. * @return the getter documentation, null if there is none. */ ! public ProgramElementDoc getGetterForProperty(ProgramElementDoc propertyMethod) { return getterSetterMap.get(propertyMethod).getGetter(); } /** * Returns the setter documentation belonging to the given property method. * @param propertyMethod the method for which the setter is needed. * @return the setter documentation, null if there is none. */ ! public ProgramElementDoc getSetterForProperty(ProgramElementDoc propertyMethod) { return getterSetterMap.get(propertyMethod).getSetter(); } /** * Return the package private members inherited by the class. Only return * if parent is package private and not documented. * - * @param configuration the current configuration of the doclet. * @return the package private members inherited by the class. */ ! private List<ProgramElementDoc> getInheritedPackagePrivateMethods(Configuration configuration) { ! List<ProgramElementDoc> results = new ArrayList<>(); ! for (ClassDoc currentClass : visibleClasses) { ! if (currentClass != classdoc && ! currentClass.isPackagePrivate() && ! !utils.isLinkable(currentClass, configuration)) { // Document these members in the child class because // the parent is inaccessible. ! results.addAll(getMembersFor(currentClass)); } } return results; } --- 57,215 ---- */ public class VisibleMemberMap { private boolean noVisibleMembers = true; ! public static enum Kind { ! INNER_CLASSES, ! ENUM_CONSTANTS, ! FIELDS, ! CONSTRUCTORS, ! METHODS, ! ANNOTATION_TYPE_FIELDS, ! ANNOTATION_TYPE_MEMBER_OPTIONAL, ! ANNOTATION_TYPE_MEMBER_REQUIRED, ! PROPERTIES; ! public static final EnumSet<Kind> summarySet = EnumSet.range(INNER_CLASSES, METHODS); ! public static final EnumSet<Kind> detailSet = EnumSet.range(ENUM_CONSTANTS, METHODS); ! public static String getNavLinkLabels(Kind kind) { ! switch (kind) { ! case INNER_CLASSES: ! return "doclet.navNested"; ! case ENUM_CONSTANTS: ! return "doclet.navEnum"; ! case FIELDS: ! return "doclet.navField"; ! case CONSTRUCTORS: ! return "doclet.navConstructor"; ! case METHODS: ! return "doclet.navMethod"; ! default: ! throw new AssertionError("unknown kind:" + kind); ! } ! } ! } public static final String STARTLEVEL = "start"; + // properties aren't named setA* or getA* + private static final Pattern GETTERSETTERPATTERN = Pattern.compile("[sg]et\\p{Upper}.*"); /** ! * List of TypeElement objects for which ClassMembers objects are built. */ ! private final Set<TypeElement> visibleClasses; /** * Map for each member name on to a map which contains members with same * name-signature. The mapped map will contain mapping for each MemberDoc * onto it's respecive level string. */ ! private final Map<Object, Map<Element, String>> memberNameMap = new HashMap<>(); /** * Map of class and it's ClassMembers object. */ ! private final Map<TypeElement, ClassMembers> classMap = new HashMap<>(); /** * Type whose visible members are requested. This is the leaf of * the class tree being mapped. */ ! private final TypeElement typeElement; /** * Member kind: InnerClasses/Fields/Methods? */ ! private final Kind kind; /** * The configuration this VisibleMemberMap was created with. */ private final Configuration configuration; private final Utils utils; + private final Comparator<Element> comparator; ! private static final Map<TypeElement, List<Element>> propertiesCache = new HashMap<>(); ! private static final Map<Element, Element> classPropertiesMap = new HashMap<>(); ! private static final Map<Element, GetterSetter> getterSetterMap = new HashMap<>(); /** ! * Construct a VisibleMemberMap of the given type for the given class. * ! * @param typeElement whose members are being mapped. * @param kind the kind of member that is being mapped. * @param configuration the configuration to use to construct this * VisibleMemberMap. If the field configuration.nodeprecated is true the * deprecated members are excluded from the map. If the field * configuration.javafx is true the JavaFX features are used. */ ! public VisibleMemberMap(TypeElement typeElement, ! Kind kind, Configuration configuration) { ! this.typeElement = typeElement; this.kind = kind; this.configuration = configuration; this.utils = configuration.utils; ! comparator = utils.makeGeneralPurposeComparator(); ! visibleClasses = new LinkedHashSet<>(); ! new ClassMembers(typeElement, STARTLEVEL).build(); } /** * Return the list of visible classes in this map. * * @return the list of visible classes in this map. */ ! public SortedSet<TypeElement> getVisibleClasses() { ! SortedSet<TypeElement> vClasses = new TreeSet<>(comparator); ! vClasses.addAll(visibleClasses); ! return vClasses; } /** * Returns the property field documentation belonging to the given member. ! * @param element the member for which the property documentation is needed. * @return the property field documentation, null if there is none. */ ! public Element getPropertyMemberDoc(Element element) { ! return classPropertiesMap.get(element); } /** * Returns the getter documentation belonging to the given property method. * @param propertyMethod the method for which the getter is needed. * @return the getter documentation, null if there is none. */ ! public Element getGetterForProperty(Element propertyMethod) { return getterSetterMap.get(propertyMethod).getGetter(); } /** * Returns the setter documentation belonging to the given property method. * @param propertyMethod the method for which the setter is needed. * @return the setter documentation, null if there is none. */ ! public Element getSetterForProperty(Element propertyMethod) { return getterSetterMap.get(propertyMethod).getSetter(); } /** * Return the package private members inherited by the class. Only return * if parent is package private and not documented. * * @return the package private members inherited by the class. */ ! private List<Element> getInheritedPackagePrivateMethods() { ! List<Element> results = new ArrayList<>(); ! for (TypeElement currentClass : visibleClasses) { ! if (currentClass != typeElement && ! utils.isPackagePrivate(currentClass) && ! !utils.isLinkable(currentClass)) { // Document these members in the child class because // the parent is inaccessible. ! results.addAll(classMap.get(currentClass).members); } } return results; }
*** 189,280 **** * end of the list members that are inherited by inaccessible parents. We * document these members in the child because the parent is not documented. * * @param configuration the current configuration of the doclet. */ ! public List<ProgramElementDoc> getLeafClassMembers(Configuration configuration) { ! List<ProgramElementDoc> result = getMembersFor(classdoc); ! result.addAll(getInheritedPackagePrivateMethods(configuration)); return result; } /** * Retrn the list of members for the given class. * ! * @param cd the class to retrieve the list of visible members for. * * @return the list of members for the given class. */ ! public List<ProgramElementDoc> getMembersFor(ClassDoc cd) { ! ClassMembers clmembers = classMap.get(cd); ! if (clmembers == null) { ! return new ArrayList<>(); } ! return clmembers.getMembers(); } ! /** ! * Sort the given mixed list of classes and interfaces to a list of ! * classes followed by interfaces traversed. Don't sort alphabetically. ! */ ! private void sort(List<ClassDoc> list) { ! List<ClassDoc> classes = new ArrayList<>(); ! List<ClassDoc> interfaces = new ArrayList<>(); ! for (ClassDoc cd : list) { ! if (cd.isClass()) { ! classes.add(cd); } ! else { ! interfaces.add(cd); } - } - list.clear(); - list.addAll(classes); - list.addAll(interfaces); - } ! private void fillMemberLevelMap(List<ProgramElementDoc> list, String level) { ! for (ProgramElementDoc element : list) { Object key = getMemberKey(element); ! Map<ProgramElementDoc, String> memberLevelMap = memberNameMap.get(key); if (memberLevelMap == null) { memberLevelMap = new HashMap<>(); memberNameMap.put(key, memberLevelMap); } memberLevelMap.put(element, level); } } ! private void purgeMemberLevelMap(List<ProgramElementDoc> list, String level) { ! for (ProgramElementDoc element : list) { Object key = getMemberKey(element); ! Map<ProgramElementDoc, String> memberLevelMap = memberNameMap.get(key); if (memberLevelMap != null && level.equals(memberLevelMap.get(element))) memberLevelMap.remove(element); } } /** ! * Represents a class member. We should be able to just use a ! * ProgramElementDoc instead of this class, but that doesn't take ! * type variables in consideration when comparing. */ private class ClassMember { ! private Set<ProgramElementDoc> members; ! public ClassMember(ProgramElementDoc programElementDoc) { members = new HashSet<>(); ! members.add(programElementDoc); } ! public void addMember(ProgramElementDoc programElementDoc) { ! members.add(programElementDoc); ! } ! ! public boolean isEqual(MethodDoc member) { ! for (ProgramElementDoc element : members) { ! if (utils.executableMembersEqual(member, (MethodDoc) element)) { members.add(member); return true; } } return false; --- 218,298 ---- * end of the list members that are inherited by inaccessible parents. We * document these members in the child because the parent is not documented. * * @param configuration the current configuration of the doclet. */ ! public SortedSet<Element> getLeafClassMembers() { ! SortedSet<Element> result = getMembersFor(typeElement); ! result.addAll(getInheritedPackagePrivateMethods()); return result; } + public Set<Element> getLeafClassMembersSourceOrder() { + Set<Element> result = new LinkedHashSet<>(classMap.get(typeElement).members); + result.addAll(getInheritedPackagePrivateMethods()); + return result; + } + /** * Retrn the list of members for the given class. * ! * @param typeElement the class to retrieve the list of visible members for. * * @return the list of members for the given class. */ ! public SortedSet<Element> getMembersFor(TypeElement typeElement) { ! return asSortedSet(classMap.get(typeElement).members); } ! ! public boolean hasMembersFor(TypeElement typeElement) { ! return !classMap.get(typeElement).members.isEmpty(); } ! private SortedSet<Element> asSortedSet(Collection<Element> in) { ! if (in == null) { ! return Collections.emptySortedSet(); } ! TreeSet<Element> out = new TreeSet<>(comparator); ! out.addAll(in); ! return out; } ! private void fillMemberLevelMap(List<? extends Element> list, String level) { ! for (Element element : list) { Object key = getMemberKey(element); ! Map<Element, String> memberLevelMap = memberNameMap.get(key); if (memberLevelMap == null) { memberLevelMap = new HashMap<>(); memberNameMap.put(key, memberLevelMap); } memberLevelMap.put(element, level); } } ! private void purgeMemberLevelMap(Iterable<? extends Element> list, String level) { ! for (Element element : list) { Object key = getMemberKey(element); ! Map<Element, String> memberLevelMap = memberNameMap.get(key); if (memberLevelMap != null && level.equals(memberLevelMap.get(element))) memberLevelMap.remove(element); } } /** ! * Represents a class member. */ private class ClassMember { ! private Set<Element> members; ! public ClassMember(Element element) { members = new HashSet<>(); ! members.add(element); } ! public boolean isEqual(ExecutableElement member) { ! for (Element element : members) { ! if (utils.executableMembersEqual(member, (ExecutableElement) element)) { members.add(member); return true; } } return false;
*** 289,321 **** /** * The mapping class, whose inherited members are put in the * {@link #members} list. */ ! private ClassDoc mappingClass; /** * List of inherited members from the mapping class. */ ! private List<ProgramElementDoc> members = new ArrayList<>(); /** * Level/Depth of inheritance. */ ! private String level; ! /** ! * Return list of inherited members from mapping class. ! * ! * @return List Inherited members. ! */ ! public List<ProgramElementDoc> getMembers() { ! return members; ! } ! ! private ClassMembers(ClassDoc mappingClass, String level) { ! this.mappingClass = mappingClass; this.level = level; if (classMap.containsKey(mappingClass) && level.startsWith(classMap.get(mappingClass).level)) { //Remove lower level class so that it can be replaced with //same class found at higher level. --- 307,330 ---- /** * The mapping class, whose inherited members are put in the * {@link #members} list. */ ! private final TypeElement typeElement; /** * List of inherited members from the mapping class. */ ! private Set<Element> members = new LinkedHashSet<>(); /** * Level/Depth of inheritance. */ ! private final String level; ! private ClassMembers(TypeElement mappingClass, String level) { ! this.typeElement = mappingClass; this.level = level; if (classMap.containsKey(mappingClass) && level.startsWith(classMap.get(mappingClass).level)) { //Remove lower level class so that it can be replaced with //same class found at higher level.
*** 326,359 **** } if (!classMap.containsKey(mappingClass)) { classMap.put(mappingClass, this); visibleClasses.add(mappingClass); } - } private void build() { ! if (kind == CONSTRUCTORS) { ! addMembers(mappingClass); } else { mapClass(); } } private void mapClass() { ! addMembers(mappingClass); ! ClassDoc[] interfaces = mappingClass.interfaces(); ! for (ClassDoc anInterface : interfaces) { String locallevel = level + 1; ! ClassMembers cm = new ClassMembers(anInterface, locallevel); cm.mapClass(); } ! if (mappingClass.isClass()) { ! ClassDoc superclass = mappingClass.superclass(); ! if (!(superclass == null || mappingClass.equals(superclass))) { ! ClassMembers cm = new ClassMembers(superclass, ! level + "c"); cm.mapClass(); } } } --- 335,366 ---- } if (!classMap.containsKey(mappingClass)) { classMap.put(mappingClass, this); visibleClasses.add(mappingClass); } } private void build() { ! if (kind == Kind.CONSTRUCTORS) { ! addMembers(typeElement); } else { mapClass(); } } private void mapClass() { ! addMembers(typeElement); ! List<? extends TypeMirror> interfaces = typeElement.getInterfaces(); ! for (TypeMirror anInterface : interfaces) { String locallevel = level + 1; ! ClassMembers cm = new ClassMembers(utils.asTypeElement(anInterface), locallevel); cm.mapClass(); } ! if (utils.isClass(typeElement)) { ! TypeElement superclass = utils.getSuperClass(typeElement); ! if (!(superclass == null || typeElement.equals(superclass))) { ! ClassMembers cm = new ClassMembers(superclass, level + "c"); cm.mapClass(); } } }
*** 363,505 **** * string for ctii. If mapping class member is not already in the * inherited member list and if it is visible in the ctii and not * overridden, put such a member in the inherited member list. * Adjust member-level-map, class-map. */ ! private void addMembers(ClassDoc fromClass) { ! List<ProgramElementDoc> cdmembers = getClassMembers(fromClass, true); ! List<ProgramElementDoc> incllist = new ArrayList<>(); ! for (ProgramElementDoc pgmelem : cdmembers) { ! if (!found(members, pgmelem) && ! memberIsVisible(pgmelem) && ! !isOverridden(pgmelem, level) && ! !isTreatedAsPrivate(pgmelem)) { ! incllist.add(pgmelem); } } ! if (incllist.size() > 0) { noVisibleMembers = false; } members.addAll(incllist); fillMemberLevelMap(getClassMembers(fromClass, false), level); } ! private boolean isTreatedAsPrivate(ProgramElementDoc pgmelem) { if (!configuration.javafx) { return false; } ! Tag[] aspTags = pgmelem.tags("@treatAsPrivate"); ! boolean result = (aspTags != null) && (aspTags.length > 0); return result; } /** ! * Is given doc item visible in given classdoc in terms fo inheritance? ! * The given doc item is visible in the given classdoc if it is public ! * or protected and if it is package-private if it's containing class ! * is in the same package as the given classdoc. */ ! private boolean memberIsVisible(ProgramElementDoc pgmdoc) { ! if (pgmdoc.containingClass().equals(classdoc)) { //Member is in class that we are finding visible members for. //Of course it is visible. return true; ! } else if (pgmdoc.isPrivate()) { //Member is in super class or implemented interface. //Private, so not inherited. return false; ! } else if (pgmdoc.isPackagePrivate()) { //Member is package private. Only return true if its class is in //same package. ! return pgmdoc.containingClass().containingPackage().equals( ! classdoc.containingPackage()); } else { //Public members are always inherited. return true; } } /** * Return all available class members. */ ! private List<ProgramElementDoc> getClassMembers(ClassDoc cd, boolean filter) { ! if (cd.isEnum() && kind == CONSTRUCTORS) { //If any of these rules are hit, return empty array because //we don't document these members ever. ! return Arrays.asList(new ProgramElementDoc[] {}); } ! ProgramElementDoc[] members = null; switch (kind) { case ANNOTATION_TYPE_FIELDS: ! members = cd.fields(filter); break; case ANNOTATION_TYPE_MEMBER_OPTIONAL: ! members = cd.isAnnotationType() ? ! filter((AnnotationTypeDoc) cd, false) : ! new AnnotationTypeElementDoc[] {}; break; case ANNOTATION_TYPE_MEMBER_REQUIRED: ! members = cd.isAnnotationType() ? ! filter((AnnotationTypeDoc) cd, true) : ! new AnnotationTypeElementDoc[] {}; break; ! case INNERCLASSES: ! members = cd.innerClasses(filter); break; case ENUM_CONSTANTS: ! members = cd.enumConstants(); break; case FIELDS: ! members = cd.fields(filter); break; case CONSTRUCTORS: ! members = cd.constructors(); break; case METHODS: ! members = cd.methods(filter); ! checkOnPropertiesTags((MethodDoc[])members); break; case PROPERTIES: ! members = properties(cd, filter); break; default: ! members = new ProgramElementDoc[0]; } // Deprected members should be excluded or not? if (configuration.nodeprecated) { ! return utils.excludeDeprecatedMembersAsList(members); } ! return Arrays.asList(members); } /** * Filter the annotation type members and return either the required * members or the optional members, depending on the value of the * required parameter. * ! * @param doc The annotation type to process. * @param required * @return the annotation type members and return either the required * members or the optional members, depending on the value of the * required parameter. */ ! private AnnotationTypeElementDoc[] filter(AnnotationTypeDoc doc, ! boolean required) { ! AnnotationTypeElementDoc[] members = doc.elements(); ! List<AnnotationTypeElementDoc> targetMembers = new ArrayList<>(); ! for (AnnotationTypeElementDoc member : members) { ! if ((required && member.defaultValue() == null) || ! ((!required) && member.defaultValue() != null)) { targetMembers.add(member); } } ! return targetMembers.toArray(new AnnotationTypeElementDoc[]{}); } ! private boolean found(List<ProgramElementDoc> list, ProgramElementDoc elem) { ! for (ProgramElementDoc pgmelem : list) { if (utils.matches(pgmelem, elem)) { return true; } } return false; --- 370,526 ---- * string for ctii. If mapping class member is not already in the * inherited member list and if it is visible in the ctii and not * overridden, put such a member in the inherited member list. * Adjust member-level-map, class-map. */ ! private void addMembers(TypeElement fromClass) { ! List<? extends Element> classMembers = getClassMembers(fromClass, true); ! List<Element> incllist = new ArrayList<>(); ! for (Element element : classMembers) { ! if (!found(members, element)) { ! if (memberIsVisible(element)) { ! if (!isOverridden(element, level)) { ! if (!isTreatedAsPrivate(element)) { ! incllist.add(element); } } ! } ! } ! } ! if (!incllist.isEmpty()) { noVisibleMembers = false; } members.addAll(incllist); fillMemberLevelMap(getClassMembers(fromClass, false), level); } ! private boolean isTreatedAsPrivate(Element pgmelem) { if (!configuration.javafx) { return false; } ! List<? extends DocTree> aspTags = utils.getBlockTags(pgmelem, "@treatAsPrivate"); ! boolean result = (aspTags != null) && (!aspTags.isEmpty()); return result; } /** ! * Is given element visible in given typeElement in terms of inheritance? The given element ! * is visible in the given typeElement if it is public or protected and if it is ! * package-private if it's containing class is in the same package as the given typeElement. */ ! private boolean memberIsVisible(Element element) { ! if (utils.getEnclosingTypeElement(element).equals(VisibleMemberMap.this.typeElement)) { //Member is in class that we are finding visible members for. //Of course it is visible. return true; ! } else if (utils.isPrivate(element)) { //Member is in super class or implemented interface. //Private, so not inherited. return false; ! } else if (utils.isPackagePrivate(element)) { //Member is package private. Only return true if its class is in //same package. ! return utils.containingPackage(element).equals(utils.containingPackage(VisibleMemberMap.this.typeElement)); } else { //Public members are always inherited. return true; } } /** * Return all available class members. */ ! private List<? extends Element> getClassMembers(TypeElement te, boolean filter) { ! if (utils.isEnum(te) && kind == Kind.CONSTRUCTORS) { //If any of these rules are hit, return empty array because //we don't document these members ever. ! return Collections.emptyList(); } ! List<? extends Element> list; switch (kind) { case ANNOTATION_TYPE_FIELDS: ! list = (filter) ! ? utils.getAnnotationFields(te) ! : utils.getAnnotationFieldsUnfiltered(te); break; case ANNOTATION_TYPE_MEMBER_OPTIONAL: ! list = utils.isAnnotationType(te) ! ? filterAnnotations(te, false) ! : Collections.emptyList(); break; case ANNOTATION_TYPE_MEMBER_REQUIRED: ! list = utils.isAnnotationType(te) ! ? filterAnnotations(te, true) ! : Collections.emptyList(); break; ! case INNER_CLASSES: ! List<TypeElement> xlist = filter ! ? utils.getInnerClasses(te) ! : utils.getInnerClassesUnfiltered(te); ! list = new ArrayList<>(xlist); break; case ENUM_CONSTANTS: ! list = utils.getEnumConstants(te); break; case FIELDS: ! if (filter) { ! list = utils.isAnnotationType(te) ! ? utils.getAnnotationFields(te) ! : utils.getFields(te); ! } else { ! list = utils.isAnnotationType(te) ! ? utils.getAnnotationFieldsUnfiltered(te) ! : utils.getFieldsUnfiltered(te); ! } break; case CONSTRUCTORS: ! list = utils.getConstructors(te); break; case METHODS: ! list = filter ? utils.getMethods(te) : utils.getMethodsUnfiltered(te); ! checkOnPropertiesTags(list); break; case PROPERTIES: ! list = properties(te, filter); break; default: ! list = Collections.emptyList(); } // Deprected members should be excluded or not? if (configuration.nodeprecated) { ! return utils.excludeDeprecatedMembers(list); } ! return list; } /** * Filter the annotation type members and return either the required * members or the optional members, depending on the value of the * required parameter. * ! * @param typeElement The annotation type to process. * @param required * @return the annotation type members and return either the required * members or the optional members, depending on the value of the * required parameter. */ ! private List<Element> filterAnnotations(TypeElement typeElement, boolean required) { ! List<Element> members = utils.getAnnotationMethods(typeElement); ! List<Element> targetMembers = new ArrayList<>(); ! for (Element member : members) { ! ExecutableElement ee = (ExecutableElement)member; ! if ((required && ee.getDefaultValue() == null) ! || ((!required) && ee.getDefaultValue() != null)) { targetMembers.add(member); } } ! return targetMembers; } ! private boolean found(Iterable<Element> list, Element elem) { ! for (Element pgmelem : list) { if (utils.matches(pgmelem, elem)) { return true; } } return false;
*** 509,569 **** /** * Is member overridden? The member is overridden if it is found in the * same level hierarchy e.g. member at level "11" overrides member at * level "111". */ ! private boolean isOverridden(ProgramElementDoc pgmdoc, String level) { ! Map<?,String> memberLevelMap = (Map<?,String>) memberNameMap.get(getMemberKey(pgmdoc)); if (memberLevelMap == null) return false; for (String mappedlevel : memberLevelMap.values()) { ! if (mappedlevel.equals(STARTLEVEL) || ! (level.startsWith(mappedlevel) && ! !level.equals(mappedlevel))) { return true; } } return false; } ! private ProgramElementDoc[] properties(final ClassDoc cd, final boolean filter) { ! final MethodDoc[] allMethods = cd.methods(filter); ! final FieldDoc[] allFields = cd.fields(false); ! if (propertiesCache.containsKey(cd)) { ! return propertiesCache.get(cd); } ! final List<MethodDoc> result = new ArrayList<>(); ! for (final MethodDoc propertyMethod : allMethods) { ! ! if (!isPropertyMethod(propertyMethod)) { continue; } ! final MethodDoc getter = getterForField(allMethods, propertyMethod); ! final MethodDoc setter = setterForField(allMethods, propertyMethod); ! final FieldDoc field = fieldForProperty(allFields, propertyMethod); ! addToPropertiesMap(setter, getter, propertyMethod, field); getterSetterMap.put(propertyMethod, new GetterSetter(getter, setter)); ! result.add(propertyMethod); } ! final ProgramElementDoc[] resultAray = ! result.toArray(new ProgramElementDoc[result.size()]); ! propertiesCache.put(cd, resultAray); ! return resultAray; } ! private void addToPropertiesMap(MethodDoc setter, ! MethodDoc getter, ! MethodDoc propertyMethod, ! FieldDoc field) { ! if ((field == null) ! || (field.getRawCommentText() == null) ! || field.getRawCommentText().length() == 0) { addToPropertiesMap(setter, propertyMethod); addToPropertiesMap(getter, propertyMethod); addToPropertiesMap(propertyMethod, propertyMethod); } else { addToPropertiesMap(getter, field); --- 530,589 ---- /** * Is member overridden? The member is overridden if it is found in the * same level hierarchy e.g. member at level "11" overrides member at * level "111". */ ! private boolean isOverridden(Element element, String level) { ! Object key = getMemberKey(element); ! Map<?, String> memberLevelMap = (Map<?, String>) memberNameMap.get(key); if (memberLevelMap == null) return false; for (String mappedlevel : memberLevelMap.values()) { ! if (mappedlevel.equals(STARTLEVEL) ! || (level.startsWith(mappedlevel) ! && !level.equals(mappedlevel))) { return true; } } return false; } ! private List<Element> properties(final TypeElement typeElement, final boolean filter) { ! final List<ExecutableElement> allMethods = filter ! ? utils.getMethods(typeElement) ! : utils.getMethodsUnfiltered(typeElement); ! final List<VariableElement> allFields = utils.getFieldsUnfiltered(typeElement); ! if (propertiesCache.containsKey(typeElement)) { ! return propertiesCache.get(typeElement); } ! final List<Element> result = new ArrayList<>(); ! for (final Element propertyMethod : allMethods) { ! ExecutableElement ee = (ExecutableElement)propertyMethod; ! if (!isPropertyMethod(ee)) { continue; } ! final ExecutableElement getter = getterForField(allMethods, ee); ! final ExecutableElement setter = setterForField(allMethods, ee); ! final VariableElement field = fieldForProperty(allFields, ee); ! addToPropertiesMap(setter, getter, ee, field); getterSetterMap.put(propertyMethod, new GetterSetter(getter, setter)); ! result.add(ee); } ! propertiesCache.put(typeElement, result); ! return result; } ! private void addToPropertiesMap(ExecutableElement setter, ! ExecutableElement getter, ! ExecutableElement propertyMethod, ! VariableElement field) { ! if (field == null || utils.getDocCommentTree(field) == null) { addToPropertiesMap(setter, propertyMethod); addToPropertiesMap(getter, propertyMethod); addToPropertiesMap(propertyMethod, propertyMethod); } else { addToPropertiesMap(getter, field);
*** 570,734 **** addToPropertiesMap(setter, field); addToPropertiesMap(propertyMethod, field); } } ! private void addToPropertiesMap(ProgramElementDoc propertyMethod, ! ProgramElementDoc commentSource) { if (null == propertyMethod || null == commentSource) { return; } ! final String methodRawCommentText = propertyMethod.getRawCommentText(); /* The second condition is required for the property buckets. In * this case the comment is at the property method (not at the field) * and it needs to be listed in the map. */ ! if ((null == methodRawCommentText || 0 == methodRawCommentText.length()) ! || propertyMethod.equals(commentSource)) { classPropertiesMap.put(propertyMethod, commentSource); } } ! private MethodDoc getterForField(MethodDoc[] methods, ! MethodDoc propertyMethod) { ! final String propertyMethodName = propertyMethod.name(); ! final String fieldName = ! propertyMethodName.substring(0, propertyMethodName.lastIndexOf("Property")); final String fieldNameUppercased = "" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); final String getterNamePattern; ! final String fieldTypeName = propertyMethod.returnType().toString(); if ("boolean".equals(fieldTypeName) || fieldTypeName.endsWith("BooleanProperty")) { getterNamePattern = "(is|get)" + fieldNameUppercased; } else { getterNamePattern = "get" + fieldNameUppercased; } ! for (MethodDoc methodDoc : methods) { ! if (Pattern.matches(getterNamePattern, methodDoc.name())) { ! if (0 == methodDoc.parameters().length ! && (methodDoc.isPublic() || methodDoc.isProtected())) { ! return methodDoc; } } } return null; } ! private MethodDoc setterForField(MethodDoc[] methods, ! MethodDoc propertyMethod) { ! final String propertyMethodName = propertyMethod.name(); final String fieldName = propertyMethodName.substring(0, propertyMethodName.lastIndexOf("Property")); final String fieldNameUppercased = "" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); final String setter = "set" + fieldNameUppercased; ! for (MethodDoc methodDoc : methods) { ! if (setter.equals(methodDoc.name())) { ! if (1 == methodDoc.parameters().length ! && "void".equals(methodDoc.returnType().simpleTypeName()) ! && (methodDoc.isPublic() || methodDoc.isProtected())) { ! return methodDoc; } } } return null; } ! private FieldDoc fieldForProperty(FieldDoc[] fields, MethodDoc property) { ! for (FieldDoc field : fields) { ! final String fieldName = field.name(); final String propertyName = fieldName + "Property"; ! if (propertyName.equals(property.name())) { return field; } } return null; } ! // properties aren't named setA* or getA* ! private final Pattern pattern = Pattern.compile("[sg]et\\p{Upper}.*"); ! private boolean isPropertyMethod(MethodDoc method) { if (!configuration.javafx) { return false; } ! if (!method.name().endsWith("Property")) { return false; } ! if (! memberIsVisible(method)) { return false; } ! if (pattern.matcher(method.name()).matches()) { return false; } ! if (method.typeParameters().length > 0) { return false; } ! return 0 == method.parameters().length ! && !"void".equals(method.returnType().simpleTypeName()); } ! private void checkOnPropertiesTags(MethodDoc[] members) { ! for (MethodDoc methodDoc: members) { ! if (methodDoc.isIncluded()) { ! for (Tag tag: methodDoc.tags()) { ! String tagName = tag.name(); if (tagName.equals("@propertySetter") || tagName.equals("@propertyGetter") || tagName.equals("@propertyDescription")) { ! if (!isPropertyGetterOrSetter(members, methodDoc)) { ! configuration.message.warning(tag.position(), "doclet.javafx_tag_misuse"); } break; } } } } } ! private boolean isPropertyGetterOrSetter(MethodDoc[] members, ! MethodDoc methodDoc) { ! boolean found = false; ! String propertyName = utils.propertyNameFromMethodName(configuration, methodDoc.name()); if (!propertyName.isEmpty()) { String propertyMethodName = propertyName + "Property"; ! for (MethodDoc member: members) { ! if (member.name().equals(propertyMethodName)) { ! found = true; ! break; } } } ! return found; } } private class GetterSetter { ! private final ProgramElementDoc getter; ! private final ProgramElementDoc setter; ! public GetterSetter(ProgramElementDoc getter, ProgramElementDoc setter) { this.getter = getter; this.setter = setter; } ! public ProgramElementDoc getGetter() { return getter; } ! public ProgramElementDoc getSetter() { return setter; } } /** --- 590,750 ---- addToPropertiesMap(setter, field); addToPropertiesMap(propertyMethod, field); } } ! private void addToPropertiesMap(Element propertyMethod, ! Element commentSource) { if (null == propertyMethod || null == commentSource) { return; } ! DocCommentTree docTree = utils.getDocCommentTree(propertyMethod); /* The second condition is required for the property buckets. In * this case the comment is at the property method (not at the field) * and it needs to be listed in the map. */ ! if ((docTree == null) || propertyMethod.equals(commentSource)) { classPropertiesMap.put(propertyMethod, commentSource); } } ! private ExecutableElement getterForField(List<ExecutableElement> methods, ! ExecutableElement propertyMethod) { ! final String propertyMethodName = utils.getSimpleName(propertyMethod); ! final String fieldName = propertyMethodName.substring(0, propertyMethodName.lastIndexOf("Property")); final String fieldNameUppercased = "" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); final String getterNamePattern; ! final String fieldTypeName = propertyMethod.getReturnType().toString(); if ("boolean".equals(fieldTypeName) || fieldTypeName.endsWith("BooleanProperty")) { getterNamePattern = "(is|get)" + fieldNameUppercased; } else { getterNamePattern = "get" + fieldNameUppercased; } ! for (ExecutableElement method : methods) { ! if (Pattern.matches(getterNamePattern, utils.getSimpleName(method))) { ! if (method.getParameters().isEmpty() && ! utils.isPublic(method) || utils.isProtected(method)) { ! return method; } } } return null; } ! private ExecutableElement setterForField(List<ExecutableElement> methods, ! ExecutableElement propertyMethod) { ! final String propertyMethodName = utils.getSimpleName(propertyMethod); final String fieldName = propertyMethodName.substring(0, propertyMethodName.lastIndexOf("Property")); final String fieldNameUppercased = "" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); final String setter = "set" + fieldNameUppercased; ! for (ExecutableElement method : methods) { ! if (setter.equals(utils.getSimpleName(method))) { ! if (method.getParameters().size() == 1 ! && method.getReturnType().getKind() == TypeKind.VOID ! && (utils.isPublic(method) || utils.isProtected(method))) { ! return method; } } } return null; } ! private VariableElement fieldForProperty(List<VariableElement> fields, ExecutableElement property) { ! for (VariableElement field : fields) { ! final String fieldName = utils.getSimpleName(field); final String propertyName = fieldName + "Property"; ! if (propertyName.equals(utils.getSimpleName(property))) { return field; } } return null; } ! private boolean isPropertyMethod(ExecutableElement method) { if (!configuration.javafx) { return false; } ! if (!utils.getSimpleName(method).endsWith("Property")) { return false; } ! if (!memberIsVisible(method)) { return false; } ! if (GETTERSETTERPATTERN.matcher(utils.getSimpleName(method)).matches()) { return false; } ! if (!method.getTypeParameters().isEmpty()) { return false; } ! return method.getParameters().isEmpty() ! && method.getReturnType().getKind() != TypeKind.VOID; } ! private void checkOnPropertiesTags(List<? extends Element> members) { ! for (Element e: members) { ! ExecutableElement ee = (ExecutableElement)e; ! if (utils.isIncluded(ee)) { ! CommentHelper ch = utils.getCommentHelper(ee); ! for (DocTree tree: utils.getBlockTags(ee)) { ! String tagName = ch.getTagName(tree); if (tagName.equals("@propertySetter") || tagName.equals("@propertyGetter") || tagName.equals("@propertyDescription")) { ! if (!isPropertyGetterOrSetter(members, ee)) { ! configuration.message.warning(ch.getDocTreePath(tree), "doclet.javafx_tag_misuse"); } break; } } } } } ! private boolean isPropertyGetterOrSetter(List<? extends Element> members, ! ExecutableElement method) { ! String propertyName = utils.propertyName(method); if (!propertyName.isEmpty()) { String propertyMethodName = propertyName + "Property"; ! for (Element member: members) { ! if (utils.getSimpleName(member).equals(propertyMethodName)) { ! return true; } } } ! return false; } } private class GetterSetter { ! private final Element getter; ! private final Element setter; ! public GetterSetter(Element getter, Element setter) { this.getter = getter; this.setter = setter; } ! public Element getGetter() { return getter; } ! public Element getSetter() { return setter; } } /**
*** 738,771 **** */ public boolean noVisibleMembers() { return noVisibleMembers; } ! private ClassMember getClassMember(MethodDoc member) { for (Object key : memberNameMap.keySet()) { if (key instanceof String) { continue; ! } else if (((ClassMember) key).isEqual(member)) { return (ClassMember) key; } } return new ClassMember(member); } /** * Return the key to the member map for the given member. */ ! private Object getMemberKey(ProgramElementDoc doc) { ! if (doc.isConstructor()) { ! return doc.name() + ((ExecutableMemberDoc)doc).signature(); ! } else if (doc.isMethod()) { ! return getClassMember((MethodDoc) doc); ! } else if (doc.isField() || doc.isEnumConstant() || doc.isAnnotationTypeElement()) { ! return doc.name(); } else { // it's a class or interface ! String classOrIntName = doc.name(); //Strip off the containing class name because we only want the member name. ! classOrIntName = classOrIntName.indexOf('.') != 0 ? classOrIntName.substring(classOrIntName.lastIndexOf('.'), classOrIntName.length()) : classOrIntName; return "clint" + classOrIntName; } } } --- 754,790 ---- */ public boolean noVisibleMembers() { return noVisibleMembers; } ! private ClassMember getClassMember(ExecutableElement member) { for (Object key : memberNameMap.keySet()) { if (key instanceof String) { continue; ! } ! if (((ClassMember) key).isEqual(member)) { return (ClassMember) key; } } return new ClassMember(member); } /** * Return the key to the member map for the given member. */ ! private Object getMemberKey(Element element) { ! if (utils.isConstructor(element)) { ! return utils.getSimpleName(element) + utils.flatSignature((ExecutableElement)element); ! } else if (utils.isMethod(element)) { ! return getClassMember((ExecutableElement) element); ! } else if (utils.isField(element) || utils.isEnumConstant(element) || utils.isAnnotationType(element)) { ! return utils.getSimpleName(element); } else { // it's a class or interface ! String classOrIntName = utils.getSimpleName(element); //Strip off the containing class name because we only want the member name. ! classOrIntName = classOrIntName.indexOf('.') != 0 ! ? classOrIntName.substring(classOrIntName.lastIndexOf('.')) ! : classOrIntName; return "clint" + classOrIntName; } } }