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