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.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  }