Skip to content
This repository has been archived by the owner on Sep 2, 2022. It is now read-only.
Permalink
Browse files
8270866: NPE in DocTreePath.getTreePath()
Reviewed-by: jjg
  • Loading branch information
hns committed Jul 27, 2021
1 parent f662127 commit fbe28e4
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 60 deletions.
@@ -335,7 +335,7 @@ protected void addUseInfo(List<? extends Element> members, Content heading, Cont
: HtmlLinkInfo.Kind.MEMBER,
te, element, typeContent);
Content desc = new ContentBuilder();
writer.addSummaryLinkComment(this, element, desc);
writer.addSummaryLinkComment(element, desc);
useTable.addRow(summaryType, typeContent, desc);
}
contentTree.add(useTable);
@@ -363,7 +363,7 @@ public void addMemberSummary(TypeElement tElement, Element member,
addSummaryLink(tElement, member, summaryLink);
rowContents.add(summaryLink);
Content desc = new ContentBuilder();
writer.addSummaryLinkComment(this, member, firstSentenceTrees, desc);
writer.addSummaryLinkComment(member, firstSentenceTrees, desc);
rowContents.add(desc);
table.addRow(member, rowContents);
}
@@ -1162,7 +1162,7 @@ private Content plainOrCode(boolean plain, Content body) {
public void addInlineComment(Element element, DocTree tag, Content htmltree) {
CommentHelper ch = utils.getCommentHelper(element);
List<? extends DocTree> description = ch.getDescription(tag);
addCommentTags(element, tag, description, false, false, false, htmltree);
addCommentTags(element, description, false, false, false, htmltree);
}

/**
@@ -1249,22 +1249,6 @@ public void addInlineComment(Element element, Content htmltree) {
*/
private void addCommentTags(Element element, List<? extends DocTree> tags, boolean depr,
boolean first, boolean inSummary, Content htmltree) {
addCommentTags(element, null, tags, depr, first, inSummary, htmltree);
}

/**
* Adds the comment tags.
*
* @param element for which the comment tags will be generated
* @param holderTag the block tag context for the inline tags
* @param tags the first sentence tags for the doc
* @param depr true if it is deprecated
* @param first true if the first sentence tags should be added
* @param inSummary true if the comment tags are added into the summary section
* @param htmltree the documentation tree to which the comment tags will be added
*/
private void addCommentTags(Element element, DocTree holderTag, List<? extends DocTree> tags, boolean depr,
boolean first, boolean inSummary, Content htmltree) {
if (options.noComment()) {
return;
}
@@ -38,7 +38,6 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.TagName;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;

@@ -136,25 +135,22 @@ protected void addIndexComment(Element member, List<? extends DocTree> firstSent
/**
* Add the summary link for the member.
*
* @param mw the writer for the member being documented
* @param member the member to be documented
* @param contentTree the content tree to which the link will be added
*/
public void addSummaryLinkComment(AbstractMemberWriter mw, Element member, Content contentTree) {
public void addSummaryLinkComment(Element member, Content contentTree) {
List<? extends DocTree> tags = utils.getFirstSentenceTrees(member);
addSummaryLinkComment(mw, member, tags, contentTree);
addSummaryLinkComment(member, tags, contentTree);
}

/**
* Add the summary link comment.
*
* @param mw the writer for the member being documented
* @param member the member being documented
* @param firstSentenceTags the first sentence tags for the member to be documented
* @param tdSummary the content tree to which the comment will be added
*/
public void addSummaryLinkComment(AbstractMemberWriter mw,
Element member, List<? extends DocTree> firstSentenceTags, Content tdSummary) {
public void addSummaryLinkComment(Element member, List<? extends DocTree> firstSentenceTags, Content tdSummary) {
addIndexComment(member, firstSentenceTags, tdSummary);
}

@@ -97,7 +97,6 @@ private Content retrieveInheritedDocumentation(TagletWriter writer,
if (!inheritedDoc.inlineTags.isEmpty()) {
replacement = writer.commentTagsToOutput(inheritedDoc.holder, inheritedDoc.holderTag,
inheritedDoc.inlineTags, isFirstSentence);
ch.setOverrideElement(inheritedDoc.holder);
}

} else {
@@ -206,9 +206,7 @@ private Content getInheritedTagletOutput(ParamKind kind, Element holder,
String lname = kind != ParamKind.TYPE_PARAMETER
? utils.getSimpleName(e)
: utils.getTypeName(e.asType(), false);
CommentHelper ch = utils.getCommentHelper(holder);
ch.setOverrideElement(inheritedDoc.holder);
Content content = processParamTag(holder, kind, writer,
Content content = processParamTag(inheritedDoc.holder, kind, writer,
(ParamTree) inheritedDoc.holderTag,
lname,
alreadyDocumented.isEmpty());
@@ -121,9 +121,7 @@ public Content getAllBlockTagOutput(Element holder, TagletWriter writer) {
Input input = new DocFinder.Input(utils, holder, this);
DocFinder.Output inheritedDoc = DocFinder.search(writer.configuration(), input);
if (inheritedDoc.holderTag != null) {
CommentHelper ch = utils.getCommentHelper(input.element);
ch.setOverrideElement(inheritedDoc.holder);
return writer.returnTagOutput(holder, (ReturnTree) inheritedDoc.holderTag, false);
return writer.returnTagOutput(inheritedDoc.holder, (ReturnTree) inheritedDoc.holderTag, false);
}
return null;
}
@@ -165,37 +165,16 @@ Element getElement(ReferenceTree rtree) {
}
return configuration.docEnv.getTypeUtils().asElement(symbol);
}
// case A: the element contains no comments associated and
// the comments need to be copied from ancestor
// case B: the element has @inheritDoc, then the ancestral comment
// as appropriate has to be copied over.

// Case A.
if (dcTree == null && overriddenElement != null) {
CommentHelper ovch = utils.getCommentHelper(overriddenElement);
return ovch.getElement(rtree);
}
if (dcTree == null) {
return null;
}
DocTreePath docTreePath = DocTreePath.getPath(path, dcTree, rtree);
DocTreePath docTreePath = getDocTreePath(rtree);
if (docTreePath == null) {
// Case B.
if (overriddenElement != null) {
CommentHelper ovch = utils.getCommentHelper(overriddenElement);
return ovch.getElement(rtree);
}
return null;
}
DocTrees doctrees = configuration.docEnv.getDocTrees();
return doctrees.getElement(docTreePath);
}

public TypeMirror getType(ReferenceTree rtree) {
// Workaround for JDK-8269706
if (path == null || dcTree == null || rtree == null)
return null;
DocTreePath docTreePath = DocTreePath.getPath(path, dcTree, rtree);
DocTreePath docTreePath = getDocTreePath(rtree);
if (docTreePath != null) {
DocTrees doctrees = configuration.docEnv.getDocTrees();
return doctrees.getType(docTreePath);
@@ -700,9 +679,18 @@ public ReferenceTree getType(DocTree dtree) {
}

public DocTreePath getDocTreePath(DocTree dtree) {
if (path == null || dcTree == null || dtree == null)
if (dcTree == null && overriddenElement != null) {
// This is an inherited comment, return path from ancestor.
return configuration.utils.getCommentHelper(overriddenElement).getDocTreePath(dtree);
} else if (path == null || dcTree == null || dtree == null) {
return null;
return DocTreePath.getPath(path, dcTree, dtree);
}
DocTreePath dtPath = DocTreePath.getPath(path, dcTree, dtree);
if (dtPath == null && overriddenElement != null) {
// The overriding element has a doc tree, but it doesn't contain what we're looking for.
return configuration.utils.getCommentHelper(overriddenElement).getDocTreePath(dtree);
}
return dtPath;
}

public Element getOverriddenElement() {
@@ -23,7 +23,7 @@

/*
* @test
* @bug 8269722
* @bug 8269722 8270866
* @summary NPE in HtmlDocletWriter, reporting errors on inherited tags
* @library /tools/lib ../../lib
* @modules jdk.javadoc/jdk.javadoc.internal.tool
@@ -67,6 +67,14 @@ public void m(int i) { }
"-Xdoclint:-missing", "-XDdoe",
src.resolve("BadParam.java").toString());
checkExit(Exit.OK);
checkOutput("BadParam.Base.html", true, """
<dt>Parameters:</dt>
<dd><code>i</code> - a &lt; b</dd>
""");
checkOutput("BadParam.Sub.html", true, """
<dt>Parameters:</dt>
<dd><code>i</code> - a &lt; b</dd>
""");
}

@Test
@@ -91,5 +99,64 @@ public int m() { }
"-Xdoclint:-missing",
src.resolve("BadReturn.java").toString());
checkExit(Exit.OK);
checkOutput("BadReturn.Base.html", true, """
<dt>Returns:</dt>
<dd>a &lt; b</dd>
""");
checkOutput("BadReturn.Sub.html", true, """
<dt>Returns:</dt>
<dd>a &lt; b</dd>
""");
}

@Test
public void testBadInheritedReference(Path base) throws Exception {
Path src = base.resolve("src");
tb.writeJavaFiles(src, """
public class BadReference {
public interface Intf {
/**
* {@link NonExistingClass}
*/
public void m();
}

public static class Impl1 implements Intf {
public void m() { }
}

public static class Impl2 implements Intf {
/**
* {@inheritDoc}
*/
public void m() { }
}

// subclass has doc comment but inherits main description
public static class Impl3 implements Intf {
/**
* @since 1
*/
public void m() { }
}
}
""");

javadoc("-d", base.resolve("out").toString(),
"-Xdoclint:-reference",
src.resolve("BadReference.java").toString());
checkExit(Exit.OK);
checkOutput("BadReference.Intf.html", true, """
<div class="block"><code>NonExistingClass</code></div>
""");
checkOutput("BadReference.Impl1.html", true, """
<div class="block"><code>NonExistingClass</code></div>
""");
checkOutput("BadReference.Impl2.html", true, """
<div class="block"><code>NonExistingClass</code></div>
""");
checkOutput("BadReference.Impl3.html", true, """
<div class="block"><code>NonExistingClass</code></div>
""");
}
}
}

1 comment on commit fbe28e4

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.