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 }