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  
11  /**
12   * Checks that there is no empty line between a javadoc and it's subject.
13   *
14   * <p>You can't have empty lines between javadoc block and
15   * a class/method/variable. They should stay together, always.
16   *
17   * @since 0.3
18   */
19  public final class JavadocLocationCheck extends AbstractCheck {
20  
21      @Override
22      public int[] getDefaultTokens() {
23          return new int[] {
24              TokenTypes.CLASS_DEF,
25              TokenTypes.INTERFACE_DEF,
26              TokenTypes.VARIABLE_DEF,
27              TokenTypes.CTOR_DEF,
28              TokenTypes.METHOD_DEF,
29          };
30      }
31  
32      @Override
33      public int[] getAcceptableTokens() {
34          return this.getDefaultTokens();
35      }
36  
37      @Override
38      public int[] getRequiredTokens() {
39          return this.getDefaultTokens();
40      }
41  
42      @Override
43      public void visitToken(final DetailAST ast) {
44          if (!JavadocLocationCheck.isField(ast)) {
45              return;
46          }
47          final String[] lines = this.getLines();
48          int current = ast.getLineNo();
49          boolean found = false;
50          final int start = current;
51          --current;
52          while (true) {
53              if (current <= 0) {
54                  break;
55              }
56              final String line = lines[current - 1].trim();
57              if (line.endsWith("*/")) {
58                  found = true;
59                  break;
60              }
61              if (!line.isEmpty()) {
62                  break;
63              }
64              --current;
65          }
66          if (found) {
67              this.report(start, current);
68          }
69      }
70  
71      /**
72       * Report empty lines between current and end line.
73       * @param current Current line
74       * @param end Final line
75       */
76      private void report(final int current, final int end) {
77          final int diff = current - end;
78          if (diff > 1) {
79              for (int pos = 1; pos < diff; pos += 1) {
80                  this.log(
81                      end + pos,
82                      "Empty line between javadoc and subject"
83                  );
84              }
85          }
86      }
87  
88      /**
89       * Returns {@code TRUE} if a specified node is something that should have
90       * a Javadoc, which includes classes, interface, class methods, and
91       * class variables.
92       * @param node Node to check
93       * @return Is it a Javadoc-required entity?
94       */
95      private static boolean isField(final DetailAST node) {
96          boolean yes = true;
97          if (TokenTypes.VARIABLE_DEF == node.getType()) {
98              yes = TokenTypes.OBJBLOCK == node.getParent().getType();
99          }
100         return yes;
101     }
102 }