View Javadoc

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  }