| /* |
| * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * 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. |
| * If you write code that depends on this, you do so at your own risk. |
| * This code and its internal interfaces are subject to change or |
| * deletion without notice.</b> |
| * |
| * @author Atul M Dambalkar |
| * @author Jamie Ho (rewrite) |
| */ |
| 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<ClassDoc>(); |
| |
| /** |
| * 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<Object,Map<ProgramElementDoc,String>>(); |
| |
| /** |
| * Map of class and it's ClassMembers object. |
| */ |
| private final Map<ClassDoc,ClassMembers> classMap = new HashMap<ClassDoc,ClassMembers>(); |
| |
| /** |
| * 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 static final Map<ClassDoc, ProgramElementDoc[]> propertiesCache = |
| new HashMap<ClassDoc, ProgramElementDoc[]>(); |
| private static final Map<ProgramElementDoc, ProgramElementDoc> classPropertiesMap = |
| new HashMap<ProgramElementDoc, ProgramElementDoc>(); |
| private static final Map<ProgramElementDoc, GetterSetter> getterSetterMap = |
| new HashMap<ProgramElementDoc, GetterSetter>(); |
| |
| /** |
| * 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; |
| 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<ProgramElementDoc>(); |
| for (Iterator<ClassDoc> iter = visibleClasses.iterator(); iter.hasNext(); ) { |
| ClassDoc currentClass = iter.next(); |
| if (currentClass != classdoc && |
| currentClass.isPackagePrivate() && |
| !Util.isLinkable(currentClass, configuration)) { |
| // Document these members in the child class because |
| // the parent is inaccessible. |
| results.addAll(getMembersFor(currentClass)); |
| } |
| } |
| return results; |
| } |
| |
| /** |
| * Return the visible members of the class being mapped. Also append at the |
| * 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<ProgramElementDoc>(); |
| } |
| 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<ClassDoc>(); |
| List<ClassDoc> interfaces = new ArrayList<ClassDoc>(); |
| for (int i = 0; i < list.size(); i++) { |
| ClassDoc cd = list.get(i); |
| 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 (int i = 0; i < list.size(); i++) { |
| Object key = getMemberKey(list.get(i)); |
| Map<ProgramElementDoc,String> memberLevelMap = memberNameMap.get(key); |
| if (memberLevelMap == null) { |
| memberLevelMap = new HashMap<ProgramElementDoc,String>(); |
| memberNameMap.put(key, memberLevelMap); |
| } |
| memberLevelMap.put(list.get(i), level); |
| } |
| } |
| |
| private void purgeMemberLevelMap(List<ProgramElementDoc> list, String level) { |
| for (int i = 0; i < list.size(); i++) { |
| Object key = getMemberKey(list.get(i)); |
| Map<ProgramElementDoc, String> memberLevelMap = memberNameMap.get(key); |
| if (memberLevelMap != null && level.equals(memberLevelMap.get(list.get(i)))) |
| memberLevelMap.remove(list.get(i)); |
| } |
| } |
| |
| /** |
| * 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<ProgramElementDoc>(); |
| members.add(programElementDoc); |
| } |
| |
| public void addMember(ProgramElementDoc programElementDoc) { |
| members.add(programElementDoc); |
| } |
| |
| public boolean isEqual(MethodDoc member) { |
| for (Iterator<ProgramElementDoc> iter = members.iterator(); iter.hasNext(); ) { |
| MethodDoc member2 = (MethodDoc) iter.next(); |
| if (Util.executableMembersEqual(member, member2)) { |
| members.add(member); |
| return true; |
| } |
| } |
| return false; |
| } |
| } |
| |
| /** |
| * A data structure that represents the class members for |
| * a visible class. |
| */ |
| private class ClassMembers { |
| |
| /** |
| * 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<ProgramElementDoc>(); |
| |
| /** |
| * 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. |
| purgeMemberLevelMap(getClassMembers(mappingClass, false), |
| classMap.get(mappingClass).level); |
| classMap.remove(mappingClass); |
| visibleClasses.remove(mappingClass); |
| } |
| 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 (int i = 0; i < interfaces.length; i++) { |
| String locallevel = level + 1; |
| ClassMembers cm = new ClassMembers(interfaces[i], 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(); |
| } |
| } |
| } |
| |
| /** |
| * Get all the valid members from the mapping class. Get the list of |
| * members for the class to be included into(ctii), also get the level |
| * 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<ProgramElementDoc>(); |
| for (int i = 0; i < cdmembers.size(); i++) { |
| ProgramElementDoc pgmelem = cdmembers.get(i); |
| 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 Util.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<AnnotationTypeElementDoc>(); |
| for (int i = 0; i < members.length; i++) { |
| if ((required && members[i].defaultValue() == null) || |
| ((!required) && members[i].defaultValue() != null)){ |
| targetMembers.add(members[i]); |
| } |
| } |
| return targetMembers.toArray(new AnnotationTypeElementDoc[]{}); |
| } |
| |
| private boolean found(List<ProgramElementDoc> list, ProgramElementDoc elem) { |
| for (int i = 0; i < list.size(); i++) { |
| ProgramElementDoc pgmelem = list.get(i); |
| if (Util.matches(pgmelem, elem)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| |
| /** |
| * 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; |
| String mappedlevel = null; |
| Iterator<String> iterator = memberLevelMap.values().iterator(); |
| while (iterator.hasNext()) { |
| mappedlevel = iterator.next(); |
| 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<MethodDoc>(); |
| |
| 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); |
| 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 (!method.name().endsWith("Property")) { |
| return false; |
| } |
| |
| if (! memberIsVisible(method)) { |
| return false; |
| } |
| |
| if (pattern.matcher(method.name()).matches()) { |
| 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 = Util.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; |
| } |
| } |
| |
| /** |
| * Return true if this map has no visible members. |
| * |
| * @return true if this map has no visible members. |
| */ |
| public boolean noVisibleMembers() { |
| return noVisibleMembers; |
| } |
| |
| private ClassMember getClassMember(MethodDoc member) { |
| for (Iterator<?> iter = memberNameMap.keySet().iterator(); iter.hasNext();) { |
| Object key = iter.next(); |
| 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; |
| } |
| } |
| } |