1
2
3
4 package net.sourceforge.pmd.lang.java.rule.design;
5
6 import net.sourceforge.pmd.lang.ast.Node;
7 import net.sourceforge.pmd.lang.java.ast.ASTAnnotation;
8 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody;
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.ASTFieldDeclaration;
14 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
15 import net.sourceforge.pmd.lang.java.ast.ASTResultType;
16 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
17
18 public class UseUtilityClassRule extends AbstractJavaRule {
19
20 @Override
21 public Object visit(ASTClassOrInterfaceBody decl, Object data) {
22 if (decl.jjtGetParent() instanceof ASTClassOrInterfaceDeclaration) {
23 ASTClassOrInterfaceDeclaration parent = (ASTClassOrInterfaceDeclaration) decl.jjtGetParent();
24 if (parent.isAbstract() || parent.isInterface() || isExceptionType(parent)) {
25 return super.visit(decl, data);
26 }
27 int i = decl.jjtGetNumChildren();
28 int methodCount = 0;
29 boolean isOK = false;
30 while (i > 0) {
31 Node p = decl.jjtGetChild(--i);
32 if (p.jjtGetNumChildren() == 0) {
33 continue;
34 }
35 Node n = skipAnnotations(p);
36 if (n instanceof ASTFieldDeclaration) {
37 if (!((ASTFieldDeclaration) n).isStatic()) {
38 isOK = true;
39 break;
40 }
41 } else if (n instanceof ASTConstructorDeclaration) {
42 if (((ASTConstructorDeclaration) n).isPrivate()) {
43 isOK = true;
44 break;
45 }
46 } else if (n instanceof ASTMethodDeclaration) {
47 ASTMethodDeclaration m = (ASTMethodDeclaration) n;
48 if (!m.isPrivate()) {
49 methodCount++;
50 }
51 if (!m.isStatic()) {
52 isOK = true;
53 break;
54 }
55
56
57 if (m.getMethodName().equals("suite")) {
58 ASTResultType res = m.getResultType();
59 ASTClassOrInterfaceType c = res.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
60 if (c != null && c.hasImageEqualTo("Test")) {
61 isOK = true;
62 break;
63 }
64 }
65
66 }
67 }
68 if (!isOK && methodCount > 0) {
69 addViolation(data, decl);
70 }
71 }
72 return super.visit(decl, data);
73 }
74
75 private Node skipAnnotations(Node p) {
76 int index = 0;
77 Node n = p.jjtGetChild(index++);
78 while (n instanceof ASTAnnotation && index < p.jjtGetNumChildren()) {
79 n = p.jjtGetChild(index++);
80 }
81 return n;
82 }
83
84 private boolean isExceptionType(ASTClassOrInterfaceDeclaration parent) {
85 ASTExtendsList extendsList = parent.getFirstChildOfType(ASTExtendsList.class);
86 if (extendsList != null) {
87 ASTClassOrInterfaceType superClass = extendsList.getFirstChildOfType(ASTClassOrInterfaceType.class);
88 if (superClass.getType() != null && Throwable.class.isAssignableFrom(superClass.getType())) {
89 return true;
90 }
91 if (superClass.getType() == null && superClass.getImage().endsWith("Exception")) {
92 return true;
93 }
94 }
95 return false;
96 }
97
98 }