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.ASTMethodDeclaration;
9 import net.sourceforge.pmd.ast.JavaParserVisitorAdapter;
10 import net.sourceforge.pmd.ast.SimpleNode;
11 import net.sourceforge.pmd.symboltable.MethodScope;
12
13 import java.text.MessageFormat;
14 import java.util.Iterator;
15 import java.util.List;
16 import java.util.Properties;
17
18 public abstract class AbstractRule extends JavaParserVisitorAdapter implements Rule {
19
20 protected String name = getClass().getName();
21 protected Properties properties = new Properties();
22 protected String message;
23 protected String description;
24 protected String example;
25 protected String ruleSetName;
26 protected boolean include;
27 protected boolean usesDFA;
28 protected int priority = LOWEST_PRIORITY;
29 protected String externalInfoUrl;
30
31 public String getRuleSetName() {
32 return ruleSetName;
33 }
34
35 public void setRuleSetName(String ruleSetName) {
36 this.ruleSetName = ruleSetName;
37 }
38
39 public String getDescription() {
40 return description;
41 }
42
43 public void setDescription(String description) {
44 this.description = description;
45 }
46
47 public String getExample() {
48 return example;
49 }
50
51 public void setExample(String example) {
52 this.example = example;
53 }
54
55 public boolean hasProperty(String name) {
56 return properties.containsKey(name);
57 }
58
59 public void addProperty(String name, String value) {
60 properties.setProperty(name, value);
61 }
62
63 public void addProperties(Properties properties) {
64 this.properties.putAll(properties);
65 }
66
67 public double getDoubleProperty(String name) {
68 return Double.parseDouble(properties.getProperty(name));
69 }
70
71 public int getIntProperty(String name) {
72 return Integer.parseInt(properties.getProperty(name));
73 }
74
75 public boolean getBooleanProperty(String name) {
76 return Boolean.valueOf(properties.getProperty(name)).booleanValue();
77 }
78
79 public String getStringProperty(String name) {
80 return properties.getProperty(name);
81 }
82
83 public String getName() {
84 return name;
85 }
86
87 public void setName(String name) {
88 this.name = name;
89 }
90
91 public String getMessage() {
92 return message;
93 }
94
95 public void setMessage(String message) {
96 this.message = message;
97 }
98
99 public String getExternalInfoUrl() {
100 return externalInfoUrl;
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 public RuleViolation createRuleViolation(RuleContext ctx, SimpleNode node) {
148 String packageName = node.getScope().getEnclosingSourceFileScope().getPackageName() == null ? "" : node.getScope().getEnclosingSourceFileScope().getPackageName();
149 RuleViolation v = new RuleViolation(this, ctx, packageName, findClassName(node), findMethodName(node))/package-summary.html">RuleViolation v = new RuleViolation(this, ctx, packageName, findClassName(node), findMethodName(node));
150 extractNodeInfo(v, node);
151 return v;
152 }
153
154 public RuleViolation createRuleViolation(RuleContext ctx, SimpleNode node, String specificDescription) {
155 String packageName = node.getScope().getEnclosingSourceFileScope().getPackageName() == null ? "" : node.getScope().getEnclosingSourceFileScope().getPackageName();
156 RuleViolation rv = new RuleViolation(this, node/getBeginLine(), specificDescription, ctx, packageName, findClassName(node), findMethodName(node))/package-summary.html">RuleViolation rv = new RuleViolation(this, node.getBeginLine(), specificDescription, ctx, packageName, findClassName(node), findMethodName(node));
157 extractNodeInfo(rv, node);
158 return rv;
159 }
160
161 public RuleViolation createRuleViolation(RuleContext ctx, SimpleNode node, String variableName, String specificDescription) {
162 String packageName = node.getScope().getEnclosingSourceFileScope().getPackageName() == null ? "" : node.getScope().getEnclosingSourceFileScope().getPackageName();
163 return<RuleViolation(this, node/getBeginLine(), node/getEndLine(), variableName, specificDescription, ctx, packageName, findClassName(node), findMethodName(node))/package-summary.html">/strong> new RuleViolation(this, node.getBeginLine(), node.getEndLine(), variableName, specificDescription, ctx, packageName, findClassName(node), findMethodName(node));
164 }
165
166 private String findMethodName(SimpleNode node) {
167 return node.getFirstParentOfType(ASTMethodDeclaration.class) == null ? "" : ((MethodScope)node.getScope().getEnclosingMethodScope()).getName();
168 }
169
170 private String findClassName(SimpleNode node) {
171 String className;
172 if (node.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class) == null) {
173
174 className = "";
175 } else {
176
177 className = node.getScope().getEnclosingClassScope().getClassName() == null ? "" : node.getScope().getEnclosingClassScope().getClassName();
178 }
179 return className;
180 }
181
182 public Properties getProperties() {
183 return properties;
184 }
185
186 public boolean include() {
187 return include;
188 }
189
190 public void setInclude(boolean include) {
191 this.include = include;
192 }
193
194 public int getPriority() {
195 return priority;
196 }
197
198 public String getPriorityName() {
199 return PRIORITIES[getPriority() - 1];
200 }
201
202 public void setPriority(int priority) {
203 this.priority = priority;
204 }
205
206 public void setUsesDFA() {
207 this.usesDFA = true;
208 }
209
210 public boolean usesDFA() {
211 return this.usesDFA;
212 }
213
214 protected void visitAll(List acus, RuleContext ctx) {
215 for (Iterator i = acus.iterator(); i.hasNext();) {
216 ASTCompilationUnit node = (ASTCompilationUnit) i.next();
217 visit(node, ctx);
218 }
219 }
220
221 /***
222 * Adds a violation to the report.
223 *
224 * @param ctx the RuleContext
225 * @param node the node that produces the violation, may be null, in which case all line and column info will be set to zero
226 */
227 protected final void addViolation(Object data, SimpleNode node) {
228 RuleContext ctx = (RuleContext)data;
229 ctx.getReport().addRuleViolation(createRuleViolation(ctx, node));
230 }
231
232 /***
233 * Adds a violation to the report.
234 *
235 * @param ctx the RuleContext
236 * @param node the node that produces the violation, may be null, in which case all line and column info will be set to zero
237 * @param embed a message to embed in the rule violation message
238 */
239 protected final void addViolation(Object data, SimpleNode node, String embed) {
240 RuleContext ctx = (RuleContext)data;
241 ctx.getReport().addRuleViolation(createRuleViolation(ctx, node, MessageFormat.format(getMessage(), new Object[]{embed})));
242 }
243
244 /***
245 * Gets the Image of the first parent node of type ASTClassOrInterfaceDeclaration or <code>null</code>
246 *
247 * @param node the node which will be searched
248 */
249 protected final String getDeclaringType(SimpleNode node) {
250 ASTClassOrInterfaceDeclaration c = (ASTClassOrInterfaceDeclaration) node.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class);
251 if (c!=null)
252 return c.getImage();
253 return null;
254 }
255
256 private final void extractNodeInfo(RuleViolation v, SimpleNode n) {
257 if (n==null) {
258 v.setLine(0);
259 v.setColumnInfo(0, 0);
260 } else {
261 v.setLine(n.getBeginLine());
262 v.setColumnInfo(n.getBeginColumn(), n.getEndColumn());
263 }
264 }
265
266 }