/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.rules.design; import net.sourceforge.pmd.AbstractRule; import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.ast.ASTName; import net.sourceforge.pmd.ast.ASTWhileStatement; import net.sourceforge.pmd.ast.SimpleNode; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class PositionalIteratorRule extends AbstractRule { public Object visit(ASTWhileStatement node, Object data) { if (hasNameAsChild((SimpleNode) node.jjtGetChild(0))) { String exprName = getName((SimpleNode) node.jjtGetChild(0)); if (exprName.indexOf(".hasNext") != -1 && node.jjtGetNumChildren() > 1) { SimpleNode loopBody = (SimpleNode) node.jjtGetChild(1); List names = new ArrayList(); collectNames(getVariableName(exprName), names, loopBody); int nextCount = 0; for (Iterator i = names.iterator(); i.hasNext();) { String name = (String) i.next(); if (name.indexOf(".next") != -1) { nextCount++; } } if (nextCount > 1) { RuleContext ctx = (RuleContext) data; ctx.getReport().addRuleViolation(createRuleViolation(ctx, node.getBeginLine())); } } } return null; } private String getVariableName(String exprName) { return exprName.substring(0, exprName.indexOf('.')); } private void collectNames(String target, List names, SimpleNode node) { for (int i = 0; i < node.jjtGetNumChildren(); i++) { SimpleNode child = (SimpleNode) node.jjtGetChild(i); if (child.jjtGetNumChildren() > 0) { collectNames(target, names, child); } else { if (child instanceof ASTName && child.getImage().indexOf(".") != -1 && target.equals(getVariableName(child.getImage()))) { names.add(child.getImage()); } } } } private boolean hasNameAsChild(SimpleNode node) { while (node.jjtGetNumChildren() > 0) { if (node.jjtGetChild(0) instanceof ASTName) { return true; } return hasNameAsChild((SimpleNode) node.jjtGetChild(0)); } return false; } private String getName(SimpleNode node) { while (node.jjtGetNumChildren() > 0) { if (node.jjtGetChild(0) instanceof ASTName) { return ((ASTName) node.jjtGetChild(0)).getImage(); } return getName((SimpleNode) node.jjtGetChild(0)); } throw new IllegalArgumentException("Check with hasNameAsChild() first!"); } }