View Javadoc

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