SignatureDeclareThrowsExceptionRule.java
001 package net.sourceforge.pmd.lang.java.rule.strictexception;
002 
003 import java.util.List;
004 
005 import net.sourceforge.pmd.lang.ast.Node;
006 import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
007 import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
008 import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
009 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
010 import net.sourceforge.pmd.lang.java.ast.ASTName;
011 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
012 
013 /**
014  <p/>
015  *
016  @author <a mailto:trondandersen@c2i.net>Trond Andersen</a>
017  @version 1.0
018  @since 1.2
019  */
020 
021 public class SignatureDeclareThrowsExceptionRule extends AbstractJavaRule {
022 
023     private boolean junitImported;
024 
025     @Override
026     public Object visit(ASTCompilationUnit node, Object o) {
027         junitImported = false;
028         return super.visit(node, o);
029     }
030 
031     @Override
032     public Object visit(ASTImportDeclaration node, Object o) {
033         if (node.getImportedName().indexOf("junit"!= -1) {
034             junitImported = true;
035         }
036         return super.visit(node, o);
037     }
038 
039     @Override
040     public Object visit(ASTMethodDeclaration methodDeclaration, Object o) {
041         if ((methodDeclaration.getMethodName().equals("setUp"|| methodDeclaration.getMethodName().equals("tearDown")) && junitImported) {
042             return super.visit(methodDeclaration, o);
043         }
044 
045         if (methodDeclaration.getMethodName().startsWith("test")) {
046             return super.visit(methodDeclaration, o);
047         }
048 
049         List<ASTName> exceptionList = methodDeclaration.findDescendantsOfType(ASTName.class);
050         if (!exceptionList.isEmpty()) {
051             evaluateExceptions(exceptionList, o);
052         }
053         return super.visit(methodDeclaration, o);
054     }
055 
056 
057     @Override
058     public Object visit(ASTConstructorDeclaration constructorDeclaration, Object o) {
059         List<ASTName> exceptionList = constructorDeclaration.findDescendantsOfType(ASTName.class);
060         if (!exceptionList.isEmpty()) {
061             evaluateExceptions(exceptionList, o);
062         }
063         return super.visit(constructorDeclaration, o);
064     }
065 
066     /**
067      * Checks all exceptions for possible violation on the exception declaration.
068      *
069      @param exceptionList containing all exception for declaration
070      @param context
071      */
072     private void evaluateExceptions(List<ASTName> exceptionList, Object context) {
073         for (ASTName exception: exceptionList) {
074             if (hasDeclaredExceptionInSignature(exception)) {
075                 addViolation(context, exception);
076             }
077         }
078     }
079 
080     /**
081      * Checks if the given value is defined as <code>Exception</code> and the parent is either
082      * a method or constructor declaration.
083      *
084      @param exception to evaluate
085      @return true if <code>Exception</code> is declared and has proper parents
086      */
087     private boolean hasDeclaredExceptionInSignature(ASTName exception) {
088         return exception.hasImageEqualTo("Exception"&& isParentSignatureDeclaration(exception);
089     }
090 
091     /**
092      @param exception to evaluate
093      @return true if parent node is either a method or constructor declaration
094      */
095     private boolean isParentSignatureDeclaration(ASTName exception) {
096         Node parent = exception.jjtGetParent().jjtGetParent();
097         return parent instanceof ASTMethodDeclaration || parent instanceof ASTConstructorDeclaration;
098     }
099 
100 }