/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.rule.design;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTAnnotation;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTExtendsList;
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTResultType;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
public class UseUtilityClassRule extends AbstractJavaRule {
@Override
public Object visit(ASTClassOrInterfaceBody decl, Object data) {
if (decl.jjtGetParent() instanceof ASTClassOrInterfaceDeclaration) {
ASTClassOrInterfaceDeclaration parent = (ASTClassOrInterfaceDeclaration) decl.jjtGetParent();
if (parent.isAbstract() || parent.isInterface() || isExceptionType(parent)) {
return super.visit(decl, data);
}
int i = decl.jjtGetNumChildren();
int methodCount = 0;
boolean isOK = false;
while (i > 0) {
Node p = decl.jjtGetChild(--i);
if (p.jjtGetNumChildren() == 0) {
continue;
}
Node n = skipAnnotations(p);
if (n instanceof ASTFieldDeclaration) {
if (!((ASTFieldDeclaration) n).isStatic()) {
isOK = true;
break;
}
} else if (n instanceof ASTConstructorDeclaration) {
if (((ASTConstructorDeclaration) n).isPrivate()) {
isOK = true;
break;
}
} else if (n instanceof ASTMethodDeclaration) {
ASTMethodDeclaration m = (ASTMethodDeclaration) n;
if (!m.isPrivate()) {
methodCount++;
}
if (!m.isStatic()) {
isOK = true;
break;
}
// TODO use symbol table
if (m.getMethodName().equals("suite")) {
ASTResultType res = m.getResultType();
ASTClassOrInterfaceType c = res.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
if (c != null && c.hasImageEqualTo("Test")) {
isOK = true;
break;
}
}
}
}
if (!isOK && methodCount > 0) {
addViolation(data, decl);
}
}
return super.visit(decl, data);
}
private Node skipAnnotations(Node p) {
int index = 0;
Node n = p.jjtGetChild(index++);
while (n instanceof ASTAnnotation && index < p.jjtGetNumChildren()) {
n = p.jjtGetChild(index++);
}
return n;
}
private boolean isExceptionType(ASTClassOrInterfaceDeclaration parent) {
ASTExtendsList extendsList = parent.getFirstChildOfType(ASTExtendsList.class);
if (extendsList != null) {
ASTClassOrInterfaceType superClass = extendsList.getFirstChildOfType(ASTClassOrInterfaceType.class);
if (superClass.getType() != null && Throwable.class.isAssignableFrom(superClass.getType())) {
return true;
}
if (superClass.getType() == null && superClass.getImage().endsWith("Exception")) {
return true;
}
}
return false;
}
}