8050031: [javadoc] class-use pages have duplicates and missing entries
authorksrini
Wed, 27 Aug 2014 06:56:29 -0700
changeset 26270 a3635e6d3d78
parent 26269 0d8efbb110b4
child 26271 97603426a4ce
8050031: [javadoc] class-use pages have duplicates and missing entries Reviewed-by: jjg
langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/AbstractTreeWriter.java
langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java
langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java
langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/ClassTree.java
langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/ClassUseMapper.java
langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/Utils.java
langtools/test/com/sun/javadoc/lib/JavadocTester.java
langtools/test/com/sun/javadoc/testOrdering/TestOrdering.java
langtools/test/com/sun/javadoc/testUseOption/TestUseOption.java
langtools/test/com/sun/javadoc/testUseOption/unique/C1.java
langtools/test/com/sun/javadoc/testUseOption/unique/UseMe.java
--- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/AbstractTreeWriter.java	Tue Aug 26 08:12:42 2014 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/AbstractTreeWriter.java	Wed Aug 27 06:56:29 2014 -0700
@@ -82,10 +82,9 @@
      * @param isEnum true if we are generating a tree for enums
      * @param contentTree the content tree to which the level information will be added
      */
-    protected void addLevelInfo(ClassDoc parent, List<ClassDoc> list,
+    protected void addLevelInfo(ClassDoc parent, Collection<ClassDoc> list,
             boolean isEnum, Content contentTree) {
-        int size = list.size();
-        if (size > 0) {
+        if (!list.isEmpty()) {
             Content ul = new HtmlTree(HtmlTag.UL);
             for (ClassDoc local : list) {
                 HtmlTree li = new HtmlTree(HtmlTag.LI);
@@ -109,9 +108,9 @@
      * @param heading heading for the tree
      * @param div the content tree to which the tree will be added
      */
-    protected void addTree(List<ClassDoc> list, String heading, Content div) {
-        if (list.size() > 0) {
-            ClassDoc firstClassDoc = list.get(0);
+    protected void addTree(SortedSet<ClassDoc> list, String heading, Content div) {
+        if (!list.isEmpty()) {
+            ClassDoc firstClassDoc = list.first();
             Content headingContent = getResource(heading);
             div.addContent(HtmlTree.HEADING(HtmlConstants.CONTENT_HEADING, true,
                     headingContent));
--- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java	Tue Aug 26 08:12:42 2014 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java	Wed Aug 27 06:56:29 2014 -0700
@@ -158,7 +158,7 @@
      */
     public static void generate(ConfigurationImpl configuration,
                                 ClassTree classtree)  {
-        ClassUseMapper mapper = new ClassUseMapper(configuration.root, classtree);
+        ClassUseMapper mapper = new ClassUseMapper(configuration, classtree);
         for (ClassDoc aClass : configuration.root.classes()) {
             // If -nodeprecated option is set and the containing package is marked
             // as deprecated, do not generate the class-use page. We will still generate
--- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java	Tue Aug 26 08:12:42 2014 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java	Wed Aug 27 06:56:29 2014 -0700
@@ -411,8 +411,8 @@
                     classDoc.qualifiedName().equals("org.omg.CORBA.Object")) {
                 return;    // Don't generate the list, too huge
             }
-            List<ClassDoc> subclasses = classtree.subs(classDoc, false);
-            if (subclasses.size() > 0) {
+            SortedSet<ClassDoc> subclasses = classtree.subs(classDoc, false);
+            if (!subclasses.isEmpty()) {
                 Content label = getResource(
                         "doclet.Subclasses");
                 Content dt = HtmlTree.DT(label);
@@ -429,8 +429,8 @@
      */
     public void addSubInterfacesInfo(Content classInfoTree) {
         if (classDoc.isInterface()) {
-            List<ClassDoc> subInterfaces = classtree.allSubs(classDoc, false);
-            if (subInterfaces.size() > 0) {
+            SortedSet<ClassDoc> subInterfaces = classtree.allSubs(classDoc, false);
+            if (!subInterfaces.isEmpty()) {
                 Content label = getResource(
                         "doclet.Subinterfaces");
                 Content dt = HtmlTree.DT(label);
@@ -453,8 +453,8 @@
                 classDoc.qualifiedName().equals("java.io.Serializable")) {
             return;   // Don't generate the list, too big
         }
-        List<ClassDoc> implcl = classtree.implementingclasses(classDoc);
-        if (implcl.size() > 0) {
+        SortedSet<ClassDoc> implcl = classtree.implementingclasses(classDoc);
+        if (!implcl.isEmpty()) {
             Content label = getResource(
                     "doclet.Implementing_Classes");
             Content dt = HtmlTree.DT(label);
@@ -580,21 +580,23 @@
      * @param list the list of classes
      * @return a content tree for the class list
      */
-    private Content getClassLinks(LinkInfoImpl.Kind context, List<?> list) {
+    private Content getClassLinks(LinkInfoImpl.Kind context, Collection<?> list) {
         Object[] typeList = list.toArray();
         Content dd = new HtmlTree(HtmlTag.DD);
-        for (int i = 0; i < list.size(); i++) {
-            if (i > 0) {
+        boolean isFirst = true;
+        for (Object item : typeList) {
+            if (!isFirst) {
                 Content separator = new StringContent(", ");
                 dd.addContent(separator);
+            } else {
+                isFirst = false;
             }
-            if (typeList[i] instanceof ClassDoc) {
-                Content link = getLink(
-                        new LinkInfoImpl(configuration, context, (ClassDoc)(typeList[i])));
+
+            if (item instanceof ClassDoc) {
+                Content link = getLink(new LinkInfoImpl(configuration, context, (ClassDoc)item));
                 dd.addContent(link);
             } else {
-                Content link = getLink(
-                        new LinkInfoImpl(configuration, context, (Type)(typeList[i])));
+                Content link = getLink(new LinkInfoImpl(configuration, context, (Type)item));
                 dd.addContent(link);
             }
         }
--- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/ClassTree.java	Tue Aug 26 08:12:42 2014 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/ClassTree.java	Wed Aug 27 06:56:29 2014 -0700
@@ -51,38 +51,39 @@
      * List of baseclasses. Contains only java.lang.Object. Can be used to get
      * the mapped listing of sub-classes.
      */
-    private List<ClassDoc> baseclasses = new ArrayList<>();
+    final private SortedSet<ClassDoc> baseclasses;
 
     /**
     * Mapping for each Class with their SubClasses
     */
-    private Map<ClassDoc,List<ClassDoc>> subclasses = new HashMap<>();
+    final private Map<ClassDoc, SortedSet<ClassDoc>> subclasses = new HashMap<>();
 
     /**
      * List of base-interfaces. Contains list of all the interfaces who do not
      * have super-interfaces. Can be used to get the mapped listing of
      * sub-interfaces.
      */
-    private List<ClassDoc> baseinterfaces = new ArrayList<>();
+    final private SortedSet<ClassDoc> baseinterfaces;
 
     /**
     * Mapping for each Interface with their SubInterfaces
     */
-    private Map<ClassDoc,List<ClassDoc>> subinterfaces = new HashMap<>();
+    final private Map<ClassDoc, SortedSet<ClassDoc>> subinterfaces = new HashMap<>();
 
-    private List<ClassDoc> baseEnums = new ArrayList<>();
-    private Map<ClassDoc,List<ClassDoc>> subEnums = new HashMap<>();
+    final private SortedSet<ClassDoc> baseEnums;
+    final private Map<ClassDoc, SortedSet<ClassDoc>> subEnums = new HashMap<>();
 
-    private List<ClassDoc> baseAnnotationTypes = new ArrayList<>();
-    private Map<ClassDoc,List<ClassDoc>> subAnnotationTypes = new HashMap<>();
+    final private SortedSet<ClassDoc> baseAnnotationTypes;
+    final private Map<ClassDoc, SortedSet<ClassDoc>> subAnnotationTypes = new HashMap<>();
 
     /**
     * Mapping for each Interface with classes who implement it.
     */
-    private Map<ClassDoc,List<ClassDoc>> implementingclasses = new HashMap<>();
+    final private Map<ClassDoc, SortedSet<ClassDoc>> implementingclasses = new HashMap<>();
 
     private final Configuration configuration;
     private final Utils utils;
+    private final Comparator<Doc> comparator;
     /**
      * Constructor. Build the Tree using the Root of this Javadoc run.
      *
@@ -94,7 +95,13 @@
         configuration.message.notice("doclet.Building_Tree");
         this.configuration = configuration;
         this.utils = configuration.utils;
+        comparator = utils.makeGeneralPurposeComparator();
+        baseAnnotationTypes = new TreeSet<>(comparator);
+        baseEnums = new TreeSet<>(comparator);
+        baseclasses = new TreeSet<>(comparator);
+        baseinterfaces = new TreeSet<>(comparator);
         buildTree(configuration.root.classes());
+
     }
 
     /**
@@ -106,6 +113,11 @@
     public ClassTree(RootDoc root, Configuration configuration) {
         this.configuration = configuration;
         this.utils = configuration.utils;
+        comparator = utils.makeGeneralPurposeComparator();
+        baseAnnotationTypes = new TreeSet<>(comparator);
+        baseEnums = new TreeSet<>(comparator);
+        baseclasses = new TreeSet<>(comparator);
+        baseinterfaces = new TreeSet<>(comparator);
         buildTree(root.classes());
     }
 
@@ -113,11 +125,16 @@
      * Constructor. Build the tree for the given array of classes.
      *
      * @param classes Array of classes.
-     * @param configuration The curren configuration of the doclet.
+     * @param configuration The current configuration of the doclet.
      */
     public ClassTree(ClassDoc[] classes, Configuration configuration) {
         this.configuration = configuration;
         this.utils = configuration.utils;
+        comparator = utils.makeGeneralPurposeComparator();
+        baseAnnotationTypes = new TreeSet<>(comparator);
+        baseEnums = new TreeSet<>(comparator);
+        baseclasses = new TreeSet<>(comparator);
+        baseinterfaces = new TreeSet<>(comparator);
         buildTree(classes);
     }
 
@@ -152,23 +169,11 @@
                 processType(aClass, configuration, baseclasses, subclasses);
             } else if (aClass.isInterface()) {
                 processInterface(aClass);
-                List<ClassDoc> list = implementingclasses.get(aClass);
-                if (list != null) {
-                    Collections.sort(list);
-                }
             } else if (aClass.isAnnotationType()) {
                 processType(aClass, configuration, baseAnnotationTypes,
                     subAnnotationTypes);
             }
         }
-
-        Collections.sort(baseinterfaces);
-        for (List<ClassDoc> docs : subinterfaces.values()) {
-            Collections.sort(docs);
-        }
-        for (List<ClassDoc> docs : subclasses.values()) {
-            Collections.sort(docs);
-        }
     }
 
     /**
@@ -184,7 +189,7 @@
      * @param configuration the current configurtation of the doclet.
      */
     private void processType(ClassDoc cd, Configuration configuration,
-            List<ClassDoc> bases, Map<ClassDoc,List<ClassDoc>> subs) {
+            Collection<ClassDoc> bases, Map<ClassDoc, SortedSet<ClassDoc>> subs) {
         ClassDoc superclass = utils.getFirstVisibleSuperClassCD(cd, configuration);
         if (superclass != null) {
             if (!add(subs, superclass, cd)) {
@@ -239,10 +244,10 @@
      * @param cd sub-interface to be mapped.
      * @returns boolean true if class added, false if class already processed.
      */
-    private boolean add(Map<ClassDoc,List<ClassDoc>> map, ClassDoc superclass, ClassDoc cd) {
-        List<ClassDoc> list = map.get(superclass);
+    private boolean add(Map<ClassDoc, SortedSet<ClassDoc>> map, ClassDoc superclass, ClassDoc cd) {
+        SortedSet<ClassDoc> list = map.get(superclass);
         if (list == null) {
-            list = new ArrayList<>();
+            list = new TreeSet<>(comparator);
             map.put(superclass, list);
         }
         if (list.contains(cd)) {
@@ -261,12 +266,12 @@
      * @param cd class for which the sub-class list is requested.
      * @returns List Sub-Class list for the class passed.
      */
-    private List<ClassDoc> get(Map<ClassDoc,List<ClassDoc>> map, ClassDoc cd) {
-        List<ClassDoc> list = map.get(cd);
-        if (list == null) {
-            return new ArrayList<>();
+    private SortedSet<ClassDoc> get(Map<ClassDoc, SortedSet<ClassDoc>> map, ClassDoc cd) {
+        SortedSet<ClassDoc> aset = map.get(cd);
+        if (aset == null) {
+            return new TreeSet<>(comparator);
         }
-        return list;
+        return aset;
     }
 
     /**
@@ -274,7 +279,7 @@
      *
      * @param cd class whose sub-class list is required.
      */
-    public List<ClassDoc> subclasses(ClassDoc cd) {
+    public SortedSet<ClassDoc> subclasses(ClassDoc cd) {
         return get(subclasses, cd);
     }
 
@@ -283,7 +288,7 @@
      *
      * @param cd interface whose sub-interface list is required.
      */
-    public List<ClassDoc> subinterfaces(ClassDoc cd) {
+    public SortedSet<ClassDoc> subinterfaces(ClassDoc cd) {
         return get(subinterfaces, cd);
     }
 
@@ -292,25 +297,23 @@
      *
      * @param cd interface whose implementing-classes list is required.
      */
-    public List<ClassDoc> implementingclasses(ClassDoc cd) {
-        List<ClassDoc> result = get(implementingclasses, cd);
-        List<ClassDoc> subinterfaces = allSubs(cd, false);
+    public SortedSet<ClassDoc> implementingclasses(ClassDoc cd) {
+        SortedSet<ClassDoc> result = get(implementingclasses, cd);
+        SortedSet<ClassDoc> intfcs = allSubs(cd, false);
 
         //If class x implements a subinterface of cd, then it follows
         //that class x implements cd.
-        Iterator<ClassDoc> implementingClassesIter, subInterfacesIter = subinterfaces.listIterator();
-        ClassDoc c;
-        while(subInterfacesIter.hasNext()){
-            implementingClassesIter = implementingclasses(
-                    subInterfacesIter.next()).listIterator();
-            while(implementingClassesIter.hasNext()){
-                c = implementingClassesIter.next();
-                if(! result.contains(c)){
+        Iterator<ClassDoc> subInterfacesIter = intfcs.iterator();
+        while (subInterfacesIter.hasNext()) {
+            Iterator<ClassDoc> implementingClassesIter
+                    = implementingclasses(subInterfacesIter.next()).iterator();
+            while (implementingClassesIter.hasNext()) {
+                ClassDoc c = implementingClassesIter.next();
+                if (!result.contains(c)) {
                     result.add(c);
                 }
             }
         }
-        Collections.sort(result);
         return result;
     }
 
@@ -321,7 +324,7 @@
      * @param isEnum true if the subclasses should be forced to come from the
      * enum tree.
      */
-    public List<ClassDoc> subs(ClassDoc cd, boolean isEnum) {
+    public SortedSet<ClassDoc> subs(ClassDoc cd, boolean isEnum) {
         if (isEnum) {
             return get(subEnums, cd);
         } else if (cd.isAnnotationType()) {
@@ -344,19 +347,21 @@
      * @param isEnum true if the subclasses should be forced to come from the
      * enum tree.
      */
-    public List<ClassDoc> allSubs(ClassDoc cd, boolean isEnum) {
-        List<ClassDoc> list = subs(cd, isEnum);
+    public SortedSet<ClassDoc> allSubs(ClassDoc cd, boolean isEnum) {
+        // new entries added to the list are searched as well
+        List<ClassDoc> list = new ArrayList<>(subs(cd, isEnum));
         for (int i = 0; i < list.size(); i++) {
             cd = list.get(i);
-            List<ClassDoc> tlist = subs(cd, isEnum);
+            SortedSet<ClassDoc> tlist = subs(cd, isEnum);
             for (ClassDoc tcd : tlist) {
                 if (!list.contains(tcd)) {
                     list.add(tcd);
                 }
             }
         }
-        Collections.sort(list);
-        return list;
+        SortedSet<ClassDoc> oset = new TreeSet<>(comparator);
+        oset.addAll(list);
+        return oset;
     }
 
     /**
@@ -364,7 +369,7 @@
      *  thw classdoc for java.lang.Object, since this is the base class for all
      *  classes.
      */
-    public List<ClassDoc> baseclasses() {
+    public SortedSet<ClassDoc> baseclasses() {
         return baseclasses;
     }
 
@@ -372,7 +377,7 @@
      *  Return the list of base interfaces. This is the list of interfaces
      *  which do not have super-interface.
      */
-    public List<ClassDoc> baseinterfaces() {
+    public SortedSet<ClassDoc> baseinterfaces() {
         return baseinterfaces;
     }
 
@@ -380,7 +385,7 @@
      *  Return the list of base enums. This is the list of enums
      *  which do not have super-enums.
      */
-    public List<ClassDoc> baseEnums() {
+    public SortedSet<ClassDoc> baseEnums() {
         return baseEnums;
     }
 
@@ -388,7 +393,7 @@
      *  Return the list of base annotation types. This is the list of
      *  annotation types which do not have super-annotation types.
      */
-    public List<ClassDoc> baseAnnotationTypes() {
+    public SortedSet<ClassDoc> baseAnnotationTypes() {
         return baseAnnotationTypes;
     }
 }
--- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/ClassUseMapper.java	Tue Aug 26 08:12:42 2014 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/ClassUseMapper.java	Wed Aug 27 06:56:29 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2014, 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
@@ -28,6 +28,7 @@
 import java.util.*;
 
 import com.sun.javadoc.*;
+import com.sun.tools.doclets.formats.html.ConfigurationImpl;
 
 /**
  * Map all class uses for a given class.
@@ -181,10 +182,11 @@
      */
     public Map<String,List<FieldDoc>> annotationToFieldDoc = new HashMap<>();
 
-
-    public ClassUseMapper(RootDoc root, ClassTree classtree) {
+    private final Utils utils;
+    public ClassUseMapper(ConfigurationImpl configuration, ClassTree classtree) {
+        RootDoc root = configuration.root;
         this.classtree = classtree;
-
+        utils = configuration.utils;
         // Map subclassing, subinterfacing implementing, ...
         for (ClassDoc doc : classtree.baseclasses()) {
             subclasses(doc);
@@ -234,8 +236,8 @@
     private Collection<ClassDoc> subclasses(ClassDoc cd) {
         Collection<ClassDoc> ret = classToSubclass.get(cd.qualifiedName());
         if (ret == null) {
-            ret = new TreeSet<>();
-            List<ClassDoc> subs = classtree.subclasses(cd);
+            ret = new TreeSet<>(utils.makeComparatorForClassUse());
+            SortedSet<ClassDoc> subs = classtree.subclasses(cd);
             if (subs != null) {
                 ret.addAll(subs);
                 for (ClassDoc sub : subs) {
@@ -253,8 +255,8 @@
     private Collection<ClassDoc> subinterfaces(ClassDoc cd) {
         Collection<ClassDoc> ret = classToSubinterface.get(cd.qualifiedName());
         if (ret == null) {
-            ret = new TreeSet<>();
-            List<ClassDoc> subs = classtree.subinterfaces(cd);
+            ret = new TreeSet<>(utils.makeComparatorForClassUse());
+            SortedSet<ClassDoc> subs = classtree.subinterfaces(cd);
             if (subs != null) {
                 ret.addAll(subs);
                 for (ClassDoc sub : subs) {
@@ -275,8 +277,8 @@
     private Collection<ClassDoc> implementingClasses(ClassDoc cd) {
         Collection<ClassDoc> ret = classToImplementingClass.get(cd.qualifiedName());
         if (ret == null) {
-            ret = new TreeSet<>();
-            List<ClassDoc> impl = classtree.implementingclasses(cd);
+            ret = new TreeSet<>(utils.makeComparatorForClassUse());
+            SortedSet<ClassDoc> impl = classtree.implementingclasses(cd);
             if (impl != null) {
                 ret.addAll(impl);
                 for (ClassDoc anImpl : impl) {
@@ -297,25 +299,26 @@
      */
     private void mapExecutable(ExecutableMemberDoc em) {
         boolean isConstructor = em.isConstructor();
-        List<Type> classArgs = new ArrayList<>();
+        Set<Type> classArgs = new TreeSet<>(utils.makeTypeComparator());
         for (Parameter param : em.parameters()) {
             Type pcd = param.type();
-            // primitives don't get mapped, also avoid dups
-            if ((!param.type().isPrimitive()) &&
-                !classArgs.contains(pcd) &&
-                !(pcd instanceof TypeVariable)) {
-                add(isConstructor ? classToConstructorArgs : classToMethodArgs,
-                    pcd.asClassDoc(), em);
-                classArgs.add(pcd);
-                mapTypeParameters(isConstructor ?
-                                  classToConstructorDocArgTypeParam : classToExecMemberDocArgTypeParam,
-                                  pcd, em);
+            // ignore primitives and typevars, typevars are handled elsewhere
+            if ((!param.type().isPrimitive()) && !(pcd instanceof TypeVariable)) {
+                 // avoid dups
+                if (classArgs.add(pcd)) {
+                    add(isConstructor ? classToConstructorArgs : classToMethodArgs,
+                            pcd.asClassDoc(), em);
+                    mapTypeParameters(isConstructor
+                                ? classToConstructorDocArgTypeParam
+                                : classToExecMemberDocArgTypeParam,
+                            pcd, em);
+                }
             }
-            mapAnnotations(
-                    isConstructor ?
-                    classToConstructorParamAnnotation :
-                    classToExecMemberDocParamAnnotation,
+            mapAnnotations(isConstructor
+                        ? classToConstructorParamAnnotation
+                        : classToExecMemberDocParamAnnotation,
                     param, em);
+
         }
         for (ClassDoc anException : em.thrownExceptions()) {
             add(isConstructor ? classToConstructorThrows : classToMethodThrows,
--- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/Utils.java	Tue Aug 26 08:12:42 2014 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/Utils.java	Wed Aug 27 06:56:29 2014 -0700
@@ -248,15 +248,20 @@
             throw new DocletAbortException(exc);
         }
     }
-
+    /**
+     * Returns a TypeComparator object suitable for sorting Types.
+     * @return a TypeComparator objectt
+     */
+    public Comparator<Type> makeTypeComparator() {
+        return new TypeComparator();
+    }
     /**
      * We want the list of types in alphabetical order.  However, types are not
      * comparable.  We need a comparator for now.
      */
     private static class TypeComparator implements Comparator<Type> {
         public int compare(Type type1, Type type2) {
-            return type1.qualifiedTypeName().compareToIgnoreCase(
-                type2.qualifiedTypeName());
+            return compareStrings(type1.qualifiedTypeName(), type2.qualifiedTypeName());
         }
     }
 
@@ -812,7 +817,15 @@
         collator.setStrength(caseSensitive ? Collator.TERTIARY : Collator.SECONDARY);
         return collator.compare(s1, s2);
     }
-
+    /**
+     * A simple comparator which compares simple names, then the fully qualified names
+     * and finally the kinds, ClassUse comparator works well for this purpose.
+     *
+     * @return a simple general purpose doc comparator
+     */
+    public Comparator<Doc> makeGeneralPurposeComparator() {
+        return makeComparatorForClassUse();
+    }
     /**
      * A comparator for index file presentations, and are sorted as follows:
      *  1. sort on simple names of entities
--- a/langtools/test/com/sun/javadoc/lib/JavadocTester.java	Tue Aug 26 08:12:42 2014 -0700
+++ b/langtools/test/com/sun/javadoc/lib/JavadocTester.java	Wed Aug 27 06:56:29 2014 -0700
@@ -467,6 +467,31 @@
     }
 
     /**
+     * Ensures that a series of strings appear only once, in the generated output,
+     * noting that, this test does not exhaustively check for all other possible
+     * duplicates once one is found.
+     * @param path the file to check
+     * @param strings ensure each are unique
+     */
+    public void checkUnique(String path, String... strings) {
+        String fileString = readOutputFile(path);
+        for (String s : strings) {
+            int currentIndex = fileString.indexOf(s);
+            checking(s + " at index " + currentIndex);
+            if (currentIndex == -1) {
+                failed(s + " not found.");
+                continue;
+            }
+            int nextindex = fileString.indexOf(s, currentIndex + s.length());
+            if (nextindex == -1) {
+                passed(s + " is unique");
+            } else {
+                failed(s + " is not unique, found at " + nextindex);
+            }
+        }
+    }
+
+    /**
      * Compare a set of files in each of two directories.
      *
      * @param baseDir1 the directory containing the first set of files
--- a/langtools/test/com/sun/javadoc/testOrdering/TestOrdering.java	Tue Aug 26 08:12:42 2014 -0700
+++ b/langtools/test/com/sun/javadoc/testOrdering/TestOrdering.java	Wed Aug 27 06:56:29 2014 -0700
@@ -119,6 +119,8 @@
         javadoc(cmdArgs.toArray(new String[cmdArgs.size()]));
         checkExit(Exit.OK);
         checkOrder("index-all.html", composeTestVectors());
+        checkOrder("add0/add/package-tree.html", expectedPackageTreeOrdering);
+        checkOrder("overview-tree.html", expectedOverviewOrdering);
     }
 
     @Test
@@ -381,4 +383,44 @@
         "add3/add/Add.html#ADDADD\"",
         "add3/Add.html#ADDADD\""
     };
+    final String expectedPackageTreeOrdering[] = {
+        "<a href=\"../../add0/add/Add.add.html\" title=\"enum in add0.add\">",
+        "<a href=\"../../add0/add/Add.ADD.html\" title=\"enum in add0.add\">"
+    };
+    final String expectedOverviewOrdering[] = {
+        "<a href=\"Add.add.html\" title=\"enum in &lt;Unnamed&gt;\">",
+        "<a href=\"add0/Add.add.html\" title=\"enum in add0\">",
+        "<a href=\"add0/add/Add.add.html\" title=\"enum in add0.add\">",
+        "<a href=\"add0/add/add/Add.add.html\" title=\"enum in add0.add.add\">",
+        "<a href=\"add0/add/add/add/Add.add.html\" title=\"enum in add0.add.add.add\">",
+        "<a href=\"add1/Add.add.html\" title=\"enum in add1\">",
+        "<a href=\"add1/add/Add.add.html\" title=\"enum in add1.add\">",
+        "<a href=\"add1/add/add/Add.add.html\" title=\"enum in add1.add.add\">",
+        "<a href=\"add1/add/add/add/Add.add.html\" title=\"enum in add1.add.add.add\">",
+        "<a href=\"add2/Add.add.html\" title=\"enum in add2\">",
+        "<a href=\"add2/add/Add.add.html\" title=\"enum in add2.add\">",
+        "<a href=\"add2/add/add/Add.add.html\" title=\"enum in add2.add.add\">",
+        "<a href=\"add2/add/add/add/Add.add.html\" title=\"enum in add2.add.add.add\">",
+        "<a href=\"add3/Add.add.html\" title=\"enum in add3\">",
+        "<a href=\"add3/add/Add.add.html\" title=\"enum in add3.add\">",
+        "<a href=\"add3/add/add/Add.add.html\" title=\"enum in add3.add.add\">",
+        "<a href=\"add3/add/add/add/Add.add.html\" title=\"enum in add3.add.add.add\">",
+        "<a href=\"Add.ADD.html\" title=\"enum in &lt;Unnamed&gt;\">",
+        "<a href=\"add0/Add.ADD.html\" title=\"enum in add0\">",
+        "<a href=\"add0/add/Add.ADD.html\" title=\"enum in add0.add\">",
+        "<a href=\"add0/add/add/Add.ADD.html\" title=\"enum in add0.add.add\">",
+        "<a href=\"add0/add/add/add/Add.ADD.html\" title=\"enum in add0.add.add.add\">",
+        "<a href=\"add1/Add.ADD.html\" title=\"enum in add1\">",
+        "<a href=\"add1/add/Add.ADD.html\" title=\"enum in add1.add\">",
+        "<a href=\"add1/add/add/Add.ADD.html\" title=\"enum in add1.add.add\">",
+        "<a href=\"add1/add/add/add/Add.ADD.html\" title=\"enum in add1.add.add.add\">",
+        "<a href=\"add2/Add.ADD.html\" title=\"enum in add2\">",
+        "<a href=\"add2/add/Add.ADD.html\" title=\"enum in add2.add\">",
+        "<a href=\"add2/add/add/Add.ADD.html\" title=\"enum in add2.add.add\">",
+        "<a href=\"add2/add/add/add/Add.ADD.html\" title=\"enum in add2.add.add.add\">",
+        "<a href=\"add3/Add.ADD.html\" title=\"enum in add3\">",
+        "<a href=\"add3/add/Add.ADD.html\" title=\"enum in add3.add\">",
+        "<a href=\"add3/add/add/Add.ADD.html\" title=\"enum in add3.add.add\">",
+        "<a href=\"add3/add/add/add/Add.ADD.html\" title=\"enum in add3.add.add.add\">",
+    };
 }
--- a/langtools/test/com/sun/javadoc/testUseOption/TestUseOption.java	Tue Aug 26 08:12:42 2014 -0700
+++ b/langtools/test/com/sun/javadoc/testUseOption/TestUseOption.java	Wed Aug 27 06:56:29 2014 -0700
@@ -23,8 +23,8 @@
 
 /*
  * @test
- * @bug 4496290 4985072 7006178 7068595 8016328
- * @summary A simple test to determine if -use works.
+ * @bug 4496290 4985072 7006178 7068595 8016328 8050031
+ * @summary A simple test to ensure class-use files are correct.
  * @author jamieh
  * @library ../lib
  * @build JavadocTester
@@ -139,4 +139,18 @@
                 + "<a href=\"class-use/UsedInC.html#%3CUnnamed%3E\">UsedInC</a>&nbsp;</td>"
         );
     }
+
+    @Test
+    void test3() {
+        javadoc("-d", "out-3",
+                "-sourcepath", testSrc,
+                "-use",
+                "-package", "unique");
+        checkExit(Exit.OK);
+        checkUnique("unique/class-use/UseMe.html",
+                "<a href=\"../../unique/C1.html#umethod1-unique.UseMe-unique.UseMe:A-\">",
+                "<a href=\"../../unique/C1.html#umethod2-unique.UseMe-unique.UseMe-\">",
+                "<a href=\"../../unique/C1.html#umethod3-unique.UseMe-unique.UseMe-\">",
+                "<a href=\"../../unique/C1.html#C1-unique.UseMe-unique.UseMe-\">");
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/com/sun/javadoc/testUseOption/unique/C1.java	Wed Aug 27 06:56:29 2014 -0700
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, 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.
+ *
+ * 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 unique;
+
+/**
+ * A class to ensure we get unique entries in class-use for each of these,
+ * so make sure each method is uniquely named to avoid false positives
+ */
+
+public class C1 {
+
+    /**
+     * Ctor C1 to test uniqueness
+     * @param a param
+     * @param b param
+     */
+    public C1(UseMe a, UseMe b){}
+
+    /**
+     * umethod1 to test uniqueness
+     * @param one param
+     * @param uarray param
+     */
+    public void umethod1(UseMe<?> one, UseMe<?>[] uarray){}
+
+    /**
+     * umethod1 to test uniqueness
+     * @param one param
+     * @param two param
+     */
+    public void umethod2(UseMe<?> one, UseMe<?> two){}
+
+    /**
+     * umethod1 to test uniqueness
+     * @param a param
+     * @param b param
+     */
+    public void umethod3(UseMe a, UseMe b){}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/com/sun/javadoc/testUseOption/unique/UseMe.java	Wed Aug 27 06:56:29 2014 -0700
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2014, 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.
+ *
+ * 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 unique;
+
+public class UseMe<T> {}