8288699: cleanup HTML tree in HtmlDocletWriter.commentTagsToContent

Reviewed-by: hannesw
This commit is contained in:
Jonathan Gibbons 2022-07-08 19:33:03 +00:00
parent 6aaf141f61
commit 54b4576f78
18 changed files with 348 additions and 173 deletions

View File

@ -877,6 +877,32 @@ public class DocCommentParser {
}
nextChar();
}
} else {
String CDATA = "[CDATA["; // full prefix is <![CDATA[
for (int i = 0; i < CDATA.length(); i++) {
if (ch == CDATA.charAt(i)) {
nextChar();
} else {
return erroneous("dc.invalid.html", p);
}
}
// suffix is ]]>
while (bp < buflen) {
if (ch == ']') {
int n = 0;
while (bp < buflen && ch == ']') {
n++;
nextChar();
}
if (n >= 2 && ch == '>') {
nextChar();
return m.at(p).newTextTree(newString(p, bp));
}
} else {
nextChar();
}
}
return erroneous("dc.invalid.html", p);
}
}

View File

@ -3339,6 +3339,9 @@ compiler.err.dc.bad.inline.tag=\
compiler.err.dc.identifier.expected=\
identifier expected
compiler.err.dc.invalid.html=\
invalid HTML
compiler.err.dc.malformed.html=\
malformed HTML

View File

@ -125,7 +125,7 @@ public abstract class AbstractOverviewIndexWriter extends HtmlDocletWriter {
protected void addConfigurationTitle(Content target) {
String doctitle = configuration.getOptions().docTitle();
if (!doctitle.isEmpty()) {
var title = new RawHtml(doctitle);
var title = RawHtml.of(doctitle);
var heading = HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING,
HtmlStyle.title, title);
var div = HtmlTree.DIV(HtmlStyle.header, heading);

View File

@ -500,7 +500,7 @@ public class HtmlDocletWriter {
*/
protected HtmlTree getHeader(Navigation.PageMode pageMode, Element element) {
return HtmlTree.HEADER()
.add(new RawHtml(replaceDocRootDir(options.top())))
.add(RawHtml.of(replaceDocRootDir(options.top())))
.add(getNavBar(pageMode, element).getContent());
}
@ -515,7 +515,7 @@ public class HtmlDocletWriter {
*/
protected Navigation getNavBar(Navigation.PageMode pageMode, Element element) {
return new Navigation(element, configuration, pageMode, path)
.setUserHeader(new RawHtml(replaceDocRootDir(options.header())));
.setUserHeader(RawHtml.of(replaceDocRootDir(options.header())));
}
/**
@ -532,7 +532,7 @@ public class HtmlDocletWriter {
.add(new HtmlTree(TagName.HR))
.add(HtmlTree.P(HtmlStyle.legalCopy,
HtmlTree.SMALL(
new RawHtml(replaceDocRootDir(bottom)))));
RawHtml.of(replaceDocRootDir(bottom)))));
}
/**
@ -1004,7 +1004,7 @@ public class HtmlDocletWriter {
}
case START_ELEMENT -> {
// @see <a href="...">...</a>
return new RawHtml(replaceDocRootDir(removeTrailingSlash(seeText)));
return RawHtml.of(replaceDocRootDir(removeTrailingSlash(seeText)));
}
case REFERENCE -> {
// @see reference label...
@ -1484,7 +1484,6 @@ public class HtmlDocletWriter {
}
};
CommentHelper ch = utils.getCommentHelper(element);
// Array of all possible inline tags for this javadoc run
configuration.tagletManager.checkTags(element, trees, true);
commentRemoved = false;
@ -1511,103 +1510,108 @@ public class HtmlDocletWriter {
}
}
boolean allDone = new SimpleDocTreeVisitor<Boolean, Content>() {
var docTreeVisitor = new SimpleDocTreeVisitor<Boolean, Content>() {
private boolean inAnAtag() {
if (utils.isStartElement(tag)) {
StartElementTree st = (StartElementTree)tag;
Name name = st.getName();
if (name != null) {
HtmlTag htag = HtmlTag.get(name);
return htag != null && htag.equals(HtmlTag.A);
}
}
return false;
return (tag instanceof StartElementTree st) && equalsIgnoreCase(st.getName(), "a");
}
private boolean equalsIgnoreCase(Name name, String s) {
return name != null && name.toString().equalsIgnoreCase(s);
}
@Override
public Boolean visitAttribute(AttributeTree node, Content c) {
StringBuilder sb = new StringBuilder(SPACER).append(node.getName().toString());
public Boolean visitAttribute(AttributeTree node, Content content) {
if (!content.isEmpty()) {
content.add(" ");
}
content.add(node.getName());
if (node.getValueKind() == ValueKind.EMPTY) {
result.add(sb);
return false;
}
sb.append("=");
content.add("=");
String quote = switch (node.getValueKind()) {
case DOUBLE -> "\"";
case SINGLE -> "'";
default -> "";
};
sb.append(quote);
result.add(sb);
Content docRootContent = new ContentBuilder();
content.add(quote);
boolean isHRef = inAnAtag() && node.getName().toString().equalsIgnoreCase("href");
/* In the following code for an attribute value:
* 1. {@docRoot} followed by text beginning "/.." is replaced by the value
* of the docrootParent option, followed by the remainder of the text
* 2. in the value of an "href" attribute in a <a> tag, an initial text
* value will have a relative link redirected.
* Note that, realistically, it only makes sense to ever use {@docRoot}
* at the beginning of a URL in an attribute value, but this is not
* required or enforced.
*/
boolean isHRef = inAnAtag() && equalsIgnoreCase(node.getName(), "href");
boolean first = true;
DocRootTree pendingDocRoot = null;
for (DocTree dt : node.getValue()) {
if (utils.isText(dt) && isHRef) {
String text = ((TextTree) dt).getBody();
if (text.startsWith("/..") && !options.docrootParent().isEmpty()) {
result.add(options.docrootParent());
docRootContent = new ContentBuilder();
result.add(textCleanup(text.substring(3), isLastNode));
} else {
if (!docRootContent.isEmpty()) {
docRootContent = copyDocRootContent(docRootContent);
} else {
text = redirectRelativeLinks(element, (TextTree) dt);
if (pendingDocRoot != null) {
if (dt instanceof TextTree tt) {
String text = tt.getBody();
if (text.startsWith("/..") && !options.docrootParent().isEmpty()) {
content.add(options.docrootParent());
content.add(textCleanup(text.substring(3), isLastNode));
pendingDocRoot = null;
continue;
}
result.add(textCleanup(text, isLastNode));
}
} else {
docRootContent = copyDocRootContent(docRootContent);
dt.accept(this, docRootContent);
pendingDocRoot.accept(this, content);
pendingDocRoot = null;
}
if (dt instanceof TextTree tt) {
String text = tt.getBody();
if (first && isHRef) {
text = redirectRelativeLinks(element, tt);
}
content.add(textCleanup(text, isLastNode));
} else if (dt instanceof DocRootTree drt) {
// defer until we see what, if anything, follows this node
pendingDocRoot = drt;
} else {
dt.accept(this, content);
}
first = false;
}
copyDocRootContent(docRootContent);
result.add(quote);
return false;
}
@Override
public Boolean visitComment(CommentTree node, Content c) {
result.add(new RawHtml(node.getBody()));
return false;
}
private Content copyDocRootContent(Content content) {
if (!content.isEmpty()) {
result.add(content);
return new ContentBuilder();
if (pendingDocRoot != null) {
pendingDocRoot.accept(this, content);
}
return content;
}
@Override
public Boolean visitDocRoot(DocRootTree node, Content c) {
Content docRootContent = getInlineTagOutput(element, node, context);
if (c != null) {
c.add(docRootContent);
} else {
result.add(docRootContent);
}
content.add(quote);
return false;
}
@Override
public Boolean visitEndElement(EndElementTree node, Content c) {
RawHtml rawHtml = new RawHtml("</" + node.getName() + ">");
result.add(rawHtml);
public Boolean visitComment(CommentTree node, Content content) {
content.add(RawHtml.comment(node.getBody()));
return false;
}
@Override
public Boolean visitEntity(EntityTree node, Content c) {
result.add(new RawHtml(node.toString()));
public Boolean visitDocRoot(DocRootTree node, Content content) {
content.add(getInlineTagOutput(element, node, context));
return false;
}
@Override
public Boolean visitErroneous(ErroneousTree node, Content c) {
public Boolean visitEndElement(EndElementTree node, Content content) {
content.add(RawHtml.endElement(node.getName()));
return false;
}
@Override
public Boolean visitEntity(EntityTree node, Content content) {
content.add(Entity.of(node.getName()));
return false;
}
@Override
public Boolean visitErroneous(ErroneousTree node, Content content) {
DocTreePath dtp = ch.getDocTreePath(node);
if (dtp != null) {
String body = node.getBody();
@ -1617,11 +1621,11 @@ public class HtmlDocletWriter {
if (!configuration.isDocLintSyntaxGroupEnabled()) {
messages.warning(dtp, "doclet.tag.invalid_input", body);
}
result.add(invalidTagOutput(resources.getText("doclet.tag.invalid_input", body),
content.add(invalidTagOutput(resources.getText("doclet.tag.invalid_input", body),
Optional.empty()));
} else {
messages.warning(dtp, "doclet.tag.invalid_usage", body);
result.add(invalidTagOutput(resources.getText("doclet.tag.invalid", tagName),
content.add(invalidTagOutput(resources.getText("doclet.tag.invalid", tagName),
Optional.of(Text.of(body))));
}
}
@ -1629,24 +1633,24 @@ public class HtmlDocletWriter {
}
@Override
public Boolean visitInheritDoc(InheritDocTree node, Content c) {
public Boolean visitInheritDoc(InheritDocTree node, Content content) {
Content output = getInlineTagOutput(element, node, context);
result.add(output);
content.add(output);
// if we obtained the first sentence successfully, nothing more to do
return (context.isFirstSentence && !output.isEmpty());
}
@Override
public Boolean visitIndex(IndexTree node, Content p) {
public Boolean visitIndex(IndexTree node, Content content) {
Content output = getInlineTagOutput(element, node, context);
if (output != null) {
result.add(output);
content.add(output);
}
return false;
}
@Override
public Boolean visitLink(LinkTree node, Content c) {
public Boolean visitLink(LinkTree node, Content content) {
var inTags = context.inTags;
if (inTags.contains(LINK) || inTags.contains(LINK_PLAIN) || inTags.contains(SEE)) {
DocTreePath dtp = ch.getDocTreePath(node);
@ -1657,55 +1661,50 @@ public class HtmlDocletWriter {
if (label.isEmpty()) {
label = Text.of(node.getReference().getSignature());
}
result.add(label);
content.add(label);
} else {
Content content = seeTagToContent(element, node, context.within(node));
result.add(content);
Content c = seeTagToContent(element, node, context.within(node));
content.add(c);
}
return false;
}
@Override
public Boolean visitLiteral(LiteralTree node, Content c) {
public Boolean visitLiteral(LiteralTree node, Content content) {
String s = node.getBody().getBody();
Content content = Text.of(utils.normalizeNewlines(s));
if (node.getKind() == CODE)
content = HtmlTree.CODE(content);
result.add(content);
Content t = Text.of(utils.normalizeNewlines(s));
content.add(node.getKind() == CODE ? HtmlTree.CODE(t) : t);
return false;
}
@Override
public Boolean visitSee(SeeTree node, Content c) {
result.add(seeTagToContent(element, node, context));
public Boolean visitSee(SeeTree node, Content content) {
content.add(seeTagToContent(element, node, context));
return false;
}
@Override
public Boolean visitStartElement(StartElementTree node, Content c) {
String text = "<" + node.getName();
RawHtml rawHtml = new RawHtml(utils.normalizeNewlines(text));
result.add(rawHtml);
public Boolean visitStartElement(StartElementTree node, Content content) {
Content attrs = new ContentBuilder();
for (DocTree dt : node.getAttributes()) {
dt.accept(this, null);
dt.accept(this, attrs);
}
result.add(new RawHtml(node.isSelfClosing() ? "/>" : ">"));
content.add(RawHtml.startElement(node.getName(), attrs, node.isSelfClosing()));
return false;
}
@Override
public Boolean visitSummary(SummaryTree node, Content c) {
public Boolean visitSummary(SummaryTree node, Content content) {
Content output = getInlineTagOutput(element, node, context);
result.add(output);
content.add(output);
return false;
}
@Override
public Boolean visitSystemProperty(SystemPropertyTree node, Content p) {
public Boolean visitSystemProperty(SystemPropertyTree node, Content content) {
Content output = getInlineTagOutput(element, node, context);
if (output != null) {
result.add(output);
content.add(output);
}
return false;
}
@ -1728,23 +1727,28 @@ public class HtmlDocletWriter {
}
@Override
public Boolean visitText(TextTree node, Content c) {
public Boolean visitText(TextTree node, Content content) {
String text = node.getBody();
result.add(new RawHtml(textCleanup(text, isLastNode, commentRemoved)));
result.add(text.startsWith("<![CDATA[")
? RawHtml.cdata(text)
: Text.of(textCleanup(text, isLastNode, commentRemoved)));
return false;
}
@Override
protected Boolean defaultAction(DocTree node, Content c) {
protected Boolean defaultAction(DocTree node, Content content) {
Content output = getInlineTagOutput(element, node, context);
if (output != null) {
result.add(output);
content.add(output);
}
return false;
}
}.visit(tag, null);
};
boolean allDone = docTreeVisitor.visit(tag, result);
commentRemoved = false;
if (allDone)
break;
}
@ -1897,15 +1901,6 @@ public class HtmlDocletWriter {
return text;
}
/**
* According to
* <cite>The Java Language Specification</cite>,
* all the outer classes and static nested classes are core classes.
*/
public boolean isCoreClass(TypeElement typeElement) {
return utils.getEnclosingTypeElement(typeElement) == null || utils.isStatic(typeElement);
}
/**
* {@return the annotation types info for the given element}
*
@ -2166,6 +2161,7 @@ public class HtmlDocletWriter {
}
}.visit(t);
}
@Override
public Content visitAnnotation(AnnotationMirror a, Void p) {
List<Content> list = getAnnotations(List.of(a), false);
@ -2175,10 +2171,12 @@ public class HtmlDocletWriter {
}
return buf;
}
@Override
public Content visitEnumConstant(VariableElement c, Void p) {
return getDocLink(HtmlLinkInfo.Kind.ANNOTATION, c, c.getSimpleName());
}
@Override
public Content visitArray(List<? extends AnnotationValue> vals, Void p) {
ContentBuilder buf = new ContentBuilder();
@ -2190,6 +2188,7 @@ public class HtmlDocletWriter {
}
return buf;
}
@Override
protected Content defaultAction(Object o, Void p) {
return Text.of(annotationValue.toString());
@ -2274,10 +2273,6 @@ public class HtmlDocletWriter {
return HtmlStyle.valueOf(page);
}
Script getMainBodyScript() {
return mainBodyScript;
}
/**
* Returns the path of module/package specific stylesheets for the element.
* @param element module/Package element

View File

@ -134,7 +134,7 @@ public class HtmlSerialFieldWriter extends FieldWriterImpl
CommentHelper ch = utils.getCommentHelper(field);
List<? extends DocTree> description = ch.getDescription(serialFieldTag);
if (!description.isEmpty()) {
Content serialFieldContent = new RawHtml(ch.getText(description));
Content serialFieldContent = RawHtml.of(ch.getText(description)); // should interpret tags
var div = HtmlTree.DIV(HtmlStyle.block, serialFieldContent);
content.add(div);
}

View File

@ -530,7 +530,7 @@ public class Signatures {
*/
private int appendTypeParameters(Content target, int lastLineSeparator) {
// Apply different wrapping strategies for type parameters
// depending of combined length of type parameters and return type.
// depending on the combined length of type parameters and return type.
int typeParamLength = typeParameters.charCount();
if (typeParamLength >= TYPE_PARAMS_MAX_INLINE_LENGTH) {

View File

@ -52,6 +52,7 @@ import com.sun.source.doctree.ReturnTree;
import com.sun.source.doctree.SeeTree;
import com.sun.source.doctree.SnippetTree;
import com.sun.source.doctree.SystemPropertyTree;
import com.sun.source.doctree.TextTree;
import com.sun.source.doctree.ThrowsTree;
import com.sun.source.util.DocTreePath;
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
@ -307,7 +308,7 @@ public class TagletWriterImpl extends TagletWriter {
public Content returnTagOutput(Element element, ReturnTree returnTag, boolean inline) {
CommentHelper ch = utils.getCommentHelper(element);
List<? extends DocTree> desc = ch.getDescription(returnTag);
Content content = htmlWriter.commentTagsToContent(element, desc , context.within(returnTag));
Content content = htmlWriter.commentTagsToContent(element, desc, context.within(returnTag));
return inline
? new ContentBuilder(contents.getContent("doclet.Returns_0", content))
: new ContentBuilder(HtmlTree.DT(contents.returns), HtmlTree.DD(content));
@ -371,7 +372,7 @@ public class TagletWriterImpl extends TagletWriter {
many = true;
}
return new ContentBuilder(
HtmlTree.DT(new RawHtml(header)),
HtmlTree.DT(RawHtml.of(header)),
HtmlTree.DD(body));
}
@ -504,9 +505,9 @@ public class TagletWriterImpl extends TagletWriter {
excName = htmlWriter.getLink(new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.MEMBER,
substituteType));
} else if (exception == null) {
excName = new RawHtml(throwsTag.getExceptionName().toString());
excName = RawHtml.of(throwsTag.getExceptionName().toString());
} else if (exception.asType() == null) {
excName = new RawHtml(utils.getFullyQualifiedName(exception));
excName = Text.of(utils.getFullyQualifiedName(exception));
} else {
HtmlLinkInfo link = new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.MEMBER,
exception.asType());

View File

@ -41,6 +41,16 @@ public class Entity extends Content {
public final String text;
/**
* Creates an entity with a given name or numeric value.
*
* @param name the name, or numeric value
* @return the entity
*/
public static Entity of(CharSequence name) {
return new Entity("&" + name + ";");
}
private Entity(String text) {
this.text = text;
}

View File

@ -36,14 +36,91 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants;
*/
public class RawHtml extends Content {
private final String rawHtmlContent;
protected final String rawHtmlContent;
/**
* Creates HTML for an arbitrary string of HTML.
* The string is accepted as-is and is not validated in any way.
* It should be syntactically well-formed and contain matching {@code <} and {@code >},
* and matching quotes for attributes.
*
* @param rawHtml the string
* @return the HTML
*/
public static RawHtml of(CharSequence rawHtml) {
return new RawHtml(rawHtml) {
@Override
public int charCount() {
return charCount(rawHtmlContent);
}
};
}
/**
* Creates HTML for the start of an element.
*
* @param name the name of the element
* @param attrs content containing any attributes
* @param selfClosing whether this is a self-closing element.
* @return the HTML
*/
public static RawHtml startElement(CharSequence name, Content attrs, boolean selfClosing) {
StringBuilder sb = new StringBuilder("<" + name);
if (!attrs.isEmpty()) {
sb.append(" ");
sb.append(attrs);
}
sb.append(selfClosing ? "/>" : ">");
return new RawHtml(sb);
}
/**
* Creates HTML for the end of an element.
*
* @param name the name of the element
* @return the HTML
*/
public static RawHtml endElement(CharSequence name) {
return new RawHtml("</" + name + ">");
}
/**
* Creates HTML for an HTML comment.
*
* The body will be enclosed in {@code <!--} and {@code -->} if it does not
* already begin and end with those sequences.
*
* @param body the body of the comment
*
* @return the HTML
*/
public static RawHtml comment(String body) {
return section("<!--", body, "-->");
}
/**
* Creates HTML for an HTML CDATA section.
*
* The body will be enclosed in {@code <![CDATA]} and {@code ]]>} if it does not
* already begin and end with those sequences.
*
* @param body the body of the CDATA section
*
* @return the HTML
*/
public static RawHtml cdata(String body) {
return section("<![CDATA[", body, "]]>");
}
private static RawHtml section(String prefix, String body, String suffix) {
return new RawHtml(body.startsWith(prefix) && body.endsWith(suffix) ? body : prefix + body + suffix);
}
/**
* Constructor to construct a RawHtml object.
*
* @param rawHtml raw HTML text to be added
*/
public RawHtml(CharSequence rawHtml) {
private RawHtml(CharSequence rawHtml) {
rawHtmlContent = rawHtml.toString();
}
@ -59,12 +136,7 @@ public class RawHtml extends Content {
private enum State { TEXT, ENTITY, TAG, STRING }
@Override
public int charCount() {
return charCount(rawHtmlContent);
}
static int charCount(CharSequence htmlText) {
protected static int charCount(CharSequence htmlText) {
State state = State.TEXT;
int count = 0;
for (int i = 0; i < htmlText.length(); i++) {
@ -80,9 +152,12 @@ public class RawHtml extends Content {
count++;
break;
case '\r':
case '\n':
// Windows uses "\r\n" as line separator while UNIX uses "\n".
// Ignore line separators to get consistent results across platforms.
// Skip the "\r" to get consistent results across platforms.
if (i + 1 < htmlText.length() && htmlText.charAt(i + 1) == '\n') {
i++;
}
count++;
break;
default:
count++;

View File

@ -33,6 +33,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants;
/**
* Class for containing immutable string content for HTML tags of javadoc output.
* Any special HTML characters will be escaped if and when the content is written out.
*/
public class Text extends Content {
private final String string;
@ -55,7 +56,7 @@ public class Text extends Content {
* @param content content for the object
*/
private Text(CharSequence content) {
string = Entity.escapeHtmlChars(content);
string = content.toString();
}
@Override
@ -65,7 +66,20 @@ public class Text extends Content {
@Override
public int charCount() {
return RawHtml.charCount(string);
return charCount(string);
}
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;
}
@Override
@ -75,7 +89,7 @@ public class Text extends Content {
@Override
public boolean write(Writer out, boolean atNewline) throws IOException {
out.write(string);
out.write(Entity.escapeHtmlChars(string));
return string.endsWith(DocletConstants.NL);
}

View File

@ -34,6 +34,7 @@ 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.
* Any special HTML characters will be escaped if and when the content is written out.
*/
public class TextBuilder extends Content {
@ -52,19 +53,17 @@ public class TextBuilder extends Content {
* @param initialContent initial content for the object
*/
public TextBuilder(CharSequence initialContent) {
stringBuilder = new StringBuilder();
Entity.escapeHtmlChars(initialContent, stringBuilder);
stringBuilder = new StringBuilder(initialContent);
}
/**
* Adds content for the StringContent object. The method escapes
* HTML characters for the string content that is added.
* Adds content for the StringContent object.
*
* @param strContent string content to be added
*/
@Override
public TextBuilder add(CharSequence strContent) {
Entity.escapeHtmlChars(strContent, stringBuilder);
stringBuilder.append(strContent);
return this;
}
@ -75,7 +74,7 @@ public class TextBuilder extends Content {
@Override
public int charCount() {
return RawHtml.charCount(stringBuilder.toString());
return Text.charCount(stringBuilder);
}
@Override
@ -85,7 +84,7 @@ public class TextBuilder extends Content {
@Override
public boolean write(Writer out, boolean atNewline) throws IOException {
String s = stringBuilder.toString();
String s = Entity.escapeHtmlChars(stringBuilder);
out.write(s);
return s.endsWith(DocletConstants.NL);
}

View File

@ -128,6 +128,40 @@ public class CommentUtils {
return treeFactory.newTextTree(resources.getText(key));
}
/**
* Parses a string, looking for simple embedded HTML.
* @param s the string
* @return the list of parsed {@code DocTree} nodes
*/
private List<DocTree> parse(String s) {
List<DocTree> list = null;
Pattern p = Pattern.compile("(?i)<(/)?([a-z0-9]+)(/)?>");
Matcher m = p.matcher(s);
int start = 0;
while (m.find()) {
if (list == null) {
list = new ArrayList<>();
}
if (m.start() > 0) {
list.add(treeFactory.newTextTree(s.substring(start, m.start())));
}
Name name = elementUtils.getName(m.group(2));
list.add(m.group(1) == null
? treeFactory.newStartElementTree(name, List.of(), m.group(3) != null)
: treeFactory.newEndElementTree(name));
start = m.end();
}
if (list == null) {
return List.of(treeFactory.newTextTree(s));
} else {
if (start < s.length()) {
list.add(treeFactory.newTextTree(s.substring(start, s.length())));
}
return list;
}
}
public void setEnumValuesTree(ExecutableElement ee) {
List<DocTree> fullBody = new ArrayList<>();
fullBody.add(treeFactory.newTextTree(resources.getText("doclet.enum_values_doc.fullbody")));
@ -142,8 +176,7 @@ public class CommentUtils {
}
public void setEnumValueOfTree(ExecutableElement ee) {
List<DocTree> fullBody = new ArrayList<>();
fullBody.add(treeFactory.newTextTree(resources.getText("doclet.enum_valueof_doc.fullbody")));
List<DocTree> fullBody = parse(resources.getText("doclet.enum_valueof_doc.fullbody"));
List<DocTree> tags = new ArrayList<>();
@ -242,15 +275,15 @@ public class CommentUtils {
int start = 0;
while (m.find(start)) {
if (m.start() > start) {
contents.add(treeFactory.newTextTree(body.substring(start, m.start())));
contents.addAll(parse(body.substring(start, m.start())));
}
ReferenceTree refTree = treeFactory.newReferenceTree(m.group(1));
List<DocTree> descr = List.of(treeFactory.newTextTree(m.group(2).trim())) ;
List<DocTree> descr = parse(m.group(2).trim());
contents.add(treeFactory.newLinkTree(refTree, descr));
start = m.end();
}
if (start < body.length()) {
contents.add(treeFactory.newTextTree(body.substring(start)));
contents.addAll(parse(body.substring(start)));
}
}
@ -485,16 +518,16 @@ public class CommentUtils {
String text = resources.getText(key);
int index = text.indexOf("{0}");
if (index == -1) {
return List.of(treeFactory.newTextTree(text));
return parse(text);
} else {
Name CODE = elementUtils.getName("code");
return List.of(
treeFactory.newTextTree(text.substring(0, index)),
treeFactory.newStartElementTree(CODE, List.of(), false),
treeFactory.newTextTree(name.toString()),
treeFactory.newEndElementTree(CODE),
treeFactory.newTextTree(text.substring(index + 3))
);
var list = new ArrayList<DocTree>();
list.addAll(parse(text.substring(0, index)));
list.add(treeFactory.newStartElementTree(CODE, List.of(), false));
list.add(treeFactory.newTextTree(name.toString())) ;
list.add(treeFactory.newEndElementTree(CODE));
list.addAll(parse(text.substring(index + 3)));
return list;
}
}

View File

@ -133,9 +133,7 @@ public abstract class Content {
}
/**
* Return the number of characters of plain text content in this object
* (optional operation.)
* @return the number of characters of plain text content in this
* {@return the number of characters of plain text content in this object}
*/
public int charCount() {
return 0;

View File

@ -107,7 +107,7 @@ public final class UserTaglet implements Taglet {
@Override
public Content getInlineTagOutput(Element element, DocTree tag, TagletWriter writer) {
Content output = writer.getOutputInstance();
output.add(new RawHtml(userTaglet.toString(List.of(tag), element)));
output.add(RawHtml.of(userTaglet.toString(List.of(tag), element)));
return output;
}
@ -119,7 +119,7 @@ public final class UserTaglet implements Taglet {
if (!tags.isEmpty()) {
String tagString = userTaglet.toString(tags, holder);
if (tagString != null) {
output.add(new RawHtml(tagString));
output.add(RawHtml.of(tagString));
}
}
return output;

View File

@ -314,7 +314,7 @@ public class CommentHelper {
public String visitSee(SeeTree node, Void p) {
Utils utils = configuration.utils;
return node.getReference().stream()
.filter(utils::isText)
.filter(dt -> dt.getKind() == DocTree.Kind.TEXT)
.map(dt -> ((TextTree) dt).getBody())
.collect(Collectors.joining());
}

View File

@ -2176,18 +2176,6 @@ public class Utils {
return mdle.getQualifiedName().toString();
}
public boolean isStartElement(DocTree doctree) {
return isKind(doctree, START_ELEMENT);
}
public boolean isText(DocTree doctree) {
return isKind(doctree, TEXT);
}
private boolean isKind(DocTree doctree, DocTree.Kind match) {
return doctree.getKind() == match;
}
private final CommentHelperCache commentHelperCache = new CommentHelperCache(this);
public CommentHelper getCommentHelper(Element element) {

View File

@ -44,6 +44,7 @@ public class TestTypeAnnotations extends JavadocTester {
@Test
public void test() {
javadoc("-d", "out",
"-Xdoclint:none",
"--no-platform-links",
"-sourcepath", testSrc,
"-private",

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2012, 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.
*/
// key: compiler.err.dc.invalid.html
// key: compiler.note.note
// key: compiler.note.proc.messager
// run: backdoor
// options: -processor DocCommentProcessor -proc:only
/** <![CDATA[ */
class InvalidHtml { }