View Javadoc

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