8242607: -Xdoclint doesn't report missing/unexpected comments
Reviewed-by: ksrini
This commit is contained in:
parent
0652a7883d
commit
07e6b75ff5
src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit
test/langtools/jdk/javadoc
@ -38,6 +38,7 @@ import java.net.URI;
|
||||
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 class CommentUtils {
|
||||
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 class CommentUtils {
|
||||
|
||||
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 class CommentUtils {
|
||||
}
|
||||
|
||||
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 class CommentUtils {
|
||||
|
||||
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 class CommentUtils {
|
||||
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 class CommentUtils {
|
||||
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 class CommentUtils {
|
||||
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 class CommentUtils {
|
||||
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 @@ public class CommentUtils {
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 class CommentUtils {
|
||||
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 class CommentUtils {
|
||||
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.source.util.TreePath;
|
||||
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 class Utils {
|
||||
* @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 class Utils {
|
||||
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 class Utils {
|
||||
*/
|
||||
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 class Utils {
|
||||
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 class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
boolean isValidDuo(DocCommentDuo duo) {
|
||||
return duo != null && duo.dcTree != null;
|
||||
}
|
||||
|
||||
public DocCommentTree getDocCommentTree(Element element) {
|
||||
CommentHelper ch = commentHelperCache.get(element);
|
||||
if (ch != null) {
|
||||
|
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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 8242607
|
||||
* @summary -Xdoclint doesn't report missing/unexpected comments
|
||||
* @library /tools/lib ../../lib
|
||||
* @modules jdk.javadoc/jdk.javadoc.internal.tool
|
||||
* @build toolbox.ToolBox javadoc.tester.*
|
||||
* @run main TestMissingComment
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import javadoc.tester.JavadocTester;
|
||||
import toolbox.ToolBox;
|
||||
|
||||
public class TestMissingComment extends JavadocTester {
|
||||
public static void main(String... args) throws Exception {
|
||||
TestMissingComment tester = new TestMissingComment();
|
||||
tester.runTests(m -> new Object[] { Path.of(m.getName() )});
|
||||
}
|
||||
|
||||
private ToolBox tb = new ToolBox();
|
||||
|
||||
@Test
|
||||
public void testClass(Path base) throws Exception {
|
||||
test(base.resolve("class"), """
|
||||
// no doc comment
|
||||
public class C { }
|
||||
""",
|
||||
"""
|
||||
testClass/class/src/C.java:2: warning: no comment
|
||||
public class C { }
|
||||
^
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecutable(Path base) throws Exception {
|
||||
test(base.resolve("executable"), """
|
||||
/** Class comment. */
|
||||
public class C {
|
||||
// no doc comment
|
||||
public void m() { }
|
||||
}
|
||||
""",
|
||||
"""
|
||||
testExecutable/executable/src/C.java:4: warning: no comment
|
||||
public void m() { }
|
||||
^
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testField(Path base) throws Exception {
|
||||
test(base.resolve("field"), """
|
||||
/** Class comment. */
|
||||
public class C {
|
||||
// no doc comment
|
||||
public int f;
|
||||
}
|
||||
""",
|
||||
"""
|
||||
testField/field/src/C.java:4: warning: no comment
|
||||
public int f;
|
||||
^
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNested(Path base) throws Exception {
|
||||
test(base.resolve("nest"), """
|
||||
/** Class comment. */
|
||||
public class C {
|
||||
// no doc comment
|
||||
public class Nested { }
|
||||
}
|
||||
""",
|
||||
"""
|
||||
testNested/nest/src/C.java:4: warning: no comment
|
||||
public class Nested { }
|
||||
^
|
||||
""");
|
||||
}
|
||||
|
||||
private void test(Path base, String code, String expect) throws Exception {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src, code);
|
||||
|
||||
javadoc("-d", base.resolve("api").toString(),
|
||||
"-Xdoclint:missing",
|
||||
src.resolve("C.java").toString());
|
||||
checkExit(Exit.OK);
|
||||
checkOutput(Output.OUT, true,
|
||||
expect.replace("/", File.separator),
|
||||
"1 warning");
|
||||
}
|
||||
}
|
@ -44,6 +44,9 @@ public class QuietOption {
|
||||
final File testSrc;
|
||||
final String thisClassName;
|
||||
|
||||
/**
|
||||
* Dummy javadoc comment.
|
||||
*/
|
||||
public QuietOption() {
|
||||
File javaHome = new File(System.getProperty("java.home"));
|
||||
if (javaHome.getName().endsWith("jre"))
|
||||
@ -53,6 +56,11 @@ public class QuietOption {
|
||||
thisClassName = QuietOption.class.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy javadoc comment.
|
||||
* @param args dummy
|
||||
* @throws Exception if error
|
||||
*/
|
||||
public static void main(String... args) throws Exception {
|
||||
QuietOption test = new QuietOption();
|
||||
test.run1();
|
||||
|
@ -108,6 +108,8 @@ public class DocLintTest {
|
||||
|
||||
DL_ERR_P1TEST(ERROR, "P1Test.java:3:16: compiler.err.proc.messager: malformed HTML"),
|
||||
DL_ERR_P2TEST(ERROR, "P2Test.java:3:16: compiler.err.proc.messager: malformed HTML"),
|
||||
DL_WARN_P1TEST(WARNING, "P1Test.java:2:8: compiler.warn.proc.messager: no comment"),
|
||||
DL_WARN_P2TEST(WARNING, "P2Test.java:2:8: compiler.warn.proc.messager: no comment"),
|
||||
|
||||
// doclint messages when -XDrawDiagnostics is not in effect
|
||||
DL_ERR9A(ERROR, "Test.java:9: error: reference not found"),
|
||||
@ -201,11 +203,13 @@ public class DocLintTest {
|
||||
|
||||
test(List.of(htmlVersion, rawDiags),
|
||||
Main.Result.ERROR,
|
||||
EnumSet.of(Message.DL_ERR_P1TEST, Message.DL_ERR_P2TEST));
|
||||
EnumSet.of(Message.DL_ERR_P1TEST, Message.DL_ERR_P2TEST,
|
||||
Message.DL_WARN_P1TEST, Message.DL_WARN_P2TEST));
|
||||
|
||||
test(List.of(htmlVersion, rawDiags, "-Xdoclint/package:p1"),
|
||||
Main.Result.ERROR,
|
||||
EnumSet.of(Message.DL_ERR_P1TEST));
|
||||
EnumSet.of(Message.DL_ERR_P1TEST,
|
||||
Message.DL_WARN_P1TEST));
|
||||
|
||||
test(List.of(htmlVersion, rawDiags, "-Xdoclint/package:*p"),
|
||||
Main.Result.ERROR,
|
||||
|
Loading…
x
Reference in New Issue
Block a user