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 com.puppycrawl.tools.checkstyle.StatelessCheck; 023import com.puppycrawl.tools.checkstyle.api.DetailNode; 024import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes; 025import com.puppycrawl.tools.checkstyle.utils.CommonUtil; 026import com.puppycrawl.tools.checkstyle.utils.JavadocUtil; 027 028/** 029 * <div> 030 * Checks that the block tag is followed by description. 031 * </div> 032 * 033 * <ul> 034 * <li> 035 * Property {@code violateExecutionOnNonTightHtml} - Control when to print violations 036 * if the Javadoc being examined by this check violates the tight html rules defined at 037 * <a href="https://checkstyle.org/writingjavadocchecks.html#Tight-HTML_rules">Tight-HTML Rules</a>. 038 * Type is {@code boolean}. 039 * Default value is {@code false}. 040 * </li> 041 * <li> 042 * Property {@code javadocTokens} - javadoc tokens to check 043 * Type is {@code java.lang.String[]}. 044 * Validation type is {@code tokenSet}. 045 * Default value is 046 * Since version 7.3 047 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/JavadocTokenTypes.html#PARAM_LITERAL"> 048 * PARAM_LITERAL</a>, 049 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/JavadocTokenTypes.html#RETURN_LITERAL"> 050 * RETURN_LITERAL</a>, 051 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/JavadocTokenTypes.html#THROWS_LITERAL"> 052 * THROWS_LITERAL</a>, 053 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/JavadocTokenTypes.html#EXCEPTION_LITERAL"> 054 * EXCEPTION_LITERAL</a>, 055 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/JavadocTokenTypes.html#DEPRECATED_LITERAL"> 056 * DEPRECATED_LITERAL</a>. 057 * </li> 058 * </ul> 059 * 060 * <p> 061 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} 062 * </p> 063 * 064 * <p> 065 * Violation Message Keys: 066 * </p> 067 * <ul> 068 * <li> 069 * {@code javadoc.missed.html.close} 070 * </li> 071 * <li> 072 * {@code javadoc.parse.rule.error} 073 * </li> 074 * <li> 075 * {@code javadoc.unclosedHtml} 076 * </li> 077 * <li> 078 * {@code javadoc.wrong.singleton.html.tag} 079 * </li> 080 * <li> 081 * {@code non.empty.atclause} 082 * </li> 083 * </ul> 084 * 085 * @since 6.0 086 */ 087@StatelessCheck 088public class NonEmptyAtclauseDescriptionCheck extends AbstractJavadocCheck { 089 090 /** 091 * A key is pointing to the warning message text in "messages.properties" 092 * file. 093 */ 094 public static final String MSG_KEY = "non.empty.atclause"; 095 096 @Override 097 public int[] getDefaultJavadocTokens() { 098 return new int[] { 099 JavadocTokenTypes.PARAM_LITERAL, 100 JavadocTokenTypes.RETURN_LITERAL, 101 JavadocTokenTypes.THROWS_LITERAL, 102 JavadocTokenTypes.EXCEPTION_LITERAL, 103 JavadocTokenTypes.DEPRECATED_LITERAL, 104 }; 105 } 106 107 @Override 108 public void visitJavadocToken(DetailNode ast) { 109 if (isEmptyTag(ast.getParent())) { 110 log(ast.getLineNumber(), MSG_KEY); 111 } 112 } 113 114 /** 115 * Tests if block tag is empty. 116 * 117 * @param tagNode block tag. 118 * @return true, if block tag is empty. 119 */ 120 private static boolean isEmptyTag(DetailNode tagNode) { 121 final DetailNode tagDescription = 122 JavadocUtil.findFirstToken(tagNode, JavadocTokenTypes.DESCRIPTION); 123 return tagDescription == null 124 || hasOnlyEmptyText(tagDescription); 125 } 126 127 /** 128 * Tests if description node is empty (has only new lines and blank strings). 129 * 130 * @param description description node. 131 * @return true, if description node has only new lines and blank strings. 132 */ 133 private static boolean hasOnlyEmptyText(DetailNode description) { 134 boolean result = true; 135 for (DetailNode child : description.getChildren()) { 136 if (child.getType() != JavadocTokenTypes.LEADING_ASTERISK 137 && !CommonUtil.isBlank(child.getText())) { 138 result = false; 139 break; 140 } 141 } 142 return result; 143 } 144 145}