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.Iterator; 17 import java.util.Set; 18 19 /*** 20 * Using a DateFormatter (SimpleDateFormatter) which is static can cause 21 * unexpected results when used in a multi threaded environment. This rule will 22 * find static (Simple)DateFormatters which are used in an unsynchronized 23 * manner. 24 * 25 * @link http://developer.java.sun.com/developer/bugParade/bugs/4093418.html 26 * @link http://developer.java.sun.com/developer/bugParade/bugs/4228335.html 27 * @link http://developer.java.sun.com/developer/bugParade/bugs/4261469.html 28 * @see RFE1020790 - Check for SimpleDateFormat as singleton http://sourceforge.net/tracker/index.php?func=detail&aid=1020790&group_id=56262&atid=479924 29 * @author Allan Caplan 30 */ 31 public class UnsynchronizedStaticDateFormatter extends AbstractRule { 32 33 private static Set targets = new HashSet(); 34 static { 35 targets.add("DateFormat"); 36 targets.add("SimpleDateFormat"); 37 targets.add("java.text.DateFormat"); 38 targets.add("java.text.SimpleDateFormat"); 39 } 40 41 public Object visit(ASTFieldDeclaration node, Object data) { 42 if (!node.isStatic()) { 43 return data; 44 } 45 ASTClassOrInterfaceType cit = (ASTClassOrInterfaceType) node.getFirstChildOfType(ASTClassOrInterfaceType.class); 46 if (cit == null || !targets.contains(cit.getImage())) { 47 return data; 48 } 49 ASTVariableDeclaratorId var = (ASTVariableDeclaratorId) node.getFirstChildOfType(ASTVariableDeclaratorId.class); 50 for (Iterator i = var.getUsages().iterator(); i.hasNext();) { 51 NameOccurrence occ = (NameOccurrence) i.next(); 52 SimpleNode n = occ.getLocation(); 53 if ((ASTSynchronizedStatement) n.getFirstParentOfType(ASTSynchronizedStatement.class) != null) { 54 continue; 55 } 56 ASTMethodDeclaration method = (ASTMethodDeclaration) n.getFirstParentOfType(ASTMethodDeclaration.class); 57 if (method != null && !method.isSynchronized()) { 58 addViolation(data, n); 59 } 60 } 61 return data; 62 } 63 }