001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2020 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.Arrays; 023import java.util.Collections; 024import java.util.List; 025 026import com.puppycrawl.tools.checkstyle.StatelessCheck; 027import com.puppycrawl.tools.checkstyle.api.AbstractCheck; 028import com.puppycrawl.tools.checkstyle.api.DetailAST; 029import com.puppycrawl.tools.checkstyle.api.FileContents; 030import com.puppycrawl.tools.checkstyle.api.Scope; 031import com.puppycrawl.tools.checkstyle.api.TextBlock; 032import com.puppycrawl.tools.checkstyle.api.TokenTypes; 033import com.puppycrawl.tools.checkstyle.utils.AnnotationUtil; 034import com.puppycrawl.tools.checkstyle.utils.CommonUtil; 035import com.puppycrawl.tools.checkstyle.utils.ScopeUtil; 036 037/** 038 * <p> 039 * Checks for missing Javadoc comments for class, enum, interface, and annotation interface 040 * definitions. The scope to verify is specified using the {@code Scope} class and defaults 041 * to {@code Scope.PUBLIC}. To verify another scope, set property scope to one of the 042 * {@code Scope} constants. 043 * </p> 044 * <ul> 045 * <li> 046 * Property {@code scope} - specify the visibility scope where Javadoc comments are checked. 047 * Type is {@code com.puppycrawl.tools.checkstyle.api.Scope}. 048 * Default value is {@code public}. 049 * </li> 050 * <li> 051 * Property {@code excludeScope} - specify the visibility scope where Javadoc comments are not 052 * checked. 053 * Type is {@code com.puppycrawl.tools.checkstyle.api.Scope}. 054 * Default value is {@code null}. 055 * </li> 056 * <li> 057 * Property {@code skipAnnotations} - specify the list of annotations that allow missed 058 * documentation. Only short names are allowed, e.g. {@code Generated}. 059 * Type is {@code java.lang.String[]}. 060 * Default value is {@code Generated}. 061 * </li> 062 * <li> 063 * Property {@code tokens} - tokens to check 064 * Type is {@code java.lang.String[]}. 065 * Validation type is {@code tokenSet}. 066 * Default value is: 067 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INTERFACE_DEF"> 068 * INTERFACE_DEF</a>, 069 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CLASS_DEF"> 070 * CLASS_DEF</a>, 071 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_DEF"> 072 * ENUM_DEF</a>, 073 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ANNOTATION_DEF"> 074 * ANNOTATION_DEF</a>, 075 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#RECORD_DEF"> 076 * RECORD_DEF</a>. 077 * </li> 078 * </ul> 079 * <p> 080 * To configure the default check to make sure all public class, enum, interface, and annotation 081 * interface, definitions have javadocs: 082 * </p> 083 * <pre> 084 * <module name="MissingJavadocType"/> 085 * </pre> 086 * <p> 087 * Example: 088 * </p> 089 * <pre> 090 * public class PublicClass {} // violation 091 * private class PublicClass {} 092 * protected class PublicClass {} 093 * class PackagePrivateClass {} 094 * </pre> 095 * <p> 096 * To configure the check for {@code private} scope: 097 * </p> 098 * <pre> 099 * <module name="MissingJavadocType"> 100 * <property name="scope" value="private"/> 101 * </module> 102 * </pre> 103 * <p> 104 * Example: 105 * </p> 106 * <pre> 107 * public class PublicClass {} // violation 108 * private class PublicClass {} // violation 109 * protected class PublicClass {} // violation 110 * class PackagePrivateClass {} // violation 111 * </pre> 112 * <p> 113 * To configure the check for {@code private} classes only: 114 * </p> 115 * <pre> 116 * <module name="MissingJavadocType"> 117 * <property name="scope" value="private"/> 118 * <property name="excludeScope" value="package"/> 119 * </module> 120 * </pre> 121 * <p> 122 * Example: 123 * </p> 124 * <pre> 125 * public class PublicClass {} 126 * private class PublicClass {} // violation 127 * protected class PublicClass {} 128 * class PackagePrivateClass {} 129 * </pre> 130 * <p> 131 * Example that allows missing comments for classes annotated with {@code @SpringBootApplication} 132 * and {@code @Configuration}: 133 * </p> 134 * <pre> 135 * @SpringBootApplication // no violations about missing comment on class 136 * public class Application {} 137 * 138 * @Configuration // no violations about missing comment on class 139 * class DatabaseConfiguration {} 140 * </pre> 141 * <p> 142 * Use following configuration: 143 * </p> 144 * <pre> 145 * <module name="MissingJavadocType"> 146 * <property name="skipAnnotations" value="SpringBootApplication,Configuration"/> 147 * </module> 148 * </pre> 149 * <p> 150 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} 151 * </p> 152 * <p> 153 * Violation Message Keys: 154 * </p> 155 * <ul> 156 * <li> 157 * {@code javadoc.missing} 158 * </li> 159 * </ul> 160 * 161 * @since 8.20 162 */ 163@StatelessCheck 164public class MissingJavadocTypeCheck extends AbstractCheck { 165 166 /** 167 * A key is pointing to the warning message text in "messages.properties" 168 * file. 169 */ 170 public static final String MSG_JAVADOC_MISSING = "javadoc.missing"; 171 172 /** Specify the visibility scope where Javadoc comments are checked. */ 173 private Scope scope = Scope.PUBLIC; 174 /** Specify the visibility scope where Javadoc comments are not checked. */ 175 private Scope excludeScope; 176 177 /** 178 * Specify the list of annotations that allow missed documentation. 179 * Only short names are allowed, e.g. {@code Generated}. 180 */ 181 private List<String> skipAnnotations = Collections.singletonList("Generated"); 182 183 /** 184 * Setter to specify the visibility scope where Javadoc comments are checked. 185 * 186 * @param scope a scope. 187 */ 188 public void setScope(Scope scope) { 189 this.scope = scope; 190 } 191 192 /** 193 * Setter to specify the visibility scope where Javadoc comments are not checked. 194 * 195 * @param excludeScope a scope. 196 */ 197 public void setExcludeScope(Scope excludeScope) { 198 this.excludeScope = excludeScope; 199 } 200 201 /** 202 * Setter to specify the list of annotations that allow missed documentation. 203 * Only short names are allowed, e.g. {@code Generated}. 204 * 205 * @param userAnnotations user's value. 206 */ 207 public void setSkipAnnotations(String... userAnnotations) { 208 skipAnnotations = Arrays.asList(userAnnotations); 209 } 210 211 @Override 212 public int[] getDefaultTokens() { 213 return getAcceptableTokens(); 214 } 215 216 @Override 217 public int[] getAcceptableTokens() { 218 return new int[] { 219 TokenTypes.INTERFACE_DEF, 220 TokenTypes.CLASS_DEF, 221 TokenTypes.ENUM_DEF, 222 TokenTypes.ANNOTATION_DEF, 223 TokenTypes.RECORD_DEF, 224 }; 225 } 226 227 @Override 228 public int[] getRequiredTokens() { 229 return CommonUtil.EMPTY_INT_ARRAY; 230 } 231 232 @Override 233 public void visitToken(DetailAST ast) { 234 if (shouldCheck(ast)) { 235 final FileContents contents = getFileContents(); 236 final int lineNo = ast.getLineNo(); 237 final TextBlock textBlock = contents.getJavadocBefore(lineNo); 238 if (textBlock == null) { 239 log(ast, MSG_JAVADOC_MISSING); 240 } 241 } 242 } 243 244 /** 245 * Whether we should check this node. 246 * 247 * @param ast a given node. 248 * @return whether we should check a given node. 249 */ 250 private boolean shouldCheck(final DetailAST ast) { 251 final Scope customScope; 252 253 if (ScopeUtil.isInInterfaceOrAnnotationBlock(ast)) { 254 customScope = Scope.PUBLIC; 255 } 256 else { 257 final DetailAST mods = ast.findFirstToken(TokenTypes.MODIFIERS); 258 customScope = ScopeUtil.getScopeFromMods(mods); 259 } 260 final Scope surroundingScope = ScopeUtil.getSurroundingScope(ast); 261 262 return customScope.isIn(scope) 263 && (surroundingScope == null || surroundingScope.isIn(scope)) 264 && (excludeScope == null 265 || !customScope.isIn(excludeScope) 266 || surroundingScope != null 267 && !surroundingScope.isIn(excludeScope)) 268 && !AnnotationUtil.containsAnnotation(ast, skipAnnotations); 269 } 270 271}