Clover coverage report - PMD - 3.9 Coverage timestamp: Tue Dec 19 2006 09:38:44 EST FRAMES NO FRAMES |
file stats: | LOC: | 157 |  | Methods: | 5
| NCLOC: | 123 |  | Classes: | 1
Source file | Conditionals | Statements | Methods | TOTAL
DoubleCheckedLocking.java | 56.2% | 92.8% | 100% | 78.7% |

1 |  | /**
2 |  | * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3 |  | */
4 |  | package net.sourceforge.pmd.rules;
5 |  |
6 |  | import net.sourceforge.pmd.ast.ASTAssignmentOperator;
7 |  | import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
8 |  | import net.sourceforge.pmd.ast.ASTIfStatement;
9 |  | import net.sourceforge.pmd.ast.ASTLiteral;
10 |  | import net.sourceforge.pmd.ast.ASTMethodDeclaration;
11 |  | import net.sourceforge.pmd.ast.ASTName;
12 |  | import net.sourceforge.pmd.ast.ASTNullLiteral;
13 |  | import net.sourceforge.pmd.ast.ASTPrimaryExpression;
14 |  | import net.sourceforge.pmd.ast.ASTPrimaryPrefix;
15 |  | import net.sourceforge.pmd.ast.ASTReferenceType;
16 |  | import net.sourceforge.pmd.ast.ASTReturnStatement;
17 |  | import net.sourceforge.pmd.ast.ASTStatementExpression;
18 |  | import net.sourceforge.pmd.ast.ASTSynchronizedStatement;
19 |  | import net.sourceforge.pmd.ast.ASTType;
20 |  | import net.sourceforge.pmd.ast.Node;
21 |  |
22 |  | import java.util.ArrayList;
23 |  | import java.util.List;
24 |  |
25 |  | /**
26 |  | * void method() {
27 |  | * if(x == null) {
28 |  | * synchronized(this){
29 |  | * if(x == null) {
30 |  | * x = new | method();
31 |  | * }
32 |  | * }
33 |  | * }
34 |  | * 1. The error is when one uses the value assigned within a synchronized
35 |  | * section, outside of a synchronized section.
36 |  | * if(x == null) is outside of synchronized section
37 |  | * x = new | method();
38 |  | * <p/>
39 |  | * <p/>
40 |  | * Very very specific check for double checked locking.
41 |  | *
42 |  | * @author CL Gilbert (dnoyeb@users.sourceforge.net)
43 |  | */
44 |  | public class DoubleCheckedLocking extends net.sourceforge.pmd.AbstractRule {
45 |  |
46 | 4 | public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
47 | 4 | if (node.isInterface()) {
48 | 1 | return data;
49 |  | }
50 | 3 | return super.visit(node, data);
51 |  | }
52 |  |
53 | 3 | public Object visit(ASTMethodDeclaration node, Object data) {
54 | 3 | if (node.getResultType().isVoid()) {
55 | 1 | return super.visit(node, data);
56 |  | }
57 |  |
58 | 2 | ASTType typeNode = (ASTType) node.getResultType().jjtGetChild(0);
59 | 2 | if (typeNode.jjtGetNumChildren() == 0 || !(typeNode.jjtGetChild(0) instanceof ASTReferenceType)) {
60 | 0 | return super.visit(node, data);
61 |  | }
62 |  |
63 | 2 | List finder = new ArrayList();
64 | 2 | node.findChildrenOfType(ASTReturnStatement.class, finder, true);
65 | 2 | if (finder.size() != 1) {
66 | 1 | return super.visit(node, data);
67 |  | }
68 | 1 | ASTReturnStatement rs = (ASTReturnStatement) finder.get(0);
69 |  |
70 | 1 | finder.clear();
71 | 1 | rs.findChildrenOfType(ASTPrimaryExpression.class, finder, true);
72 | 1 | ASTPrimaryExpression ape = (ASTPrimaryExpression) finder.get(0);
73 | 1 | Node lastChild = ape.jjtGetChild(ape.jjtGetNumChildren() - 1);
74 | 1 | String returnVariableName = null;
75 | 1 | if (lastChild instanceof ASTPrimaryPrefix) {
76 | 1 | returnVariableName = getNameFromPrimaryPrefix((ASTPrimaryPrefix) lastChild);
77 |  | }
78 | 1 | if (returnVariableName == null) {
79 | 0 | return super.visit(node, data);
80 |  | }
81 | 1 | finder.clear();
82 | 1 | node.findChildrenOfType(ASTIfStatement.class, finder, true);
83 | 1 | if (finder.size() == 2) {
84 | 1 | ASTIfStatement is = (ASTIfStatement) finder.get(0);
85 | 1 | if (ifVerify(is, returnVariableName)) {
86 |  | //find synchronized
87 | 1 | finder.clear();
88 | 1 | is.findChildrenOfType(ASTSynchronizedStatement.class, finder, true);
89 | 1 | if (finder.size() == 1) {
90 | 1 | ASTSynchronizedStatement ss = (ASTSynchronizedStatement) finder.get(0);
91 | 1 | finder.clear();
92 | 1 | ss.findChildrenOfType(ASTIfStatement.class, finder, true);
93 | 1 | if (finder.size() == 1) {
94 | 1 | ASTIfStatement is2 = (ASTIfStatement) finder.get(0);
95 | 1 | if (ifVerify(is2, returnVariableName)) {
96 | 1 | finder.clear();
97 | 1 | is2.findChildrenOfType(ASTStatementExpression.class, finder, true);
98 | 1 | if (finder.size() == 1) {
99 | 1 | ASTStatementExpression se = (ASTStatementExpression) finder.get(0);
100 | 1 | if (se.jjtGetNumChildren() == 3) { //primaryExpression, AssignmentOperator, Expression
101 | 1 | if (se.jjtGetChild(0) instanceof ASTPrimaryExpression) {
102 | 1 | ASTPrimaryExpression pe = (ASTPrimaryExpression) se.jjtGetChild(0);
103 | 1 | if (matchName(pe, returnVariableName)) {
104 | 1 | if (se.jjtGetChild(1) instanceof ASTAssignmentOperator) {
105 | 1 | addViolation(data, node);
106 |  | }
107 |  | }
108 |  | }
109 |  | }
110 |  | }
111 |  | }
112 |  | }
113 |  | }
114 |  | }
115 |  | }
116 | 1 | return super.visit(node, data);
117 |  | }
118 |  |
119 | 2 | private boolean ifVerify(ASTIfStatement is, String varname) {
120 | 2 | List finder = new ArrayList();
121 | 2 | is.findChildrenOfType(ASTPrimaryExpression.class, finder, true);
122 | 2 | if (finder.size() > 1) {
123 | 2 | ASTPrimaryExpression apeLeft = (ASTPrimaryExpression) finder.get(0);
124 | 2 | if (matchName(apeLeft, varname)) {
125 | 2 | ASTPrimaryExpression apeRight = (ASTPrimaryExpression) finder.get(1);
126 | 2 | if ((apeRight.jjtGetNumChildren() == 1) && (apeRight.jjtGetChild(0) instanceof ASTPrimaryPrefix)) {
127 | 2 | ASTPrimaryPrefix pp2 = (ASTPrimaryPrefix) apeRight.jjtGetChild(0);
128 | 2 | if ((pp2.jjtGetNumChildren() == 1) && (pp2.jjtGetChild(0) instanceof ASTLiteral)) {
129 | 2 | ASTLiteral lit = (ASTLiteral) pp2.jjtGetChild(0);
130 | 2 | if ((lit.jjtGetNumChildren() == 1) && (lit.jjtGetChild(0) instanceof ASTNullLiteral)) {
131 | 2 | return true;
132 |  | }
133 |  | }
134 |  | }
135 |  | }
136 |  | }
137 | 0 | return false;
138 |  | }
139 |  |
140 | 3 | private boolean matchName(ASTPrimaryExpression ape, String name) {
141 | 3 | if ((ape.jjtGetNumChildren() == 1) && (ape.jjtGetChild(0) instanceof ASTPrimaryPrefix)) {
142 | 3 | ASTPrimaryPrefix pp = (ASTPrimaryPrefix) ape.jjtGetChild(0);
143 | 3 | String name2 = getNameFromPrimaryPrefix(pp);
144 | 3 | if (name2 != null && name2.equals(name)) {
145 | 3 | return true;
146 |  | }
147 |  | }
148 | 0 | return false;
149 |  | }
150 |  |
151 | 4 | private String getNameFromPrimaryPrefix(ASTPrimaryPrefix pp) {
152 | 4 | if ((pp.jjtGetNumChildren() == 1) && (pp.jjtGetChild(0) instanceof ASTName)) {
153 | 4 | return ((ASTName) pp.jjtGetChild(0)).getImage();
154 |  | }
155 | 0 | return null;
156 |  | }
157 |  | }