View Javadoc

1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.rules.migration;
5   
6   import net.sourceforge.pmd.ast.ASTAnnotation;
7   import net.sourceforge.pmd.ast.ASTBlock;
8   import net.sourceforge.pmd.ast.ASTBlockStatement;
9   import net.sourceforge.pmd.ast.ASTCatchStatement;
10  import net.sourceforge.pmd.ast.ASTClassOrInterfaceBodyDeclaration;
11  import net.sourceforge.pmd.ast.ASTMethodDeclaration;
12  import net.sourceforge.pmd.ast.ASTName;
13  import net.sourceforge.pmd.ast.ASTThrowStatement;
14  import net.sourceforge.pmd.ast.ASTTryStatement;
15  import net.sourceforge.pmd.ast.Node;
16  import net.sourceforge.pmd.ast.SimpleNode;
17  import net.sourceforge.pmd.rules.junit.AbstractJUnitRule;
18  
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  /**
23   * This rule finds code like this:
24   * 
25   * <pre>
26   * public void testFoo() {
27   *     try {
28   *         doSomething();
29   *         fail(&quot;should have thrown an exception&quot;);
30   *     } catch (Exception e) {
31   *     }
32   * }
33   * </pre>
34   * 
35   * In JUnit 4, use
36   * 
37   * <pre>
38   *  &#064;Test(expected = Exception.class)
39   * </pre>
40   * 
41   * @author acaplan
42   * 
43   */
44  public class JUnitUseExpected extends AbstractJUnitRule {
45  
46      public Object visit(ASTClassOrInterfaceBodyDeclaration node, Object data) {
47          boolean inAnnotation = false;
48          for (int i = 0; i < node.jjtGetNumChildren(); i++) {
49              Node child = node.jjtGetChild(i);
50              if (ASTAnnotation.class.equals(child.getClass())) {
51                  ASTName annotationName = ((SimpleNode) child).getFirstChildOfType(ASTName.class);
52                  if ("Test".equals(annotationName.getImage())) {
53                      inAnnotation = true;
54                      continue;
55                  }
56              }
57              if (ASTMethodDeclaration.class.equals(child.getClass())) {
58                  boolean isJUnitMethod = isJUnitMethod((ASTMethodDeclaration) child, data);
59                  if (inAnnotation || isJUnitMethod) {
60                      List<SimpleNode> found = new ArrayList<SimpleNode>();
61                      found.addAll((List<SimpleNode>) visit((ASTMethodDeclaration) child, data));
62                      for (SimpleNode name : found) {
63                          addViolation(data, name);
64                      }
65                  }
66              }
67              inAnnotation = false;
68          }
69  
70          return super.visit(node, data);
71      }
72  
73      public Object visit(ASTMethodDeclaration node, Object data) {
74          List<ASTTryStatement> catches = node.findChildrenOfType(ASTTryStatement.class);
75          List<SimpleNode> found = new ArrayList<SimpleNode>();
76          if (catches.isEmpty()) {
77              return found;
78          }
79          for (ASTTryStatement trySt : catches) {
80              ASTCatchStatement cStatement = getCatch(trySt);
81              if (cStatement != null) {
82                  ASTBlock block = (ASTBlock) cStatement.jjtGetChild(1);
83                  if (block.jjtGetNumChildren() != 0) {
84                      continue;
85                  }
86                  List<ASTBlockStatement> blocks = ((SimpleNode) trySt.jjtGetChild(0)).findChildrenOfType(ASTBlockStatement.class);
87                  if (blocks.isEmpty()) {
88                      continue;
89                  }
90                  ASTBlockStatement st = blocks.get(blocks.size() - 1);
91                  ASTName name = st.getFirstChildOfType(ASTName.class);
92                  if (name != null && st.equals(name.getNthParent(5)) && "fail".equals(name.getImage())) {
93                      found.add(name);
94                      continue;
95                  }
96                  ASTThrowStatement th = st.getFirstChildOfType(ASTThrowStatement.class);
97                  if (th != null && st.equals(th.getNthParent(2))) {
98                      found.add(th);
99                      continue;
100                 }
101             }
102         }
103         return found;
104     }
105 
106     private ASTCatchStatement getCatch(Node n) {
107         for (int i = 0; i < n.jjtGetNumChildren(); i++) {
108             if (n.jjtGetChild(i) instanceof ASTCatchStatement) {
109                 return (ASTCatchStatement) n.jjtGetChild(i);
110             }
111         }
112         return null;
113     }
114 }