/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.lang.java.rule; import java.util.Set; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; import net.sourceforge.pmd.lang.java.ast.AccessNode; import net.sourceforge.pmd.lang.java.ast.CanSuppressWarnings; import net.sourceforge.pmd.lang.java.ast.JavaNode; import net.sourceforge.pmd.lang.java.symboltable.ClassNameDeclaration; import net.sourceforge.pmd.lang.java.symboltable.ClassScope; import net.sourceforge.pmd.lang.java.symboltable.MethodScope; import net.sourceforge.pmd.lang.java.symboltable.SourceFileScope; import net.sourceforge.pmd.lang.rule.ParametricRuleViolation; import net.sourceforge.pmd.lang.symboltable.Scope; /** * This is a Java RuleViolation. It knows how to try to extract the following * extra information from the violation node: * <ul> * <li>Package name</li> * <li>Class name</li> * <li>Method name</li> * <li>Variable name</li> * <li>Suppression indicator</li> * </ul> */ public class JavaRuleViolation extends ParametricRuleViolation<JavaNode> { public JavaRuleViolation(Rule rule, RuleContext ctx, JavaNode node, String message, int beginLine, int endLine) { this(rule, ctx, node, message); setLines(beginLine, endLine); } public JavaRuleViolation(Rule rule, RuleContext ctx, JavaNode node, String message) { super(rule, ctx, node, message); if (node != null) { final Scope scope = node.getScope(); final SourceFileScope sourceFileScope = scope.getEnclosingScope(SourceFileScope.class); // Package name is on SourceFileScope packageName = sourceFileScope.getPackageName() == null ? "" : sourceFileScope.getPackageName(); // Class name is built from enclosing ClassScopes setClassNameFrom(node); // Method name comes from 1st enclosing MethodScope if (scope.getEnclosingScope(MethodScope.class) != null) { methodName = scope.getEnclosingScope(MethodScope.class).getName(); } // Variable name node specific setVariableNameIfExists(node); if (!suppressed) { suppressed = isSupressed(node, getRule()); } } } /** * Check for suppression on this node, on parents, and on contained types * for ASTCompilationUnit * * @param node */ public static boolean isSupressed(Node node, Rule rule) { boolean result = suppresses(node, rule); if (!result && node instanceof ASTCompilationUnit) { for (int i = 0; !result && i < node.jjtGetNumChildren(); i++) { result = suppresses(node.jjtGetChild(i), rule); } } if (!result) { Node parent = node.jjtGetParent(); while (!result && parent != null) { result = suppresses(parent, rule); parent = parent.jjtGetParent(); } } return result; } private void setClassNameFrom(JavaNode node) { String qualifiedName = null; for (ASTClassOrInterfaceDeclaration parent : node.getParentsOfType(ASTClassOrInterfaceDeclaration.class)) { String clsName = parent.getScope().getEnclosingScope(ClassScope.class).getClassName(); if (qualifiedName == null) { qualifiedName = clsName; } else { qualifiedName = clsName + '$' + qualifiedName; } } if (qualifiedName == null) { Set<ClassNameDeclaration> classes = node.getScope().getEnclosingScope(SourceFileScope.class) .getClassDeclarations().keySet(); for (ClassNameDeclaration c : classes) { // find the first public class/enum declaration if (c.getAccessNodeParent() instanceof AccessNode) { if (((AccessNode) c.getAccessNodeParent()).isPublic()) { qualifiedName = c.getImage(); break; } } } } if (qualifiedName != null) { className = qualifiedName; } } private static boolean suppresses(final Node node, Rule rule) { return node instanceof CanSuppressWarnings && ((CanSuppressWarnings) node).hasSuppressWarningsAnnotationFor(rule); } private void setVariableNameIfExists(Node node) { if (node instanceof ASTFieldDeclaration) { variableName = ((ASTFieldDeclaration) node).getVariableName(); } else if (node instanceof ASTLocalVariableDeclaration) { variableName = ((ASTLocalVariableDeclaration) node).getVariableName(); } else if (node instanceof ASTVariableDeclarator) { variableName = node.jjtGetChild(0).getImage(); } else if (node instanceof ASTVariableDeclaratorId) { variableName = node.getImage(); } else if (node instanceof ASTFormalParameter) { setVariableNameIfExists(node.getFirstChildOfType(ASTVariableDeclaratorId.class)); } else { variableName = ""; } } }