View Javadoc
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 }