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  			if (!suppressed) {
65  			    suppressed = isSupressed(node, getRule());
66  			}
67  		}
68  	}
69  
70      /**
71       * Check for suppression on this node, on parents, and on contained types
72       * for ASTCompilationUnit
73       * 
74       * @param node
75       */
76      public static boolean isSupressed(Node node, Rule rule) {
77          boolean result = suppresses(node, rule);
78  
79          if (!result && node instanceof ASTCompilationUnit) {
80              for (int i = 0; !result && i < node.jjtGetNumChildren(); i++) {
81                  result = suppresses(node.jjtGetChild(i), rule);
82              }
83          }
84          if (!result) {
85              Node parent = node.jjtGetParent();
86              while (!result && parent != null) {
87                  result = suppresses(parent, rule);
88                  parent = parent.jjtGetParent();
89              }
90          }
91          return result;
92      }
93  
94  	private void setClassNameFrom(JavaNode node) {
95  		
96  		String qualifiedName = null;
97  		for (ASTClassOrInterfaceDeclaration parent : node.getParentsOfType(ASTClassOrInterfaceDeclaration.class)) {
98  			String clsName = parent.getScope().getEnclosingScope(ClassScope.class).getClassName();
99  			if (qualifiedName == null) {
100 				qualifiedName = clsName;
101 			} else {
102 				qualifiedName = clsName + '$' + qualifiedName;
103 			}
104 		}
105 		if (qualifiedName != null) {
106 			className = qualifiedName;
107 		}
108 	}
109 
110 	private static boolean suppresses(final Node node, Rule rule) {
111 		return node instanceof CanSuppressWarnings
112 				&& ((CanSuppressWarnings) node).hasSuppressWarningsAnnotationFor(rule);
113 	}
114 
115 	private void setVariableNameIfExists(Node node) {
116 		if (node instanceof ASTFieldDeclaration) {
117 			variableName = ((ASTFieldDeclaration) node).getVariableName();
118 		} else if (node instanceof ASTLocalVariableDeclaration) {
119 			variableName = ((ASTLocalVariableDeclaration) node)
120 					.getVariableName();
121 		} else if (node instanceof ASTVariableDeclarator) {
122 			variableName = node.jjtGetChild(0).getImage();
123 		} else if (node instanceof ASTVariableDeclaratorId) {
124 			variableName = node.getImage();
125 		} else if (node instanceof ASTFormalParameter) {
126 		    setVariableNameIfExists(node.getFirstChildOfType(ASTVariableDeclaratorId.class));
127 		} else {
128 		    variableName = "";
129 		}
130 	}
131 }