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 }
|