1 /** 2 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html 3 */ 4 package net.sourceforge.pmd.rules.design; 5 6 import net.sourceforge.pmd.AbstractRule; 7 import net.sourceforge.pmd.ast.ASTName; 8 import net.sourceforge.pmd.ast.ASTWhileStatement; 9 import net.sourceforge.pmd.ast.SimpleNode; 10 11 import java.util.ArrayList; 12 import java.util.List; 13 14 public class PositionalIteratorRule extends AbstractRule { 15 16 public Object visit(ASTWhileStatement node, Object data) { 17 if (hasNameAsChild((SimpleNode) node.jjtGetChild(0))) { 18 String exprName = getName((SimpleNode) node.jjtGetChild(0)); 19 if (exprName.indexOf(".hasNext") != -1 && node.jjtGetNumChildren() > 1) { 20 21 SimpleNode loopBody = (SimpleNode) node.jjtGetChild(1); 22 List<String> names = new ArrayList<String>(); 23 collectNames(getVariableName(exprName), names, loopBody); 24 int nextCount = 0; 25 for (String name: names) { 26 if (name.indexOf(".next") != -1) { 27 nextCount++; 28 } 29 } 30 31 if (nextCount > 1) { 32 addViolation(data, node); 33 } 34 35 } 36 } 37 return null; 38 } 39 40 private String getVariableName(String exprName) { 41 return exprName.substring(0, exprName.indexOf('.')); 42 } 43 44 private void collectNames(String target, List<String> names, SimpleNode node) { 45 for (int i = 0; i < node.jjtGetNumChildren(); i++) { 46 SimpleNode child = (SimpleNode) node.jjtGetChild(i); 47 if (child.jjtGetNumChildren() > 0) { 48 collectNames(target, names, child); 49 } else { 50 if (child instanceof ASTName && isQualifiedName(child) && target.equals(getVariableName(child.getImage()))) { 51 names.add(child.getImage()); 52 } 53 } 54 } 55 } 56 57 private boolean hasNameAsChild(SimpleNode node) { 58 while (node.jjtGetNumChildren() > 0) { 59 if (node.jjtGetChild(0) instanceof ASTName) { 60 return true; 61 } 62 return hasNameAsChild((SimpleNode) node.jjtGetChild(0)); 63 } 64 return false; 65 } 66 67 private String getName(SimpleNode node) { 68 while (node.jjtGetNumChildren() > 0) { 69 if (node.jjtGetChild(0) instanceof ASTName) { 70 return ((ASTName) node.jjtGetChild(0)).getImage(); 71 } 72 return getName((SimpleNode) node.jjtGetChild(0)); 73 } 74 throw new IllegalArgumentException("Check with hasNameAsChild() first!"); 75 } 76 }