From 1b756bfa3a1be2004af3ea12e86199ca0604c841 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Thu, 18 Aug 2022 21:57:05 +0000 Subject: [PATCH] 8236048: Cleanup use of Utils.normalizeNewlines Reviewed-by: hannesw --- .../html/AbstractExecutableMemberWriter.java | 12 ++-- .../formats/html/DocFilesHandlerImpl.java | 5 +- .../formats/html/HtmlDocletWriter.java | 11 ++- .../doclets/formats/html/HtmlLinkFactory.java | 4 +- .../doclets/formats/html/Signatures.java | 13 ++-- .../formats/html/SourceToHTMLConverter.java | 7 +- .../internal/doclets/formats/html/Table.java | 6 +- .../doclets/formats/html/TableHeader.java | 4 +- .../formats/html/TagletWriterImpl.java | 27 ++++---- .../formats/html/markup/BodyContents.java | 6 +- .../doclets/formats/html/markup/Comment.java | 15 ++-- .../formats/html/markup/ContentBuilder.java | 4 +- .../doclets/formats/html/markup/Entity.java | 15 ++-- .../doclets/formats/html/markup/Head.java | 5 +- .../formats/html/markup/HtmlDocument.java | 13 ++-- .../doclets/formats/html/markup/HtmlTree.java | 25 +++---- .../doclets/formats/html/markup/RawHtml.java | 16 ++--- .../doclets/formats/html/markup/Script.java | 4 +- .../doclets/formats/html/markup/Text.java | 69 +++++++++++++++---- .../formats/html/markup/TextBuilder.java | 12 ++-- .../internal/doclets/toolkit/BaseOptions.java | 9 ++- .../internal/doclets/toolkit/Content.java | 9 ++- .../doclets/toolkit/util/DocFile.java | 8 ++- .../doclets/toolkit/util/DocletConstants.java | 10 --- .../internal/doclets/toolkit/util/Utils.java | 26 ------- .../testHtmlDocument/TestHtmlDocument.java | 4 +- 26 files changed, 170 insertions(+), 169 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java index 19d81d4e310ee..b1018015bb4d9 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java @@ -42,8 +42,8 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; import jdk.javadoc.internal.doclets.formats.html.markup.TagName; +import jdk.javadoc.internal.doclets.formats.html.markup.Text; import jdk.javadoc.internal.doclets.toolkit.Content; -import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; import static jdk.javadoc.internal.doclets.formats.html.HtmlLinkInfo.Kind.EXECUTABLE_MEMBER_PARAM; import static jdk.javadoc.internal.doclets.formats.html.HtmlLinkInfo.Kind.MEMBER; @@ -211,7 +211,7 @@ protected Content getParameters(ExecutableElement member, boolean includeAnnotat TypeMirror rcvrType = member.getReceiverType(); if (includeAnnotations && rcvrType != null && isAnnotatedReceiver(rcvrType)) { addReceiver(member, rcvrType, result); - sep = "," + DocletConstants.NL + " "; + sep = "," + Text.NL + " "; } int paramstart; ExecutableType instMeth = utils.asInstantiatedMethodType(typeElement, member); @@ -225,7 +225,7 @@ protected Content getParameters(ExecutableElement member, boolean includeAnnotat Content annotationInfo = writer.getAnnotationInfo(param, false); if (!annotationInfo.isEmpty()) { result.add(annotationInfo) - .add(DocletConstants.NL) + .add(Text.NL) .add(" "); } } @@ -237,14 +237,14 @@ protected Content getParameters(ExecutableElement member, boolean includeAnnotat for (int i = paramstart + 1; i < parameters.size(); i++) { result.add(","); - result.add(DocletConstants.NL); + result.add(Text.NL); result.add(" "); if (includeAnnotations) { Content annotationInfo = writer.getAnnotationInfo(parameters.get(i), false); if (!annotationInfo.isEmpty()) { result.add(annotationInfo) - .add(DocletConstants.NL) + .add(Text.NL) .add(" "); } } @@ -268,7 +268,7 @@ protected Content getExceptions(ExecutableElement member) { for (TypeMirror t : exceptions) { if (!result.isEmpty()) { result.add(","); - result.add(DocletConstants.NL); + result.add(Text.NL); } Content link = writer.getLink(new HtmlLinkInfo(configuration, THROWS_TYPE, t)); result.add(link); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandlerImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandlerImpl.java index e22ec6bee4370..6567f6e13fb51 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandlerImpl.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandlerImpl.java @@ -38,7 +38,6 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; -import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; import jdk.javadoc.internal.doclets.toolkit.util.Utils; import jdk.javadoc.internal.doclint.HtmlTag; @@ -232,7 +231,7 @@ private List getLocalHeaderTags(List dtree default: if (inHead) { localTags.add(startElem); - localTags.add(docTreeFactory.newTextTree(DocletConstants.NL)); + localTags.add(docTreeFactory.newTextTree("\n")); } } break; @@ -248,7 +247,7 @@ private List getLocalHeaderTags(List dtree default: if (inHead) { localTags.add(endElem); - localTags.add(docTreeFactory.newTextTree(DocletConstants.NL)); + localTags.add(docTreeFactory.newTextTree("\n")); } } break; 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 fdd8f040766b3..9fb9dbd08cd20 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 @@ -104,7 +104,6 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocLink; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; -import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; import jdk.javadoc.internal.doclets.toolkit.util.Utils; import jdk.javadoc.internal.doclets.toolkit.util.Utils.DeclarationPreviewLanguageFeatures; import jdk.javadoc.internal.doclets.toolkit.util.Utils.ElementFlag; @@ -1169,7 +1168,7 @@ public Content commentTagsToContent(Element element, final Content result = new ContentBuilder() { @Override public ContentBuilder add(CharSequence text) { - return super.add(utils.normalizeNewlines(text)); + return super.add(Text.normalizeNewlines(text)); } }; CommentHelper ch = utils.getCommentHelper(element); @@ -1357,7 +1356,7 @@ public Boolean visitLink(LinkTree node, Content content) { @Override public Boolean visitLiteral(LiteralTree node, Content content) { String s = node.getBody().getBody(); - Content t = Text.of(utils.normalizeNewlines(s)); + Content t = Text.of(Text.normalizeNewlines(s)); content.add(node.getKind() == CODE ? HtmlTree.CODE(t) : t); return false; } @@ -1405,7 +1404,7 @@ private CharSequence textCleanup(String text, boolean isLast, boolean stripLeadi text = text.stripTrailing(); } text = utils.replaceTabs(text); - return utils.normalizeNewlines(text); + return Text.normalizeNewlines(text); } @Override @@ -1732,7 +1731,7 @@ public Void visitArray(List vals, List { content.add(a).add(" "); }); + .forEach(a -> content.add(a).add(" ")); Content link = writer.getLink(new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.RECORD_COMPONENT, e.asType())); content.add(link); @@ -544,7 +543,7 @@ private int appendTypeParameters(Content target, int lastLineSeparator) { // sum below includes length of modifiers plus type params added above if (lineLength + returnType.charCount() > RETURN_TYPE_MAX_LINE_LENGTH) { - target.add(DocletConstants.NL); + target.add(Text.NL); newLastLineSeparator = target.charCount(); } else { target.add(Entity.NO_BREAK_SPACE); @@ -574,7 +573,7 @@ private void appendParametersAndExceptions(Content target, int lastLineSeparator // Exceptions if (exceptions != null && !exceptions.isEmpty()) { CharSequence indent = " ".repeat(Math.max(0, indentSize + 1 - 7)); - target.add(DocletConstants.NL) + target.add(Text.NL) .add(indent) .add("throws ") .add(HtmlTree.SPAN(HtmlStyle.exceptions, exceptions)); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java index 1bdb285fd8cfe..5afc8f8c31fb6 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java @@ -50,7 +50,6 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; -import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; import jdk.javadoc.internal.doclets.toolkit.util.SimpleDocletException; import jdk.javadoc.internal.doclets.toolkit.util.Utils; @@ -69,7 +68,7 @@ public class SourceToHTMLConverter { /** * New line to be added to the documentation. */ - private static final String NEW_LINE = DocletConstants.NL; + private static final String NEW_LINE = Text.NL; private final HtmlConfiguration configuration; private final HtmlOptions options; @@ -289,9 +288,9 @@ private static Content getHeader() { private static void addLineNo(Content pre, int lineno) { var span = HtmlTree.SPAN(HtmlStyle.sourceLineNo); if (lineno < 10) { - span.add("00" + Integer.toString(lineno)); + span.add("00" + lineno); } else if (lineno < 100) { - span.add("0" + Integer.toString(lineno)); + span.add("0" + lineno); } else { span.add(Integer.toString(lineno)); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java index 869d9439909dd..bb8189171c743 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java @@ -30,9 +30,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.function.Predicate; @@ -354,8 +352,8 @@ public boolean isEmpty() { } @Override - public boolean write(Writer out, boolean atNewline) throws IOException { - return toContent().write(out, atNewline); + public boolean write(Writer out, String newline, boolean atNewline) throws IOException { + return toContent().write(out, newline, atNewline); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TableHeader.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TableHeader.java index ff7d18adc14ba..d80e1f26e66e6 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TableHeader.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TableHeader.java @@ -140,8 +140,8 @@ public boolean isEmpty() { } @Override - public boolean write(Writer out, boolean atNewline) throws IOException { - return toContent().write(out, atNewline); + public boolean write(Writer out, String newline, boolean atNewline) throws IOException { + return toContent().write(out, newline, atNewline); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java index 1637d8fbef445..cdcff1adaf951 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java @@ -208,7 +208,7 @@ public Content getOutputInstance() { @Override protected Content codeTagOutput(Element element, LiteralTree tag) { - return HtmlTree.CODE(Text.of(utils.normalizeNewlines(tag.getBody().getBody()))); + return HtmlTree.CODE(Text.of(Text.normalizeNewlines(tag.getBody().getBody()))); } @Override @@ -309,18 +309,17 @@ public Content linkTagOutput(Element element, LinkTree tag) { @Override protected Content literalTagOutput(Element element, LiteralTree tag) { - return Text.of(utils.normalizeNewlines(tag.getBody().getBody())); + return Text.of(Text.normalizeNewlines(tag.getBody().getBody())); } @Override public Content getParamHeader(ParamTaglet.ParamKind kind) { - Content header; - switch (kind) { - case PARAMETER: header = contents.parameters ; break; - case TYPE_PARAMETER: header = contents.typeParameters ; break; - case RECORD_COMPONENT: header = contents.recordComponents ; break; - default: throw new IllegalArgumentException(kind.toString()); - } + Content header = switch (kind) { + case PARAMETER -> contents.parameters; + case TYPE_PARAMETER -> contents.typeParameters; + case RECORD_COMPONENT -> contents.recordComponents; + default -> throw new IllegalArgumentException(kind.toString()); + }; return HtmlTree.DT(header); } @@ -384,9 +383,9 @@ public Content seeTagOutput(Element holder, List seeTags) { // Use a different style if any link label is longer than 30 chars or contains commas. boolean hasLongLabels = links.stream().anyMatch(this::isLongOrHasComma); var seeList = HtmlTree.UL(hasLongLabels ? HtmlStyle.seeListLong : HtmlStyle.seeList); - links.stream().filter(Predicate.not(Content::isEmpty)).forEach(item -> { - seeList.add(HtmlTree.LI(item)); - }); + links.stream() + .filter(Predicate.not(Content::isEmpty)) + .forEach(item -> seeList.add(HtmlTree.LI(item))); return new ContentBuilder( HtmlTree.DT(contents.seeAlso), @@ -630,7 +629,7 @@ protected Content snippetTagOutput(Element element, SnippetTree tag, StyledText } content.consumeBy((styles, sequence) -> { - CharSequence text = utils.normalizeNewlines(sequence); + CharSequence text = Text.normalizeNewlines(sequence); if (styles.isEmpty()) { code.add(text); } else { @@ -778,7 +777,7 @@ protected Content invalidTagOutput(String summary, Optional detail) { return htmlWriter.invalidTagOutput(summary, detail.isEmpty() || detail.get().isEmpty() ? Optional.empty() - : Optional.of(Text.of(utils.normalizeNewlines(detail.get())))); + : Optional.of(Text.of(Text.normalizeNewlines(detail.get())))); } @Override diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/BodyContents.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/BodyContents.java index 47ce415275c50..a6354a88aa0be 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/BodyContents.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/BodyContents.java @@ -42,7 +42,7 @@ */ public class BodyContents extends Content { - private List mainContents = new ArrayList<>(); + private final List mainContents = new ArrayList<>(); private HtmlTree header = null; private HtmlTree footer = null; @@ -74,8 +74,8 @@ public boolean isEmpty() { } @Override - public boolean write(Writer out, boolean atNewline) throws IOException { - return toContent().write(out, atNewline); + public boolean write(Writer out, String newline, boolean atNewline) throws IOException { + return toContent().write(out, newline, atNewline); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Comment.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Comment.java index a7b8b95e6626d..78adad48bd735 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Comment.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Comment.java @@ -30,14 +30,13 @@ import java.util.Objects; import jdk.javadoc.internal.doclets.toolkit.Content; -import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; /** * Class for generating a comment for HTML pages of javadoc output. */ public class Comment extends Content { - private String commentText; + private final String commentText; /** * Constructor to construct a Comment object. @@ -54,12 +53,14 @@ public boolean isEmpty() { } @Override - public boolean write(Writer out, boolean atNewline) throws IOException { - if (!atNewline) - out.write(DocletConstants.NL); + public boolean write(Writer out, String newline, boolean atNewline) throws IOException { + if (!atNewline) { + out.write(newline); + } out.write("" + DocletConstants.NL); + out.write(commentText.replace("\n", newline)); + out.write(" -->"); + out.write(newline); return true; } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ContentBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ContentBuilder.java index 44b9550007367..45888144deb03 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ContentBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ContentBuilder.java @@ -76,9 +76,9 @@ public ContentBuilder add(CharSequence text) { } @Override - public boolean write(Writer writer, boolean atNewline) throws IOException { + public boolean write(Writer writer, String newline, boolean atNewline) throws IOException { for (Content content: contents) { - atNewline = content.write(writer, atNewline); + atNewline = content.write(writer, newline, atNewline); } return atNewline; } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Entity.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Entity.java index d5aa6806cd3cb..c2d20432134a6 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Entity.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Entity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -56,7 +56,7 @@ private Entity(String text) { } @Override - public boolean write(Writer writer, boolean atNewline) throws IOException { + public boolean write(Writer writer, String newline, boolean atNewline) throws IOException { writer.write(text); return false; } @@ -86,10 +86,11 @@ static String escapeHtmlChars(CharSequence s) { char ch = str.charAt(i); switch (ch) { // only start building a new string if we need to - case '<': case '>': case '&': + case '<', '>', '&' -> { StringBuilder sb = new StringBuilder(str.substring(0, i)); escapeHtmlChars(str, i, sb); return sb.toString(); + } } } return str; @@ -110,10 +111,10 @@ private static void escapeHtmlChars(String s, int start, StringBuilder sb) { for (int i = start ; i < s.length(); i++) { char ch = s.charAt(i); switch (ch) { - case '<': sb.append(Entity.LESS_THAN.text); break; - case '>': sb.append(Entity.GREATER_THAN.text); break; - case '&': sb.append(Entity.AMPERSAND.text); break; - default: sb.append(ch); break; + case '<' -> sb.append(Entity.LESS_THAN.text); + case '>' -> sb.append(Entity.GREATER_THAN.text); + case '&' -> sb.append(Entity.AMPERSAND.text); + default -> sb.append(ch); } } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java index af4f6808cc500..d014abd7b4cad 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java @@ -31,7 +31,6 @@ import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; -import java.util.Date; import java.util.List; import java.util.Locale; @@ -254,8 +253,8 @@ public boolean isEmpty() { } @Override - public boolean write(Writer out, boolean atNewline) throws IOException { - return toContent().write(out, atNewline); + public boolean write(Writer out, String newline, boolean atNewline) throws IOException { + return toContent().write(out, newline, atNewline); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocument.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocument.java index 748c0487e98d5..99e2ec1b64210 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocument.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocument.java @@ -28,12 +28,10 @@ import java.io.IOException; import java.io.StringWriter; import java.io.Writer; -import java.util.*; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.util.DocFile; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; -import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; /** * Class for generating an HTML document for javadoc output. @@ -53,13 +51,14 @@ public HtmlDocument(Content html) { /** * Writes the content of this document to the specified file. + * Newlines are written using the platform line separator. * * @param docFile the file * @throws DocFileIOException if an {@code IOException} occurs while writing the file */ public void write(DocFile docFile) throws DocFileIOException { try (Writer writer = docFile.openWriter()) { - write(writer); + write(writer, DocFile.PLATFORM_LINE_SEPARATOR); } catch (IOException e) { throw new DocFileIOException(docFile, DocFileIOException.Mode.WRITE, e); } @@ -68,16 +67,16 @@ public void write(DocFile docFile) throws DocFileIOException { @Override public String toString() { try (Writer writer = new StringWriter()) { - write(writer); + write(writer, "\n"); return writer.toString(); } catch (IOException e) { throw new Error(e); } } - private void write(Writer writer) throws IOException { + private void write(Writer writer, String newline) throws IOException { writer.write(docType.text); - writer.write(DocletConstants.NL); - docContent.write(writer, true); + writer.write(newline); + docContent.write(writer, newline, true); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java index f8d2419e353b1..7f2a5f8b04878 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java @@ -32,7 +32,6 @@ import java.util.ArrayList; import java.util.BitSet; import java.util.Collection; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -41,7 +40,6 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr.Role; import jdk.javadoc.internal.doclets.toolkit.Content; -import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; /** * A tree node representing an HTML element, containing the name of the element, @@ -1051,19 +1049,17 @@ public boolean isVoid() { } @Override - public boolean write(Writer out, boolean atNewline) throws IOException { + public boolean write(Writer out, String newline, boolean atNewline) throws IOException { boolean isInline = isInline(); - if (!isInline && !atNewline) - out.write(DocletConstants.NL); + if (!isInline && !atNewline) { + out.write(newline); + } String tagString = tagName.toString(); out.write("<"); out.write(tagString); - Iterator iterator = attrs.keySet().iterator(); - HtmlAttr key; - String value; - while (iterator.hasNext()) { - key = iterator.next(); - value = attrs.get(key); + for (var attr : attrs.entrySet()) { + var key = attr.getKey(); + var value = attr.getValue(); out.write(" "); out.write(key.toString()); if (!value.isEmpty()) { @@ -1074,15 +1070,16 @@ public boolean write(Writer out, boolean atNewline) throws IOException { } out.write(">"); boolean nl = false; - for (Content c : content) - nl = c.write(out, nl); + for (Content c : content) { + nl = c.write(out, newline, nl); + } if (!isVoid()) { out.write(""); } if (!isInline) { - out.write(DocletConstants.NL); + out.write(newline); return true; } else { return false; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/RawHtml.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/RawHtml.java index 26aea9e58b239..02e8aff13baad 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/RawHtml.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/RawHtml.java @@ -29,7 +29,6 @@ import java.io.Writer; import jdk.javadoc.internal.doclets.toolkit.Content; -import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; /** * Class for generating raw HTML content to be added to HTML pages of javadoc output. @@ -121,6 +120,7 @@ private static RawHtml section(String prefix, String body, String suffix) { * @param rawHtml raw HTML text to be added */ private RawHtml(CharSequence rawHtml) { + assert Text.checkNewlines(rawHtml); rawHtmlContent = rawHtml.toString(); } @@ -151,14 +151,6 @@ protected static int charCount(CharSequence htmlText) { state = State.ENTITY; count++; break; - case '\r': - // Windows uses "\r\n" as line separator while UNIX uses "\n". - // Skip the "\r" to get consistent results across platforms. - if (i + 1 < htmlText.length() && htmlText.charAt(i + 1) == '\n') { - i++; - } - count++; - break; default: count++; } @@ -192,8 +184,8 @@ protected static int charCount(CharSequence htmlText) { } @Override - public boolean write(Writer out, boolean atNewline) throws IOException { - out.write(rawHtmlContent); - return rawHtmlContent.endsWith(DocletConstants.NL); + public boolean write(Writer out, String newline, boolean atNewline) throws IOException { + out.write(rawHtmlContent.replace("\n", newline)); + return rawHtmlContent.endsWith("\n"); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Script.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Script.java index e67e85654cf76..e76372897b33b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Script.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Script.java @@ -197,9 +197,9 @@ public ScriptContent add(CharSequence code) { } @Override - public boolean write(Writer writer, boolean atNewline) throws IOException { + public boolean write(Writer writer, String newline, boolean atNewline) throws IOException { String s = sb.toString(); - writer.write(s.replace("\n", DocletConstants.NL)); + writer.write(s.replace("\n", newline)); return s.endsWith("\n"); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Text.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Text.java index 8a264e446ef28..389617a1d8129 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Text.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Text.java @@ -29,13 +29,14 @@ import java.io.Writer; import jdk.javadoc.internal.doclets.toolkit.Content; -import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; /** * Class for containing immutable string content for HTML tags of javadoc output. + * Newlines are always represented by {@code \n}. * Any special HTML characters will be escaped if and when the content is written out. */ public class Text extends Content { + private final String string; public static final Text EMPTY = Text.of(""); @@ -56,6 +57,7 @@ public static Text of(CharSequence content) { * @param content content for the object */ private Text(CharSequence content) { + assert checkNewlines(content); string = content.toString(); } @@ -70,16 +72,7 @@ public int charCount() { } static int charCount(CharSequence cs) { - int count = 0; - for (int i = 0; i < cs.length(); i++) { - // Windows uses "\r\n" as line separator while UNIX uses "\n". - // Skip the "\r" to get consistent results across platforms. - if (cs.charAt(i) == '\r' && (i + 1 < cs.length()) && cs.charAt(i + 1) == '\n') { - i++; - } - count++; - } - return count; + return cs.length(); } @Override @@ -88,9 +81,57 @@ public String toString() { } @Override - public boolean write(Writer out, boolean atNewline) throws IOException { - out.write(Entity.escapeHtmlChars(string)); - return string.endsWith(DocletConstants.NL); + public boolean write(Writer out, String newline, boolean atNewline) throws IOException { + out.write(Entity.escapeHtmlChars(string).replace("\n", newline)); + return string.endsWith("\n"); + } + + /** + * The newline character, to be used when creating {@code Content} nodes. + */ + public static final String NL = "\n"; + + /** + * Returns a given string with all newlines in the form {@code \n}. + * + * The sequences of interest are {@code \n}, {@code \r\n}, and {@code \r}. + * {@code \n} is already in the right form, so can be ignored, + * leaving code to handle {@code \r\n}, and {@code \r}. + * + * @param text the string + * @return the string with newlines in the form {@code \n} + */ + public static CharSequence normalizeNewlines(CharSequence text) { + // fast-track when the input is a string with no \r characters + if (text instanceof String s && s.indexOf('\r') != -1) { + return text; + } else { + var sb = new StringBuilder(); + var s = text.toString(); + int sLen = s.length(); + int start = 0; + int pos; + while ((pos = s.indexOf('\r', start)) != -1) { + sb.append(s, start, pos); + sb.append('\n'); + pos++; + if (pos < sLen && s.charAt(pos) == '\n') { + pos++; + } + start = pos; + } + sb.append(s.substring(start)); + return sb; + } + } + + /** + * Check for the absence of {@code \r} characters. + * @param cs the characters to be checked + * @return {@code true} if there are no {@code \r} characters, and {@code false} otherwise + */ + static boolean checkNewlines(CharSequence cs) { + return !cs.toString().contains("\r"); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/TextBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/TextBuilder.java index af4eb091c77e7..0bdd81c73ed52 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/TextBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/TextBuilder.java @@ -29,11 +29,11 @@ import java.io.Writer; import jdk.javadoc.internal.doclets.toolkit.Content; -import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; /** * Class for generating string content for HTML tags of javadoc output. * The content is mutable to the extent that additional content may be added. + * Newlines are always represented by {@code \n}. * Any special HTML characters will be escaped if and when the content is written out. */ public class TextBuilder extends Content { @@ -53,6 +53,7 @@ public TextBuilder() { * @param initialContent initial content for the object */ public TextBuilder(CharSequence initialContent) { + assert Text.checkNewlines(initialContent); stringBuilder = new StringBuilder(initialContent); } @@ -63,6 +64,7 @@ public TextBuilder(CharSequence initialContent) { */ @Override public TextBuilder add(CharSequence strContent) { + assert Text.checkNewlines(strContent); stringBuilder.append(strContent); return this; } @@ -74,7 +76,7 @@ public boolean isEmpty() { @Override public int charCount() { - return Text.charCount(stringBuilder); + return stringBuilder.length(); } @Override @@ -83,9 +85,9 @@ public String toString() { } @Override - public boolean write(Writer out, boolean atNewline) throws IOException { + public boolean write(Writer out, String newline, boolean atNewline) throws IOException { String s = Entity.escapeHtmlChars(stringBuilder); - out.write(s); - return s.endsWith(DocletConstants.NL); + out.write(s.replace("\n", newline)); + return s.endsWith("\n"); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseOptions.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseOptions.java index 45fbfa8d0b858..339a17f5b4010 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseOptions.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseOptions.java @@ -320,12 +320,17 @@ public enum ModularityMismatchPolicy { private final BaseConfiguration config; + /** + * The default amount of space between tab stops. + */ + public static final int DEFAULT_TAB_STOP_LENGTH = 8; + protected BaseOptions(BaseConfiguration config) { this.config = config; excludedDocFileDirs = new HashSet<>(); excludedQualifiers = new HashSet<>(); - sourceTabSize = DocletConstants.DEFAULT_TAB_STOP_LENGTH; + sourceTabSize = DEFAULT_TAB_STOP_LENGTH; groupPairs = new ArrayList<>(0); } @@ -597,7 +602,7 @@ public boolean process(String opt, List args) { } if (sourceTabSize <= 0) { messages.warning("doclet.sourcetab_warning"); - sourceTabSize = DocletConstants.DEFAULT_TAB_STOP_LENGTH; + sourceTabSize = DEFAULT_TAB_STOP_LENGTH; } return true; } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Content.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Content.java index d2ff98b331c56..9ad23e6cfa2cd 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Content.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Content.java @@ -38,6 +38,7 @@ public abstract class Content { /** * Returns a string representation of the content. + * Newlines are represented by {@code \n}. * * @return string representation of the content */ @@ -45,7 +46,7 @@ public abstract class Content { public String toString() { StringWriter out = new StringWriter(); try { - write(out, true); + write(out, "\n", true); } catch (IOException e) { // cannot happen from StringWriter throw new AssertionError(e); @@ -106,14 +107,16 @@ public Content addAll(Collection items, Function mapper) { } /** - * Writes content to a writer. + * Writes content to a writer, using a given newline sequence, which should be + * either {@code \n} or the platform line separator. * * @param writer the writer + * @param newline the newline sequence to use * @param atNewline whether the writer has just written a newline * @return whether the writer has just written a newline * @throws IOException if an error occurs while writing the output */ - public abstract boolean write(Writer writer, boolean atNewline) throws IOException; + public abstract boolean write(Writer writer, String newline, boolean atNewline) throws IOException; /** * Returns true if the content is empty. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocFile.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocFile.java index fa1245597e930..017a7e7892c24 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocFile.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocFile.java @@ -51,6 +51,12 @@ */ public abstract class DocFile { + /** + * The line separator for the current platform. + * Use this when writing to external files. + */ + public static final String PLATFORM_LINE_SEPARATOR = System.getProperty("line.separator"); + /** Create a DocFile for a directory. */ public static DocFile createFileForDirectory(BaseConfiguration configuration, String file) { return DocFileFactory.getFactory(configuration).createFileForDirectory(file); @@ -214,7 +220,7 @@ private void copyResource(DocPath resource, boolean replaceNewLine, Resources re String line; while ((line = readResourceLine(resource, reader)) != null) { write(this, writer, resources == null ? line : localize(line, resources)); - write(this, writer, DocletConstants.NL); + write(this, writer, PLATFORM_LINE_SEPARATOR); } } catch (IOException e) { throw new DocFileIOException(this, DocFileIOException.Mode.WRITE, e); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocletConstants.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocletConstants.java index 9782e5bf568c4..15e47b963bafd 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocletConstants.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocletConstants.java @@ -31,16 +31,6 @@ */ public class DocletConstants { - /** - * The default amount of space between tab stops. - */ - public static final int DEFAULT_TAB_STOP_LENGTH = 8; - - /** - * The line separator for the current operating system. - */ - public static final String NL = System.getProperty("line.separator"); - /** * The default module or a package name. */ diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java index 85e3e45ebf72a..664121f5f6e3b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java @@ -1235,32 +1235,6 @@ public String replaceTabs(String text) { return result.toString(); } - public CharSequence normalizeNewlines(CharSequence text) { - StringBuilder sb = new StringBuilder(); - final int textLength = text.length(); - final String NL = DocletConstants.NL; - int pos = 0; - for (int i = 0; i < textLength; i++) { - char ch = text.charAt(i); - switch (ch) { - case '\n' -> { - sb.append(text, pos, i); - sb.append(NL); - pos = i + 1; - } - case '\r' -> { - sb.append(text, pos, i); - sb.append(NL); - if (i + 1 < textLength && text.charAt(i + 1) == '\n') - i++; - pos = i + 1; - } - } - } - sb.append(text, pos, textLength); - return sb; - } - /** * Returns a locale independent lower cased String. That is, it * always uses US locale, this is a clone of the one in StringUtils. diff --git a/test/langtools/jdk/javadoc/doclet/testHtmlDocument/TestHtmlDocument.java b/test/langtools/jdk/javadoc/doclet/testHtmlDocument/TestHtmlDocument.java index 7ff8de5267b99..8d04bb6153491 100644 --- a/test/langtools/jdk/javadoc/doclet/testHtmlDocument/TestHtmlDocument.java +++ b/test/langtools/jdk/javadoc/doclet/testHtmlDocument/TestHtmlDocument.java @@ -36,8 +36,6 @@ import jdk.javadoc.internal.doclets.formats.html.markup.*; -import static jdk.javadoc.internal.doclets.toolkit.util.DocletConstants.NL; - /** * The class reads each file, complete with newlines, into a string to easily * compare the existing markup with the generated markup. @@ -56,7 +54,7 @@ public static void main(String... args) throws Exception { public void test() { checking("markup"); // Check whether the generated markup is same as the existing markup. - String expected = readFile(testSrc, "testMarkup.html").replace("\n", NL); + String expected = readFile(testSrc, "testMarkup.html"); String actual = generateHtmlTree(); if (actual.equals(expected)) { passed("");