001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2026 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.Arrays; 023import java.util.BitSet; 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.JavadocCommentsTokenTypes; 032import com.puppycrawl.tools.checkstyle.api.TokenTypes; 033import com.puppycrawl.tools.checkstyle.internal.annotation.PreserveOrder; 034import com.puppycrawl.tools.checkstyle.utils.JavadocUtil; 035import com.puppycrawl.tools.checkstyle.utils.TokenUtil; 036 037/** 038 * <div> 039 * Checks the order of 040 * <a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html#CHDBEFIF"> 041 * javadoc block-tags or javadoc tags</a>. 042 * </div> 043 * 044 * <p> 045 * Note: Google used the term "at-clauses" for block tags in their guide till 2017-02-28. 046 * </p> 047 * 048 * @since 6.0 049 */ 050@StatelessCheck 051public class AtclauseOrderCheck extends AbstractJavadocCheck { 052 053 /** 054 * A key is pointing to the warning message text in "messages.properties" file. 055 */ 056 public static final String MSG_KEY = "at.clause.order"; 057 058 /** 059 * Default order of atclauses. 060 */ 061 private static final String[] DEFAULT_ORDER = { 062 "@author", "@version", 063 "@param", "@return", 064 "@throws", "@exception", 065 "@see", "@since", 066 "@serial", "@serialField", 067 "@serialData", "@deprecated", 068 }; 069 070 /** 071 * Specify block tags targeted. 072 */ 073 @XdocsPropertyType(PropertyType.TOKEN_ARRAY) 074 private BitSet target = TokenUtil.asBitSet( 075 TokenTypes.CLASS_DEF, 076 TokenTypes.INTERFACE_DEF, 077 TokenTypes.ENUM_DEF, 078 TokenTypes.METHOD_DEF, 079 TokenTypes.CTOR_DEF, 080 TokenTypes.VARIABLE_DEF, 081 TokenTypes.RECORD_DEF, 082 TokenTypes.COMPACT_CTOR_DEF 083 ); 084 085 /** 086 * Specify the order by tags. 087 * Default value is 088 * {@literal @}author, {@literal @}version, {@literal @}param, {@literal @}return, 089 * {@literal @}throws, {@literal @}exception, {@literal @}see, {@literal @}since, 090 * {@literal @}serial, {@literal @}serialField, {@literal @}serialData, {@literal @}deprecated. 091 */ 092 @PreserveOrder 093 private List<String> tagOrder = Arrays.asList(DEFAULT_ORDER); 094 095 /** 096 * Creates a new {@code AtclauseOrderCheck} instance. 097 */ 098 public AtclauseOrderCheck() { 099 // no code by default 100 } 101 102 /** 103 * Setter to specify block tags targeted. 104 * 105 * @param targets user's targets. 106 * @since 6.0 107 */ 108 public void setTarget(String... targets) { 109 target = TokenUtil.asBitSet(targets); 110 } 111 112 /** 113 * Setter to specify the order by tags. 114 * 115 * @param orders user's orders. 116 * @since 6.0 117 */ 118 public void setTagOrder(String... orders) { 119 tagOrder = Arrays.asList(orders); 120 } 121 122 @Override 123 public int[] getDefaultJavadocTokens() { 124 return new int[] { 125 JavadocCommentsTokenTypes.JAVADOC_CONTENT, 126 }; 127 } 128 129 @Override 130 public int[] getRequiredJavadocTokens() { 131 return getAcceptableJavadocTokens(); 132 } 133 134 @Override 135 public void visitJavadocToken(DetailNode ast) { 136 final int parentType = getParentType(getBlockCommentAst()); 137 138 if (target.get(parentType)) { 139 checkOrderInTagSection(ast); 140 } 141 } 142 143 /** 144 * Checks order of atclauses in tag section node. 145 * 146 * @param javadoc Javadoc root node. 147 */ 148 private void checkOrderInTagSection(DetailNode javadoc) { 149 int maxIndexOfPreviousTag = 0; 150 DetailNode node = javadoc.getFirstChild(); 151 152 while (node != null) { 153 if (node.getType() == JavadocCommentsTokenTypes.JAVADOC_BLOCK_TAG) { 154 final String tagText = JavadocUtil.getTagName(node); 155 final int indexOfCurrentTag = tagOrder.indexOf("@" + tagText); 156 157 if (indexOfCurrentTag != -1) { 158 if (indexOfCurrentTag < maxIndexOfPreviousTag) { 159 log(node.getLineNumber(), MSG_KEY, tagOrder.toString()); 160 } 161 else { 162 maxIndexOfPreviousTag = indexOfCurrentTag; 163 } 164 } 165 } 166 node = node.getNextSibling(); 167 } 168 } 169 170 /** 171 * Returns type of parent node. 172 * 173 * @param commentBlock child node. 174 * @return parent type. 175 */ 176 private static int getParentType(DetailAST commentBlock) { 177 final DetailAST parentNode = commentBlock.getParent(); 178 int result = parentNode.getType(); 179 if (result == TokenTypes.TYPE || result == TokenTypes.MODIFIERS) { 180 result = parentNode.getParent().getType(); 181 } 182 else if (parentNode.getParent() != null 183 && parentNode.getParent().getType() == TokenTypes.MODIFIERS) { 184 result = parentNode.getParent().getParent().getType(); 185 } 186 return result; 187 } 188 189}