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;
5   
6   import net.sourceforge.pmd.Rule;
7   import net.sourceforge.pmd.RuleContext;
8   import net.sourceforge.pmd.lang.ast.Node;
9   import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
10  import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
11  import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
12  import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
13  import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;
14  import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
15  import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
16  import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
17  import net.sourceforge.pmd.lang.java.ast.CanSuppressWarnings;
18  import net.sourceforge.pmd.lang.java.ast.JavaNode;
19  import net.sourceforge.pmd.lang.java.symboltable.ClassScope;
20  import net.sourceforge.pmd.lang.java.symboltable.MethodScope;
21  import net.sourceforge.pmd.lang.java.symboltable.SourceFileScope;
22  import net.sourceforge.pmd.lang.rule.ParametricRuleViolation;
23  import net.sourceforge.pmd.lang.symboltable.Scope;
24  
25  /**
26   * This is a Java RuleViolation. It knows how to try to extract the following
27   * extra information from the violation node:
28   * <ul>
29   * <li>Package name</li>
30   * <li>Class name</li>
31   * <li>Method name</li>
32   * <li>Variable name</li>
33   * <li>Suppression indicator</li>
34   * </ul>
35   */
36  public class JavaRuleViolation extends ParametricRuleViolation<JavaNode> {
37  
38  	public JavaRuleViolation(Rule rule, RuleContext ctx, JavaNode node, String message, int beginLine, int endLine) {
39  		this(rule, ctx, node, message);
40  
41  		setLines(beginLine, endLine);
42  	}
43  
44  	public JavaRuleViolation(Rule rule, RuleContext ctx, JavaNode node, String message) {
45  		super(rule, ctx, node, message);
46  
47  		if (node != null) {
48  			final Scope scope = node.getScope();
49  			final SourceFileScope sourceFileScope = scope.getEnclosingScope(SourceFileScope.class);
50  
51  			// Package name is on SourceFileScope
52  			packageName = sourceFileScope.getPackageName() == null ? ""	: sourceFileScope.getPackageName();
53  
54  			// Class name is built from enclosing ClassScopes
55  			setClassNameFrom(node);
56  			
57  			// Method name comes from 1st enclosing MethodScope
58  			if (node.getFirstParentOfType(ASTMethodDeclaration.class) != null) {
59  				methodName = scope.getEnclosingScope(MethodScope.class).getName();
60  			}
61  			// Variable name node specific
62  			setVariableNameIfExists(node);
63  
64  			// Check for suppression on this node, on parents, and on contained
65  			// types for ASTCompilationUnit
66  			if (!suppressed) {
67  				suppressed = suppresses(node);
68  			}
69  			if (!suppressed && node instanceof ASTCompilationUnit) {
70  				for (int i = 0; !suppressed && i < node.jjtGetNumChildren(); i++) {
71  					suppressed = suppresses(node.jjtGetChild(i));
72  				}
73  			}
74  			if (!suppressed) {
75  				Node parent = node.jjtGetParent();
76  				while (!suppressed && parent != null) {
77  					suppressed = suppresses(parent);
78  					parent = parent.jjtGetParent();
79  				}
80  			}
81  		}
82  	}
83  
84  	private void setClassNameFrom(JavaNode node) {
85  		
86  		String qualifiedName = null;
87  		for (ASTClassOrInterfaceDeclaration parent : node.getParentsOfType(ASTClassOrInterfaceDeclaration.class)) {
88  			String clsName = parent.getScope().getEnclosingScope(ClassScope.class).getClassName();
89  			if (qualifiedName == null) {
90  				qualifiedName = clsName;
91  			} else {
92  				qualifiedName = clsName + '$' + qualifiedName;
93  			}
94  		}
95  		if (qualifiedName != null) {
96  			className = qualifiedName;
97  		}
98  	}
99  
100 	private boolean suppresses(final Node node) {
101 		return node instanceof CanSuppressWarnings
102 				&& ((CanSuppressWarnings) node).hasSuppressWarningsAnnotationFor(getRule());
103 	}
104 
105 	private void setVariableNameIfExists(Node node) {
106 		if (node instanceof ASTFieldDeclaration) {
107 			variableName = ((ASTFieldDeclaration) node).getVariableName();
108 		} else if (node instanceof ASTLocalVariableDeclaration) {
109 			variableName = ((ASTLocalVariableDeclaration) node)
110 					.getVariableName();
111 		} else if (node instanceof ASTVariableDeclarator) {
112 			variableName = node.jjtGetChild(0).getImage();
113 		} else if (node instanceof ASTVariableDeclaratorId) {
114 			variableName = node.getImage();
115 		} else if (node instanceof ASTFormalParameter) {
116 		    setVariableNameIfExists(node.getFirstChildOfType(ASTVariableDeclaratorId.class));
117 		} else {
118 		    variableName = "";
119 		}
120 	}
121 }