001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2026 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.Set; 023 024import com.puppycrawl.tools.checkstyle.StatelessCheck; 025import com.puppycrawl.tools.checkstyle.api.DetailAST; 026import com.puppycrawl.tools.checkstyle.api.DetailNode; 027import com.puppycrawl.tools.checkstyle.api.JavadocCommentsTokenTypes; 028import com.puppycrawl.tools.checkstyle.utils.JavadocUtil; 029import com.puppycrawl.tools.checkstyle.utils.TokenUtil; 030 031/** 032 * <div> 033 * Checks that a Javadoc block can fit in a single-line and doesn't contain block tags. 034 * Javadoc comment that contains at least one block tag should be formatted in a few lines. 035 * </div> 036 * 037 * @since 6.0 038 */ 039@StatelessCheck 040public class SingleLineJavadocCheck extends AbstractJavadocCheck { 041 042 /** 043 * A key is pointing to the warning message text in "messages.properties" file. 044 */ 045 public static final String MSG_KEY = "singleline.javadoc"; 046 047 /** 048 * Specify 049 * <a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDBEFIF"> 050 * block tags</a> which are ignored by the check. 051 */ 052 private Set<String> ignoredTags = Set.of(); 053 054 /** 055 * Control whether 056 * <a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDBEFIF"> 057 * inline tags</a> must be ignored. 058 */ 059 private boolean ignoreInlineTags = true; 060 061 /** 062 * Creates a new {@code SingleLineJavadocCheck} instance. 063 */ 064 public SingleLineJavadocCheck() { 065 // no code by default 066 } 067 068 /** 069 * Setter to specify 070 * <a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDBEFIF"> 071 * block tags</a> which are ignored by the check. 072 * 073 * @param tags to be ignored by check. 074 * @since 6.8 075 */ 076 public void setIgnoredTags(String... tags) { 077 ignoredTags = Set.of(tags); 078 } 079 080 /** 081 * Setter to control whether 082 * <a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDBEFIF"> 083 * inline tags</a> must be ignored. 084 * 085 * @param ignoreInlineTags whether inline tags must be ignored. 086 * @since 6.8 087 */ 088 public void setIgnoreInlineTags(boolean ignoreInlineTags) { 089 this.ignoreInlineTags = ignoreInlineTags; 090 } 091 092 @Override 093 public int[] getDefaultJavadocTokens() { 094 return new int[] { 095 JavadocCommentsTokenTypes.JAVADOC_CONTENT, 096 }; 097 } 098 099 @Override 100 public int[] getRequiredJavadocTokens() { 101 return getAcceptableJavadocTokens(); 102 } 103 104 @Override 105 public void visitJavadocToken(DetailNode ast) { 106 if (isSingleLineJavadoc(getBlockCommentAst()) 107 && (hasJavadocTags(ast) || !ignoreInlineTags && hasJavadocInlineTags(ast))) { 108 log(ast.getLineNumber(), MSG_KEY); 109 } 110 } 111 112 /** 113 * Checks if comment is single-line comment. 114 * 115 * @param blockCommentStart the AST tree in which a block comment starts 116 * @return true, if comment is single-line comment. 117 */ 118 private static boolean isSingleLineJavadoc(DetailAST blockCommentStart) { 119 final DetailAST blockCommentEnd = blockCommentStart.getLastChild(); 120 return TokenUtil.areOnSameLine(blockCommentStart, blockCommentEnd); 121 } 122 123 /** 124 * Checks if comment has javadoc tags which are not ignored. Also works 125 * on custom tags. As block tags can be interpreted only at the beginning of a line, 126 * only the first instance is checked. 127 * 128 * @param javadocRoot javadoc root node. 129 * @return true, if comment has javadoc tags which are not ignored. 130 * @see <a href= 131 * "https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#blockandinlinetags"> 132 * Block and inline tags</a> 133 */ 134 private boolean hasJavadocTags(DetailNode javadocRoot) { 135 final DetailNode javadocTagSection = 136 JavadocUtil.findFirstToken( 137 javadocRoot, JavadocCommentsTokenTypes.JAVADOC_BLOCK_TAG); 138 return javadocTagSection != null && !isTagIgnored(javadocTagSection); 139 } 140 141 /** 142 * Checks if comment has in-line tags which are not ignored. 143 * 144 * @param javadocRoot javadoc root node. 145 * @return true, if comment has in-line tags which are not ignored. 146 * @see <a href= 147 * "https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#javadoctags"> 148 * JavadocTags</a> 149 */ 150 private boolean hasJavadocInlineTags(DetailNode javadocRoot) { 151 DetailNode javadocTagSection = 152 JavadocUtil.findFirstToken( 153 javadocRoot, JavadocCommentsTokenTypes.JAVADOC_INLINE_TAG); 154 boolean foundTag = false; 155 while (javadocTagSection != null) { 156 if (!isTagIgnored(javadocTagSection)) { 157 foundTag = true; 158 break; 159 } 160 javadocTagSection = JavadocUtil.getNextSibling( 161 javadocTagSection, JavadocCommentsTokenTypes.JAVADOC_INLINE_TAG); 162 } 163 return foundTag; 164 } 165 166 /** 167 * Checks if list of ignored tags contains javadocTagSection's javadoc tag. 168 * 169 * @param javadocTagSection to check javadoc tag in. 170 * @return true, if ignoredTags contains javadocTagSection's javadoc tag. 171 */ 172 private boolean isTagIgnored(DetailNode javadocTagSection) { 173 final String tagName = JavadocUtil.getTagName(javadocTagSection); 174 return ignoredTags.contains("@" + tagName); 175 } 176 177}