1 /**
2 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3 */
4 package net.sourceforge.pmd.rules.design;
5
6 import net.sourceforge.pmd.AbstractRule;
7 import net.sourceforge.pmd.ast.ASTClassOrInterfaceType;
8 import net.sourceforge.pmd.ast.ASTFieldDeclaration;
9 import net.sourceforge.pmd.ast.ASTMethodDeclaration;
10 import net.sourceforge.pmd.ast.ASTSynchronizedStatement;
11 import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;
12 import net.sourceforge.pmd.ast.SimpleNode;
13 import net.sourceforge.pmd.symboltable.NameOccurrence;
14
15 import java.util.HashSet;
16 import java.util.Set;
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 UnsynchronizedStaticDateFormatter extends AbstractRule {
31
32 private static Set<String> targets = new HashSet<String>();
33 static {
34 targets.add("DateFormat");
35 targets.add("SimpleDateFormat");
36 targets.add("java.text.DateFormat");
37 targets.add("java.text.SimpleDateFormat");
38 }
39
40 public Object visit(ASTFieldDeclaration node, Object data) {
41 if (!node.isStatic()) {
42 return data;
43 }
44 ASTClassOrInterfaceType cit = node.getFirstChildOfType(ASTClassOrInterfaceType.class);
45 if (cit == null || !targets.contains(cit.getImage())) {
46 return data;
47 }
48 ASTVariableDeclaratorId var = node.getFirstChildOfType(ASTVariableDeclaratorId.class);
49 for (NameOccurrence occ: var.getUsages()) {
50 SimpleNode n = occ.getLocation();
51 if (n.getFirstParentOfType(ASTSynchronizedStatement.class) != null) {
52 continue;
53 }
54 ASTMethodDeclaration method = n.getFirstParentOfType(ASTMethodDeclaration.class);
55 if (method != null && !method.isSynchronized()) {
56 addViolation(data, n);
57 }
58 }
59 return data;
60 }
61 }