1
2
3
4 package net.sourceforge.pmd.lang.java.rule.sunsecure;
5
6 import java.util.List;
7
8 import org.jaxen.JaxenException;
9
10 import net.sourceforge.pmd.lang.ast.Node;
11 import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
12 import net.sourceforge.pmd.lang.java.ast.ASTArrayInitializer;
13 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
14 import net.sourceforge.pmd.lang.java.ast.ASTExpression;
15 import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
16 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
17 import net.sourceforge.pmd.lang.java.ast.ASTName;
18 import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
19 import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
20 import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
21 import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
22 import net.sourceforge.pmd.lang.java.ast.ASTTypeDeclaration;
23 import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
24 import net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer;
25
26
27
28
29
30
31
32
33 public class MethodReturnsInternalArrayRule extends AbstractSunSecureRule {
34
35 @Override
36 public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
37 if (node.isInterface()) {
38 return data;
39 }
40 return super.visit(node, data);
41 }
42
43 @Override
44 public Object visit(ASTMethodDeclaration method, Object data) {
45 if (!method.getResultType().returnsArray() || method.isPrivate()) {
46 return data;
47 }
48 List<ASTReturnStatement> returns = method.findDescendantsOfType(ASTReturnStatement.class);
49 ASTTypeDeclaration td = method.getFirstParentOfType(ASTTypeDeclaration.class);
50 for (ASTReturnStatement ret: returns) {
51 final String vn = getReturnedVariableName(ret);
52 if (!isField(vn, td)) {
53 continue;
54 }
55 if (ret.findDescendantsOfType(ASTPrimarySuffix.class).size() > 2) {
56 continue;
57 }
58 if (ret.hasDescendantOfType(ASTAllocationExpression.class)) {
59 continue;
60 }
61 if (hasArraysCopyOf(ret)) {
62 continue;
63 }
64 if (hasClone(ret, vn)) {
65 continue;
66 }
67 if (isEmptyArray(vn, td)) {
68 continue;
69 }
70 if (!isLocalVariable(vn, method)) {
71 addViolation(data, ret, vn);
72 } else {
73
74 final ASTPrimaryPrefix pp = ret.getFirstDescendantOfType(ASTPrimaryPrefix.class);
75 if (pp != null && pp.usesThisModifier()) {
76 final ASTPrimarySuffix ps = ret.getFirstDescendantOfType(ASTPrimarySuffix.class);
77 if (ps.hasImageEqualTo(vn)) {
78 addViolation(data, ret, vn);
79 }
80 }
81 }
82 }
83 return data;
84 }
85
86 private boolean hasClone(ASTReturnStatement ret, String varName) {
87 List<ASTPrimaryExpression> expressions = ret.findDescendantsOfType(ASTPrimaryExpression.class);
88 for (ASTPrimaryExpression e : expressions) {
89 if (e.jjtGetChild(0) instanceof ASTPrimaryPrefix
90 && e.jjtGetNumChildren() == 2
91 && e.jjtGetChild(1) instanceof ASTPrimarySuffix
92 && ((ASTPrimarySuffix) e.jjtGetChild(1)).isArguments()
93 && ((ASTPrimarySuffix) e.jjtGetChild(1)).getArgumentCount() == 0) {
94 ASTName name = e.getFirstDescendantOfType(ASTName.class);
95 if (name != null && name.hasImageEqualTo(varName + ".clone")) {
96 return true;
97 }
98 }
99 }
100 return false;
101 }
102
103 private boolean hasArraysCopyOf(ASTReturnStatement ret) {
104 List<ASTPrimaryExpression> expressions = ret.findDescendantsOfType(ASTPrimaryExpression.class);
105 for (ASTPrimaryExpression e : expressions) {
106 if (e.jjtGetNumChildren() == 2 && e.jjtGetChild(0) instanceof ASTPrimaryPrefix
107 && e.jjtGetChild(0).jjtGetNumChildren() == 1 && e.jjtGetChild(0).jjtGetChild(0) instanceof ASTName
108 && e.jjtGetChild(0).jjtGetChild(0).getImage().endsWith("Arrays.copyOf")) {
109 return true;
110 }
111 }
112 return false;
113 }
114
115 private boolean isEmptyArray(String varName, ASTTypeDeclaration typeDeclaration) {
116 final List<ASTFieldDeclaration> fds = typeDeclaration.findDescendantsOfType(ASTFieldDeclaration.class);
117 if (fds != null) {
118 for (ASTFieldDeclaration fd : fds) {
119 final ASTVariableDeclaratorId vid = fd.getFirstDescendantOfType(ASTVariableDeclaratorId.class);
120 if (vid != null && vid.hasImageEqualTo(varName)) {
121 ASTVariableInitializer initializer = fd.getFirstDescendantOfType(ASTVariableInitializer.class);
122 if (initializer != null && initializer.jjtGetNumChildren() == 1) {
123 Node child = initializer.jjtGetChild(0);
124 if (child instanceof ASTArrayInitializer && child.jjtGetNumChildren() == 0) {
125 return true;
126 } else if (child instanceof ASTExpression) {
127 try {
128 List<? extends Node> arrayAllocation = child.findChildNodesWithXPath("./PrimaryExpression/PrimaryPrefix/AllocationExpression/ArrayDimsAndInits/Expression/PrimaryExpression/PrimaryPrefix/Literal[@IntLiteral=\"true\"][@Image=\"0\"]");
129 if (arrayAllocation != null && arrayAllocation.size() == 1) {
130 return true;
131 }
132 } catch (JaxenException e) {
133 return false;
134 }
135 }
136 }
137 }
138 }
139 }
140 return false;
141 }
142 }