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 }