From 882f909b383cb8cd709ac01b585349f6c98bf53e Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Wed, 18 Dec 2024 11:12:15 +0100 Subject: [PATCH] WIP --- .../formats/html/taglets/SnippetTaglet.java | 47 ++++++------ .../toolkit/resources/doclets.properties | 6 +- .../ReproducibleSnippetTest.java | 75 +++++++++++++++++++ 3 files changed, 103 insertions(+), 25 deletions(-) create mode 100644 test/langtools/jdk/javadoc/doclet/ReproducibleSnippet/ReproducibleSnippetTest.java diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java index 93f83c5ba90c1..aeb0d55e87d4c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java @@ -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 @@ -49,6 +49,7 @@ import com.sun.source.doctree.TextTree; import com.sun.source.util.DocTreePath; +import com.sun.tools.javac.tree.DCTree; import jdk.javadoc.doclet.Taglet; import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; @@ -68,6 +69,7 @@ import jdk.javadoc.internal.html.Text; import static jdk.javadoc.internal.doclets.formats.html.taglets.SnippetTaglet.Language.*; +import static jdk.javadoc.internal.doclint.Messages.Group.MISSING; /** * A taglet that represents the {@code @snippet} tag. @@ -133,43 +135,40 @@ private Content snippetTagOutput(Element element, SnippetTree tag, StyledText co if (lang != null && !lang.isBlank()) { code.addStyle("language-" + lang); } - + //todo err: ambigious link (location) content.consumeBy((styles, sequence) -> { CharSequence text = Text.normalizeNewlines(sequence); if (styles.isEmpty()) { code.add(text); } else { Element e = null; - String t = null; - boolean linkEncountered = false; + String linkEncountered = null; boolean markupEncountered = false; Set classes = new HashSet<>(); for (Style s : styles) { - if (s instanceof Style.Name n) { - classes.add(n.name()); - } else if (s instanceof Style.Link l) { - assert !linkEncountered; // TODO: do not assert; pick the first link report on subsequent - linkEncountered = true; - t = l.target(); - e = getLinkedElement(element, t); - if (e == null) { - // TODO: diagnostic output + switch (s) { + case Style.Name n -> classes.add(n.name()); + case Style.Link l -> { + if (linkEncountered != null) { // link encountered + messages.error(utils.getCommentHelper(element).getDocTreePath(tag), + "doclet.error.snippet.ambiguous.link", + linkEncountered, + l.target(), + content.asCharSequence().toString().trim()); + } + linkEncountered = l.target(); + e = getLinkedElement(element, linkEncountered); + if (e == null) { + // TODO: diagnostic output + } } - } else if (s instanceof Style.Markup) { - markupEncountered = true; - break; - } else { - // TODO: transform this if...else into an exhaustive - // switch over the sealed Style hierarchy when "Pattern - // Matching for switch" has been implemented (JEP 406 - // and friends) - throw new AssertionError(styles); + case Style.Markup m -> markupEncountered = true; } } Content c; if (markupEncountered) { return; - } else if (linkEncountered) { + } else if (linkEncountered != null) { assert e != null; //disable preview tagging inside the snippets: Utils.PreviewFlagProvider prevPreviewProvider = utils.setPreviewFlagProvider(el -> false); @@ -177,7 +176,7 @@ private Content snippetTagOutput(Element element, SnippetTree tag, StyledText co var lt = (LinkTaglet) config.tagletManager.getTaglet(DocTree.Kind.LINK); c = lt.linkSeeReferenceOutput(element, null, - t, + linkEncountered, e, false, // TODO: for now Text.of(sequence.toString()), diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties index 0ee9429ec0c65..8bfaa8f96781a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2010, 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 @@ -432,3 +432,7 @@ doclet.cannot_use_snippet_path=\ # 0: path; 1: exception doclet.error_setting_snippet_path=\ Error setting snippet path {0}: {1} + +# 0: location +doclet.error.snippet.ambiguous.link=\ + ambiguous links: {0}, {1} to {2} diff --git a/test/langtools/jdk/javadoc/doclet/ReproducibleSnippet/ReproducibleSnippetTest.java b/test/langtools/jdk/javadoc/doclet/ReproducibleSnippet/ReproducibleSnippetTest.java new file mode 100644 index 0000000000000..0cb4b8b2ce0d4 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/ReproducibleSnippet/ReproducibleSnippetTest.java @@ -0,0 +1,75 @@ +/* + * 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 8346128 8346659 + * @summary Check that snippet generation is reproducible + * @library /tools/lib ../../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * @build toolbox.ToolBox javadoc.tester.* + * @run main ReproducibleSnippetTest + */ + +import javadoc.tester.JavadocTester; +import toolbox.ToolBox; + +import java.nio.file.Path; + +public class ReproducibleSnippetTest extends JavadocTester { + ToolBox tb = new ToolBox(); + + public static void main(String... args) throws Exception { + var tester = new ReproducibleSnippetTest(); + tester.runTests(); + } + + @Test + public void test(Path base) throws Exception { + + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + """ + package p; + public interface One { + /** + * {@code One obj1} + * {@snippet lang = java: + * // @link substring="ab" target="One#ab" : + * obj1.ab(a()); // @link substring="a" target="#a" + *} class comment + */ + void start(); + int a(); + void with(); + void ab(int i); + } + """); + javadoc("-d", + "out", + "-sourcepath", + src.toString(), + "p"); + checkExit(Exit.ERROR); + } +}