From 873558ee80d741469ade030c732091bead431c46 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Wed, 8 Feb 2023 21:57:22 +0000 Subject: [PATCH] 8300914: Allow `@` as an escape in documentation comments Reviewed-by: prappo --- .../com/sun/source/doctree/DocTree.java | 12 +- .../sun/source/doctree/DocTreeVisitor.java | 18 ++- .../com/sun/source/doctree/EscapeTree.java | 57 +++++++ .../com/sun/source/util/DocTreeFactory.java | 28 +++- .../com/sun/source/util/DocTreeScanner.java | 18 ++- .../sun/source/util/SimpleDocTreeVisitor.java | 18 ++- .../tools/javac/parser/DocCommentParser.java | 80 +++++++++- .../com/sun/tools/javac/tree/DCTree.java | 29 +++- .../com/sun/tools/javac/tree/DocPretty.java | 13 +- .../sun/tools/javac/tree/DocTreeMaker.java | 10 +- .../shellsupport/doc/JavadocFormatter.java | 9 +- .../formats/html/HtmlDocletWriter.java | 7 + .../doclets/toolkit/util/CommentHelper.java | 8 +- .../jdk/javadoc/internal/doclint/Checker.java | 12 +- .../langtools/tools/doclint/HtmlTagsTest.java | 8 + test/langtools/tools/doclint/HtmlTagsTest.out | 8 +- test/langtools/tools/doclint/ReturnTest.java | 31 ++++ test/langtools/tools/doclint/ReturnTest.out | 19 +++ test/langtools/tools/doclint/SummaryTest.java | 15 +- test/langtools/tools/doclint/SummaryTest.out | 11 +- .../tools/javac/doctree/AtEscapeTest.java | 148 ++++++++++++++++++ .../tools/javac/doctree/DocCommentTester.java | 9 +- 22 files changed, 543 insertions(+), 25 deletions(-) create mode 100644 src/jdk.compiler/share/classes/com/sun/source/doctree/EscapeTree.java create mode 100644 test/langtools/tools/doclint/ReturnTest.java create mode 100644 test/langtools/tools/doclint/ReturnTest.out create mode 100644 test/langtools/tools/javac/doctree/AtEscapeTest.java diff --git a/src/jdk.compiler/share/classes/com/sun/source/doctree/DocTree.java b/src/jdk.compiler/share/classes/com/sun/source/doctree/DocTree.java index 7f81af9a507..a7c2c49df83 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/doctree/DocTree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/doctree/DocTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2023, 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 @@ -103,6 +103,14 @@ public interface DocTree { */ ERRONEOUS, + /** + * Used for instances of {@link EscapeTree} + * representing some escaped documentation text. + * + * @since 21 + */ + ESCAPE, + /** * Used for instances of {@link ThrowsTree} * representing an {@code @exception} tag. @@ -250,7 +258,7 @@ public interface DocTree { /** * Used for instances of {@link TextTree} - * representing some documentation text. + * representing some plain documentation text. */ TEXT, diff --git a/src/jdk.compiler/share/classes/com/sun/source/doctree/DocTreeVisitor.java b/src/jdk.compiler/share/classes/com/sun/source/doctree/DocTreeVisitor.java index 7bfaa7acd46..d7ddbe30d9e 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/doctree/DocTreeVisitor.java +++ b/src/jdk.compiler/share/classes/com/sun/source/doctree/DocTreeVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2023, 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 @@ -143,6 +143,22 @@ public interface DocTreeVisitor { */ R visitErroneous(ErroneousTree node, P p); + /** + * Visits an {@code EscapeTree} node. + * + * @implSpec Visits the provided {@code EscapeTree} node + * by calling {@code visitOther(node, p)}. + * + * @param node the node being visited + * @param p a parameter value + * @return a result value + * + * @since 21 + */ + default R visitEscape(EscapeTree node, P p) { + return visitOther(node, p); + } + /** * Visits a {@code HiddenTree} node. * diff --git a/src/jdk.compiler/share/classes/com/sun/source/doctree/EscapeTree.java b/src/jdk.compiler/share/classes/com/sun/source/doctree/EscapeTree.java new file mode 100644 index 00000000000..e29bfd31893 --- /dev/null +++ b/src/jdk.compiler/share/classes/com/sun/source/doctree/EscapeTree.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 com.sun.source.doctree; + +import javax.lang.model.element.Element; +import javax.lang.model.util.Elements; + +/** + * A tree node for a character represented by an escape sequence. + * + * @apiNote This class does not itself constrain the set of valid escape sequences, + * although the set may be effectively constrained to those defined in the + * + * Documentation Comment Specification for the Standard Doclet, + * including the following context-sensitive escape sequences: + * + * + * + * @since 21 + */ +public interface EscapeTree extends TextTree { + /** + * {@inheritDoc} + * + *

Note: this method returns the escaped character, not the original escape sequence. + */ + @Override + String getBody(); +} diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeFactory.java b/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeFactory.java index 78e973d23d4..571db71546e 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeFactory.java +++ b/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2023, 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,9 @@ package com.sun.source.util; import java.util.List; +import javax.lang.model.element.Element; import javax.lang.model.element.Name; +import javax.lang.model.util.Elements; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; @@ -43,6 +45,7 @@ import com.sun.source.doctree.DocTypeTree; import com.sun.source.doctree.EndElementTree; import com.sun.source.doctree.EntityTree; import com.sun.source.doctree.ErroneousTree; +import com.sun.source.doctree.EscapeTree; import com.sun.source.doctree.HiddenTree; import com.sun.source.doctree.IdentifierTree; import com.sun.source.doctree.IndexTree; @@ -175,6 +178,29 @@ public interface DocTreeFactory { */ ErroneousTree newErroneousTree(String text, Diagnostic diag); + /** + * Creates a new {@code EscapeTree} object, to represent an escaped character. + * + * @apiNote This method does not itself constrain the set of valid escape sequences, + * although the set may be effectively constrained to those defined in the + * + * Documentation Comment Specification for the Standard Doclet, + * including the following context-sensitive escape sequences: + * + *

+ * + * @param ch the character + * @return an {@code EscapeTree} object + * + * @since 21 + */ + EscapeTree newEscapeTree(char ch); + /** * Creates a new {@code ThrowsTree} object, to represent an {@code @exception} tag. * @param name the name of the exception diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeScanner.java b/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeScanner.java index bd5a64324ca..28cc82e7378 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeScanner.java +++ b/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeScanner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2023, 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 @@ -277,6 +277,22 @@ public class DocTreeScanner implements DocTreeVisitor { return null; } + /** + * {@inheritDoc} + * + * @implSpec This implementation returns {@code null}. + * + * @param node {@inheritDoc} + * @param p {@inheritDoc} + * @return the result of scanning + * + * @since 21 + */ + @Override + public R visitEscape(EscapeTree node, P p) { + return null; + } + /** * {@inheritDoc} * diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/SimpleDocTreeVisitor.java b/src/jdk.compiler/share/classes/com/sun/source/util/SimpleDocTreeVisitor.java index b3a27f9e6b4..bdd6225c869 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/util/SimpleDocTreeVisitor.java +++ b/src/jdk.compiler/share/classes/com/sun/source/util/SimpleDocTreeVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2023, 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 @@ -232,6 +232,22 @@ public class SimpleDocTreeVisitor implements DocTreeVisitor { return defaultAction(node, p); } + /** + * {@inheritDoc} + * + * @implSpec This implementation calls {@code defaultAction}. + * + * @param node {@inheritDoc} + * @param p {@inheritDoc} + * @return the result of {@code defaultAction} + * + * @since 21 + */ + @Override + public R visitEscape(EscapeTree node, P p) { + return defaultAction(node, p); + } + /** * {@inheritDoc} * diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java index 1a12e939f4f..dbf5075c59a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java @@ -152,6 +152,10 @@ public class DocCommentParser { } } + char peekChar() { + return buf[bp < buflen ? bp + 1 : buflen]; + } + protected List blockContent() { return blockContent(Phase.BODY); } @@ -224,9 +228,32 @@ public class DocCommentParser { break; case '@': + // check for context-sensitive escape sequences: + // newline whitespace @@ + // newline whitespace @* + // *@/ if (newline) { - addPendingText(trees, lastNonWhite); - break loop; + char peek = peekChar(); + if (peek == '@' || peek == '*') { + addPendingText(trees, bp - 1); + nextChar(); + trees.add(m.at(bp - 1).newEscapeTree(ch)); + newline = false; + nextChar(); + textStart = bp; + break; + } else { + addPendingText(trees, lastNonWhite); + break loop; + } + } else if (textStart != -1 && buf[bp - 1] == '*' && peekChar() == '/') { + addPendingText(trees, bp - 1); + nextChar(); + trees.add(m.at(bp - 1).newEscapeTree('/')); + newline = false; + nextChar(); + textStart = bp; + break; } // fallthrough @@ -294,10 +321,24 @@ public class DocCommentParser { newline = false; nextChar(); if (ch == '@') { - addPendingText(list, bp - 2); - list.add(inlineTag()); - textStart = bp; - lastNonWhite = -1; + // check for context-sensitive escape-sequence + // {@@ + if (peekChar() == '@') { + if (textStart == -1) { + textStart = bp - 1; + } + addPendingText(list, bp - 1); + nextChar(); + list.add(m.at(bp - 1).newEscapeTree('@')); + nextChar(); + textStart = -1; + lastNonWhite = bp; + } else { + addPendingText(list, bp - 2); + list.add(inlineTag()); + textStart = bp; + lastNonWhite = -1; + } } else { if (textStart == -1) textStart = bp - 1; @@ -624,6 +665,33 @@ public class DocCommentParser { nextChar(); break; + case '@': + // check for context-sensitive escape sequences: + // newline whitespace @@ + // newline whitespace @* + // *@/ + if (newline) { + char peek = peekChar(); + if (peek == '@' || peek == '*') { + addPendingText(trees, bp - 1); + nextChar(); + trees.add(m.at(bp - 1).newEscapeTree(ch)); + newline = false; + nextChar(); + textStart = bp; + break; + } + } else if (textStart != -1 && buf[bp - 1] == '*' && peekChar() == '/') { + addPendingText(trees, bp - 1); + nextChar(); + trees.add(m.at(bp - 1).newEscapeTree('/')); + newline = false; + nextChar(); + textStart = bp; + break; + } + // fallthrough + default: if (textStart == -1) textStart = bp; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java index 95cb6e0fa3c..ceab2e08f0c 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2023, 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 @@ -168,6 +168,11 @@ public abstract class DCTree implements DocTree { return err.pos + err.body.length(); } + case ESCAPE -> { + DCEscape esc = (DCEscape) this; + return esc.pos + 2; + } + case IDENTIFIER -> { DCIdentifier ident = (DCIdentifier) this; return ident.pos + ident.name.length(); @@ -641,7 +646,29 @@ public abstract class DCTree implements DocTree { this.prefPos = prefPos; return this; } + } + public static class DCEscape extends DCTree implements EscapeTree { + public final char ch; + + DCEscape(char ch) { + this.ch = ch; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public Kind getKind() { + return Kind.ESCAPE; + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public R accept(DocTreeVisitor v, D d) { + return v.visitEscape(this, d); + } + + @Override @DefinedBy(Api.COMPILER_TREE) + public String getBody() { + return String.valueOf(ch); + } } public static class DCHidden extends DCBlockTag implements HiddenTree { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocPretty.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocPretty.java index e7c65ffac4e..8fd6e0541ae 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocPretty.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocPretty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2023, 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 @@ -245,6 +245,17 @@ public class DocPretty implements DocTreeVisitor { return null; } + @Override @DefinedBy(Api.COMPILER_TREE) + public Void visitEscape(EscapeTree node, Void p) { + try { + out.write("@"); + print(node.getBody()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + return null; + } + @Override @DefinedBy(Api.COMPILER_TREE) public Void visitHidden(HiddenTree node, Void p) { try { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java index cd6fdad70e6..81b9ac992c7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2023, 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 @@ -60,6 +60,7 @@ import com.sun.tools.javac.tree.DCTree.DCDocType; import com.sun.tools.javac.tree.DCTree.DCEndElement; import com.sun.tools.javac.tree.DCTree.DCEntity; import com.sun.tools.javac.tree.DCTree.DCErroneous; +import com.sun.tools.javac.tree.DCTree.DCEscape; import com.sun.tools.javac.tree.DCTree.DCHidden; import com.sun.tools.javac.tree.DCTree.DCIdentifier; import com.sun.tools.javac.tree.DCTree.DCIndex; @@ -276,6 +277,13 @@ public class DocTreeMaker implements DocTreeFactory { return tree; } + @Override @DefinedBy(Api.COMPILER_TREE) + public DCEscape newEscapeTree(char ch) { + DCEscape tree = new DCEscape(ch); + tree.pos = pos; + return tree; + } + @Override @DefinedBy(Api.COMPILER_TREE) public DCThrows newExceptionTree(ReferenceTree name, List description) { // TODO: verify the reference is just to a type (not a field or method) diff --git a/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/JavadocFormatter.java b/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/JavadocFormatter.java index afc10d0c988..07d3ccae510 100644 --- a/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/JavadocFormatter.java +++ b/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/JavadocFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, 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 @@ -48,6 +48,7 @@ import com.sun.source.doctree.DocCommentTree; import com.sun.source.doctree.DocTree; import com.sun.source.doctree.EndElementTree; import com.sun.source.doctree.EntityTree; +import com.sun.source.doctree.EscapeTree; import com.sun.source.doctree.InlineTagTree; import com.sun.source.doctree.LinkTree; import com.sun.source.doctree.LiteralTree; @@ -218,6 +219,12 @@ public class JavadocFormatter { return null; } + @Override @DefinedBy(Api.COMPILER_TREE) + public Object visitEscape(EscapeTree node, Object p) { + result.append(node.getBody()); + return null; + } + @Override @DefinedBy(Api.COMPILER_TREE) public Object visitLink(LinkTree node, Object p) { if (!node.getLabel().isEmpty()) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java index 11818f89424..29dd88e31ec 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java @@ -67,6 +67,7 @@ import com.sun.source.doctree.DocTree.Kind; import com.sun.source.doctree.EndElementTree; import com.sun.source.doctree.EntityTree; import com.sun.source.doctree.ErroneousTree; +import com.sun.source.doctree.EscapeTree; import com.sun.source.doctree.IndexTree; import com.sun.source.doctree.InheritDocTree; import com.sun.source.doctree.LinkTree; @@ -1338,6 +1339,12 @@ public class HtmlDocletWriter { return false; } + @Override + public Boolean visitEscape(EscapeTree node, Content content) { + result.add(node.getBody()); + return false; + } + @Override public Boolean visitInheritDoc(InheritDocTree node, Content content) { Content output = getInlineTagOutput(element, node, context); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java index 7007a160f9d..008ce5ab80d 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, 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 @@ -31,6 +31,7 @@ import com.sun.source.doctree.CommentTree; import com.sun.source.doctree.DeprecatedTree; import com.sun.source.doctree.DocCommentTree; import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.EscapeTree; import com.sun.source.doctree.IdentifierTree; import com.sun.source.doctree.InlineTagTree; import com.sun.source.doctree.LinkTree; @@ -386,6 +387,11 @@ public class CommentHelper { return node.getBody(); } + @Override + public List visitEscape(EscapeTree node, Void p) { + return asList(node.getBody()); + } + @Override public List visitLiteral(LiteralTree node, Void p) { return asList(node.getBody().getBody()); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java index fa9d3029673..061b05db6a9 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2023, 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 @@ -65,6 +65,7 @@ import com.sun.source.doctree.DocTree; import com.sun.source.doctree.EndElementTree; import com.sun.source.doctree.EntityTree; import com.sun.source.doctree.ErroneousTree; +import com.sun.source.doctree.EscapeTree; import com.sun.source.doctree.IdentifierTree; import com.sun.source.doctree.IndexTree; import com.sun.source.doctree.InheritDocTree; @@ -348,6 +349,7 @@ public class Checker extends DocTreePathScanner { @Override @DefinedBy(Api.COMPILER_TREE) public Void visitEntity(EntityTree tree, Void ignore) { + hasNonWhitespaceText = true; checkAllowsText(tree); markEnclosingTag(Flag.HAS_TEXT); String s = env.trees.getCharacters(tree); @@ -358,6 +360,14 @@ public class Checker extends DocTreePathScanner { } + @Override @DefinedBy(Api.COMPILER_TREE) + public Void visitEscape(EscapeTree tree, Void ignore) { + hasNonWhitespaceText = true; + checkAllowsText(tree); + markEnclosingTag(Flag.HAS_TEXT); + return null; + } + void checkAllowsText(DocTree tree) { TagStackItem top = tagStack.peek(); if (top != null diff --git a/test/langtools/tools/doclint/HtmlTagsTest.java b/test/langtools/tools/doclint/HtmlTagsTest.java index b922a67d8f1..cb0aa2eb984 100644 --- a/test/langtools/tools/doclint/HtmlTagsTest.java +++ b/test/langtools/tools/doclint/HtmlTagsTest.java @@ -66,6 +66,14 @@ public class HtmlTagsTest { */ public void inline_not_allowed() { } + /** + *
    &
  • ...
+ */ + public void entity_not_allowed() { } + /** + *
    *@/
  • ...
+ */ + public void escape_not_allowed() { } } diff --git a/test/langtools/tools/doclint/HtmlTagsTest.out b/test/langtools/tools/doclint/HtmlTagsTest.out index 8117de21dc1..8e8b1441888 100644 --- a/test/langtools/tools/doclint/HtmlTagsTest.out +++ b/test/langtools/tools/doclint/HtmlTagsTest.out @@ -43,5 +43,11 @@ HtmlTagsTest.java:60: error: text not allowed in
    element HtmlTagsTest.java:65: error: tag not allowed here: *
      text
    • ...
    ^ -13 errors +HtmlTagsTest.java:70: error: text not allowed in
      element + *
        &
      • ...
      + ^ +HtmlTagsTest.java:75: error: text not allowed in
        element + *
          *@/
        • ...
        + ^ +15 errors 2 warnings diff --git a/test/langtools/tools/doclint/ReturnTest.java b/test/langtools/tools/doclint/ReturnTest.java new file mode 100644 index 00000000000..9b3b819f94c --- /dev/null +++ b/test/langtools/tools/doclint/ReturnTest.java @@ -0,0 +1,31 @@ +/* + * @test /nodynamiccopyright/ + * @modules jdk.javadoc/jdk.javadoc.internal.doclint + * @build DocLintTester + * @run main DocLintTester -ref ReturnTest.out ReturnTest.java + */ + +/** No comment. */ +public class ReturnTest { + /** + {@return legal} **/ + public int m_legal() { return 0; } + + /**

        {@return illegal} **/ + public int m_illegal_html() { return 0; } + + /** text {@return illegal} **/ + public int m_illegal_text() { return 0; } + + /** &{@return illegal} **/ + public int m_illegal_entity() { return 0; } + + /** @@{@return illegal} **/ + public int m_illegal_escape() { return 0; } + + /** {@return legal} text {@return illegal} **/ + public int m_illegal_repeat() { return 0; } + + /** . */ + private ReturnTest() { } +} diff --git a/test/langtools/tools/doclint/ReturnTest.out b/test/langtools/tools/doclint/ReturnTest.out new file mode 100644 index 00000000000..85937e07fcd --- /dev/null +++ b/test/langtools/tools/doclint/ReturnTest.out @@ -0,0 +1,19 @@ +ReturnTest.java:14: warning: {@return} not at beginning of description + /**

        {@return illegal} **/ + ^ +ReturnTest.java:17: warning: {@return} not at beginning of description + /** text {@return illegal} **/ + ^ +ReturnTest.java:20: warning: {@return} not at beginning of description + /** &{@return illegal} **/ + ^ +ReturnTest.java:23: warning: {@return} not at beginning of description + /** @@{@return illegal} **/ + ^ +ReturnTest.java:26: warning: @return has already been specified + /** {@return legal} text {@return illegal} **/ + ^ +ReturnTest.java:26: warning: {@return} not at beginning of description + /** {@return legal} text {@return illegal} **/ + ^ +6 warnings \ No newline at end of file diff --git a/test/langtools/tools/doclint/SummaryTest.java b/test/langtools/tools/doclint/SummaryTest.java index 595374739f1..d6b27e418e1 100644 --- a/test/langtools/tools/doclint/SummaryTest.java +++ b/test/langtools/tools/doclint/SummaryTest.java @@ -9,13 +9,22 @@ public class SummaryTest { /** {@summary legal} **/ - public void m0() {} + public void m_legal() {} /**

        {@summary illegal} **/ - public void m1() {} + public void m_illegal_html() {} + + /** text {@summary illegal} **/ + public void m_illegal_text() {} + + /** &{@summary illegal} **/ + public void m_illegal_entity() {} + + /** @@{@summary illegal} **/ + public void m_illegal_escape() {} /** {@summary legal} text {@summary illegal} **/ - public void m2() {} + public void m_illegal_repeat() {} /** . */ private SummaryTest() { } diff --git a/test/langtools/tools/doclint/SummaryTest.out b/test/langtools/tools/doclint/SummaryTest.out index 026def99cf7..9557ad93c75 100644 --- a/test/langtools/tools/doclint/SummaryTest.out +++ b/test/langtools/tools/doclint/SummaryTest.out @@ -2,6 +2,15 @@ SummaryTest.java:14: warning: invalid use of @summary /**

        {@summary illegal} **/ ^ SummaryTest.java:17: warning: invalid use of @summary + /** text {@summary illegal} **/ + ^ +SummaryTest.java:20: warning: invalid use of @summary + /** &{@summary illegal} **/ + ^ +SummaryTest.java:23: warning: invalid use of @summary + /** @@{@summary illegal} **/ + ^ +SummaryTest.java:26: warning: invalid use of @summary /** {@summary legal} text {@summary illegal} **/ ^ -2 warnings +5 warnings diff --git a/test/langtools/tools/javac/doctree/AtEscapeTest.java b/test/langtools/tools/javac/doctree/AtEscapeTest.java new file mode 100644 index 00000000000..83e1806f391 --- /dev/null +++ b/test/langtools/tools/javac/doctree/AtEscapeTest.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2023, 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 8300914 + * @summary Allow `@` as an escape in documentation comments + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.file + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + * @build DocCommentTester + * @run main DocCommentTester AtEscapeTest.java + */ + +class AtEscapeTest { + /** + * abc + * @@tag + * def + */ + void escape_block_tag() { } +/* +DocComment[DOC_COMMENT, pos:1 + firstSentence: 3 + Text[TEXT, pos:1, abc|_] + Escape[ESCAPE, pos:6, @] + Text[TEXT, pos:8, tag|_def] + body: empty + block tags: empty +] +*/ + + /** + * abc {@@tag} def + */ + void escape_inline_tag() { } +/* +DocComment[DOC_COMMENT, pos:1 + firstSentence: 3 + Text[TEXT, pos:1, abc_{] + Escape[ESCAPE, pos:6, @] + Text[TEXT, pos:8, tag}_def] + body: empty + block tags: empty +] +*/ + + /** + * abc /* def *@/ ghi + */ + void escape_end_comment() { } +/* +DocComment[DOC_COMMENT, pos:1 + firstSentence: 3 + Text[TEXT, pos:1, abc_/*_def_*] + Escape[ESCAPE, pos:13, /] + Text[TEXT, pos:15, _ghi] + body: empty + block tags: empty +] +*/ + /** + abc + @* def + ghi + */ + void escape_asterisk() { } +/* +DocComment[DOC_COMMENT, pos:5 + firstSentence: 3 + Text[TEXT, pos:5, abc|_____] + Escape[ESCAPE, pos:14, *] + Text[TEXT, pos:16, _def|_____ghi] + body: empty + block tags: empty +] +*/ + + /** + * abc. + * not an escaped tag @@tag; + * xyz. + */ + void not_escaped_tag() { } +/* +DocComment[DOC_COMMENT, pos:1 + firstSentence: 1 + Text[TEXT, pos:1, abc.] + body: 1 + Text[TEXT, pos:7, not_an_escaped_tag_@@tag;|_xyz.] + block tags: empty +] +*/ + + /** + * abc. + * not an escaped asterisk @*; + * xyz. + */ + void not_escaped_asterisk() { } +/* +DocComment[DOC_COMMENT, pos:1 + firstSentence: 1 + Text[TEXT, pos:1, abc.] + body: 1 + Text[TEXT, pos:7, not_an_escaped_asterisk_@*;|_xyz.] + block tags: empty +] +*/ + + /** + * abc. + * not an escaped solidus @/. + * xyz. + */ + void not_escaped_solidus() { } +/* +DocComment[DOC_COMMENT, pos:1 + firstSentence: 1 + Text[TEXT, pos:1, abc.] + body: 1 + Text[TEXT, pos:7, not_an_escaped_solidus_@/.|_xyz.] + block tags: empty +] +*/ + +} diff --git a/test/langtools/tools/javac/doctree/DocCommentTester.java b/test/langtools/tools/javac/doctree/DocCommentTester.java index 023e295c78e..641e58a379d 100644 --- a/test/langtools/tools/javac/doctree/DocCommentTester.java +++ b/test/langtools/tools/javac/doctree/DocCommentTester.java @@ -462,6 +462,11 @@ public class DocCommentTester { return null; } + public Void visitEscape(EscapeTree node, Void p) { + header(node, node.getBody()); + return null; + } + public Void visitHidden(HiddenTree node, Void p) { header(node); indent(+1); @@ -933,7 +938,7 @@ public class DocCommentTester { * @return the normalized content */ String normalize(String s, boolean normalizeTags) { - String s2 = s.trim().replaceFirst("\\.\\s*\\n *@", ".\n@"); + String s2 = s.trim().replaceFirst("\\.\\s*\\n *@(?![@*])", ".\n@"); StringBuilder sb = new StringBuilder(); Pattern p = Pattern.compile("(?i)\\{@([a-z][a-z0-9.:-]*)( )?"); Matcher m = p.matcher(s2); @@ -952,7 +957,7 @@ public class DocCommentTester { } String normalizeFragment(String s) { - return s.replaceAll("\n[ \t]+@", "\n@"); + return s.replaceAll("\n[ \t]+@(?![@*])", "\n@"); } int copyLiteral(String s, int start, StringBuilder sb) {