Skip to content

Commit e8460e8

Browse files
Add Javadoc for graph construction, cycle analysis, report rendering, and related tests
1 parent 2e476ed commit e8460e8

30 files changed

Lines changed: 267 additions & 0 deletions

‎codebase-graph-builder/src/main/java/org/hjug/graphbuilder/CompositeGraphBuilder.java‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,16 @@ public CodebaseGraphDTO getCodebaseGraphDTO(
123123
return getCodebaseGraphDTO(repositoryPath, repositoryRoot, config);
124124
}
125125

126+
/**
127+
* Combines Java and Kotlin graphs, source mappings, and disharmonies.
128+
*
129+
* <p>Shared edge weights are summed before unattributed vertices are reconciled,
130+
* locations are hydrated, and package-to-class relationships are rebuilt.
131+
*
132+
* @param javaDto the Java analysis result
133+
* @param kotlinDto the Kotlin analysis result
134+
* @return the unified codebase graph
135+
*/
126136
static CodebaseGraphDTO merge(CodebaseGraphDTO javaDto, CodebaseGraphDTO kotlinDto) {
127137
Graph<VertexInfo, DefaultWeightedEdge> mergedClassGraph =
128138
new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
@@ -312,6 +322,10 @@ private static String simpleName(String fqn) {
312322
return lastDot >= 0 ? fqn.substring(lastDot + 1) : fqn;
313323
}
314324

325+
/**
326+
* Redirects a fabricated vertex's edges to its canonical declaration, summing duplicate weights.
327+
* Self-loops introduced by contraction are dropped, and new cross-package edges are recorded.
328+
*/
315329
private static void contractVertex(
316330
Graph<VertexInfo, DefaultWeightedEdge> classGraph,
317331
Graph<VertexInfo, DefaultWeightedEdge> packageGraph,
@@ -372,6 +386,7 @@ private static void contractVertex(
372386
classGraph.removeVertex(fabricatedVertex);
373387
}
374388

389+
/** Adds or increments a package edge when both class endpoints have distinct, nonempty packages. */
375390
private static void addPackageEdgeIfCrossPackage(
376391
Graph<VertexInfo, DefaultWeightedEdge> packageGraph, VertexInfo classSource, VertexInfo classTarget) {
377392
String pkgSource = packageName(classSource.getName());
@@ -400,6 +415,7 @@ private static String packageName(String fqn) {
400415
return lastDot >= 0 ? fqn.substring(0, lastDot) : "";
401416
}
402417

418+
/** Copies source vertices and edges into the target, adding weights for edges already present. */
403419
private static void mergeGraph(
404420
Graph<VertexInfo, DefaultWeightedEdge> source, Graph<VertexInfo, DefaultWeightedEdge> target) {
405421
// Add vertices
@@ -422,6 +438,7 @@ private static void mergeGraph(
422438
}
423439
}
424440

441+
/** Maps a source DTO's package-to-class relationships onto the corresponding merged graph edges. */
425442
private static void mergeClassRelationships(
426443
CodebaseGraphDTO dto,
427444
Graph<VertexInfo, DefaultWeightedEdge> sourceClassGraph,

‎codebase-graph-builder/src/main/java/org/hjug/graphbuilder/GraphDependencyCollector.java‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,26 @@ public class GraphDependencyCollector implements DependencyCollector {
3838
/** Registry of the VertexInfo instances created for each vertex name. */
3939
private final Map<String, VertexInfo> vertexRegistry = new HashMap<>();
4040

41+
/**
42+
* Creates a dependency collector that writes into the supplied graphs.
43+
*
44+
* @param classReferencesGraph the graph receiving class dependencies
45+
* @param packageReferencesGraph the graph receiving cross-package dependencies
46+
*/
4147
public GraphDependencyCollector(
4248
Graph<VertexInfo, DefaultWeightedEdge> classReferencesGraph,
4349
Graph<VertexInfo, DefaultWeightedEdge> packageReferencesGraph) {
4450
this.classReferencesGraph = classReferencesGraph;
4551
this.packageReferencesGraph = packageReferencesGraph;
4652
}
4753

54+
/**
55+
* Adds or increments a class dependency and records its corresponding package relationship.
56+
* Dependencies from a class to itself are ignored.
57+
*
58+
* @param fromClassFqn the fully qualified source class name
59+
* @param toClassFqn the fully qualified target class name
60+
*/
4861
@Override
4962
public void addClassDependency(String fromClassFqn, String toClassFqn) {
5063
if (fromClassFqn.equals(toClassFqn)) {
@@ -78,6 +91,13 @@ public void addClassDependency(String fromClassFqn, String toClassFqn) {
7891
}
7992
}
8093

94+
/**
95+
* Adds or increments the package dependency implied by two class names.
96+
*
97+
* @param fromClassFqn the fully qualified source class name
98+
* @param toClassFqn the fully qualified target class name
99+
* @return the package edge, or {@code null} for equal or empty endpoint packages
100+
*/
81101
@Override
82102
public DefaultWeightedEdge addPackageDependency(String fromClassFqn, String toClassFqn) {
83103
String fromPackageName = getPackageFromFqn(fromClassFqn);
@@ -128,6 +148,12 @@ private VertexInfo getOrCreateVertex(String name) {
128148
return vertexRegistry.computeIfAbsent(name, VertexInfo::forName);
129149
}
130150

151+
/**
152+
* Records the raw source location reported by a visitor for later inspection.
153+
*
154+
* @param classFqn the fully qualified class name
155+
* @param sourceFilePath the visitor-reported source location
156+
*/
131157
@Override
132158
public void recordClassLocation(String classFqn, String sourceFilePath) {
133159
// Capture the location reported during collection; repository-relative
@@ -140,6 +166,11 @@ public void registerPackage(String packageName) {
140166
packagesInCodebase.add(packageName);
141167
}
142168

169+
/**
170+
* Registers a class vertex with its derived parent namespace, even if it has no dependencies.
171+
*
172+
* @param classFqn the fully qualified class name
173+
*/
143174
@Override
144175
public void registerClassVertex(String classFqn) {
145176
classReferencesGraph.addVertex(getOrCreateVertex(classFqn));

‎codebase-graph-builder/src/main/java/org/hjug/graphbuilder/VertexInfo.java‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public class VertexInfo {
3232
private final String parentNamespace;
3333
private String locationOnDisk;
3434

35+
/** Creates a vertex with the supplied identity and parent namespace, leaving its disk location unset. */
3536
private VertexInfo(String name, String parentNamespace) {
3637
this.name = name;
3738
this.parentNamespace = parentNamespace;
@@ -128,6 +129,12 @@ public String getParentNamespace() {
128129
return parentNamespace;
129130
}
130131

132+
/**
133+
* Compares vertex names; parent namespaces and hydrated disk locations do not affect identity.
134+
*
135+
* @param o the object to compare
136+
* @return whether the other object is a vertex with the same name
137+
*/
131138
@Override
132139
public boolean equals(Object o) {
133140
if (this == o) {
@@ -139,11 +146,21 @@ public boolean equals(Object o) {
139146
return name.equals(((VertexInfo) o).name);
140147
}
141148

149+
/**
150+
* Returns a name-based hash that remains stable when the disk location is hydrated.
151+
*
152+
* @return the vertex name's hash code
153+
*/
142154
@Override
143155
public int hashCode() {
144156
return name.hashCode();
145157
}
146158

159+
/**
160+
* Returns the vertex name for graph edge rendering.
161+
*
162+
* @return the fully qualified class name or package name
163+
*/
147164
@Override
148165
public String toString() {
149166
return name;

‎codebase-graph-builder/src/main/java/org/hjug/graphbuilder/VertexInfoHydrator.java‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
*/
2222
public final class VertexInfoHydrator {
2323

24+
/** Prevents instantiation of this utility class. */
2425
private VertexInfoHydrator() {}
2526

2627
/**
@@ -49,6 +50,13 @@ public static void hydrate(
4950
}
5051
}
5152

53+
/**
54+
* Resolves a class source path, falling back to its outer Java class or enclosing Kotlin construct.
55+
*
56+
* @param fqn the fully qualified class name
57+
* @param mapping the repository-relative class-to-source-file mapping
58+
* @return the mapped source path, or {@code null} if neither the class nor its enclosing class is mapped
59+
*/
5260
private static String resolveClassLocation(String fqn, Map<String, String> mapping) {
5361
String direct = mapping.get(fqn);
5462
if (direct != null) {
@@ -135,6 +143,7 @@ private static String directMemberPackageName(String fqn) {
135143
return packageName;
136144
}
137145

146+
/** Returns the directory of the package's selected direct-member source file, or {@code null} if unmapped. */
138147
private static String resolvePackageLocation(String packageName, Map<String, String> packagePathIndex) {
139148
String memberPath = packagePathIndex.get(packageName);
140149
if (memberPath == null) {

‎codebase-graph-builder/src/main/java/org/hjug/graphbuilder/graphbuilder/KotlinSourceFileGraphBuilder.java‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@
3636
@Slf4j
3737
public class KotlinSourceFileGraphBuilder implements SourceFileGraphBuilder {
3838

39+
/**
40+
* Builds dependency graphs and metrics from Kotlin source files, honoring configured test exclusions.
41+
* Recoverable partial parse trees are visited before the resulting graph metadata is finalized.
42+
*
43+
* @param repositoryPath the source directory to scan
44+
* @param repositoryRoot the repository root used to canonicalize source locations
45+
* @param config the parser and source-exclusion settings
46+
* @return the Kotlin codebase graph with hydrated vertex locations
47+
* @throws IOException if source files cannot be read
48+
*/
3949
@Override
4050
public CodebaseGraphDTO buildGraph(String repositoryPath, String repositoryRoot, GraphBuilderConfig config)
4151
throws IOException {

‎codebase-graph-builder/src/main/java/org/hjug/graphbuilder/metrics/GraphMetricsCollector.java‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,24 @@ public class GraphMetricsCollector implements DependencyCollector {
3030
/** Maps callee full-qualified method signature → set of caller class FQNs (CC). */
3131
private final Map<String, Set<String>> calleeToCallerClasses = new HashMap<>();
3232

33+
/**
34+
* Creates a metrics collector backed by the supplied dependency graphs.
35+
*
36+
* @param classGraph the graph receiving class dependencies
37+
* @param packageGraph the graph receiving package dependencies
38+
*/
3339
public GraphMetricsCollector(
3440
Graph<VertexInfo, DefaultWeightedEdge> classGraph, Graph<VertexInfo, DefaultWeightedEdge> packageGraph) {
3541
this.classGraph = classGraph;
3642
this.packageGraph = packageGraph;
3743
}
3844

45+
/**
46+
* Adds or increments a class edge and records the target dependency in the source class metrics.
47+
*
48+
* @param fromClass the fully qualified source class name
49+
* @param toClass the fully qualified target class name
50+
*/
3951
@Override
4052
public void addClassDependency(String fromClass, String toClass) {
4153
VertexInfo fromVertex = VertexInfo.forName(fromClass);
@@ -61,6 +73,13 @@ public void addClassDependency(String fromClass, String toClass) {
6173
getOrCreateClassMetrics(fromClass).addDependency(toClass);
6274
}
6375

76+
/**
77+
* Adds or increments a dependency between the supplied package names.
78+
*
79+
* @param fromPackage the source package name
80+
* @param toPackage the target package name
81+
* @return the newly created or existing package edge
82+
*/
6483
@Override
6584
public DefaultWeightedEdge addPackageDependency(String fromPackage, String toPackage) {
6685
VertexInfo fromPackageVertex = VertexInfo.forName(fromPackage);
@@ -91,6 +110,11 @@ public void recordClassLocation(String classFqn, String sourceFilePath) {
91110
classToSourceFileMapping.put(classFqn, sourceFilePath);
92111
}
93112

113+
/**
114+
* Ensures a package vertex exists even when no dependency edge has been recorded for it.
115+
*
116+
* @param packageName the package to register
117+
*/
94118
@Override
95119
public void registerPackage(String packageName) {
96120
VertexInfo packageVertex = VertexInfo.forName(packageName);
@@ -99,11 +123,21 @@ public void registerPackage(String packageName) {
99123
}
100124
}
101125

126+
/**
127+
* Ensures a class vertex exists independently of its dependency edges.
128+
*
129+
* @param classFqn the fully qualified class name
130+
*/
102131
@Override
103132
public void registerClassVertex(String classFqn) {
104133
classGraph.addVertex(VertexInfo.forName(classFqn));
105134
}
106135

136+
/**
137+
* Returns the names of all vertices currently present in the package graph.
138+
*
139+
* @return a set of package names
140+
*/
107141
public Set<String> getPackagesInCodebase() {
108142
return packageGraph.vertexSet().stream().map(VertexInfo::getName).collect(java.util.stream.Collectors.toSet());
109143
}

‎codebase-graph-builder/src/test/java/org/hjug/graphbuilder/CompositeGraphBuilderJavaOnlyTest.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ void analyzeKotlinSwitchHasBeenRemoved() {
8383
Arrays.stream(methods).map(Method::getName).toArray()));
8484
}
8585

86+
/** Verifies that the default configuration includes Kotlin declarations and their source mappings. */
8687
@DisplayName("Default config parses Kotlin sources unconditionally (.kt entries appear)")
8788
@Test
8889
void defaultConfigParsesKotlinSources() throws IOException {

‎codebase-graph-builder/src/test/java/org/hjug/graphbuilder/CompositeGraphBuilderTest.java‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
class CompositeGraphBuilderTest {
1717

18+
/** Verifies that a mixed source directory produces one graph containing Java and Kotlin dependencies. */
1819
@DisplayName("A directory with both Java and Kotlin source files produces a single graph with cross-language edges")
1920
@Test
2021
void parseMixedSourceDirectoryTest() throws IOException {
@@ -52,6 +53,7 @@ void parseMixedSourceDirectoryTest() throws IOException {
5253
VertexInfo.forName("com.ideacrest.parser.mixedclasses.SharedTarget")));
5354
}
5455

56+
/** Verifies that cross-package Java references resolve to canonical Kotlin vertices and package edges. */
5557
@DisplayName("Cross-package Java-to-Kotlin reference is reconciled to the canonical Kotlin FQN")
5658
@Test
5759
void parseMixedSourceDirectoryCrossPackageTest() throws IOException {

0 commit comments

Comments
 (0)