8254622: Hide superclasses from conditionally exported packages

Reviewed-by: kcr, liach
This commit is contained in:
Hannes Wallnöfer 2025-04-13 10:08:39 +00:00
parent ed756b9700
commit 5d97608970
21 changed files with 408 additions and 85 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2025, 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,8 +28,6 @@ package jdk.internal.event;
/**
* Base class for events, to be subclassed in order to define events and their
* fields.
*
* @hidden
*/
public abstract class Event {
/**

View File

@ -157,9 +157,6 @@ public class VectorSupport {
public static class VectorSpecies<E> {}
/**
* @hidden
*/
public static class VectorPayload {
private final Object payload; // array of primitives
@ -172,26 +169,18 @@ public class VectorSupport {
}
}
/**
* @hidden
*/
public static class Vector<E> extends VectorPayload {
public Vector(Object payload) {
super(payload);
}
}
/**
* @hidden
*/
public static class VectorShuffle<E> extends VectorPayload {
public VectorShuffle(Object payload) {
super(payload);
}
}
/**
* @hidden
*/
public static class VectorMask<E> extends VectorPayload {
public VectorMask(Object payload) {
super(payload);

View File

@ -266,15 +266,12 @@ public abstract class AbstractMemberWriter {
var inheritedMembersFromMap = asSortedSet(visibleMemberTable.getAllVisibleMembers(kind));
for (TypeElement inheritedClass : visibleMemberTable.getVisibleTypeElements()) {
if (!(utils.isPublic(inheritedClass) || utils.isLinkable(inheritedClass))) {
if (!utils.isVisible(inheritedClass)) {
continue;
}
if (Objects.equals(inheritedClass, typeElement)) {
continue;
}
if (utils.hasHiddenTag(inheritedClass)) {
continue;
}
List<? extends Element> members = inheritedMembersFromMap.stream()
.filter(e -> Objects.equals(utils.getEnclosingTypeElement(e), inheritedClass))

View File

@ -128,22 +128,20 @@ public abstract class AbstractTreeWriter extends HtmlDocletWriter {
if (interfaces.size() > (utils.isPlainInterface(typeElement) ? 1 : 0)) {
boolean isFirst = true;
for (TypeElement intf : interfaces) {
if (parent != intf) {
if (utils.isPublic(intf) || utils.isLinkable(intf)) {
if (isFirst) {
isFirst = false;
if (utils.isPlainInterface(typeElement)) {
content.add(" (");
content.add(contents.also);
content.add(" extends ");
} else {
content.add(" (implements ");
}
if (parent != intf && utils.isVisible(intf)) {
if (isFirst) {
isFirst = false;
if (utils.isPlainInterface(typeElement)) {
content.add(" (");
content.add(contents.also);
content.add(" extends ");
} else {
content.add(", ");
content.add(" (implements ");
}
addPreQualifiedClassLink(HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS, intf, content);
} else {
content.add(", ");
}
addPreQualifiedClassLink(HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS, intf, content);
}
}
if (!isFirst) {

View File

@ -111,7 +111,7 @@ public class AllClassesIndexWriter extends HtmlDocletWriter {
boolean noDeprecated = options.noDeprecated();
Set<TypeElement> includedTypes = configuration.getIncludedTypeElements();
for (TypeElement typeElement : includedTypes) {
if (utils.hasHiddenTag(typeElement) || !utils.isCoreClass(typeElement)) {
if (utils.isHidden(typeElement) || !utils.isCoreClass(typeElement)) {
continue;
}
if (noDeprecated

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2025, 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
@ -409,7 +409,7 @@ public class HtmlDoclet extends AbstractDoclet {
protected void generateClassFiles(SortedSet<TypeElement> typeElems, ClassTree classTree)
throws DocletException {
for (TypeElement te : typeElems) {
if (utils.hasHiddenTag(te) ||
if (utils.isHidden(te) ||
!(configuration.isGeneratedDoc(te) && utils.isIncluded(te))) {
continue;
}

View File

@ -292,7 +292,7 @@ public class HtmlLinkFactory {
Content link = new ContentBuilder();
if (utils.isIncluded(typeElement)) {
if (configuration.isGeneratedDoc(typeElement) && !utils.hasHiddenTag(typeElement)) {
if (configuration.isGeneratedDoc(typeElement) && !utils.isHidden(typeElement)) {
DocPath fileName = getPath(linkInfo);
if (linkInfo.linkToSelf() || typeElement != m_writer.getCurrentTypeElement()) {
link.add(m_writer.links.createLink(

View File

@ -238,12 +238,10 @@ public class MethodWriter extends AbstractExecutableMemberWriter {
protected void addComments(TypeMirror holderType, ExecutableElement method, Content methodContent) {
TypeElement holder = utils.asTypeElement(holderType);
if (!utils.getFullBody(method).isEmpty()) {
if (holder.equals(typeElement) ||
!(utils.isPublic(holder) ||
utils.isLinkable(holder))) {
if (holder.equals(typeElement) || !utils.isVisible(holder)) {
writer.addInlineComment(method, methodContent);
} else {
if (!utils.hasHiddenTag(holder) && !utils.hasHiddenTag(method)) {
if (!utils.isHidden(holder) && !utils.isHidden(method)) {
Content link =
writer.getDocLink(HtmlLinkInfo.Kind.PLAIN,
holder, method,
@ -349,7 +347,7 @@ public class MethodWriter extends AbstractExecutableMemberWriter {
}
Utils utils = writer.utils;
TypeElement holder = utils.getEnclosingTypeElement(method);
if (!(utils.isPublic(holder) || utils.isLinkable(holder))) {
if (!utils.isVisible(holder) || utils.isHidden(method)) {
//This is an implementation detail that should not be documented.
return;
}
@ -358,9 +356,6 @@ public class MethodWriter extends AbstractExecutableMemberWriter {
//is not visible so don't document this.
return;
}
if (utils.hasHiddenTag(holder) || utils.hasHiddenTag(method)) {
return;
}
Contents contents = writer.contents;
Content label;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2025, 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
@ -45,7 +45,6 @@ import jdk.javadoc.internal.html.Content;
import jdk.javadoc.internal.html.ContentBuilder;
import jdk.javadoc.internal.html.Entity;
import jdk.javadoc.internal.html.HtmlAttr;
import jdk.javadoc.internal.html.HtmlTag;
import jdk.javadoc.internal.html.HtmlTree;
import jdk.javadoc.internal.html.Text;
@ -404,7 +403,7 @@ public class Navigation {
: Text.of(pkg.getQualifiedName()));
// Breadcrumb navigation displays nested classes as separate links.
// Enclosing classes may be undocumented, in which case we just display the class name.
case TypeElement type -> (configuration.isGeneratedDoc(type) && !configuration.utils.hasHiddenTag(type))
case TypeElement type -> (configuration.isGeneratedDoc(type) && !configuration.utils.isHidden(type))
? links.createLink(pathToRoot.resolve(
docPaths.forClass(type)), type.getSimpleName().toString())
: HtmlTree.SPAN(Text.of(type.getSimpleName().toString()));

View File

@ -199,11 +199,10 @@ public class PropertyWriter extends AbstractMemberWriter {
protected void addComments(ExecutableElement property, Content propertyContent) {
TypeElement holder = (TypeElement)property.getEnclosingElement();
if (!utils.getFullBody(property).isEmpty()) {
if (holder.equals(typeElement) ||
(!utils.isPublic(holder) || utils.isLinkable(holder))) {
if (holder.equals(typeElement) || !utils.isVisible(holder)) {
writer.addInlineComment(property, propertyContent);
} else {
if (!utils.hasHiddenTag(holder) && !utils.hasHiddenTag(property)) {
if (!utils.isHidden(holder) && !utils.isHidden(property)) {
Content link =
writer.getDocLink(HtmlLinkInfo.Kind.PLAIN,
holder, property,

View File

@ -608,7 +608,7 @@ public class SerializedFormWriter extends SubWriterHolderWriter {
*/
public boolean isVisibleClass(TypeElement typeElement) {
return visibleClasses.contains(typeElement) && configuration.isGeneratedDoc(typeElement)
&& !utils.hasHiddenTag(typeElement);
&& !utils.isHidden(typeElement);
}
Content getClassHeader(TypeElement typeElement) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2025, 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
@ -162,7 +162,7 @@ public class Signatures {
boolean isFirst = true;
for (TypeMirror type : interfaces) {
TypeElement tDoc = utils.asTypeElement(type);
if (!(utils.isPublic(tDoc) || utils.isLinkable(tDoc))) {
if (!utils.isVisible(tDoc)) {
continue;
}
if (isFirst) {

View File

@ -248,8 +248,7 @@ public class LinkTaglet extends BaseTaglet {
containing = utils.getEnclosingTypeElement(overriddenMethod);
}
}
if (refSignature.trim().startsWith("#") &&
! (utils.isPublic(containing) || utils.isLinkable(containing))) {
if (refSignature.trim().startsWith("#") && !utils.isVisible(containing)) {
// Since the link is relative and the holder is not even being
// documented, this must be an inherited link. Redirect it.
// The current class either overrides the referenced member or

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2025, 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
@ -233,7 +233,7 @@ public class ClassTree {
continue;
}
if (utils.hasHiddenTag(te)) {
if (utils.isHidden(te)) {
continue;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2025, 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
@ -246,7 +246,7 @@ public abstract class IndexBuilder {
* Should this element be added to the index?
*/
private boolean shouldIndex(Element element) {
if (utils.hasHiddenTag(element)) {
if (utils.isHidden(element)) {
return false;
}

View File

@ -384,7 +384,7 @@ public class Utils {
public boolean isUndocumentedEnclosure(TypeElement enclosingTypeElement) {
return (isPackagePrivate(enclosingTypeElement) || isPrivate(enclosingTypeElement)
|| hasHiddenTag(enclosingTypeElement))
|| isHidden(enclosingTypeElement))
&& !isLinkable(enclosingTypeElement);
}
@ -786,7 +786,7 @@ public class Utils {
if (!visited.add(e)) {
continue; // seen it before
}
if (isPublic(e) || isLinkable(e)) {
if (isVisible(e)) {
results.add(t);
}
addSuperInterfaces(t, results, visited);
@ -849,7 +849,7 @@ public class Utils {
return
typeElem != null &&
((isIncluded(typeElem) && configuration.isGeneratedDoc(typeElem) &&
!hasHiddenTag(typeElem)) ||
!isHidden(typeElem)) ||
(configuration.extern.isExternal(typeElem) &&
(isPublic(typeElem) || isProtected(typeElem))));
}
@ -874,7 +874,7 @@ public class Utils {
return isLinkable((TypeElement) elem); // defer to existing behavior
}
if (isIncluded(elem) && !hasHiddenTag(elem)) {
if (isIncluded(elem) && !isHidden(elem)) {
return true;
}
@ -1006,7 +1006,7 @@ public class Utils {
t = supertypes.get(0); // if non-empty, the first element is always the superclass
var te = asTypeElement(t);
assert alreadySeen.add(te); // it should be the first time we see `te`
if (!hasHiddenTag(te) && (isPublic(te) || isLinkable(te))) {
if (isVisible(te)) {
return t;
}
}
@ -1237,16 +1237,32 @@ public class Utils {
}
/**
* Returns true if the element is included or selected, contains &#64;hidden tag,
* or if javafx flag is present and element contains &#64;treatAsPrivate
* tag.
* @param e the queried element
* @return true if it exists, false otherwise
* Returns {@code true} if the type element is visible. This means that it is not hidden,
* and is either public or linkable (either internally or externally).
*
* @param typeElement the type element
* @return {@code true} if the type element is visible
*/
public boolean hasHiddenTag(Element e) {
// Non-included elements may still be visible via "transclusion" from undocumented enclosures,
// but we don't want to run doclint on them, possibly causing warnings or errors.
public boolean isVisible(TypeElement typeElement) {
return !isHidden(typeElement) && (isPublic(typeElement) || isLinkable(typeElement));
}
/**
* Returns true if the element is hidden. An element is hidden if it contains a
* &#64;hidden tag, or if javafx flag is present and the element contains a
* &#64;treatAsPrivate tag, or the element is a type and is not included and
* not exported unconditionally by its module.
* @param e the queried element
* @return true if element is hidden, false otherwise
*/
public boolean isHidden(Element e) {
// Non-included elements may still be visible through the type hierarchy
if (!isIncluded(e)) {
// Treat types that are not included and not unconditionally exported as hidden
if (isClassOrInterface(e) && isUnexportedType((TypeElement) e)) {
return true;
}
// Use unchecked method to avoid running doclint, causing warnings or errors.
return hasBlockTagUnchecked(e, HIDDEN);
}
if (options.javafx() &&
@ -1256,6 +1272,21 @@ public class Utils {
return hasBlockTag(e, DocTree.Kind.HIDDEN);
}
/**
* {@return true if typeElement is in a package that is not unconditionally exported
* by its module}
* @param typeElement a type element
*/
private boolean isUnexportedType(TypeElement typeElement) {
var pkg = elementUtils.getPackageOf(typeElement);
var mdl = elementUtils.getModuleOf(typeElement);
return mdl != null && !mdl.isUnnamed()
&& mdl.getDirectives().stream()
.filter(d -> d.getKind() == ModuleElement.DirectiveKind.EXPORTS)
.map(d -> (ModuleElement.ExportsDirective) d)
.noneMatch(e -> e.getPackage().equals(pkg) && e.getTargetModules() == null);
}
/*
* Returns true if the passed method does not change the specification it
* inherited.
@ -1293,14 +1324,14 @@ public class Utils {
new TreeSet<>(comparators.generalPurposeComparator());
if (!javafx) {
for (TypeElement te : classlist) {
if (!hasHiddenTag(te)) {
if (!isHidden(te)) {
filteredOutClasses.add(te);
}
}
return filteredOutClasses;
}
for (TypeElement e : classlist) {
if (isPrivate(e) || isPackagePrivate(e) || hasHiddenTag(e)) {
if (isPrivate(e) || isPackagePrivate(e) || isHidden(e)) {
continue;
}
filteredOutClasses.add(e);
@ -2831,7 +2862,7 @@ public class Utils {
next = null; // end-of-hierarchy
break;
}
if (isPlainInterface(peek) && !isPublic(peek) && !isLinkable(peek)) {
if (isPlainInterface(peek) && !isVisible(peek)) {
// we don't consider such interfaces directly, but may consider
// their supertypes (subject to this check for each of them)
continue;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2025, 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
@ -502,7 +502,7 @@ public class VisibleMemberTable {
private boolean mustDocument(Element e) {
// these checks are ordered in a particular way to avoid parsing unless absolutely necessary
return utils.shouldDocument(e) && !utils.hasHiddenTag(e);
return utils.shouldDocument(e) && !utils.isHidden(e);
}
private boolean allowInheritedMembers(Element e, Kind kind, LocalMemberTable lmt) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2025, 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
@ -23,7 +23,7 @@
/*
* @test
* @bug 8073100 8182765 8196202 8261079 8261976
* @bug 8073100 8182765 8196202 8261079 8261976 8254622
* @summary ensure the hidden tag works as intended
* @library ../../lib
* @modules jdk.javadoc/jdk.javadoc.internal.tool
@ -139,7 +139,8 @@ public class TestHiddenTag extends JavadocTester {
"InvisibleParent.InvisibleInner",
"invisibleField",
"invisibleMethod",
"invisibleDefaultMethod");
"invisibleDefaultMethod",
"InvisibleInterface");
checkOutput("pkg1/InvisibleParent.VisibleInner.html", true,
"""
@ -151,12 +152,13 @@ public class TestHiddenTag extends JavadocTester {
checkOutput("pkg1/package-tree.html", false, "A.InvisibleInner");
checkOutput("pkg1/package-tree.html", false, "InvisibleParent.html");
checkOutput("pkg1/package-tree.html", false, "InvisibleParent.html", "InvisibleInterface");
checkFiles(false,
"pkg1/A.InvisibleInner.html",
"pkg1/A.InvisibleInnerExtendsVisibleInner.html",
"pkg1/InvisibleParent.html",
"pkg1/InvisibleParent.InvisibleInner.html");
"pkg1/InvisibleParent.InvisibleInner.html",
"pkg1/InvisibleParent.InvisibleInterface.html");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2025, 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
@ -27,7 +27,10 @@ import pkg2.UndocumentedParent;
/**
* A visible class, extending invisible classes.
*
* @see #invisibleInterfaceDefaultMethod()
* @see #invisibleInterfaceInterfaceMethod()
*/
public class Child extends UndocumentedParent<Child> {
public class Child extends UndocumentedParent<Child> implements InvisibleParent.InvisibleInterface {
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2025, 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
@ -55,4 +55,20 @@ public abstract class InvisibleParent<T extends InvisibleParent> implements Intf
*/
public static class InvisibleInner {}
/**
* An invisible interface.
* @hidden
*/
public static interface InvisibleInterface {
/**
* Default method in invisible interface.
*/
default void invisibleInterfaceDefaultMethod() {}
/**
* Interface method in invisible interface.
*/
void invisibleInterfaceInterfaceMethod();
}
}

View File

@ -0,0 +1,297 @@
/*
* Copyright (c) 2025, 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.
*/
/*
* @test
* @bug 8254622
* @summary Hide superclasses from conditionally exported packages
* @library /tools/lib ../../lib
* @modules jdk.javadoc/jdk.javadoc.internal.tool
* @build javadoc.tester.* toolbox.ToolBox
* @run main TestUnexported
*/
import java.io.IOException;
import java.nio.file.Path;
import toolbox.ModuleBuilder;
import toolbox.ToolBox;
import javadoc.tester.JavadocTester;
public class TestUnexported extends JavadocTester {
final ToolBox tb;
final Path src;
public static void main(String... args) throws Exception {
var tester = new TestUnexported();
tester.runTests();
}
TestUnexported() throws IOException {
tb = new ToolBox();
src = Path.of("src");
new ModuleBuilder(tb, "ma")
.classes("""
package pa;
import pa.internal.*;
/**
* Class with unexported super types.
*/
public abstract class A extends InternalClass implements InternalInterface {}
""",
"""
package pa.internal;
/**
* Conditionally exported class.
*/
public class InternalClass {
/**
* Method in internal class.
*/
public void p() {}
}
""",
"""
package pa.internal;
/**
* Conditionally exported interface.
*/
public interface InternalInterface {
/**
* Method in internal interface.
*/
public void m();
}
""")
.exports("pa")
.exportsTo("pa.internal", "mb")
.write(src);
new ModuleBuilder(tb, "mb")
.classes("""
package pb;
import pa.internal.*;
/**
* Class with conditionally exported super types.
*/
public abstract class B extends InternalClass implements InternalInterface {}
""",
"""
package pb;
import pa.internal.*;
/**
* Interface with conditionally exported super interface.
*/
public interface I extends InternalInterface {}
""")
.requires("ma")
.exports("pb")
.write(src);
}
// Types in packages that are exported conditionally are hidden in public API documentation.
@Test
public void test(Path base) throws Exception {
Path outDir = base.resolve("out");
javadoc("-d", outDir.toString(),
"--no-platform-links",
"--module-source-path", src.toString(),
"--show-packages", "exported",
"--module", "ma,mb");
checkExit(Exit.OK);
checkFiles(false, "ma/pa/internal/InternalClass.html", "ma/pa/internal/InternalInterface.html");
checkOutput("ma/pa/A.html", false, "InternalInterface", "InternalClass");
checkOutput("mb/pb/B.html", false, "InternalInterface", "InternalClass");
checkOutput("mb/pb/I.html", false, "InternalInterface");
checkOrder("ma/pa/A.html", """
<div class="inheritance" title="Inheritance Tree">java.lang.Object
<div class="inheritance">pa.A</div>
""",
"""
<div class="type-signature"><span class="modifiers">public abstract class </spa\
n><span class="element-name type-name-label">A</span>
<span class="extends-implements">extends java.lang.Object</span></div>
""",
"""
<section class="detail" id="m()">
<h3>m</h3>
<div class="horizontal-scroll">
<div class="member-signature"><span class="return-type">void</span>&nbsp;<span \
class="element-name">m</span>()</div>
<div class="block">Method in internal interface.</div>
</div>
</section>
""",
"""
<section class="detail" id="p()">
<h3>p</h3>
<div class="horizontal-scroll">
<div class="member-signature"><span class="modifiers">public</span>&nbsp;<span \
class="return-type">void</span>&nbsp;<span class="element-name">p</span>()</div>
<div class="block">Method in internal class.</div>
</div>
</section>
""");
checkOrder("mb/pb/B.html", """
<div class="inheritance" title="Inheritance Tree">java.lang.Object
<div class="inheritance">pb.B</div>
""",
"""
<div class="type-signature"><span class="modifiers">public abstract class </spa\
n><span class="element-name type-name-label">B</span>
<span class="extends-implements">extends java.lang.Object</span></div>
""",
"""
<section class="detail" id="m()">
<h3>m</h3>
<div class="horizontal-scroll">
<div class="member-signature"><span class="return-type">void</span>&nbsp;<span \
class="element-name">m</span>()</div>
<div class="block">Method in internal interface.</div>
</div>
</section>
""",
"""
<section class="detail" id="p()">
<h3>p</h3>
<div class="horizontal-scroll">
<div class="member-signature"><span class="modifiers">public</span>&nbsp;<span \
class="return-type">void</span>&nbsp;<span class="element-name">p</span>()</div>
<div class="block">Method in internal class.</div>
</div>
</section>
""");
checkOrder("mb/pb/I.html", """
<div class="type-signature"><span class="modifiers">public interface </span><sp\
an class="element-name type-name-label">I</span></div>
""",
"""
<section class="detail" id="m()">
<h3>m</h3>
<div class="horizontal-scroll">
<div class="member-signature"><span class="return-type">void</span>&nbsp;<span \
class="element-name">m</span>()</div>
<div class="block">Method in internal interface.</div>
</div>
</section>
""");
}
// Types in packages that are exported conditionally are shown when documenting
// all module packages including internal ones.
@Test
public void testIncluded(Path base) throws Exception {
Path outDir = base.resolve("out");
javadoc("-d", outDir.toString(),
"--no-platform-links",
"--module-source-path", src.toString(),
"--show-module-contents", "all",
"--show-packages", "all",
"--module", "ma,mb");
checkExit(Exit.OK);
checkFiles(true, "ma/pa/internal/InternalClass.html", "ma/pa/internal/InternalInterface.html");
checkOutput("ma/pa/A.html", true, "InternalInterface", "InternalClass");
checkOutput("mb/pb/B.html", true, "InternalInterface", "InternalClass");
checkOutput("mb/pb/I.html", true, "InternalInterface");
checkOrder("ma/pa/A.html",
"""
<div class="inheritance" title="Inheritance Tree">java.lang.Object
<div class="inheritance"><a href="internal/InternalClass.html" title="class in \
pa.internal">pa.internal.InternalClass</a>
<div class="inheritance">pa.A</div>
""",
"""
<div class="type-signature"><span class="modifiers">public abstract class </spa\
n><span class="element-name type-name-label">A</span>
<span class="extends-implements">extends <a href="internal/InternalClass.html" \
title="class in pa.internal">InternalClass</a>
implements <a href="internal/InternalInterface.html" title="interface in pa.int\
ernal">InternalInterface</a></span></div>
""",
"""
<h3 id="methods-inherited-from-class-pa.internal.InternalClass">Methods inherit\
ed from class&nbsp;<a href="internal/InternalClass.html#method-summary" title="\
class in pa.internal">InternalClass</a></h3>
<code><a href="internal/InternalClass.html#p()" title="p()">p</a></code></div>
""",
"""
<h3 id="methods-inherited-from-class-pa.internal.InternalInterface">Methods inh\
erited from interface&nbsp;<a href="internal/InternalInterface.html#method-summ\
ary" title="interface in pa.internal">InternalInterface</a></h3>
<code><a href="internal/InternalInterface.html#m()" title="m()">m</a></code></div>
""");
checkOrder("mb/pb/B.html",
"""
<div class="inheritance" title="Inheritance Tree">java.lang.Object
<div class="inheritance"><a href="../../ma/pa/internal/InternalClass.html" titl\
e="class in pa.internal">pa.internal.InternalClass</a>
<div class="inheritance">pb.B</div>
""",
"""
<div class="type-signature"><span class="modifiers">public abstract class </spa\
n><span class="element-name type-name-label">B</span>
<span class="extends-implements">extends <a href="../../ma/pa/internal/Internal\
Class.html" title="class in pa.internal">InternalClass</a>
implements <a href="../../ma/pa/internal/InternalInterface.html" title="interfa\
ce in pa.internal">InternalInterface</a></span></div>
""",
"""
<h3 id="methods-inherited-from-class-pa.internal.InternalClass">Methods inherit\
ed from class&nbsp;<a href="../../ma/pa/internal/InternalClass.html#method-summ\
ary" title="class in pa.internal">InternalClass</a></h3>
<code><a href="../../ma/pa/internal/InternalClass.html#p()" title="p()">p</a></code></div>
""",
"""
<h3 id="methods-inherited-from-class-pa.internal.InternalInterface">Methods inh\
erited from interface&nbsp;<a href="../../ma/pa/internal/InternalInterface.html\
#method-summary" title="interface in pa.internal">InternalInterface</a></h3>
<code><a href="../../ma/pa/internal/InternalInterface.html#m()" title="m()">m</a></code></div>
""");
}
}