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

This page was automatically generated by Maven