View Javadoc
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