Skip to content
Permalink
Browse files
8242607: -Xdoclint doesn't report missing/unexpected comments
Reviewed-by: ksrini
  • Loading branch information
jonathan-gibbons committed Jun 10, 2020
1 parent 0652a78 commit 07e6b75ff57ce746b4fdb06e06abbd3d298cd8fa
Showing 5 changed files with 215 additions and 56 deletions.
@@ -38,6 +38,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@@ -74,10 +75,18 @@ public class CommentUtils {
final Utils utils;
final Resources resources;
final DocTreeFactory treeFactory;
final HashMap<Element, DocCommentDuo> dcTreesMap = new HashMap<>();
final DocTrees trees;
final Elements elementUtils;

/**
* A map for storing automatically generated comments for various
* elements, such as mandated elements (Enum.values, Enum.valueOf, etc)
* and JavaFX properties.
*
* @see Utils#dcTreeCache
*/
final HashMap<Element, DocCommentInfo> dcInfoMap = new HashMap<>();

protected CommentUtils(BaseConfiguration configuration) {
this.configuration = configuration;
utils = configuration.utils;
@@ -133,7 +142,7 @@ public void setEnumValuesTree(ExecutableElement ee) {
List<DocTree> tags = new ArrayList<>();
tags.add(treeFactory.newReturnTree(descriptions));
DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, tags);
dcTreesMap.put(ee, new DocCommentDuo(null, docTree));
dcInfoMap.put(ee, new DocCommentInfo(null, docTree));
}

public void setEnumValueOfTree(ExecutableElement ee) {
@@ -167,7 +176,7 @@ public void setEnumValueOfTree(ExecutableElement ee) {

DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, tags);

dcTreesMap.put(ee, new DocCommentDuo(null, docTree));
dcInfoMap.put(ee, new DocCommentInfo(null, docTree));
}

/**
@@ -190,7 +199,7 @@ public void setRecordConstructorTree(ExecutableElement ee) {
}

DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, tags);
dcTreesMap.put(ee, new DocCommentDuo(null, docTree));
dcInfoMap.put(ee, new DocCommentInfo(null, docTree));
}

/**
@@ -226,7 +235,7 @@ public void setRecordEqualsTree(ExecutableElement ee) {

TreePath treePath = utils.getTreePath(ee.getEnclosingElement());
DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, List.of(paramTree, returnTree));
dcTreesMap.put(ee, new DocCommentDuo(treePath, docTree));
dcInfoMap.put(ee, new DocCommentInfo(treePath, docTree));
}

private void add(List<DocTree> contents, String resourceKey) {
@@ -262,7 +271,7 @@ public void setRecordHashCodeTree(ExecutableElement ee) {
List.of(makeTextTreeForResource("doclet.record_hashCode_doc.return")));

DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, List.of(returnTree));
dcTreesMap.put(ee, new DocCommentDuo(null, docTree));
dcInfoMap.put(ee, new DocCommentInfo(null, docTree));
}

/**
@@ -277,7 +286,7 @@ public void setRecordToStringTree(ExecutableElement ee) {
treeFactory.newTextTree(resources.getText("doclet.record_toString_doc.return"))));

DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, List.of(returnTree));
dcTreesMap.put(ee, new DocCommentDuo(null, docTree));
dcInfoMap.put(ee, new DocCommentInfo(null, docTree));
}

/**
@@ -294,7 +303,7 @@ public void setRecordAccessorTree(ExecutableElement ee) {
makeDescriptionWithComponent("doclet.record_accessor_doc.return", te, ee.getSimpleName()));

DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, List.of(returnTree));
dcTreesMap.put(ee, new DocCommentDuo(null, docTree));
dcInfoMap.put(ee, new DocCommentInfo(null, docTree));
}

/**
@@ -308,7 +317,7 @@ public void setRecordFieldTree(VariableElement ve) {
makeDescriptionWithComponent("doclet.record_field_doc.fullbody", te, ve.getSimpleName());

DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, List.of());
dcTreesMap.put(ve, new DocCommentDuo(null, docTree));
dcInfoMap.put(ve, new DocCommentInfo(null, docTree));
}

/**
@@ -395,16 +404,19 @@ private List<DocTree> makeDescriptionWithName(String key, Name name) {
}

/*
* Returns the TreePath/DocCommentTree duo for synthesized element.
* Returns the TreePath/DocCommentTree info that has been generated for an element.
* @param e the element
* @return the info object containing the tree path and doc comment
*/
public DocCommentDuo getSyntheticCommentDuo(Element e) {
return dcTreesMap.get(e);
// "synthetic" is not the best word here, and should not be confused with synthetic elements
public DocCommentInfo getSyntheticCommentInfo(Element e) {
return dcInfoMap.get(e);
}

/*
* Returns the TreePath/DocCommentTree duo for html sources.
* Returns the TreePath/DocCommentTree info for HTML sources.
*/
public DocCommentDuo getHtmlCommentDuo(Element e) {
public DocCommentInfo getHtmlCommentInfo(Element e) {
FileObject fo = null;
PackageElement pe = null;
switch (e.getKind()) {
@@ -431,7 +443,7 @@ public DocCommentDuo getHtmlCommentDuo(Element e) {
return null;
}
DocTreePath treePath = trees.getDocTreePath(fo, pe);
return new DocCommentDuo(treePath.getTreePath(), dcTree);
return new DocCommentInfo(treePath.getTreePath(), dcTree);
}

public DocCommentTree parse(URI uri, String text) {
@@ -447,24 +459,34 @@ public CharSequence getCharContent(boolean ignoreEncoding) {
public void setDocCommentTree(Element element, List<? extends DocTree> fullBody,
List<? extends DocTree> blockTags) {
DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, blockTags);
dcTreesMap.put(element, new DocCommentDuo(null, docTree));
dcInfoMap.put(element, new DocCommentInfo(null, docTree));
// A method having null comment (no comment) that might need to be replaced
// with a synthetic comment, remove such a comment from the cache.
// with a generated comment, remove such a comment from the cache.
utils.removeCommentHelper(element);
}

/**
* A simplistic container to transport a TreePath, DocCommentTree pair.
* Here is why we need this:
* a. not desirable to add javac's pair.
* b. DocTreePath is not a viable option either, as a null TreePath is required
* to represent synthetic comments for Enum.values, valuesOf, javafx properties.
* Info about a doc comment:
* the position in the enclosing AST, and
* the parsed doc comment itself.
*
* The position in the AST is {@code null} for automatically generated comments,
* such as for {@code Enum.values}, {@code Enum.valuesOf}, and JavaFX properties.
*/
public static class DocCommentDuo {
public static class DocCommentInfo {
/**
* The position of the comment in the enclosing AST, or {@code null}
* for automatically generated comments.
*/
public final TreePath treePath;

/**
* The doc comment tree that is the root node of a parsed doc comment,
* or {@code null} if there is no comment.
*/
public final DocCommentTree dcTree;

public DocCommentDuo(TreePath treePath, DocCommentTree dcTree) {
public DocCommentInfo(TreePath treePath, DocCommentTree dcTree) {
this.treePath = treePath;
this.dcTree = dcTree;
}
@@ -107,7 +107,7 @@
import com.sun.tools.javac.model.JavacTypes;
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
import jdk.javadoc.internal.doclets.toolkit.BaseOptions;
import jdk.javadoc.internal.doclets.toolkit.CommentUtils.DocCommentDuo;
import jdk.javadoc.internal.doclets.toolkit.CommentUtils.DocCommentInfo;
import jdk.javadoc.internal.doclets.toolkit.Resources;
import jdk.javadoc.internal.doclets.toolkit.WorkArounds;
import jdk.javadoc.internal.doclets.toolkit.taglets.BaseTaglet;
@@ -2651,13 +2651,13 @@ public boolean hasBlockTag(Element element, DocTree.Kind kind, final String tagN
* @return TreePath
*/
public TreePath getTreePath(Element e) {
DocCommentDuo duo = dcTreeCache.get(e);
if (duo != null && duo.treePath != null) {
return duo.treePath;
DocCommentInfo info = dcTreeCache.get(e);
if (info != null && info.treePath != null) {
return info.treePath;
}
duo = configuration.cmtUtils.getSyntheticCommentDuo(e);
if (duo != null && duo.treePath != null) {
return duo.treePath;
info = configuration.cmtUtils.getSyntheticCommentInfo(e);
if (info != null && info.treePath != null) {
return info.treePath;
}
Map<Element, TreePath> elementToTreePath = configuration.workArounds.getElementToTreePath();
TreePath path = elementToTreePath.get(e);
@@ -2668,7 +2668,14 @@ public TreePath getTreePath(Element e) {
return elementToTreePath.computeIfAbsent(e, docTrees::getPath);
}

private final Map<Element, DocCommentDuo> dcTreeCache = new LinkedHashMap<>();
/**
* A cache of doc comment info objects for elements.
* The entries may come from the AST and DocCommentParser, or may be autromatically
* generated comments for mandated elements and JavaFX properties.
*
* @see CommentUtils.dcInfoMap
*/
private final Map<Element, DocCommentInfo> dcTreeCache = new LinkedHashMap<>();

/**
* Retrieves the doc comments for a given element.
@@ -2677,34 +2684,34 @@ public TreePath getTreePath(Element e) {
*/
public DocCommentTree getDocCommentTree0(Element element) {

DocCommentDuo duo = null;
DocCommentInfo info = null;

ElementKind kind = element.getKind();
if (kind == ElementKind.PACKAGE || kind == ElementKind.OTHER) {
duo = dcTreeCache.get(element); // local cache
if (duo == null && kind == ElementKind.PACKAGE) {
info = dcTreeCache.get(element); // local cache
if (info == null && kind == ElementKind.PACKAGE) {
// package-info.java
duo = getDocCommentTuple(element);
info = getDocCommentInfo(element);
}
if (duo == null) {
if (info == null) {
// package.html or overview.html
duo = configuration.cmtUtils.getHtmlCommentDuo(element); // html source
info = configuration.cmtUtils.getHtmlCommentInfo(element); // html source
}
} else {
duo = configuration.cmtUtils.getSyntheticCommentDuo(element);
if (duo == null) {
duo = dcTreeCache.get(element); // local cache
info = configuration.cmtUtils.getSyntheticCommentInfo(element);
if (info == null) {
info = dcTreeCache.get(element); // local cache
}
if (duo == null) {
duo = getDocCommentTuple(element); // get the real mccoy
if (info == null) {
info = getDocCommentInfo(element); // get the real mccoy
}
}

DocCommentTree docCommentTree = isValidDuo(duo) ? duo.dcTree : null;
TreePath path = isValidDuo(duo) ? duo.treePath : null;
DocCommentTree docCommentTree = info == null ? null : info.dcTree;
if (!dcTreeCache.containsKey(element)) {
if (docCommentTree != null && path != null) {
if (!configuration.isAllowScriptInComments()) {
TreePath path = info == null ? null : info.treePath;
if (path != null) {
if (docCommentTree != null && !configuration.isAllowScriptInComments()) {
try {
javaScriptScanner.scan(docCommentTree, path, p -> {
throw new JavaScriptScanner.Fault();
@@ -2714,20 +2721,21 @@ public DocCommentTree getDocCommentTree0(Element element) {
throw new UncheckedDocletException(new SimpleDocletException(text, jsf));
}
}
// run doclint even if docCommentTree is null, to trigger checks for missing comments
configuration.workArounds.runDocLint(path);
}
dcTreeCache.put(element, duo);
dcTreeCache.put(element, info);
}
return docCommentTree;
}

private DocCommentDuo getDocCommentTuple(Element element) {
private DocCommentInfo getDocCommentInfo(Element element) {
// prevent nasty things downstream with overview element
if (element.getKind() != ElementKind.OTHER) {
TreePath path = getTreePath(element);
if (path != null) {
DocCommentTree docCommentTree = docTrees.getDocCommentTree(path);
return new DocCommentDuo(path, docCommentTree);
return new DocCommentInfo(path, docCommentTree);
}
}
return null;
@@ -2752,10 +2760,6 @@ public void checkJavaScriptInOption(String name, String value) {
}
}

boolean isValidDuo(DocCommentDuo duo) {
return duo != null && duo.dcTree != null;
}

public DocCommentTree getDocCommentTree(Element element) {
CommentHelper ch = commentHelperCache.get(element);
if (ch != null) {

0 comments on commit 07e6b75

Please sign in to comment.