diff --git a/src/main/java/org/apache/maven/plugins/pmd/PmdCollectingRenderer.java b/src/main/java/org/apache/maven/plugins/pmd/PmdCollectingRenderer.java index 2370eadb..12ada600 100644 --- a/src/main/java/org/apache/maven/plugins/pmd/PmdCollectingRenderer.java +++ b/src/main/java/org/apache/maven/plugins/pmd/PmdCollectingRenderer.java @@ -22,12 +22,15 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.codehaus.plexus.util.StringUtils; import net.sourceforge.pmd.Report; import net.sourceforge.pmd.Report.ProcessingError; +import net.sourceforge.pmd.Report.SuppressedViolation; import net.sourceforge.pmd.RuleViolation; import net.sourceforge.pmd.renderers.AbstractRenderer; import net.sourceforge.pmd.util.datasource.DataSource; @@ -41,8 +44,9 @@ */ public class PmdCollectingRenderer extends AbstractRenderer { - private List errors = Collections.synchronizedList( new ArrayList() ); - private List violations = Collections.synchronizedList( new ArrayList() ); + private List errors = Collections.synchronizedList( new ArrayList<>() ); + private List violations = Collections.synchronizedList( new ArrayList<>() ); + private List suppressed = Collections.synchronizedList( new ArrayList<> () ); /** * Collects all reports from all threads. @@ -57,6 +61,7 @@ public void renderFileReport( Report report ) throws IOException { violations.addAll( report.getViolations() ); errors.addAll( report.getProcessingErrors() ); + suppressed.addAll( report.getSuppressedViolations() ); } /** @@ -129,6 +134,19 @@ public Report asReport() { report.addError( e ); } + Map suppressedLines = new HashMap(); + for ( SuppressedViolation s : suppressed ) + { + if ( s.suppressedByNOPMD() ) + { + suppressedLines.put( s.getRuleViolation().getBeginLine(), s.getUserMessage() ); + } + } + report.suppress( suppressedLines ); + for ( SuppressedViolation s : suppressed ) + { + report.addRuleViolation( s.getRuleViolation() ); + } return report; } diff --git a/src/main/java/org/apache/maven/plugins/pmd/PmdReport.java b/src/main/java/org/apache/maven/plugins/pmd/PmdReport.java index 2c68e0f7..124deb94 100644 --- a/src/main/java/org/apache/maven/plugins/pmd/PmdReport.java +++ b/src/main/java/org/apache/maven/plugins/pmd/PmdReport.java @@ -216,6 +216,14 @@ public class PmdReport @Parameter( property = "pmd.renderViolationsByPriority", defaultValue = "true" ) private boolean renderViolationsByPriority = true; + /** + * Add a section in the HTML report that lists the suppressed violations. + * + * @since 3.17.0 + */ + @Parameter( property = "pmd.renderSuppressedViolations", defaultValue = "true" ) + private boolean renderSuppressedViolations = true; + /** * Before PMD is executed, the configured rulesets are resolved and copied into this directory. *

Note: Before 3.13.0, this was by default ${project.build.directory}. @@ -501,6 +509,10 @@ private void generateMavenSiteReport( Locale locale ) doxiaRenderer.setRenderViolationsByPriority( renderViolationsByPriority ); doxiaRenderer.setFiles( filesToProcess ); doxiaRenderer.setViolations( pmdResult.getViolations() ); + if ( renderSuppressedViolations ) + { + doxiaRenderer.setSuppressedViolations( pmdResult.getSuppressedViolations() ); + } if ( renderProcessingErrors ) { doxiaRenderer.setProcessingErrors( pmdResult.getErrors() ); diff --git a/src/main/java/org/apache/maven/plugins/pmd/PmdReportGenerator.java b/src/main/java/org/apache/maven/plugins/pmd/PmdReportGenerator.java index a0943631..e266cb56 100644 --- a/src/main/java/org/apache/maven/plugins/pmd/PmdReportGenerator.java +++ b/src/main/java/org/apache/maven/plugins/pmd/PmdReportGenerator.java @@ -35,6 +35,7 @@ import org.apache.maven.doxia.sink.Sink; import org.apache.maven.plugin.logging.Log; import org.apache.maven.plugins.pmd.model.ProcessingError; +import org.apache.maven.plugins.pmd.model.SuppressedViolation; import org.apache.maven.plugins.pmd.model.Violation; import org.codehaus.plexus.util.StringUtils; @@ -58,6 +59,8 @@ public class PmdReportGenerator private Set violations = new HashSet<>(); + private List suppressedViolations = new ArrayList<>(); + private List processingErrors = new ArrayList<>(); private boolean aggregate; @@ -93,6 +96,11 @@ public List getViolations() return new ArrayList<>( violations ); } + public void setSuppressedViolations( Collection suppressedViolations ) + { + this.suppressedViolations = new ArrayList<>( suppressedViolations ); + } + public void setProcessingErrors( Collection errors ) { this.processingErrors = new ArrayList<>( errors ); @@ -377,6 +385,73 @@ private void outputLineLink( int line, PmdFileInfo fileInfo ) } } + // PMD might run the analysis multi-threaded, so the suppressed violations might be reported + // out of order. We sort them here by filename before writing them to + // the report. + private void renderSuppressedViolations() + throws IOException + { + sink.section1(); + sink.sectionTitle1(); + sink.text( bundle.getString( "report.pmd.suppressedViolations.title" ) ); + sink.sectionTitle1_(); + + Collections.sort( suppressedViolations, new Comparator() + { + @Override + public int compare( SuppressedViolation o1, SuppressedViolation o2 ) + { + return o1.getFilename().compareTo( o2.getFilename() ); + } + } ); + + sink.table(); + sink.tableRow(); + sink.tableHeaderCell(); + sink.text( bundle.getString( "report.pmd.suppressedViolations.column.filename" ) ); + sink.tableHeaderCell_(); + sink.tableHeaderCell(); + sink.text( bundle.getString( "report.pmd.suppressedViolations.column.ruleMessage" ) ); + sink.tableHeaderCell_(); + sink.tableHeaderCell(); + sink.text( bundle.getString( "report.pmd.suppressedViolations.column.suppressionType" ) ); + sink.tableHeaderCell_(); + sink.tableHeaderCell(); + sink.text( bundle.getString( "report.pmd.suppressedViolations.column.userMessage" ) ); + sink.tableHeaderCell_(); + sink.tableRow_(); + + for ( SuppressedViolation suppressedViolation : suppressedViolations ) + { + String filename = suppressedViolation.getFilename(); + PmdFileInfo fileInfo = determineFileInfo( filename ); + filename = shortenFilename( filename, fileInfo ); + + sink.tableRow(); + + sink.tableCell(); + sink.text( filename ); + sink.tableCell_(); + + sink.tableCell(); + sink.text( suppressedViolation.getRuleMessage() ); + sink.tableCell_(); + + sink.tableCell(); + sink.text( suppressedViolation.getSuppressionType() ); + sink.tableCell_(); + + sink.tableCell(); + sink.text( suppressedViolation.getUserMessage() ); + sink.tableCell_(); + + sink.tableRow_(); + } + + sink.table_(); + sink.section1_(); + } + private void processProcessingErrors() throws IOException { // sort the problem by filename first, since PMD is executed multi-threaded @@ -492,6 +567,11 @@ public void render() sink.paragraph_(); } + if ( !suppressedViolations.isEmpty() ) + { + renderSuppressedViolations(); + } + if ( !processingErrors.isEmpty() ) { processProcessingErrors(); diff --git a/src/main/java/org/apache/maven/plugins/pmd/exec/PmdResult.java b/src/main/java/org/apache/maven/plugins/pmd/exec/PmdResult.java index 93645d74..667b8491 100644 --- a/src/main/java/org/apache/maven/plugins/pmd/exec/PmdResult.java +++ b/src/main/java/org/apache/maven/plugins/pmd/exec/PmdResult.java @@ -32,6 +32,7 @@ import org.apache.maven.plugins.pmd.model.PmdErrorDetail; import org.apache.maven.plugins.pmd.model.PmdFile; import org.apache.maven.plugins.pmd.model.ProcessingError; +import org.apache.maven.plugins.pmd.model.SuppressedViolation; import org.apache.maven.plugins.pmd.model.Violation; import org.apache.maven.plugins.pmd.model.io.xpp3.PmdXpp3Reader; import org.apache.maven.reporting.MavenReportException; @@ -43,6 +44,7 @@ public class PmdResult { private final List processingErrors = new ArrayList<>(); private final List violations = new ArrayList<>(); + private final List suppressedViolations = new ArrayList<>(); public static final PmdResult EMPTY = new PmdResult(); @@ -68,6 +70,7 @@ private void loadResult( File pmdFile, String encoding ) throws MavenReportExcep PmdXpp3Reader reader = new PmdXpp3Reader(); PmdErrorDetail details = reader.read( reader1, false ); processingErrors.addAll( details.getErrors() ); + suppressedViolations.addAll( details.getSuppressedViolations() ); for ( PmdFile file : details.getFiles() ) { @@ -147,6 +150,11 @@ public Collection getViolations() return violations; } + public Collection getSuppressedViolations() + { + return suppressedViolations; + } + public Collection getErrors() { return processingErrors; diff --git a/src/main/mdo/pmd.mdo b/src/main/mdo/pmd.mdo index 2c2a084b..f41ee3c8 100644 --- a/src/main/mdo/pmd.mdo +++ b/src/main/mdo/pmd.mdo @@ -45,6 +45,13 @@ under the License. * + + suppressedViolations + + SuppressedViolation + * + + errors @@ -126,6 +133,27 @@ under the License. + + SuppressedViolation + + + filename + String + + + suppressionType + String + + + ruleMessage + String + + + userMessage + String + + + ProcessingError diff --git a/src/main/resources/pmd-report.properties b/src/main/resources/pmd-report.properties index afe94603..98858b9d 100644 --- a/src/main/resources/pmd-report.properties +++ b/src/main/resources/pmd-report.properties @@ -27,6 +27,11 @@ report.pmd.files=Files report.pmd.violationsByPriority=Violations By Priority report.pmd.priority=Priority report.pmd.noProblems=PMD found no problems in your source code. +report.pmd.suppressedViolations.title=Suppressed Violations +report.pmd.suppressedViolations.column.filename=Filename +report.pmd.suppressedViolations.column.ruleMessage=Rule message +report.pmd.suppressedViolations.column.suppressionType=Suppression type +report.pmd.suppressedViolations.column.userMessage=Reason report.pmd.processingErrors.title=Processing Errors report.pmd.processingErrors.column.filename=Filename report.pmd.processingErrors.column.problem=Problem diff --git a/src/main/resources/pmd-report_de.properties b/src/main/resources/pmd-report_de.properties index 83f72d4b..a3dfea62 100644 --- a/src/main/resources/pmd-report_de.properties +++ b/src/main/resources/pmd-report_de.properties @@ -27,6 +27,11 @@ report.pmd.files=Dateien report.pmd.violationsByPriority=Verst\u00f6\u00dfe nach Priorit\u00e4t report.pmd.priority=Priorit\u00e4t report.pmd.noProblems=PMD hat keine Probleme in dem Quellcode gefunden. +report.pmd.suppressedViolations.title=Unterdr\u00fcckte Verst\u00f6\u00dfe +report.pmd.suppressedViolations.column.filename=Datei +report.pmd.suppressedViolations.column.ruleMessage=Regel +report.pmd.suppressedViolations.column.suppressionType=Art der Unterdr\u00fcckung +report.pmd.suppressedViolations.column.userMessage=Grund report.pmd.processingErrors.title=Verarbeitungsprobleme report.pmd.processingErrors.column.filename=Datei report.pmd.processingErrors.column.problem=Problem diff --git a/src/test/java/org/apache/maven/plugins/pmd/PmdReportTest.java b/src/test/java/org/apache/maven/plugins/pmd/PmdReportTest.java index db8f94f9..c8ddae3f 100644 --- a/src/test/java/org/apache/maven/plugins/pmd/PmdReportTest.java +++ b/src/test/java/org/apache/maven/plugins/pmd/PmdReportTest.java @@ -530,6 +530,51 @@ public void testSuppressMarkerConfiguration() String str = readFile( generatedFile ); // check that there is no violation reported for "unusedVar2" - as it is suppressed + assertFalse( str.contains( "Avoid unused private fields such as 'unusedVar2'.\n " ) ); + // but it appears as suppressed + assertTrue( str.contains( "suppressiontype=\"nopmd\" msg=\"Avoid unused private fields such as 'unusedVar2'.\"" )); + + generatedFile = new File( getBasedir(), "target/test/unit/default-configuration/target/site/pmd.html" ); + renderer( mojo, generatedFile ); + assertTrue( FileUtils.fileExists( generatedFile.getAbsolutePath() ) ); + + // check if there's a link to the JXR files + str = readFile( generatedFile ); + + assertTrue( str.contains( "/xref/def/configuration/AppSample.html#L27" ) ); + // suppressed violation + assertTrue( str.contains( "Avoid unused private fields such as 'unusedVar2'." ) ); + } + + public void testSuppressMarkerConfigurationWithoutRendering() + throws Exception + { + File testPom = + new File( getBasedir(), + "src/test/resources/unit/default-configuration/pmd-with-suppressMarker-no-render-plugin-config.xml" ); + PmdReport mojo = (PmdReport) lookupMojo( "pmd", testPom ); + mojo.execute(); + + // check if the PMD files were generated + File generatedFile = new File( getBasedir(), "target/test/unit/default-configuration/target/pmd.xml" ); + assertTrue( FileUtils.fileExists( generatedFile.getAbsolutePath() ) ); + + String str = readFile( generatedFile ); + + // check that there is no violation reported for "unusedVar2" - as it is suppressed + assertFalse( str.contains( "Avoid unused private fields such as 'unusedVar2'.\n " ) ); + // but it appears as suppressed + assertTrue( str.contains( "suppressiontype=\"nopmd\" msg=\"Avoid unused private fields such as 'unusedVar2'.\"" )); + + generatedFile = new File( getBasedir(), "target/test/unit/default-configuration/target/site/pmd.html" ); + renderer( mojo, generatedFile ); + assertTrue( FileUtils.fileExists( generatedFile.getAbsolutePath() ) ); + + // check if there's a link to the JXR files + str = readFile( generatedFile ); + + assertTrue( str.contains( "/xref/def/configuration/AppSample.html#L27" ) ); + // suppressed violations are not rendered assertFalse( str.contains( "Avoid unused private fields such as 'unusedVar2'." ) ); } diff --git a/src/test/resources/unit/default-configuration/pmd-with-suppressMarker-no-render-plugin-config.xml b/src/test/resources/unit/default-configuration/pmd-with-suppressMarker-no-render-plugin-config.xml new file mode 100644 index 00000000..1f94bf20 --- /dev/null +++ b/src/test/resources/unit/default-configuration/pmd-with-suppressMarker-no-render-plugin-config.xml @@ -0,0 +1,70 @@ + + + + 4.0.0 + def.configuration + suppressMarker-no-render-configuration + jar + 1.0-SNAPSHOT + 2006 + Maven PMD Plugin SuppressMarker No Render Configuration Test + http://maven.apache.org + + default-configuration + + + org.apache.maven.plugins + maven-pmd-plugin + + + ${basedir}/target/test/unit/default-configuration/target/site + ${basedir}/target/test/unit/default-configuration/target + ${basedir}/target/test/unit/default-configuration/target/pmd/rulesets + xml + true + ${basedir}/target/test/unit/default-configuration/target/site/xref + UTF-8 + + SUPPRESSME + false + + + ${basedir}/src/test/resources/unit/default-configuration/ + + + + + pmd + pmd + 3.6 + + + + + + + + + org.apache.maven.plugins + maven-jxr-plugin + + + +