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.coding; 021 022import java.util.ArrayDeque; 023import java.util.Deque; 024 025import com.puppycrawl.tools.checkstyle.api.Check; 026import com.puppycrawl.tools.checkstyle.api.DetailAST; 027import com.puppycrawl.tools.checkstyle.api.Scope; 028import com.puppycrawl.tools.checkstyle.api.TokenTypes; 029import com.puppycrawl.tools.checkstyle.utils.ScopeUtils; 030 031/** 032 * Checks that the parts of a class or interface declaration 033 * appear in the order suggested by the 034 * <a 035 * href="http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-141855.html#1852" 036 * >Code Conventions for the Java Programming Language</a>. 037 * 038 * 039 * <ol> 040 * <li> Class (static) variables. First the public class variables, then 041 * the protected, then package level (no access modifier), and then 042 * the private. </li> 043 * <li> Instance variables. First the public class variables, then 044 * the protected, then package level (no access modifier), and then 045 * the private. </li> 046 * <li> Constructors </li> 047 * <li> Methods </li> 048 * </ol> 049 * 050 * <p>Available options: 051 * <ul> 052 * <li>ignoreModifiers</li> 053 * <li>ignoreConstructors</li> 054 * </ul> 055 * 056 * <p>Purpose of <b>ignore*</b> option is to ignore related violations, 057 * however it still impacts on other class members. 058 * 059 * <p>For example: 060 * <pre>{@code 061 * class K { 062 * int a; 063 * void m(){} 064 * K(){} <-- "Constructor definition in wrong order" 065 * int b; <-- "Instance variable definition in wrong order" 066 * } 067 * }</pre> 068 * 069 * <p>With <b>ignoreConstructors</b> option: 070 * <pre>{@code 071 * class K { 072 * int a; 073 * void m(){} 074 * K(){} 075 * int b; <-- "Instance variable definition in wrong order" 076 * } 077 * }</pre> 078 * 079 * <p>With <b>ignoreConstructors</b> option and without a method definition in a source class: 080 * <pre>{@code 081 * class K { 082 * int a; 083 * K(){} 084 * int b; <-- "Instance variable definition in wrong order" 085 * } 086 * }</pre> 087 * 088 * <p>An example of how to configure the check is: 089 * 090 * <pre> 091 * <module name="DeclarationOrder"/> 092 * </pre> 093 * 094 * @author r_auckenthaler 095 */ 096public class DeclarationOrderCheck extends Check { 097 098 /** 099 * A key is pointing to the warning message text in "messages.properties" 100 * file. 101 */ 102 public static final String MSG_CONSTRUCTOR = "declaration.order.constructor"; 103 104 /** 105 * A key is pointing to the warning message text in "messages.properties" 106 * file. 107 */ 108 public static final String MSG_STATIC = "declaration.order.static"; 109 110 /** 111 * A key is pointing to the warning message text in "messages.properties" 112 * file. 113 */ 114 public static final String MSG_INSTANCE = "declaration.order.instance"; 115 116 /** 117 * A key is pointing to the warning message text in "messages.properties" 118 * file. 119 */ 120 public static final String MSG_ACCESS = "declaration.order.access"; 121 122 /** State for the VARIABLE_DEF. */ 123 private static final int STATE_STATIC_VARIABLE_DEF = 1; 124 125 /** State for the VARIABLE_DEF. */ 126 private static final int STATE_INSTANCE_VARIABLE_DEF = 2; 127 128 /** State for the CTOR_DEF. */ 129 private static final int STATE_CTOR_DEF = 3; 130 131 /** State for the METHOD_DEF. */ 132 private static final int STATE_METHOD_DEF = 4; 133 134 /** 135 * List of Declaration States. This is necessary due to 136 * inner classes that have their own state 137 */ 138 private final Deque<ScopeState> scopeStates = new ArrayDeque<>(); 139 140 /** If true, ignores the check to constructors. */ 141 private boolean ignoreConstructors; 142 /** If true, ignore the check to modifiers (fields, ...). */ 143 private boolean ignoreModifiers; 144 145 @Override 146 public int[] getDefaultTokens() { 147 return getAcceptableTokens(); 148 } 149 150 @Override 151 public int[] getAcceptableTokens() { 152 return new int[] { 153 TokenTypes.CTOR_DEF, 154 TokenTypes.METHOD_DEF, 155 TokenTypes.MODIFIERS, 156 TokenTypes.OBJBLOCK, 157 }; 158 } 159 160 @Override 161 public int[] getRequiredTokens() { 162 return getAcceptableTokens(); 163 } 164 165 @Override 166 public void visitToken(DetailAST ast) { 167 final int parentType = ast.getParent().getType(); 168 169 switch (ast.getType()) { 170 case TokenTypes.OBJBLOCK: 171 scopeStates.push(new ScopeState()); 172 break; 173 case TokenTypes.MODIFIERS: 174 if (parentType == TokenTypes.VARIABLE_DEF 175 && ast.getParent().getParent().getType() == TokenTypes.OBJBLOCK) { 176 processModifiers(ast); 177 } 178 break; 179 case TokenTypes.CTOR_DEF: 180 if (parentType == TokenTypes.OBJBLOCK) { 181 processConstructor(ast); 182 } 183 break; 184 case TokenTypes.METHOD_DEF: 185 if (parentType == TokenTypes.OBJBLOCK) { 186 final ScopeState state = scopeStates.peek(); 187 // nothing can be bigger than method's state 188 state.currentScopeState = STATE_METHOD_DEF; 189 } 190 break; 191 default: 192 break; 193 } 194 } 195 196 /** 197 * Process constructor. 198 * @param ast constructor AST 199 */ 200 private void processConstructor(DetailAST ast) { 201 202 final ScopeState state = scopeStates.peek(); 203 if (state.currentScopeState > STATE_CTOR_DEF) { 204 if (!ignoreConstructors) { 205 log(ast, MSG_CONSTRUCTOR); 206 } 207 } 208 else { 209 state.currentScopeState = STATE_CTOR_DEF; 210 } 211 } 212 213 /** 214 * Process modifiers. 215 * @param ast ast of Modifiers 216 */ 217 private void processModifiers(DetailAST ast) { 218 219 final ScopeState state = scopeStates.peek(); 220 if (ast.findFirstToken(TokenTypes.LITERAL_STATIC) == null) { 221 if (state.currentScopeState > STATE_INSTANCE_VARIABLE_DEF) { 222 log(ast, MSG_INSTANCE); 223 } 224 else if (state.currentScopeState == STATE_STATIC_VARIABLE_DEF) { 225 state.declarationAccess = Scope.PUBLIC; 226 state.currentScopeState = STATE_INSTANCE_VARIABLE_DEF; 227 } 228 } 229 else { 230 if (state.currentScopeState > STATE_STATIC_VARIABLE_DEF) { 231 if (!ignoreModifiers 232 || state.currentScopeState > STATE_INSTANCE_VARIABLE_DEF) { 233 log(ast, MSG_STATIC); 234 } 235 } 236 else { 237 state.currentScopeState = STATE_STATIC_VARIABLE_DEF; 238 } 239 } 240 241 final Scope access = ScopeUtils.getScopeFromMods(ast); 242 if (state.declarationAccess.compareTo(access) > 0) { 243 if (!ignoreModifiers) { 244 log(ast, MSG_ACCESS); 245 } 246 } 247 else { 248 state.declarationAccess = access; 249 } 250 } 251 252 @Override 253 public void leaveToken(DetailAST ast) { 254 if (ast.getType() == TokenTypes.OBJBLOCK) { 255 scopeStates.pop(); 256 } 257 } 258 259 /** 260 * Sets whether to ignore constructors. 261 * @param ignoreConstructors whether to ignore constructors. 262 */ 263 public void setIgnoreConstructors(boolean ignoreConstructors) { 264 this.ignoreConstructors = ignoreConstructors; 265 } 266 267 /** 268 * Sets whether to ignore modifiers. 269 * @param ignoreModifiers whether to ignore modifiers. 270 */ 271 public void setIgnoreModifiers(boolean ignoreModifiers) { 272 this.ignoreModifiers = ignoreModifiers; 273 } 274 275 /** 276 * Private class to encapsulate the state. 277 */ 278 private static class ScopeState { 279 /** The state the check is in. */ 280 private int currentScopeState = STATE_STATIC_VARIABLE_DEF; 281 282 /** The sub-state the check is in. */ 283 private Scope declarationAccess = Scope.PUBLIC; 284 } 285}