View Javadoc

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; // trivial
116         }
117         
118         if (this == o) {
119             return true;  // trivial
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             // This takes care of nodes which are outside a class definition - i.e., import declarations
174             className = "";
175         } else {
176              // default to symbol table lookup
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 }