001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2022 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.PropertyType; 027import com.puppycrawl.tools.checkstyle.StatelessCheck; 028import com.puppycrawl.tools.checkstyle.XdocsPropertyType; 029import com.puppycrawl.tools.checkstyle.api.DetailAST; 030import com.puppycrawl.tools.checkstyle.api.DetailNode; 031import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes; 032import com.puppycrawl.tools.checkstyle.api.TokenTypes; 033import com.puppycrawl.tools.checkstyle.utils.JavadocUtil; 034import com.puppycrawl.tools.checkstyle.utils.TokenUtil; 035 036/** 037 * <p> 038 * Checks the order of 039 * <a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDBEFIF"> 040 * javadoc block-tags or javadoc tags</a>. 041 * </p> 042 * <p> 043 * Note: Google used the term "at-clauses" for block tags in their guide till 2017-02-28. 044 * </p> 045 * 046 * <ul> 047 * <li> 048 * Property {@code violateExecutionOnNonTightHtml} - Control when to print violations if the 049 * Javadoc being examined by this check violates the tight html rules defined at 050 * <a href="https://checkstyle.org/writingjavadocchecks.html#Tight-HTML_rules">Tight-HTML Rules</a>. 051 * Type is {@code boolean}. 052 * Default value is {@code false}. 053 * </li> 054 * <li> 055 * Property {@code target} - Specify the list of block tags targeted. 056 * Type is {@code java.lang.String[]}. 057 * Validation type is {@code tokenTypesSet}. 058 * Default value is 059 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CLASS_DEF"> 060 * CLASS_DEF</a>, 061 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INTERFACE_DEF"> 062 * INTERFACE_DEF</a>, 063 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_DEF"> 064 * ENUM_DEF</a>, 065 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#METHOD_DEF"> 066 * METHOD_DEF</a>, 067 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CTOR_DEF"> 068 * CTOR_DEF</a>, 069 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#VARIABLE_DEF"> 070 * VARIABLE_DEF</a>, 071 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#RECORD_DEF"> 072 * RECORD_DEF</a>, 073 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#COMPACT_CTOR_DEF"> 074 * COMPACT_CTOR_DEF</a>. 075 * </li> 076 * <li> 077 * Property {@code tagOrder} - Specify the order by tags. 078 * Type is {@code java.lang.String[]}. 079 * Default value is 080 * {@code @author, @deprecated, @exception, @param, @return, @see, @serial, @serialData, @serialField, @since, @throws, @version}. 081 * </li> 082 * </ul> 083 * <p> 084 * To configure the default check: 085 * </p> 086 * <pre> 087 * <module name="AtclauseOrder"/> 088 * </pre> 089 * <p> 090 * Example: 091 * </p> 092 * <pre> 093 * /** 094 * * Some javadoc. // OK 095 * * 096 * * @author Some javadoc. // OK 097 * * @version Some javadoc. // OK 098 * * @param Some javadoc. // OK 099 * * @return Some javadoc. // OK 100 * * @throws Some javadoc. // OK 101 * * @exception Some javadoc. // OK 102 * * @see Some javadoc. // OK 103 * * @since Some javadoc. // OK 104 * * @serial Some javadoc. // OK 105 * * @serialField // OK 106 * * @serialData // OK 107 * * @deprecated Some javadoc. // OK 108 * */ 109 * 110 * class Valid implements Serializable 111 * { 112 * } 113 * 114 * /** 115 * * Some javadoc. 116 * * 117 * * @since Some javadoc. // OK 118 * * @version Some javadoc. // Violation - wrong order 119 * * @deprecated 120 * * @see Some javadoc. // Violation - wrong order 121 * * @author Some javadoc. // Violation - wrong order 122 * */ 123 * 124 * class Invalid implements Serializable 125 * { 126 * } 127 * </pre> 128 * <p> 129 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} 130 * </p> 131 * <p> 132 * Violation Message Keys: 133 * </p> 134 * <ul> 135 * <li> 136 * {@code at.clause.order} 137 * </li> 138 * <li> 139 * {@code javadoc.missed.html.close} 140 * </li> 141 * <li> 142 * {@code javadoc.parse.rule.error} 143 * </li> 144 * <li> 145 * {@code javadoc.wrong.singleton.html.tag} 146 * </li> 147 * </ul> 148 * 149 * @since 6.0 150 */ 151@StatelessCheck 152public class AtclauseOrderCheck extends AbstractJavadocCheck { 153 154 /** 155 * A key is pointing to the warning message text in "messages.properties" 156 * file. 157 */ 158 public static final String MSG_KEY = "at.clause.order"; 159 160 /** 161 * Default order of atclauses. 162 */ 163 private static final String[] DEFAULT_ORDER = { 164 "@author", "@version", 165 "@param", "@return", 166 "@throws", "@exception", 167 "@see", "@since", 168 "@serial", "@serialField", 169 "@serialData", "@deprecated", 170 }; 171 172 /** 173 * Specify the list of block tags targeted. 174 */ 175 @XdocsPropertyType(PropertyType.TOKEN_ARRAY) 176 private List<Integer> target = Arrays.asList( 177 TokenTypes.CLASS_DEF, 178 TokenTypes.INTERFACE_DEF, 179 TokenTypes.ENUM_DEF, 180 TokenTypes.METHOD_DEF, 181 TokenTypes.CTOR_DEF, 182 TokenTypes.VARIABLE_DEF, 183 TokenTypes.RECORD_DEF, 184 TokenTypes.COMPACT_CTOR_DEF 185 ); 186 187 /** 188 * Specify the order by tags. 189 */ 190 private List<String> tagOrder = Arrays.asList(DEFAULT_ORDER); 191 192 /** 193 * Setter to specify the list of block tags targeted. 194 * 195 * @param targets user's targets. 196 */ 197 public void setTarget(String... targets) { 198 final List<Integer> customTarget = new ArrayList<>(); 199 for (String temp : targets) { 200 customTarget.add(TokenUtil.getTokenId(temp.trim())); 201 } 202 target = customTarget; 203 } 204 205 /** 206 * Setter to specify the order by tags. 207 * 208 * @param orders user's orders. 209 */ 210 public void setTagOrder(String... orders) { 211 final List<String> customOrder = new ArrayList<>(); 212 for (String order : orders) { 213 customOrder.add(order.trim()); 214 } 215 tagOrder = customOrder; 216 } 217 218 @Override 219 public int[] getDefaultJavadocTokens() { 220 return new int[] { 221 JavadocTokenTypes.JAVADOC, 222 }; 223 } 224 225 @Override 226 public int[] getRequiredJavadocTokens() { 227 return getAcceptableJavadocTokens(); 228 } 229 230 @Override 231 public void visitJavadocToken(DetailNode ast) { 232 final int parentType = getParentType(getBlockCommentAst()); 233 234 if (target.contains(parentType)) { 235 checkOrderInTagSection(ast); 236 } 237 } 238 239 /** 240 * Checks order of atclauses in tag section node. 241 * 242 * @param javadoc Javadoc root node. 243 */ 244 private void checkOrderInTagSection(DetailNode javadoc) { 245 int maxIndexOfPreviousTag = 0; 246 247 for (DetailNode node : javadoc.getChildren()) { 248 if (node.getType() == JavadocTokenTypes.JAVADOC_TAG) { 249 final String tagText = JavadocUtil.getFirstChild(node).getText(); 250 final int indexOfCurrentTag = tagOrder.indexOf(tagText); 251 252 if (indexOfCurrentTag != -1) { 253 if (indexOfCurrentTag < maxIndexOfPreviousTag) { 254 log(node.getLineNumber(), MSG_KEY, tagOrder.toString()); 255 } 256 else { 257 maxIndexOfPreviousTag = indexOfCurrentTag; 258 } 259 } 260 } 261 } 262 } 263 264 /** 265 * Returns type of parent node. 266 * 267 * @param commentBlock child node. 268 * @return parent type. 269 */ 270 private static int getParentType(DetailAST commentBlock) { 271 final DetailAST parentNode = commentBlock.getParent(); 272 int result = parentNode.getType(); 273 if (result == TokenTypes.TYPE || result == TokenTypes.MODIFIERS) { 274 result = parentNode.getParent().getType(); 275 } 276 else if (parentNode.getParent() != null 277 && parentNode.getParent().getType() == TokenTypes.MODIFIERS) { 278 result = parentNode.getParent().getParent().getType(); 279 } 280 return result; 281 } 282 283}