View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.java.rule.sunsecure;
5   
6   import java.util.List;
7   
8   import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
9   import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
10  import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
11  import net.sourceforge.pmd.lang.java.ast.ASTName;
12  import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
13  import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
14  import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
15  import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
16  import net.sourceforge.pmd.lang.java.ast.ASTTypeDeclaration;
17  
18  /**
19   * Implementation note: this rule currently ignores return types of y.x.z,
20   * currently it handles only local type fields.
21   * Created on Jan 17, 2005
22   *
23   * @author mgriffa
24   */
25  public class MethodReturnsInternalArrayRule extends AbstractSunSecureRule {
26  
27      @Override
28      public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
29          if (node.isInterface()) {
30              return data;
31          }
32          return super.visit(node, data);
33      }
34  
35      @Override
36      public Object visit(ASTMethodDeclaration method, Object data) {
37          if (!method.getResultType().returnsArray() || method.isPrivate()) {
38              return data;
39          }
40          List<ASTReturnStatement> returns = method.findDescendantsOfType(ASTReturnStatement.class);
41          ASTTypeDeclaration td = method.getFirstParentOfType(ASTTypeDeclaration.class);
42          for (ASTReturnStatement ret: returns) {
43              final String vn = getReturnedVariableName(ret);
44              if (!isField(vn, td)) {
45                  continue;
46              }
47              if (ret.findDescendantsOfType(ASTPrimarySuffix.class).size() > 2) {
48                  continue;
49              }
50              if (ret.hasDescendantOfType(ASTAllocationExpression.class)) {
51                  continue;
52              }
53              if (hasArraysCopyOf(ret)) {
54                  continue;
55              }
56              if (hasClone(ret, vn)) {
57                  continue;
58              }
59              if (!isLocalVariable(vn, method)) {
60                  addViolation(data, ret, vn);
61              } else {
62                  // This is to handle field hiding
63                  final ASTPrimaryPrefix pp = ret.getFirstDescendantOfType(ASTPrimaryPrefix.class);
64                  if (pp != null && pp.usesThisModifier()) {
65                      final ASTPrimarySuffix ps = ret.getFirstDescendantOfType(ASTPrimarySuffix.class);
66                      if (ps.hasImageEqualTo(vn)) {
67                          addViolation(data, ret, vn);
68                      }
69                  }
70              }
71          }
72          return data;
73      }
74  
75      private boolean hasClone(ASTReturnStatement ret, String varName) {
76          List<ASTPrimaryExpression> expressions = ret.findDescendantsOfType(ASTPrimaryExpression.class);
77          for (ASTPrimaryExpression e : expressions) {
78              if (e.jjtGetChild(0) instanceof ASTPrimaryPrefix
79                      && e.jjtGetNumChildren() == 2
80                      && e.jjtGetChild(1) instanceof ASTPrimarySuffix
81                      && ((ASTPrimarySuffix) e.jjtGetChild(1)).isArguments()
82                      && ((ASTPrimarySuffix) e.jjtGetChild(1)).getArgumentCount() == 0) {
83                  ASTName name = e.getFirstDescendantOfType(ASTName.class);
84                  if (name != null && name.hasImageEqualTo(varName + ".clone")) {
85                      return true;
86                  }
87              }
88          }
89          return false;
90      }
91  
92      private boolean hasArraysCopyOf(ASTReturnStatement ret) {
93          List<ASTPrimaryExpression> expressions = ret.findDescendantsOfType(ASTPrimaryExpression.class);
94          for (ASTPrimaryExpression e : expressions) {
95              if (e.jjtGetNumChildren() == 2 && e.jjtGetChild(0) instanceof ASTPrimaryPrefix
96                      && e.jjtGetChild(0).jjtGetNumChildren() == 1 && e.jjtGetChild(0).jjtGetChild(0) instanceof ASTName
97                      && e.jjtGetChild(0).jjtGetChild(0).getImage().endsWith("Arrays.copyOf")) {
98                  return true;
99              }
100         }
101         return false;
102     }
103 }