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