View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
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 = p.jjtGetChild(0);
36                  if (n instanceof ASTAnnotation) {
37                      n = p.jjtGetChild(1);
38                  }
39                  if (n instanceof ASTFieldDeclaration) {
40                      if (!((ASTFieldDeclaration) n).isStatic()) {
41                          isOK = true;
42                          break;
43                      }
44                  } else if (n instanceof ASTConstructorDeclaration) {
45                      if (((ASTConstructorDeclaration) n).isPrivate()) {
46                          isOK = true;
47                          break;
48                      }
49                  } else if (n instanceof ASTMethodDeclaration) {
50                      ASTMethodDeclaration m = (ASTMethodDeclaration) n;
51                      if (!m.isPrivate()) {
52                          methodCount++;
53                      }
54                      if (!m.isStatic()) {
55                          isOK = true;
56                          break;
57                      }
58  
59                      // TODO use symbol table
60                      if (m.getMethodName().equals("suite")) {
61                          ASTResultType res = m.getResultType();
62                          ASTClassOrInterfaceType c = res.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
63                          if (c != null && c.hasImageEqualTo("Test")) {
64                              isOK = true;
65                              break;
66                          }
67                      }
68  
69                  }
70              }
71              if (!isOK && methodCount > 0) {
72                  addViolation(data, decl);
73              }
74          }
75          return super.visit(decl, data);
76      }
77  
78      private boolean isExceptionType(ASTClassOrInterfaceDeclaration parent) {
79          ASTExtendsList extendsList = parent.getFirstChildOfType(ASTExtendsList.class);
80          if (extendsList != null) {
81              ASTClassOrInterfaceType superClass = extendsList.getFirstChildOfType(ASTClassOrInterfaceType.class);
82              if (superClass.getType() != null && Throwable.class.isAssignableFrom(superClass.getType())) {
83                  return true;
84              }
85              if (superClass.getType() == null && superClass.getImage().endsWith("Exception")) {
86                  return true;
87              }
88          }
89          return false;
90      }
91  
92  }