diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 7dcc6c4..ac16f64 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -9,7 +9,7 @@ jobs: strategy: matrix: - java: [ '11', '17', '20' ] + java: [ '8', '11', '17', '21', '23-ea' ] steps: - uses: actions/checkout@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index af0e583..6f0bc26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,22 @@ ## 2.0.0 (2023-??-??) -Java 11 or later is required. +Java 11 or later is required to run require-javadoc. + +## 1.0.9 (2024-03-28) + +Don't require documentation on record parameters (fields), because Javadoc +requires `@param` tags in the Javadoc for the record. + +## 1.0.8 (2024-03-27) + +Bugfix: reinstate support for compiling and running under JDK 8. + +## 1.0.7 (2024-03-26) + +Support Java 17 syntax. + +Support compiling and running under JDK 21. ## 1.0.6 (2022-12-02) diff --git a/README.md b/README.md index 68d693e..e59ef18 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # require-javadoc -This program requires that a Javadoc comment be present on +This program requires that a Javadoc comment is present on every Java class, constructor, method, and field. It does not require a Javadoc comment on methods with an `@Override` annotation, nor on fields named `serialVersionUID`. @@ -92,7 +92,7 @@ which is part of the [plume-scripts package](https://github.com/plume-lib/plume- if [ -d "/tmp/$USER/plume-scripts" ] ; then git -C /tmp/$USER/plume-scripts pull -q 2>&1 else - mkdir -p /tmp/$USER && git -C /tmp/$USER/ clone --filter=blob:none -q https://github.com/plume-lib/plume-scripts.git + mkdir -p /tmp/$USER && git -C /tmp/$USER/ clone --depth=1 -q https://github.com/plume-lib/plume-scripts.git fi (./gradlew requireJavadoc > /tmp/warnings.txt 2>&1) || true /tmp/$USER/plume-scripts/ci-lint-diff /tmp/warnings.txt @@ -108,7 +108,7 @@ configurations { requireJavadoc } dependencies { - requireJavadoc "org.plumelib:require-javadoc:1.0.6" + requireJavadoc "org.plumelib:require-javadoc:1.0.9" } task requireJavadoc(type: JavaExec) { group = 'Documentation' @@ -150,7 +150,7 @@ Therefore, you may want to use all three. * Starting in JDK 18, `javadoc -Xdoclint:all` produces error messages about missing Javadoc comments. This reduces the need for the `require-javadoc` program. The require-javadoc program is still useful for people who: - * are using JDK 17 or earlier + * are using JDK 17 or earlier, or * desire finer-grained control over which program elements must be documented. `-Xdoclint` provides [only](https://docs.oracle.com/en/java/javase/17/docs/specs/man/javadoc.html#additional-options-provided-by-the-standard-doclet) diff --git a/build.gradle b/build.gradle index 45c4b46..58c70d6 100644 --- a/build.gradle +++ b/build.gradle @@ -3,29 +3,47 @@ plugins { id 'application' // To create a fat jar build/libs/...-all.jar, run: ./gradlew shadowJar - id 'com.github.johnrengelman.shadow' version '8.1.1' + id 'com.gradleup.shadow' version '8.3.5' // Code formatting; defines targets "spotlessApply" and "spotlessCheck" - // Requires JDK 11 or higher; the plugin crashes under JDK 8. - id 'com.diffplug.spotless' version '6.25.0' + // Version 6.14.0 and later requires JRE 11+, but version 6.13.0 doesn't work on JRE 21. + id 'com.diffplug.spotless' version '6.13.0' // Error Prone linter - id('net.ltgt.errorprone') version '3.1.0' + // TODO: Java 23: remove "apply false". + id('net.ltgt.errorprone') version '4.1.0' apply false // Checker Framework pluggable type-checking - id 'org.checkerframework' version '0.6.37' + id 'org.checkerframework' version '0.6.45' +} + +// TODO: Java 23: remove this code block. +if (JavaVersion.current() <= JavaVersion.VERSION_22) { + apply plugin: 'net.ltgt.errorprone' +} + +// TODO: Java 23: remove this code block. +if (JavaVersion.current() <= JavaVersion.VERSION_22) { + apply plugin: 'net.ltgt.errorprone' } repositories { + mavenLocal() mavenCentral() maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } } +ext { + errorproneVersion = '2.36.0' + isJava17orHigher = JavaVersion.current() >= JavaVersion.VERSION_17 + isJava21orHigher = JavaVersion.current() >= JavaVersion.VERSION_21 +} + dependencies { - implementation 'com.github.javaparser:javaparser-core:3.25.8' + implementation 'com.github.javaparser:javaparser-core:3.26.3' implementation 'org.plumelib:options:2.0.3' implementation 'org.plumelib:plume-util:1.9.0' - implementation 'com.google.code.gson:gson:2.10.1' + implementation 'com.google.code.gson:gson:2.11.0' } // To upload to Maven Central, see instructions in the file. @@ -41,52 +59,63 @@ compileJava { options.compilerArgs += '--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED' } -sourceCompatibility = 11 -targetCompatibility = 11 +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} -spotless { - format 'misc', { - // define the files to apply `misc` to - target '*.md', '.gitignore' +// TODO: Why is this condition needed? +if (! isJava21orHigher) { + spotless { + format 'misc', { + // define the files to apply `misc` to + target '*.md', '.gitignore' - // define the steps to apply to those files - trimTrailingWhitespace() - indentWithSpaces(2) - endWithNewline() - } - java { - targetExclude('**/WeakIdentityHashMap.java') - googleJavaFormat() - formatAnnotations() - } - groovyGradle { - target '**/*.gradle' - greclipse() // which formatter Spotless should use to format .gradle files. - indentWithSpaces(2) - trimTrailingWhitespace() - // endWithNewline() // Don't want to end empty files with a newline + // define the steps to apply to those files + trimTrailingWhitespace() + indentWithSpaces(2) + endWithNewline() + } + java { + targetExclude('**/WeakIdentityHashMap.java') + googleJavaFormat() + formatAnnotations() + } + groovyGradle { + target '**/*.gradle' + greclipse() // which formatter Spotless should use to format .gradle files. + indentWithSpaces(2) + trimTrailingWhitespace() + // endWithNewline() // Don't want to end empty files with a newline + } } } -/// Error Prone linter +// Error Prone linter -dependencies { - errorprone('com.google.errorprone:error_prone_core:2.25.0') -} -tasks.withType(JavaCompile).configureEach { - // "-processing" avoids javac warning "No processor claimed any of these annotations". - options.compilerArgs << '-Xlint:all,-processing' << '-Werror' - // Only needed when debugging. - options.compilerArgs << '-g' - options.errorprone { - // disable('ReferenceEquality') // Use Interning Checker instead. - // disable('StringSplitter') // Obscure case isn't likely. - // disable('AnnotateFormatMethod') // Error Prone doesn't know about Checker Framework @FormatMethod +// TODO: Java 23: remove the "if" line" and corresponding "}" +if (JavaVersion.current() <= JavaVersion.VERSION_22) { + dependencies { + errorprone("com.google.errorprone:error_prone_core:${errorproneVersion}") + } + tasks.withType(JavaCompile).configureEach { + // "-processing" avoids javac warning "No processor claimed any of these annotations". + // "-Xlint:-options" is because of JDK 21 warning "source value 8 is obsolete..." + options.compilerArgs << '-Xlint:all,-processing,-options' << '-Werror' + // Only needed when debugging. + options.compilerArgs << '-g' + options.errorprone { + // ExtendsObject does not yet exist in Error Prone 2.10.0. + // disable('ExtendsObject') // Incorrect when using the Checker Framework + disable('ReferenceEquality') // Use Interning Checker instead. + disable('AnnotateFormatMethod') // Error Prone doesn't know about Checker Framework @FormatMethod + } + options.errorprone.enabled = isJava17orHigher } } -/// Checker Framework pluggable type-checking +// Checker Framework pluggable type-checking apply plugin: 'org.checkerframework' @@ -106,21 +135,27 @@ checkerFramework { 'org.checkerframework.common.initializedfields.InitializedFieldsChecker', ] extraJavacArgs = [ - '-Werror', + // No "'-Werror'" because of JDK 21 warning "source value 8 is obsolete..." + // '-Werror', '-AcheckPurityAnnotations', '-ArequirePrefixInWarningSuppressions', '-AwarnRedundantAnnotations', '-AwarnUnneededSuppressions', ] } - -ext.checkerFrameworkVersion = '3.43.0-SNAPSHOT' -dependencies { - compileOnly "org.checkerframework:checker-qual:${checkerFrameworkVersion}" - testCompileOnly "org.checkerframework:checker-qual:${checkerFrameworkVersion}" - checkerFramework "org.checkerframework:checker:${checkerFrameworkVersion}" +// To use a snapshot version of the Checker Framework. +if (false) { + // TODO: Change the above test to false when CF is released. + ext.checkerFrameworkVersion = '3.48.4' + dependencies { + compileOnly "org.checkerframework:checker-qual:${checkerFrameworkVersion}" + testCompileOnly "org.checkerframework:checker-qual:${checkerFrameworkVersion}" + checkerFramework "org.checkerframework:checker:${checkerFrameworkVersion}" + } + configurations.all { + resolutionStrategy.cacheChangingModulesFor 0, 'minutes' + } } - // To use a locally-built Checker Framework, run gradle with "-PcfLocal". if (project.hasProperty('cfLocal')) { def cfHome = String.valueOf(System.getenv('CHECKERFRAMEWORK')) @@ -130,12 +165,20 @@ if (project.hasProperty('cfLocal')) { checkerFramework files(cfHome + '/checker/dist/checker.jar') } } +// TODO: Java 23: remove this block. +if (JavaVersion.current() > JavaVersion.VERSION_22) { + checkerFramework { + skipCheckerFramework = true + } +} -/// Javadoc +// Javadoc // Turn Javadoc warnings into errors. javadoc { - options.addStringOption('Xwerror', '-Xdoclint:all') + // No "'-Werror'" because of JDK 21 warning "source value 8 is obsolete..." + // options.addStringOption('Xwerror', '-Xdoclint:all') + options.addStringOption('Xdoclint:all', '-quiet') options.addStringOption('private', '-quiet') options.addStringOption('source', '11') // Buggy per https://github.com/java9-modularity/gradle-modules-plugin/issues/170 @@ -168,12 +211,19 @@ task javadocWeb(type: Javadoc) { source = sourceSets.main.allJava destinationDir = file("/cse/web/research/plumelib/${project.name}/api") classpath = project.sourceSets.main.compileClasspath - options.addStringOption('source', '11') + options.addStringOption('source', '8') doLast { ant.replaceregexp(match:"@import url\\('resources/fonts/dejavu.css'\\);\\s*", replace:'', flags:'g', byline:true) { fileset(dir: destinationDir) } + // Set permissions + project.exec { + commandLine('chgrp', '-R', 'plse_www', "/cse/web/research/plumelib/${project.name}/api") + } + project.exec { + commandLine('chmod', '-R', 'g+w', "/cse/web/research/plumelib/${project.name}/api") + } } } @@ -182,13 +232,14 @@ configurations { requireJavadoc } dependencies { - requireJavadoc 'org.plumelib:require-javadoc:1.0.6' + requireJavadoc 'org.plumelib:require-javadoc:1.0.9' } task requireJavadoc(type: JavaExec) { // "dependsOn jar" because this is the requireJavadoc project itself, and // Gradle uses the built-from-source version of // 'org.plumelib:require-javadoc'. So declare a dependency on it. dependsOn jar + group = 'Documentation' description = 'Ensures that Javadoc documentation exists.' mainClass = 'org.plumelib.javadoc.RequireJavadoc' classpath = configurations.requireJavadoc @@ -196,7 +247,7 @@ task requireJavadoc(type: JavaExec) { } check.dependsOn requireJavadoc -/// Emacs support +// Emacs support /* Make Emacs TAGS table */ task tags(type: Exec) { diff --git a/gradle/mavencentral.gradle b/gradle/mavencentral.gradle index 8065602..1ccc8e1 100644 --- a/gradle/mavencentral.gradle +++ b/gradle/mavencentral.gradle @@ -1,9 +1,9 @@ -// REQUIREMENTS to make a release: + // REQUIREMENTS to make a release: // * Your ~/.gradle/gradle.properties file must contain: -// ossrhUsername=YOUR_USER_NAME_HERE -// ossrhPassword=YOUR_PASSWORD_HERE +// SONATYPE_NEXUS_USERNAME=... +// SONATYPE_NEXUS_PASSWORD=... -// To make a release (run on any filesystem, except the last step): +// To make a release (run on any filesystem, except the `javadocWeb` step): // * git pull // * In ../build.gradle, ensure that "To use a snapshot version" is not enabled. // * Update the version number in ../README.md and in this file (multiple times in each). @@ -14,15 +14,18 @@ // * Run in the top-level directory: ./gradlew clean publish // * Browse to https://oss.sonatype.org/#stagingRepositories, complete the Maven Central release. // * Add a git tag: -// VER=1.0.6 && git commit -m "Version $VER" && git push && git tag -a v$VER -m "Version $VER" && git push && git push --tags -// * Make a GitHub release. Go to the GitHub releases page, make a release, call it "require-javadoc 1.0.6", use the text from ../CHANGELOG.md as the description, attach the .jar and -all.jar files from ../build/libs/ . +// VER=1.0.9 && git commit -m "Version $VER" && git push && git tag -a v$VER -m "Version $VER" && git push && git push --tags +// * Make a GitHub release. Go to the GitHub releases page, make a release, call it "require-javadoc 1.0.9", use the text from ../CHANGELOG.md as the description, attach the .jar and -all.jar files from ../build/libs/ . // * Finally, run on the CSE filesystem: git pull && ./gradlew javadocWeb apply plugin: 'maven-publish' apply plugin: 'signing' -group "org.plumelib" -version "1.0.6" +group 'org.plumelib' +version '1.0.9' +ext { + packageName = 'require-javadoc' +} final isSnapshot = version.contains('SNAPSHOT') @@ -43,12 +46,12 @@ publishing { pom { name = 'Require-Javadoc' description = 'Require Javadoc comments to be present.' - url = 'https://github.com/plume-lib/require-javadoc' + url = "https://github.com/plume-lib/${packageName}" scm { - connection = 'scm:git:git@github.com:plume-lib/require-javadoc.git' - developerConnection = 'scm:git:git@github.com:plume-lib/require-javadoc.git' - url = 'git@github.com:plume-lib/require-javadoc.git' + connection = "scm:git:git@github.com:plume-lib/${packageName}.git" + developerConnection = "scm:git:git@github.com:plume-lib/${packageName}.git" + url = "git@github.com:plume-lib/${packageName}.git" } licenses { @@ -76,8 +79,8 @@ publishing { : project.properties.getOrDefault('RELEASE_REPOSITORY_URL', 'https://oss.sonatype.org/service/local/staging/deploy/maven2/') ) credentials { - username = project.properties.get('ossrhUsername') - password = project.properties.get('ossrhPassword') + username = project.properties.get('SONATYPE_NEXUS_USERNAME') + password = project.properties.get('SONATYPE_NEXUS_PASSWORD') } } } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd49..a4b76b9 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a80b22c..cea7a79 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a4..f3b75f3 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 6689b85..9b42019 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/settings.gradle b/settings.gradle index 686fbd3..0cf51e3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,8 +1,8 @@ -buildscript { - if (JavaVersion.current() == JavaVersion.VERSION_1_8) { - throw new Error("Use Java 11 or later.") - } -} +// buildscript { +// if (JavaVersion.current() == JavaVersion.VERSION_1_8) { +// throw new Error("Use Java 11 or later.") +// } +// } // Project name is read-only in build scripts, and defaults to directory name. rootProject.name = 'require-javadoc' diff --git a/src/main/java/org/plumelib/javadoc/RequireJavadoc.java b/src/main/java/org/plumelib/javadoc/RequireJavadoc.java index 2c11df7..430e3e6 100644 --- a/src/main/java/org/plumelib/javadoc/RequireJavadoc.java +++ b/src/main/java/org/plumelib/javadoc/RequireJavadoc.java @@ -3,6 +3,7 @@ import static com.github.javaparser.utils.PositionUtils.sortByBeginPosition; import com.github.javaparser.ParseProblemException; +import com.github.javaparser.ParserConfiguration; import com.github.javaparser.Position; import com.github.javaparser.Range; import com.github.javaparser.StaticJavaParser; @@ -19,6 +20,7 @@ import com.github.javaparser.ast.body.FieldDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.Parameter; +import com.github.javaparser.ast.body.RecordDeclaration; import com.github.javaparser.ast.body.VariableDeclarator; import com.github.javaparser.ast.comments.Comment; import com.github.javaparser.ast.expr.AnnotationExpr; @@ -126,7 +128,7 @@ public class RequireJavadoc { @Option("Don't report problems in trivial getters and setters") public boolean dont_require_trivial_properties; - /** If true, don't check type declarations: classes, interfaces, enums, annotations. */ + /** If true, don't check type declarations: classes, interfaces, enums, annotations, records. */ @Option("Don't report problems in type declarations") public boolean dont_require_type; @@ -185,6 +187,9 @@ public static void main(String[] args) { System.out.println("Checking " + javaFile); } try { + ParserConfiguration parserConfiguration = new ParserConfiguration(); + parserConfiguration.setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_17); + StaticJavaParser.setConfiguration(parserConfiguration); CompilationUnit cu = StaticJavaParser.parse(javaFile); RequireJavadocVisitor visitor = rj.new RequireJavadocVisitor(javaFile); visitor.visit(cu, null); @@ -210,7 +215,11 @@ private RequireJavadoc() {} * * @param args the directories and files listed on the command line */ - @SuppressWarnings("lock:type.arguments.not.inferred") // no locking here + @SuppressWarnings({ + "lock:unneeded.suppression", // TEMPORARY, until a CF release is made + "lock:methodref.receiver", // Comparator.comparing + "lock:type.arguments.not.inferred" // Comparator.comparing + }) private void setJavaFiles(String[] args) { if (args.length == 0) { args = new String[] {workingDirAbsolute.toString()}; @@ -705,7 +714,7 @@ public void visit(CompilationUnit cu, Void ignore) { if (verbose) { System.out.printf("Visiting compilation unit%n"); } - super.visit(cu, ignore); + super.visit(cu, null); } @Override @@ -723,7 +732,7 @@ public void visit(ClassOrInterfaceDeclaration cd, Void ignore) { if (!dont_require_type && !hasJavadocComment(cd)) { errors.add(errorString(cd, name)); } - super.visit(cd, ignore); + super.visit(cd, null); } @Override @@ -744,7 +753,7 @@ public void visit(ConstructorDeclaration cd, Void ignore) { if (!dont_require_method && !hasJavadocComment(cd)) { errors.add(errorString(cd, name)); } - super.visit(cd, ignore); + super.visit(cd, null); } @Override @@ -768,7 +777,7 @@ public void visit(MethodDeclaration md, Void ignore) { if (!dont_require_method && !isOverride(md) && !hasJavadocComment(md)) { errors.add(errorString(md, name)); } - super.visit(md, ignore); + super.visit(md, null); } @Override @@ -797,7 +806,7 @@ public void visit(FieldDeclaration fd, Void ignore) { } } if (shouldRequire) { - super.visit(fd, ignore); + super.visit(fd, null); } } @@ -816,7 +825,7 @@ public void visit(EnumDeclaration ed, Void ignore) { if (!dont_require_type && !hasJavadocComment(ed)) { errors.add(errorString(ed, name)); } - super.visit(ed, ignore); + super.visit(ed, null); } @Override @@ -831,7 +840,7 @@ public void visit(EnumConstantDeclaration ecd, Void ignore) { if (!dont_require_field && !hasJavadocComment(ecd)) { errors.add(errorString(ecd, name)); } - super.visit(ecd, ignore); + super.visit(ecd, null); } @Override @@ -849,7 +858,7 @@ public void visit(AnnotationDeclaration ad, Void ignore) { if (!dont_require_type && !hasJavadocComment(ad)) { errors.add(errorString(ad, name)); } - super.visit(ad, ignore); + super.visit(ad, null); } @Override @@ -864,7 +873,27 @@ public void visit(AnnotationMemberDeclaration amd, Void ignore) { if (!dont_require_method && !hasJavadocComment(amd)) { errors.add(errorString(amd, name)); } - super.visit(amd, ignore); + super.visit(amd, null); + } + + @Override + public void visit(RecordDeclaration rd, Void ignore) { + if (dont_require_private && rd.isPrivate()) { + return; + } + String name = rd.getNameAsString(); + if (shouldNotRequire(name)) { + return; + } + if (verbose) { + System.out.printf("Visiting record %s%n", name); + } + if (!dont_require_type && !hasJavadocComment(rd)) { + errors.add(errorString(rd, name)); + } + // Don't warn about record parameters, because Javadoc requires @param for them in the record + // declaration itself. + super.visit(rd, null); } /** diff --git a/src/test/JavaRecords.java b/src/test/JavaRecords.java new file mode 100644 index 0000000..180672d --- /dev/null +++ b/src/test/JavaRecords.java @@ -0,0 +1,15 @@ +/** My record. */ +record MyRecord( + /** First field. */ + String first, + String second, + /** Third field. */ + String third) {} + +record MyOtherRecord( + /** First field. */ + String first, + /** First field. */ + String second) {} + +class Undocumented {} diff --git a/src/test/README b/src/test/README index b8d4a69..c460f70 100644 --- a/src/test/README +++ b/src/test/README @@ -2,6 +2,6 @@ Tests are not yet automated. :-( The diff output should be empty: -(cd ../.. && ./gradlew assemble) && java -cp ../../build/libs/require-javadoc-1.0.6-all.jar org.plumelib.javadoc.RequireJavadoc --relative --dont-require-trivial-properties --dont-require-noarg-constructor > out.txt +(cd ../.. && ./gradlew assemble) && sleep .1 && java -cp ../../build/libs/require-javadoc-1.0.9-all.jar org.plumelib.javadoc.RequireJavadoc --relative --dont-require-trivial-properties --dont-require-noarg-constructor > out.txt diff expected.txt out.txt diff --git a/src/test/expected.txt b/src/test/expected.txt index 691a1fb..0668216 100644 --- a/src/test/expected.txt +++ b/src/test/expected.txt @@ -1,3 +1,6 @@ +JavaRecords.java:5:5: missing documentation for second +JavaRecords.java:9:1: missing documentation for MyOtherRecord +JavaRecords.java:15:1: missing documentation for Undocumented NoArgConstructor.java:8:3: missing documentation for HasArgConstructor TrivialProperties.java:165:3: missing documentation for getFoo1 TrivialProperties.java:169:3: missing documentation for foo1