001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2022 the original author or authors. 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018/////////////////////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle.checks.javadoc; 021 022import java.util.Set; 023 024import com.puppycrawl.tools.checkstyle.StatelessCheck; 025import com.puppycrawl.tools.checkstyle.api.AbstractCheck; 026import com.puppycrawl.tools.checkstyle.api.DetailAST; 027import com.puppycrawl.tools.checkstyle.api.FileContents; 028import com.puppycrawl.tools.checkstyle.api.Scope; 029import com.puppycrawl.tools.checkstyle.api.TextBlock; 030import com.puppycrawl.tools.checkstyle.api.TokenTypes; 031import com.puppycrawl.tools.checkstyle.utils.AnnotationUtil; 032import com.puppycrawl.tools.checkstyle.utils.CommonUtil; 033import com.puppycrawl.tools.checkstyle.utils.ScopeUtil; 034 035/** 036 * <p> 037 * Checks for missing Javadoc comments for class, enum, interface, and annotation interface 038 * definitions. The scope to verify is specified using the {@code Scope} class and defaults 039 * to {@code Scope.PUBLIC}. To verify another scope, set property scope to one of the 040 * {@code Scope} constants. 041 * </p> 042 * <ul> 043 * <li> 044 * Property {@code scope} - specify the visibility scope where Javadoc comments are checked. 045 * Type is {@code com.puppycrawl.tools.checkstyle.api.Scope}. 046 * Default value is {@code public}. 047 * </li> 048 * <li> 049 * Property {@code excludeScope} - specify the visibility scope where Javadoc comments are not 050 * checked. 051 * Type is {@code com.puppycrawl.tools.checkstyle.api.Scope}. 052 * Default value is {@code null}. 053 * </li> 054 * <li> 055 * Property {@code skipAnnotations} - specify annotations that allow missed 056 * documentation. If annotation is present in target sources in multiple forms of qualified 057 * name, all forms should be listed in this property. 058 * Type is {@code java.lang.String[]}. 059 * Default value is {@code Generated}. 060 * </li> 061 * <li> 062 * Property {@code tokens} - tokens to check 063 * Type is {@code java.lang.String[]}. 064 * Validation type is {@code tokenSet}. 065 * Default value is: 066 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INTERFACE_DEF"> 067 * INTERFACE_DEF</a>, 068 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CLASS_DEF"> 069 * CLASS_DEF</a>, 070 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_DEF"> 071 * ENUM_DEF</a>, 072 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ANNOTATION_DEF"> 073 * ANNOTATION_DEF</a>, 074 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#RECORD_DEF"> 075 * RECORD_DEF</a>. 076 * </li> 077 * </ul> 078 * <p> 079 * To configure the default check to make sure all public class, enum, interface, and annotation 080 * interface, definitions have javadocs: 081 * </p> 082 * <pre> 083 * <module name="MissingJavadocType"/> 084 * </pre> 085 * <p> 086 * Example: 087 * </p> 088 * <pre> 089 * public class PublicClass {} // violation 090 * private class PublicClass {} 091 * protected class PublicClass {} 092 * class PackagePrivateClass {} 093 * </pre> 094 * <p> 095 * To configure the check for {@code private} scope: 096 * </p> 097 * <pre> 098 * <module name="MissingJavadocType"> 099 * <property name="scope" value="private"/> 100 * </module> 101 * </pre> 102 * <p> 103 * Example: 104 * </p> 105 * <pre> 106 * public class PublicClass {} // violation 107 * private class PublicClass {} // violation 108 * protected class PublicClass {} // violation 109 * class PackagePrivateClass {} // violation 110 * </pre> 111 * <p> 112 * To configure the check for {@code private} classes only: 113 * </p> 114 * <pre> 115 * <module name="MissingJavadocType"> 116 * <property name="scope" value="private"/> 117 * <property name="excludeScope" value="package"/> 118 * </module> 119 * </pre> 120 * <p> 121 * Example: 122 * </p> 123 * <pre> 124 * public class PublicClass {} 125 * private class PublicClass {} // violation 126 * protected class PublicClass {} 127 * class PackagePrivateClass {} 128 * </pre> 129 * <p> 130 * To configure a check that allows missing comments for classes annotated 131 * with {@code @SpringBootApplication} and {@code @Configuration}: 132 * </p> 133 * <pre> 134 * <module name="MissingJavadocType"> 135 * <property name="skipAnnotations" value="SpringBootApplication,Configuration"/> 136 * </module> 137 * </pre> 138 * <p> 139 * Example: 140 * </p> 141 * <pre> 142 * @SpringBootApplication // no violations about missing comment on class 143 * public class Application {} 144 * 145 * @Configuration // no violations about missing comment on class 146 * class DatabaseConfiguration {} 147 * </pre> 148 * <p> 149 * To configure a check that allows missing comments for classes annotated with {@code @Annotation} 150 * and {@code @MyClass.Annotation}: 151 * </p> 152 * <pre> 153 * <module name="MissingJavadocType"> 154 * <property name="skipAnnotations" value="Annotation,MyClass.Annotation"/> 155 * </module> 156 * </pre> 157 * <p> 158 * Example: 159 * </p> 160 * <pre> 161 * @Annotation // ok 162 * class Class1 {} 163 * 164 * @MyClass.Annotation // ok 165 * class Class2 {} 166 * 167 * @com.mycompany.MyClass.Annotation // violation, as this form is missed in config 168 * class Class3 {} 169 * </pre> 170 * <p> 171 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} 172 * </p> 173 * <p> 174 * Violation Message Keys: 175 * </p> 176 * <ul> 177 * <li> 178 * {@code javadoc.missing} 179 * </li> 180 * </ul> 181 * 182 * @since 8.20 183 */ 184@StatelessCheck 185public class MissingJavadocTypeCheck extends AbstractCheck { 186 187 /** 188 * A key is pointing to the warning message text in "messages.properties" 189 * file. 190 */ 191 public static final String MSG_JAVADOC_MISSING = "javadoc.missing"; 192 193 /** Specify the visibility scope where Javadoc comments are checked. */ 194 private Scope scope = Scope.PUBLIC; 195 /** Specify the visibility scope where Javadoc comments are not checked. */ 196 private Scope excludeScope; 197 198 /** 199 * Specify annotations that allow missed documentation. 200 * If annotation is present in target sources in multiple forms of qualified 201 * name, all forms should be listed in this property. 202 */ 203 private Set<String> skipAnnotations = Set.of("Generated"); 204 205 /** 206 * Setter to specify the visibility scope where Javadoc comments are checked. 207 * 208 * @param scope a scope. 209 */ 210 public void setScope(Scope scope) { 211 this.scope = scope; 212 } 213 214 /** 215 * Setter to specify the visibility scope where Javadoc comments are not checked. 216 * 217 * @param excludeScope a scope. 218 */ 219 public void setExcludeScope(Scope excludeScope) { 220 this.excludeScope = excludeScope; 221 } 222 223 /** 224 * Setter to specify annotations that allow missed documentation. 225 * If annotation is present in target sources in multiple forms of qualified 226 * name, all forms should be listed in this property. 227 * 228 * @param userAnnotations user's value. 229 */ 230 public void setSkipAnnotations(String... userAnnotations) { 231 skipAnnotations = Set.of(userAnnotations); 232 } 233 234 @Override 235 public int[] getDefaultTokens() { 236 return getAcceptableTokens(); 237 } 238 239 @Override 240 public int[] getAcceptableTokens() { 241 return new int[] { 242 TokenTypes.INTERFACE_DEF, 243 TokenTypes.CLASS_DEF, 244 TokenTypes.ENUM_DEF, 245 TokenTypes.ANNOTATION_DEF, 246 TokenTypes.RECORD_DEF, 247 }; 248 } 249 250 @Override 251 public int[] getRequiredTokens() { 252 return CommonUtil.EMPTY_INT_ARRAY; 253 } 254 255 // suppress deprecation until https://github.com/checkstyle/checkstyle/issues/11166 256 @SuppressWarnings("deprecation") 257 @Override 258 public void visitToken(DetailAST ast) { 259 if (shouldCheck(ast)) { 260 final FileContents contents = getFileContents(); 261 final int lineNo = ast.getLineNo(); 262 final TextBlock textBlock = contents.getJavadocBefore(lineNo); 263 if (textBlock == null) { 264 log(ast, MSG_JAVADOC_MISSING); 265 } 266 } 267 } 268 269 /** 270 * Whether we should check this node. 271 * 272 * @param ast a given node. 273 * @return whether we should check a given node. 274 */ 275 private boolean shouldCheck(final DetailAST ast) { 276 final Scope customScope = ScopeUtil.getScope(ast); 277 final Scope surroundingScope = ScopeUtil.getSurroundingScope(ast); 278 279 return customScope.isIn(scope) 280 && (surroundingScope == null || surroundingScope.isIn(scope)) 281 && (excludeScope == null 282 || !customScope.isIn(excludeScope) 283 || surroundingScope != null 284 && !surroundingScope.isIn(excludeScope)) 285 && !AnnotationUtil.containsAnnotation(ast, skipAnnotations); 286 } 287 288}