Skip to content

Commit f2d2eef

Browse files
committed
8177100: APIs duplicated in JavaDoc
Reviewed-by: liach, hannesw
1 parent 1c56072 commit f2d2eef

File tree

2 files changed

+228
-14
lines changed

2 files changed

+228
-14
lines changed

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

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -678,22 +678,16 @@ private boolean allowInheritedMethod(ExecutableElement inheritedMethod,
678678
return false;
679679
}
680680

681-
// Multiple-Inheritance: remove the interface method that may have
682-
// been overridden by another interface method in the hierarchy
683-
//
684-
// Note: The following approach is very simplistic and is compatible
685-
// with old VMM. A future enhancement, may include a contention breaker,
686-
// to correctly eliminate those methods that are merely definitions
687-
// in favor of concrete overriding methods, for instance those that have
688-
// API documentation and are not abstract OR default methods.
681+
// Multiple-Inheritance: No Contention. In Java's method resolution,
682+
// any override of a signature (whether by a subclass or by a subinterface,
683+
// including when it is final from superclasses) always takes precedence
684+
// over the original interface definition. All interface methods have low resolution priority.
685+
// Therefore, when considering an interface inherited method, as soon as
686+
// at least one overrider exists in the inheritance chain,
687+
// we do not inherit the older interface definition.
689688
if (inInterface) {
690689
List<ExecutableElement> list = overriddenByTable.get(inheritedMethod);
691-
if (list != null) {
692-
boolean found = list.stream()
693-
.anyMatch(this::isDeclaredInInterface);
694-
if (found)
695-
return false;
696-
}
690+
if (list != null && !list.isEmpty()) return false;
697691
}
698692

699693
Elements elementUtils = config.docEnv.getElementUtils();
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8177100
27+
* @summary Test to check for duplicate methods across different inheritance patterns
28+
* @library /tools/lib ../../lib
29+
* @modules jdk.javadoc/jdk.javadoc.internal.tool
30+
* @build toolbox.ToolBox javadoc.tester.*
31+
* @run main TestDuplicateMethods
32+
*/
33+
34+
import java.io.IOException;
35+
import java.nio.file.Path;
36+
37+
import javadoc.tester.JavadocTester;
38+
import toolbox.ToolBox;
39+
40+
public class TestDuplicateMethods extends JavadocTester {
41+
42+
public static void main(String... args) throws Exception {
43+
var tester = new TestDuplicateMethods();
44+
tester.runTests();
45+
}
46+
47+
ToolBox tb = new ToolBox();
48+
Path src = Path.of("src");
49+
50+
51+
TestDuplicateMethods() throws IOException {
52+
// Diamond class inheritance
53+
tb.writeJavaFiles(src, """
54+
package p;
55+
interface A {
56+
/**
57+
* JavaDoc for method in interface A.
58+
*/
59+
abstract void testA( );
60+
}""", """
61+
package p;
62+
interface B extends A {
63+
/**
64+
* JavaDoc for method in interface B.
65+
*/
66+
abstract void testB( );
67+
}""", """
68+
package p;
69+
abstract class C implements A {
70+
/**
71+
* Inherited JavaDoc for method in class C.
72+
*/
73+
public final void testA( ) {
74+
// Do nothing.
75+
}
76+
}""","""
77+
package p;
78+
public final class D extends C implements B {
79+
/**
80+
* Inherited JavaDoc.
81+
*/
82+
public final void testB() {
83+
// Do nothing.
84+
}
85+
}
86+
""");
87+
88+
// Mirrors the implementation of StringBuilder
89+
tb.writeJavaFiles(src,
90+
"""
91+
package sb;
92+
public interface I {
93+
/**
94+
* JavaDoc for method in public interface I.
95+
*/
96+
void testI();
97+
}
98+
""", """
99+
package sb;
100+
abstract class P implements I {
101+
/**
102+
* Inherited JavaDoc for method in class P.
103+
*/
104+
public final void testI() {
105+
// Do nothing.
106+
}
107+
}
108+
""", """
109+
package sb;
110+
public class U extends P implements I {
111+
// No overrides
112+
}
113+
"""
114+
);
115+
116+
// Mirrors the implementation of HashMap
117+
tb.writeJavaFiles(src,
118+
"""
119+
package hm;
120+
public interface J {
121+
/**
122+
* JavaDoc for method in public interface J.
123+
*/
124+
void testJ();
125+
}
126+
""",
127+
"""
128+
package hm;
129+
public abstract class PubJ implements J {
130+
/**
131+
* Inherited JavaDoc for method in public abstract class PubJ.
132+
*/
133+
public final void testJ() {
134+
// Do nothing.
135+
}
136+
}
137+
""",
138+
"""
139+
package hm;
140+
public class V extends PubJ implements J {
141+
// No override
142+
}
143+
"""
144+
);
145+
}
146+
147+
@Test
148+
public void testDiamondInheritance(Path base) {
149+
javadoc("-d", base.resolve("out").toString(),
150+
"-sourcepath", src.toString(),
151+
"p");
152+
checkExit(Exit.OK);
153+
checkOutput("p/D.html", true,
154+
"""
155+
<div class="block">Inherited JavaDoc for method in class C.</div>
156+
""", """
157+
<div class="member-signature"><span class="modifiers">public final</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name">testA</span>()</div>
158+
<div class="block">Inherited JavaDoc for method in class C.</div>
159+
"""
160+
);
161+
162+
checkOutput("p/D.html", false, """
163+
<div class="block">JavaDoc for method in Interface A.</div>""", """
164+
<div class="member-signature"><span class="return-type">void</span>&nbsp;<span class="element-name">testA</span>()</div>
165+
<div class="block">JavaDoc for method in Interface A.</div>""");
166+
167+
168+
checkOutput("p/D.html", false,
169+
"""
170+
<div class="block">JavaDoc for method in interface A.</div>
171+
""");
172+
}
173+
174+
@Test
175+
public void testStringBuilderInheritance(Path base) {
176+
javadoc("-d", base.resolve("out").toString(),
177+
"-sourcepath", src.toString(),
178+
"sb");
179+
checkExit(Exit.OK);
180+
181+
checkOutput("sb/U.html", false,
182+
"""
183+
<div class="inherited-list">
184+
<h3 id="methods-inherited-from-class-sb.I">Methods inherited from interface&nbsp;<a href="I.html#method-summary" title="interface in sb">I</a></h3>
185+
<code><a href="I.html#testI()" title="testI()">testI</a></code></div>
186+
""");
187+
188+
checkOutput("sb/U.html", true,
189+
"""
190+
<h3>testI</h3>
191+
<div class="horizontal-scroll">
192+
<div class="member-signature"><span class="modifiers">public final</span>&nbsp;<span class="return-type">void</span>&nbsp;<span class="element-name">testI</span>()</div>
193+
<div class="block">Inherited JavaDoc for method in class P.</div>
194+
<dl class="notes">
195+
<dt>Specified by:</dt>
196+
<dd><code><a href="I.html#testI()">testI</a></code>&nbsp;in interface&nbsp;<code><a href="I.html" title="interface in sb">I</a></code></dd>
197+
</dl>""");
198+
}
199+
200+
@Test
201+
public void testHashMapInheritance(Path base) {
202+
javadoc("-d", base.resolve("out").toString(),
203+
"-sourcepath", src.toString(),
204+
"hm");
205+
checkExit(Exit.OK);
206+
207+
checkOutput("hm/V.html", false,
208+
"""
209+
<div class="inherited-list">
210+
<h3 id="methods-inherited-from-class-hm.J">Methods inherited from interface&nbsp;<a href="J.html#method-summary" title="interface in hm">J</a></h3>
211+
<code><a href="J.html#testJ()" title="testJ()">testJ</a></code></div>""");
212+
213+
checkOutput("hm/V.html", true,
214+
"""
215+
<div class="inherited-list">
216+
<h3 id="methods-inherited-from-class-hm.PubJ">Methods inherited from class&nbsp;<a href="PubJ.html#method-summary" title="class in hm">PubJ</a></h3>
217+
<code><a href="PubJ.html#testJ()" title="testJ()">testJ</a></code></div>
218+
""");
219+
}
220+
}

0 commit comments

Comments
 (0)