1 //////////////////////////////////////////////////////////////////////////////// 2 // checkstyle: Checks Java source code for adherence to a set of rules. 3 // Copyright (C) 2001-2019 the original author or authors. 4 // 5 // This library is free software; you can redistribute it and/or 6 // modify it under the terms of the GNU Lesser General Public 7 // License as published by the Free Software Foundation; either 8 // version 2.1 of the License, or (at your option) any later version. 9 // 10 // This library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 // Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public 16 // License along with this library; if not, write to the Free Software 17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 //////////////////////////////////////////////////////////////////////////////// 19 20 package com.puppycrawl.tools.checkstyle.checks.javadoc; 21 22 import java.util.Arrays; 23 import java.util.Collections; 24 import java.util.List; 25 26 import com.puppycrawl.tools.checkstyle.StatelessCheck; 27 import com.puppycrawl.tools.checkstyle.api.AbstractCheck; 28 import com.puppycrawl.tools.checkstyle.api.DetailAST; 29 import com.puppycrawl.tools.checkstyle.api.FileContents; 30 import com.puppycrawl.tools.checkstyle.api.Scope; 31 import com.puppycrawl.tools.checkstyle.api.TextBlock; 32 import com.puppycrawl.tools.checkstyle.api.TokenTypes; 33 import com.puppycrawl.tools.checkstyle.utils.AnnotationUtil; 34 import com.puppycrawl.tools.checkstyle.utils.CommonUtil; 35 import com.puppycrawl.tools.checkstyle.utils.ScopeUtil; 36 37 /** 38 * <p> 39 * Checks for missing Javadoc comments for class, enum, interface, and annotation interface 40 * definitions. The scope to verify is specified using the {@code Scope} class and defaults 41 * to {@code Scope.PUBLIC}. To verify another scope, set property scope to one of the 42 * {@code Scope} constants. 43 * </p> 44 * <ul> 45 * <li> 46 * Property {@code scope} - specify the visibility scope where Javadoc comments are checked. 47 * Default value is {@code public}. 48 * </li> 49 * <li> 50 * Property {@code excludeScope} - specify the visibility scope where Javadoc comments are not 51 * checked. Default value is {@code null}. 52 * </li> 53 * <li> 54 * Property {@code skipAnnotations} - specify the list of annotations that allow missed 55 * documentation. Only short names are allowed, e.g. {@code Generated}. Default value is 56 * {@code Generated}. 57 * </li> 58 * <li> 59 * Property {@code tokens} - tokens to check Default value is: 60 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INTERFACE_DEF">INTERFACE_DEF</a>, 61 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CLASS_DEF">CLASS_DEF</a>, 62 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_DEF">ENUM_DEF</a>, 63 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ANNOTATION_DEF">ANNOTATION_DEF</a>. 64 * </li> 65 * </ul> 66 * <p> 67 * To configure the default check to make sure all public class, enum, interface, and annotation 68 * interface, definitions have javadocs: 69 * </p> 70 * <pre> 71 * <module name="MissingJavadocType"/> 72 * </pre> 73 * <p> 74 * Example: 75 * </p> 76 * <pre> 77 * public class PublicClass {} // violation 78 * private class PublicClass {} 79 * protected class PublicClass {} 80 * class PackagePrivateClass {} 81 * </pre> 82 * <p> 83 * To configure the check for {@code private} scope: 84 * </p> 85 * <pre> 86 * <module name="MissingJavadocType"> 87 * <property name="scope" value="private"/> 88 * </module> 89 * </pre> 90 * <p> 91 * Example: 92 * </p> 93 * <pre> 94 * public class PublicClass {} // violation 95 * private class PublicClass {} // violation 96 * protected class PublicClass {} // violation 97 * class PackagePrivateClass {} // violation 98 * </pre> 99 * <p> 100 * To configure the check for {@code private} classes only: 101 * </p> 102 * <pre> 103 * <module name="MissingJavadocType"> 104 * <property name="scope" value="private"/> 105 * <property name="excludeScope" value="package"/> 106 * </module> 107 * </pre> 108 * <p> 109 * Example: 110 * </p> 111 * <pre> 112 * public class PublicClass {} 113 * private class PublicClass {} // violation 114 * protected class PublicClass {} 115 * class PackagePrivateClass {} 116 * </pre> 117 * <p> 118 * Example that allows missing comments for classes annotated with {@code @SpringBootApplication} 119 * and {@code @Configuration}: 120 * </p> 121 * <pre> 122 * @SpringBootApplication // no violations about missing comment on class 123 * public class Application {} 124 * 125 * @Configuration // no violations about missing comment on class 126 * class DatabaseConfiguration {} 127 * </pre> 128 * <p> 129 * Use following configuration: 130 * </p> 131 * <pre> 132 * <module name="MissingJavadocType"> 133 * <property name="skipAnnotations" value="SpringBootApplication,Configuration"/> 134 * </module> 135 * </pre> 136 * @since 8.20 137 */ 138 @StatelessCheck 139 public class MissingJavadocTypeCheck extends AbstractCheck { 140 141 /** 142 * A key is pointing to the warning message text in "messages.properties" 143 * file. 144 */ 145 public static final String MSG_JAVADOC_MISSING = "javadoc.missing"; 146 147 /** Specify the visibility scope where Javadoc comments are checked. */ 148 private Scope scope = Scope.PUBLIC; 149 /** Specify the visibility scope where Javadoc comments are not checked. */ 150 private Scope excludeScope; 151 152 /** 153 * Specify the list of annotations that allow missed documentation. 154 * Only short names are allowed, e.g. {@code Generated}. 155 */ 156 private List<String> skipAnnotations = Collections.singletonList("Generated"); 157 158 /** 159 * Setter to specify the visibility scope where Javadoc comments are checked. 160 * @param scope a scope. 161 */ 162 public void setScope(Scope scope) { 163 this.scope = scope; 164 } 165 166 /** 167 * Setter to specify the visibility scope where Javadoc comments are not checked. 168 * @param excludeScope a scope. 169 */ 170 public void setExcludeScope(Scope excludeScope) { 171 this.excludeScope = excludeScope; 172 } 173 174 /** 175 * Setter to specify the list of annotations that allow missed documentation. 176 * Only short names are allowed, e.g. {@code Generated}. 177 * @param userAnnotations user's value. 178 */ 179 public void setSkipAnnotations(String... userAnnotations) { 180 skipAnnotations = Arrays.asList(userAnnotations); 181 } 182 183 @Override 184 public int[] getDefaultTokens() { 185 return getAcceptableTokens(); 186 } 187 188 @Override 189 public int[] getAcceptableTokens() { 190 return new int[] { 191 TokenTypes.INTERFACE_DEF, 192 TokenTypes.CLASS_DEF, 193 TokenTypes.ENUM_DEF, 194 TokenTypes.ANNOTATION_DEF, 195 }; 196 } 197 198 @Override 199 public int[] getRequiredTokens() { 200 return CommonUtil.EMPTY_INT_ARRAY; 201 } 202 203 @Override 204 public void visitToken(DetailAST ast) { 205 if (shouldCheck(ast)) { 206 final FileContents contents = getFileContents(); 207 final int lineNo = ast.getLineNo(); 208 final TextBlock textBlock = contents.getJavadocBefore(lineNo); 209 if (textBlock == null) { 210 log(lineNo, MSG_JAVADOC_MISSING); 211 } 212 } 213 } 214 215 /** 216 * Whether we should check this node. 217 * @param ast a given node. 218 * @return whether we should check a given node. 219 */ 220 private boolean shouldCheck(final DetailAST ast) { 221 final Scope customScope; 222 223 if (ScopeUtil.isInInterfaceOrAnnotationBlock(ast)) { 224 customScope = Scope.PUBLIC; 225 } 226 else { 227 final DetailAST mods = ast.findFirstToken(TokenTypes.MODIFIERS); 228 customScope = ScopeUtil.getScopeFromMods(mods); 229 } 230 final Scope surroundingScope = ScopeUtil.getSurroundingScope(ast); 231 232 return customScope.isIn(scope) 233 && (surroundingScope == null || surroundingScope.isIn(scope)) 234 && (excludeScope == null 235 || !customScope.isIn(excludeScope) 236 || surroundingScope != null 237 && !surroundingScope.isIn(excludeScope)) 238 && !AnnotationUtil.containsAnnotation(ast, skipAnnotations); 239 } 240 241 }