AbstractRuleViolation.java
001 /**
002  * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003  */
004 package net.sourceforge.pmd.lang.rule;
005 
006 import java.util.regex.Pattern;
007 
008 import net.sourceforge.pmd.PropertyDescriptor;
009 import net.sourceforge.pmd.Rule;
010 import net.sourceforge.pmd.RuleContext;
011 import net.sourceforge.pmd.RuleViolation;
012 import net.sourceforge.pmd.lang.ast.Node;
013 
014 public abstract class AbstractRuleViolation implements RuleViolation {
015 
016     protected Rule rule;
017     protected String description;
018     protected boolean suppressed;
019     protected String filename;
020 
021     protected int beginLine;
022     protected int beginColumn;
023 
024     protected int endLine;
025     protected int endColumn;
026 
027     protected String packageName;
028     protected String className;
029     protected String methodName;
030     protected String variableName;
031 
032     // FUTURE Fix to understand when a violation _must_ have a Node, and when it must not (to prevent erroneous Rules silently logging w/o a Node).  Modify RuleViolationFactory to support identifying without a Node, and update Rule base classes too.
033     public AbstractRuleViolation(Rule rule, RuleContext ctx, Node node, String message) {
034   this.rule = rule;
035   this.description = message;
036   this.filename = ctx.getSourceCodeFilename();
037   if (this.filename == null) {
038       this.filename = "";
039   }
040   if (node != null) {
041       this.beginLine = node.getBeginLine();
042       this.beginColumn = node.getBeginColumn();
043       this.endLine = node.getEndLine();
044       this.endColumn = node.getEndColumn();
045   }
046   this.packageName = "";
047   this.className = "";
048   this.methodName = "";
049   this.variableName = "";
050 
051   // Apply Rule specific suppressions
052   if (node != null && rule != null) {
053       // Regex
054       String regex = rule.getProperty(Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR);
055       if (regex != null && description != null) {
056     if (Pattern.matches(regex, description)) {
057         suppressed = true;
058     }
059       }
060 
061       // XPath
062       if (!suppressed) {
063     String xpath = rule.getProperty(Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR);
064     if (xpath != null) {
065         suppressed = node.hasDescendantMatchingXPath(xpath);
066     }
067       }
068   }
069     }
070 
071     protected String expandVariables(String message) {
072   if (message.indexOf("${">= 0) {
073       StringBuilder buf = new StringBuilder(message);
074       int startIndex = -1;
075       while ((startIndex = buf.indexOf("${", startIndex + 1)) >= 0) {
076     final int endIndex = buf.indexOf("}", startIndex);
077     if (endIndex >= 0) {
078         final String name = buf.substring(startIndex + 2, endIndex);
079         if (isVariable(name)) {
080       buf.replace(startIndex, endIndex + 1, getVariableValue(name));
081         }
082     }
083       }
084       return buf.toString();
085   else {
086       return message;
087   }
088     }
089 
090     protected boolean isVariable(String name) {
091   return "variableName".equals(name|| "methodName".equals(name|| "className".equals(name)
092     || "packageName".equals(name|| rule.getPropertyDescriptor(name!= null;
093     }
094 
095     protected String getVariableValue(String name) {
096   if ("variableName".equals(name)) {
097       return variableName;
098   else if ("methodName".equals(name)) {
099       return methodName;
100   else if ("className".equals(name)) {
101       return className;
102   else if ("packageName".equals(name)) {
103       return packageName;
104   else {
105       final PropertyDescriptor<?> propertyDescriptor = rule.getPropertyDescriptor(name);
106       return String.valueOf(rule.getProperty(propertyDescriptor));
107   }
108     }
109 
110     public Rule getRule() {
111   return rule;
112     }
113 
114     public String getDescription() {
115   return expandVariables(description);
116     }
117 
118     public boolean isSuppressed() {
119   return this.suppressed;
120     }
121 
122     public String getFilename() {
123   return filename;
124     }
125 
126     public int getBeginLine() {
127   return beginLine;
128     }
129 
130     public int getBeginColumn() {
131   return beginColumn;
132     }
133 
134     public int getEndLine() {
135   return endLine;
136     }
137 
138     public int getEndColumn() {
139   return endColumn;
140     }
141 
142     public String getPackageName() {
143   return packageName;
144     }
145 
146     public String getClassName() {
147   return className;
148     }
149 
150     public String getMethodName() {
151   return methodName;
152     }
153 
154     public String getVariableName() {
155   return variableName;
156     }
157 
158     @Override
159     public String toString() {
160   return getFilename() ':' + getRule() ':' + getDescription() ':' + beginLine;
161     }
162 }