View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2024 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.JavadocTokenTypes;
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   * <ul>
38   * <li>
39   * Property {@code ignoreInlineTags} - Control whether
40   * <a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDBEFIF">
41   * inline tags</a> must be ignored.
42   * Type is {@code boolean}.
43   * Default value is {@code true}.
44   * </li>
45   * <li>
46   * Property {@code ignoredTags} - Specify
47   * <a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDBEFIF">
48   * block tags</a> which are ignored by the check.
49   * Type is {@code java.lang.String[]}.
50   * Default value is {@code ""}.
51   * </li>
52   * <li>
53   * Property {@code violateExecutionOnNonTightHtml} - Control when to print violations
54   * if the Javadoc being examined by this check violates the tight html rules defined at
55   * <a href="https://checkstyle.org/writingjavadocchecks.html#Tight-HTML_rules">Tight-HTML Rules</a>.
56   * Type is {@code boolean}.
57   * Default value is {@code false}.
58   * </li>
59   * </ul>
60   *
61   * <p>
62   * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker}
63   * </p>
64   *
65   * <p>
66   * Violation Message Keys:
67   * </p>
68   * <ul>
69   * <li>
70   * {@code javadoc.missed.html.close}
71   * </li>
72   * <li>
73   * {@code javadoc.parse.rule.error}
74   * </li>
75   * <li>
76   * {@code javadoc.unclosedHtml}
77   * </li>
78   * <li>
79   * {@code javadoc.wrong.singleton.html.tag}
80   * </li>
81   * <li>
82   * {@code singleline.javadoc}
83   * </li>
84   * </ul>
85   *
86   * @since 6.0
87   */
88  @StatelessCheck
89  public class SingleLineJavadocCheck extends AbstractJavadocCheck {
90  
91      /**
92       * A key is pointing to the warning message text in "messages.properties"
93       * file.
94       */
95      public static final String MSG_KEY = "singleline.javadoc";
96  
97      /**
98       * Specify
99       * <a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDBEFIF">
100      * block tags</a> which are ignored by the check.
101      */
102     private Set<String> ignoredTags = Set.of();
103 
104     /**
105      * Control whether
106      * <a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDBEFIF">
107      * inline tags</a> must be ignored.
108      */
109     private boolean ignoreInlineTags = true;
110 
111     /**
112      * Setter to specify
113      * <a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDBEFIF">
114      * block tags</a> which are ignored by the check.
115      *
116      * @param tags to be ignored by check.
117      * @since 6.8
118      */
119     public void setIgnoredTags(String... tags) {
120         ignoredTags = Set.of(tags);
121     }
122 
123     /**
124      * Setter to control whether
125      * <a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDBEFIF">
126      * inline tags</a> must be ignored.
127      *
128      * @param ignoreInlineTags whether inline tags must be ignored.
129      * @since 6.8
130      */
131     public void setIgnoreInlineTags(boolean ignoreInlineTags) {
132         this.ignoreInlineTags = ignoreInlineTags;
133     }
134 
135     @Override
136     public int[] getDefaultJavadocTokens() {
137         return new int[] {
138             JavadocTokenTypes.JAVADOC,
139         };
140     }
141 
142     @Override
143     public int[] getRequiredJavadocTokens() {
144         return getAcceptableJavadocTokens();
145     }
146 
147     @Override
148     public void visitJavadocToken(DetailNode ast) {
149         if (isSingleLineJavadoc(getBlockCommentAst())
150                 && (hasJavadocTags(ast) || !ignoreInlineTags && hasJavadocInlineTags(ast))) {
151             log(ast.getLineNumber(), MSG_KEY);
152         }
153     }
154 
155     /**
156      * Checks if comment is single-line comment.
157      *
158      * @param blockCommentStart the AST tree in which a block comment starts
159      * @return true, if comment is single-line comment.
160      */
161     private static boolean isSingleLineJavadoc(DetailAST blockCommentStart) {
162         final DetailAST blockCommentEnd = blockCommentStart.getLastChild();
163         return TokenUtil.areOnSameLine(blockCommentStart, blockCommentEnd);
164     }
165 
166     /**
167      * Checks if comment has javadoc tags which are not ignored. Also works
168      * on custom tags. As block tags can be interpreted only at the beginning of a line,
169      * only the first instance is checked.
170      *
171      * @param javadocRoot javadoc root node.
172      * @return true, if comment has javadoc tags which are not ignored.
173      * @see <a href=
174      * "https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#blockandinlinetags">
175      * Block and inline tags</a>
176      */
177     private boolean hasJavadocTags(DetailNode javadocRoot) {
178         final DetailNode javadocTagSection =
179                 JavadocUtil.findFirstToken(javadocRoot, JavadocTokenTypes.JAVADOC_TAG);
180         return javadocTagSection != null && !isTagIgnored(javadocTagSection);
181     }
182 
183     /**
184      * Checks if comment has in-line tags which are not ignored.
185      *
186      * @param javadocRoot javadoc root node.
187      * @return true, if comment has in-line tags which are not ignored.
188      * @see <a href=
189      * "https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#javadoctags">
190      * JavadocTags</a>
191      */
192     private boolean hasJavadocInlineTags(DetailNode javadocRoot) {
193         DetailNode javadocTagSection =
194                 JavadocUtil.findFirstToken(javadocRoot, JavadocTokenTypes.JAVADOC_INLINE_TAG);
195         boolean foundTag = false;
196         while (javadocTagSection != null) {
197             if (!isTagIgnored(javadocTagSection)) {
198                 foundTag = true;
199                 break;
200             }
201             javadocTagSection = JavadocUtil.getNextSibling(
202                     javadocTagSection, JavadocTokenTypes.JAVADOC_INLINE_TAG);
203         }
204         return foundTag;
205     }
206 
207     /**
208      * Checks if list of ignored tags contains javadocTagSection's javadoc tag.
209      *
210      * @param javadocTagSection to check javadoc tag in.
211      * @return true, if ignoredTags contains javadocTagSection's javadoc tag.
212      */
213     private boolean isTagIgnored(DetailNode javadocTagSection) {
214         return ignoredTags.contains(JavadocUtil.getTagName(javadocTagSection));
215     }
216 
217 }