8277300: Issues with javadoc support for preview features

Reviewed-by: prappo, jjg
This commit is contained in:
Jan Lahoda 2022-02-18 09:41:12 +00:00
parent 138a17195d
commit 834d55c59f
8 changed files with 239 additions and 30 deletions
src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets
test/langtools/jdk/javadoc/doclet/testPreview

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2022, 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
@ -89,18 +89,29 @@ public class HtmlLinkFactory extends LinkFactory {
}
Content label = classLinkInfo.getClassLinkLabel(configuration);
Set<ElementFlag> flags;
Element target;
Element previewTarget;
boolean showPreview = !classLinkInfo.skipPreview;
if (!hasWhere && showPreview) {
flags = utils.elementFlags(typeElement);
target = typeElement;
previewTarget = typeElement;
} else if ((classLinkInfo.context == HtmlLinkInfo.Kind.SEE_TAG || classLinkInfo.context == HtmlLinkInfo.Kind.MEMBER_DEPRECATED_PREVIEW) &&
classLinkInfo.targetMember != null && showPreview) {
flags = utils.elementFlags(classLinkInfo.targetMember);
target = classLinkInfo.targetMember;
TypeElement enclosing = utils.getEnclosingTypeElement(classLinkInfo.targetMember);
Set<ElementFlag> enclosingFlags = utils.elementFlags(enclosing);
if (flags.contains(ElementFlag.PREVIEW) && enclosingFlags.contains(ElementFlag.PREVIEW)) {
if (enclosing.equals(m_writer.getCurrentPageElement())) {
//skip the PREVIEW tag:
flags = EnumSet.copyOf(flags);
flags.remove(ElementFlag.PREVIEW);
}
previewTarget = enclosing;
} else {
previewTarget = classLinkInfo.targetMember;
}
} else {
flags = EnumSet.noneOf(ElementFlag.class);
target = null;
previewTarget = null;
}
Content link = new ContentBuilder();
@ -115,7 +126,7 @@ public class HtmlLinkFactory extends LinkFactory {
title));
if (flags.contains(ElementFlag.PREVIEW)) {
link.add(HtmlTree.SUP(m_writer.links.createLink(
filename.fragment(m_writer.htmlIds.forPreviewSection(target).name()),
filename.fragment(m_writer.htmlIds.forPreviewSection(previewTarget).name()),
m_writer.contents.previewMark)));
}
return link;
@ -130,7 +141,7 @@ public class HtmlLinkFactory extends LinkFactory {
if (flags.contains(ElementFlag.PREVIEW)) {
link.add(HtmlTree.SUP(m_writer.getCrossClassLink(
typeElement,
m_writer.htmlIds.forPreviewSection(target).name(),
m_writer.htmlIds.forPreviewSection(previewTarget).name(),
m_writer.contents.previewMark,
null, false)));
}
@ -192,7 +203,7 @@ public class HtmlLinkFactory extends LinkFactory {
*/
protected Content getTypeParameterLink(LinkInfo linkInfo, TypeMirror typeParam) {
HtmlLinkInfo typeLinkInfo = new HtmlLinkInfo(m_writer.configuration,
((HtmlLinkInfo) linkInfo).getContext(), typeParam).skipPreview(true);
((HtmlLinkInfo) linkInfo).getContext(), typeParam);
typeLinkInfo.excludeTypeBounds = linkInfo.excludeTypeBounds;
typeLinkInfo.excludeTypeParameterLinks = linkInfo.excludeTypeParameterLinks;
typeLinkInfo.linkToSelf = linkInfo.linkToSelf;

@ -76,6 +76,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
import jdk.javadoc.internal.doclets.toolkit.util.IndexItem;
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
import jdk.javadoc.internal.doclets.toolkit.util.Utils.PreviewFlagProvider;
/**
* The taglet writer that writes HTML.
@ -435,12 +436,18 @@ public class TagletWriterImpl extends TagletWriter {
int idx = line.indexOf(strippedLine);
assert idx >= 0; // because the stripped line is a substring of the line being stripped
Text whitespace = Text.of(utils.normalizeNewlines(line.substring(0, idx)));
// If the leading whitespace is not excluded from the link,
// browsers might exhibit unwanted behavior. For example, a
// browser might display hand-click cursor while user hovers
// over that whitespace portion of the line; or use
// underline decoration.
c = new ContentBuilder(whitespace, htmlWriter.linkToContent(element, e, t, strippedLine));
//disable preview tagging inside the snippets:
PreviewFlagProvider prevPreviewProvider = utils.setPreviewFlagProvider(el -> false);
try {
// If the leading whitespace is not excluded from the link,
// browsers might exhibit unwanted behavior. For example, a
// browser might display hand-click cursor while user hovers
// over that whitespace portion of the line; or use
// underline decoration.
c = new ContentBuilder(whitespace, htmlWriter.linkToContent(element, e, t, strippedLine));
} finally {
utils.setPreviewFlagProvider(prevPreviewProvider);
}
// We don't care about trailing whitespace.
} else {
c = HtmlTree.SPAN(Text.of(text));

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2022, 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
@ -3053,9 +3053,11 @@ public class Utils {
*/
public boolean isPreviewAPI(Element el) {
boolean parentPreviewAPI = false;
Element enclosing = el.getEnclosingElement();
if (enclosing != null && (enclosing.getKind().isClass() || enclosing.getKind().isInterface())) {
parentPreviewAPI = configuration.workArounds.isPreviewAPI(enclosing);
if (!isClassOrInterface(el)) {
Element enclosing = el.getEnclosingElement();
if (isClassOrInterface(enclosing)) {
parentPreviewAPI = configuration.workArounds.isPreviewAPI(enclosing);
}
}
boolean previewAPI = configuration.workArounds.isPreviewAPI(el);
return !parentPreviewAPI && previewAPI;
@ -3082,18 +3084,12 @@ public class Utils {
*/
public Set<ElementFlag> elementFlags(Element el) {
Set<ElementFlag> flags = EnumSet.noneOf(ElementFlag.class);
PreviewSummary previewAPIs = declaredUsingPreviewAPIs(el);
if (isDeprecated(el)) {
flags.add(ElementFlag.DEPRECATED);
}
if ((!previewLanguageFeaturesUsed(el).isEmpty() ||
configuration.workArounds.isPreviewAPI(el) ||
!previewAPIs.previewAPI.isEmpty() ||
!previewAPIs.reflectivePreviewAPI.isEmpty() ||
!previewAPIs.declaredUsingPreviewFeature.isEmpty()) &&
!hasNoProviewAnnotation(el)) {
if (previewFlagProvider.isPreview(el)) {
flags.add(ElementFlag.PREVIEW);
}
@ -3109,9 +3105,42 @@ public class Utils {
PREVIEW
}
private boolean hasNoProviewAnnotation(Element el) {
private boolean isClassOrInterface(Element el) {
return el != null && (el.getKind().isClass() || el.getKind().isInterface());
}
private boolean hasNoPreviewAnnotation(Element el) {
return el.getAnnotationMirrors()
.stream()
.anyMatch(am -> "jdk.internal.javac.NoPreview".equals(getQualifiedTypeName(am.getAnnotationType())));
}
private PreviewFlagProvider previewFlagProvider = new PreviewFlagProvider() {
@Override
public boolean isPreview(Element el) {
PreviewSummary previewAPIs = declaredUsingPreviewAPIs(el);
Element enclosing = el.getEnclosingElement();
return ( !previewLanguageFeaturesUsed(el).isEmpty()
|| configuration.workArounds.isPreviewAPI(el)
|| ( !isClassOrInterface(el) && isClassOrInterface(enclosing)
&& configuration.workArounds.isPreviewAPI(enclosing))
|| !previewAPIs.previewAPI.isEmpty()
|| !previewAPIs.reflectivePreviewAPI.isEmpty()
|| !previewAPIs.declaredUsingPreviewFeature.isEmpty())
&& !hasNoPreviewAnnotation(el);
}
};
public PreviewFlagProvider setPreviewFlagProvider(PreviewFlagProvider provider) {
Objects.requireNonNull(provider);
PreviewFlagProvider old = previewFlagProvider;
previewFlagProvider = provider;
return old;
}
public interface PreviewFlagProvider {
public boolean isPreview(Element el);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2022, 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 8250768 8261976
* @bug 8250768 8261976 8277300
* @summary test generated docs for items declared using preview
* @library ../../lib
* @modules jdk.javadoc/jdk.javadoc.internal.tool
@ -33,8 +33,6 @@
*/
import java.nio.file.Paths;
import java.text.MessageFormat;
import java.util.ResourceBundle;
import javadoc.tester.JavadocTester;
public class TestPreview extends JavadocTester {
@ -101,4 +99,25 @@ public class TestPreview extends JavadocTester {
</div>
""");
}
@Test
public void test8277300() {
javadoc("-d", "out-8277300",
"--add-exports", "java.base/jdk.internal.javac=api2",
"--source-path", Paths.get(testSrc, "api2").toAbsolutePath().toString(),
"--show-packages=all",
"api2/api");
checkExit(Exit.OK);
checkOutput("api2/api/API.html", true,
"<p><a href=\"#test()\"><code>test()</code></a></p>",
"<p><a href=\"#testNoPreviewInSig()\"><code>testNoPreviewInSig()</code></a></p>",
"title=\"class or interface in java.util\" class=\"external-link\">List</a>&lt;<a href=\"API.html\" title=\"class in api\">API</a><sup><a href=\"#preview-api.API\">PREVIEW</a></sup>&gt;");
checkOutput("api2/api/API2.html", true,
"<a href=\"API.html#test()\"><code>API.test()</code></a><sup><a href=\"API.html#preview-api.API\">PREVIEW</a></sup>",
"<a href=\"API.html#testNoPreviewInSig()\"><code>API.testNoPreviewInSig()</code></a><sup><a href=\"API.html#preview-api.API\">PREVIEW</a></sup>",
"<a href=\"API3.html#test()\"><code>API3.test()</code></a><sup><a href=\"API3.html#preview-test()\">PREVIEW</a></sup>");
checkOutput("api2/api/API3.html", true,
"<div class=\"block\"><a href=\"#test()\"><code>test()</code></a><sup><a href=\"#preview-test()\">PREVIEW</a></sup></div>");
}
}

@ -0,0 +1,46 @@
/*
* Copyright (c) 2022, 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 api;
import java.util.List;
import jdk.internal.javac.PreviewFeature;
import jdk.internal.javac.PreviewFeature.Feature;
/**
* <p>{@link API#test()}</p>
* <p>{@link API#testNoPreviewInSig()}</p>
*/
@PreviewFeature(feature=Feature.TEST, reflective=false)
public class API {
public API test() {
return null;
}
public void testNoPreviewInSig() {
}
public void typeArgs(List<API> api) {
}
}

@ -0,0 +1,33 @@
/*
* Copyright (c) 2022, 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 api;
/**
* <p>{@link API#test()}
* <p>{@link API#testNoPreviewInSig()}
* <p>{@link API3#test()}
*/
public class API2 {
}

@ -0,0 +1,39 @@
/*
* Copyright (c) 2022, 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 api;
import jdk.internal.javac.PreviewFeature;
import jdk.internal.javac.PreviewFeature.Feature;
/**
* {@link API3#test()}
*/
public class API3 {
@PreviewFeature(feature=Feature.TEST, reflective=false)
public void test() {
return null;
}
}

@ -0,0 +1,25 @@
/*
* Copyright (c) 2022, 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.
*/
module api2 {
exports api;
}