8272374: doclint should report missing "body" comments

Reviewed-by: kcr, hannesw
This commit is contained in:
Jonathan Gibbons 2021-08-16 20:48:25 +00:00
parent b2c272d4e2
commit ae45592d33
37 changed files with 270 additions and 129 deletions

View File

@ -23,7 +23,7 @@
# questions.
#
DOCLINT += -Xdoclint:all/protected,-reference \
DOCLINT += -Xdoclint:all/protected,-reference,-missing \
'-Xdoclint/package:java.*,javax.*'
COPY += .gif .png .wav .txt .xml .css .pf
CLEAN += iio-plugin.properties cursors.properties

View File

@ -182,9 +182,6 @@ public class Checker extends DocTreePathScanner<Void, Void> {
reportMissing("dc.missing.comment");
return null;
}
} else {
if (tree == null) {
if (isDefaultConstructor()) {
@ -195,6 +192,17 @@ public class Checker extends DocTreePathScanner<Void, Void> {
reportMissing("dc.missing.comment");
}
return null;
} else if (tree.getFirstSentence().isEmpty() && !isOverridingMethod) {
if (tree.getBlockTags().isEmpty()) {
reportMissing("dc.empty.comment");
return null;
} else {
// Don't report an empty description if the comment contains @deprecated,
// because javadoc will use the content of that tag in summary tables.
if (tree.getBlockTags().stream().allMatch(t -> t.getKind() != DocTree.Kind.DEPRECATED)) {
env.messages.report(MISSING, Kind.WARNING, tree, "dc.empty.description");
}
}
}
}

View File

@ -39,6 +39,8 @@ dc.bad.option = bad option: {0}
dc.bad.value.for.option = bad value for option: {0} {1}
dc.default.constructor = use of default constructor, which does not provide a comment
dc.empty = no description for @{0}
dc.empty.comment = empty comment
dc.empty.description = no initial description
dc.entity.invalid = invalid entity &{0};
dc.exception.not.thrown = exception not thrown: {0}
dc.exists.param = @param "{0}" has already been specified

View File

@ -32,7 +32,6 @@ import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
@ -63,25 +62,21 @@ public class DocLintTest {
final String code =
/* 01 */ "/** Class comment. */\n" +
/* 02 */ "public class Test { /** */ Test() { }\n" +
/* 02 */ "public class Test { /** Constructor comment. */ Test() { }\n" +
/* 03 */ " /** Method comment. */\n" +
/* 04 */ " public void method() { }\n" +
/* 05 */ "\n" +
/* 06 */ " /** Syntax < error. */\n" +
/* 07 */ """
\s private void syntaxError() { }
""" +
/* 07 */ " private void syntaxError() { }\n" +
/* 08 */ "\n" +
/* 09 */ " /** @see DoesNotExist */\n" +
/* 10 */ """
\s protected void referenceError() { }
""" +
/* 11 */ "\n" +
/* 12 */ " /** @return */\n" +
/* 13 */ """
\s public int emptyReturn() { return 0; }
""" +
/* 14 */ "}\n";
/* 09 */ " /** Description. \n" +
/* 10 */ " * @see DoesNotExist */\n" +
/* 11 */ " protected void referenceError() { }\n" +
/* 12 */ "\n" +
/* 13 */ " /** Description. \n" +
/* 14 */ " * @return */\n" +
/* 15 */ " public int emptyReturn() { return 0; }\n" +
/* 16 */ "}\n";
final String p1Code =
/* 01 */ "package p1;\n" +
@ -103,8 +98,8 @@ public class DocLintTest {
private enum Message {
// doclint messages
DL_ERR6(ERROR, "Test.java:6:16: compiler.err.proc.messager: malformed HTML"),
DL_ERR9(ERROR, "Test.java:9:14: compiler.err.proc.messager: reference not found"),
DL_WRN12(WARNING, "Test.java:12:9: compiler.warn.proc.messager: no description for @return"),
DL_ERR10(ERROR, "Test.java:10:13: compiler.err.proc.messager: reference not found"),
DL_WRN14(WARNING, "Test.java:14:8: compiler.warn.proc.messager: no description for @return"),
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"),
@ -112,12 +107,12 @@ public class DocLintTest {
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"),
DL_WRN12A(WARNING, "Test.java:12: warning: no description for @return"),
DL_ERR10A(ERROR, "Test.java:10: error: reference not found"),
DL_WRN14A(WARNING, "Test.java:14: warning: no description for @return"),
// javadoc messages about bad content: these should only appear when doclint is disabled
JD_WRN10(WARNING, "Test.java:10: warning: Tag @see: reference not found: DoesNotExist"),
JD_WRN13(WARNING, "Test.java:13: warning: @return tag has no arguments."),
JD_WRN14(WARNING, "Test.java:14: warning: @return tag has no arguments."),
// javadoc messages for bad options
OPT_BADARG(ERROR, "error: Invalid argument for -Xdoclint option"),
@ -156,11 +151,11 @@ public class DocLintTest {
test(List.of(htmlVersion),
Main.Result.ERROR,
EnumSet.of(Message.DL_ERR9A, Message.DL_WRN12A));
EnumSet.of(Message.DL_ERR10A, Message.DL_WRN14A));
test(List.of(htmlVersion, rawDiags),
Main.Result.ERROR,
EnumSet.of(Message.DL_ERR9, Message.DL_WRN12));
EnumSet.of(Message.DL_ERR10, Message.DL_WRN14));
// test(List.of("-Xdoclint:none"),
// Main.Result.OK,
@ -168,7 +163,7 @@ public class DocLintTest {
test(List.of(htmlVersion, rawDiags, "-Xdoclint"),
Main.Result.ERROR,
EnumSet.of(Message.DL_ERR9, Message.DL_WRN12));
EnumSet.of(Message.DL_ERR10, Message.DL_WRN14));
test(List.of(htmlVersion, rawDiags, "-Xdoclint:all/public"),
Main.Result.ERROR,
@ -176,23 +171,23 @@ public class DocLintTest {
test(List.of(htmlVersion, rawDiags, "-Xdoclint:all", "-public"),
Main.Result.OK,
EnumSet.of(Message.DL_WRN12));
EnumSet.of(Message.DL_WRN14));
test(List.of(htmlVersion, rawDiags, "-Xdoclint:missing"),
Main.Result.OK,
EnumSet.of(Message.DL_WRN12));
EnumSet.of(Message.DL_WRN14));
test(List.of(htmlVersion, rawDiags, "-private"),
Main.Result.ERROR,
EnumSet.of(Message.DL_ERR6, Message.DL_ERR9, Message.DL_WRN12));
EnumSet.of(Message.DL_ERR6, Message.DL_ERR10, Message.DL_WRN14));
test(List.of(htmlVersion, rawDiags, "-Xdoclint:missing,syntax", "-private"),
Main.Result.ERROR,
EnumSet.of(Message.DL_ERR6, Message.DL_WRN12));
EnumSet.of(Message.DL_ERR6, Message.DL_WRN14));
test(List.of(htmlVersion, rawDiags, "-Xdoclint:reference"),
Main.Result.ERROR,
EnumSet.of(Message.DL_ERR9));
EnumSet.of(Message.DL_ERR10));
test(List.of(htmlVersion, rawDiags, "-Xdoclint:badarg"),
Main.Result.ERROR,

View File

@ -18,8 +18,8 @@
* @run main DocLintTester -Xmsgs:all,-syntax/private -ref AccessTest.package.out AccessTest.java
*/
/** */
public class AccessTest { /** */ AccessTest() { }
/** . */
public class AccessTest { /** . */ AccessTest() { }
/**
* public a < b
*/
@ -41,8 +41,8 @@ public class AccessTest { /** */ AccessTest() { }
private void private_syntax_error() { }
}
/** */
class AccessTest2 { /** */ AccessTest2() { }
/** Class comment. */
class AccessTest2 { /** Constructor comment. */ AccessTest2() { }
/**
* public a < b
*/

View File

@ -11,7 +11,7 @@
* @author bpatel
*/
/**
/** .
* @customTag Text for a custom tag.
* @custom.tag Text for another custom tag.
* @unknownTag Text for an unknown tag.

View File

@ -8,7 +8,10 @@
* @run main DocLintTester -Xmsgs:missing -ref EmptyAuthorTest.out EmptyAuthorTest.java
*/
/** @author */
/**
* .
* @author
*/
public class EmptyAuthorTest {
/** */ EmptyAuthorTest() { }
}
/** . */ EmptyAuthorTest() { }
}

View File

@ -1,5 +1,5 @@
EmptyAuthorTest.java:11: warning: no description for @author
/** @author */
^
EmptyAuthorTest.java:13: warning: no description for @author
* @author
^
1 warning

View File

@ -0,0 +1,79 @@
/*
* @test /nodynamiccopyright/
* @bug 8272374
* @summary doclint should report missing "body" comments
* @modules jdk.javadoc/jdk.javadoc.internal.doclint
* @build DocLintTester
* @run main DocLintTester -Xmsgs:-missing EmptyDescriptionTest.java
* @run main DocLintTester -Xmsgs:missing -ref EmptyDescriptionTest.out EmptyDescriptionTest.java
*/
/** . */
public class EmptyDescriptionTest {
// a default constructor triggers its own variant of "no comment"
// no comment
public int f1;
// empty comment
/** */
public int f2;
// empty description
/**
* @since 1.0
*/
public int f3;
// deprecated: no diagnostic
/**
* @deprecated do not use
*/
public int f4;
// no comment
public int m1() { return 0; }
// empty comment
/** */
public int m2() { return 0; }
// empty description
/**
* @return 0
*/
public int m3() { return 0; }
// deprecated: no diagnostic
/**
* @deprecated do not use
* @return 0
*/
public int m4() { return 0; };
/**
* A class containing overriding methods.
* Overriding methods with missing/empty comments do not generate messages
* since they are presumed to inherit descriptions as needed.
*/
public static class Nested extends EmptyDescriptionTest {
/** . */ Nested() { }
@Override
public int m1() { return 1; }
// empty comment
/** */
@Override
public int m2() { return 1; }
// empty description
/**
* @return 1
*/
@Override
public int m3() { return 1; }
}
}

View File

@ -0,0 +1,22 @@
EmptyDescriptionTest.java:13: warning: use of default constructor, which does not provide a comment
public class EmptyDescriptionTest {
^
EmptyDescriptionTest.java:17: warning: no comment
public int f1;
^
EmptyDescriptionTest.java:21: warning: empty comment
public int f2;
^
EmptyDescriptionTest.java:25: warning: no initial description
* @since 1.0
^
EmptyDescriptionTest.java:36: warning: no comment
public int m1() { return 0; }
^
EmptyDescriptionTest.java:40: warning: empty comment
public int m2() { return 0; }
^
EmptyDescriptionTest.java:44: warning: no initial description
* @return 0
^
7 warnings

View File

@ -9,7 +9,10 @@
*/
/** . */
public class EmptyExceptionTest { /** */ EmptyExceptionTest() { }
/** @exception NullPointerException */
public class EmptyExceptionTest { /** . */ EmptyExceptionTest() { }
/**
* .
* @exception NullPointerException
*/
void emptyException() throws NullPointerException { }
}

View File

@ -1,4 +1,4 @@
EmptyExceptionTest.java:13: warning: no description for @exception
/** @exception NullPointerException */
^
EmptyExceptionTest.java:15: warning: no description for @exception
* @exception NullPointerException
^
1 warning

View File

@ -10,6 +10,9 @@
/** . */
public class EmptyParamTest { /** . */ EmptyParamTest() { }
/** @param i */
/**
* .
* @param i
*/
void emptyParam(int i) { }
}

View File

@ -1,5 +1,5 @@
EmptyParamTest.java:13: warning: no description for @param
/** @param i */
^
EmptyParamTest.java:15: warning: no description for @param
* @param i
^
1 warning

View File

@ -10,6 +10,9 @@
/** . */
public class EmptyReturnTest { /** . */ EmptyReturnTest() { }
/** @return */
/**
* .
* @return
*/
int emptyReturn() { return 0; }
}

View File

@ -1,5 +1,4 @@
EmptyReturnTest.java:13: warning: no description for @return
/** @return */
^
EmptyReturnTest.java:15: warning: no description for @return
* @return
^
1 warning

View File

@ -15,6 +15,7 @@ import java.io.Serializable;
public class EmptySerialFieldTest implements Serializable { /** . */ EmptySerialFieldTest() { }
/**
* .
* @serialField empty String
*/
private static final ObjectStreamField[] serialPersistentFields = {

View File

@ -1,4 +1,4 @@
EmptySerialFieldTest.java:18: warning: no description for @serialField
EmptySerialFieldTest.java:19: warning: no description for @serialField
* @serialField empty String
^
1 warning

View File

@ -10,6 +10,9 @@
/** . */
public class EmptySinceTest { /** . */ EmptySinceTest() { }
/** @since */
/**
* .
* @since
*/
void emptySince() { }
}

View File

@ -1,5 +1,4 @@
EmptySinceTest.java:13: warning: no description for @since
/** @since */
^
EmptySinceTest.java:15: warning: no description for @since
* @since
^
1 warning

View File

@ -10,6 +10,9 @@
/** . */
public class EmptyVersionTest { /** . */ EmptyVersionTest() { }
/** @version */
/**
* .
* @version
*/
void missingVersion() { }
}

View File

@ -1,4 +1,4 @@
EmptyVersionTest.java:13: warning: no description for @version
/** @version */
^
EmptyVersionTest.java:15: warning: no description for @version
* @version
^
1 warning

View File

@ -9,13 +9,17 @@
* @author jlahoda
*/
/**@deprecated*/
/**
* .
* @deprecated*/
public class EndWithIdentifierTest {
/**{@link*/
private void unfinishedInlineTagName() {}
/**@see List*/
/**
* .
* @see List*/
private void endsWithIdentifier() {}
/**&amp*/

View File

@ -1,19 +1,19 @@
EndWithIdentifierTest.java:15: error: syntax error in reference
EndWithIdentifierTest.java:17: error: syntax error in reference
/**{@link*/
^
EndWithIdentifierTest.java:18: error: reference not found
/**@see List*/
EndWithIdentifierTest.java:22: error: reference not found
* @see List*/
^
EndWithIdentifierTest.java:21: error: semicolon missing
EndWithIdentifierTest.java:25: error: semicolon missing
/**&amp*/
^
EndWithIdentifierTest.java:24: error: malformed HTML
EndWithIdentifierTest.java:28: error: malformed HTML
/**<a*/
^
EndWithIdentifierTest.java:27: error: malformed HTML
EndWithIdentifierTest.java:31: error: malformed HTML
/**</a*/
^
EndWithIdentifierTest.java:30: error: malformed HTML
EndWithIdentifierTest.java:34: error: malformed HTML
/**<a name*/
^
6 errors

View File

@ -41,7 +41,7 @@ import java.util.function.Function;
*/
public final class LambdaTest
{
/** */ LambdaTest() { }
/** . */ LambdaTest() { }
/**
* The field itself has docs.

View File

@ -7,7 +7,7 @@
* @run main DocLintTester -ref LiteralTest.out LiteralTest.java
*/
/** */
/** . */
public class LiteralTest {
/** <code> abc {@literal < & > } def </code> */
public void ok_literal_in_code() { }
@ -15,6 +15,6 @@ public class LiteralTest {
/** <code> abc {@code < & > } def </code> */
public void bad_code_in_code() { }
/** */
/** . */
LiteralTest() { }
}

View File

@ -10,15 +10,15 @@
/** . */
public class MissingParamsTest {
/** */
/** . */
MissingParamsTest(int param) { }
/** */
/** . */
<T> MissingParamsTest() { }
/** */
/** . */
void missingParam(int param) { }
/** */
/** . */
<T> void missingTyparam() { }
}

View File

@ -19,6 +19,6 @@ public class MissingReturnTest {
/** no return required */
Void return_Void() { }
/** */
/** . */
int missingReturn() { }
}

View File

@ -8,11 +8,11 @@
* @run main DocLintTester -Xmsgs:missing -ref MissingThrowsTest.out MissingThrowsTest.java
*/
/** */
/** . */
public class MissingThrowsTest {
/** */
/** . */
void missingThrows() throws Exception { }
/** */
/** . */
MissingThrowsTest() { }
}

View File

@ -7,9 +7,12 @@
/** <html> */
public class MultipleDocLintOptionsTest {
/** @return */
/**
* .
* @return
*/
int emptyReturn() { return -1; }
/** */
/** . */
MultipleDocLintOptionsTest() { }
}

View File

@ -1,5 +1,5 @@
MultipleDocLintOptionsTest.java:8:5: compiler.err.proc.messager: element not allowed in documentation comments: <html>
MultipleDocLintOptionsTest.java:8:5: compiler.err.proc.messager: element not closed: html
MultipleDocLintOptionsTest.java:10:9: compiler.warn.proc.messager: no description for @return
MultipleDocLintOptionsTest.java:12:8: compiler.warn.proc.messager: no description for @return
2 errors
1 warning

View File

@ -8,49 +8,58 @@
* @run main DocLintTester -ref ReferenceTest.out ReferenceTest.java
*/
/** */
/** . */
public class ReferenceTest {
/**
* .
* @param x description
*/
public int invalid_param;
/**
* .
* @param x description
*/
public class InvalidParam { /** . */ private InvalidParam() { } }
/**
* .
* @param x description
*/
public void param_name_not_found(int a) { }
/**
* .
* @param <X> description
*/
public class typaram_name_not_found { /** . */ private typaram_name_not_found() { } }
/**
* .
* @see Object#tooStrong()
*/
public void ref_not_found() { }
/**
* .
* @return x description
*/
public int invalid_return;
/**
* .
* @return x description
*/
public void invalid_return();
/**
* .
* @throws Exception description
*/
public void exception_not_thrown() { }
/**
* .
* @param <T> throwable
* @throws T description
*/

View File

@ -1,40 +1,40 @@
ReferenceTest.java:14: error: invalid use of @param
ReferenceTest.java:15: error: invalid use of @param
* @param x description
^
ReferenceTest.java:19: error: invalid use of @param
ReferenceTest.java:21: error: invalid use of @param
* @param x description
^
ReferenceTest.java:24: error: @param name not found
ReferenceTest.java:27: error: @param name not found
* @param x description
^
ReferenceTest.java:26: warning: no @param for a
ReferenceTest.java:29: warning: no @param for a
public void param_name_not_found(int a) { }
^
ReferenceTest.java:29: error: @param name not found
ReferenceTest.java:33: error: @param name not found
* @param <X> description
^
ReferenceTest.java:34: error: reference not found
ReferenceTest.java:39: error: reference not found
* @see Object#tooStrong()
^
ReferenceTest.java:39: error: invalid use of @return
ReferenceTest.java:45: error: invalid use of @return
* @return x description
^
ReferenceTest.java:44: error: invalid use of @return
ReferenceTest.java:51: error: invalid use of @return
* @return x description
^
ReferenceTest.java:49: error: exception not thrown: java.lang.Exception
ReferenceTest.java:57: error: exception not thrown: java.lang.Exception
* @throws Exception description
^
ReferenceTest.java:62: error: reference not found
ReferenceTest.java:71: error: reference not found
* {@link not.Found<String>}
^
ReferenceTest.java:65: error: reference not found
ReferenceTest.java:74: error: reference not found
* @see not.Found<String>
^
ReferenceTest.java:72: error: reference not found
ReferenceTest.java:81: error: reference not found
* {@link not.Found[]}
^
ReferenceTest.java:75: error: reference not found
ReferenceTest.java:84: error: reference not found
* @see not.Found[]
^
12 errors

View File

@ -8,14 +8,14 @@
* @run main DocLintTester -ref SyntaxTest.out SyntaxTest.java
*/
/** */
/** . */
public class SyntaxTest {
/**
* a < b
*/
public void syntax_error() { }
/** */
/** . */
private SyntaxTest() { }
}

View File

@ -12,8 +12,8 @@
/** Unexpected comment */
package bad;
/** */
/** . */
class Test {
/** */ Test() { }
/** . */ Test() { }
}

View File

@ -18,5 +18,5 @@ public class StatsTest {
/** 4 undocumented signature items */
public int warnings(int a1, int a2) throws Exception { return 0; }
/** */ StatsTest() { }
/** . */ StatsTest() { }
}

View File

@ -62,27 +62,29 @@ public class DocLintTest {
JavaFileObject file;
final String code =
/* 01 */ "/** Class comment. */\n" +
/* 02 */ "public class Test { /** */ Test() { }\n" +
/* 03 */ " /** Method comment. */\n" +
/* 04 */ " public void method() { }\n" +
/* 05 */ "\n" +
/* 06 */ " /** Syntax < error. */\n" +
/* 07 */ " private void syntaxError() { }\n" +
/* 08 */ "\n" +
/* 09 */ " /** @see DoesNotExist */\n" +
/* 10 */ " protected void referenceError() { }\n" +
/* 08 */ "\n" +
/* 09 */ " /** @return */\n" +
/* 10 */ " public int emptyReturn() { return 0; }\n" +
/* 11 */ "}\n";
/* 01 */ "/** Class comment. */\n" +
/* 02 */ "public class Test { /** Constructor comment. */ Test() { }\n" +
/* 03 */ " /** Method comment. */\n" +
/* 04 */ " public void method() { }\n" +
/* 05 */ "\n" +
/* 06 */ " /** Syntax < error. */\n" +
/* 07 */ " private void syntaxError() { }\n" +
/* 08 */ "\n" +
/* 09 */ " /** Description. \n" +
/* 10 */ " * @see DoesNotExist */\n" +
/* 11 */ " protected void referenceError() { }\n" +
/* 12 */ "\n" +
/* 13 */ " /** Description. \n" +
/* 14 */ " * @return */\n" +
/* 15 */ " public int emptyReturn() { return 0; }\n" +
/* 16 */ "}\n";
final String rawDiags = "-XDrawDiagnostics";
private enum Message {
// doclint messages
DL_ERR6(ERROR, "Test.java:6:16: compiler.err.proc.messager: malformed HTML"),
DL_ERR9(ERROR, "Test.java:9:14: compiler.err.proc.messager: reference not found"),
DL_WRN12(WARNING, "Test.java:12:9: compiler.warn.proc.messager: no description for @return"),
DL_ERR10(ERROR, "Test.java:10:13: compiler.err.proc.messager: reference not found"),
DL_WRN14(WARNING, "Test.java:14:8: compiler.warn.proc.messager: no description for @return"),
OPT_BADARG(ERROR, "error: invalid flag: -Xdoclint:badarg");
@ -129,19 +131,19 @@ public class DocLintTest {
test(Arrays.asList(rawDiags, "-Xdoclint"),
Main.Result.ERROR,
EnumSet.of(Message.DL_ERR6, Message.DL_ERR9, Message.DL_WRN12));
EnumSet.of(Message.DL_ERR6, Message.DL_ERR10, Message.DL_WRN14));
test(Arrays.asList(rawDiags, "-Xdoclint:all/public"),
Main.Result.OK,
EnumSet.of(Message.DL_WRN12));
EnumSet.of(Message.DL_WRN14));
test(Arrays.asList(rawDiags, "-Xdoclint:syntax,missing"),
Main.Result.ERROR,
EnumSet.of(Message.DL_ERR6, Message.DL_WRN12));
EnumSet.of(Message.DL_ERR6, Message.DL_WRN14));
test(Arrays.asList(rawDiags, "-Xdoclint:reference"),
Main.Result.ERROR,
EnumSet.of(Message.DL_ERR9));
EnumSet.of(Message.DL_ERR10));
test(Arrays.asList(rawDiags, "-Xdoclint:badarg"),
Main.Result.CMDERR,