Skip to content

Commit 0741cd3

Browse files
committedJul 6, 2023
8311264: JavaDoc index comparator is not transitive
Reviewed-by: jjg
1 parent edb2be1 commit 0741cd3

File tree

4 files changed

+115
-36
lines changed

4 files changed

+115
-36
lines changed
 

‎src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Comparators.java

+16-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -238,17 +238,8 @@ public Comparator<Element> makeIndexElementComparator() {
238238
*/
239239
@Override
240240
public int compare(Element e1, Element e2) {
241-
int result;
242241
// first, compare names as appropriate
243-
if ((utils.isModule(e1) || utils.isPackage(e1)) && (utils.isModule(e2) || utils.isPackage(e2))) {
244-
result = compareFullyQualifiedNames(e1, e2);
245-
} else if (utils.isModule(e1) || utils.isPackage(e1)) {
246-
result = utils.compareStrings(utils.getFullyQualifiedName(e1), utils.getSimpleName(e2));
247-
} else if (utils.isModule(e2) || utils.isPackage(e2)) {
248-
result = utils.compareStrings(utils.getSimpleName(e1), utils.getFullyQualifiedName(e2));
249-
} else {
250-
result = compareNames(e1, e2);
251-
}
242+
int result = utils.compareStrings(getIndexElementKey(e1), getIndexElementKey(e2));
252243
if (result != 0) {
253244
return result;
254245
}
@@ -274,6 +265,20 @@ public int compare(Element e1, Element e2) {
274265
return indexUseComparator;
275266
}
276267

268+
/**
269+
* {@return the element's primary key for use in the index comparator}
270+
* This method can be used by other comparators which need to produce results
271+
* that are consistent with the index comparator.
272+
*
273+
* @param element an element
274+
*/
275+
public String getIndexElementKey(Element element) {
276+
return switch (element.getKind()) {
277+
case MODULE, PACKAGE -> utils.getFullyQualifiedName(element);
278+
default -> utils.getSimpleName(element);
279+
};
280+
}
281+
277282
private Comparator<TypeMirror> typeMirrorClassUseComparator = null;
278283

279284
/**

‎src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/IndexBuilder.java

+29-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -119,7 +119,7 @@ public IndexBuilder(BaseConfiguration configuration,
119119
itemsByFirstChar = new TreeMap<>();
120120
itemsByCategory = new EnumMap<>(IndexItem.Category.class);
121121

122-
mainComparator = makeIndexComparator(classesOnly);
122+
mainComparator = classesOnly ? makeClassComparator() : makeIndexComparator();
123123
}
124124

125125
/**
@@ -310,6 +310,13 @@ private static Character keyCharacter(String s) {
310310
return '*';
311311
}
312312

313+
/**
314+
* Returns a comparator for the all-classes list.
315+
* @return a comparator for class element items
316+
*/
317+
private Comparator<IndexItem> makeClassComparator() {
318+
return Comparator.comparing(IndexItem::getElement, utils.comparators.makeAllClassesComparator());
319+
}
313320

314321
/**
315322
* Returns a comparator for the {@code IndexItem}s in the index page.
@@ -318,15 +325,17 @@ private static Character keyCharacter(String s) {
318325
*
319326
* @return a comparator for index page items
320327
*/
321-
private Comparator<IndexItem> makeIndexComparator(boolean classesOnly) {
322-
Comparator<Element> elementComparator = classesOnly
323-
? utils.comparators.makeAllClassesComparator()
324-
: utils.comparators.makeIndexElementComparator();
325-
326-
Comparator<IndexItem> labelComparator =
327-
(ii1, ii2) -> utils.compareStrings(ii1.getLabel(), ii2.getLabel());
328+
private Comparator<IndexItem> makeIndexComparator() {
329+
// We create comparators specific to element and search tag items, and a
330+
// base comparator used to compare between the two kinds of items.
331+
// In order to produce consistent results, it is important that the base comparator
332+
// uses the same primary sort keys as both the element and search tag comparators
333+
// (see JDK-8311264).
334+
Comparator<Element> elementComparator = utils.comparators.makeIndexElementComparator();
335+
Comparator<IndexItem> baseComparator =
336+
(ii1, ii2) -> utils.compareStrings(getIndexItemKey(ii1), getIndexItemKey(ii2));
328337
Comparator<IndexItem> searchTagComparator =
329-
labelComparator
338+
baseComparator
330339
.thenComparing(IndexItem::getHolder)
331340
.thenComparing(IndexItem::getDescription)
332341
.thenComparing(IndexItem::getUrl);
@@ -350,9 +359,9 @@ private Comparator<IndexItem> makeIndexComparator(boolean classesOnly) {
350359
return d;
351360
}
352361

353-
// If one is an element item, compare labels; if equal, put element item last
362+
// If one is an element item, compare item keys; if equal, put element item last
354363
if (ii1.isElementItem() || ii2.isElementItem()) {
355-
int d = labelComparator.compare(ii1, ii2);
364+
int d = baseComparator.compare(ii1, ii2);
356365
return d != 0 ? d : ii1.isElementItem() ? 1 : -1;
357366
}
358367

@@ -361,6 +370,14 @@ private Comparator<IndexItem> makeIndexComparator(boolean classesOnly) {
361370
};
362371
}
363372

373+
private String getIndexItemKey(IndexItem ii) {
374+
// For element items return the key used by the element comparator;
375+
// for search tag items return the item's label.
376+
return ii.isElementItem()
377+
? utils.comparators.getIndexElementKey(ii.getElement())
378+
: ii.getLabel();
379+
}
380+
364381
/**
365382
* Returns a Comparator for IndexItems in the types category of the search index.
366383
* Items are compared by short name, falling back to the main comparator if names are equal.

‎test/langtools/jdk/javadoc/doclet/testIndex/TestIndex.java

+32-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
2424
/*
2525
* @test
2626
* @bug 4852280 4517115 4973608 4994589 8026567 8071982 8196202 8234746
27+
* 8311264
2728
* @summary Perform tests on index.html file.
2829
* Also test that index-all.html has the appropriate output.
2930
* Test for unnamed package in index.
@@ -50,22 +51,44 @@ public void test() {
5051
checkExit(Exit.OK);
5152

5253
//Test index-all.html
53-
checkOutput("index-all.html", true,
54+
checkOrder("index-all.html",
55+
"""
56+
<a href="pkg/AnnotationType.html" class="type-name-link" title="annotation inter\
57+
face in pkg">AnnotationType</a> - Annotation Interface in <a href="pkg/package-s\
58+
ummary.html">pkg</a>""",
59+
"""
60+
<a href="pkg/C.html#c()" class="member-name-link">c()</a> - Method in class pkg.\
61+
<a href="pkg/C.html" title="class in pkg">C</a>""",
62+
"""
63+
<a href="pkg/C.html#c-heading" class="search-tag-link">C</a> - Search tag in cla\
64+
ss pkg.C""",
5465
"""
5566
<a href="pkg/C.html" class="type-name-link" title="class in pkg">C</a> - Class i\
5667
n <a href="pkg/package-summary.html">pkg</a>""",
5768
"""
58-
<a href="pkg/Interface.html" class="type-name-link" title="interface in pkg">Int\
59-
erface</a> - Interface in <a href="pkg/package-summary.html">pkg</a>""",
69+
<a href="pkg/C.html#%3Cinit%3E()" class="member-name-link">C()</a> - Constructor\
70+
for class pkg.<a href="pkg/C.html" title="class in pkg">C</a>""",
6071
"""
61-
<a href="pkg/AnnotationType.html" class="type-name-link" title="annotation inter\
62-
face in pkg">AnnotationType</a> - Annotation Interface in <a href="pkg/package-s\
63-
ummary.html">pkg</a>""",
72+
<a href="pkg/C.html#%3Cinit%3E(int)" class="member-name-link">C(int)</a> - Const\
73+
ructor for class pkg.<a href="pkg/C.html" title="class in pkg">C</a>""",
74+
"""
75+
<a href="pkg/C.html#c_()" class="member-name-link">c_()</a> - Method in class pk\
76+
g.<a href="pkg/C.html" title="class in pkg">C</a>""",
77+
"""
78+
<a href="pkg/C.html#c/d" class="search-tag-link">c/d</a> - Search tag in class p\
79+
kg.C""",
80+
"""
81+
<a href="pkg/C.html#c-d-heading" class="search-tag-link">C/D</a> - Search tag in\
82+
class pkg.C""",
6483
"""
6584
<a href="pkg/Coin.html" class="type-name-link" title="enum class in pkg">Coin</a\
6685
> - Enum Class in <a href="pkg/package-summary.html">pkg</a>""",
6786
"""
68-
Class in <a href="package-summary.html">Unnamed Package</a>""",
87+
<dt><a href="pkg/Coin.html#Enum" class="search-tag-link">Enum</a> - Search tag i\
88+
n enum class pkg.Coin</dt>""",
89+
"""
90+
<a href="pkg/Interface.html" class="type-name-link" title="interface in pkg">Int\
91+
erface</a> - Interface in <a href="pkg/package-summary.html">pkg</a>""",
6992
"""
7093
<dl class="index">
7194
<dt><a href="pkg/C.html#Java" class="member-name-link">Java</a> - Static variabl\
@@ -76,6 +99,6 @@ in class pkg.<a href="pkg/C.html" title="class in pkg">C</a></dt>
7699
<dd>&nbsp;</dd>
77100
</dl>""",
78101
"""
79-
<dt><a href="pkg/Coin.html#Enum" class="search-tag-link">Enum</a> - Search tag in enum class pkg.Coin</dt>""");
102+
Class in <a href="package-summary.html">Unnamed Package</a>""");
80103
}
81104
}

‎test/langtools/jdk/javadoc/doclet/testIndex/pkg/C.java

+38-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -23,11 +23,45 @@
2323

2424
package pkg;
2525

26+
/**
27+
* A class to test sorting of index items.
28+
*
29+
* <h2>C</h2>
30+
*
31+
* Section "C" should appear right before language elements with the same name.
32+
*
33+
* <h3>C/D</h3>
34+
*
35+
* Section "C/D" should appear after items named "C" in the index.
36+
*
37+
* {@index c/d should appear before the section above}
38+
*/
2639
public class C {
2740

28-
//Test that Java appears before JDK in the index. The fact
29-
//that 'D' is uppercase and 'a' is lowercase should make no difference
30-
//in ordering.
41+
/**
42+
* Empty constructor.
43+
*/
44+
public C() {}
45+
46+
/**
47+
* Constructor with a parameter.
48+
* @param i an int
49+
*/
50+
public C(int i) {}
51+
52+
/**
53+
* Lower case "c" method should appear before upper case "C" elements and sections in index.
54+
*/
55+
public void c() {}
56+
57+
/**
58+
* Should appear after all items named "c" or "C".
59+
*/
60+
public void c_() {}
61+
62+
// Test that Java appears before JDK in the index. The fact
63+
// that 'D' is uppercase and 'a' is lowercase should make no difference
64+
// in ordering.
3165
public static final String JDK = "1.5";
3266
public static final String Java = "1.5";
3367

0 commit comments

Comments
 (0)
Please sign in to comment.