1
2
3
4 package net.sourceforge.pmd.lang.java.typeresolution.rules;
5
6 import java.util.List;
7
8 import net.sourceforge.pmd.lang.ast.Node;
9 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
10 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
11 import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
12 import net.sourceforge.pmd.lang.java.ast.ASTExtendsList;
13 import net.sourceforge.pmd.lang.java.ast.ASTImplementsList;
14 import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
15 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
16 import net.sourceforge.pmd.lang.java.ast.ASTName;
17 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
18 import net.sourceforge.pmd.lang.rule.properties.BooleanProperty;
19
20
21
22
23
24
25
26
27
28
29
30
31
32 public class SignatureDeclareThrowsException extends AbstractJavaRule {
33
34 private static final BooleanProperty IGNORE_JUNIT_COMPLETELY_DESCRIPTOR = new BooleanProperty("IgnoreJUnitCompletely",
35 "Allow all methods in a JUnit testcase to throw Exceptions", false, 1.0f);
36
37
38 private boolean junitImported = false;
39
40 public SignatureDeclareThrowsException() {
41 definePropertyDescriptor(IGNORE_JUNIT_COMPLETELY_DESCRIPTOR);
42 }
43
44 @Override
45 public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
46 if (junitImported) {
47 return super.visit(node, data);
48 }
49
50 ASTImplementsList impl = node.getFirstChildOfType(ASTImplementsList.class);
51 if (impl != null && impl.jjtGetParent().equals(node)) {
52 for (int ix = 0; ix < impl.jjtGetNumChildren(); ix++) {
53 ASTClassOrInterfaceType type = (ASTClassOrInterfaceType) impl.jjtGetChild(ix);
54 if (isJUnitTest(type)) {
55 junitImported = true;
56 return super.visit(node, data);
57 }
58 }
59 }
60 if (node.jjtGetNumChildren() != 0 && node.jjtGetChild(0) instanceof ASTExtendsList) {
61 ASTClassOrInterfaceType type = (ASTClassOrInterfaceType) node.jjtGetChild(0).jjtGetChild(0);
62 if (isJUnitTest(type)) {
63 junitImported = true;
64 return super.visit(node, data);
65 }
66 }
67
68 return super.visit(node, data);
69 }
70
71 private boolean isJUnitTest(ASTClassOrInterfaceType type) {
72 Class<?> clazz = type.getType();
73 if (clazz == null) {
74 if ("junit.framework.Test".equals(type.getImage())) {
75 return true;
76 }
77 } else if (isJUnitTest(clazz)) {
78 return true;
79 } else {
80 while (clazz != null && !Object.class.equals(clazz)) {
81 for(Class<?> intf : clazz.getInterfaces()) {
82 if (isJUnitTest(intf)) {
83 return true;
84 }
85 }
86 clazz = clazz.getSuperclass();
87 }
88 }
89 return false;
90 }
91
92 private boolean isJUnitTest(Class<?> clazz) {
93 return clazz.getName().equals("junit.framework.Test");
94 }
95
96 @Override
97 public Object visit(ASTImportDeclaration node, Object o) {
98 if (node.getImportedName().indexOf("junit") != -1) {
99 junitImported = true;
100 }
101 return super.visit(node, o);
102 }
103
104
105 @Override
106 public Object visit(ASTMethodDeclaration methodDeclaration, Object o) {
107 if (junitImported && isAllowedMethod(methodDeclaration)) {
108 return super.visit(methodDeclaration, o);
109 }
110
111 checkExceptions(methodDeclaration, o);
112
113 return super.visit(methodDeclaration, o);
114 }
115
116 private boolean isAllowedMethod(ASTMethodDeclaration methodDeclaration) {
117 if (getProperty(IGNORE_JUNIT_COMPLETELY_DESCRIPTOR)) {
118 return true;
119 } else {
120 return methodDeclaration.getMethodName().equals("setUp") || methodDeclaration
121 .getMethodName().equals("tearDown");
122 }
123 }
124
125 @Override
126 public Object visit(ASTConstructorDeclaration constructorDeclaration, Object o) {
127 checkExceptions(constructorDeclaration, o);
128
129 return super.visit(constructorDeclaration, o);
130 }
131
132
133
134
135 private void checkExceptions(Node method, Object o) {
136 List<ASTName> exceptionList = method.findDescendantsOfType(ASTName.class);
137 if (!exceptionList.isEmpty()) {
138 evaluateExceptions(exceptionList, o);
139 }
140 }
141
142
143
144
145
146
147
148 private void evaluateExceptions(List<ASTName> exceptionList, Object context) {
149 for (ASTName exception: exceptionList) {
150 if (hasDeclaredExceptionInSignature(exception)) {
151 addViolation(context, exception);
152 }
153 }
154 }
155
156
157
158
159
160
161
162
163 private boolean hasDeclaredExceptionInSignature(ASTName exception) {
164 return exception.hasImageEqualTo("Exception") && isParentSignatureDeclaration(exception);
165 }
166
167
168
169
170
171 private boolean isParentSignatureDeclaration(ASTName exception) {
172 Node parent = exception.jjtGetParent().jjtGetParent();
173 return parent instanceof ASTMethodDeclaration || parent instanceof ASTConstructorDeclaration;
174 }
175 }