View Javadoc

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  }