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.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 && child.getImage().indexOf(".") != -1 && 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  }