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 * <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 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/JavadocTokenTypes.html#PARAM_LITERAL"> 047 * PARAM_LITERAL</a>, 048 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/JavadocTokenTypes.html#RETURN_LITERAL"> 049 * RETURN_LITERAL</a>, 050 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/JavadocTokenTypes.html#THROWS_LITERAL"> 051 * THROWS_LITERAL</a>, 052 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/JavadocTokenTypes.html#EXCEPTION_LITERAL"> 053 * EXCEPTION_LITERAL</a>, 054 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/JavadocTokenTypes.html#DEPRECATED_LITERAL"> 055 * DEPRECATED_LITERAL</a>. 056 * </li> 057 * </ul> 058 * 059 * <p> 060 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} 061 * </p> 062 * 063 * <p> 064 * Violation Message Keys: 065 * </p> 066 * <ul> 067 * <li> 068 * {@code javadoc.missed.html.close} 069 * </li> 070 * <li> 071 * {@code javadoc.parse.rule.error} 072 * </li> 073 * <li> 074 * {@code javadoc.unclosedHtml} 075 * </li> 076 * <li> 077 * {@code javadoc.wrong.singleton.html.tag} 078 * </li> 079 * <li> 080 * {@code non.empty.atclause} 081 * </li> 082 * </ul> 083 * 084 * @since 6.0 085 */ 086@StatelessCheck 087public class NonEmptyAtclauseDescriptionCheck extends AbstractJavadocCheck { 088 089 /** 090 * A key is pointing to the warning message text in "messages.properties" 091 * file. 092 */ 093 public static final String MSG_KEY = "non.empty.atclause"; 094 095 @Override 096 public int[] getDefaultJavadocTokens() { 097 return new int[] { 098 JavadocTokenTypes.PARAM_LITERAL, 099 JavadocTokenTypes.RETURN_LITERAL, 100 JavadocTokenTypes.THROWS_LITERAL, 101 JavadocTokenTypes.EXCEPTION_LITERAL, 102 JavadocTokenTypes.DEPRECATED_LITERAL, 103 }; 104 } 105 106 @Override 107 public void visitJavadocToken(DetailNode ast) { 108 if (isEmptyTag(ast.getParent())) { 109 log(ast.getLineNumber(), MSG_KEY); 110 } 111 } 112 113 /** 114 * Tests if block tag is empty. 115 * 116 * @param tagNode block tag. 117 * @return true, if block tag is empty. 118 */ 119 private static boolean isEmptyTag(DetailNode tagNode) { 120 final DetailNode tagDescription = 121 JavadocUtil.findFirstToken(tagNode, JavadocTokenTypes.DESCRIPTION); 122 return tagDescription == null 123 || hasOnlyEmptyText(tagDescription); 124 } 125 126 /** 127 * Tests if description node is empty (has only new lines and blank strings). 128 * 129 * @param description description node. 130 * @return true, if description node has only new lines and blank strings. 131 */ 132 private static boolean hasOnlyEmptyText(DetailNode description) { 133 boolean result = true; 134 for (DetailNode child : description.getChildren()) { 135 if (child.getType() != JavadocTokenTypes.LEADING_ASTERISK 136 && !CommonUtil.isBlank(child.getText())) { 137 result = false; 138 break; 139 } 140 } 141 return result; 142 } 143 144}