001: package net.sourceforge.pmd.rules.strictexception;
002:
003: import net.sourceforge.pmd.AbstractRule;
004: import net.sourceforge.pmd.ast.ASTCompilationUnit;
005: import net.sourceforge.pmd.ast.ASTConstructorDeclaration;
006: import net.sourceforge.pmd.ast.ASTImportDeclaration;
007: import net.sourceforge.pmd.ast.ASTMethodDeclaration;
008: import net.sourceforge.pmd.ast.ASTName;
009: import net.sourceforge.pmd.ast.Node;
010:
011: import java.util.List;
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: // FUTURE Rename to SignatureDeclareThrowsExceptionRule
021: public class ExceptionSignatureDeclaration extends AbstractRule {
022:
023: private boolean junitImported;
024:
025: public Object visit(ASTCompilationUnit node, Object o) {
026: junitImported = false;
027: return super .visit(node, o);
028: }
029:
030: public Object visit(ASTImportDeclaration node, Object o) {
031: if (node.getImportedName().indexOf("junit") != -1) {
032: junitImported = true;
033: }
034: return super .visit(node, o);
035: }
036:
037: public Object visit(ASTMethodDeclaration methodDeclaration, Object o) {
038: if ((methodDeclaration.getMethodName().equals("setUp") || methodDeclaration
039: .getMethodName().equals("tearDown"))
040: && junitImported) {
041: return super .visit(methodDeclaration, o);
042: }
043:
044: if (methodDeclaration.getMethodName().startsWith("test")) {
045: return super .visit(methodDeclaration, o);
046: }
047:
048: List<ASTName> exceptionList = methodDeclaration
049: .findChildrenOfType(ASTName.class);
050: if (!exceptionList.isEmpty()) {
051: evaluateExceptions(exceptionList, o);
052: }
053: return super .visit(methodDeclaration, o);
054: }
055:
056: public Object visit(
057: ASTConstructorDeclaration constructorDeclaration, Object o) {
058: List<ASTName> exceptionList = constructorDeclaration
059: .findChildrenOfType(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,
073: Object context) {
074: for (ASTName exception : exceptionList) {
075: if (hasDeclaredExceptionInSignature(exception)) {
076: addViolation(context, exception);
077: }
078: }
079: }
080:
081: /**
082: * Checks if the given value is defined as <code>Exception</code> and the parent is either
083: * a method or constructor declaration.
084: *
085: * @param exception to evaluate
086: * @return true if <code>Exception</code> is declared and has proper parents
087: */
088: private boolean hasDeclaredExceptionInSignature(ASTName exception) {
089: return exception.hasImageEqualTo("Exception")
090: && isParentSignatureDeclaration(exception);
091: }
092:
093: /**
094: * @param exception to evaluate
095: * @return true if parent node is either a method or constructor declaration
096: */
097: private boolean isParentSignatureDeclaration(ASTName exception) {
098: Node parent = exception.jjtGetParent().jjtGetParent();
099: return parent instanceof ASTMethodDeclaration
100: || parent instanceof ASTConstructorDeclaration;
101: }
102:
103: }
|