1 ///////////////////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3 // Copyright (C) 2001-2026 the original author or authors.
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ///////////////////////////////////////////////////////////////////////////////////////////////
19
20 package com.puppycrawl.tools.checkstyle.checks.javadoc;
21
22 import java.util.Set;
23
24 import com.puppycrawl.tools.checkstyle.StatelessCheck;
25 import com.puppycrawl.tools.checkstyle.api.DetailAST;
26 import com.puppycrawl.tools.checkstyle.api.DetailNode;
27 import com.puppycrawl.tools.checkstyle.api.JavadocCommentsTokenTypes;
28 import com.puppycrawl.tools.checkstyle.utils.JavadocUtil;
29 import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
30
31 /**
32 * <div>
33 * Checks that a Javadoc block can fit in a single-line and doesn't contain block tags.
34 * Javadoc comment that contains at least one block tag should be formatted in a few lines.
35 * </div>
36 *
37 * @since 6.0
38 */
39 @StatelessCheck
40 public class SingleLineJavadocCheck extends AbstractJavadocCheck {
41
42 /**
43 * A key is pointing to the warning message text in "messages.properties"
44 * file.
45 */
46 public static final String MSG_KEY = "singleline.javadoc";
47
48 /**
49 * Specify
50 * <a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDBEFIF">
51 * block tags</a> which are ignored by the check.
52 */
53 private Set<String> ignoredTags = Set.of();
54
55 /**
56 * Control whether
57 * <a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDBEFIF">
58 * inline tags</a> must be ignored.
59 */
60 private boolean ignoreInlineTags = true;
61
62 /**
63 * Creates a new {@code SingleLineJavadocCheck} instance.
64 */
65 public SingleLineJavadocCheck() {
66 // no code by default
67 }
68
69 /**
70 * Setter to specify
71 * <a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDBEFIF">
72 * block tags</a> which are ignored by the check.
73 *
74 * @param tags to be ignored by check.
75 * @since 6.8
76 */
77 public void setIgnoredTags(String... tags) {
78 ignoredTags = Set.of(tags);
79 }
80
81 /**
82 * Setter to control whether
83 * <a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDBEFIF">
84 * inline tags</a> must be ignored.
85 *
86 * @param ignoreInlineTags whether inline tags must be ignored.
87 * @since 6.8
88 */
89 public void setIgnoreInlineTags(boolean ignoreInlineTags) {
90 this.ignoreInlineTags = ignoreInlineTags;
91 }
92
93 @Override
94 public int[] getDefaultJavadocTokens() {
95 return new int[] {
96 JavadocCommentsTokenTypes.JAVADOC_CONTENT,
97 };
98 }
99
100 @Override
101 public int[] getRequiredJavadocTokens() {
102 return getAcceptableJavadocTokens();
103 }
104
105 @Override
106 public void visitJavadocToken(DetailNode ast) {
107 if (isSingleLineJavadoc(getBlockCommentAst())
108 && (hasJavadocTags(ast) || !ignoreInlineTags && hasJavadocInlineTags(ast))) {
109 log(ast.getLineNumber(), MSG_KEY);
110 }
111 }
112
113 /**
114 * Checks if comment is single-line comment.
115 *
116 * @param blockCommentStart the AST tree in which a block comment starts
117 * @return true, if comment is single-line comment.
118 */
119 private static boolean isSingleLineJavadoc(DetailAST blockCommentStart) {
120 final DetailAST blockCommentEnd = blockCommentStart.getLastChild();
121 return TokenUtil.areOnSameLine(blockCommentStart, blockCommentEnd);
122 }
123
124 /**
125 * Checks if comment has javadoc tags which are not ignored. Also works
126 * on custom tags. As block tags can be interpreted only at the beginning of a line,
127 * only the first instance is checked.
128 *
129 * @param javadocRoot javadoc root node.
130 * @return true, if comment has javadoc tags which are not ignored.
131 * @see <a href=
132 * "https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#blockandinlinetags">
133 * Block and inline tags</a>
134 */
135 private boolean hasJavadocTags(DetailNode javadocRoot) {
136 final DetailNode javadocTagSection =
137 JavadocUtil.findFirstToken(
138 javadocRoot, JavadocCommentsTokenTypes.JAVADOC_BLOCK_TAG);
139 return javadocTagSection != null && !isTagIgnored(javadocTagSection);
140 }
141
142 /**
143 * Checks if comment has in-line tags which are not ignored.
144 *
145 * @param javadocRoot javadoc root node.
146 * @return true, if comment has in-line tags which are not ignored.
147 * @see <a href=
148 * "https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#javadoctags">
149 * JavadocTags</a>
150 */
151 private boolean hasJavadocInlineTags(DetailNode javadocRoot) {
152 DetailNode javadocTagSection =
153 JavadocUtil.findFirstToken(
154 javadocRoot, JavadocCommentsTokenTypes.JAVADOC_INLINE_TAG);
155 boolean foundTag = false;
156 while (javadocTagSection != null) {
157 if (!isTagIgnored(javadocTagSection)) {
158 foundTag = true;
159 break;
160 }
161 javadocTagSection = JavadocUtil.getNextSibling(
162 javadocTagSection, JavadocCommentsTokenTypes.JAVADOC_INLINE_TAG);
163 }
164 return foundTag;
165 }
166
167 /**
168 * Checks if list of ignored tags contains javadocTagSection's javadoc tag.
169 *
170 * @param javadocTagSection to check javadoc tag in.
171 * @return true, if ignoredTags contains javadocTagSection's javadoc tag.
172 */
173 private boolean isTagIgnored(DetailNode javadocTagSection) {
174 final String tagName = JavadocUtil.getTagName(javadocTagSection);
175 return ignoredTags.contains("@" + tagName);
176 }
177
178 }