UnsynchronizedStaticDateFormatterRule.java
01 /**
02  * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
03  */
04 package net.sourceforge.pmd.lang.java.rule.design;
05 
06 import java.util.Set;
07 
08 import net.sourceforge.pmd.lang.ast.Node;
09 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
10 import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
11 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
12 import net.sourceforge.pmd.lang.java.ast.ASTSynchronizedStatement;
13 import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
14 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
15 import net.sourceforge.pmd.lang.java.symboltable.NameOccurrence;
16 import net.sourceforge.pmd.util.CollectionUtil;
17 
18 /**
19  * Using a DateFormatter (SimpleDateFormatter) which is static can cause
20  * unexpected results when used in a multi-threaded environment. This rule will
21  * find static (Simple)DateFormatters which are used in an unsynchronized
22  * manner.
23  * Refer to these Bug Parade issues:
24  * <a href="http://developer.java.sun.com/developer/bugParade/bugs/4093418.html">4093418</a>
25  * <a href="http://developer.java.sun.com/developer/bugParade/bugs/4228335.html">4228335</a>
26  * <a href="http://developer.java.sun.com/developer/bugParade/bugs/4261469.html">4261469</a>
27  * see RFE1020790 - Check for SimpleDateFormat as singleton http://sourceforge.net/tracker/index.php?func=detail&aid=1020790&group_id=56262&atid=479924
28  @author Allan Caplan
29  */
30 public class UnsynchronizedStaticDateFormatterRule extends AbstractJavaRule {
31 
32     private static Set<String> targets = CollectionUtil.asSet(new String[] {
33       "DateFormat""SimpleDateFormat""java.text.DateFormat","java.text.SimpleDateFormat"
34       });
35 
36     @Override
37     public Object visit(ASTFieldDeclaration node, Object data) {
38         if (!node.isStatic()) {
39             return data;
40         }
41         ASTClassOrInterfaceType cit = node.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
42         if (cit == null || !targets.contains(cit.getImage())) {
43             return data;
44         }
45         ASTVariableDeclaratorId var = node.getFirstDescendantOfType(ASTVariableDeclaratorId.class);
46         for (NameOccurrence occ: var.getUsages()) {
47             Node n = occ.getLocation();
48             if (n.getFirstParentOfType(ASTSynchronizedStatement.class!= null) {
49                 continue;
50             }
51             ASTMethodDeclaration method = n.getFirstParentOfType(ASTMethodDeclaration.class);
52             if (method != null && !method.isSynchronized()) {
53                 addViolation(data, n);
54             }
55         }
56         return data;
57     }
58 }