1 4 package net.sourceforge.pmd.dfa; 5 6 import net.sourceforge.pmd.AbstractRule; 7 import net.sourceforge.pmd.PropertyDescriptor; 8 import net.sourceforge.pmd.RuleContext; 9 import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration; 10 import net.sourceforge.pmd.ast.ASTMethodDeclaration; 11 import net.sourceforge.pmd.ast.SimpleNode; 12 import net.sourceforge.pmd.dfa.pathfinder.CurrentPath; 13 import net.sourceforge.pmd.dfa.pathfinder.DAAPathFinder; 14 import net.sourceforge.pmd.dfa.pathfinder.Executable; 15 import net.sourceforge.pmd.dfa.variableaccess.VariableAccess; 16 import net.sourceforge.pmd.properties.IntegerProperty; 17 18 import java.text.MessageFormat ; 19 import java.util.ArrayList ; 20 import java.util.Hashtable ; 21 import java.util.Iterator ; 22 import java.util.List ; 23 import java.util.Map ; 24 25 31 public class DaaRule extends AbstractRule implements Executable { 32 private RuleContext rc; 33 private List daaRuleViolations; 34 private int maxRuleViolations; 35 private int currentRuleViolationCount; 36 37 private static final PropertyDescriptor maxPathDescriptor = new IntegerProperty( 38 "maxpaths", "Maximum number of paths per method", 5000, 1.0f 39 ); 40 41 private static final PropertyDescriptor maxViolationsDescriptor = new IntegerProperty( 42 "maxviolations", "Maximum number of anomalys per class", 1000, 2.0f 43 ); 44 45 private static final Map propertyDescriptorsByName = asFixedMap( 46 new PropertyDescriptor[] { maxPathDescriptor, maxViolationsDescriptor}); 47 48 protected Map propertiesByName() { 49 return propertyDescriptorsByName; 50 } 51 52 private static class Usage { 53 public int accessType; 54 public IDataFlowNode node; 55 56 public Usage(int accessType, IDataFlowNode node) { 57 this.accessType = accessType; 58 this.node = node; 59 } 60 61 public String toString() { 62 return "accessType = " + accessType + ", line = " + node.getLine(); 63 } 64 } 65 66 public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { 67 this.maxRuleViolations = getIntProperty(maxViolationsDescriptor); 68 this.currentRuleViolationCount = 0; 69 return super.visit(node, data); 70 } 71 72 public Object visit(ASTMethodDeclaration methodDeclaration, Object data) { 73 this.rc = (RuleContext) data; 74 this.daaRuleViolations = new ArrayList (); 75 76 final IDataFlowNode node = (IDataFlowNode) methodDeclaration.getDataFlowNode().getFlow().get(0); 77 78 final DAAPathFinder pathFinder = new DAAPathFinder(node, this, getIntProperty(maxPathDescriptor)); 79 pathFinder.run(); 80 81 super.visit(methodDeclaration, data); 82 return data; 83 } 84 85 public void execute(CurrentPath path) { 86 if (maxNumberOfViolationsReached()) { 87 return; 89 } 90 91 final Hashtable hash = new Hashtable (); 92 93 final Iterator pathIterator = path.iterator(); 94 while (pathIterator.hasNext()) { 95 IDataFlowNode inode = (IDataFlowNode) pathIterator.next(); 97 if (inode.getVariableAccess() != null) { 98 for (int g = 0; g < inode.getVariableAccess().size(); g++) { 100 final VariableAccess va = (VariableAccess) inode.getVariableAccess().get(g); 101 102 final Usage lastUsage = (Usage) hash.get(va.getVariableName()); 104 if (lastUsage != null) { 105 checkVariableAccess(inode, va, lastUsage); 107 } 108 109 final Usage newUsage = new Usage(va.getAccessType(), inode); 110 hash.put(va.getVariableName(), newUsage); 112 } 113 } 114 } 115 } 116 117 122 private void checkVariableAccess(IDataFlowNode inode, VariableAccess va, final Usage u) { 123 final int startLine = u.node.getLine(); 125 final int endLine = inode.getLine(); 126 127 final SimpleNode lastNode = inode.getSimpleNode(); 128 final SimpleNode firstNode = u.node.getSimpleNode(); 129 130 if (va.accessTypeMatches(u.accessType) && va.isDefinition() ) { addDaaViolation(rc, lastNode, "DD", va.getVariableName(), startLine, endLine); 132 } else if (u.accessType == VariableAccess.UNDEFINITION && va.isReference()) { addDaaViolation(rc, lastNode, "UR", va.getVariableName(), startLine, endLine); 134 } else if (u.accessType == VariableAccess.DEFINITION && va.isUndefinition()) { addDaaViolation(rc, firstNode, "DU", va.getVariableName(), startLine, endLine); 136 } 137 } 138 139 146 private final void addDaaViolation(Object data, SimpleNode node, String type, String var, int startLine, int endLine) { 147 if (!maxNumberOfViolationsReached() 148 && !violationAlreadyExists(type, var, startLine, endLine) 149 && node != null) { 150 final RuleContext ctx = (RuleContext) data; 151 final Object [] params = new Object [] { type, var, new Integer (startLine), new Integer (endLine) }; 152 String msg = type; 153 if (getMessage() != null) { 154 msg = MessageFormat.format(getMessage(), params); 155 } 156 final DaaRuleViolation violation = new DaaRuleViolation(this, ctx, node, type, msg, var, startLine, endLine); 157 ctx.getReport().addRuleViolation(violation); 158 this.daaRuleViolations.add(violation); 159 this.currentRuleViolationCount++; 160 } 161 } 162 163 167 private boolean maxNumberOfViolationsReached() { 168 return this.currentRuleViolationCount >= this.maxRuleViolations; 169 } 170 171 180 private boolean violationAlreadyExists(String type, String var, int startLine, int endLine) { 181 final Iterator violationIterator = this.daaRuleViolations.iterator(); 182 while (violationIterator.hasNext()) { 183 final DaaRuleViolation violation = (DaaRuleViolation)violationIterator.next(); 184 if ((violation.getBeginLine() == startLine) 185 && (violation.getEndLine() == endLine) 186 && violation.getType().equals(type) 187 && violation.getVariableName().equals(var)) { 188 return true; 189 } 190 } 191 return false; 192 } 193 } 194 | Popular Tags |