diff --git a/src/it/MPMD-266-typeresolution-aggregated/invoker.properties b/src/it/MPMD-266-typeresolution-aggregated/invoker.properties index 2490429a..59e9a7b0 100644 --- a/src/it/MPMD-266-typeresolution-aggregated/invoker.properties +++ b/src/it/MPMD-266-typeresolution-aggregated/invoker.properties @@ -15,6 +15,6 @@ # specific language governing permissions and limitations # under the License. -invoker.goals = clean install -invoker.goals.2 = site +invoker.goals = clean verify +invoker.goals.2 = verify site -DskipTests invoker.maven.version = 3+ diff --git a/src/it/MPMD-266-typeresolution-aggregated/module-a/pom.xml b/src/it/MPMD-266-typeresolution-aggregated/module-a/pom.xml index d60ab9e4..a71e17de 100644 --- a/src/it/MPMD-266-typeresolution-aggregated/module-a/pom.xml +++ b/src/it/MPMD-266-typeresolution-aggregated/module-a/pom.xml @@ -30,4 +30,17 @@ under the License. MPMD-266-typeresolution-aggregated-module-a + + + + @project.groupId@ + @project.artifactId@ + + + ../ruleset.xml + + + + + diff --git a/src/it/MPMD-266-typeresolution-aggregated/module-b/pom.xml b/src/it/MPMD-266-typeresolution-aggregated/module-b/pom.xml index 3a67e1fc..e16304ac 100644 --- a/src/it/MPMD-266-typeresolution-aggregated/module-b/pom.xml +++ b/src/it/MPMD-266-typeresolution-aggregated/module-b/pom.xml @@ -30,6 +30,20 @@ under the License. MPMD-266-typeresolution-aggregated-module-b + + + + @project.groupId@ + @project.artifactId@ + + + ../ruleset.xml + + + + + + ${project.groupId} diff --git a/src/it/MPMD-266-typeresolution-aggregated/pom.xml b/src/it/MPMD-266-typeresolution-aggregated/pom.xml index 1cce966d..c56846bf 100644 --- a/src/it/MPMD-266-typeresolution-aggregated/pom.xml +++ b/src/it/MPMD-266-typeresolution-aggregated/pom.xml @@ -55,6 +55,11 @@ under the License. @project.version@ true + false + 1 + + ruleset.xml + diff --git a/src/it/MPMD-266-typeresolution-aggregated/ruleset.xml b/src/it/MPMD-266-typeresolution-aggregated/ruleset.xml index d0f3f04b..f6924eda 100644 --- a/src/it/MPMD-266-typeresolution-aggregated/ruleset.xml +++ b/src/it/MPMD-266-typeresolution-aggregated/ruleset.xml @@ -25,6 +25,8 @@ under the License. xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd"> Custom Ruleset for test case MPMD-266 - + + 5 + diff --git a/src/it/MPMD-277-multi-module-check/invoker.properties b/src/it/MPMD-277-multi-module-check/invoker.properties new file mode 100644 index 00000000..abe0f0da --- /dev/null +++ b/src/it/MPMD-277-multi-module-check/invoker.properties @@ -0,0 +1,20 @@ +# 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. + +invoker.goals = clean package +invoker.goals.2 = verify +invoker.maven.version = 3+ diff --git a/src/it/MPMD-277-multi-module-check/module-a/pom.xml b/src/it/MPMD-277-multi-module-check/module-a/pom.xml new file mode 100644 index 00000000..c972de6b --- /dev/null +++ b/src/it/MPMD-277-multi-module-check/module-a/pom.xml @@ -0,0 +1,33 @@ + + + + + + 4.0.0 + + + org.apache.maven.plugins.pmd.it + MPMD-277-multi-module-check-parent + 1.0-SNAPSHOT + + + MPMD-277-multi-module-check-module-a + + diff --git a/src/it/MPMD-277-multi-module-check/module-a/src/main/java/module/a/IModuleA.java b/src/it/MPMD-277-multi-module-check/module-a/src/main/java/module/a/IModuleA.java new file mode 100644 index 00000000..83cfecf9 --- /dev/null +++ b/src/it/MPMD-277-multi-module-check/module-a/src/main/java/module/a/IModuleA.java @@ -0,0 +1,24 @@ +package module.a; + +/* + * 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. + */ + +public interface IModuleA +{ +} \ No newline at end of file diff --git a/src/it/MPMD-277-multi-module-check/module-a/src/main/java/module/a/ModuleA.java b/src/it/MPMD-277-multi-module-check/module-a/src/main/java/module/a/ModuleA.java new file mode 100644 index 00000000..9d5d21dd --- /dev/null +++ b/src/it/MPMD-277-multi-module-check/module-a/src/main/java/module/a/ModuleA.java @@ -0,0 +1,24 @@ +package module.a; + +/* + * 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. + */ + +public class ModuleA implements IModuleA +{ +} \ No newline at end of file diff --git a/src/it/MPMD-277-multi-module-check/module-b/pom.xml b/src/it/MPMD-277-multi-module-check/module-b/pom.xml new file mode 100644 index 00000000..8d76fcda --- /dev/null +++ b/src/it/MPMD-277-multi-module-check/module-b/pom.xml @@ -0,0 +1,46 @@ + + + + + + 4.0.0 + + + org.apache.maven.plugins.pmd.it + MPMD-277-multi-module-check-parent + 1.0-SNAPSHOT + + + MPMD-277-multi-module-check-module-b + + + + ${project.groupId} + MPMD-277-multi-module-check-module-a + ${project.version} + + + + org.apache.commons + commons-math + 2.2 + + + diff --git a/src/it/MPMD-277-multi-module-check/module-b/src/main/java/module/b/ModuleB.java b/src/it/MPMD-277-multi-module-check/module-b/src/main/java/module/b/ModuleB.java new file mode 100644 index 00000000..0689d93a --- /dev/null +++ b/src/it/MPMD-277-multi-module-check/module-b/src/main/java/module/b/ModuleB.java @@ -0,0 +1,54 @@ +package module.b; + +/* + * 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. + */ + +import module.a.IModuleA; +import module.a.ModuleA; +import org.apache.commons.math.complex.Complex; +import org.apache.commons.math.FieldElement; + +public class ModuleB +{ + public static void main( String[] args ) + { + ModuleA m = new ModuleA(); + doSomething( m ); + } + + // this method will be detected as being unsued, + // if typeresolution is not setup correctly: module a needs + // to be on PMD's auxclasspath, so that PMD knows, that ModuleA + // implements IModuleA + private static void doSomething( IModuleA module ) + { + System.out.println( module ); + } + + public static void aPublicMethod() + { + Complex u = new Complex(1, 1); + aPrivateMethod( u ); + } + + private static void aPrivateMethod( FieldElement u ) + { + System.out.println( "aPrivateMethod: " + u ); + } +} \ No newline at end of file diff --git a/src/it/MPMD-277-multi-module-check/pom.xml b/src/it/MPMD-277-multi-module-check/pom.xml new file mode 100644 index 00000000..5c7b8871 --- /dev/null +++ b/src/it/MPMD-277-multi-module-check/pom.xml @@ -0,0 +1,69 @@ + + + + + + 4.0.0 + + org.apache.maven.plugins.pmd.it + MPMD-277-multi-module-check-parent + 1.0-SNAPSHOT + pom + + + UTF-8 + 1.8 + 1.8 + + + + module-a + module-b + + + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + true + true + + + + + check + + + + + + + + + @project.groupId@ + @project.artifactId@ + + + + diff --git a/src/it/MPMD-277-multi-module-check/ruleset.xml b/src/it/MPMD-277-multi-module-check/ruleset.xml new file mode 100644 index 00000000..004e68ad --- /dev/null +++ b/src/it/MPMD-277-multi-module-check/ruleset.xml @@ -0,0 +1,30 @@ + + + + + + Custom Ruleset for test case MPMD-277 + + + + diff --git a/src/it/MPMD-277-multi-module-check/verify.groovy b/src/it/MPMD-277-multi-module-check/verify.groovy new file mode 100644 index 00000000..ac95dd70 --- /dev/null +++ b/src/it/MPMD-277-multi-module-check/verify.groovy @@ -0,0 +1,23 @@ +/* + * 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. + */ + +File pmdXml = new File( basedir, "target/pmd.xml" ) +assert pmdXml.exists() +assert !pmdXml.text.contains( "Avoid unused private methods such as 'doSomething(IModuleA)'." ) +assert !pmdXml.text.contains( "Avoid unused private methods such as 'aPrivateMethod(FieldElement)'." ) 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 0e2fcd22..054af566 100644 --- a/src/main/java/org/apache/maven/plugins/pmd/PmdReport.java +++ b/src/main/java/org/apache/maven/plugins/pmd/PmdReport.java @@ -45,7 +45,10 @@ import org.apache.maven.project.MavenProject; import org.apache.maven.project.ProjectBuildingRequest; import org.apache.maven.reporting.MavenReportException; +import org.apache.maven.shared.artifact.filter.resolve.AndFilter; +import org.apache.maven.shared.artifact.filter.resolve.ExclusionsFilter; import org.apache.maven.shared.artifact.filter.resolve.ScopeFilter; +import org.apache.maven.shared.artifact.filter.resolve.TransformableFilter; import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResult; import org.apache.maven.shared.transfer.dependencies.resolve.DependencyResolver; import org.codehaus.plexus.resource.ResourceManager; @@ -721,24 +724,49 @@ private void configureTypeResolution( PMDConfiguration configuration ) throws Ma { List dependencies = new ArrayList<>(); + // collect exclusions for projects within the reactor + // if module a depends on module b and both are in the reactor + // then we don't want to resolve the dependency as an artifact. + List exclusionPatterns = new ArrayList<>(); for ( MavenProject localProject : reactorProjects ) { - // Add the project's target folder first - classpath.addAll( includeTests ? localProject.getTestClasspathElements() - : localProject.getCompileClasspathElements() ); + exclusionPatterns.add( localProject.getGroupId() + ":" + localProject.getArtifactId() ); + } + TransformableFilter filter = new AndFilter( Arrays.asList( + new ExclusionsFilter( exclusionPatterns ), + includeTests ? ScopeFilter.including( "test" ) : ScopeFilter.including( "compile" ) + ) ); + for ( MavenProject localProject : reactorProjects ) + { ProjectBuildingRequest buildingRequest = new DefaultProjectBuildingRequest( session.getProjectBuildingRequest() ); Iterable resolvedDependencies = dependencyResolver.resolveDependencies( - buildingRequest, localProject.getModel(), - includeTests ? ScopeFilter.including( "test" ) : ScopeFilter.including( "compile" ) ); + buildingRequest, localProject.getModel(), filter ); for ( ArtifactResult resolvedArtifact : resolvedDependencies ) { dependencies.add( resolvedArtifact.getArtifact().getFile().toString() ); } + List projectCompileClasspath = includeTests ? localProject.getTestClasspathElements() + : localProject.getCompileClasspathElements(); + // Add the project's target folder first + classpath.addAll( projectCompileClasspath ); + if ( !localProject.isExecutionRoot() ) + { + for ( String path : projectCompileClasspath ) + { + File pathFile = new File( path ); + if ( !pathFile.exists() || pathFile.list().length == 0 ) + { + getLog().warn( "The project " + localProject.getArtifactId() + + " does not seem to be compiled. PMD results might be inaccurate." ); + } + } + } + } // Add the dependencies as last entries diff --git a/src/site/fml/faq.fml b/src/site/fml/faq.fml index e9f80c05..658a1544 100644 --- a/src/site/fml/faq.fml +++ b/src/site/fml/faq.fml @@ -99,5 +99,34 @@ under the License.

+ + + What does the warning "The project xyz does not seem to be compiled. PMD results might be inaccurate." mean? + + +

+ In order to improve PMD's results, type resolution should be used. It is enabled by default + (property typeResolution) and helps to avoid false positive + findings by matching the exact types of method parameters or variables. +

+

+ However, this requires that the project is built first, so that not only the project's dependencies + can be used for type resolution, but also the project's classes as well. +

+

+ When using the property aggregate, this is problematic: With + aggregate=true, PMD is executed at the root of a multi-module project before the individual + modules are built. Then the types of the individual projects are not available, which might lead to + false positive findings e.g. for the rule "UnusedPrivateMethod". + If this might be the case, then the warning "The project xyz does not seem + to be compiled. PMD results might be inaccurate" is issued. +

+

+ In order to use type resolution and aggregate together, maven needs to be execute in two passes: + First pass will compile the projects (e.g. mvn clean package) and the second pass + will execute PMD without clean via the verify phase (e.g. mvn verify). +

+
+
\ No newline at end of file