View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2011-2026 Yegor Bugayenko
3    * SPDX-License-Identifier: MIT
4    */
5   package com.qulice.checkstyle;
6   
7   import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
8   import com.puppycrawl.tools.checkstyle.api.DetailAST;
9   import com.puppycrawl.tools.checkstyle.api.TokenTypes;
10  import java.util.Arrays;
11  
12  /**
13   * Checks method bodies for comments. All comments in method bodies are
14   * prohibited.
15   *
16   * <p>We believe that in-code comments and empty lines are evil. If you
17   * need to use
18   * a comment inside a method - your code needs refactoring. Either move that
19   * comment to a method javadoc block or add a logging mechanism with the same
20   * text.
21   *
22   * @since 0.3
23   */
24  public final class MethodBodyCommentsCheck extends AbstractCheck {
25  
26      @Override
27      public int[] getDefaultTokens() {
28          return new int[] {
29              TokenTypes.CTOR_DEF,
30              TokenTypes.METHOD_DEF,
31          };
32      }
33  
34      @Override
35      public int[] getAcceptableTokens() {
36          return this.getDefaultTokens();
37      }
38  
39      @Override
40      public int[] getRequiredTokens() {
41          return this.getDefaultTokens();
42      }
43  
44      @Override
45      public void visitToken(final DetailAST ast) {
46          final DetailAST start = ast.findFirstToken(TokenTypes.SLIST);
47          if (start != null) {
48              final String[] lines = Arrays.copyOf(
49                  this.getLines(), this.getLines().length
50              );
51              this.maskAnonymous(start, lines);
52              this.checkMethod(
53                  lines,
54                  start.getLineNo(),
55                  start.findFirstToken(TokenTypes.RCURLY).getLineNo() - 1
56              );
57          }
58      }
59  
60      /**
61       * Replace with empty strings the lines that belong to the body of any
62       * anonymous class found anywhere in the given subtree.
63       * @param node Root of the subtree to scan
64       * @param lines Lines to be modified in place
65       */
66      private void maskAnonymous(final DetailAST node, final String... lines) {
67          for (DetailAST child = node.getFirstChild(); child != null;
68              child = child.getNextSibling()) {
69              if (child.getType() == TokenTypes.LITERAL_NEW) {
70                  final DetailAST block = child.findFirstToken(
71                      TokenTypes.OBJBLOCK
72                  );
73                  if (block != null) {
74                      Arrays.fill(
75                          lines, block.getLineNo(),
76                          block.findFirstToken(TokenTypes.RCURLY).getLineNo(),
77                          ""
78                      );
79                  }
80              }
81              this.maskAnonymous(child, lines);
82          }
83      }
84  
85      /**
86       * Checks method body for comments.
87       * @param lines Array of lines, containing code to check
88       * @param start Start line of the method body
89       * @param end End line of the method body
90       */
91      private void checkMethod(final String[] lines, final int start,
92          final int end) {
93          final boolean oneliner = start == end - 1;
94          for (int pos = start; pos < end; ++pos) {
95              final String line = lines[pos].trim();
96              if (line.startsWith("//") || line.startsWith("/*")) {
97                  final String comment = line.substring(2).trim();
98                  if (!comment.startsWith("@checkstyle") && !oneliner) {
99                      this.log(pos + 1, "Comments in method body are prohibited");
100                 }
101             }
102         }
103     }
104 }