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