Merge pull request #59 from adangel:MPMD-309
[MPMD-309] Add configuration option to show suppressed violations
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 2370ead..12ada60 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<ProcessingError> errors = Collections.synchronizedList( new ArrayList<ProcessingError>() );
- private List<RuleViolation> violations = Collections.synchronizedList( new ArrayList<RuleViolation>() );
+ private List<ProcessingError> errors = Collections.synchronizedList( new ArrayList<>() );
+ private List<RuleViolation> violations = Collections.synchronizedList( new ArrayList<>() );
+ private List<SuppressedViolation> suppressed = Collections.synchronizedList( new ArrayList<> () );
/**
* Collects all reports from all threads.
@@ -57,6 +61,7 @@
{
violations.addAll( report.getViolations() );
errors.addAll( report.getProcessingErrors() );
+ suppressed.addAll( report.getSuppressedViolations() );
}
/**
@@ -129,6 +134,19 @@
{
report.addError( e );
}
+ Map<Integer, String> suppressedLines = new HashMap<Integer, String>();
+ 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 2c68e0f..124deb9 100644
--- a/src/main/java/org/apache/maven/plugins/pmd/PmdReport.java
+++ b/src/main/java/org/apache/maven/plugins/pmd/PmdReport.java
@@ -217,6 +217,14 @@
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.
* <p>Note: Before 3.13.0, this was by default ${project.build.directory}.
*
@@ -501,6 +509,10 @@
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 a094363..e266cb5 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 @@
private Set<Violation> violations = new HashSet<>();
+ private List<SuppressedViolation> suppressedViolations = new ArrayList<>();
+
private List<ProcessingError> processingErrors = new ArrayList<>();
private boolean aggregate;
@@ -93,6 +96,11 @@
return new ArrayList<>( violations );
}
+ public void setSuppressedViolations( Collection<SuppressedViolation> suppressedViolations )
+ {
+ this.suppressedViolations = new ArrayList<>( suppressedViolations );
+ }
+
public void setProcessingErrors( Collection<ProcessingError> errors )
{
this.processingErrors = new ArrayList<>( errors );
@@ -377,6 +385,73 @@
}
}
+ // 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<SuppressedViolation>()
+ {
+ @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 @@
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 93645d7..667b849 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 @@
{
private final List<ProcessingError> processingErrors = new ArrayList<>();
private final List<Violation> violations = new ArrayList<>();
+ private final List<SuppressedViolation> suppressedViolations = new ArrayList<>();
public static final PmdResult EMPTY = new PmdResult();
@@ -68,6 +70,7 @@
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 @@
return violations;
}
+ public Collection<SuppressedViolation> getSuppressedViolations()
+ {
+ return suppressedViolations;
+ }
+
public Collection<ProcessingError> getErrors()
{
return processingErrors;
diff --git a/src/main/mdo/pmd.mdo b/src/main/mdo/pmd.mdo
index 2c2a084..f41ee3c 100644
--- a/src/main/mdo/pmd.mdo
+++ b/src/main/mdo/pmd.mdo
@@ -46,6 +46,13 @@
</association>
</field>
<field>
+ <name>suppressedViolations</name>
+ <association xml.tagName="suppressedviolation" xml.itemsStyle="flat">
+ <type>SuppressedViolation</type>
+ <multiplicity>*</multiplicity>
+ </association>
+ </field>
+ <field>
<name>errors</name>
<association xml.tagName="error" xml.itemsStyle="flat">
<type>ProcessingError</type>
@@ -127,6 +134,27 @@
</codeSegments>
</class>
<class>
+ <name>SuppressedViolation</name>
+ <fields>
+ <field xml.attribute="true">
+ <name>filename</name>
+ <type>String</type>
+ </field>
+ <field xml.tagName="suppressiontype" xml.attribute="true">
+ <name>suppressionType</name>
+ <type>String</type>
+ </field>
+ <field xml.tagName="msg" xml.attribute="true">
+ <name>ruleMessage</name>
+ <type>String</type>
+ </field>
+ <field xml.tagName="usermsg" xml.attribute="true">
+ <name>userMessage</name>
+ <type>String</type>
+ </field>
+ </fields>
+ </class>
+ <class>
<name>ProcessingError</name>
<fields>
<field xml.attribute="true">
diff --git a/src/main/resources/pmd-report.properties b/src/main/resources/pmd-report.properties
index afe9460..98858b9 100644
--- a/src/main/resources/pmd-report.properties
+++ b/src/main/resources/pmd-report.properties
@@ -27,6 +27,11 @@
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 83f72d4..a3dfea6 100644
--- a/src/main/resources/pmd-report_de.properties
+++ b/src/main/resources/pmd-report_de.properties
@@ -27,6 +27,11 @@
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 db8f94f..c8ddae3 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 @@
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 </violation>" ) );
+ // 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 </violation>" ) );
+ // 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 0000000..1f94bf2
--- /dev/null
+++ b/src/test/resources/unit/default-configuration/pmd-with-suppressMarker-no-render-plugin-config.xml
@@ -0,0 +1,70 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>def.configuration</groupId>
+ <artifactId>suppressMarker-no-render-configuration</artifactId>
+ <packaging>jar</packaging>
+ <version>1.0-SNAPSHOT</version>
+ <inceptionYear>2006</inceptionYear>
+ <name>Maven PMD Plugin SuppressMarker No Render Configuration Test</name>
+ <url>http://maven.apache.org</url>
+ <build>
+ <finalName>default-configuration</finalName>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-pmd-plugin</artifactId>
+ <configuration>
+ <project implementation="org.apache.maven.plugins.pmd.stubs.DefaultConfigurationMavenProjectStub"/>
+ <outputDirectory>${basedir}/target/test/unit/default-configuration/target/site</outputDirectory>
+ <targetDirectory>${basedir}/target/test/unit/default-configuration/target</targetDirectory>
+ <rulesetsTargetDirectory>${basedir}/target/test/unit/default-configuration/target/pmd/rulesets</rulesetsTargetDirectory>
+ <format>xml</format>
+ <linkXRef>true</linkXRef>
+ <xrefLocation>${basedir}/target/test/unit/default-configuration/target/site/xref</xrefLocation>
+ <sourceEncoding>UTF-8</sourceEncoding>
+
+ <suppressMarker>SUPPRESSME</suppressMarker>
+ <renderSuppressedViolations>false</renderSuppressedViolations>
+
+ <compileSourceRoots>
+ <compileSourceRoot>${basedir}/src/test/resources/unit/default-configuration/</compileSourceRoot>
+ </compileSourceRoots>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>pmd</groupId>
+ <artifactId>pmd</artifactId>
+ <version>3.6</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jxr-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </reporting>
+</project>