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.strictexception;
5   
6   import java.util.Collections;
7   import java.util.List;
8   
9   import net.sourceforge.pmd.lang.ast.Node;
10  import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
11  import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
12  import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
13  import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
14  import net.sourceforge.pmd.lang.java.ast.ASTName;
15  import net.sourceforge.pmd.lang.java.ast.ASTNameList;
16  import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
17  
18  /**
19   * <p/>
20   *
21   * @author <a mailto:trondandersen@c2i.net>Trond Andersen</a>
22   * @version 1.0
23   * @since 1.2
24   */
25  
26  public class SignatureDeclareThrowsExceptionRule extends AbstractJavaRule {
27  
28      private boolean junitImported;
29  
30      @Override
31      public Object visit(ASTCompilationUnit node, Object o) {
32          junitImported = false;
33          return super.visit(node, o);
34      }
35  
36      @Override
37      public Object visit(ASTImportDeclaration node, Object o) {
38          if (node.getImportedName().indexOf("junit") != -1) {
39              junitImported = true;
40          }
41          return super.visit(node, o);
42      }
43  
44      @Override
45      public Object visit(ASTMethodDeclaration methodDeclaration, Object o) {
46          if ((methodDeclaration.getMethodName().equals("setUp") || methodDeclaration.getMethodName().equals("tearDown")) && junitImported) {
47              return super.visit(methodDeclaration, o);
48          }
49  
50          if (methodDeclaration.getMethodName().startsWith("test")) {
51              return super.visit(methodDeclaration, o);
52          }
53  
54          List<ASTName> exceptionList = Collections.emptyList();
55          ASTNameList nameList = methodDeclaration.getFirstChildOfType(ASTNameList.class);
56          if (nameList != null) {
57              exceptionList = nameList.findDescendantsOfType(ASTName.class);
58          }
59          if (!exceptionList.isEmpty()) {
60              evaluateExceptions(exceptionList, o);
61          }
62          return super.visit(methodDeclaration, o);
63      }
64  
65  
66      @Override
67      public Object visit(ASTConstructorDeclaration constructorDeclaration, Object o) {
68          List<ASTName> exceptionList = constructorDeclaration.findDescendantsOfType(ASTName.class);
69          if (!exceptionList.isEmpty()) {
70              evaluateExceptions(exceptionList, o);
71          }
72          return super.visit(constructorDeclaration, o);
73      }
74  
75      /**
76       * Checks all exceptions for possible violation on the exception declaration.
77       *
78       * @param exceptionList containing all exception for declaration
79       * @param context
80       */
81      private void evaluateExceptions(List<ASTName> exceptionList, Object context) {
82          for (ASTName exception: exceptionList) {
83              if (hasDeclaredExceptionInSignature(exception)) {
84                  addViolation(context, exception);
85              }
86          }
87      }
88  
89      /**
90       * Checks if the given value is defined as <code>Exception</code> and the parent is either
91       * a method or constructor declaration.
92       *
93       * @param exception to evaluate
94       * @return true if <code>Exception</code> is declared and has proper parents
95       */
96      private boolean hasDeclaredExceptionInSignature(ASTName exception) {
97          return exception.hasImageEqualTo("Exception") && isParentSignatureDeclaration(exception);
98      }
99  
100     /**
101      * Checks if the given exception is declared in the method or constructor
102      * signature.
103      * @param exception to evaluate
104      * @return true if parent node is either a method or constructor declaration
105      */
106     private boolean isParentSignatureDeclaration(ASTName exception) {
107         Node parent = exception.jjtGetParent().jjtGetParent();
108         return parent instanceof ASTMethodDeclaration || parent instanceof ASTConstructorDeclaration;
109     }
110 
111 }