1 /***
2 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3 */
4 package net.sourceforge.pmd;
5
6 import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
7 import net.sourceforge.pmd.ast.ASTCompilationUnit;
8 import net.sourceforge.pmd.ast.JavaParserVisitorAdapter;
9 import net.sourceforge.pmd.ast.Node;
10 import net.sourceforge.pmd.ast.SimpleNode;
11
12 import java.text.MessageFormat;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.Properties;
16
17 public abstract class AbstractRule extends JavaParserVisitorAdapter implements Rule {
18
19 protected String name = getClass().getName();
20 protected Properties properties = new Properties();
21 protected String message;
22 protected String description;
23 protected String example;
24 protected String ruleSetName;
25 protected boolean include;
26 protected boolean usesDFA;
27 protected int priority = LOWEST_PRIORITY;
28 protected String externalInfoUrl;
29
30 public String getRuleSetName() {
31 return ruleSetName;
32 }
33
34 public void setRuleSetName(String ruleSetName) {
35 this.ruleSetName = ruleSetName;
36 }
37
38 public String getDescription() {
39 return description;
40 }
41
42 public void setDescription(String description) {
43 this.description = description;
44 }
45
46 public String getExample() {
47 return example;
48 }
49
50 public void setExample(String example) {
51 this.example = example;
52 }
53
54 public boolean hasProperty(String name) {
55 return properties.containsKey(name);
56 }
57
58 public void addProperty(String name, String value) {
59 properties.setProperty(name, value);
60 }
61
62 public void addProperties(Properties properties) {
63 this.properties.putAll(properties);
64 }
65
66 public double getDoubleProperty(String name) {
67 return Double.parseDouble(properties.getProperty(name));
68 }
69
70 public int getIntProperty(String name) {
71 return Integer.parseInt(properties.getProperty(name));
72 }
73
74 public boolean getBooleanProperty(String name) {
75 return Boolean.valueOf(properties.getProperty(name)).booleanValue();
76 }
77
78 public String getStringProperty(String name) {
79 return properties.getProperty(name);
80 }
81
82 public String getName() {
83 return name;
84 }
85
86 public void setName(String name) {
87 this.name = name;
88 }
89
90 public String getMessage() {
91 return message;
92 }
93
94 public void setMessage(String message) {
95 this.message = message;
96 }
97
98 public String getExternalInfoUrl() {
99 return externalInfoUrl;
100 }
101
102 public void setExternalInfoUrl(String url) {
103 this.externalInfoUrl = url;
104 }
105
106 /***
107 * Test if rules are equals. Rules are equals if
108 * 1. they have the same implementation class
109 * 2. they have the same name
110 * 3. they have the same priority
111 * 4. they share the same properties/values
112 */
113 public boolean equals(Object o) {
114 if (o == null) {
115 return false;
116 }
117
118 if (this == o) {
119 return true;
120 }
121
122 Rule rule = null;
123 boolean equality = this.getClass().getName().equals(o.getClass().getName());
124
125 if (equality) {
126 rule = (Rule) o;
127 equality = this.getName().equals(rule.getName())
128 && this.getPriority() == rule.getPriority()
129 && this.getProperties().equals(rule.getProperties());
130 }
131
132 return equality;
133 }
134
135 /***
136 * Return a hash code to conform to equality. Try with a string.
137 */
138 public int hashCode() {
139 String s = this.getClass().getName() + this.getName() + String.valueOf(this.getPriority()) + this.getProperties().toString();
140 return s.hashCode();
141 }
142
143 public void apply(List acus, RuleContext ctx) {
144 visitAll(acus, ctx);
145 }
146
147
148 public Properties getProperties() {
149 return properties;
150 }
151
152 public boolean include() {
153 return include;
154 }
155
156 public void setInclude(boolean include) {
157 this.include = include;
158 }
159
160 public int getPriority() {
161 return priority;
162 }
163
164 public String getPriorityName() {
165 return PRIORITIES[getPriority() - 1];
166 }
167
168 public void setPriority(int priority) {
169 this.priority = priority;
170 }
171
172 public void setUsesDFA() {
173 this.usesDFA = true;
174 }
175
176 public boolean usesDFA() {
177 return this.usesDFA;
178 }
179
180 protected void visitAll(List acus, RuleContext ctx) {
181 for (Iterator i = acus.iterator(); i.hasNext();) {
182 ASTCompilationUnit node = (ASTCompilationUnit) i.next();
183 visit(node, ctx);
184 }
185 }
186
187 /***
188 * Adds a violation to the report.
189 *
190 * @param ctx the RuleContext
191 * @param node the node that produces the violation
192 */
193 protected final void addViolation(Object data, SimpleNode node) {
194 RuleContext ctx = (RuleContext) data;
195 ctx.getReport().addRuleViolation(new RuleViolation(this, ctx, node));
196 }
197
198 /***
199 * Adds a violation to the report.
200 *
201 * @param ctx the RuleContext
202 * @param node the node that produces the violation
203 * @param msg specific message to put in the report
204 */
205 protected final void addViolationWithMessage(Object data, SimpleNode node, String msg) {
206 RuleContext ctx = (RuleContext) data;
207 ctx.getReport().addRuleViolation(new RuleViolation(this, ctx, node, msg));
208 }
209
210 /***
211 * Adds a violation to the report.
212 *
213 * @param ctx the RuleContext
214 * @param node the node that produces the violation
215 * @param embed a variable to embed in the rule violation message
216 */
217 protected final void addViolation(Object data, SimpleNode node, String embed) {
218 RuleContext ctx = (RuleContext) data;
219 ctx.getReport().addRuleViolation(new RuleViolation(this, ctx, node, MessageFormat.format(getMessage(), new Object[]{embed})));
220 }
221
222 /***
223 * Adds a violation to the report.
224 *
225 * @param ctx the RuleContext
226 * @param node the node that produces the violation, may be null, in which case all line and column info will be set to zero
227 * @param args objects to embed in the rule violation message
228 */
229 protected final void addViolation(Object data, Node node, Object[] args) {
230 RuleContext ctx = (RuleContext) data;
231 ctx.getReport().addRuleViolation(new RuleViolation(this, ctx, (SimpleNode) node, MessageFormat.format(getMessage(), args)));
232 }
233
234 /***
235 * Gets the Image of the first parent node of type ASTClassOrInterfaceDeclaration or <code>null</code>
236 *
237 * @param node the node which will be searched
238 */
239 protected final String getDeclaringType(SimpleNode node) {
240 ASTClassOrInterfaceDeclaration c = (ASTClassOrInterfaceDeclaration) node.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class);
241 if (c != null)
242 return c.getImage();
243 return null;
244 }
245 }