View Javadoc

    1   /*
    2    * Created on Jan 17, 2005
    3    *
    4    * $Id$
    5    */
    6   package net.sourceforge.pmd.lang.java.rule.sunsecure;
    7
    8   import java.util.ArrayList;
    9   import java.util.List;
    10
    11  import net.sourceforge.pmd.lang.ast.Node;
    12  import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator;
    13  import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement;
    14  import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
    15  import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
    16  import net.sourceforge.pmd.lang.java.ast.ASTEqualityExpression;
    17  import net.sourceforge.pmd.lang.java.ast.ASTExpression;
    18  import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
    19  import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters;
    20  import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
    21  import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
    22  import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
    23  import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
    24  import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
    25  import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
    26
    27  /**
    28   * @author mgriffa
    29   */
    30  public class ArrayIsStoredDirectlyRule extends AbstractSunSecureRule {
    31
    32      @Override
    33      public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
    34          if (node.isInterface()) {
    35              return data;
    36          }
    37          return super.visit(node, data);
    38      }
    39
    40      @Override
    41      public Object visit(ASTConstructorDeclaration node, Object data) {
    42          ASTFormalParameter[] arrs = getArrays(node.getParameters());
    43          if (arrs != null) {
    44              //TODO check if one of these arrays is stored in a non local variable
    45              List<ASTBlockStatement> bs = node.findDescendantsOfType(ASTBlockStatement.class);
    46              checkAll(data, arrs, bs);
    47          }
    48          return data;
    49      }
    50
    51      @Override
    52      public Object visit(ASTMethodDeclaration node, Object data) {
    53          final ASTFormalParameters params = node.getFirstDescendantOfType(ASTFormalParameters.class);
    54          ASTFormalParameter[] arrs = getArrays(params);
    55          if (arrs != null) {
    56              checkAll(data, arrs, node.findDescendantsOfType(ASTBlockStatement.class));
    57          }
    58          return data;
    59      }
    60
    61      private void checkAll(Object context, ASTFormalParameter[] arrs, List<ASTBlockStatement> bs) {
    62          for (ASTFormalParameter element : arrs) {
    63              checkForDirectAssignment(context, element, bs);
    64          }
    65      }
    66
    67      private String getExpressionVarName(Node e) {
    68          String assignedVar = getFirstNameImage(e);
    69          if (assignedVar == null) {
    70              ASTPrimarySuffix suffix = e.getFirstDescendantOfType(ASTPrimarySuffix.class);
    71              if (suffix != null) {
    72                  assignedVar = suffix.getImage();
    73                  ASTPrimaryPrefix prefix = e.getFirstDescendantOfType(ASTPrimaryPrefix.class);
    74                  if (prefix != null) {
    75                      if (prefix.usesThisModifier()) {
    76                          assignedVar = "this." + assignedVar;
    77                      } else if (prefix.usesSuperModifier()) {
    78                          assignedVar = "super." + assignedVar;
    79                      }
    80                  }
    81              }
    82          }
    83          return assignedVar;
    84      }
    85
    86      /**
    87       * Checks if the variable designed in parameter is written to a field (not local variable) in the statements.
    88       */
    89      private boolean checkForDirectAssignment(Object ctx, final ASTFormalParameter parameter, final List<ASTBlockStatement> bs) {
    90          final ASTVariableDeclaratorId vid = parameter.getFirstDescendantOfType(ASTVariableDeclaratorId.class);
    91          final String varName = vid.getImage();
    92          for (ASTBlockStatement b: bs) {
    93              if (b.hasDescendantOfType(ASTAssignmentOperator.class)) {
    94                  final ASTStatementExpression se = b.getFirstDescendantOfType(ASTStatementExpression.class);
    95                  if (se == null || !(se.jjtGetChild(0) instanceof ASTPrimaryExpression)) {
    96                      continue;
    97                  }
    98                  ASTPrimaryExpression pe = (ASTPrimaryExpression) se.jjtGetChild(0);
    99                  String assignedVar = getExpressionVarName(pe);
    100                 if (assignedVar == null) {
    101                     continue;
    102                 }
    103
    104                 Node n = pe.getFirstParentOfType(ASTMethodDeclaration.class);
    105                 if (n == null) {
    106 					n = pe.getFirstParentOfType(ASTConstructorDeclaration.class);
    107 					if (n == null) {
    108 						continue;
    109 					}
    110 				}
    111                 if (!isLocalVariable(assignedVar, n)) {
    112                     // TODO could this be more clumsy?  We really
    113                     // need to build out the PMD internal framework more
    114                     // to support simply queries like "isAssignedTo()" or something
    115                     if (se.jjtGetNumChildren() < 3) {
    116                         continue;
    117                     }
    118                     ASTExpression e = (ASTExpression) se.jjtGetChild(2);
    119                     if (e.hasDescendantOfType(ASTEqualityExpression.class)) {
    120                         continue;
    121                     }
    122                     String val = getExpressionVarName(e);
    123                     if (val == null) {
    124                         continue;
    125                     }
    126                     ASTPrimarySuffix foo = se.getFirstDescendantOfType(ASTPrimarySuffix.class);
    127                     if (foo != null && foo.isArrayDereference()) {
    128                         continue;
    129                     }
    130
    131                     if (val.equals(varName)) {
    132                 	Node md = parameter.getFirstParentOfType(ASTMethodDeclaration.class);
    133                         if (md == null) {
    134                         	md = pe.getFirstParentOfType(ASTConstructorDeclaration.class);
    135         				}
    136                         if (!isLocalVariable(varName, md)) {
    137                             addViolation(ctx, parameter, varName);
    138                         }
    139                     }
    140                 }
    141             }
    142         }
    143         return false;
    144     }
    145
    146     private final ASTFormalParameter[] getArrays(ASTFormalParameters params) {
    147         final List<ASTFormalParameter> l = params.findChildrenOfType(ASTFormalParameter.class);
    148         if (l != null && !l.isEmpty()) {
    149             List<ASTFormalParameter> l2 = new ArrayList<ASTFormalParameter>();
    150             for (ASTFormalParameter fp: l) {
    151                 if (fp.isArray()) {
    152 		    l2.add(fp);
    153 		}
    154             }
    155             return l2.toArray(new ASTFormalParameter[l2.size()]);
    156         }
    157         return null;
    158     }
    159
    160 }