001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2025 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.regex.Matcher; 023import java.util.regex.Pattern; 024 025import com.puppycrawl.tools.checkstyle.StatelessCheck; 026import com.puppycrawl.tools.checkstyle.api.AbstractCheck; 027import com.puppycrawl.tools.checkstyle.api.DetailAST; 028import com.puppycrawl.tools.checkstyle.api.FileContents; 029import com.puppycrawl.tools.checkstyle.api.SeverityLevel; 030import com.puppycrawl.tools.checkstyle.api.TextBlock; 031import com.puppycrawl.tools.checkstyle.api.TokenTypes; 032import com.puppycrawl.tools.checkstyle.utils.CommonUtil; 033 034/** 035 * <div> 036 * Requires user defined Javadoc tag to be present in Javadoc comment with defined format. 037 * To define the format for a tag, set property tagFormat to a regular expression. 038 * Property tagSeverity is used for severity of events when the tag exists. 039 * No violation reported in case there is no javadoc. 040 * </div> 041 * 042 * <ul> 043 * <li> 044 * Property {@code tag} - Specify the name of tag. 045 * Type is {@code java.lang.String}. 046 * Default value is {@code null}. 047 * </li> 048 * <li> 049 * Property {@code tagFormat} - Specify the regexp to match tag content. 050 * Type is {@code java.util.regex.Pattern}. 051 * Default value is {@code null}. 052 * </li> 053 * <li> 054 * Property {@code tagSeverity} - Specify the severity level when tag is found and printed. 055 * Type is {@code com.puppycrawl.tools.checkstyle.api.SeverityLevel}. 056 * Default value is {@code info}. 057 * </li> 058 * <li> 059 * Property {@code tokens} - tokens to check 060 * Type is {@code java.lang.String[]}. 061 * Validation type is {@code tokenSet}. 062 * Default value is: 063 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INTERFACE_DEF"> 064 * INTERFACE_DEF</a>, 065 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CLASS_DEF"> 066 * CLASS_DEF</a>, 067 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_DEF"> 068 * ENUM_DEF</a>, 069 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ANNOTATION_DEF"> 070 * ANNOTATION_DEF</a>, 071 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#RECORD_DEF"> 072 * RECORD_DEF</a>. 073 * </li> 074 * </ul> 075 * 076 * <p> 077 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} 078 * </p> 079 * 080 * <p> 081 * Violation Message Keys: 082 * </p> 083 * <ul> 084 * <li> 085 * {@code javadoc.writeTag} 086 * </li> 087 * <li> 088 * {@code type.missingTag} 089 * </li> 090 * <li> 091 * {@code type.tagFormat} 092 * </li> 093 * </ul> 094 * 095 * @since 4.2 096 */ 097@StatelessCheck 098public class WriteTagCheck 099 extends AbstractCheck { 100 101 /** 102 * A key is pointing to the warning message text in "messages.properties" 103 * file. 104 */ 105 public static final String MSG_MISSING_TAG = "type.missingTag"; 106 107 /** 108 * A key is pointing to the warning message text in "messages.properties" 109 * file. 110 */ 111 public static final String MSG_WRITE_TAG = "javadoc.writeTag"; 112 113 /** 114 * A key is pointing to the warning message text in "messages.properties" 115 * file. 116 */ 117 public static final String MSG_TAG_FORMAT = "type.tagFormat"; 118 119 /** Compiled regexp to match tag. */ 120 private Pattern tagRegExp; 121 /** Specify the regexp to match tag content. */ 122 private Pattern tagFormat; 123 124 /** Specify the name of tag. */ 125 private String tag; 126 /** Specify the severity level when tag is found and printed. */ 127 private SeverityLevel tagSeverity = SeverityLevel.INFO; 128 129 /** 130 * Setter to specify the name of tag. 131 * 132 * @param tag tag to check 133 * @since 4.2 134 */ 135 public void setTag(String tag) { 136 this.tag = tag; 137 tagRegExp = CommonUtil.createPattern(tag + "\\s*(.*$)"); 138 } 139 140 /** 141 * Setter to specify the regexp to match tag content. 142 * 143 * @param pattern a {@code String} value 144 * @since 4.2 145 */ 146 public void setTagFormat(Pattern pattern) { 147 tagFormat = pattern; 148 } 149 150 /** 151 * Setter to specify the severity level when tag is found and printed. 152 * 153 * @param severity The new severity level 154 * @see SeverityLevel 155 * @since 4.2 156 */ 157 public final void setTagSeverity(SeverityLevel severity) { 158 tagSeverity = severity; 159 } 160 161 @Override 162 public int[] getDefaultTokens() { 163 return new int[] { 164 TokenTypes.INTERFACE_DEF, 165 TokenTypes.CLASS_DEF, 166 TokenTypes.ENUM_DEF, 167 TokenTypes.ANNOTATION_DEF, 168 TokenTypes.RECORD_DEF, 169 }; 170 } 171 172 @Override 173 public int[] getAcceptableTokens() { 174 return new int[] { 175 TokenTypes.INTERFACE_DEF, 176 TokenTypes.CLASS_DEF, 177 TokenTypes.ENUM_DEF, 178 TokenTypes.ANNOTATION_DEF, 179 TokenTypes.METHOD_DEF, 180 TokenTypes.CTOR_DEF, 181 TokenTypes.ENUM_CONSTANT_DEF, 182 TokenTypes.ANNOTATION_FIELD_DEF, 183 TokenTypes.RECORD_DEF, 184 TokenTypes.COMPACT_CTOR_DEF, 185 }; 186 } 187 188 @Override 189 public int[] getRequiredTokens() { 190 return CommonUtil.EMPTY_INT_ARRAY; 191 } 192 193 // suppress deprecation until https://github.com/checkstyle/checkstyle/issues/11166 194 @SuppressWarnings("deprecation") 195 @Override 196 public void visitToken(DetailAST ast) { 197 final FileContents contents = getFileContents(); 198 final int lineNo = ast.getLineNo(); 199 final TextBlock cmt = 200 contents.getJavadocBefore(lineNo); 201 if (cmt != null) { 202 checkTag(lineNo, cmt.getText()); 203 } 204 } 205 206 /** 207 * Verifies that a type definition has a required tag. 208 * 209 * @param lineNo the line number for the type definition. 210 * @param comment the Javadoc comment for the type definition. 211 */ 212 private void checkTag(int lineNo, String... comment) { 213 if (tagRegExp != null) { 214 boolean hasTag = false; 215 for (int i = 0; i < comment.length; i++) { 216 final String commentValue = comment[i]; 217 final Matcher matcher = tagRegExp.matcher(commentValue); 218 if (matcher.find()) { 219 hasTag = true; 220 final int contentStart = matcher.start(1); 221 final String content = commentValue.substring(contentStart); 222 if (tagFormat == null || tagFormat.matcher(content).find()) { 223 logTag(lineNo + i - comment.length, tag, content); 224 } 225 else { 226 log(lineNo + i - comment.length, MSG_TAG_FORMAT, tag, tagFormat.pattern()); 227 } 228 } 229 } 230 if (!hasTag) { 231 log(lineNo, MSG_MISSING_TAG, tag); 232 } 233 } 234 } 235 236 /** 237 * Log a message. 238 * 239 * @param line the line number where the violation was found 240 * @param tagName the javadoc tag to be logged 241 * @param tagValue the contents of the tag 242 * 243 * @see java.text.MessageFormat 244 */ 245 private void logTag(int line, String tagName, String tagValue) { 246 final String originalSeverity = getSeverity(); 247 setSeverity(tagSeverity.getName()); 248 249 log(line, MSG_WRITE_TAG, tagName, tagValue); 250 251 setSeverity(originalSeverity); 252 } 253 254}