ArrayIsStoredDirectlyRule.java
001 /*
002  * Created on Jan 17, 2005
003  *
004  * $Id: ArrayIsStoredDirectlyRule.java 6245 2008-06-22 18:07:30Z xlv $
005  */
006 package net.sourceforge.pmd.lang.java.rule.sunsecure;
007 
008 import java.util.ArrayList;
009 import java.util.List;
010 
011 import net.sourceforge.pmd.lang.ast.Node;
012 import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator;
013 import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement;
014 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
015 import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
016 import net.sourceforge.pmd.lang.java.ast.ASTEqualityExpression;
017 import net.sourceforge.pmd.lang.java.ast.ASTExpression;
018 import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
019 import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters;
020 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
021 import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
022 import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
023 import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
024 import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
025 
026 /**
027  @author mgriffa
028  */
029 public class ArrayIsStoredDirectlyRule extends AbstractSunSecureRule {
030 
031     @Override
032     public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
033         if (node.isInterface()) {
034             return data;
035         }
036         return super.visit(node, data);
037     }
038 
039     @Override
040     public Object visit(ASTConstructorDeclaration node, Object data) {
041         ASTFormalParameter[] arrs = getArrays(node.getParameters());
042         if (arrs != null) {
043             //TODO check if one of these arrays is stored in a non local variable
044             List<ASTBlockStatement> bs = node.findDescendantsOfType(ASTBlockStatement.class);
045             checkAll(data, arrs, bs);
046         }
047         return data;
048     }
049 
050     @Override
051     public Object visit(ASTMethodDeclaration node, Object data) {
052         final ASTFormalParameters params = node.getFirstDescendantOfType(ASTFormalParameters.class);
053         ASTFormalParameter[] arrs = getArrays(params);
054         if (arrs != null) {
055             checkAll(data, arrs, node.findDescendantsOfType(ASTBlockStatement.class));
056         }
057         return data;
058     }
059 
060     private void checkAll(Object context, ASTFormalParameter[] arrs, List<ASTBlockStatement> bs) {
061         for (ASTFormalParameter element : arrs) {
062             checkForDirectAssignment(context, element, bs);
063         }
064     }
065 
066     /**
067      * Checks if the variable designed in parameter is written to a field (not local variable) in the statements.
068      */
069     private boolean checkForDirectAssignment(Object ctx, final ASTFormalParameter parameter, final List<ASTBlockStatement> bs) {
070         final ASTVariableDeclaratorId vid = parameter.getFirstDescendantOfType(ASTVariableDeclaratorId.class);
071         final String varName = vid.getImage();
072         for (ASTBlockStatement b: bs) {
073             if (b.hasDescendantOfType(ASTAssignmentOperator.class)) {
074                 final ASTStatementExpression se = b.getFirstDescendantOfType(ASTStatementExpression.class);
075                 if (se == null || !(se.jjtGetChild(0instanceof ASTPrimaryExpression)) {
076                     continue;
077                 }
078                 ASTPrimaryExpression pe = (ASTPrimaryExpressionse.jjtGetChild(0);
079                 String assignedVar = getFirstNameImage(pe);
080                 if (assignedVar == null) {
081                     ASTPrimarySuffix suffix = se.getFirstDescendantOfType(ASTPrimarySuffix.class);
082                     if (suffix == null) {
083                         continue;
084                     }
085                     assignedVar = suffix.getImage();
086                 }
087 
088                 Node n = pe.getFirstParentOfType(ASTMethodDeclaration.class);
089                 if (n == null) {
090           n = pe.getFirstParentOfType(ASTConstructorDeclaration.class);
091           if (n == null) {
092             continue;
093           }
094         }
095                 if (!isLocalVariable(assignedVar, n)) {
096                     // TODO could this be more clumsy?  We really
097                     // need to build out the PMD internal framework more
098                     // to support simply queries like "isAssignedTo()" or something
099                     if (se.jjtGetNumChildren() 3) {
100                         continue;
101                     }
102                     ASTExpression e = (ASTExpressionse.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 }