Mon, 17 Dec 2012 07:47:05 -0800
8004832: Add new doclint package
Reviewed-by: mcimadamore
jjg@1455 | 1 | package tidystats; |
jjg@1455 | 2 | |
jjg@1455 | 3 | import java.io.IOException; |
jjg@1455 | 4 | import java.nio.charset.Charset; |
jjg@1455 | 5 | import java.nio.file.FileSystem; |
jjg@1455 | 6 | import java.nio.file.FileSystems; |
jjg@1455 | 7 | import java.nio.file.Files; |
jjg@1455 | 8 | import java.nio.file.Path; |
jjg@1455 | 9 | import java.util.ArrayList; |
jjg@1455 | 10 | import java.util.Comparator; |
jjg@1455 | 11 | import java.util.HashMap; |
jjg@1455 | 12 | import java.util.List; |
jjg@1455 | 13 | import java.util.Map; |
jjg@1455 | 14 | import java.util.Set; |
jjg@1455 | 15 | import java.util.TreeMap; |
jjg@1455 | 16 | import java.util.TreeSet; |
jjg@1455 | 17 | import java.util.regex.Matcher; |
jjg@1455 | 18 | import java.util.regex.Pattern; |
jjg@1455 | 19 | |
jjg@1455 | 20 | public class Main { |
jjg@1455 | 21 | public static void main(String... args) throws IOException { |
jjg@1455 | 22 | new Main().run(args); |
jjg@1455 | 23 | } |
jjg@1455 | 24 | |
jjg@1455 | 25 | void run(String... args) throws IOException { |
jjg@1455 | 26 | FileSystem fs = FileSystems.getDefault(); |
jjg@1455 | 27 | List<Path> paths = new ArrayList<>(); |
jjg@1455 | 28 | |
jjg@1455 | 29 | int i; |
jjg@1455 | 30 | for (i = 0; i < args.length; i++) { |
jjg@1455 | 31 | String arg = args[i]; |
jjg@1455 | 32 | if (arg.startsWith("-")) |
jjg@1455 | 33 | throw new IllegalArgumentException(arg); |
jjg@1455 | 34 | else |
jjg@1455 | 35 | break; |
jjg@1455 | 36 | } |
jjg@1455 | 37 | |
jjg@1455 | 38 | for ( ; i < args.length; i++) { |
jjg@1455 | 39 | Path p = fs.getPath(args[i]); |
jjg@1455 | 40 | paths.add(p); |
jjg@1455 | 41 | } |
jjg@1455 | 42 | |
jjg@1455 | 43 | for (Path p: paths) { |
jjg@1455 | 44 | scan(p); |
jjg@1455 | 45 | } |
jjg@1455 | 46 | |
jjg@1455 | 47 | print("%6d files read", files); |
jjg@1455 | 48 | print("%6d files had no errors or warnings", ok); |
jjg@1455 | 49 | print("%6d files reported \"Not all warnings/errors were shown.\"", overflow); |
jjg@1455 | 50 | print("%6d errors found", errs); |
jjg@1455 | 51 | print("%6d warnings found", warns); |
jjg@1455 | 52 | print("%6d recommendations to use CSS", css); |
jjg@1455 | 53 | print(""); |
jjg@1455 | 54 | |
jjg@1455 | 55 | Map<Integer, Set<String>> sortedCounts = new TreeMap<>( |
jjg@1455 | 56 | new Comparator<Integer>() { |
jjg@1455 | 57 | @Override |
jjg@1455 | 58 | public int compare(Integer o1, Integer o2) { |
jjg@1455 | 59 | return o2.compareTo(o1); |
jjg@1455 | 60 | } |
jjg@1455 | 61 | }); |
jjg@1455 | 62 | |
jjg@1455 | 63 | for (Map.Entry<Pattern, Integer> e: counts.entrySet()) { |
jjg@1455 | 64 | Pattern p = e.getKey(); |
jjg@1455 | 65 | Integer n = e.getValue(); |
jjg@1455 | 66 | Set<String> set = sortedCounts.get(n); |
jjg@1455 | 67 | if (set == null) |
jjg@1455 | 68 | sortedCounts.put(n, (set = new TreeSet<>())); |
jjg@1455 | 69 | set.add(p.toString()); |
jjg@1455 | 70 | } |
jjg@1455 | 71 | |
jjg@1455 | 72 | for (Map.Entry<Integer, Set<String>> e: sortedCounts.entrySet()) { |
jjg@1455 | 73 | for (String p: e.getValue()) { |
jjg@1455 | 74 | if (p.startsWith(".*")) p = p.substring(2); |
jjg@1455 | 75 | print("%6d: %s", e.getKey(), p); |
jjg@1455 | 76 | } |
jjg@1455 | 77 | } |
jjg@1455 | 78 | } |
jjg@1455 | 79 | |
jjg@1455 | 80 | void scan(Path p) throws IOException { |
jjg@1455 | 81 | if (Files.isDirectory(p)) { |
jjg@1455 | 82 | for (Path c: Files.newDirectoryStream(p)) { |
jjg@1455 | 83 | scan(c); |
jjg@1455 | 84 | } |
jjg@1455 | 85 | } else if (isTidyFile(p)) { |
jjg@1455 | 86 | scan(Files.readAllLines(p, Charset.defaultCharset())); |
jjg@1455 | 87 | } |
jjg@1455 | 88 | } |
jjg@1455 | 89 | |
jjg@1455 | 90 | boolean isTidyFile(Path p) { |
jjg@1455 | 91 | return Files.isRegularFile(p) && p.getFileName().toString().endsWith(".tidy"); |
jjg@1455 | 92 | } |
jjg@1455 | 93 | |
jjg@1455 | 94 | void scan(List<String> lines) { |
jjg@1455 | 95 | Matcher m; |
jjg@1455 | 96 | files++; |
jjg@1455 | 97 | for (String line: lines) { |
jjg@1455 | 98 | if (okPattern.matcher(line).matches()) { |
jjg@1455 | 99 | ok++; |
jjg@1455 | 100 | } else if ((m = countPattern.matcher(line)).matches()) { |
jjg@1455 | 101 | warns += Integer.valueOf(m.group(1)); |
jjg@1455 | 102 | errs += Integer.valueOf(m.group(2)); |
jjg@1455 | 103 | if (m.group(3) != null) |
jjg@1455 | 104 | overflow++; |
jjg@1455 | 105 | } else if ((m = guardPattern.matcher(line)).matches()) { |
jjg@1455 | 106 | boolean found = false; |
jjg@1455 | 107 | for (Pattern p: patterns) { |
jjg@1455 | 108 | if ((m = p.matcher(line)).matches()) { |
jjg@1455 | 109 | found = true; |
jjg@1455 | 110 | count(p); |
jjg@1455 | 111 | break; |
jjg@1455 | 112 | } |
jjg@1455 | 113 | } |
jjg@1455 | 114 | if (!found) |
jjg@1455 | 115 | System.err.println("Unrecognized line: " + line); |
jjg@1455 | 116 | } else if (cssPattern.matcher(line).matches()) { |
jjg@1455 | 117 | css++; |
jjg@1455 | 118 | } |
jjg@1455 | 119 | } |
jjg@1455 | 120 | } |
jjg@1455 | 121 | |
jjg@1455 | 122 | Map<Pattern, Integer> counts = new HashMap<>(); |
jjg@1455 | 123 | void count(Pattern p) { |
jjg@1455 | 124 | Integer i = counts.get(p); |
jjg@1455 | 125 | counts.put(p, (i == null) ? 1 : i + 1); |
jjg@1455 | 126 | } |
jjg@1455 | 127 | |
jjg@1455 | 128 | void print(String format, Object... args) { |
jjg@1455 | 129 | System.out.println(String.format(format, args)); |
jjg@1455 | 130 | } |
jjg@1455 | 131 | |
jjg@1455 | 132 | Pattern okPattern = Pattern.compile("No warnings or errors were found."); |
jjg@1455 | 133 | Pattern countPattern = Pattern.compile("([0-9]+) warnings, ([0-9]+) errors were found!.*?(Not all warnings/errors were shown.)?"); |
jjg@1455 | 134 | Pattern cssPattern = Pattern.compile("You are recommended to use CSS.*"); |
jjg@1455 | 135 | Pattern guardPattern = Pattern.compile("line [0-9]+ column [0-9]+ - (Error|Warning):.*"); |
jjg@1455 | 136 | |
jjg@1455 | 137 | Pattern[] patterns = { |
jjg@1455 | 138 | Pattern.compile(".*Error: <.*> is not recognized!"), |
jjg@1455 | 139 | Pattern.compile(".*Error: missing quote mark for attribute value"), |
jjg@1455 | 140 | Pattern.compile(".*Warning: <.*> anchor \".*\" already defined"), |
jjg@1455 | 141 | Pattern.compile(".*Warning: <.*> attribute \".*\" has invalid value \".*\""), |
jjg@1455 | 142 | Pattern.compile(".*Warning: <.*> attribute \".*\" lacks value"), |
jjg@1455 | 143 | Pattern.compile(".*Warning: <.*> attribute \".*\" lacks value"), |
jjg@1455 | 144 | Pattern.compile(".*Warning: <.*> attribute with missing trailing quote mark"), |
jjg@1455 | 145 | Pattern.compile(".*Warning: <.*> dropping value \".*\" for repeated attribute \".*\""), |
jjg@1455 | 146 | Pattern.compile(".*Warning: <.*> inserting \".*\" attribute"), |
jjg@1455 | 147 | Pattern.compile(".*Warning: <.*> is probably intended as </.*>"), |
jjg@1455 | 148 | Pattern.compile(".*Warning: <.*> isn't allowed in <.*> elements"), |
jjg@1455 | 149 | Pattern.compile(".*Warning: <.*> lacks \".*\" attribute"), |
jjg@1455 | 150 | Pattern.compile(".*Warning: <.*> missing '>' for end of tag"), |
jjg@1455 | 151 | Pattern.compile(".*Warning: <.*> proprietary attribute \".*\""), |
jjg@1455 | 152 | Pattern.compile(".*Warning: <.*> unexpected or duplicate quote mark"), |
jjg@1455 | 153 | Pattern.compile(".*Warning: <a> cannot copy name attribute to id"), |
jjg@1455 | 154 | Pattern.compile(".*Warning: <a> escaping malformed URI reference"), |
jjg@1455 | 155 | Pattern.compile(".*Warning: <blockquote> proprietary attribute \"pre\""), |
jjg@1455 | 156 | Pattern.compile(".*Warning: discarding unexpected <.*>"), |
jjg@1455 | 157 | Pattern.compile(".*Warning: discarding unexpected </.*>"), |
jjg@1455 | 158 | Pattern.compile(".*Warning: entity \".*\" doesn't end in ';'"), |
jjg@1455 | 159 | Pattern.compile(".*Warning: inserting implicit <.*>"), |
jjg@1455 | 160 | Pattern.compile(".*Warning: inserting missing 'title' element"), |
jjg@1455 | 161 | Pattern.compile(".*Warning: missing <!DOCTYPE> declaration"), |
jjg@1455 | 162 | Pattern.compile(".*Warning: missing <.*>"), |
jjg@1455 | 163 | Pattern.compile(".*Warning: missing </.*> before <.*>"), |
jjg@1455 | 164 | Pattern.compile(".*Warning: nested emphasis <.*>"), |
jjg@1455 | 165 | Pattern.compile(".*Warning: plain text isn't allowed in <.*> elements"), |
jjg@1455 | 166 | Pattern.compile(".*Warning: replacing <p> by <br>"), |
jjg@1455 | 167 | Pattern.compile(".*Warning: replacing invalid numeric character reference .*"), |
jjg@1455 | 168 | Pattern.compile(".*Warning: replacing unexpected .* by </.*>"), |
jjg@1455 | 169 | Pattern.compile(".*Warning: trimming empty <.*>"), |
jjg@1455 | 170 | Pattern.compile(".*Warning: unescaped & or unknown entity \".*\""), |
jjg@1455 | 171 | Pattern.compile(".*Warning: unescaped & which should be written as &"), |
jjg@1455 | 172 | Pattern.compile(".*Warning: using <br> in place of <p>") |
jjg@1455 | 173 | }; |
jjg@1455 | 174 | |
jjg@1455 | 175 | int files; |
jjg@1455 | 176 | int ok; |
jjg@1455 | 177 | int warns; |
jjg@1455 | 178 | int errs; |
jjg@1455 | 179 | int css; |
jjg@1455 | 180 | int overflow; |
jjg@1455 | 181 | } |
jjg@1455 | 182 |