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;
}
}
}