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