001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2018 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.utils.CommonUtil; 028import com.puppycrawl.tools.checkstyle.utils.JavadocUtil; 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 * 044 */ 045public class JavadocTagContinuationIndentationCheck extends AbstractJavadocCheck { 046 047 /** 048 * A key is pointing to the warning message text in "messages.properties" 049 * file. 050 */ 051 public static final String MSG_KEY = "tag.continuation.indent"; 052 053 /** Default tag continuation indentation. */ 054 private static final int DEFAULT_INDENTATION = 4; 055 056 /** 057 * How many spaces to use for new indentation level. 058 */ 059 private int offset = DEFAULT_INDENTATION; 060 061 /** 062 * Sets custom indentation level. 063 * @param offset custom value. 064 */ 065 public void setOffset(int offset) { 066 this.offset = offset; 067 } 068 069 @Override 070 public int[] getDefaultJavadocTokens() { 071 return new int[] {JavadocTokenTypes.DESCRIPTION }; 072 } 073 074 @Override 075 public int[] getRequiredJavadocTokens() { 076 return getAcceptableJavadocTokens(); 077 } 078 079 @Override 080 public void visitJavadocToken(DetailNode ast) { 081 if (!isInlineDescription(ast)) { 082 final List<DetailNode> textNodes = getAllNewlineNodes(ast); 083 for (DetailNode newlineNode : textNodes) { 084 final DetailNode textNode = JavadocUtil.getNextSibling(JavadocUtil 085 .getNextSibling(newlineNode)); 086 if (textNode != null && textNode.getType() == JavadocTokenTypes.TEXT) { 087 final String text = textNode.getText(); 088 if (!CommonUtil.isBlank(text.trim()) 089 && (text.length() <= offset 090 || !text.substring(1, offset + 1).trim().isEmpty())) { 091 log(textNode.getLineNumber(), MSG_KEY, offset); 092 } 093 } 094 } 095 } 096 } 097 098 /** 099 * Finds and collects all NEWLINE nodes inside DESCRIPTION node. 100 * @param descriptionNode DESCRIPTION node. 101 * @return List with NEWLINE nodes. 102 */ 103 private static List<DetailNode> getAllNewlineNodes(DetailNode descriptionNode) { 104 final List<DetailNode> textNodes = new ArrayList<>(); 105 DetailNode node = JavadocUtil.getFirstChild(descriptionNode); 106 while (JavadocUtil.getNextSibling(node) != null) { 107 if (node.getType() == JavadocTokenTypes.NEWLINE) { 108 textNodes.add(node); 109 } 110 node = JavadocUtil.getNextSibling(node); 111 } 112 return textNodes; 113 } 114 115 /** 116 * Checks, if description node is a description of in-line tag. 117 * @param description DESCRIPTION node. 118 * @return true, if description node is a description of in-line tag. 119 */ 120 private static boolean isInlineDescription(DetailNode description) { 121 boolean isInline = false; 122 DetailNode inlineTag = description.getParent(); 123 while (inlineTag != null) { 124 if (inlineTag.getType() == JavadocTokenTypes.JAVADOC_INLINE_TAG) { 125 isInline = true; 126 break; 127 } 128 inlineTag = inlineTag.getParent(); 129 } 130 return isInline; 131 } 132 133}