001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2015 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.Arrays; 024import java.util.List; 025 026import com.puppycrawl.tools.checkstyle.api.DetailAST; 027import com.puppycrawl.tools.checkstyle.api.DetailNode; 028import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes; 029import com.puppycrawl.tools.checkstyle.api.TokenTypes; 030import com.puppycrawl.tools.checkstyle.utils.JavadocUtils; 031import com.puppycrawl.tools.checkstyle.utils.TokenUtils; 032 033/** 034 * <p> 035 * Checks the order of at-clauses. 036 * </p> 037 * 038 * <p> 039 * The check allows to configure itself by using the following properties: 040 * </p> 041 * <ul> 042 * <li> 043 * target - allows to specify targets to check at-clauses. 044 * </li> 045 * <li> 046 * tagOrder - allows to specify the order by tags. 047 * </li> 048 * </ul> 049 * <p> 050 * Default configuration: 051 * </p> 052 * <pre> 053 * <module name="AtclauseOrderCheck"> 054 * <property name="tagOrder" value="@author, @version, @param, 055 * @return, @throws, @exception, @see, @since, @serial, 056 * @serialField, @serialData, @deprecated"/> 057 * <property name="target" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, 058 * METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/> 059 * </module> 060 * </pre> 061 * 062 * @author max 063 * 064 */ 065public class AtclauseOrderCheck extends AbstractJavadocCheck { 066 067 /** 068 * A key is pointing to the warning message text in "messages.properties" 069 * file. 070 */ 071 public static final String MSG_KEY = "at.clause.order"; 072 073 /** Comma literal. */ 074 private static final String COMMA_SEPARATOR = ","; 075 /** 076 * Default order of atclauses. 077 */ 078 private static final String[] DEFAULT_ORDER = { 079 "@author", "@version", 080 "@param", "@return", 081 "@throws", "@exception", 082 "@see", "@since", 083 "@serial", "@serialField", 084 "@serialData", "@deprecated", 085 }; 086 087 /** 088 * Default target of checking atclauses. 089 */ 090 private List<Integer> target = Arrays.asList( 091 TokenTypes.CLASS_DEF, 092 TokenTypes.INTERFACE_DEF, 093 TokenTypes.ENUM_DEF, 094 TokenTypes.METHOD_DEF, 095 TokenTypes.CTOR_DEF, 096 TokenTypes.VARIABLE_DEF 097 ); 098 099 /** 100 * Order of atclauses. 101 */ 102 private List<String> tagOrder = Arrays.asList(DEFAULT_ORDER); 103 104 /** 105 * Sets custom targets. 106 * @param target user's targets. 107 */ 108 public void setTarget(String target) { 109 final List<Integer> customTarget = new ArrayList<>(); 110 final String[] sTarget = target.split(COMMA_SEPARATOR); 111 for (String aSTarget : sTarget) { 112 customTarget.add(TokenUtils.getTokenId(aSTarget.trim())); 113 } 114 this.target = customTarget; 115 } 116 117 /** 118 * Sets custom order of atclauses. 119 * @param order user's order. 120 */ 121 public void setTagOrder(String order) { 122 final List<String> customOrder = new ArrayList<>(); 123 final String[] sOrder = order.split(COMMA_SEPARATOR); 124 for (String aSOrder : sOrder) { 125 customOrder.add(aSOrder.trim()); 126 } 127 tagOrder = customOrder; 128 } 129 130 @Override 131 public int[] getDefaultJavadocTokens() { 132 return new int[] { 133 JavadocTokenTypes.JAVADOC, 134 }; 135 } 136 137 @Override 138 public int[] getAcceptableTokens() { 139 return new int[] {TokenTypes.BLOCK_COMMENT_BEGIN}; 140 } 141 142 @Override 143 public int[] getRequiredTokens() { 144 return getAcceptableTokens(); 145 } 146 147 @Override 148 public void visitJavadocToken(DetailNode ast) { 149 final int parentType = getParentType(getBlockCommentAst()); 150 151 if (target.contains(parentType)) { 152 checkOrderInTagSection(ast); 153 } 154 } 155 156 /** 157 * Checks order of atclauses in tag section node. 158 * @param javadoc Javadoc root node. 159 */ 160 private void checkOrderInTagSection(DetailNode javadoc) { 161 int maxIndexOfPreviousTag = 0; 162 163 for (DetailNode node : javadoc.getChildren()) { 164 if (node.getType() == JavadocTokenTypes.JAVADOC_TAG) { 165 final String tagText = JavadocUtils.getFirstChild(node).getText(); 166 final int indexOfCurrentTag = tagOrder.indexOf(tagText); 167 168 if (indexOfCurrentTag != -1) { 169 if (indexOfCurrentTag < maxIndexOfPreviousTag) { 170 log(node.getLineNumber(), MSG_KEY, tagOrder.toString()); 171 } 172 else { 173 maxIndexOfPreviousTag = indexOfCurrentTag; 174 } 175 } 176 } 177 } 178 } 179 180 /** 181 * Returns type of parent node. 182 * @param commentBlock child node. 183 * @return parent type. 184 */ 185 private static int getParentType(DetailAST commentBlock) { 186 int type = 0; 187 final DetailAST parentNode = commentBlock.getParent(); 188 if (parentNode != null) { 189 type = parentNode.getType(); 190 if (type == TokenTypes.TYPE || type == TokenTypes.MODIFIERS) { 191 type = parentNode.getParent().getType(); 192 } 193 } 194 return type; 195 } 196}