This is an automated email from the ASF dual-hosted git repository.

sjaranowski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-dependency-analyzer.git


The following commit(s) were added to refs/heads/master by this push:
     new 064fa0e  [MSHARED-1407] Track dependency usage by referencing classes 
(#125)
064fa0e is described below

commit 064fa0e4494b826ea58952cf63be02ce3e18bfe4
Author: Jared Stehler <jsteh...@hubspot.com>
AuthorDate: Mon Jun 3 12:55:09 2024 -0400

    [MSHARED-1407] Track dependency usage by referencing classes (#125)
---
 .../analyzer/DefaultProjectDependencyAnalyzer.java | 47 ++++++-----
 .../dependency/analyzer/DependencyAnalyzer.java    | 17 +++-
 .../dependency/analyzer/DependencyUsage.java       | 92 ++++++++++++++++++++++
 .../analyzer/ProjectDependencyAnalysis.java        | 33 +++++---
 .../analyzer/asm/ASMDependencyAnalyzer.java        |  5 +-
 .../analyzer/asm/DefaultAnnotationVisitor.java     | 11 ++-
 .../analyzer/asm/DefaultClassVisitor.java          | 24 +++---
 .../analyzer/asm/DefaultFieldVisitor.java          |  8 +-
 .../analyzer/asm/DefaultMethodVisitor.java         | 38 +++++----
 .../analyzer/asm/DefaultSignatureVisitor.java      |  8 +-
 .../analyzer/asm/DependencyClassFileVisitor.java   | 26 ++++--
 .../dependency/analyzer/asm/ResultCollector.java   | 47 +++++++----
 .../analyzer/asm/DependencyVisitorTest.java        | 13 +--
 13 files changed, 273 insertions(+), 96 deletions(-)

diff --git 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/DefaultProjectDependencyAnalyzer.java
 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/DefaultProjectDependencyAnalyzer.java
index c792571..b36bd54 100644
--- 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/DefaultProjectDependencyAnalyzer.java
+++ 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/DefaultProjectDependencyAnalyzer.java
@@ -36,6 +36,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
+import java.util.stream.Collectors;
 
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.project.MavenProject;
@@ -68,17 +69,17 @@ public class DefaultProjectDependencyAnalyzer implements 
ProjectDependencyAnalyz
             ClassesPatterns excludedClassesPatterns = new 
ClassesPatterns(excludedClasses);
             Map<Artifact, Set<String>> artifactClassMap = 
buildArtifactClassMap(project, excludedClassesPatterns);
 
-            Set<String> mainDependencyClasses = 
buildMainDependencyClasses(project, excludedClassesPatterns);
-            Set<String> testDependencyClasses = 
buildTestDependencyClasses(project, excludedClassesPatterns);
+            Set<DependencyUsage> mainDependencyClasses = 
buildMainDependencyClasses(project, excludedClassesPatterns);
+            Set<DependencyUsage> testDependencyClasses = 
buildTestDependencyClasses(project, excludedClassesPatterns);
 
-            Set<String> dependencyClasses = new HashSet<>();
+            Set<DependencyUsage> dependencyClasses = new HashSet<>();
             dependencyClasses.addAll(mainDependencyClasses);
             dependencyClasses.addAll(testDependencyClasses);
 
-            Set<String> testOnlyDependencyClasses =
+            Set<DependencyUsage> testOnlyDependencyClasses =
                     buildTestOnlyDependencyClasses(mainDependencyClasses, 
testDependencyClasses);
 
-            Map<Artifact, Set<String>> usedArtifacts = 
buildUsedArtifacts(artifactClassMap, dependencyClasses);
+            Map<Artifact, Set<DependencyUsage>> usedArtifacts = 
buildUsedArtifacts(artifactClassMap, dependencyClasses);
             Set<Artifact> mainUsedArtifacts =
                     buildUsedArtifacts(artifactClassMap, 
mainDependencyClasses).keySet();
 
@@ -90,7 +91,7 @@ public class DefaultProjectDependencyAnalyzer implements 
ProjectDependencyAnalyz
             Set<Artifact> usedDeclaredArtifacts = new 
LinkedHashSet<>(declaredArtifacts);
             usedDeclaredArtifacts.retainAll(usedArtifacts.keySet());
 
-            Map<Artifact, Set<String>> usedUndeclaredArtifactsWithClasses = 
new LinkedHashMap<>(usedArtifacts);
+            Map<Artifact, Set<DependencyUsage>> 
usedUndeclaredArtifactsWithClasses = new LinkedHashMap<>(usedArtifacts);
             Set<Artifact> usedUndeclaredArtifacts =
                     removeAll(usedUndeclaredArtifactsWithClasses.keySet(), 
declaredArtifacts);
             
usedUndeclaredArtifactsWithClasses.keySet().retainAll(usedUndeclaredArtifacts);
@@ -190,29 +191,33 @@ public class DefaultProjectDependencyAnalyzer implements 
ProjectDependencyAnalyz
         return artifactClassMap;
     }
 
-    private static Set<String> buildTestOnlyDependencyClasses(
-            Set<String> mainDependencyClasses, Set<String> 
testDependencyClasses) {
-        Set<String> testOnlyDependencyClasses = new 
HashSet<>(testDependencyClasses);
-        testOnlyDependencyClasses.removeAll(mainDependencyClasses);
+    private static Set<DependencyUsage> buildTestOnlyDependencyClasses(
+            Set<DependencyUsage> mainDependencyClasses, Set<DependencyUsage> 
testDependencyClasses) {
+        Set<DependencyUsage> testOnlyDependencyClasses = new 
HashSet<>(testDependencyClasses);
+        Set<String> mainDepClassNames = mainDependencyClasses.stream()
+                .map(DependencyUsage::getDependencyClass)
+                .collect(Collectors.toSet());
+        testOnlyDependencyClasses.removeIf(u -> 
mainDepClassNames.contains(u.getDependencyClass()));
         return testOnlyDependencyClasses;
     }
 
-    private Set<String> buildMainDependencyClasses(MavenProject project, 
ClassesPatterns excludedClasses)
+    private Set<DependencyUsage> buildMainDependencyClasses(MavenProject 
project, ClassesPatterns excludedClasses)
             throws IOException {
         String outputDirectory = project.getBuild().getOutputDirectory();
         return buildDependencyClasses(outputDirectory, excludedClasses);
     }
 
-    private Set<String> buildTestDependencyClasses(MavenProject project, 
ClassesPatterns excludedClasses)
+    private Set<DependencyUsage> buildTestDependencyClasses(MavenProject 
project, ClassesPatterns excludedClasses)
             throws IOException {
         String testOutputDirectory = 
project.getBuild().getTestOutputDirectory();
         return buildDependencyClasses(testOutputDirectory, excludedClasses);
     }
 
-    private Set<String> buildDependencyClasses(String path, ClassesPatterns 
excludedClasses) throws IOException {
+    private Set<DependencyUsage> buildDependencyClasses(String path, 
ClassesPatterns excludedClasses)
+            throws IOException {
         URL url = new File(path).toURI().toURL();
 
-        return dependencyAnalyzer.analyze(url, excludedClasses);
+        return dependencyAnalyzer.analyzeUsages(url, excludedClasses);
     }
 
     private static Set<Artifact> buildDeclaredArtifacts(MavenProject project) {
@@ -225,20 +230,20 @@ public class DefaultProjectDependencyAnalyzer implements 
ProjectDependencyAnalyz
         return declaredArtifacts;
     }
 
-    private static Map<Artifact, Set<String>> buildUsedArtifacts(
-            Map<Artifact, Set<String>> artifactClassMap, Set<String> 
dependencyClasses) {
-        Map<Artifact, Set<String>> usedArtifacts = new HashMap<>();
+    private static Map<Artifact, Set<DependencyUsage>> buildUsedArtifacts(
+            Map<Artifact, Set<String>> artifactClassMap, Set<DependencyUsage> 
dependencyClasses) {
+        Map<Artifact, Set<DependencyUsage>> usedArtifacts = new HashMap<>();
 
-        for (String className : dependencyClasses) {
-            Artifact artifact = findArtifactForClassName(artifactClassMap, 
className);
+        for (DependencyUsage classUsage : dependencyClasses) {
+            Artifact artifact = findArtifactForClassName(artifactClassMap, 
classUsage.getDependencyClass());
 
             if (artifact != null) {
-                Set<String> classesFromArtifact = usedArtifacts.get(artifact);
+                Set<DependencyUsage> classesFromArtifact = 
usedArtifacts.get(artifact);
                 if (classesFromArtifact == null) {
                     classesFromArtifact = new HashSet<>();
                     usedArtifacts.put(artifact, classesFromArtifact);
                 }
-                classesFromArtifact.add(className);
+                classesFromArtifact.add(classUsage);
             }
         }
 
diff --git 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/DependencyAnalyzer.java
 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/DependencyAnalyzer.java
index 22a6a27..e73bc56 100644
--- 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/DependencyAnalyzer.java
+++ 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/DependencyAnalyzer.java
@@ -21,6 +21,7 @@ package org.apache.maven.shared.dependency.analyzer;
 import java.io.IOException;
 import java.net.URL;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * Gets the set of classes referenced by a library given either as a jar file 
or an exploded directory.
@@ -48,5 +49,19 @@ public interface DependencyAnalyzer {
      * @return the set of class names referenced by the library
      * @throws IOException if an error occurs reading a JAR or .class file
      */
-    Set<String> analyze(URL url, ClassesPatterns excludeClasses) throws 
IOException;
+    default Set<String> analyze(URL url, ClassesPatterns excludeClasses) 
throws IOException {
+        return analyzeUsages(url, excludeClasses).stream()
+                .map(DependencyUsage::getDependencyClass)
+                .collect(Collectors.toSet());
+    }
+
+    /**
+     * <p>analyzeUsages.</p>
+     *
+     * @param url the JAR file or directory to analyze
+     * @return the set of class names referenced by the library, paired with 
the
+     * classes declaring those references.
+     * @throws IOException if an error occurs reading a JAR or .class file
+     */
+    Set<DependencyUsage> analyzeUsages(URL url, ClassesPatterns 
excludeClasses) throws IOException;
 }
diff --git 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/DependencyUsage.java
 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/DependencyUsage.java
new file mode 100644
index 0000000..6b2109d
--- /dev/null
+++ 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/DependencyUsage.java
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+package org.apache.maven.shared.dependency.analyzer;
+
+/**
+ * Usage of a dependency class by a project class.
+ *
+ * @author <a href="mailto:hijo...@gmail.com";>Jonathan Haber</a>
+ */
+public class DependencyUsage {
+
+    private final String dependencyClass;
+
+    private final String usedBy;
+
+    public DependencyUsage(String dependencyClass, String usedBy) {
+        this.dependencyClass = dependencyClass;
+        this.usedBy = usedBy;
+    }
+
+    /**
+     * @return the dependency class used by the project class
+     */
+    public String getDependencyClass() {
+        return dependencyClass;
+    }
+
+    /**
+     * @return the project class using the dependency class
+     */
+    public String getUsedBy() {
+        return usedBy;
+    }
+
+    /*
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode() {
+        int hashCode = dependencyClass.hashCode();
+        hashCode = (hashCode * 37) + usedBy.hashCode();
+
+        return hashCode;
+    }
+
+    /*
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals(Object object) {
+        if (object instanceof DependencyUsage) {
+            DependencyUsage usage = (DependencyUsage) object;
+
+            return getDependencyClass().equals(usage.getDependencyClass())
+                    && getUsedBy().equals(usage.getUsedBy());
+        }
+
+        return false;
+    }
+
+    /*
+     * @see java.lang.Object#toString()
+     */
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+
+        buffer.append("dependencyClass=").append(getDependencyClass());
+        buffer.append(",");
+        buffer.append("usedBy=").append(getUsedBy());
+
+        buffer.insert(0, "[");
+        buffer.insert(0, getClass().getName());
+
+        buffer.append("]");
+
+        return buffer.toString();
+    }
+}
diff --git 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/ProjectDependencyAnalysis.java
 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/ProjectDependencyAnalysis.java
index 1f71550..9e63cff 100644
--- 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/ProjectDependencyAnalysis.java
+++ 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/ProjectDependencyAnalysis.java
@@ -26,6 +26,7 @@ import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import org.apache.maven.artifact.Artifact;
 
@@ -39,7 +40,7 @@ public class ProjectDependencyAnalysis {
 
     private final Set<Artifact> usedDeclaredArtifacts;
 
-    private final Map<Artifact, Set<String>> usedUndeclaredArtifacts;
+    private final Map<Artifact, Set<DependencyUsage>> usedUndeclaredArtifacts;
 
     private final Set<Artifact> unusedDeclaredArtifacts;
 
@@ -49,7 +50,7 @@ public class ProjectDependencyAnalysis {
      * <p>Constructor for ProjectDependencyAnalysis.</p>
      */
     public ProjectDependencyAnalysis() {
-        this(null, (Map<Artifact, Set<String>>) null, null, null);
+        this(null, (Map<Artifact, Set<DependencyUsage>>) null, null, null);
     }
 
     /**
@@ -88,7 +89,7 @@ public class ProjectDependencyAnalysis {
 
     public ProjectDependencyAnalysis(
             Set<Artifact> usedDeclaredArtifacts,
-            Map<Artifact, Set<String>> usedUndeclaredArtifacts,
+            Map<Artifact, Set<DependencyUsage>> usedUndeclaredArtifacts,
             Set<Artifact> unusedDeclaredArtifacts,
             Set<Artifact> testArtifactsWithNonTestScope) {
         this.usedDeclaredArtifacts = safeCopy(usedDeclaredArtifacts);
@@ -121,6 +122,20 @@ public class ProjectDependencyAnalysis {
      * @return artifacts used but not declared
      */
     public Map<Artifact, Set<String>> getUsedUndeclaredArtifactsWithClasses() {
+        Map<Artifact, Set<String>> usedUndeclaredArtifactsWithClasses = new 
HashMap<>();
+
+        for (Map.Entry<Artifact, Set<DependencyUsage>> entry : 
usedUndeclaredArtifacts.entrySet()) {
+            usedUndeclaredArtifactsWithClasses.put(
+                    entry.getKey(),
+                    entry.getValue().stream()
+                            .map(DependencyUsage::getDependencyClass)
+                            .collect(Collectors.toSet()));
+        }
+
+        return usedUndeclaredArtifactsWithClasses;
+    }
+
+    public Map<Artifact, Set<DependencyUsage>> 
getUsedUndeclaredArtifactsWithUsages() {
         return safeCopy(usedUndeclaredArtifacts);
     }
 
@@ -294,29 +309,29 @@ public class ProjectDependencyAnalysis {
         return (set == null) ? Collections.emptySet() : 
Collections.unmodifiableSet(new LinkedHashSet<>(set));
     }
 
-    private static Map<Artifact, Set<String>> safeCopy(Map<Artifact, 
Set<String>> origMap) {
+    private static Map<Artifact, Set<DependencyUsage>> safeCopy(Map<Artifact, 
Set<DependencyUsage>> origMap) {
         if (origMap == null) {
             return Collections.emptyMap();
         }
 
-        Map<Artifact, Set<String>> map = new HashMap<>();
+        Map<Artifact, Set<DependencyUsage>> map = new HashMap<>();
 
-        for (Map.Entry<Artifact, Set<String>> e : origMap.entrySet()) {
+        for (Map.Entry<Artifact, Set<DependencyUsage>> e : origMap.entrySet()) 
{
             map.put(e.getKey(), Collections.unmodifiableSet(new 
LinkedHashSet<>(e.getValue())));
         }
 
         return map;
     }
 
-    private static Map<Artifact, Set<String>> mapWithKeys(Set<Artifact> keys) {
+    private static Map<Artifact, Set<DependencyUsage>> 
mapWithKeys(Set<Artifact> keys) {
         if (keys == null) {
             return Collections.emptyMap();
         }
 
-        Map<Artifact, Set<String>> map = new HashMap<>();
+        Map<Artifact, Set<DependencyUsage>> map = new HashMap<>();
 
         for (Artifact k : keys) {
-            map.put(k, Collections.<String>emptySet());
+            map.put(k, Collections.<DependencyUsage>emptySet());
         }
 
         return map;
diff --git 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/ASMDependencyAnalyzer.java
 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/ASMDependencyAnalyzer.java
index 7b542cd..4e85c7b 100644
--- 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/ASMDependencyAnalyzer.java
+++ 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/ASMDependencyAnalyzer.java
@@ -28,6 +28,7 @@ import java.util.Set;
 import org.apache.maven.shared.dependency.analyzer.ClassFileVisitorUtils;
 import org.apache.maven.shared.dependency.analyzer.ClassesPatterns;
 import org.apache.maven.shared.dependency.analyzer.DependencyAnalyzer;
+import org.apache.maven.shared.dependency.analyzer.DependencyUsage;
 
 /**
  * ASMDependencyAnalyzer
@@ -39,11 +40,11 @@ import 
org.apache.maven.shared.dependency.analyzer.DependencyAnalyzer;
 public class ASMDependencyAnalyzer implements DependencyAnalyzer {
 
     @Override
-    public Set<String> analyze(URL url, ClassesPatterns excludeClasses) throws 
IOException {
+    public Set<DependencyUsage> analyzeUsages(URL url, ClassesPatterns 
excludeClasses) throws IOException {
         DependencyClassFileVisitor visitor = new 
DependencyClassFileVisitor(excludeClasses);
 
         ClassFileVisitorUtils.accept(url, visitor);
 
-        return visitor.getDependencies();
+        return visitor.getDependencyUsages();
     }
 }
diff --git 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultAnnotationVisitor.java
 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultAnnotationVisitor.java
index b579273..562637d 100644
--- 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultAnnotationVisitor.java
+++ 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultAnnotationVisitor.java
@@ -31,34 +31,37 @@ import org.objectweb.asm.Type;
 public class DefaultAnnotationVisitor extends AnnotationVisitor {
     private final ResultCollector resultCollector;
 
+    private final String usedByClass;
+
     /**
      * <p>Constructor for DefaultAnnotationVisitor.</p>
      *
      * @param resultCollector a {@link 
org.apache.maven.shared.dependency.analyzer.asm.ResultCollector} object.
      */
-    public DefaultAnnotationVisitor(ResultCollector resultCollector) {
+    public DefaultAnnotationVisitor(ResultCollector resultCollector, String 
usedByClass) {
         super(Opcodes.ASM9);
         this.resultCollector = resultCollector;
+        this.usedByClass = usedByClass;
     }
 
     /** {@inheritDoc} */
     @Override
     public void visit(final String name, final Object value) {
         if (value instanceof Type) {
-            resultCollector.addType((Type) value);
+            resultCollector.addType(usedByClass, (Type) value);
         }
     }
 
     /** {@inheritDoc} */
     @Override
     public void visitEnum(final String name, final String desc, final String 
value) {
-        resultCollector.addDesc(desc);
+        resultCollector.addDesc(usedByClass, desc);
     }
 
     /** {@inheritDoc} */
     @Override
     public AnnotationVisitor visitAnnotation(final String name, final String 
desc) {
-        resultCollector.addDesc(desc);
+        resultCollector.addDesc(usedByClass, desc);
 
         return this;
     }
diff --git 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultClassVisitor.java
 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultClassVisitor.java
index 2d683e6..fe0291c 100644
--- 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultClassVisitor.java
+++ 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultClassVisitor.java
@@ -44,6 +44,8 @@ public class DefaultClassVisitor extends ClassVisitor {
 
     private final MethodVisitor methodVisitor;
 
+    private final String usedByClass;
+
     /**
      * <p>Constructor for DefaultClassVisitor.</p>
      *
@@ -58,13 +60,15 @@ public class DefaultClassVisitor extends ClassVisitor {
             AnnotationVisitor annotationVisitor,
             FieldVisitor fieldVisitor,
             MethodVisitor methodVisitor,
-            ResultCollector resultCollector) {
+            ResultCollector resultCollector,
+            String usedByClass) {
         super(Opcodes.ASM9);
         this.signatureVisitor = signatureVisitor;
         this.annotationVisitor = annotationVisitor;
         this.fieldVisitor = fieldVisitor;
         this.methodVisitor = methodVisitor;
         this.resultCollector = resultCollector;
+        this.usedByClass = usedByClass;
     }
 
     /**
@@ -86,8 +90,8 @@ public class DefaultClassVisitor extends ClassVisitor {
             final String superName,
             final String[] interfaces) {
         if (signature == null) {
-            resultCollector.addName(superName);
-            resultCollector.addNames(interfaces);
+            resultCollector.addName(usedByClass, superName);
+            resultCollector.addNames(usedByClass, interfaces);
         } else {
             addSignature(signature);
         }
@@ -96,7 +100,7 @@ public class DefaultClassVisitor extends ClassVisitor {
     /** {@inheritDoc} */
     @Override
     public AnnotationVisitor visitAnnotation(final String desc, final boolean 
visible) {
-        resultCollector.addDesc(desc);
+        resultCollector.addDesc(usedByClass, desc);
 
         return annotationVisitor;
     }
@@ -106,13 +110,13 @@ public class DefaultClassVisitor extends ClassVisitor {
     public FieldVisitor visitField(
             final int access, final String name, final String desc, final 
String signature, final Object value) {
         if (signature == null) {
-            resultCollector.addDesc(desc);
+            resultCollector.addDesc(usedByClass, desc);
         } else {
             addTypeSignature(signature);
         }
 
         if (value instanceof Type) {
-            resultCollector.addType((Type) value);
+            resultCollector.addType(usedByClass, (Type) value);
         }
 
         return fieldVisitor;
@@ -132,12 +136,12 @@ public class DefaultClassVisitor extends ClassVisitor {
     public MethodVisitor visitMethod(
             final int access, final String name, final String desc, final 
String signature, final String[] exceptions) {
         if (signature == null) {
-            resultCollector.addMethodDesc(desc);
+            resultCollector.addMethodDesc(usedByClass, desc);
         } else {
             addSignature(signature);
         }
 
-        resultCollector.addNames(exceptions);
+        resultCollector.addNames(usedByClass, exceptions);
 
         return methodVisitor;
     }
@@ -145,13 +149,13 @@ public class DefaultClassVisitor extends ClassVisitor {
     /** {@inheritDoc} */
     @Override
     public void visitNestHost(final String nestHost) {
-        resultCollector.addName(nestHost);
+        resultCollector.addName(usedByClass, nestHost);
     }
 
     /** {@inheritDoc} */
     @Override
     public void visitNestMember(final String nestMember) {
-        resultCollector.addName(nestMember);
+        resultCollector.addName(usedByClass, nestMember);
     }
 
     private void addSignature(final String signature) {
diff --git 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultFieldVisitor.java
 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultFieldVisitor.java
index 6f7e140..2a791b9 100644
--- 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultFieldVisitor.java
+++ 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultFieldVisitor.java
@@ -33,22 +33,26 @@ public class DefaultFieldVisitor extends FieldVisitor {
 
     private final ResultCollector resultCollector;
 
+    private final String usedByClass;
+
     /**
      * <p>Constructor for DefaultFieldVisitor.</p>
      *
      * @param annotationVisitor a {@link org.objectweb.asm.AnnotationVisitor} 
object.
      * @param resultCollector a {@link 
org.apache.maven.shared.dependency.analyzer.asm.ResultCollector} object.
      */
-    public DefaultFieldVisitor(AnnotationVisitor annotationVisitor, 
ResultCollector resultCollector) {
+    public DefaultFieldVisitor(
+            AnnotationVisitor annotationVisitor, ResultCollector 
resultCollector, String usedByClass) {
         super(Opcodes.ASM9);
         this.annotationVisitor = annotationVisitor;
         this.resultCollector = resultCollector;
+        this.usedByClass = usedByClass;
     }
 
     /** {@inheritDoc} */
     @Override
     public AnnotationVisitor visitAnnotation(final String desc, final boolean 
visible) {
-        resultCollector.addDesc(desc);
+        resultCollector.addDesc(usedByClass, desc);
 
         return annotationVisitor;
     }
diff --git 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultMethodVisitor.java
 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultMethodVisitor.java
index d1b8d94..a61bb04 100644
--- 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultMethodVisitor.java
+++ 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultMethodVisitor.java
@@ -43,6 +43,8 @@ public class DefaultMethodVisitor extends MethodVisitor {
 
     private final ResultCollector resultCollector;
 
+    private final String usedByClass;
+
     /**
      * <p>Constructor for DefaultMethodVisitor.</p>
      *
@@ -51,17 +53,21 @@ public class DefaultMethodVisitor extends MethodVisitor {
      * @param resultCollector a {@link 
org.apache.maven.shared.dependency.analyzer.asm.ResultCollector} object.
      */
     public DefaultMethodVisitor(
-            AnnotationVisitor annotationVisitor, SignatureVisitor 
signatureVisitor, ResultCollector resultCollector) {
+            AnnotationVisitor annotationVisitor,
+            SignatureVisitor signatureVisitor,
+            ResultCollector resultCollector,
+            String usedByClass) {
         super(Opcodes.ASM9);
         this.annotationVisitor = annotationVisitor;
         this.signatureVisitor = signatureVisitor;
         this.resultCollector = resultCollector;
+        this.usedByClass = usedByClass;
     }
 
     /** {@inheritDoc} */
     @Override
     public AnnotationVisitor visitAnnotation(final String desc, final boolean 
visible) {
-        resultCollector.addDesc(desc);
+        resultCollector.addDesc(usedByClass, desc);
 
         return annotationVisitor;
     }
@@ -69,7 +75,7 @@ public class DefaultMethodVisitor extends MethodVisitor {
     /** {@inheritDoc} */
     @Override
     public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath 
typePath, String desc, boolean visible) {
-        resultCollector.addDesc(desc);
+        resultCollector.addDesc(usedByClass, desc);
 
         return annotationVisitor;
     }
@@ -77,7 +83,7 @@ public class DefaultMethodVisitor extends MethodVisitor {
     /** {@inheritDoc} */
     @Override
     public AnnotationVisitor visitParameterAnnotation(final int parameter, 
final String desc, final boolean visible) {
-        resultCollector.addDesc(desc);
+        resultCollector.addDesc(usedByClass, desc);
 
         return annotationVisitor;
     }
@@ -86,7 +92,7 @@ public class DefaultMethodVisitor extends MethodVisitor {
     @Override
     public AnnotationVisitor visitLocalVariableAnnotation(
             int typeRef, TypePath typePath, Label[] start, Label[] end, int[] 
index, String desc, boolean visible) {
-        resultCollector.addDesc(desc);
+        resultCollector.addDesc(usedByClass, desc);
 
         return annotationVisitor;
     }
@@ -95,16 +101,16 @@ public class DefaultMethodVisitor extends MethodVisitor {
     @Override
     public void visitTypeInsn(final int opcode, final String desc) {
         if (desc.charAt(0) == '[') {
-            resultCollector.addDesc(desc);
+            resultCollector.addDesc(usedByClass, desc);
         } else {
-            resultCollector.addName(desc);
+            resultCollector.addName(usedByClass, desc);
         }
     }
 
     /** {@inheritDoc} */
     @Override
     public void visitFieldInsn(final int opcode, final String owner, final 
String name, final String desc) {
-        resultCollector.addName(owner);
+        resultCollector.addName(usedByClass, owner);
         /*
          * NOTE: Merely accessing a field does not impose a direct dependency 
on its type. For example, the code line
          * <code>java.lang.Object var = bean.field;</code> does not directly 
depend on the type of the field. A direct
@@ -116,30 +122,32 @@ public class DefaultMethodVisitor extends MethodVisitor {
     /** {@inheritDoc} */
     @Override
     public void visitMethodInsn(int opcode, String owner, String name, String 
desc, boolean itf) {
-        resultCollector.addName(owner);
+        resultCollector.addName(usedByClass, owner);
     }
 
     /** {@inheritDoc} */
     @Override
     public void visitLdcInsn(final Object cst) {
         if (cst instanceof Type) {
-            resultCollector.addType((Type) cst);
+            resultCollector.addType(usedByClass, (Type) cst);
         }
     }
 
     /** {@inheritDoc} */
     @Override
     public void visitMultiANewArrayInsn(final String desc, final int dims) {
-        resultCollector.addDesc(desc);
+        resultCollector.addDesc(usedByClass, desc);
     }
 
     /** {@inheritDoc} */
     @Override
     public void visitTryCatchBlock(final Label start, final Label end, final 
Label handler, final String type) {
-        resultCollector.addName(type);
+        resultCollector.addName(usedByClass, type);
     }
 
-    /** {@inheritDoc} */
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public void visitLocalVariable(
             final String name,
@@ -149,7 +157,7 @@ public class DefaultMethodVisitor extends MethodVisitor {
             final Label end,
             final int index) {
         if (signature == null) {
-            resultCollector.addDesc(desc);
+            resultCollector.addDesc(usedByClass, desc);
         } else {
             addTypeSignature(signature);
         }
@@ -167,6 +175,6 @@ public class DefaultMethodVisitor extends MethodVisitor {
         Arrays.stream(bootstrapMethodArguments)
                 .filter(Type.class::isInstance)
                 .map(Type.class::cast)
-                .forEach(resultCollector::addType);
+                .forEach(t -> resultCollector.addType(usedByClass, t));
     }
 }
diff --git 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultSignatureVisitor.java
 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultSignatureVisitor.java
index d09bca3..60e7dc6 100644
--- 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultSignatureVisitor.java
+++ 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DefaultSignatureVisitor.java
@@ -29,26 +29,28 @@ import org.objectweb.asm.signature.SignatureVisitor;
  */
 public class DefaultSignatureVisitor extends SignatureVisitor {
     private final ResultCollector resultCollector;
+    private final String usedByClass;
 
     /**
      * <p>Constructor for DefaultSignatureVisitor.</p>
      *
      * @param resultCollector a {@link 
org.apache.maven.shared.dependency.analyzer.asm.ResultCollector} object.
      */
-    public DefaultSignatureVisitor(ResultCollector resultCollector) {
+    public DefaultSignatureVisitor(ResultCollector resultCollector, String 
usedByClass) {
         super(Opcodes.ASM9);
         this.resultCollector = resultCollector;
+        this.usedByClass = usedByClass;
     }
 
     /** {@inheritDoc} */
     @Override
     public void visitClassType(final String name) {
-        resultCollector.addName(name);
+        resultCollector.addName(usedByClass, name);
     }
 
     /** {@inheritDoc} */
     @Override
     public void visitInnerClassType(final String name) {
-        resultCollector.addName(name);
+        resultCollector.addName(usedByClass, name);
     }
 }
diff --git 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DependencyClassFileVisitor.java
 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DependencyClassFileVisitor.java
index 34dac5c..3d16943 100644
--- 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DependencyClassFileVisitor.java
+++ 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/DependencyClassFileVisitor.java
@@ -26,6 +26,7 @@ import java.util.Set;
 
 import org.apache.maven.shared.dependency.analyzer.ClassFileVisitor;
 import org.apache.maven.shared.dependency.analyzer.ClassesPatterns;
+import org.apache.maven.shared.dependency.analyzer.DependencyUsage;
 import org.objectweb.asm.AnnotationVisitor;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassVisitor;
@@ -76,15 +77,16 @@ public class DependencyClassFileVisitor implements 
ClassFileVisitor {
 
             final Set<String> constantPoolClassRefs = 
ConstantPoolParser.getConstantPoolClassReferences(byteCode);
             for (String string : constantPoolClassRefs) {
-                resultCollector.addName(string);
+                resultCollector.addName(className, string);
             }
 
-            AnnotationVisitor annotationVisitor = new 
DefaultAnnotationVisitor(resultCollector);
-            SignatureVisitor signatureVisitor = new 
DefaultSignatureVisitor(resultCollector);
-            FieldVisitor fieldVisitor = new 
DefaultFieldVisitor(annotationVisitor, resultCollector);
-            MethodVisitor mv = new DefaultMethodVisitor(annotationVisitor, 
signatureVisitor, resultCollector);
-            ClassVisitor classVisitor =
-                    new DefaultClassVisitor(signatureVisitor, 
annotationVisitor, fieldVisitor, mv, resultCollector);
+            AnnotationVisitor annotationVisitor = new 
DefaultAnnotationVisitor(resultCollector, className);
+            SignatureVisitor signatureVisitor = new 
DefaultSignatureVisitor(resultCollector, className);
+            FieldVisitor fieldVisitor = new 
DefaultFieldVisitor(annotationVisitor, resultCollector, className);
+            MethodVisitor mv =
+                    new DefaultMethodVisitor(annotationVisitor, 
signatureVisitor, resultCollector, className);
+            ClassVisitor classVisitor = new DefaultClassVisitor(
+                    signatureVisitor, annotationVisitor, fieldVisitor, mv, 
resultCollector, className);
 
             reader.accept(classVisitor, 0);
         } catch (IOException exception) {
@@ -116,4 +118,14 @@ public class DependencyClassFileVisitor implements 
ClassFileVisitor {
     public Set<String> getDependencies() {
         return resultCollector.getDependencies();
     }
+
+    /**
+     * <p>getDependencyUsages.</p>
+     *
+     * @return the set of classes referenced by visited class files, paired 
with
+     * classes declaring the references.
+     */
+    public Set<DependencyUsage> getDependencyUsages() {
+        return resultCollector.getDependencyUsages();
+    }
 }
diff --git 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/ResultCollector.java
 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/ResultCollector.java
index ca9e8ee..65e3937 100644
--- 
a/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/ResultCollector.java
+++ 
b/src/main/java/org/apache/maven/shared/dependency/analyzer/asm/ResultCollector.java
@@ -20,7 +20,9 @@ package org.apache.maven.shared.dependency.analyzer.asm;
 
 import java.util.HashSet;
 import java.util.Set;
+import java.util.stream.Collectors;
 
+import org.apache.maven.shared.dependency.analyzer.DependencyUsage;
 import org.objectweb.asm.Type;
 
 /**
@@ -30,7 +32,7 @@ import org.objectweb.asm.Type;
  */
 public class ResultCollector {
 
-    private final Set<String> classes = new HashSet<>();
+    private final Set<DependencyUsage> classUsages = new HashSet<>();
 
     /**
      * <p>getDependencies.</p>
@@ -38,7 +40,18 @@ public class ResultCollector {
      * @return a {@link java.util.Set} object.
      */
     public Set<String> getDependencies() {
-        return classes;
+        return getDependencyUsages().stream()
+                .map(DependencyUsage::getDependencyClass)
+                .collect(Collectors.toSet());
+    }
+
+    /**
+     * <p>getDependencyUsages.</p>
+     *
+     * @return a {@link java.util.Set} object.
+     */
+    public Set<DependencyUsage> getDependencyUsages() {
+        return classUsages;
     }
 
     /**
@@ -46,7 +59,7 @@ public class ResultCollector {
      *
      * @param name a {@link java.lang.String} object.
      */
-    public void addName(String name) {
+    public void addName(final String usedByClass, String name) {
         if (name == null) {
             return;
         }
@@ -65,25 +78,25 @@ public class ResultCollector {
         }
 
         // decode internal representation
-        add(name.replace('/', '.'));
+        add(usedByClass, name.replace('/', '.'));
     }
 
-    void addDesc(final String desc) {
-        addType(Type.getType(desc));
+    void addDesc(final String usedByClass, final String desc) {
+        addType(usedByClass, Type.getType(desc));
     }
 
-    void addType(final Type t) {
+    void addType(final String usedByClass, final Type t) {
         switch (t.getSort()) {
             case Type.ARRAY:
-                addType(t.getElementType());
+                addType(usedByClass, t.getElementType());
                 break;
 
             case Type.METHOD:
-                addMethodDesc(t.getDescriptor());
+                addMethodDesc(usedByClass, t.getDescriptor());
                 break;
 
             case Type.OBJECT:
-                addName(t.getClassName());
+                addName(usedByClass, t.getClassName());
                 break;
             default:
         }
@@ -94,30 +107,30 @@ public class ResultCollector {
      *
      * @param name a {@link java.lang.String} object.
      */
-    public void add(String name) {
+    public void add(final String usedByClass, final String name) {
         // inner classes have equivalent compilation requirement as container 
class
         if (name.indexOf('$') < 0) {
-            classes.add(name);
+            classUsages.add(new DependencyUsage(name, usedByClass));
         }
     }
 
-    void addNames(final String[] names) {
+    void addNames(final String usedByClass, final String[] names) {
         if (names == null) {
             return;
         }
 
         for (String name : names) {
-            addName(name);
+            addName(usedByClass, name);
         }
     }
 
-    void addMethodDesc(final String desc) {
-        addType(Type.getReturnType(desc));
+    void addMethodDesc(final String usedByClass, final String desc) {
+        addType(usedByClass, Type.getReturnType(desc));
 
         Type[] types = Type.getArgumentTypes(desc);
 
         for (Type type : types) {
-            addType(type);
+            addType(usedByClass, type);
         }
     }
 }
diff --git 
a/src/test/java/org/apache/maven/shared/dependency/analyzer/asm/DependencyVisitorTest.java
 
b/src/test/java/org/apache/maven/shared/dependency/analyzer/asm/DependencyVisitorTest.java
index cad3a2a..7d814e7 100644
--- 
a/src/test/java/org/apache/maven/shared/dependency/analyzer/asm/DependencyVisitorTest.java
+++ 
b/src/test/java/org/apache/maven/shared/dependency/analyzer/asm/DependencyVisitorTest.java
@@ -41,13 +41,16 @@ class DependencyVisitorTest {
     private DefaultClassVisitor visitor;
     private MethodVisitor mv;
 
+    private String usedByClass = "com.example.MyClass";
+
     @BeforeEach
     void setUp() {
-        AnnotationVisitor annotationVisitor = new 
DefaultAnnotationVisitor(resultCollector);
-        SignatureVisitor signatureVisitor = new 
DefaultSignatureVisitor(resultCollector);
-        FieldVisitor fieldVisitor = new DefaultFieldVisitor(annotationVisitor, 
resultCollector);
-        mv = new DefaultMethodVisitor(annotationVisitor, signatureVisitor, 
resultCollector);
-        visitor = new DefaultClassVisitor(signatureVisitor, annotationVisitor, 
fieldVisitor, mv, resultCollector);
+        AnnotationVisitor annotationVisitor = new 
DefaultAnnotationVisitor(resultCollector, usedByClass);
+        SignatureVisitor signatureVisitor = new 
DefaultSignatureVisitor(resultCollector, usedByClass);
+        FieldVisitor fieldVisitor = new DefaultFieldVisitor(annotationVisitor, 
resultCollector, usedByClass);
+        mv = new DefaultMethodVisitor(annotationVisitor, signatureVisitor, 
resultCollector, usedByClass);
+        visitor = new DefaultClassVisitor(
+                signatureVisitor, annotationVisitor, fieldVisitor, mv, 
resultCollector, usedByClass);
     }
 
     @Test


Reply via email to