View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.rule;
5   
6   import java.util.regex.Pattern;
7   
8   import net.sourceforge.pmd.PropertyDescriptor;
9   import net.sourceforge.pmd.Rule;
10  import net.sourceforge.pmd.RuleContext;
11  import net.sourceforge.pmd.RuleViolation;
12  import net.sourceforge.pmd.lang.ast.Node;
13  import net.sourceforge.pmd.util.StringUtil;
14  
15  public class ParametricRuleViolation<T extends Node> implements RuleViolation {
16  
17      protected final Rule rule;
18      protected final String description;
19      protected boolean suppressed;
20      protected String filename;
21  
22      protected int beginLine;
23      protected int beginColumn;
24  
25      protected int endLine;
26      protected int endColumn;
27  
28      protected String packageName = "";
29      protected String className = "";
30      protected String methodName = "";
31      protected String variableName = "";
32  
33      // 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.
34      public ParametricRuleViolation(Rule theRule, RuleContext ctx, T node, String message) {
35  	rule = theRule;
36  	description = message;
37  	filename = ctx.getSourceCodeFilename();
38  	if (filename == null) {
39  	    filename = "";
40  	}
41  	if (node != null) {
42  	    beginLine = node.getBeginLine();
43  	    beginColumn = node.getBeginColumn();
44  	    endLine = node.getEndLine();
45  	    endColumn = node.getEndColumn();
46  	}
47  
48  	// Apply Rule specific suppressions
49  	if (node != null && rule != null) {
50  		setSuppression(rule, node);
51  	}
52  	
53      }
54  
55      private void setSuppression(Rule rule, T node) {
56      
57      	String regex = rule.getProperty(Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR);	// Regex
58      	if (regex != null && description != null) {
59      		if (Pattern.matches(regex, description)) {
60      			suppressed = true;
61      		}
62      	}
63      
64      	if (!suppressed) {	// XPath
65      		String xpath = rule.getProperty(Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR);
66      		if (xpath != null) {
67      			suppressed = node.hasDescendantMatchingXPath(xpath);
68      		}
69      	}
70      }
71  
72      protected String expandVariables(String message) {
73      	
74      	if (message.indexOf("${") < 0) {
75      	    return message;
76      	}
77      	
78  	    StringBuilder buf = new StringBuilder(message);
79  	    int startIndex = -1;
80  	    while ((startIndex = buf.indexOf("${", startIndex + 1)) >= 0) {
81  			final int endIndex = buf.indexOf("}", startIndex);
82  			if (endIndex >= 0) {
83  			    final String name = buf.substring(startIndex + 2, endIndex);
84  			    if (isVariable(name)) {
85  			    	buf.replace(startIndex, endIndex + 1, getVariableValue(name));
86  			    	}
87  				}
88  		    }
89  	    return buf.toString();	 
90      }
91  
92      protected boolean isVariable(String name) {
93      	return 
94      		StringUtil.isAnyOf(name, "variableName", "methodName", "className", "packageName") ||
95      		rule.getPropertyDescriptor(name) != null;
96      }
97  
98      protected String getVariableValue(String name) {
99  	if ("variableName".equals(name)) {
100 	    return variableName;
101 	} else if ("methodName".equals(name)) {
102 	    return methodName;
103 	} else if ("className".equals(name)) {
104 	    return className;
105 	} else if ("packageName".equals(name)) {
106 	    return packageName;
107 	} else {
108 	    final PropertyDescriptor<?> propertyDescriptor = rule.getPropertyDescriptor(name);
109 	    return String.valueOf(rule.getProperty(propertyDescriptor));
110 	}
111     }
112 
113     public Rule getRule() {
114 	return rule;
115     }
116 
117     public String getDescription() {
118 	return expandVariables(description);
119     }
120 
121     public boolean isSuppressed() {
122 	return suppressed;
123     }
124 
125     public String getFilename() {
126 	return filename;
127     }
128 
129     public int getBeginLine() {
130 	return beginLine;
131     }
132 
133     public int getBeginColumn() {
134 	return beginColumn;
135     }
136 
137     public int getEndLine() {
138 	return endLine;
139     }
140 
141     public int getEndColumn() {
142 	return endColumn;
143     }
144 
145     public String getPackageName() {
146 	return packageName;
147     }
148 
149     public String getClassName() {
150 	return className;
151     }
152 
153     public String getMethodName() {
154 	return methodName;
155     }
156 
157     public String getVariableName() {
158 	return variableName;
159     }
160 
161     public void setLines(int theBeginLine, int theEndLine) {
162     	beginLine = theBeginLine;
163     	endLine = theEndLine;
164     }
165     
166     @Override
167     public String toString() {
168 	return getFilename() + ':' + getRule() + ':' + getDescription() + ':' + beginLine;
169     }
170 }