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 }
|