View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.java.rule.design;
5   
6   import java.util.ArrayList;
7   import java.util.List;
8   
9   import net.sourceforge.pmd.lang.ast.Node;
10  import net.sourceforge.pmd.lang.java.ast.ASTName;
11  import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement;
12  import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
13  
14  public class PositionalIteratorRule extends AbstractJavaRule {
15  
16      public Object visit(ASTWhileStatement node, Object data) {
17          if (hasNameAsChild(node.jjtGetChild(0))) {
18              String exprName = getName(node.jjtGetChild(0));
19              if (exprName.indexOf(".hasNext") != -1 && node.jjtGetNumChildren() > 1) {
20  
21          	Node loopBody = node.jjtGetChild(1);
22                  List<String> names = new ArrayList<>();
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, Node node) {
45          for (int i = 0; i < node.jjtGetNumChildren(); i++) {
46              Node child = 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(Node node) {
58          if (node.jjtGetNumChildren() > 0) {
59              if (node.jjtGetChild(0) instanceof ASTName) {
60                  return true;
61              } else {
62          	return hasNameAsChild(node.jjtGetChild(0));
63              }
64          }
65          return false;
66      }
67  
68      private String getName(Node node) {
69          if (node.jjtGetNumChildren() > 0) {
70              if (node.jjtGetChild(0) instanceof ASTName) {
71                  return ((ASTName) node.jjtGetChild(0)).getImage();
72              } else {
73          	return getName(node.jjtGetChild(0));
74              }
75          }
76          throw new IllegalArgumentException("Check with hasNameAsChild() first!");
77      }
78  }