--- old/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/VisibleMemberMap.java Fri Jan 22 12:20:49 2016
+++ /dev/null Fri Jan 22 12:20:49 2016
@@ -1,771 +0,0 @@
-/*
- * 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.
- *
- *
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.
- *
- * @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 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> memberNameMap = new HashMap<>();
-
- /**
- * Map of class and it's ClassMembers object.
- */
- private final Map 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 propertiesCache = new HashMap<>();
- private static final Map classPropertiesMap = new HashMap<>();
- private static final Map 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 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 getInheritedPackagePrivateMethods(Configuration configuration) {
- List 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;
- }
-
- /**
- * 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 getLeafClassMembers(Configuration configuration) {
- List 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 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 list) {
- List classes = new ArrayList<>();
- List 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 list, String level) {
- for (ProgramElementDoc element : list) {
- Object key = getMemberKey(element);
- Map memberLevelMap = memberNameMap.get(key);
- if (memberLevelMap == null) {
- memberLevelMap = new HashMap<>();
- memberNameMap.put(key, memberLevelMap);
- }
- memberLevelMap.put(element, level);
- }
- }
-
- private void purgeMemberLevelMap(List list, String level) {
- for (ProgramElementDoc element : list) {
- Object key = getMemberKey(element);
- Map 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 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;
- }
- }
-
- /**
- * 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 members = new ArrayList<>();
-
- /**
- * Level/Depth of inheritance.
- */
- private String level;
-
- /**
- * Return list of inherited members from mapping class.
- *
- * @return List Inherited members.
- */
- public List 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 (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();
- }
- }
- }
-
- /**
- * 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 cdmembers = getClassMembers(fromClass, true);
- List 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 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 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 list, ProgramElementDoc elem) {
- for (ProgramElementDoc pgmelem : list) {
- if (utils.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;
- 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 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);
- 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;
- }
- }
-
- /**
- * 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 (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;
- }
- }
-}
--- /dev/null Fri Jan 22 12:20:49 2016
+++ new/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberMap.java Fri Jan 22 12:20:48 2016
@@ -0,0 +1,790 @@
+/*
+ * 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 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.
+ *
+ * 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.
+ *
+ * @author Atul M Dambalkar
+ * @author Jamie Ho (rewrite)
+ */
+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 summarySet = EnumSet.range(INNER_CLASSES, METHODS);
+ public static final EnumSet 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 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> memberNameMap = new HashMap<>();
+
+ /**
+ * Map of class and it's ClassMembers object.
+ */
+ private final Map 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 comparator;
+
+ private static final Map> propertiesCache = new HashMap<>();
+ private static final Map classPropertiesMap = new HashMap<>();
+ private static final Map 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 getVisibleClasses() {
+ SortedSet 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 getInheritedPackagePrivateMethods() {
+ List 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;
+ }
+
+ /**
+ * 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 SortedSet getLeafClassMembers() {
+ SortedSet result = getMembersFor(typeElement);
+ result.addAll(getInheritedPackagePrivateMethods());
+ return result;
+ }
+
+ public Set getLeafClassMembersSourceOrder() {
+ Set 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 getMembersFor(TypeElement typeElement) {
+ return asSortedSet(classMap.get(typeElement).members);
+ }
+
+ public boolean hasMembersFor(TypeElement typeElement) {
+ return !classMap.get(typeElement).members.isEmpty();
+ }
+
+ private SortedSet asSortedSet(Collection in) {
+ if (in == null) {
+ return Collections.emptySortedSet();
+ }
+ TreeSet 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 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 memberLevelMap = memberNameMap.get(key);
+ if (memberLevelMap != null && level.equals(memberLevelMap.get(element)))
+ memberLevelMap.remove(element);
+ }
+ }
+
+ /**
+ * Represents a class member.
+ */
+ private class ClassMember {
+ private Set 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;
+ }
+ }
+
+ /**
+ * 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 final TypeElement typeElement;
+
+ /**
+ * List of inherited members from the mapping class.
+ */
+ private Set 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.
+ 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 == 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();
+ }
+ }
+ }
+
+ /**
+ * 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(TypeElement fromClass) {
+ List extends Element> classMembers = getClassMembers(fromClass, true);
+ List 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 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 filterAnnotations(TypeElement typeElement, boolean required) {
+ List members = utils.getAnnotationMethods(typeElement);
+ List 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 list, Element elem) {
+ for (Element pgmelem : list) {
+ if (utils.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(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 properties(final TypeElement typeElement, final boolean filter) {
+ final List allMethods = filter
+ ? utils.getMethods(typeElement)
+ : utils.getMethodsUnfiltered(typeElement);
+ final List allFields = utils.getFieldsUnfiltered(typeElement);
+
+ if (propertiesCache.containsKey(typeElement)) {
+ return propertiesCache.get(typeElement);
+ }
+
+ final List 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);
+ 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 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 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 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;
+ }
+ }
+
+ /**
+ * 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(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;
+ }
+ }
+}