View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2011-2025 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   * @todo #260 Add handling of multiple anonymous classes inside methods by
24   *  looking at the recursive tree.
25   */
26  public final class MethodBodyCommentsCheck extends AbstractCheck {
27  
28      @Override
29      public int[] getDefaultTokens() {
30          return new int[] {
31              TokenTypes.CTOR_DEF,
32              TokenTypes.METHOD_DEF,
33          };
34      }
35  
36      @Override
37      public int[] getAcceptableTokens() {
38          return this.getDefaultTokens();
39      }
40  
41      @Override
42      public int[] getRequiredTokens() {
43          return this.getDefaultTokens();
44      }
45  
46      @Override
47      public void visitToken(final DetailAST ast) {
48          final DetailAST start = ast.findFirstToken(TokenTypes.SLIST);
49          final String[] lines = Arrays.copyOf(
50              this.getLines(), this.getLines().length
51          );
52          if (start != null) {
53              DetailAST ostart = start.findFirstToken(TokenTypes.VARIABLE_DEF);
54              final int[] tokens = {
55                  TokenTypes.ASSIGN, TokenTypes.EXPR,
56                  TokenTypes.LITERAL_NEW, TokenTypes.OBJBLOCK,
57              };
58              for (final int token : tokens) {
59                  if (ostart != null) {
60                      ostart = ostart.findFirstToken(token);
61                  }
62              }
63              if (ostart != null
64                  && ostart.getType() == tokens[tokens.length - 1]) {
65                  Arrays.fill(
66                      lines, ostart.getLineNo(),
67                      ostart.findFirstToken(TokenTypes.RCURLY).getLineNo(), ""
68                  );
69              }
70              this.checkMethod(
71                  lines,
72                  start.getLineNo(),
73                  start.findFirstToken(TokenTypes.RCURLY).getLineNo() - 1
74              );
75          }
76      }
77  
78      /**
79       * Checks method body for comments.
80       * @param lines Array of lines, containing code to check.
81       * @param start Start line of the method body.
82       * @param end End line of the method body.
83       */
84      private void checkMethod(final String[] lines, final int start,
85          final int end) {
86          final boolean oneliner = start == end - 1;
87          for (int pos = start; pos < end; ++pos) {
88              final String line = lines[pos].trim();
89              if (line.startsWith("//") || line.startsWith("/*")) {
90                  final String comment = line.substring(2).trim();
91                  if (!comment.startsWith("@checkstyle") && !oneliner) {
92                      this.log(pos + 1, "Comments in method body are prohibited");
93                  }
94              }
95          }
96      }
97  }