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