1 package net.sourceforge.pmd.rules;
2
3 import net.sourceforge.pmd.RuleContext;
4 import net.sourceforge.pmd.ast.ASTAssignmentOperator;
5 import net.sourceforge.pmd.ast.ASTClassDeclaration;
6 import net.sourceforge.pmd.ast.ASTIfStatement;
7 import net.sourceforge.pmd.ast.ASTInterfaceDeclaration;
8 import net.sourceforge.pmd.ast.ASTLiteral;
9 import net.sourceforge.pmd.ast.ASTMethodDeclaration;
10 import net.sourceforge.pmd.ast.ASTName;
11 import net.sourceforge.pmd.ast.ASTNestedClassDeclaration;
12 import net.sourceforge.pmd.ast.ASTNestedInterfaceDeclaration;
13 import net.sourceforge.pmd.ast.ASTNullLiteral;
14 import net.sourceforge.pmd.ast.ASTPrimaryExpression;
15 import net.sourceforge.pmd.ast.ASTPrimaryPrefix;
16 import net.sourceforge.pmd.ast.ASTResultType;
17 import net.sourceforge.pmd.ast.ASTReturnStatement;
18 import net.sourceforge.pmd.ast.ASTStatementExpression;
19 import net.sourceforge.pmd.ast.ASTSynchronizedStatement;
20 import net.sourceforge.pmd.ast.ASTType;
21 import net.sourceforge.pmd.ast.Node;
22
23 import java.util.ArrayList;
24 import java.util.List;
25
26 /***
27 * void method() {
28 * if(x == null) {
29 * synchronize(this){
30 * if(x == null) {
31 * x = new | method();
32 * }
33 * }
34 * }
35 * 1. The error is when one uses the value assigned within a synchronized
36 * section, outside of a synchronized section.
37 * if(x == null) is outside of synchronized section
38 * x = new | method();
39 *
40 *
41 * Very very specific check for double checked locking.
42 *
43 * @author CL Gilbert (dnoyeb@users.sourceforge.net)
44 */
45 public class DoubleCheckedLockingRule extends net.sourceforge.pmd.AbstractRule {
46
47 private boolean interfaceSkipper;
48
49 public Object visit(ASTMethodDeclaration node, Object data) {
50 if (interfaceSkipper == true) {//skip methods in interfaces
51 return super.visit(node, data);
52 }
53 ASTResultType rt = (ASTResultType) node.jjtGetChild(0);
54 if (rt.isVoid() == true) {
55 return super.visit(node, data);
56 }
57 ASTType t = (ASTType) rt.jjtGetChild(0);
58 if (t.jjtGetNumChildren() == 0 || !(t.jjtGetChild(0) instanceof ASTName)) {
59 return super.visit(node, data);
60 }
61 String returnVariableName = null;
62 List finder = new ArrayList();
63 GET_RETURN_VARIABLE_NAME:{
64 node.findChildrenOfType(ASTReturnStatement.class, finder, true);
65 if (finder.size() != 1) {
66 return super.visit(node, data);
67 }
68 ASTReturnStatement rs = (ASTReturnStatement) finder.get(0);//EXPLODES IF THE CLASS IS AN INTERFACE SINCE NO RETURN
69
70 finder.clear();
71 rs.findChildrenOfType(ASTPrimaryExpression.class, finder, true);
72 ASTPrimaryExpression ape = (ASTPrimaryExpression) finder.get(0);
73 Node lastChild = ape.jjtGetChild(ape.jjtGetNumChildren() - 1);
74 if (lastChild instanceof ASTPrimaryPrefix) {
75 returnVariableName = getNameFromPrimaryPrefix((ASTPrimaryPrefix) lastChild);
76 }
77 if (returnVariableName == null) {
78 return super.visit(node, data);
79 }
80 }
81 CHECK_OUTER_IF:{
82 finder.clear();
83 node.findChildrenOfType(ASTIfStatement.class, finder, true);
84 if (finder.size() == 2) {
85 ASTIfStatement is = (ASTIfStatement) finder.get(0);
86 if (ifVerify(is, returnVariableName)) {
87 //find synchronize
88 finder.clear();
89 is.findChildrenOfType(ASTSynchronizedStatement.class, finder, true);
90 if (finder.size() == 1) {
91 ASTSynchronizedStatement ss = (ASTSynchronizedStatement) finder.get(0);
92 finder.clear();
93 ss.findChildrenOfType(ASTIfStatement.class, finder, true);
94 if (finder.size() == 1) {
95 ASTIfStatement is2 = (ASTIfStatement) finder.get(0);
96 if (ifVerify(is2, returnVariableName)) {
97 finder.clear();
98 is2.findChildrenOfType(ASTStatementExpression.class, finder, true);
99 if (finder.size() == 1) {
100 ASTStatementExpression se = (ASTStatementExpression) finder.get(0);
101 if (se.jjtGetNumChildren() == 3) { //primaryExpression, AssignmentOperator, Expression
102 if (se.jjtGetChild(0) instanceof ASTPrimaryExpression) {
103 ASTPrimaryExpression pe = (ASTPrimaryExpression) se.jjtGetChild(0);
104 if (matchName(pe, returnVariableName)) {
105 if (se.jjtGetChild(1) instanceof ASTAssignmentOperator) {
106 RuleContext ctx = (RuleContext) data;
107 ctx.getReport().addRuleViolation(createRuleViolation(ctx, node.getBeginLine()));
108 }
109 }
110 }
111 }
112 }
113 }
114 }
115 }
116 }
117 }
118 }
119 return super.visit(node, data);
120 }
121
122 private boolean ifVerify(ASTIfStatement is, String varname) {
123 List finder = new ArrayList();
124 is.findChildrenOfType(ASTPrimaryExpression.class, finder, true);
125 if (finder.size() > 1) {
126 ASTPrimaryExpression apeLeft = (ASTPrimaryExpression) finder.get(0);
127 if (matchName(apeLeft, varname)) {
128 ASTPrimaryExpression apeRight = (ASTPrimaryExpression) finder.get(1);
129 if ((apeRight.jjtGetNumChildren() == 1) && (apeRight.jjtGetChild(0) instanceof ASTPrimaryPrefix)) {
130 ASTPrimaryPrefix pp2 = (ASTPrimaryPrefix) apeRight.jjtGetChild(0);
131 if ((pp2.jjtGetNumChildren() == 1) && (pp2.jjtGetChild(0) instanceof ASTLiteral)) {
132 ASTLiteral lit = (ASTLiteral) pp2.jjtGetChild(0);
133 if ((lit.jjtGetNumChildren() == 1) && (lit.jjtGetChild(0) instanceof ASTNullLiteral)) {
134 return true;
135 }
136 }
137 }
138 }
139 }
140 return false;
141 }
142
143 public Object visit(ASTClassDeclaration node, Object data) {
144 boolean temp = interfaceSkipper;
145 interfaceSkipper = false;
146 // String className = ((ASTUnmodifiedClassDeclaration)node.jjtGetChild(0)).getImage();
147 // System.out.println("classname = " + className);
148 Object o = super.visit(node, data);
149 interfaceSkipper = temp;
150 return o;
151 }
152
153 public Object visit(ASTNestedClassDeclaration node, Object data) {
154 boolean temp = interfaceSkipper;
155 interfaceSkipper = false;
156 // String className = ((ASTUnmodifiedNestedClassDeclaration)node.jjtGetChild(0)).getImage();
157 // System.out.println("classname = " + className);
158 Object o = super.visit(node, data);
159 interfaceSkipper = temp;
160 return o;
161 }
162
163 public Object visit(ASTInterfaceDeclaration node, Object data) {
164 boolean temp = interfaceSkipper;
165 interfaceSkipper = true;
166 Object o = super.visit(node, data);
167 interfaceSkipper = temp;
168 return o;
169 }
170
171 public Object visit(ASTNestedInterfaceDeclaration node, Object data) {
172 boolean temp = interfaceSkipper;
173 interfaceSkipper = true;
174 Object o = super.visit(node, data);
175 interfaceSkipper = temp;
176 return o;
177 }
178
179 public boolean matchName(ASTPrimaryExpression ape, String name) {
180 if ((ape.jjtGetNumChildren() == 1) && (ape.jjtGetChild(0) instanceof ASTPrimaryPrefix)) {
181 ASTPrimaryPrefix pp = (ASTPrimaryPrefix) ape.jjtGetChild(0);
182 String name2 = getNameFromPrimaryPrefix(pp);
183 if (name2 != null && name2.equals(name)) {
184 return true;
185 }
186 }
187 return false;
188 }
189
190 public String getNameFromPrimaryPrefix(ASTPrimaryPrefix pp) {
191 if ((pp.jjtGetNumChildren() == 1) && (pp.jjtGetChild(0) instanceof ASTName)) {
192 String name2 = ((ASTName) pp.jjtGetChild(0)).getImage();
193 return name2;
194 }
195 return null;
196 }
197 //Testing Section
198 // public Object visit(ASTCompilationUnit node, Object data) {
199 // interfaceSkipper = false; //safety
200 // try {
201 // return super.visit(node,data);
202 // }
203 // catch(Exception e){
204 // e.printStackTrace();
205 // throw new RuntimeException(e.getMessage());
206 // }
207 // }
208 // public Object visit(ASTMethodDeclarator node, Object data) {
209 // System.out.println("method = " + node.getImage());
210 // return super.visit(node,data);
211 // }
212 //
213 // public Object visit(ASTPackageDeclaration node, Object data){
214 // String name = ((ASTName)node.jjtGetChild(0)).getImage();
215 // System.out.println("package = " + name);
216 // return super.visit(node, data);
217 // }
218 }
This page was automatically generated by Maven