1 package com.puppycrawl.tools.checkstyle.checks.coding; 20 21 import java.util.HashSet ; 22 import java.util.Set ; 23 import java.util.regex.Pattern ; 24 import java.util.regex.PatternSyntaxException ; 25 26 import org.apache.commons.beanutils.ConversionException; 27 28 import com.puppycrawl.tools.checkstyle.api.Check; 29 import com.puppycrawl.tools.checkstyle.api.DetailAST; 30 import com.puppycrawl.tools.checkstyle.api.ScopeUtils; 31 import com.puppycrawl.tools.checkstyle.api.TokenTypes; 32 import com.puppycrawl.tools.checkstyle.api.Utils; 33 34 74 public class HiddenFieldCheck 75 extends Check 76 { 77 80 private FieldFrame mCurrentFrame; 81 82 83 private Pattern mRegexp; 84 85 86 private boolean mIgnoreSetter; 87 88 89 private boolean mIgnoreConstructorParameter; 90 91 92 private boolean mIgnoreAbstractMethods; 93 94 95 public int[] getDefaultTokens() 96 { 97 return new int[] { 98 TokenTypes.VARIABLE_DEF, 99 TokenTypes.PARAMETER_DEF, 100 TokenTypes.CLASS_DEF, 101 TokenTypes.ENUM_DEF, 102 TokenTypes.ENUM_CONSTANT_DEF, 103 }; 104 } 105 106 107 public int[] getAcceptableTokens() 108 { 109 return new int[] { 110 TokenTypes.VARIABLE_DEF, 111 TokenTypes.PARAMETER_DEF, 112 }; 113 } 114 115 116 public int[] getRequiredTokens() 117 { 118 return new int[] { 119 TokenTypes.CLASS_DEF, 120 TokenTypes.ENUM_DEF, 121 TokenTypes.ENUM_CONSTANT_DEF, 122 }; 123 } 124 125 126 public void beginTree(DetailAST aRootAST) 127 { 128 mCurrentFrame = new FieldFrame(null, true); 129 } 130 131 132 public void visitToken(DetailAST aAST) 133 { 134 if ((aAST.getType() == TokenTypes.VARIABLE_DEF) 135 || (aAST.getType() == TokenTypes.PARAMETER_DEF)) 136 { 137 processVariable(aAST); 138 return; 139 } 140 141 final DetailAST typeMods = aAST.findFirstToken(TokenTypes.MODIFIERS); 147 final boolean isStaticInnerType = 148 (typeMods != null) 149 && typeMods.branchContains(TokenTypes.LITERAL_STATIC); 150 final FieldFrame frame = 151 new FieldFrame(mCurrentFrame, isStaticInnerType); 152 153 final DetailAST objBlock = aAST.findFirstToken(TokenTypes.OBJBLOCK); 155 if (objBlock != null) { 157 DetailAST child = (DetailAST) objBlock.getFirstChild(); 158 while (child != null) { 159 if (child.getType() == TokenTypes.VARIABLE_DEF) { 160 final String name = 161 child.findFirstToken(TokenTypes.IDENT).getText(); 162 final DetailAST mods = 163 child.findFirstToken(TokenTypes.MODIFIERS); 164 if (mods.branchContains(TokenTypes.LITERAL_STATIC)) { 165 frame.addStaticField(name); 166 } 167 else { 168 frame.addInstanceField(name); 169 } 170 } 171 child = (DetailAST) child.getNextSibling(); 172 } 173 } 174 mCurrentFrame = frame; 176 } 177 178 179 public void leaveToken(DetailAST aAST) 180 { 181 if ((aAST.getType() == TokenTypes.CLASS_DEF) 182 || (aAST.getType() == TokenTypes.ENUM_DEF) 183 || (aAST.getType() == TokenTypes.ENUM_CONSTANT_DEF)) 184 { 185 mCurrentFrame = mCurrentFrame.getParent(); 187 } 188 } 189 190 196 private void processVariable(DetailAST aAST) 197 { 198 if (ScopeUtils.inInterfaceOrAnnotationBlock(aAST) 199 || (!ScopeUtils.isLocalVariableDef(aAST) 200 && (aAST.getType() != TokenTypes.PARAMETER_DEF))) 201 { 202 return; 204 } 205 final DetailAST nameAST = aAST.findFirstToken(TokenTypes.IDENT); 207 final String name = nameAST.getText(); 208 if ((mCurrentFrame.containsStaticField(name) 209 || (!inStatic(aAST) && mCurrentFrame.containsInstanceField(name))) 210 && ((mRegexp == null) || (!getRegexp().matcher(name).find())) 211 && !isIgnoredSetterParam(aAST, name) 212 && !isIgnoredConstructorParam(aAST) 213 && !isIgnoredParamOfAbstractMethod(aAST)) 214 { 215 log(nameAST, "hidden.field", name); 216 } 217 } 218 219 225 private static boolean inStatic(DetailAST aAST) 226 { 227 DetailAST parent = aAST.getParent(); 228 while (parent != null) { 229 switch (parent.getType()) { 230 case TokenTypes.STATIC_INIT: 231 return true; 232 case TokenTypes.METHOD_DEF: 233 final DetailAST mods = 234 parent.findFirstToken(TokenTypes.MODIFIERS); 235 return mods.branchContains(TokenTypes.LITERAL_STATIC); 236 default: 237 parent = parent.getParent(); 238 } 239 } 240 return false; 241 } 242 243 252 private boolean isIgnoredSetterParam(DetailAST aAST, String aName) 253 { 254 if (!(aAST.getType() == TokenTypes.PARAMETER_DEF) 255 || !mIgnoreSetter) 256 { 257 return false; 258 } 259 final DetailAST parametersAST = aAST.getParent(); 261 if (parametersAST.getChildCount() != 1) { 262 return false; 263 } 264 final DetailAST methodAST = parametersAST.getParent(); 266 if (methodAST.getType() != TokenTypes.METHOD_DEF) { 267 return false; 268 } 269 final String expectedName = 271 "set" + aName.substring(0, 1).toUpperCase() + aName.substring(1); 272 final DetailAST methodNameAST = 273 methodAST.findFirstToken(TokenTypes.IDENT); 274 final String methodName = methodNameAST.getText(); 275 if (!methodName.equals(expectedName)) { 276 return false; 277 } 278 final DetailAST typeAST = methodAST.findFirstToken(TokenTypes.TYPE); 280 return typeAST.branchContains(TokenTypes.LITERAL_VOID); 281 } 282 283 290 private boolean isIgnoredConstructorParam(DetailAST aAST) 291 { 292 if ((aAST.getType() != TokenTypes.PARAMETER_DEF) 293 || !mIgnoreConstructorParameter) 294 { 295 return false; 296 } 297 final DetailAST parametersAST = aAST.getParent(); 298 final DetailAST constructorAST = parametersAST.getParent(); 299 return (constructorAST.getType() == TokenTypes.CTOR_DEF); 300 } 301 302 310 private boolean isIgnoredParamOfAbstractMethod(DetailAST aAST) 311 { 312 if ((aAST.getType() != TokenTypes.PARAMETER_DEF) 313 || !mIgnoreAbstractMethods) 314 { 315 return false; 316 } 317 final DetailAST method = aAST.getParent().getParent(); 318 if (method.getType() != TokenTypes.METHOD_DEF) { 319 return false; 320 } 321 final DetailAST mods = method.findFirstToken(TokenTypes.MODIFIERS); 322 return ((mods != null) && mods.branchContains(TokenTypes.ABSTRACT)); 323 } 324 325 330 public void setIgnoreFormat(String aFormat) 331 throws ConversionException 332 { 333 try { 334 mRegexp = Utils.getPattern(aFormat); 335 } 336 catch (final PatternSyntaxException e) { 337 throw new ConversionException("unable to parse " + aFormat, e); 338 } 339 } 340 341 346 public void setIgnoreSetter(boolean aIgnoreSetter) 347 { 348 mIgnoreSetter = aIgnoreSetter; 349 } 350 351 356 public void setIgnoreConstructorParameter( 357 boolean aIgnoreConstructorParameter) 358 { 359 mIgnoreConstructorParameter = aIgnoreConstructorParameter; 360 } 361 362 367 public void setIgnoreAbstractMethods( 368 boolean aIgnoreAbstractMethods) 369 { 370 mIgnoreAbstractMethods = aIgnoreAbstractMethods; 371 } 372 373 374 public Pattern getRegexp() 375 { 376 return mRegexp; 377 } 378 379 386 private static class FieldFrame 387 { 388 389 private boolean mStaticType; 390 391 392 private FieldFrame mParent; 393 394 395 private final Set mInstanceFields = new HashSet (); 396 397 398 private final Set mStaticFields = new HashSet (); 399 400 404 public FieldFrame(FieldFrame aParent, boolean aStaticType) 405 { 406 mParent = aParent; 407 mStaticType = aStaticType; 408 } 409 410 413 boolean isStaticType() 414 { 415 return mStaticType; 416 } 417 418 422 public void addInstanceField(String aField) 423 { 424 mInstanceFields.add(aField); 425 } 426 427 431 public void addStaticField(String aField) 432 { 433 mStaticFields.add(aField); 434 } 435 436 441 public boolean containsInstanceField(String aField) 442 { 443 if (mInstanceFields.contains(aField)) { 444 return true; 445 } 446 if (mStaticType) { 447 return false; 448 } 449 450 return (mParent != null) && mParent.containsInstanceField(aField); 451 } 452 453 458 public boolean containsStaticField(String aField) 459 { 460 if (mStaticFields.contains(aField)) { 461 return true; 462 } 463 464 return (mParent != null) && mParent.containsStaticField(aField); 465 } 466 467 471 public FieldFrame getParent() 472 { 473 return mParent; 474 } 475 } 476 } 477 | Popular Tags |