From 9bcdadcce97826f66f10077ce735eb4027b07bc7 Mon Sep 17 00:00:00 2001 From: Alexandre FILLATRE Date: Mon, 12 Apr 2021 15:10:48 +0200 Subject: [PATCH] Processors should be considered as rightful dependencies (#82) Co-authored-by: Alexandre Fillatre Co-authored-by: cesarsotovalero --- .../DefaultProjectDependencyAnalyzer.java | 69 +++++++++++--- .../java/se/kth/depclean/DepCleanMojoIT.java | 27 +++++- .../DepCleanMojoIT/processor_used/pom.xml | 90 +++++++++++++++++++ .../processor_used/src/main/java/Main.java | 9 ++ 4 files changed, 177 insertions(+), 18 deletions(-) create mode 100644 depclean-maven-plugin/src/test/resources-its/se/kth/depclean/DepCleanMojoIT/processor_used/pom.xml create mode 100644 depclean-maven-plugin/src/test/resources-its/se/kth/depclean/DepCleanMojoIT/processor_used/src/main/java/Main.java diff --git a/depclean-core/src/main/java/se/kth/depclean/core/analysis/DefaultProjectDependencyAnalyzer.java b/depclean-core/src/main/java/se/kth/depclean/core/analysis/DefaultProjectDependencyAnalyzer.java index 9d3ef78b..1548ac67 100644 --- a/depclean-core/src/main/java/se/kth/depclean/core/analysis/DefaultProjectDependencyAnalyzer.java +++ b/depclean-core/src/main/java/se/kth/depclean/core/analysis/DefaultProjectDependencyAnalyzer.java @@ -20,25 +20,30 @@ import java.io.File; import java.io.IOException; import java.net.URL; +import java.util.Arrays; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import lombok.extern.slf4j.Slf4j; import org.apache.maven.artifact.Artifact; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Requirement; +import org.codehaus.plexus.util.xml.Xpp3Dom; import se.kth.depclean.core.analysis.asm.ASMDependencyAnalyzer; import se.kth.depclean.core.analysis.graph.DefaultCallGraph; /** * The principal class that perform the dependency analysis in a Maven project. */ +@Slf4j @Component(role = ProjectDependencyAnalyzer.class) public class DefaultProjectDependencyAnalyzer implements ProjectDependencyAnalyzer { @@ -97,10 +102,12 @@ public ProjectDependencyAnalysis analyze(MavenProject project) throws ProjectDep /* ******************** usage analysis ********************* */ // search for the dependencies used by the project - Set usedArtifacts = collectUsedArtifacts( + collectUsedArtifacts( artifactClassesMap, DefaultCallGraph.referencedClassMembers(projectClasses) ); + Set usedArtifacts = collectUsedArtifactsFromProcessors(project, artifactClassesMap); + /* ******************** results as statically used at the bytecode *********************** */ @@ -122,6 +129,47 @@ public ProjectDependencyAnalysis analyze(MavenProject project) throws ProjectDep } } + /** + * Maven processors are defined like this. + *
+   * {@code
+   *       
+   *         org.bsc.maven
+   *         maven-processor-plugin
+   *         
+   *           
+   *             process
+   *             [...]
+   *             
+   *               
+   *                 XXXProcessor
+   *               
+   *             
+   *           
+   *         
+   *       
+   * }
+   * 
+ * + * @param project the maven project + * @param artifactClassesMap previously built artifacts map + * @return all used artifacts so far + */ + private Set collectUsedArtifactsFromProcessors(MavenProject project, + Map> artifactClassesMap) { + final Xpp3Dom[] processors = Optional.ofNullable(project.getPlugin("org.bsc.maven:maven-processor-plugin")) + .map(plugin -> plugin.getExecutionsAsMap().get("process")) + .map(exec -> (Xpp3Dom) exec.getConfiguration()) + .map(config -> config.getChild("processors")) + .map(Xpp3Dom::getChildren) + .orElse(new Xpp3Dom[0]); + Arrays.stream(processors) + .forEach(processor -> findArtifactForClassName(artifactClassesMap, processor.getValue()) + .ifPresent(artifact -> artifactUsedClassesMap.putIfAbsent(artifact, new HashSet<>())) + ); + return artifactUsedClassesMap.keySet(); + } + /** * Returns a map with the artifacts (dependencies) in a Maven project and their corresponding classes. * @@ -176,28 +224,21 @@ private void buildDependenciesDependencyClasses(MavenProject project) throws IOE private Set collectUsedArtifacts(Map> artifactClassMap, Set referencedClasses) { - Set usedArtifacts = new HashSet<>(); // find for used members in each class in the dependency classes for (String clazz : referencedClasses) { - Artifact artifact = findArtifactForClassName(artifactClassMap, clazz); - if (artifact != null) { - if (!artifactUsedClassesMap.containsKey(artifact)) { - artifactUsedClassesMap.put(artifact, new HashSet<>()); - } - artifactUsedClassesMap.get(artifact).add(clazz); - usedArtifacts.add(artifact); - } + findArtifactForClassName(artifactClassMap, clazz) + .ifPresent(artifact -> artifactUsedClassesMap.putIfAbsent(artifact, new HashSet<>())); } - return usedArtifacts; + return artifactUsedClassesMap.keySet(); } - private Artifact findArtifactForClassName(Map> artifactClassMap, String className) { + private Optional findArtifactForClassName(Map> artifactClassMap, String className) { for (Map.Entry> entry : artifactClassMap.entrySet()) { if (entry.getValue().contains(className)) { - return entry.getKey(); + return Optional.of(entry.getKey()); } } - return null; + return Optional.empty(); } /** diff --git a/depclean-maven-plugin/src/test/java/se/kth/depclean/DepCleanMojoIT.java b/depclean-maven-plugin/src/test/java/se/kth/depclean/DepCleanMojoIT.java index b8370f51..b47b97f2 100644 --- a/depclean-maven-plugin/src/test/java/se/kth/depclean/DepCleanMojoIT.java +++ b/depclean-maven-plugin/src/test/java/se/kth/depclean/DepCleanMojoIT.java @@ -1,13 +1,12 @@ package se.kth.depclean; -import static com.soebes.itf.extension.assertj.MavenITAssertions.assertThat; - -import com.soebes.itf.jupiter.extension.MavenGoal; import com.soebes.itf.jupiter.extension.MavenJupiterExtension; import com.soebes.itf.jupiter.extension.MavenTest; import com.soebes.itf.jupiter.maven.MavenExecutionResult; import org.junit.jupiter.api.DisplayName; +import static com.soebes.itf.extension.assertj.MavenITAssertions.assertThat; + /** * This class executes integration tests against the DepCleanMojo. The projects used for testing are in * src/test/resources-its/se/kth/depclean/DepCleanMojoIT. The results of the DepClean executions for each project are in @@ -19,11 +18,31 @@ public class DepCleanMojoIT { @MavenTest - @MavenGoal("package") @DisplayName("Test that DepClean runs in an empty Maven project") void empty_project(MavenExecutionResult result) { assertThat(result).isFailure(); // should pass } + @MavenTest + @DisplayName("Test that DepClean runs in a Maven project with processors") + void processor_used(MavenExecutionResult result) { + assertThat(result).isSuccessful().out() + .plain().contains( + "-------------------------------------------------------", + " D E P C L E A N A N A L Y S I S R E S U L T S", + "-------------------------------------------------------", + "USED DIRECT DEPENDENCIES [1]: ", + " org.mapstruct:mapstruct-processor:1.4.2.Final:provided (1 MB)", + "USED INHERITED DEPENDENCIES [0]: ", + "USED TRANSITIVE DEPENDENCIES [1]: ", + " com.fasterxml.jackson.core:jackson-core:2.12.2:compile (356 KB)", + "POTENTIALLY UNUSED DIRECT DEPENDENCIES [1]: ", + " com.fasterxml.jackson.core:jackson-databind:2.12.2:compile (1 MB)", + "POTENTIALLY UNUSED INHERITED DEPENDENCIES [0]: ", + "POTENTIALLY UNUSED TRANSITIVE DEPENDENCIES [1]: ", + " com.fasterxml.jackson.core:jackson-annotations:2.12.2:compile (73 KB)" + ); + } + } diff --git a/depclean-maven-plugin/src/test/resources-its/se/kth/depclean/DepCleanMojoIT/processor_used/pom.xml b/depclean-maven-plugin/src/test/resources-its/se/kth/depclean/DepCleanMojoIT/processor_used/pom.xml new file mode 100644 index 00000000..d35f46e1 --- /dev/null +++ b/depclean-maven-plugin/src/test/resources-its/se/kth/depclean/DepCleanMojoIT/processor_used/pom.xml @@ -0,0 +1,90 @@ + + + 4.0.0 + + org.foo.bar + foobar + 1.0.0-SNAPSHOT + jar + foobar + + + UTF-8 + UTF-8 + 11 + 11 + + 1.4.2.Final + + + + + com.fasterxml.jackson.core + jackson-databind + 2.12.2 + + + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + provided + + + + + + com.soebes.itf.jupiter.extension + itf-failure-plugin + 0.9.0 + + + first_very_simple + initialize + + failure + + + + + + org.bsc.maven + maven-processor-plugin + 5.0-jdk8-rc1 + + + process + + process + + generate-sources + + + + org.mapstruct.ap.MappingProcessor + + + + + + + se.kth.castor + depclean-maven-plugin + ${project.version} + + + + depclean + + + + + + + + + + + diff --git a/depclean-maven-plugin/src/test/resources-its/se/kth/depclean/DepCleanMojoIT/processor_used/src/main/java/Main.java b/depclean-maven-plugin/src/test/resources-its/se/kth/depclean/DepCleanMojoIT/processor_used/src/main/java/Main.java new file mode 100644 index 00000000..9105e3c6 --- /dev/null +++ b/depclean-maven-plugin/src/test/resources-its/se/kth/depclean/DepCleanMojoIT/processor_used/src/main/java/Main.java @@ -0,0 +1,9 @@ +// import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.util.Separators; + + +public class Main { + // private static final ObjectMapper converter = new ObjectMapper(); + Separators separators = new Separators(); + int field = 42; +} \ No newline at end of file