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.coding; 020 021import com.puppycrawl.tools.checkstyle.api.Check; 022import com.puppycrawl.tools.checkstyle.api.DetailAST; 023import com.puppycrawl.tools.checkstyle.api.FastStack; 024import com.puppycrawl.tools.checkstyle.api.Scope; 025import com.puppycrawl.tools.checkstyle.api.ScopeUtils; 026import com.puppycrawl.tools.checkstyle.api.TokenTypes; 027 028/** 029 * <p> 030 * Checks that the parts of a class or interface declaration 031 * appear in the order suggested by the 032 * <a 033 * href="http://java.sun.com/docs/codeconv/html/CodeConventions.doc2.html#1852" 034 * >Code Conventions for the Java Programming Language</a>. 035 * 036 * 037 * <ol> 038 * <li> Class (static) variables. First the public class variables, then 039 * the protected, then package level (no access modifier), and then 040 * the private. </li> 041 * <li> Instance variables. First the public class variables, then 042 * the protected, then package level (no access modifier), and then 043 * the private. </li> 044 * <li> Constructors </li> 045 * <li> Methods </li> 046 * </ol> 047 * 048 * <p> 049 * An example of how to configure the check is: 050 * 051 * <pre> 052 * <module name="DeclarationOrder"/> 053 * </pre> 054 * 055 * @author r_auckenthaler 056 */ 057public class DeclarationOrderCheck extends Check 058{ 059 /** State for the VARIABLE_DEF */ 060 private static final int STATE_STATIC_VARIABLE_DEF = 1; 061 062 /** State for the VARIABLE_DEF */ 063 private static final int STATE_INSTANCE_VARIABLE_DEF = 2; 064 065 /** State for the CTOR_DEF */ 066 private static final int STATE_CTOR_DEF = 3; 067 068 /** State for the METHOD_DEF */ 069 private static final int STATE_METHOD_DEF = 4; 070 071 /** 072 * List of Declaration States. This is necessary due to 073 * inner classes that have their own state 074 */ 075 private final FastStack<ScopeState> scopeStates = FastStack.newInstance(); 076 077 /** 078 * private class to encapsulate the state 079 */ 080 private static class ScopeState 081 { 082 /** The state the check is in */ 083 private int scopeState = STATE_STATIC_VARIABLE_DEF; 084 085 /** The sub-state the check is in */ 086 private Scope declarationAccess = Scope.PUBLIC; 087 } 088 089 /** If true, ignores the check to constructors. */ 090 private boolean ignoreConstructors; 091 /** If true, ignore the check to methods. */ 092 private boolean ignoreMethods; 093 /** If true, ignore the check to modifiers (fields, ...). */ 094 private boolean ignoreModifiers; 095 096 @Override 097 public int[] getDefaultTokens() 098 { 099 return new int[] { 100 TokenTypes.CTOR_DEF, 101 TokenTypes.METHOD_DEF, 102 TokenTypes.MODIFIERS, 103 TokenTypes.OBJBLOCK, 104 }; 105 } 106 107 @Override 108 public void visitToken(DetailAST ast) 109 { 110 final int parentType = ast.getParent().getType(); 111 ScopeState state; 112 113 switch (ast.getType()) { 114 case TokenTypes.OBJBLOCK: 115 scopeStates.push(new ScopeState()); 116 break; 117 118 case TokenTypes.CTOR_DEF: 119 if (parentType != TokenTypes.OBJBLOCK) { 120 return; 121 } 122 123 state = scopeStates.peek(); 124 if (state.scopeState > STATE_CTOR_DEF) { 125 if (!ignoreConstructors) { 126 log(ast, "declaration.order.constructor"); 127 } 128 } 129 else { 130 state.scopeState = STATE_CTOR_DEF; 131 } 132 break; 133 134 case TokenTypes.METHOD_DEF: 135 state = scopeStates.peek(); 136 if (parentType != TokenTypes.OBJBLOCK) { 137 return; 138 } 139 140 if (state.scopeState > STATE_METHOD_DEF) { 141 if (!ignoreMethods) { 142 log(ast, "declaration.order.method"); 143 } 144 } 145 else { 146 state.scopeState = STATE_METHOD_DEF; 147 } 148 break; 149 150 case TokenTypes.MODIFIERS: 151 if ((parentType != TokenTypes.VARIABLE_DEF) 152 || (ast.getParent().getParent().getType() 153 != TokenTypes.OBJBLOCK)) 154 { 155 return; 156 } 157 158 state = scopeStates.peek(); 159 if (ast.findFirstToken(TokenTypes.LITERAL_STATIC) != null) { 160 if (state.scopeState > STATE_STATIC_VARIABLE_DEF) { 161 if (!ignoreModifiers 162 || state.scopeState > STATE_INSTANCE_VARIABLE_DEF) 163 { 164 log(ast, "declaration.order.static"); 165 } 166 } 167 else { 168 state.scopeState = STATE_STATIC_VARIABLE_DEF; 169 } 170 } 171 else { 172 if (state.scopeState > STATE_INSTANCE_VARIABLE_DEF) { 173 log(ast, "declaration.order.instance"); 174 } 175 else if (state.scopeState == STATE_STATIC_VARIABLE_DEF) { 176 state.declarationAccess = Scope.PUBLIC; 177 state.scopeState = STATE_INSTANCE_VARIABLE_DEF; 178 } 179 } 180 181 final Scope access = ScopeUtils.getScopeFromMods(ast); 182 if (state.declarationAccess.compareTo(access) > 0) { 183 if (!ignoreModifiers) { 184 log(ast, "declaration.order.access"); 185 } 186 } 187 else { 188 state.declarationAccess = access; 189 } 190 break; 191 192 default: 193 } 194 } 195 196 @Override 197 public void leaveToken(DetailAST ast) 198 { 199 switch (ast.getType()) { 200 case TokenTypes.OBJBLOCK: 201 scopeStates.pop(); 202 break; 203 204 default: 205 } 206 } 207 208 /** 209 * Sets whether to ignore constructors. 210 * @param ignoreConstructors whether to ignore constructors. 211 */ 212 public void setIgnoreConstructors(boolean ignoreConstructors) 213 { 214 this.ignoreConstructors = ignoreConstructors; 215 } 216 217 /** 218 * Sets whether to ignore methods. 219 * @param ignoreMethods whether to ignore methods. 220 */ 221 public void setIgnoreMethods(boolean ignoreMethods) 222 { 223 this.ignoreMethods = ignoreMethods; 224 } 225 226 /** 227 * Sets whether to ignore modifiers. 228 * @param ignoreModifiers whether to ignore modifiers. 229 */ 230 public void setIgnoreModifiers(boolean ignoreModifiers) 231 { 232 this.ignoreModifiers = ignoreModifiers; 233 } 234}