1 /* 2 * Copyright (c) 2011-2025 Yegor Bugayenko 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 1) Redistributions of source code must retain the above 9 * copyright notice, this list of conditions and the following 10 * disclaimer. 2) Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following 12 * disclaimer in the documentation and/or other materials provided 13 * with the distribution. 3) Neither the name of the Qulice.com nor 14 * the names of its contributors may be used to endorse or promote 15 * products derived from this software without specific prior written 16 * permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT 20 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22 * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 29 * OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 package com.qulice.checkstyle; 32 33 import com.puppycrawl.tools.checkstyle.api.AbstractCheck; 34 import com.puppycrawl.tools.checkstyle.api.DetailAST; 35 import com.puppycrawl.tools.checkstyle.api.TokenTypes; 36 37 /** 38 * Checks that there is no empty line between a javadoc and it's subject. 39 * 40 * <p>You can't have empty lines between javadoc block and 41 * a class/method/variable. They should stay together, always. 42 * 43 * @since 0.3 44 */ 45 public final class JavadocLocationCheck extends AbstractCheck { 46 47 @Override 48 public int[] getDefaultTokens() { 49 return new int[] { 50 TokenTypes.CLASS_DEF, 51 TokenTypes.INTERFACE_DEF, 52 TokenTypes.VARIABLE_DEF, 53 TokenTypes.CTOR_DEF, 54 TokenTypes.METHOD_DEF, 55 }; 56 } 57 58 @Override 59 public int[] getAcceptableTokens() { 60 return this.getDefaultTokens(); 61 } 62 63 @Override 64 public int[] getRequiredTokens() { 65 return this.getDefaultTokens(); 66 } 67 68 @Override 69 public void visitToken(final DetailAST ast) { 70 if (!JavadocLocationCheck.isField(ast)) { 71 return; 72 } 73 final String[] lines = this.getLines(); 74 int current = ast.getLineNo(); 75 boolean found = false; 76 final int start = current; 77 --current; 78 while (true) { 79 if (current <= 0) { 80 break; 81 } 82 final String line = lines[current - 1].trim(); 83 if (line.endsWith("*/")) { 84 found = true; 85 break; 86 } 87 if (!line.isEmpty()) { 88 break; 89 } 90 --current; 91 } 92 if (found) { 93 this.report(start, current); 94 } 95 } 96 97 /** 98 * Report empty lines between current and end line. 99 * @param current Current line 100 * @param end Final line 101 */ 102 private void report(final int current, final int end) { 103 final int diff = current - end; 104 if (diff > 1) { 105 for (int pos = 1; pos < diff; pos += 1) { 106 this.log( 107 end + pos, 108 "Empty line between javadoc and subject" 109 ); 110 } 111 } 112 } 113 114 /** 115 * Returns {@code TRUE} if a specified node is something that should have 116 * a Javadoc, which includes classes, interface, class methods, and 117 * class variables. 118 * @param node Node to check 119 * @return Is it a Javadoc-required entity? 120 */ 121 private static boolean isField(final DetailAST node) { 122 boolean yes = true; 123 if (TokenTypes.VARIABLE_DEF == node.getType()) { 124 yes = TokenTypes.OBJBLOCK == node.getParent().getType(); 125 } 126 return yes; 127 } 128 }