001: package org.acm.seguin.pmd.rules;
002:
003: import org.acm.seguin.pmd.AbstractRule;
004: import org.acm.seguin.pmd.RuleContext;
005: import net.sourceforge.jrefactory.ast.ASTArgumentList;
006: import net.sourceforge.jrefactory.ast.ASTCompilationUnit;
007: import net.sourceforge.jrefactory.ast.ASTLiteral;
008: import net.sourceforge.jrefactory.ast.Node;
009: import net.sourceforge.jrefactory.ast.SimpleNode;
010:
011: import java.text.MessageFormat;
012: import java.util.ArrayList;
013: import java.util.HashMap;
014: import java.util.Iterator;
015: import java.util.List;
016: import java.util.Map;
017:
018: public class AvoidDuplicateLiteralsRule extends AbstractRule {
019:
020: private Map literals = new HashMap();
021:
022: public Object visit(ASTCompilationUnit node, Object data) {
023: //System.err.println("AvoidDuplicateLiteralsRule: "+node.dumpString("\r\n"));
024: literals.clear();
025: super .visit(node, data);
026: int threshold = getIntProperty("threshold");
027: int size = getIntProperty("size") + 2; // remember a string has " at beginning and end!
028: int sizeThreshold = getIntProperty("sizeThreshold");
029: //System.err.println("size="+size+", threshold="+threshold+", sizeThreshold="+sizeThreshold);
030: for (Iterator i = literals.keySet().iterator(); i.hasNext();) {
031: String key = (String) i.next();
032: List occurrences = (List) literals.get(key);
033: //System.err.println("key="+key+", key.length()="+key.length()+", occurrences="+occurrences.size());
034: //System.err.println("(key.length()>size&&occurrences.size() >= threshold)="+(key.length()>size&&occurrences.size() >= threshold));
035: //System.err.println("(key.length()<=size&&occurrences.size() >= sizeThreshold)="+(key.length()<=size&&occurrences.size() >= sizeThreshold));
036: if ((key.length() > size && occurrences.size() >= threshold)
037: || (key.length() <= size && occurrences.size() >= sizeThreshold)) {
038: //System.err.println(" adding error");
039: Object[] args = new Object[] {
040: key,
041: new Integer(occurrences.size()),
042: new Integer(((SimpleNode) occurrences.get(0))
043: .getBeginLine()) };
044: String msg = MessageFormat.format(getMessage(), args);
045: RuleContext ctx = (RuleContext) data;
046: ctx.getReport().addRuleViolation(
047: createRuleViolation(ctx,
048: ((SimpleNode) occurrences.get(0))
049: .getBeginLine(), msg));
050: }
051: }
052: return data;
053: }
054:
055: public Object visit(ASTLiteral node, Object data) {
056: if (!hasAtLeastSixParents(node)) {
057: return data;
058: }
059:
060: if (!nthParentIsASTArgumentList(node, 21)) {
061: //System.err.println("AvoidDuplicateLiteralsRule: is not part of ASTArgumentList");
062: return data;
063: }
064:
065: //System.err.println("node.getImage()="+node.getImage());
066: // just catching strings for now
067: if (node.getImage() == null
068: || node.getImage().indexOf('\"') == -1) {
069: return data;
070: }
071:
072: if (literals.containsKey(node.getImage())) {
073: List occurrences = (List) literals.get(node.getImage());
074: occurrences.add(node);
075: } else {
076: List occurrences = new ArrayList();
077: occurrences.add(node);
078: literals.put(node.getImage(), occurrences);
079: }
080:
081: return data;
082: }
083:
084: private boolean nthParentIsASTArgumentList(Node node, int n) {
085: Node currentNode = node;
086: for (int i = 0; i < n; i++) {
087: if (currentNode == null) {
088: return false;
089: }
090: if (currentNode instanceof ASTArgumentList) {
091: //System.err.println("nth parent is a ASTArgumentList i="+i);
092: return true;
093: }
094: currentNode = currentNode.jjtGetParent();
095: }
096: return false;
097: }
098:
099: private boolean hasAtLeastSixParents(Node node) {
100: Node currentNode = node;
101: for (int i = 0; i < 6; i++) {
102: if (currentNode instanceof ASTCompilationUnit) {
103: //System.err.println("less than 6 parents");
104: return false;
105: }
106: currentNode = currentNode.jjtGetParent();
107: }
108: return true;
109: }
110: }
|