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.ArrayList;
23  import java.util.List;
24  import java.util.regex.Pattern;
25  
26  import com.puppycrawl.tools.checkstyle.FileStatefulCheck;
27  import com.puppycrawl.tools.checkstyle.PropertyType;
28  import com.puppycrawl.tools.checkstyle.XdocsPropertyType;
29  import com.puppycrawl.tools.checkstyle.api.DetailNode;
30  import com.puppycrawl.tools.checkstyle.api.JavadocCommentsTokenTypes;
31  import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
32  import com.puppycrawl.tools.checkstyle.utils.JavadocUtil;
33  
34  /**
35   * <div>
36   * Checks that Javadoc comments do not match a configured regular expression.
37   * </div>
38   *
39   * <p>
40   * The check can operate on raw Javadoc source or on the text visible to readers.
41   * Raw matching includes Javadoc tags, HTML tags, HTML attributes, and formatting
42   * characters. Visible-text matching ignores markup and matches only Javadoc text content.
43   * </p>
44   *
45   * @since 13.10.0
46   */
47  @FileStatefulCheck
48  public class JavadocRegexpCheck extends AbstractJavadocCheck {
49  
50      /**
51       * A key is pointing to the warning message text in "messages.properties" file.
52       */
53      public static final String MSG_JAVADOC_REGEXP = "javadoc.regexp.match";
54  
55      /**
56       * Text fragments visible to readers of the current Javadoc comment.
57       */
58      private final List<String> visibleText = new ArrayList<>();
59  
60      /**
61       * Specify the regular expression to match forbidden Javadoc content.
62       */
63      @XdocsPropertyType(PropertyType.PATTERN)
64      private String format = "^$";
65  
66      /**
67       * Control whether to ignore case when matching.
68       */
69      private boolean ignoreCase;
70  
71      /**
72       * Control whether to ignore Javadoc and HTML markup when matching.
73       */
74      private boolean ignoreMarkup;
75  
76      /**
77       * Line number of the previous collected text node.
78       */
79      private int previousTextLineNumber;
80  
81      /**
82       * Creates a new {@code JavadocRegexpCheck} instance.
83       */
84      public JavadocRegexpCheck() {
85          // no code by default
86      }
87  
88      /**
89       * Setter to specify the regular expression to match forbidden Javadoc content.
90       *
91       * @param format regular expression to match forbidden Javadoc content.
92       * @since 13.10.0
93       */
94      public void setFormat(String format) {
95          this.format = format;
96      }
97  
98      /**
99       * Setter to control whether to ignore case when matching.
100      *
101      * @param ignoreCase whether to ignore case when matching.
102      * @since 13.10.0
103      */
104     public void setIgnoreCase(boolean ignoreCase) {
105         this.ignoreCase = ignoreCase;
106     }
107 
108     /**
109      * Setter to control whether to ignore Javadoc and HTML markup when matching.
110      *
111      * @param ignoreMarkup whether to ignore Javadoc and HTML markup when matching.
112      * @since 13.10.0
113      */
114     public void setIgnoreMarkup(boolean ignoreMarkup) {
115         this.ignoreMarkup = ignoreMarkup;
116     }
117 
118     @Override
119     public int[] getRequiredJavadocTokens() {
120         return new int[] {
121             JavadocCommentsTokenTypes.TEXT,
122         };
123     }
124 
125     @Override
126     public int[] getDefaultJavadocTokens() {
127         return getRequiredJavadocTokens();
128     }
129 
130     @Override
131     public void beginJavadocTree(DetailNode rootAst) {
132         visibleText.clear();
133     }
134 
135     @Override
136     public void visitJavadocToken(DetailNode ast) {
137         if (!isIgnoredText(ast)) {
138             appendVisibleText(ast);
139         }
140     }
141 
142     @Override
143     public void finishJavadocTree(DetailNode rootAst) {
144         final String content;
145         if (ignoreMarkup) {
146             content = String.join("", visibleText);
147         }
148         else {
149             content = JavadocUtil.getJavadocCommentContent(getBlockCommentAst());
150         }
151 
152         final Pattern regexp = createRegexp();
153         if (regexp.matcher(content).find()) {
154             log(rootAst.getLineNumber(), MSG_JAVADOC_REGEXP, regexp.pattern());
155         }
156     }
157 
158     /**
159      * Creates the regexp based on {@link #format} and {@link #ignoreCase}.
160      *
161      * @return pattern used to find forbidden content.
162      */
163     private Pattern createRegexp() {
164         final int compileFlags;
165         if (ignoreCase) {
166             compileFlags = Pattern.CASE_INSENSITIVE;
167         }
168         else {
169             compileFlags = 0;
170         }
171         return CommonUtil.createPattern(format, compileFlags);
172     }
173 
174     /**
175      * Appends visible text from a Javadoc text node.
176      *
177      * @param textNode text node to append.
178      */
179     private void appendVisibleText(DetailNode textNode) {
180         if (!visibleText.isEmpty() && previousTextLineNumber < textNode.getLineNumber()) {
181             visibleText.add(" ");
182         }
183         visibleText.add(textNode.getText());
184         previousTextLineNumber = textNode.getLineNumber();
185     }
186 
187     /**
188      * Checks whether a text node belongs to a non-rendered HTML comment.
189      *
190      * @param textNode text node to check.
191      * @return {@code true} if the text node should be ignored.
192      */
193     private static boolean isIgnoredText(DetailNode textNode) {
194         boolean result = false;
195         DetailNode current = textNode;
196 
197         while (current != null) {
198             if (current.getType() == JavadocCommentsTokenTypes.HTML_COMMENT) {
199                 result = true;
200                 break;
201             }
202             current = current.getParent();
203         }
204 
205         return result;
206     }
207 
208 }