1 4 package net.sourceforge.pmd.rules.strings; 5 6 import net.sourceforge.pmd.AbstractRule; 7 import net.sourceforge.pmd.ast.ASTCompilationUnit; 8 import net.sourceforge.pmd.ast.ASTLiteral; 9 import net.sourceforge.pmd.ast.SimpleNode; 10 11 import java.io.BufferedReader ; 12 import java.io.File ; 13 import java.io.FileReader ; 14 import java.io.IOException ; 15 import java.io.LineNumberReader ; 16 import java.util.ArrayList ; 17 import java.util.HashMap ; 18 import java.util.HashSet ; 19 import java.util.Iterator ; 20 import java.util.List ; 21 import java.util.Map ; 22 import java.util.Set ; 23 24 public class AvoidDuplicateLiteralsRule extends AbstractRule { 25 26 public static class ExceptionParser { 27 28 private static final char ESCAPE_CHAR = '\\'; 29 private char delimiter; 30 31 public ExceptionParser(char delimiter) { 32 this.delimiter = delimiter; 33 } 34 35 public Set parse(String in) { 36 Set result = new HashSet (); 37 StringBuffer currentToken = new StringBuffer (); 38 boolean inEscapeMode = false; 39 for (int i = 0; i < in.length(); i++) { 40 if (inEscapeMode) { 41 inEscapeMode = false; 42 currentToken.append(in.charAt(i)); 43 continue; 44 } 45 if (in.charAt(i) == ESCAPE_CHAR) { 46 inEscapeMode = true; 47 continue; 48 } 49 if (in.charAt(i) == delimiter) { 50 result.add(currentToken.toString()); 51 currentToken = new StringBuffer (); 52 } else { 53 currentToken.append(in.charAt(i)); 54 } 55 } 56 if (currentToken.length() > 0) { 57 result.add(currentToken.toString()); 58 } 59 return result; 60 } 61 } 62 63 private static final char DEFAULT_SEPARATOR = ','; 64 private static final String EXCEPTION_LIST_PROPERTY = "exceptionlist"; 65 private static final String SEPARATOR_PROPERTY = "separator"; 66 private static final String EXCEPTION_FILE_NAME_PROPERTY = "exceptionfile"; 67 68 private Map literals = new HashMap (); 69 private Set exceptions = new HashSet (); 70 71 public Object visit(ASTCompilationUnit node, Object data) { 72 literals.clear(); 73 74 if (hasProperty(EXCEPTION_LIST_PROPERTY)) { 75 ExceptionParser p; 76 if (hasProperty(SEPARATOR_PROPERTY)) { 77 p = new ExceptionParser(getStringProperty(SEPARATOR_PROPERTY).charAt(0)); 78 } else { 79 p = new ExceptionParser(DEFAULT_SEPARATOR); 80 } 81 exceptions = p.parse(getStringProperty(EXCEPTION_LIST_PROPERTY)); 82 } else if (hasProperty(EXCEPTION_FILE_NAME_PROPERTY)) { 83 exceptions = new HashSet (); 84 LineNumberReader reader = null; 85 try { 86 reader = new LineNumberReader (new BufferedReader (new FileReader (new File (getStringProperty(EXCEPTION_FILE_NAME_PROPERTY))))); 87 String line; 88 while ((line = reader.readLine()) != null) { 89 exceptions.add(line); 90 } 91 } catch (IOException ioe) { 92 ioe.printStackTrace(); 93 } finally { 94 try { 95 if (reader != null) 96 reader.close(); 97 } catch (IOException ioe) { 98 ioe.printStackTrace(); 99 } 100 } 101 } 102 103 super.visit(node, data); 104 105 int threshold = getIntProperty("threshold"); 106 for (Iterator i = literals.keySet().iterator(); i.hasNext();) { 107 String key = (String ) i.next(); 108 List occurrences = (List ) literals.get(key); 109 if (occurrences.size() >= threshold) { 110 Object [] args = new Object []{key, new Integer (occurrences.size()), new Integer (((SimpleNode) occurrences.get(0)).getBeginLine())}; 111 addViolation(data, (SimpleNode) occurrences.get(0), args); 112 } 113 } 114 return data; 115 } 116 117 public Object visit(ASTLiteral node, Object data) { 118 if (node.getImage() == null || node.getImage().indexOf('\"') == -1 || node.getImage().length() < 5) { 120 return data; 121 } 122 123 if (exceptions.contains(node.getImage().substring(1, node.getImage().length() - 1))) { 125 return data; 126 } 127 128 if (literals.containsKey(node.getImage())) { 129 List occurrences = (List ) literals.get(node.getImage()); 130 occurrences.add(node); 131 } else { 132 List occurrences = new ArrayList (); 133 occurrences.add(node); 134 literals.put(node.getImage(), occurrences); 135 } 136 137 return data; 138 } 139 } 140 141 | Popular Tags |