View Javadoc
1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2017 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  
25  import com.puppycrawl.tools.checkstyle.api.DetailNode;
26  import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes;
27  import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
28  import com.puppycrawl.tools.checkstyle.utils.JavadocUtils;
29  
30  /**
31   * <p>
32   * Checks the indentation of the continuation lines in at-clauses.
33   * </p>
34   * <p>
35   * Default configuration:
36   * </p>
37   * <pre>
38   * &lt;module name=&quot;JavadocTagContinuationIndentation&quot;&gt;
39   *     &lt;property name=&quot;offset&quot; value=&quot;4&quot;/&gt;
40   * &lt;/module&gt;
41   * </pre>
42   *
43   * @author max
44   *
45   */
46  public class JavadocTagContinuationIndentationCheck extends AbstractJavadocCheck {
47  
48      /**
49       * A key is pointing to the warning message text in "messages.properties"
50       * file.
51       */
52      public static final String MSG_KEY = "tag.continuation.indent";
53  
54      /** Default tag continuation indentation. */
55      private static final int DEFAULT_INDENTATION = 4;
56  
57      /**
58       * How many spaces to use for new indentation level.
59       */
60      private int offset = DEFAULT_INDENTATION;
61  
62      /**
63       * Sets custom indentation level.
64       * @param offset custom value.
65       */
66      public void setOffset(int offset) {
67          this.offset = offset;
68      }
69  
70      @Override
71      public int[] getDefaultJavadocTokens() {
72          return new int[] {JavadocTokenTypes.DESCRIPTION };
73      }
74  
75      @Override
76      public int[] getRequiredJavadocTokens() {
77          return getAcceptableJavadocTokens();
78      }
79  
80      @Override
81      public void visitJavadocToken(DetailNode ast) {
82          if (!isInlineDescription(ast)) {
83              final List<DetailNode> textNodes = getAllNewlineNodes(ast);
84              for (DetailNode newlineNode : textNodes) {
85                  final DetailNode textNode = JavadocUtils.getNextSibling(JavadocUtils
86                          .getNextSibling(newlineNode));
87                  if (textNode != null && textNode.getType() == JavadocTokenTypes.TEXT) {
88                      final String text = textNode.getText();
89                      if (!CommonUtils.isBlank(text.trim())
90                              && (text.length() <= offset
91                                      || !text.substring(1, offset + 1).trim().isEmpty())) {
92                          log(textNode.getLineNumber(), MSG_KEY, offset);
93                      }
94                  }
95              }
96          }
97      }
98  
99      /**
100      * Finds and collects all NEWLINE nodes inside DESCRIPTION node.
101      * @param descriptionNode DESCRIPTION node.
102      * @return List with NEWLINE nodes.
103      */
104     private static List<DetailNode> getAllNewlineNodes(DetailNode descriptionNode) {
105         final List<DetailNode> textNodes = new ArrayList<>();
106         DetailNode node = JavadocUtils.getFirstChild(descriptionNode);
107         while (JavadocUtils.getNextSibling(node) != null) {
108             if (node.getType() == JavadocTokenTypes.NEWLINE) {
109                 textNodes.add(node);
110             }
111             node = JavadocUtils.getNextSibling(node);
112         }
113         return textNodes;
114     }
115 
116     /**
117      * Checks, if description node is a description of in-line tag.
118      * @param description DESCRIPTION node.
119      * @return true, if description node is a description of in-line tag.
120      */
121     private static boolean isInlineDescription(DetailNode description) {
122         boolean isInline = false;
123         DetailNode inlineTag = description.getParent();
124         while (inlineTag != null) {
125             if (inlineTag.getType() == JavadocTokenTypes.JAVADOC_INLINE_TAG) {
126                 isInline = true;
127                 break;
128             }
129             inlineTag = inlineTag.getParent();
130         }
131         return isInline;
132     }
133 }