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