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.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 /** 074 * Default order of atclauses. 075 */ 076 private static final String[] DEFAULT_ORDER = { 077 "@author", "@version", 078 "@param", "@return", 079 "@throws", "@exception", 080 "@see", "@since", 081 "@serial", "@serialField", 082 "@serialData", "@deprecated", 083 }; 084 085 /** 086 * Default target of checking atclauses. 087 */ 088 private List<Integer> target = Arrays.asList( 089 TokenTypes.CLASS_DEF, 090 TokenTypes.INTERFACE_DEF, 091 TokenTypes.ENUM_DEF, 092 TokenTypes.METHOD_DEF, 093 TokenTypes.CTOR_DEF, 094 TokenTypes.VARIABLE_DEF 095 ); 096 097 /** 098 * Order of atclauses. 099 */ 100 private List<String> tagOrder = Arrays.asList(DEFAULT_ORDER); 101 102 /** 103 * Sets custom targets. 104 * @param targets user's targets. 105 */ 106 public void setTarget(String... targets) { 107 final List<Integer> customTarget = new ArrayList<>(); 108 for (String temp : targets) { 109 customTarget.add(TokenUtils.getTokenId(temp.trim())); 110 } 111 target = customTarget; 112 } 113 114 /** 115 * Sets custom order of atclauses. 116 * @param orders user's orders. 117 */ 118 public void setTagOrder(String... orders) { 119 final List<String> customOrder = new ArrayList<>(); 120 for (String order : orders) { 121 customOrder.add(order.trim()); 122 } 123 tagOrder = customOrder; 124 } 125 126 @Override 127 public int[] getDefaultJavadocTokens() { 128 return new int[] { 129 JavadocTokenTypes.JAVADOC, 130 }; 131 } 132 133 @Override 134 public int[] getAcceptableTokens() { 135 return new int[] {TokenTypes.BLOCK_COMMENT_BEGIN}; 136 } 137 138 @Override 139 public int[] getRequiredTokens() { 140 return getAcceptableTokens(); 141 } 142 143 @Override 144 public void visitJavadocToken(DetailNode ast) { 145 final int parentType = getParentType(getBlockCommentAst()); 146 147 if (target.contains(parentType)) { 148 checkOrderInTagSection(ast); 149 } 150 } 151 152 /** 153 * Checks order of atclauses in tag section node. 154 * @param javadoc Javadoc root node. 155 */ 156 private void checkOrderInTagSection(DetailNode javadoc) { 157 int maxIndexOfPreviousTag = 0; 158 159 for (DetailNode node : javadoc.getChildren()) { 160 if (node.getType() == JavadocTokenTypes.JAVADOC_TAG) { 161 final String tagText = JavadocUtils.getFirstChild(node).getText(); 162 final int indexOfCurrentTag = tagOrder.indexOf(tagText); 163 164 if (indexOfCurrentTag != -1) { 165 if (indexOfCurrentTag < maxIndexOfPreviousTag) { 166 log(node.getLineNumber(), MSG_KEY, tagOrder.toString()); 167 } 168 else { 169 maxIndexOfPreviousTag = indexOfCurrentTag; 170 } 171 } 172 } 173 } 174 } 175 176 /** 177 * Returns type of parent node. 178 * @param commentBlock child node. 179 * @return parent type. 180 */ 181 private static int getParentType(DetailAST commentBlock) { 182 final DetailAST parentNode = commentBlock.getParent(); 183 int type = parentNode.getType(); 184 if (type == TokenTypes.TYPE || type == TokenTypes.MODIFIERS) { 185 type = parentNode.getParent().getType(); 186 } 187 return type; 188 } 189}