adangel$pmd
void
void start()
Writer writer,Report report
void
void render(Writer writer,Report report)
adangel$pmd
Report report = new Report();
            ctx.setReport(report);

                report.addError(
                report.addError(
                report.addError(
            return report;
    public static void processFiles(int threadCount, RuleSetFactory ruleSetFactory, SourceType sourceType, List<DataSource> files, RuleContext ctx,
            Renderer renderer, String rulesets, boolean debugEnabled, final boolean shortNamesEnabled, final String inputPath,
        List<Future<Report>> tasks = new LinkedList<Future<Report>>();
        
        Collections.sort(files, new Comparator<DataSource>() {
            public int compare(DataSource d1,DataSource d2) {
                String s1 = d1.getNiceFileName(shortNamesEnabled, inputPath);
                String s2 = d2.getNiceFileName(shortNamesEnabled, inputPath);
                return s1.compareTo(s2);
Report
Report call()
ctx.getReport().addError(
                ctx.getReport().addError(
                ctx.getReport().addError(
            context.setReport(new Report());
    public static void processFiles(int threadCount, RuleSetFactory ruleSetFactory, SourceType sourceType, List<DataSource> files, RuleContext ctx, String rulesets,
            boolean debugEnabled, boolean shortNamesEnabled, String inputPath,
            Runnable r = new PmdRunnable(executor, dataSource, niceFileName, sourceType, debugEnabled,
            executor.execute(r);
        try {
            executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
void
void run()
https://github.com/adangel/pmd/blob/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fetc%2Fchangelog.txt
https://api.github.com/repos/adangel/pmd/contents/pmd%2Fetc%2Fchangelog.txt?ref=14da817cf7cc74de98af1649d9dde7da3b4b6c7d
pmd/etc/changelog.txt
Memory footprint reduced: most renderers now use less memory by generating reports on the fly.
@@ -28,6 +28,7 @@ PMD now requires JDK 1.5 to be compiled. Java 1.4 support is provided using Retr
 - PMD will still analyze code from earlier JDKs
 - to run pmd with 1.4, use the files from the java14 directory (weaved pmd jar and support files)
 TypeResolution now looks at some ASTName nodes.
+Memory footprint reduced: most renderers now use less memory by generating reports on the fly.
 
 December 19, 2006 - 3.9:
 New rules:
https://github.com/adangel/pmd/raw/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fetc%2Fchangelog.txt
d586695272f75bddde46ecfdc57e098666d20720
modified
https://github.com/adangel/pmd/blob/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fregress%2Ftest%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FSummaryHTMLRendererTest.java
https://api.github.com/repos/adangel/pmd/contents/pmd%2Fregress%2Ftest%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FSummaryHTMLRendererTest.java?ref=14da817cf7cc74de98af1649d9dde7da3b4b6c7d
pmd/regress/test/net/sourceforge/pmd/renderers/SummaryHTMLRendererTest.java
                "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL + 
        "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL + 
        "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL + 
        "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL + 
@@ -14,7 +14,6 @@ public AbstractRenderer getRenderer() {
     public String getExpected() {
         return "<html><head><title>PMD</title></head><body>" + PMD.EOL + 
                 "<h2><center>Summary</h2></center><table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><th>Rule name</th><th>Number of violations</th><tr><td>Foo</td><td align=center>1</td></tr></table><h2><center>Detail</h2></center><table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL + 
-                "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL + 
                 "<center><h3>PMD report</h3></center><center><h3>Problems found</h3></center><table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL + 
                 "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL + 
                 "<tr bgcolor=\"lightgrey\"> " + PMD.EOL + 
@@ -30,7 +29,6 @@ public String getExpected() {
     public String getExpectedEmpty() {
         return "<html><head><title>PMD</title></head><body>" + PMD.EOL + 
         "<h2><center>Summary</h2></center><table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><th>Rule name</th><th>Number of violations</th></table><h2><center>Detail</h2></center><table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL + 
-        "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL + 
         "<center><h3>PMD report</h3></center><center><h3>Problems found</h3></center><table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL + 
         "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL + 
         "</table></table></body></html>";
@@ -39,7 +37,6 @@ public String getExpectedEmpty() {
     public String getExpectedMultiple() {
         return "<html><head><title>PMD</title></head><body>" + PMD.EOL + 
         "<h2><center>Summary</h2></center><table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><th>Rule name</th><th>Number of violations</th><tr><td>Foo</td><td align=center>2</td></tr></table><h2><center>Detail</h2></center><table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL + 
-        "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL + 
         "<center><h3>PMD report</h3></center><center><h3>Problems found</h3></center><table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL + 
         "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL + 
         "<tr bgcolor=\"lightgrey\"> " + PMD.EOL + 
@@ -60,7 +57,6 @@ public String getExpectedMultiple() {
     public String getExpectedError(ProcessingError error) {
         return "<html><head><title>PMD</title></head><body>" + PMD.EOL + 
         "<h2><center>Summary</h2></center><table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><th>Rule name</th><th>Number of violations</th></table><h2><center>Detail</h2></center><table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL + 
-        "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL + 
         "<center><h3>PMD report</h3></center><center><h3>Problems found</h3></center><table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL + 
         "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL + 
         "</table><hr/><center><h3>Processing errors</h3></center><table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL + 
https://github.com/adangel/pmd/raw/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fregress%2Ftest%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FSummaryHTMLRendererTest.java
a0d375e826b6bc0d7efec9c26c2b98282b01f3e9
modified
https://github.com/adangel/pmd/blob/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fregress%2Ftest%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FVBHTMLRendererTest.java
https://api.github.com/repos/adangel/pmd/contents/pmd%2Fregress%2Ftest%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FVBHTMLRendererTest.java?ref=14da817cf7cc74de98af1649d9dde7da3b4b6c7d
pmd/regress/test/net/sourceforge/pmd/renderers/VBHTMLRendererTest.java
        return "<html><head><title>PMD</title></head><style type=\"text/css\"><!--" + PMD.EOL + 
        "body { background-color: white; font-family:verdana, arial, helvetica, geneva; font-size: 16px; font-style: italic; color: black; }" + PMD.EOL + 
        ".title { font-family: verdana, arial, helvetica,geneva; font-size: 12px; font-weight:bold; color: white; }" + PMD.EOL + 
        ".body { font-family: verdana, arial, helvetica, geneva; font-size: 12px; font-weight:plain; color: black; }" + PMD.EOL + 
        "#TableHeader { background-color: #003366; }" + PMD.EOL + 
        "#RowColor1 { background-color: #eeeeee; }" + PMD.EOL + 
        "#RowColor2 { background-color: white; }" + PMD.EOL + 
        "--></style><body><center><br></center></body></html>";
        return "";
@@ -25,7 +25,14 @@ public String getExpected() {
     }
 
     public String getExpectedEmpty() {
-        return "";
+        return "<html><head><title>PMD</title></head><style type=\"text/css\"><!--" + PMD.EOL + 
+        "body { background-color: white; font-family:verdana, arial, helvetica, geneva; font-size: 16px; font-style: italic; color: black; }" + PMD.EOL + 
+        ".title { font-family: verdana, arial, helvetica,geneva; font-size: 12px; font-weight:bold; color: white; }" + PMD.EOL + 
+        ".body { font-family: verdana, arial, helvetica, geneva; font-size: 12px; font-weight:plain; color: black; }" + PMD.EOL + 
+        "#TableHeader { background-color: #003366; }" + PMD.EOL + 
+        "#RowColor1 { background-color: #eeeeee; }" + PMD.EOL + 
+        "#RowColor2 { background-color: white; }" + PMD.EOL + 
+        "--></style><body><center><br></center></body></html>";
     }
 
     public String getExpectedMultiple() {
https://github.com/adangel/pmd/raw/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fregress%2Ftest%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FVBHTMLRendererTest.java
1976603b63d82b6f5eb834e6180e18937372e113
modified
https://github.com/adangel/pmd/blob/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2FPMD.java
https://api.github.com/repos/adangel/pmd/contents/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2FPMD.java?ref=14da817cf7cc74de98af1649d9dde7da3b4b6c7d
pmd/src/net/sourceforge/pmd/PMD.java
import java.util.Comparator;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
        long reportStart, reportEnd;
        Renderer renderer;

        reportStart = System.nanoTime();
            renderer = opts.createRenderer();
            renderer.setWriter(w);
            renderer.start();

            reportEnd = System.nanoTime();
            Benchmark.mark(Benchmark.TYPE_REPORTING, reportEnd - reportStart, 0);
    
            RuleContext ctx = new RuleContext();

            try {
                long startLoadRules = System.nanoTime();
                RuleSetFactory ruleSetFactory = new RuleSetFactory();
                ruleSetFactory.setMinimumPriority(opts.getMinPriority());
    
                RuleSets rulesets = ruleSetFactory.createRuleSets(opts.getRulesets());
                printRuleNamesInDebug(opts.debugEnabled(), rulesets);
                long endLoadRules = System.nanoTime();
                Benchmark.mark(Benchmark.TYPE_LOAD_RULES, endLoadRules - startLoadRules, 0);
    
                processFiles(opts.getCpus(), ruleSetFactory, sourceType, files, ctx, renderer,
                        opts.getRulesets(), opts.debugEnabled(), opts.shortNamesEnabled(),
                        opts.getInputPath(), opts.getEncoding(), opts.getExcludeMarker());
            } catch (RuleSetNotFoundException rsnfe) {
                System.out.println(opts.usage());
                rsnfe.printStackTrace();
            }

            reportStart = System.nanoTime();
            renderer.end();
            reportEnd = System.nanoTime();
    private static class PmdRunnable extends PMD implements Callable<Report> {
        public Report call() {
            Report report = new Report();
            ctx.setReport(report);

                report.addError(
                report.addError(
                report.addError(
            return report;
    public static void processFiles(int threadCount, RuleSetFactory ruleSetFactory, SourceType sourceType, List<DataSource> files, RuleContext ctx,
            Renderer renderer, String rulesets, boolean debugEnabled, final boolean shortNamesEnabled, final String inputPath,
        List<Future<Report>> tasks = new LinkedList<Future<Report>>();
        
        Collections.sort(files, new Comparator<DataSource>() {
            public int compare(DataSource d1,DataSource d2) {
                String s1 = d1.getNiceFileName(shortNamesEnabled, inputPath);
                String s2 = d2.getNiceFileName(shortNamesEnabled, inputPath);
                return s1.compareTo(s2);
            }
        });
            PmdRunnable r = new PmdRunnable(executor, dataSource, niceFileName, sourceType, debugEnabled,
            Future<Report> future = executor.submit(r);
            tasks.add(future);
        while (!tasks.isEmpty()) {
            Future<Report> future = tasks.remove(0);
            Report report = null;
            try {
                report = future.get();
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
                future.cancel(true);
            } catch (ExecutionException ee) {
                Throwable t = ee.getCause();
                if (t instanceof RuntimeException) {
                    throw (RuntimeException) t;
                } else if (t instanceof Error) {
                    throw (Error) t;
                } else {
                    throw new IllegalStateException("PmdRunnable exception", t);
                }
            }
            try {
                long start = System.nanoTime();
                renderer.renderFileReport(report);
                long end = System.nanoTime();
                Benchmark.mark(Benchmark.TYPE_REPORTING, end - start, 1);
            } catch (IOException ioe) {
            }
pmd/src/net/sourceforge/pmd/PMD.java
Report report = new Report();
            ctx.setReport(report);

                report.addError(
                report.addError(
                report.addError(
            return report;
    public static void processFiles(int threadCount, RuleSetFactory ruleSetFactory, SourceType sourceType, List<DataSource> files, RuleContext ctx,
            Renderer renderer, String rulesets, boolean debugEnabled, final boolean shortNamesEnabled, final String inputPath,
        List<Future<Report>> tasks = new LinkedList<Future<Report>>();
        
        Collections.sort(files, new Comparator<DataSource>() {
            public int compare(DataSource d1,DataSource d2) {
                String s1 = d1.getNiceFileName(shortNamesEnabled, inputPath);
                String s2 = d2.getNiceFileName(shortNamesEnabled, inputPath);
                return s1.compareTo(s2);
Report call()
t instanceof Error
pmd/src/net/sourceforge/pmd/PMD.java
throw (Error) t;
else if (t instanceof Error)
        RuleContext ctx = new RuleContext();
        Report report = new Report();
        ctx.setReport(report);
        report.start();

        try {
            long startLoadRules = System.nanoTime();
            RuleSetFactory ruleSetFactory = new RuleSetFactory();
            ruleSetFactory.setMinimumPriority(opts.getMinPriority());

            RuleSets rulesets = ruleSetFactory.createRuleSets(opts.getRulesets());
            printRuleNamesInDebug(opts.debugEnabled(), rulesets);
            long endLoadRules = System.nanoTime();
            Benchmark.mark(Benchmark.TYPE_LOAD_RULES, endLoadRules - startLoadRules, 0);

            processFiles(opts.getCpus(), ruleSetFactory, sourceType, files, ctx,
                    opts.getRulesets(), opts.debugEnabled(), opts.shortNamesEnabled(),
                    opts.getInputPath(), opts.getEncoding(), opts.getExcludeMarker());
        } catch (RuleSetNotFoundException rsnfe) {
            System.out.println(opts.usage());
            rsnfe.printStackTrace();
        }
        report.end();

        long reportStart = System.nanoTime();
            Renderer r = opts.createRenderer();
            r.render(w, ctx.getReport());
            long reportEnd = System.nanoTime();
    private static class PmdRunnable extends PMD implements Runnable {
        public void run() {
                ctx.getReport().addError(
                ctx.getReport().addError(
                ctx.getReport().addError(
            context.setReport(new Report());
    public static void processFiles(int threadCount, RuleSetFactory ruleSetFactory, SourceType sourceType, List<DataSource> files, RuleContext ctx, String rulesets,
            boolean debugEnabled, boolean shortNamesEnabled, String inputPath,
            Runnable r = new PmdRunnable(executor, dataSource, niceFileName, sourceType, debugEnabled,
            executor.execute(r);
        try {
            executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
        } catch (InterruptedException e) {
        }
        long start = System.nanoTime();
        Report mainReport = ctx.getReport();
        for (PmdThread thread: factory.threadList) {
            Report r = thread.context.getReport();
            mainReport.merge(r);
        long end = System.nanoTime();
        Benchmark.mark(Benchmark.TYPE_REPORTING, end - start, 1);
pmd/src/net/sourceforge/pmd/PMD.java
ctx.getReport().addError(
                ctx.getReport().addError(
                ctx.getReport().addError(
            context.setReport(new Report());
    public static void processFiles(int threadCount, RuleSetFactory ruleSetFactory, SourceType sourceType, List<DataSource> files, RuleContext ctx, String rulesets,
            boolean debugEnabled, boolean shortNamesEnabled, String inputPath,
            Runnable r = new PmdRunnable(executor, dataSource, niceFileName, sourceType, debugEnabled,
            executor.execute(r);
        try {
            executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
void run()
@@ -25,12 +25,16 @@
 import java.io.UnsupportedEncodingException;
 import java.io.Writer;
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.Enumeration;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.StringTokenizer;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -273,40 +277,46 @@ public static void main(String[] args) {
             sourceType = SourceType.JAVA_14;
         }
 
-        RuleContext ctx = new RuleContext();
-        Report report = new Report();
-        ctx.setReport(report);
-        report.start();
-
-        try {
-            long startLoadRules = System.nanoTime();
-            RuleSetFactory ruleSetFactory = new RuleSetFactory();
-            ruleSetFactory.setMinimumPriority(opts.getMinPriority());
-
-            RuleSets rulesets = ruleSetFactory.createRuleSets(opts.getRulesets());
-            printRuleNamesInDebug(opts.debugEnabled(), rulesets);
-            long endLoadRules = System.nanoTime();
-            Benchmark.mark(Benchmark.TYPE_LOAD_RULES, endLoadRules - startLoadRules, 0);
-
-            processFiles(opts.getCpus(), ruleSetFactory, sourceType, files, ctx,
-                    opts.getRulesets(), opts.debugEnabled(), opts.shortNamesEnabled(),
-                    opts.getInputPath(), opts.getEncoding(), opts.getExcludeMarker());
-        } catch (RuleSetNotFoundException rsnfe) {
-            System.out.println(opts.usage());
-            rsnfe.printStackTrace();
-        }
-        report.end();
-
+        long reportStart, reportEnd;
+        Renderer renderer;
         Writer w = null;
-        long reportStart = System.nanoTime();
+
+        reportStart = System.nanoTime();
         try {
-            Renderer r = opts.createRenderer();
+            renderer = opts.createRenderer();
             if (opts.getReportFile() != null) {
                 w = new BufferedWriter(new FileWriter(opts.getReportFile()));
             } else {
                 w = new OutputStreamWriter(System.out);
             }
-            r.render(w, ctx.getReport());
+            renderer.setWriter(w);
+            renderer.start();
+
+            reportEnd = System.nanoTime();
+            Benchmark.mark(Benchmark.TYPE_REPORTING, reportEnd - reportStart, 0);
+    
+            RuleContext ctx = new RuleContext();
+
+            try {
+                long startLoadRules = System.nanoTime();
+                RuleSetFactory ruleSetFactory = new RuleSetFactory();
+                ruleSetFactory.setMinimumPriority(opts.getMinPriority());
+    
+                RuleSets rulesets = ruleSetFactory.createRuleSets(opts.getRulesets());
+                printRuleNamesInDebug(opts.debugEnabled(), rulesets);
+                long endLoadRules = System.nanoTime();
+                Benchmark.mark(Benchmark.TYPE_LOAD_RULES, endLoadRules - startLoadRules, 0);
+    
+                processFiles(opts.getCpus(), ruleSetFactory, sourceType, files, ctx, renderer,
+                        opts.getRulesets(), opts.debugEnabled(), opts.shortNamesEnabled(),
+                        opts.getInputPath(), opts.getEncoding(), opts.getExcludeMarker());
+            } catch (RuleSetNotFoundException rsnfe) {
+                System.out.println(opts.usage());
+                rsnfe.printStackTrace();
+            }
+
+            reportStart = System.nanoTime();
+            renderer.end();
             w.write(EOL);
             w.flush();
             if (opts.getReportFile() != null) {
@@ -327,7 +337,7 @@ public static void main(String[] args) {
                     System.out.println(e.getMessage());
                 }
             }
-            long reportEnd = System.nanoTime();
+            reportEnd = System.nanoTime();
             Benchmark.mark(Benchmark.TYPE_REPORTING, reportEnd - reportStart, 0);
         }
         
@@ -338,7 +348,7 @@ public static void main(String[] args) {
         }
     }
 
-    private static class PmdRunnable extends PMD implements Runnable {
+    private static class PmdRunnable extends PMD implements Callable<Report> {
         private final ExecutorService executor;
         private final DataSource dataSource;
         private final String fileName;
@@ -359,12 +369,15 @@ public PmdRunnable(ExecutorService executor, DataSource dataSource, String fileN
             setExcludeMarker(excludeMarker);
         }
 
-        public void run() {
+        public Report call() {
             PmdThread thread = (PmdThread) Thread.currentThread();
 
             RuleContext ctx = thread.getRuleContext();
             RuleSets rs = thread.getRuleSets(rulesets);
 
+            Report report = new Report();
+            ctx.setReport(report);
+
             ctx.setSourceCodeFilename(fileName);
             if (debugEnabled) {
                 System.out.println("Processing " + ctx.getSourceCodeFilename());
@@ -377,15 +390,15 @@ public void run() {
                 if (debugEnabled) {
                     pmde.getReason().printStackTrace();
                 }
-                ctx.getReport().addError(
+                report.addError(
                         new Report.ProcessingError(pmde.getMessage(),
                         fileName));
             } catch (IOException ioe) {
                 // unexpected exception: log and stop executor service
                 if (debugEnabled) {
                     ioe.printStackTrace();
                 }
-                ctx.getReport().addError(
+                report.addError(
                         new Report.ProcessingError(ioe.getMessage(),
                         fileName));
 
@@ -395,12 +408,13 @@ public void run() {
                 if (debugEnabled) {
                     re.printStackTrace();
                 }
-                ctx.getReport().addError(
+                report.addError(
                         new Report.ProcessingError(re.getMessage(),
                         fileName));
 
                 executor.shutdownNow();
             }
+            return report;
         }
 
     }
@@ -430,7 +444,6 @@ public PmdThread(int id, Runnable r, RuleSetFactory ruleSetFactory) {
             super(r, "PmdThread " + id);
             this.id = id;
             context = new RuleContext();
-            context.setReport(new Report());
             this.ruleSetFactory = ruleSetFactory;
         }
         
@@ -465,37 +478,61 @@ public String toString() {
      *
      * @throws IOException If one of the files could not be read
      */
-    public static void processFiles(int threadCount, RuleSetFactory ruleSetFactory, SourceType sourceType, List<DataSource> files, RuleContext ctx, String rulesets,
-            boolean debugEnabled, boolean shortNamesEnabled, String inputPath,
+    public static void processFiles(int threadCount, RuleSetFactory ruleSetFactory, SourceType sourceType, List<DataSource> files, RuleContext ctx,
+            Renderer renderer, String rulesets, boolean debugEnabled, final boolean shortNamesEnabled, final String inputPath,
             String encoding, String excludeMarker) {
 
         PmdThreadFactory factory = new PmdThreadFactory(ruleSetFactory);
         ExecutorService executor = Executors.newFixedThreadPool(threadCount, factory);
+        List<Future<Report>> tasks = new LinkedList<Future<Report>>();
+        
+        Collections.sort(files, new Comparator<DataSource>() {
+            public int compare(DataSource d1,DataSource d2) {
+                String s1 = d1.getNiceFileName(shortNamesEnabled, inputPath);
+                String s2 = d2.getNiceFileName(shortNamesEnabled, inputPath);
+                return s1.compareTo(s2);
+            }
+        });
 
         for (DataSource dataSource:files) {
             String niceFileName = dataSource.getNiceFileName(shortNamesEnabled,
                     inputPath);
 
-            Runnable r = new PmdRunnable(executor, dataSource, niceFileName, sourceType, debugEnabled,
+            PmdRunnable r = new PmdRunnable(executor, dataSource, niceFileName, sourceType, debugEnabled,
                                             encoding, rulesets, excludeMarker);
 
-            executor.execute(r);
+            Future<Report> future = executor.submit(r);
+            tasks.add(future);
         }
         executor.shutdown();
 
-        try {
-            executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
-        } catch (InterruptedException e) {
-        }
+        while (!tasks.isEmpty()) {
+            Future<Report> future = tasks.remove(0);
+            Report report = null;
+            try {
+                report = future.get();
+            } catch (InterruptedException ie) {
+                Thread.currentThread().interrupt();
+                future.cancel(true);
+            } catch (ExecutionException ee) {
+                Throwable t = ee.getCause();
+                if (t instanceof RuntimeException) {
+                    throw (RuntimeException) t;
+                } else if (t instanceof Error) {
+                    throw (Error) t;
+                } else {
+                    throw new IllegalStateException("PmdRunnable exception", t);
+                }
+            }
 
-        long start = System.nanoTime();
-        Report mainReport = ctx.getReport();
-        for (PmdThread thread: factory.threadList) {
-            Report r = thread.context.getReport();
-            mainReport.merge(r);
+            try {
+                long start = System.nanoTime();
+                renderer.renderFileReport(report);
+                long end = System.nanoTime();
+                Benchmark.mark(Benchmark.TYPE_REPORTING, end - start, 1);
+            } catch (IOException ioe) {
+            }
         }
-        long end = System.nanoTime();
-        Benchmark.mark(Benchmark.TYPE_REPORTING, end - start, 1);
     }
 
     /**
https://github.com/adangel/pmd/raw/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2FPMD.java
02f745533b2f11ad0d059284a02ca056f38617e7
modified
https://github.com/adangel/pmd/blob/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2FReport.java
https://api.github.com/repos/adangel/pmd/contents/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2FReport.java?ref=14da817cf7cc74de98af1649d9dde7da3b4b6c7d
pmd/src/net/sourceforge/pmd/Report.java
        private final long duration;
        private final String msg;
        private final String file;
        private final IRuleViolation rv;
        private final boolean isNOPMD;
        private final String userMessage;
    private final ReportTree violationTree = new ReportTree();
    private final Set<IRuleViolation> violations = new TreeSet<IRuleViolation>(COMPARATOR);
    private final Set<Metric> metrics = new HashSet<Metric>();
    private final List<ReportListener> listeners = new ArrayList<ReportListener>();
    private final List<ProcessingError> errors = new ArrayList<ProcessingError>();
        private long duration;
        private String msg;
        private String file;
        private IRuleViolation rv;
        private boolean isNOPMD;
        private String userMessage;
    private ReportTree violationTree = new ReportTree();
    private Set<IRuleViolation> violations = new TreeSet<IRuleViolation>(COMPARATOR);
    private Set<Metric> metrics = new HashSet<Metric>();
    private List<ReportListener> listeners = new ArrayList<ReportListener>();
    private List<ProcessingError> errors = new ArrayList<ProcessingError>();
@@ -19,7 +19,7 @@
 public class Report {
 
     public static class ReadableDuration {
-        private long duration;
+        private final long duration;
 
         public ReadableDuration(long duration) {
             this.duration = duration;
@@ -57,8 +57,8 @@ public String getTime() {
     }
 
     public static class ProcessingError {
-        private String msg;
-        private String file;
+        private final String msg;
+        private final String file;
 
         public ProcessingError(String msg, String file) {
             this.msg = msg;
@@ -75,9 +75,9 @@ public String getFile() {
     }
 
     public static class SuppressedViolation {
-        private IRuleViolation rv;
-        private boolean isNOPMD;
-        private String userMessage;
+        private final IRuleViolation rv;
+        private final boolean isNOPMD;
+        private final String userMessage;
 
         public SuppressedViolation(IRuleViolation rv, boolean isNOPMD, String userMessage) {
             this.isNOPMD = isNOPMD;
@@ -109,13 +109,13 @@ public String getUserMessage() {
      * better and faster sort and filter mechanism and to visualize the result
      * als tree. (ide plugins).
      * */
-    private ReportTree violationTree = new ReportTree();
+    private final ReportTree violationTree = new ReportTree();
 
     // Note that this and the above data structure are both being maintained for a bit
-    private Set<IRuleViolation> violations = new TreeSet<IRuleViolation>(COMPARATOR);
-    private Set<Metric> metrics = new HashSet<Metric>();
-    private List<ReportListener> listeners = new ArrayList<ReportListener>();
-    private List<ProcessingError> errors = new ArrayList<ProcessingError>();
+    private final Set<IRuleViolation> violations = new TreeSet<IRuleViolation>(COMPARATOR);
+    private final Set<Metric> metrics = new HashSet<Metric>();
+    private final List<ReportListener> listeners = new ArrayList<ReportListener>();
+    private final List<ProcessingError> errors = new ArrayList<ProcessingError>();
     private Map<Integer, String> linesToExclude = new HashMap<Integer, String>();
     private long start;
     private long end;
https://github.com/adangel/pmd/raw/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2FReport.java
52d7fc7f35da6ec0eb74816f7632e60615d2481e
modified
https://github.com/adangel/pmd/blob/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FAbstractRenderer.java
https://api.github.com/repos/adangel/pmd/contents/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FAbstractRenderer.java?ref=14da817cf7cc74de98af1649d9dde7da3b4b6c7d
pmd/src/net/sourceforge/pmd/renderers/AbstractRenderer.java
import java.io.Writer;
    private Writer writer;

    private Report mainReport;

    public void setWriter(Writer writer) {
        this.writer = writer;
    }

    public Writer getWriter() {
        return writer;
    }

    public void start() throws IOException {
        // default (and backward compatible) behavior is to build a full report.
        // Optimized rendering is done in OnTheFlyRenderer and descendants
        mainReport = new Report();
    }

    public void renderFileReport(Report report) throws IOException {
        // default (and backward compatible) behavior is to build a full report.
        // Optimized rendering is done in OnTheFlyRenderer and descendants
        mainReport.merge(report);
    }

    public void end() throws IOException {
        // default (and backward compatible) behavior is to build a full report.
        // Optimized rendering is done in OnTheFlyRenderer and descendants
        render(writer, mainReport);
    }
Writer writer
pmd/src/net/sourceforge/pmd/renderers/AbstractRenderer.java
this.writer = writer;
void setWriter(Writer writer)
pmd/src/net/sourceforge/pmd/renderers/AbstractRenderer.java
return writer;
Writer getWriter()
@@ -2,6 +2,7 @@
 
 import java.io.IOException;
 import java.io.StringWriter;
+import java.io.Writer;
 
 import net.sourceforge.pmd.Report;
 
@@ -23,4 +24,33 @@ public String render(Report report) {
         return w.toString();
     }
 
+    private Writer writer;
+
+    private Report mainReport;
+
+    public void setWriter(Writer writer) {
+        this.writer = writer;
+    }
+
+    public Writer getWriter() {
+        return writer;
+    }
+
+    public void start() throws IOException {
+        // default (and backward compatible) behavior is to build a full report.
+        // Optimized rendering is done in OnTheFlyRenderer and descendants
+        mainReport = new Report();
+    }
+
+    public void renderFileReport(Report report) throws IOException {
+        // default (and backward compatible) behavior is to build a full report.
+        // Optimized rendering is done in OnTheFlyRenderer and descendants
+        mainReport.merge(report);
+    }
+
+    public void end() throws IOException {
+        // default (and backward compatible) behavior is to build a full report.
+        // Optimized rendering is done in OnTheFlyRenderer and descendants
+        render(writer, mainReport);
+    }
 }
https://github.com/adangel/pmd/raw/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FAbstractRenderer.java
072f1b752f5b9896c980ad3384bf167b32597d3c
modified
https://github.com/adangel/pmd/blob/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FCSVRenderer.java
https://api.github.com/repos/adangel/pmd/contents/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FCSVRenderer.java?ref=14da817cf7cc74de98af1649d9dde7da3b4b6c7d
pmd/src/net/sourceforge/pmd/renderers/CSVRenderer.java
public class CSVRenderer extends OnTheFlyRenderer {
    private int violationCount = 1;

    public void start() throws IOException {
        getWriter().write(buf.toString());
    public void renderFileViolations(Iterator<IRuleViolation> violations) throws IOException {
        StringBuffer buf = new StringBuffer(300);
        Writer writer = getWriter();

        while (violations.hasNext()) {
            rv = violations.next();
    public void end() throws IOException {
    }

import net.sourceforge.pmd.Report;
public class CSVRenderer extends AbstractRenderer {
    public void render(Writer writer, Report report) throws IOException {
        writer.write(buf.toString());

        addViolations(writer, report, buf);
	private void addViolations(Writer writer, Report report, StringBuffer buf) throws IOException {
		int violationCount = 1;
        for (Iterator<IRuleViolation> i = report.iterator(); i.hasNext();) {
            rv = i.next();
@@ -5,16 +5,17 @@
 
 import net.sourceforge.pmd.IRuleViolation;
 import net.sourceforge.pmd.PMD;
-import net.sourceforge.pmd.Report;
 import net.sourceforge.pmd.util.StringUtil;
 
 import java.io.IOException;
 import java.io.Writer;
 import java.util.Iterator;
 
-public class CSVRenderer extends AbstractRenderer {
+public class CSVRenderer extends OnTheFlyRenderer {
 
-    public void render(Writer writer, Report report) throws IOException {
+    private int violationCount = 1;
+
+    public void start() throws IOException {
         StringBuffer buf = new StringBuffer(300);
         quoteAndCommify(buf, "Problem");
         quoteAndCommify(buf, "Package");
@@ -25,17 +26,17 @@ public void render(Writer writer, Report report) throws IOException {
         quoteAndCommify(buf, "Rule set");
         quote(buf, "Rule");
         buf.append(PMD.EOL);
-        writer.write(buf.toString());
-
-        addViolations(writer, report, buf);
+        getWriter().write(buf.toString());
     }
 
-	private void addViolations(Writer writer, Report report, StringBuffer buf) throws IOException {
-		int violationCount = 1;
+    public void renderFileViolations(Iterator<IRuleViolation> violations) throws IOException {
+        StringBuffer buf = new StringBuffer(300);
+        Writer writer = getWriter();
+
 		IRuleViolation rv;
-        for (Iterator<IRuleViolation> i = report.iterator(); i.hasNext();) {
+        while (violations.hasNext()) {
             buf.setLength(0);
-            rv = i.next();
+            rv = violations.next();
             quoteAndCommify(buf, Integer.toString(violationCount));
             quoteAndCommify(buf, rv.getPackageName());
             quoteAndCommify(buf, rv.getFilename());
@@ -50,6 +51,9 @@ private void addViolations(Writer writer, Report report, StringBuffer buf) throw
         }
 	}
 
+    public void end() throws IOException {
+    }
+
     private void quote(StringBuffer sb, String d) {
         sb.append('"').append(d).append('"');
     }
https://github.com/adangel/pmd/raw/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FCSVRenderer.java
a4b444833df2b18dc24969a727588e9014b82d53
modified
https://github.com/adangel/pmd/blob/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FEmacsRenderer.java
https://api.github.com/repos/adangel/pmd/contents/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FEmacsRenderer.java?ref=14da817cf7cc74de98af1649d9dde7da3b4b6c7d
pmd/src/net/sourceforge/pmd/renderers/EmacsRenderer.java
public class EmacsRenderer extends OnTheFlyRenderer {
    public void start() throws IOException {}

    public void renderFileViolations(Iterator<IRuleViolation> violations) throws IOException {
        Writer writer = getWriter();
        while (violations.hasNext()) {
            IRuleViolation rv = violations.next();

    public void end() throws IOException {}
import net.sourceforge.pmd.Report;
public class EmacsRenderer extends AbstractRenderer {
    public void render(Writer writer, Report report) throws IOException {
        for (Iterator<IRuleViolation> i = report.iterator(); i.hasNext();) {
            IRuleViolation rv = i.next();
@@ -4,25 +4,29 @@
 package net.sourceforge.pmd.renderers;
 
 import net.sourceforge.pmd.IRuleViolation;
-import net.sourceforge.pmd.Report;
 
 import java.io.IOException;
 import java.io.Writer;
 import java.util.Iterator;
 
-public class EmacsRenderer extends AbstractRenderer {
+public class EmacsRenderer extends OnTheFlyRenderer {
 
     protected static final String EOL = System.getProperty("line.separator", "\n");
 
-    public void render(Writer writer, Report report) throws IOException {
+    public void start() throws IOException {}
+
+    public void renderFileViolations(Iterator<IRuleViolation> violations) throws IOException {
+        Writer writer = getWriter();
         StringBuffer buf = new StringBuffer();
-        for (Iterator<IRuleViolation> i = report.iterator(); i.hasNext();) {
-            IRuleViolation rv = i.next();
+        while (violations.hasNext()) {
+            IRuleViolation rv = violations.next();
             buf.setLength(0);
             buf.append(EOL).append(rv.getFilename());
             buf.append(':').append(Integer.toString(rv.getBeginLine()));
             buf.append(": ").append(rv.getDescription());
             writer.write(buf.toString());
         }
     }
+
+    public void end() throws IOException {}
 }
https://github.com/adangel/pmd/raw/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FEmacsRenderer.java
aa6f77d5c8e14599c723d60aaaab14b53c87a3b9
modified
https://github.com/adangel/pmd/blob/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FHTMLRenderer.java
https://api.github.com/repos/adangel/pmd/contents/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FHTMLRenderer.java?ref=14da817cf7cc74de98af1649d9dde7da3b4b6c7d
pmd/src/net/sourceforge/pmd/renderers/HTMLRenderer.java
import java.util.List;
public class HTMLRenderer extends OnTheFlyRenderer {
    private final String linkPrefix;
    private final String linePrefix;

    private int violationCount = 1;
    boolean colorize = true;
        writer.write("<center><h3>PMD report</h3></center>");
        writer.write("<center><h3>Problems found</h3></center>");
        writer.write("<table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL + "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL);
        setWriter(writer);
        renderFileReport(report);
        writer.write("</table>");
        glomProcessingErrors(writer, errors);
            glomSuppressions(writer, suppressed);

    public void start() throws IOException {
        Writer writer = getWriter();
        writer.write("<html><head><title>PMD</title></head><body>" + PMD.EOL);
    }

    public void renderFileViolations(Iterator<IRuleViolation> violations) throws IOException {
        Writer writer = getWriter();
        glomIRuleViolations(writer, violations);
    }

    public void end() throws IOException {
        Writer writer = getWriter();
        writer.write("</table>");
        glomProcessingErrors(writer, errors);
        if (showSuppressedViolations) {
            glomSuppressions(writer, suppressed);
        }
        writer.write("</body></html>");
    }

    private void glomIRuleViolations(Writer writer, Iterator<IRuleViolation> violations) throws IOException {
        StringBuffer buf = new StringBuffer(500);
        while (violations.hasNext()) {
            IRuleViolation rv = violations.next();
    private void glomProcessingErrors(Writer writer, List<Report.ProcessingError> errors) throws IOException {
        if (!errors.isEmpty()) {
    
            StringBuffer buf = new StringBuffer(500);
            boolean colorize = true;
            for (Report.ProcessingError pe: errors) {
                buf.setLength(0);
                buf.append("<tr");
                if (colorize) {
                    buf.append(" bgcolor=\"lightgrey\"");
                }
                colorize = !colorize;
                buf.append("> " + PMD.EOL);
                buf.append("<td>" + pe.getFile() + "</td>" + PMD.EOL);
                buf.append("<td>" + pe.getMsg() + "</td>" + PMD.EOL);
                buf.append("</tr>" + PMD.EOL);
                writer.write(buf.toString());
                
    private void glomSuppressions(Writer writer, List<Report.SuppressedViolation> suppressed) throws IOException {
        if (!suppressed.isEmpty()) {

            StringBuffer buf = new StringBuffer(500);
            boolean colorize = true;
            for (Report.SuppressedViolation sv: suppressed) {
                buf.setLength(0);
                buf.append("<tr");
                if (colorize) {
                    buf.append(" bgcolor=\"lightgrey\"");
                }
                colorize = !colorize;
                buf.append("> " + PMD.EOL);
                buf.append("<td align=\"left\">" + sv.getRuleViolation().getFilename() + "</td>" + PMD.EOL);
                buf.append("<td align=\"center\">" + sv.getRuleViolation().getBeginLine() + "</td>" + PMD.EOL);
                buf.append("<td align=\"center\">" + sv.getRuleViolation().getRule().getName() + "</td>" + PMD.EOL);
                buf.append("<td align=\"center\">" + (sv.suppressedByNOPMD() ? "NOPMD" : "Annotation") + "</td>" + PMD.EOL);
                buf.append("<td align=\"center\">" + (sv.getUserMessage() == null ? "" : sv.getUserMessage()) + "</td>" + PMD.EOL);
                buf.append("</tr>" + PMD.EOL);
                writer.write(buf.toString());
public class HTMLRenderer extends AbstractRenderer {
    private String linkPrefix;
    private String linePrefix;
    public void render(Writer writer, Report report) throws IOException {
        writer.write("<html><head><title>PMD</title></head><body>" + PMD.EOL);
        renderBody(writer, report);
        writer.write("</body></html>");
    }

        glomIRuleViolations(writer, report);
        glomProcessingErrors(writer, report);
            glomSuppressions(writer, report);
    
    private void glomIRuleViolations(Writer writer, Report report) throws IOException {
        boolean colorize = true;
        int violationCount = 1;
        StringBuffer buf = new StringBuffer(500);
        for (Iterator<IRuleViolation> i = report.iterator(); i.hasNext();) {
            IRuleViolation rv = i.next();
        if (violationCount > 0) {
            writer.write("</table>");
        }
    private void glomProcessingErrors(Writer writer, Report report) throws IOException {
        boolean colorize = true;
        int violationCount;
        // errors
        if (report.errors().hasNext()) {
        }
        violationCount = 0;
        StringBuffer buf = new StringBuffer(500);
        for (Iterator<Report.ProcessingError> i = report.errors(); i.hasNext();) {
            Report.ProcessingError pe = i.next();
            buf.setLength(0);
            buf.append("<tr");
            if (colorize) {
                buf.append(" bgcolor=\"lightgrey\"");
            colorize = !colorize;
            buf.append("> " + PMD.EOL);
            buf.append("<td>" + pe.getFile() + "</td>" + PMD.EOL);
            buf.append("<td>" + pe.getMsg() + "</td>" + PMD.EOL);
            buf.append("</tr>" + PMD.EOL);
            writer.write(buf.toString());
            violationCount++;
        }
        if (violationCount > 0) {
    private void glomSuppressions(Writer writer, Report report) throws IOException {
        boolean colorize = true;
        boolean hasSuppressedViolations = !report.getSuppressedRuleViolations().isEmpty();
        if (hasSuppressedViolations) {
        }
        StringBuffer buf = new StringBuffer(500);
        for (Report.SuppressedViolation sv: report.getSuppressedRuleViolations()) {
            buf.setLength(0);
            buf.append("<tr");
            if (colorize) {
                buf.append(" bgcolor=\"lightgrey\"");
            colorize = !colorize;
            buf.append("> " + PMD.EOL);
            buf.append("<td align=\"left\">" + sv.getRuleViolation().getFilename() + "</td>" + PMD.EOL);
            buf.append("<td align=\"center\">" + sv.getRuleViolation().getBeginLine() + "</td>" + PMD.EOL);
            buf.append("<td align=\"center\">" + sv.getRuleViolation().getRule().getName() + "</td>" + PMD.EOL);
            buf.append("<td align=\"center\">" + (sv.suppressedByNOPMD() ? "NOPMD" : "Annotation") + "</td>" + PMD.EOL);
            buf.append("<td align=\"center\">" + (sv.getUserMessage() == null ? "" : sv.getUserMessage()) + "</td>" + PMD.EOL);
            buf.append("</tr>" + PMD.EOL);
            writer.write(buf.toString());
        }
        if (hasSuppressedViolations) {
@@ -11,11 +11,15 @@
 import java.io.IOException;
 import java.io.Writer;
 import java.util.Iterator;
+import java.util.List;
 
-public class HTMLRenderer extends AbstractRenderer {
+public class HTMLRenderer extends OnTheFlyRenderer {
 
-    private String linkPrefix;
-    private String linePrefix;
+    private final String linkPrefix;
+    private final String linePrefix;
+
+    private int violationCount = 1;
+    boolean colorize = true;
 
     public HTMLRenderer(String linkPrefix, String linePrefix) {
         this.linkPrefix = linkPrefix;
@@ -27,29 +31,46 @@ public HTMLRenderer() {
         this(null, null);
     }
 
-    public void render(Writer writer, Report report) throws IOException {
-        writer.write("<html><head><title>PMD</title></head><body>" + PMD.EOL);
-        renderBody(writer, report);
-        writer.write("</body></html>");
-    }
-
     public void renderBody(Writer writer, Report report) throws IOException {
-        glomIRuleViolations(writer, report);
-        glomProcessingErrors(writer, report);
+        writer.write("<center><h3>PMD report</h3></center>");
+        writer.write("<center><h3>Problems found</h3></center>");
+        writer.write("<table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL + "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL);
+        setWriter(writer);
+        renderFileReport(report);
+        writer.write("</table>");
+        glomProcessingErrors(writer, errors);
         if (showSuppressedViolations) {
-            glomSuppressions(writer, report);
+            glomSuppressions(writer, suppressed);
         }
     }
-    
-    private void glomIRuleViolations(Writer writer, Report report) throws IOException {
-        boolean colorize = true;
-        int violationCount = 1;
-        StringBuffer buf = new StringBuffer(500);
+
+    public void start() throws IOException {
+        Writer writer = getWriter();
+        writer.write("<html><head><title>PMD</title></head><body>" + PMD.EOL);
         writer.write("<center><h3>PMD report</h3></center>");
         writer.write("<center><h3>Problems found</h3></center>");
         writer.write("<table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL + "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL);
-        for (Iterator<IRuleViolation> i = report.iterator(); i.hasNext();) {
-            IRuleViolation rv = i.next();
+    }
+
+    public void renderFileViolations(Iterator<IRuleViolation> violations) throws IOException {
+        Writer writer = getWriter();
+        glomIRuleViolations(writer, violations);
+    }
+
+    public void end() throws IOException {
+        Writer writer = getWriter();
+        writer.write("</table>");
+        glomProcessingErrors(writer, errors);
+        if (showSuppressedViolations) {
+            glomSuppressions(writer, suppressed);
+        }
+        writer.write("</body></html>");
+    }
+
+    private void glomIRuleViolations(Writer writer, Iterator<IRuleViolation> violations) throws IOException {
+        StringBuffer buf = new StringBuffer(500);
+        while (violations.hasNext()) {
+            IRuleViolation rv = violations.next();
             buf.setLength(0);
             buf.append("<tr");
             if (colorize) {
@@ -71,68 +92,58 @@ private void glomIRuleViolations(Writer writer, Report report) throws IOExceptio
             writer.write(buf.toString());
             violationCount++;
         }
-        if (violationCount > 0) {
-            writer.write("</table>");
-        }
     }
 
-    private void glomProcessingErrors(Writer writer, Report report) throws IOException {
-        boolean colorize = true;
-        int violationCount;
-        // errors
-        if (report.errors().hasNext()) {
+    private void glomProcessingErrors(Writer writer, List<Report.ProcessingError> errors) throws IOException {
+        if (!errors.isEmpty()) {
             writer.write("<hr/>");
             writer.write("<center><h3>Processing errors</h3></center>");
             writer.write("<table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL + "<th>File</th><th>Problem</th></tr>" + PMD.EOL);
-        }
-        violationCount = 0;
-        StringBuffer buf = new StringBuffer(500);
-        for (Iterator<Report.ProcessingError> i = report.errors(); i.hasNext();) {
-            Report.ProcessingError pe = i.next();
-            buf.setLength(0);
-            buf.append("<tr");
-            if (colorize) {
-                buf.append(" bgcolor=\"lightgrey\"");
+    
+            StringBuffer buf = new StringBuffer(500);
+            boolean colorize = true;
+            for (Report.ProcessingError pe: errors) {
+                buf.setLength(0);
+                buf.append("<tr");
+                if (colorize) {
+                    buf.append(" bgcolor=\"lightgrey\"");
+                }
+                colorize = !colorize;
+                buf.append("> " + PMD.EOL);
+                buf.append("<td>" + pe.getFile() + "</td>" + PMD.EOL);
+                buf.append("<td>" + pe.getMsg() + "</td>" + PMD.EOL);
+                buf.append("</tr>" + PMD.EOL);
+                writer.write(buf.toString());
+                
             }
-            colorize = !colorize;
-            buf.append("> " + PMD.EOL);
-            buf.append("<td>" + pe.getFile() + "</td>" + PMD.EOL);
-            buf.append("<td>" + pe.getMsg() + "</td>" + PMD.EOL);
-            buf.append("</tr>" + PMD.EOL);
-            writer.write(buf.toString());
-            violationCount++;
-        }
-        if (violationCount > 0) {
             writer.write("</table>");
         }
     }
 
-    private void glomSuppressions(Writer writer, Report report) throws IOException {
-        boolean colorize = true;
-        boolean hasSuppressedViolations = !report.getSuppressedRuleViolations().isEmpty();
-        if (hasSuppressedViolations) {
+    private void glomSuppressions(Writer writer, List<Report.SuppressedViolation> suppressed) throws IOException {
+        if (!suppressed.isEmpty()) {
             writer.write("<hr/>");
             writer.write("<center><h3>Suppressed warnings</h3></center>");
             writer.write("<table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL + "<th>File</th><th>Line</th><th>Rule</th><th>NOPMD or Annotation</th><th>Reason</th></tr>" + PMD.EOL);
-        }
-        StringBuffer buf = new StringBuffer(500);
-        for (Report.SuppressedViolation sv: report.getSuppressedRuleViolations()) {
-            buf.setLength(0);
-            buf.append("<tr");
-            if (colorize) {
-                buf.append(" bgcolor=\"lightgrey\"");
+
+            StringBuffer buf = new StringBuffer(500);
+            boolean colorize = true;
+            for (Report.SuppressedViolation sv: suppressed) {
+                buf.setLength(0);
+                buf.append("<tr");
+                if (colorize) {
+                    buf.append(" bgcolor=\"lightgrey\"");
+                }
+                colorize = !colorize;
+                buf.append("> " + PMD.EOL);
+                buf.append("<td align=\"left\">" + sv.getRuleViolation().getFilename() + "</td>" + PMD.EOL);
+                buf.append("<td align=\"center\">" + sv.getRuleViolation().getBeginLine() + "</td>" + PMD.EOL);
+                buf.append("<td align=\"center\">" + sv.getRuleViolation().getRule().getName() + "</td>" + PMD.EOL);
+                buf.append("<td align=\"center\">" + (sv.suppressedByNOPMD() ? "NOPMD" : "Annotation") + "</td>" + PMD.EOL);
+                buf.append("<td align=\"center\">" + (sv.getUserMessage() == null ? "" : sv.getUserMessage()) + "</td>" + PMD.EOL);
+                buf.append("</tr>" + PMD.EOL);
+                writer.write(buf.toString());
             }
-            colorize = !colorize;
-            buf.append("> " + PMD.EOL);
-            buf.append("<td align=\"left\">" + sv.getRuleViolation().getFilename() + "</td>" + PMD.EOL);
-            buf.append("<td align=\"center\">" + sv.getRuleViolation().getBeginLine() + "</td>" + PMD.EOL);
-            buf.append("<td align=\"center\">" + sv.getRuleViolation().getRule().getName() + "</td>" + PMD.EOL);
-            buf.append("<td align=\"center\">" + (sv.suppressedByNOPMD() ? "NOPMD" : "Annotation") + "</td>" + PMD.EOL);
-            buf.append("<td align=\"center\">" + (sv.getUserMessage() == null ? "" : sv.getUserMessage()) + "</td>" + PMD.EOL);
-            buf.append("</tr>" + PMD.EOL);
-            writer.write(buf.toString());
-        }
-        if (hasSuppressedViolations) {
             writer.write("</table>");
         }
     }
https://github.com/adangel/pmd/raw/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FHTMLRenderer.java
6c4f4aefe86e75851320a85bd4b57d4722282ae7
modified
https://github.com/adangel/pmd/blob/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FIDEAJRenderer.java
https://api.github.com/repos/adangel/pmd/contents/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FIDEAJRenderer.java?ref=14da817cf7cc74de98af1649d9dde7da3b4b6c7d
pmd/src/net/sourceforge/pmd/renderers/IDEAJRenderer.java
public class IDEAJRenderer extends OnTheFlyRenderer {
    public void start() throws IOException {}

    public void renderFileViolations(Iterator<IRuleViolation> violations) throws IOException {
        Writer writer = getWriter();
            render(writer, violations, sourcePath);
        render(writer, violations, classAndMethodName, singleFileName);
    public void end() throws IOException {}

    private void render(Writer writer, Iterator<IRuleViolation> violations, String sourcePathString) throws IOException {
        while (violations.hasNext()) {
            IRuleViolation rv = violations.next();
    private void render(Writer writer, Iterator<IRuleViolation> violations, String classAndMethod, String file) throws IOException {
        while (violations.hasNext()) {
            IRuleViolation rv = violations.next();
import net.sourceforge.pmd.Report;
public class IDEAJRenderer extends AbstractRenderer {
    public void render(Writer writer, Report report) throws IOException {
            render(writer, report, sourcePath);
        render(writer, report, classAndMethodName, singleFileName);
    private void render(Writer writer, Report report, String sourcePathString) throws IOException {
        for (Iterator<IRuleViolation> i = report.iterator(); i.hasNext();) {
            IRuleViolation rv = i.next();
    private void render(Writer writer, Report report, String classAndMethod, String file) throws IOException {
        for (Iterator<IRuleViolation> i = report.iterator(); i.hasNext();) {
            IRuleViolation rv = i.next();
@@ -5,7 +5,6 @@
 
 import net.sourceforge.pmd.IRuleViolation;
 import net.sourceforge.pmd.PMD;
-import net.sourceforge.pmd.Report;
 
 import java.io.IOException;
 import java.io.Writer;
@@ -14,7 +13,7 @@
 import java.util.Set;
 import java.util.StringTokenizer;
 
-public class IDEAJRenderer extends AbstractRenderer {
+public class IDEAJRenderer extends OnTheFlyRenderer {
 
 	private static final String FILE_SEPARATOR = System.getProperty("file.separator");
 	private static final String PATH_SEPARATOR = System.getProperty("path.separator");
@@ -45,37 +44,42 @@ public IDEAJRenderer(String[] args) {
         this.args = args;
     }
 
-    public void render(Writer writer, Report report) throws IOException {
+    public void start() throws IOException {}
+
+    public void renderFileViolations(Iterator<IRuleViolation> violations) throws IOException {
+        Writer writer = getWriter();
         if (args[4].equals(".method")) {
             // working on a directory tree
             String sourcePath = args[3];
-            render(writer, report, sourcePath);
+            render(writer, violations, sourcePath);
             return;
         }
         // working on one file
         String classAndMethodName = args[4];
         String singleFileName = args[5];
-        render(writer, report, classAndMethodName, singleFileName);
+        render(writer, violations, classAndMethodName, singleFileName);
     }
 
-    private void render(Writer writer, Report report, String sourcePathString) throws IOException {
+    public void end() throws IOException {}
+
+    private void render(Writer writer, Iterator<IRuleViolation> violations, String sourcePathString) throws IOException {
         SourcePath sourcePath = new SourcePath(sourcePathString);
         StringBuffer buf = new StringBuffer();
-        for (Iterator<IRuleViolation> i = report.iterator(); i.hasNext();) {
+        while (violations.hasNext()) {
             buf.setLength(0);
-            IRuleViolation rv = i.next();
+            IRuleViolation rv = violations.next();
             buf.append(rv.getDescription() + PMD.EOL);
             buf.append(" at ").append(getFullyQualifiedClassName(rv.getFilename(), sourcePath)).append(".method(");
             buf.append(getSimpleFileName(rv.getFilename())).append(':').append(rv.getBeginLine()).append(')').append(PMD.EOL);
             writer.write(buf.toString());
         }
     }
 
-    private void render(Writer writer, Report report, String classAndMethod, String file) throws IOException {
+    private void render(Writer writer, Iterator<IRuleViolation> violations, String classAndMethod, String file) throws IOException {
         StringBuffer buf = new StringBuffer();
-        for (Iterator<IRuleViolation> i = report.iterator(); i.hasNext();) {
+        while (violations.hasNext()) {
             buf.setLength(0);
-            IRuleViolation rv = i.next();
+            IRuleViolation rv = violations.next();
             buf.append(rv.getDescription()).append(PMD.EOL);
             buf.append(" at ").append(classAndMethod).append('(').append(file).append(':').append(rv.getBeginLine()).append(')').append(PMD.EOL);
             writer.write(buf.toString());
https://github.com/adangel/pmd/raw/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FIDEAJRenderer.java
229386f4d72cff2092188bf063e40edc24f7ca30
modified
https://github.com/adangel/pmd/blob/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FRenderer.java
https://api.github.com/repos/adangel/pmd/contents/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FRenderer.java?ref=14da817cf7cc74de98af1649d9dde7da3b4b6c7d
pmd/src/net/sourceforge/pmd/renderers/Renderer.java
    /**
     * 
     * @deprecated This method consumes too much memory.
     * Use the start, renderFileReport and end methods instead.
     * 
     */
    void setWriter(Writer writer);

    Writer getWriter();

    void start() throws IOException;

    void renderFileReport(Report report) throws IOException;

    void end() throws IOException;

@@ -20,6 +20,22 @@ public interface Renderer {
      */
     String render(Report report);
 
+    /**
+     * 
+     * @deprecated This method consumes too much memory.
+     * Use the start, renderFileReport and end methods instead.
+     * 
+     */
     void render(Writer writer, Report report) throws IOException;
 
+    void setWriter(Writer writer);
+
+    Writer getWriter();
+
+    void start() throws IOException;
+
+    void renderFileReport(Report report) throws IOException;
+
+    void end() throws IOException;
+
 }
https://github.com/adangel/pmd/raw/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FRenderer.java
40f686536d15a5b5c7e6d1e68acb1975755763ff
modified
https://github.com/adangel/pmd/blob/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FSummaryHTMLRenderer.java
https://api.github.com/repos/adangel/pmd/contents/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FSummaryHTMLRenderer.java?ref=14da817cf7cc74de98af1649d9dde7da3b4b6c7d
pmd/src/net/sourceforge/pmd/renderers/SummaryHTMLRenderer.java
        writer.write("<table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL);
        writer.write("<table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL + "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL);
@@ -22,7 +22,7 @@ public void render(Writer writer, Report report) throws IOException {
         writer.write("<html><head><title>PMD</title></head><body>" + PMD.EOL);
         renderSummary(writer, report);
         writer.write("<h2><center>Detail</h2></center>");
-        writer.write("<table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL + "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL);
+        writer.write("<table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL);
         new HTMLRenderer(linkPrefix,linePrefix).renderBody(writer, report);
         writer.write("</table></body></html>");
     }
https://github.com/adangel/pmd/raw/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FSummaryHTMLRenderer.java
64009639be56e542df6e5d07d31befa09f5537ff
modified
https://github.com/adangel/pmd/blob/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FTextPadRenderer.java
https://api.github.com/repos/adangel/pmd/contents/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FTextPadRenderer.java?ref=14da817cf7cc74de98af1649d9dde7da3b4b6c7d
pmd/src/net/sourceforge/pmd/renderers/TextPadRenderer.java
public class TextPadRenderer extends OnTheFlyRenderer {

    public void start() throws IOException {}

    public void renderFileViolations(Iterator<IRuleViolation> violations) throws IOException {
        Writer writer = getWriter();
        while (violations.hasNext()) {
            IRuleViolation rv = violations.next();

    public void end() throws IOException {}
import net.sourceforge.pmd.Report;
public class TextPadRenderer extends AbstractRenderer {
    public void render(Writer writer, Report report) throws IOException {
        Iterator<IRuleViolation> i;
        try {
            i = report.iterator();
        } catch (NullPointerException npx) {
            throw new NullPointerException("ERROR in " + this.getClass().getName() + ".render:  Parameter report is null.");
        }
        while (i.hasNext()) {
            IRuleViolation rv = i.next();
@@ -5,7 +5,6 @@
 
 import net.sourceforge.pmd.IRuleViolation;
 import net.sourceforge.pmd.PMD;
-import net.sourceforge.pmd.Report;
 
 import java.io.IOException;
 import java.io.Writer;
@@ -26,17 +25,15 @@
  *
  * @author Jeff Epstein, based upon <a href="EmacsRenderer.html">EmacsRenderer</a>, Tuesday, September 23, 2003
  */
-public class TextPadRenderer extends AbstractRenderer {
-    public void render(Writer writer, Report report) throws IOException {
+public class TextPadRenderer extends OnTheFlyRenderer {
+
+    public void start() throws IOException {}
+
+    public void renderFileViolations(Iterator<IRuleViolation> violations) throws IOException {
+        Writer writer = getWriter();
         StringBuffer buf = new StringBuffer();
-        Iterator<IRuleViolation> i;
-        try {
-            i = report.iterator();
-        } catch (NullPointerException npx) {
-            throw new NullPointerException("ERROR in " + this.getClass().getName() + ".render:  Parameter report is null.");
-        }
-        while (i.hasNext()) {
-            IRuleViolation rv = i.next();
+        while (violations.hasNext()) {
+            IRuleViolation rv = violations.next();
             buf.setLength(0);
             //Filename
             buf.append(PMD.EOL).append(rv.getFilename() + "(");
@@ -49,4 +46,6 @@ public void render(Writer writer, Report report) throws IOException {
             writer.write(buf.toString());
         }
     }
+
+    public void end() throws IOException {}
 }
https://github.com/adangel/pmd/raw/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FTextPadRenderer.java
bb93ec85206a84e6e799f836e0d21e132fc44c25
modified
https://github.com/adangel/pmd/blob/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FTextRenderer.java
https://api.github.com/repos/adangel/pmd/contents/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FTextRenderer.java?ref=14da817cf7cc74de98af1649d9dde7da3b4b6c7d
pmd/src/net/sourceforge/pmd/renderers/TextRenderer.java
public class TextRenderer extends OnTheFlyRenderer {
    private boolean empty;

    public void start() throws IOException {
        empty = true;
    }

    public void renderFileViolations(Iterator<IRuleViolation> violations) throws IOException {
        Writer writer = getWriter();
        empty = !violations.hasNext();
        while (violations.hasNext()) {
            IRuleViolation rv = violations.next();
    }
    public void end() throws IOException {
        Writer writer = getWriter();
        StringBuffer buf = new StringBuffer();
        if (!errors.isEmpty()) {
            empty = false;
            for(Report.ProcessingError error: errors) {
                buf.setLength(0);
                buf.append(PMD.EOL).append(error.getFile());
                buf.append("\t-\t").append(error.getMsg());
                writer.write(buf.toString());
            }
        for(Report.SuppressedViolation excluded: suppressed) {
            buf.setLength(0);
            writer.write(buf.toString());
        }

        if (empty) {
            getWriter().write("No problems found!");

public class TextRenderer extends AbstractRenderer {
    public void render(Writer writer, Report report) throws IOException {
        if (report.isEmpty()) {
            buf.append("No problems found!");
            if (showSuppressedViolations) {
                addSuppressed(report, buf);
            }
            writer.write(buf.toString());
            return;
        }
        
        for (Iterator<IRuleViolation> i = report.iterator(); i.hasNext();) {
            IRuleViolation rv = i.next();
        for (Iterator<Report.ProcessingError> i = report.errors(); i.hasNext();) {
            buf.setLength(0);
            Report.ProcessingError error = i.next();
            buf.append(PMD.EOL).append(error.getFile());
            buf.append("\t-\t").append(error.getMsg());
            writer.write(buf.toString());
        }
        if (showSuppressedViolations) {
            buf.setLength(0);
            addSuppressed(report, buf);
            writer.write(buf.toString());
    }
    private void addSuppressed(Report report, StringBuffer buf) {
        for (Report.SuppressedViolation excluded: report.getSuppressedRuleViolations()) {
@@ -11,51 +11,56 @@
 import java.io.Writer;
 import java.util.Iterator;
 
-public class TextRenderer extends AbstractRenderer {
+public class TextRenderer extends OnTheFlyRenderer {
 
-    public void render(Writer writer, Report report) throws IOException {
+    private boolean empty;
+
+    public void start() throws IOException {
+        empty = true;
+    }
+
+    public void renderFileViolations(Iterator<IRuleViolation> violations) throws IOException {
+        Writer writer = getWriter();
         StringBuffer buf = new StringBuffer();
 
-        if (report.isEmpty()) {
-            buf.append("No problems found!");
-            if (showSuppressedViolations) {
-                addSuppressed(report, buf);
-            }
-            writer.write(buf.toString());
-            return;
-        }
-        
-        for (Iterator<IRuleViolation> i = report.iterator(); i.hasNext();) {
+        empty = !violations.hasNext();
+        while (violations.hasNext()) {
             buf.setLength(0);
-            IRuleViolation rv = i.next();
+            IRuleViolation rv = violations.next();
             buf.append(PMD.EOL).append(rv.getFilename());
             buf.append(':').append(Integer.toString(rv.getBeginLine()));
             buf.append('\t').append(rv.getDescription());
             writer.write(buf.toString());
         }
+    }
 
-        for (Iterator<Report.ProcessingError> i = report.errors(); i.hasNext();) {
-            buf.setLength(0);
-            Report.ProcessingError error = i.next();
-            buf.append(PMD.EOL).append(error.getFile());
-            buf.append("\t-\t").append(error.getMsg());
-            writer.write(buf.toString());
-        }
+    public void end() throws IOException {
+        Writer writer = getWriter();
+        StringBuffer buf = new StringBuffer();
+        if (!errors.isEmpty()) {
+            empty = false;
 
-        if (showSuppressedViolations) {
-            buf.setLength(0);
-            addSuppressed(report, buf);
-            writer.write(buf.toString());
+            for(Report.ProcessingError error: errors) {
+                buf.setLength(0);
+                buf.append(PMD.EOL).append(error.getFile());
+                buf.append("\t-\t").append(error.getMsg());
+                writer.write(buf.toString());
+            }
         }
-    }
 
-    private void addSuppressed(Report report, StringBuffer buf) {
-        for (Report.SuppressedViolation excluded: report.getSuppressedRuleViolations()) {
+        for(Report.SuppressedViolation excluded: suppressed) {
+            buf.setLength(0);
             buf.append(PMD.EOL);
             buf.append(excluded.getRuleViolation().getRule().getName());
             buf.append(" rule violation suppressed by ");
             buf.append(excluded.suppressedByNOPMD() ? "//NOPMD" : "Annotation");
             buf.append(" in ").append(excluded.getRuleViolation().getFilename());
+            writer.write(buf.toString());
+        }
+
+        if (empty) {
+            getWriter().write("No problems found!");
         }
     }
+
 }
https://github.com/adangel/pmd/raw/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FTextRenderer.java
83e7b1865889e1a37d297851059b8a7ab18c16aa
modified
https://github.com/adangel/pmd/blob/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FVBHTMLRenderer.java
https://api.github.com/repos/adangel/pmd/contents/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FVBHTMLRenderer.java?ref=14da817cf7cc74de98af1649d9dde7da3b4b6c7d
pmd/src/net/sourceforge/pmd/renderers/VBHTMLRenderer.java
public class VBHTMLRenderer extends OnTheFlyRenderer {
    public void start() throws IOException {
        getWriter().write(header());      
    }

    public void renderFileViolations(Iterator<IRuleViolation> violations) throws IOException {
        if (!violations.hasNext()) {
        Writer writer = getWriter();
        while (violations.hasNext()) {
            IRuleViolation rv = violations.next();
    }

    public void end() throws IOException {
        Writer writer = getWriter();
        StringBuffer sb = new StringBuffer();
        
        if (!errors.isEmpty()) {
            boolean colorize = false;
            for (Report.ProcessingError error: errors) {
                sb.append("<td><font class=body>").append(error).append("\"</font></td></tr>");
        writer.write(footer());     
public class VBHTMLRenderer extends AbstractRenderer {
    public void render(Writer writer, Report report) throws IOException {
        if (report.isEmpty()) {

        writer.write(header());
        for (Iterator<IRuleViolation> iter = report.iterator(); iter.hasNext();) {
            IRuleViolation rv = iter.next();
        Iterator iter = report.errors();
        if (iter.hasNext()) {
            colorize = false;
            while (iter.hasNext()) {
                sb.append("<td><font class=body>").append(iter.next()).append("\"</font></td></tr>");
        writer.write(footer());
@@ -15,23 +15,26 @@
  * @author Vladimir
  * @version $Revision$ $Date$
  */
-public class VBHTMLRenderer extends AbstractRenderer {
+public class VBHTMLRenderer extends OnTheFlyRenderer {
 
-    public void render(Writer writer, Report report) throws IOException {
-        if (report.isEmpty()) {
+    public void start() throws IOException {
+        getWriter().write(header());      
+    }
+
+    public void renderFileViolations(Iterator<IRuleViolation> violations) throws IOException {
+        if (!violations.hasNext()) {
             return;
         }
 
+        Writer writer = getWriter();
         StringBuffer sb = new StringBuffer();
         String filename = null;
         String lineSep = PMD.EOL;
 
         boolean colorize = false;
-
-        writer.write(header());
-        for (Iterator<IRuleViolation> iter = report.iterator(); iter.hasNext();) {
+        while (violations.hasNext()) {
             sb.setLength(0);
-            IRuleViolation rv = iter.next();
+            IRuleViolation rv = violations.next();
             if (!rv.getFilename().equals(filename)) { // New File
                 if (filename != null) {
                     sb.append("</table></br>");
@@ -59,29 +62,34 @@ public void render(Writer writer, Report report) throws IOException {
         if (filename != null) {
             writer.write("</table>");
         }
+    }
+
+    public void end() throws IOException {
+        Writer writer = getWriter();
+        StringBuffer sb = new StringBuffer();
+        
         writer.write("<br>");
 
         // output the problems
-        Iterator iter = report.errors();
-        if (iter.hasNext()) {
+        if (!errors.isEmpty()) {
             sb.setLength(0);
             sb.append("<table border=\"0\" width=\"80%\">");
             sb.append("<tr id=TableHeader><td><font class=title>&nbsp;Problems found</font></td></tr>");
-            colorize = false;
-            while (iter.hasNext()) {
+            boolean colorize = false;
+            for (Report.ProcessingError error: errors) {
                 if (colorize) {
                     sb.append("<tr id=RowColor1>");
                 } else {
                     sb.append("<tr id=RowColor2>");
                 }
                 colorize = !colorize;
-                sb.append("<td><font class=body>").append(iter.next()).append("\"</font></td></tr>");
+                sb.append("<td><font class=body>").append(error).append("\"</font></td></tr>");
             }
             sb.append("</table>");
             writer.write(sb.toString());
         }
 
-        writer.write(footer());
+        writer.write(footer());     
     }
 
     private String header() {
https://github.com/adangel/pmd/raw/14da817cf7cc74de98af1649d9dde7da3b4b6c7d/pmd%2Fsrc%2Fnet%2Fsourceforge%2Fpmd%2Frenderers%2FVBHTMLRenderer.java
d933e75457782e5dfa59fd32d6a838606d69652e
modified
adangel$pmd
Report report = new Report();
            ctx.setReport(report);

                report.addError(
                report.addError(
                report.addError(
            return report;
    public static void processFiles(int threadCount, RuleSetFactory ruleSetFactory, SourceType sourceType, List<DataSource> files, RuleContext ctx,
            Renderer renderer, String rulesets, boolean debugEnabled, final boolean shortNamesEnabled, final String inputPath,
        List<Future<Report>> tasks = new LinkedList<Future<Report>>();
        
        Collections.sort(files, new Comparator<DataSource>() {
            public int compare(DataSource d1,DataSource d2) {
                String s1 = d1.getNiceFileName(shortNamesEnabled, inputPath);
                String s2 = d2.getNiceFileName(shortNamesEnabled, inputPath);
                return s1.compareTo(s2);
Report
Report call()
ctx.getReport().addError(
                ctx.getReport().addError(
                ctx.getReport().addError(
            context.setReport(new Report());
    public static void processFiles(int threadCount, RuleSetFactory ruleSetFactory, SourceType sourceType, List<DataSource> files, RuleContext ctx, String rulesets,
            boolean debugEnabled, boolean shortNamesEnabled, String inputPath,
            Runnable r = new PmdRunnable(executor, dataSource, niceFileName, sourceType, debugEnabled,
            executor.execute(r);
        try {
            executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
void
void run()