001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2016 the original author or authors. 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018//////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle.checks.javadoc; 021 022import java.util.ArrayList; 023import java.util.List; 024 025import com.puppycrawl.tools.checkstyle.api.DetailNode; 026import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes; 027import com.puppycrawl.tools.checkstyle.api.TokenTypes; 028import com.puppycrawl.tools.checkstyle.utils.JavadocUtils; 029 030/** 031 * <p> 032 * Checks the indentation of the continuation lines in at-clauses. 033 * </p> 034 * <p> 035 * Default configuration: 036 * </p> 037 * <pre> 038 * <module name="JavadocTagContinuationIndentation"> 039 * <property name="offset" value="4"/> 040 * </module> 041 * </pre> 042 * 043 * @author max 044 * 045 */ 046public class JavadocTagContinuationIndentationCheck extends AbstractJavadocCheck { 047 048 /** 049 * A key is pointing to the warning message text in "messages.properties" 050 * file. 051 */ 052 public static final String MSG_KEY = "tag.continuation.indent"; 053 054 /** Default tag continuation indentation. */ 055 private static final int DEFAULT_INDENTATION = 4; 056 057 /** 058 * How many spaces to use for new indentation level. 059 */ 060 private int offset = DEFAULT_INDENTATION; 061 062 /** 063 * Sets custom indentation level. 064 * @param offset custom value. 065 */ 066 public void setOffset(int offset) { 067 this.offset = offset; 068 } 069 070 @Override 071 public int[] getDefaultJavadocTokens() { 072 return new int[] {JavadocTokenTypes.DESCRIPTION }; 073 } 074 075 @Override 076 public int[] getAcceptableTokens() { 077 return new int[] {TokenTypes.BLOCK_COMMENT_BEGIN }; 078 } 079 080 @Override 081 public int[] getRequiredTokens() { 082 return getAcceptableTokens(); 083 } 084 085 @Override 086 public void visitJavadocToken(DetailNode ast) { 087 if (!isInlineDescription(ast)) { 088 final List<DetailNode> textNodes = getAllNewlineNodes(ast); 089 for (DetailNode newlineNode : textNodes) { 090 final DetailNode textNode = JavadocUtils.getNextSibling(JavadocUtils 091 .getNextSibling(newlineNode)); 092 if (textNode != null && textNode.getType() == JavadocTokenTypes.TEXT 093 && textNode.getChildren().length > 1) { 094 final DetailNode whitespace = JavadocUtils.getFirstChild(textNode); 095 if (whitespace.getText().length() - 1 < offset) { 096 log(textNode.getLineNumber(), MSG_KEY, offset); 097 } 098 } 099 } 100 } 101 } 102 103 /** 104 * Finds and collects all NEWLINE nodes inside DESCRIPTION node. 105 * @param descriptionNode DESCRIPTION node. 106 * @return List with NEWLINE nodes. 107 */ 108 private static List<DetailNode> getAllNewlineNodes(DetailNode descriptionNode) { 109 final List<DetailNode> textNodes = new ArrayList<>(); 110 DetailNode node = JavadocUtils.getFirstChild(descriptionNode); 111 while (JavadocUtils.getNextSibling(node) != null) { 112 if (node.getType() == JavadocTokenTypes.NEWLINE) { 113 textNodes.add(node); 114 } 115 node = JavadocUtils.getNextSibling(node); 116 } 117 return textNodes; 118 } 119 120 /** 121 * Checks, if description node is a description of in-line tag. 122 * @param description DESCRIPTION node. 123 * @return true, if description node is a description of in-line tag. 124 */ 125 private static boolean isInlineDescription(DetailNode description) { 126 DetailNode inlineTag = description.getParent(); 127 while (inlineTag != null) { 128 if (inlineTag.getType() == JavadocTokenTypes.JAVADOC_INLINE_TAG) { 129 return true; 130 } 131 inlineTag = inlineTag.getParent(); 132 } 133 return false; 134 } 135}