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