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.Iterator;
13 import java.util.List;
14
15 public class PositionalIteratorRule extends AbstractRule {
16
17 public Object visit(ASTWhileStatement node, Object data) {
18 if (hasNameAsChild((SimpleNode) node.jjtGetChild(0))) {
19 String exprName = getName((SimpleNode) node.jjtGetChild(0));
20 if (exprName.indexOf(".hasNext") != -1 && node.jjtGetNumChildren() > 1) {
21
22 SimpleNode loopBody = (SimpleNode) node.jjtGetChild(1);
23 List names = new ArrayList();
24 collectNames(getVariableName(exprName), names, loopBody);
25 int nextCount = 0;
26 for (Iterator i = names.iterator(); i.hasNext();) {
27 String name = (String) i.next();
28 if (name.indexOf(".next") != -1) {
29 nextCount++;
30 }
31 }
32
33 if (nextCount > 1) {
34 addViolation(data, node);
35 }
36
37 }
38 }
39 return null;
40 }
41
42 private String getVariableName(String exprName) {
43 return exprName.substring(0, exprName.indexOf('.'));
44 }
45
46 private void collectNames(String target, List names, SimpleNode node) {
47 for (int i = 0; i < node.jjtGetNumChildren(); i++) {
48 SimpleNode child = (SimpleNode) node.jjtGetChild(i);
49 if (child.jjtGetNumChildren() > 0) {
50 collectNames(target, names, child);
51 } else {
52 if (child instanceof ASTName && isQualifiedName(child) && target.equals(getVariableName(child.getImage()))) {
53 names.add(child.getImage());
54 }
55 }
56 }
57 }
58
59 private boolean hasNameAsChild(SimpleNode node) {
60 while (node.jjtGetNumChildren() > 0) {
61 if (node.jjtGetChild(0) instanceof ASTName) {
62 return true;
63 }
64 return hasNameAsChild((SimpleNode) node.jjtGetChild(0));
65 }
66 return false;
67 }
68
69 private String getName(SimpleNode node) {
70 while (node.jjtGetNumChildren() > 0) {
71 if (node.jjtGetChild(0) instanceof ASTName) {
72 return ((ASTName) node.jjtGetChild(0)).getImage();
73 }
74 return getName((SimpleNode) node.jjtGetChild(0));
75 }
76 throw new IllegalArgumentException("Check with hasNameAsChild() first!");
77 }
78 }