Thank you for your help, Jon.
I've rewritten it a bit (also had to change the Util.executableMembersEqual
method to fix some issues),
so now all the tests should pass and I have fixed some other bugs.
Now the order of classes is the same and order of interfaces is mostly the same.
I tried to get as close to the original as possible, but although it seems I'm
traversing the inheritance tree the same way as original implementation, I'm
unable to retain
the exact original order. But in most cases it is the same. What are the
reasons for the
order to stay the same?
I tried to do the diff on java.lang and java.util and there are some
differences, but I'm not
sure which version is correct:
1. In java.lang.StringBuilder there is a section 'Methods inherited from
interface CharSequence'.
In the original version it contains charAt, chars, codePoints, length,
subSequence and in mine
contains just chars, codePoints. But the methods charAt, length and
subSequence are overriden
by the StringBuilder class, so I don't think they should be there. What do
you think?
The same thing appears in other classes, for example ArrayList.
2. AbstractQueue (and other Collections) - similar case as the above, but the
methods are overriden in
one of the parent classes.
3. In HashMap (and any other implementations of Map) there is no MapEntry inner
interface in the
original version, whereas in mine there is. It is public inner interface and
it is not hidden
by anything, so I cannot see a reason why it shouldn't be there.
Michael
diff -r 571f8ebc2d51 src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java
--- a/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java Sun Sep 22 12:53:03 2013 +0100
+++ b/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java Mon Sep 23 13:49:08 2013 +0200
@@ -139,27 +139,30 @@
MethodDoc method1 = (MethodDoc) member1;
MethodDoc method2 = (MethodDoc) member2;
+ Parameter[] targetParams = method1.parameters();
+ Parameter[] currentParams = method2.parameters();
+
+ if(!method1.name().equals(method2.name())
+ || currentParams.length != targetParams.length)
+ return false;
+
if (method1.isStatic() && method2.isStatic()) {
- Parameter[] targetParams = method1.parameters();
- Parameter[] currentParams;
- if (method1.name().equals(method2.name()) &&
- (currentParams = method2.parameters()).length ==
- targetParams.length) {
- int j;
- for (j = 0; j < targetParams.length; j++) {
+ for (int j = 0; j < targetParams.length; j++) {
if (! (targetParams[j].typeName().equals(
- currentParams[j].typeName()) ||
- currentParams[j].type() instanceof TypeVariable ||
- targetParams[j].type() instanceof TypeVariable)) {
- break;
+ currentParams[j].typeName())) ||
+ targetParams[j].type().getClass() != currentParams[j].type().getClass()) {
+ return false;
}
}
- if (j == targetParams.length) {
- return true;
+ return true;
+ } else {
+ for (int i = 0; i < targetParams.length; i++) {
+ if (!(targetParams[i].type().getClass() == currentParams[i].type().getClass()
+ || targetParams[i].type() instanceof TypeVariable
+ || currentParams[i].type() instanceof TypeVariable)) {
+ return false;
+ }
}
- }
- return false;
- } else {
return method1.overrides(method2) ||
method2.overrides(method1) ||
member1 == member2;
diff -r 571f8ebc2d51 src/share/classes/com/sun/tools/doclets/internal/toolkit/util/VisibleMemberMap.java
--- a/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/VisibleMemberMap.java Sun Sep 22 12:53:03 2013 +0100
+++ b/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/VisibleMemberMap.java Mon Sep 23 13:49:08 2013 +0200
@@ -48,8 +48,6 @@
*/
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;
@@ -71,23 +69,15 @@
* 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.
+ * Maps classes to their visible members
*/
- private final Map<Object,Map<ProgramElementDoc,String>> memberNameMap = new HashMap<Object,Map<ProgramElementDoc,String>>();
-
+ private final Map<ClassDoc, List<ProgramElementDoc>> memberMap = new HashMap<>();
+
/**
* 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;
/**
@@ -124,7 +114,7 @@
this.classdoc = classdoc;
this.kind = kind;
this.configuration = configuration;
- new ClassMembers(classdoc, STARTLEVEL).build();
+ new MapBuilder().build();
}
/**
@@ -207,11 +197,7 @@
* @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();
+ return memberMap.get(cd);
}
/**
@@ -234,157 +220,134 @@
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);
+ private class MapBuilder {
+ Map<ClassDoc, Integer> levelMap = new HashMap<>();
+
+ public void build() {
+ switch (kind) {
+ case CONSTRUCTORS:
+ List<ProgramElementDoc> ctors = new ArrayList<>();
+ for (ProgramElementDoc member : getClassMembers(classdoc, true)) {
+ if (member instanceof ConstructorDoc && memberIsVisible(member)
+ && !isTreatedAsPrivate(member)) {
+ ctors.add(member);
+ }
+ }
+ memberMap.put(classdoc, ctors);
+ break;
+ case METHODS:
+ fillMethodMap(classdoc, new HashSet<MethodWrapper>(), 0);
+ break;
+ default:
+ fillMap(classdoc, new HashMap<String, ProgramElementDoc>(), 0);
}
- memberLevelMap.put(list.get(i), level);
}
- }
+
+ private class MethodWrapper {
+ private final MethodDoc method;
+
+ public MethodWrapper(MethodDoc method) {
+ this.method = method;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof MethodWrapper)) return false;
+ MethodWrapper m = (MethodWrapper)o;
+ return Util.executableMembersEqual(method, m.method);
+ }
+
+ @Override
+ public int hashCode() {
+ return method.name().hashCode();
+ }
- 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 (level.equals(memberLevelMap.get(list.get(i))))
- memberLevelMap.remove(list.get(i));
+ @Override
+ public String toString() {
+ return method.toString();
+ }
}
- }
-
- /**
- * 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;
+
+ private void fillMap(ClassDoc clazz, Map<String, ProgramElementDoc> memberAcc, int level) {
+ int thatLevel = 0;
+ if (!levelMap.containsKey(clazz)) {
+ levelMap.put(clazz, level);
+ } else {
+ thatLevel = levelMap.get(clazz);
+ if (thatLevel < level) {
+ levelMap.put(clazz, level);
}
}
- return false;
- }
- }
- /**
- * A data structure that represents the class members for
- * a visible class.
- */
- private class ClassMembers {
+ if (thatLevel <= level) {
+ List<ProgramElementDoc> members = new ArrayList<>();
+ for (ProgramElementDoc member : getClassMembers(clazz, true)) {
+ if (memberIsVisible(member) && !isTreatedAsPrivate(member)) {
+ String key = member.name().substring(member.name().lastIndexOf(".") + 1);
+ if (!memberAcc.containsKey(key)) {
+ memberAcc.put(key, member);
+ members.add(member);
+ }
+ }
+ }
- /**
- * The mapping class, whose inherited members are put in the
- * {@link #members} list.
- */
- private ClassDoc mappingClass;
+ if (level != 0 && thatLevel == level) {
+ memberMap.get(clazz).retainAll(members);
+ } else {
+ memberMap.put(clazz, members);
+ visibleClasses.remove(clazz);
+ visibleClasses.add(clazz);
+ }
- /**
- * List of inherited members from the mapping class.
- */
- private List<ProgramElementDoc> members = new ArrayList<ProgramElementDoc>();
+ for (ClassDoc inf : clazz.interfaces()) {
+ fillMap(inf, new HashMap<>(memberAcc), level + 1);
+ }
- /**
- * 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();
+ if (clazz.isClass() && clazz.superclass() != null) {
+ fillMap(clazz.superclass(), memberAcc, level + 1);
}
}
}
- /**
- * 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);
+ private void fillMethodMap(ClassDoc clazz, Set<MethodWrapper> found, int level) {
+ int thatLevel = 0;
+ if (!levelMap.containsKey(clazz)) {
+ levelMap.put(clazz, level);
+ } else {
+ thatLevel = levelMap.get(clazz);
+ if (thatLevel < level) {
+ levelMap.put(clazz, level);
}
}
- if (incllist.size() > 0) {
- noVisibleMembers = false;
- }
- members.addAll(incllist);
- fillMemberLevelMap(getClassMembers(fromClass, false), level);
+
+ if (thatLevel <= level) {
+ visibleClasses.remove(clazz);
+ visibleClasses.add(clazz);
+ List<ProgramElementDoc> members = new ArrayList<>();
+ for (ProgramElementDoc member : getClassMembers(clazz, true)) {
+ if (memberIsVisible(member) && !isTreatedAsPrivate(member)) {
+ MethodWrapper wrapper = new MethodWrapper((MethodDoc) member);
+ if (!found.contains(wrapper)) {
+ found.add(wrapper);
+ members.add(member);
+ }
+ }
+ }
+
+ if (level != 0 && thatLevel == level) {
+ memberMap.get(clazz).retainAll(members);
+ } else {
+ memberMap.put(clazz, members);
+ }
+
+ for (ClassDoc inf : clazz.interfaces()) {
+ fillMethodMap(inf, new HashSet<>(found), level + 1);
+ }
+
+ if (clazz.isClass() && clazz.superclass() != null) {
+ fillMethodMap(clazz.superclass(), found, level + 1);
+ }
+ }
}
private boolean isTreatedAsPrivate(ProgramElementDoc pgmelem) {
@@ -500,39 +463,6 @@
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);
@@ -660,7 +590,7 @@
}
return null;
}
-
+
// properties aren't named setA* or getA*
private final Pattern pattern = Pattern.compile("[sg]et\\p{Upper}.*");
private boolean isPropertyMethod(MethodDoc method) {
@@ -740,36 +670,11 @@
* @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;
+ for(List<ProgramElementDoc> lst: memberMap.values()) {
+ if (!lst.isEmpty()) {
+ return false;
}
}
- 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;
- }
+ return true;
}
}