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 = 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                      // TODO use symbol table
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  }