From 5df963b73b436904577fa53faac1009ba5995076 Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Fri, 24 Apr 2026 21:05:28 +0000 Subject: [PATCH] fix(spotbugs): eliminate 12 SpotBugs findings (RAN-23) Resolves RAN-23. | File | Finding | Fix | |---|---|---| | CodeIqApplication.java:57-58 | DLS_DEAD_LOCAL_STORE (isIndex, isEnrich) | Remove unused locals; only isServe drives profile selection. | | analyzer/Analyzer.java:279 | DLS_DEAD_LOCAL_STORE (fileInventory) | Drop the never-read buildFileInventory call and its now-orphan helper + unused imports. | | analyzer/Analyzer.java:388-389 | DLS_DEAD_LOCAL_STORE (flushed, recoveredEdges) | Drop the locals but keep flush()/flushDeferred() calls for their side effects (provenance stamping, dropped-edge counter). | | cache/AnalysisCache.java:114,151 | CT_CONSTRUCTOR_THROW x2 | Mark class final to neutralize finalizer-subclass attack on partially constructed instance. | | cli/EnrichCommand.java:153-154 | DLS_DEAD_LOCAL_STORE (flushed, recoveredEdges) | Same as Analyzer -- drop locals, keep calls. | | cli/EnrichCommand.java:425 | REC_CATCH_EXCEPTION | Narrow catch(Exception) to catch(IOException \| RuntimeException). | | detector/frontend/ReactComponentDetector.java:113 | UC_USELESS_OBJECT (allDetected) | Delete -- never queried. | | detector/go/GoStructuresDetector.java:142 | UC_USELESS_OBJECT (methodPositions) | Delete -- never read; methodStarts is built from scratch lower down. | | query/TopologyService.java:198 | UC_USELESS_OBJECT (edgeKinds) | Delete the map and its put -- blast-radius never uses it. | Also fixes a pre-existing DE_MIGHT_IGNORE at FileDiscovery.java:167 that SpotBugs only surfaced once the original 12 cleared (empty catch on Files.size() IOException). No changes to spotbugs-exclude.xml. Verification: - mvn spotbugs:check -- BugInstance size is 0 (BUILD SUCCESS). - Unblocks RAN-24 (binding spotbugs:check to mvn verify). Co-Authored-By: Paperclip Co-Authored-By: Claude Opus 4.7 (1M context) --- .../randomcodespace/iq/CodeIqApplication.java | 2 -- .../randomcodespace/iq/analyzer/Analyzer.java | 31 +++++-------------- .../iq/analyzer/FileDiscovery.java | 1 + .../iq/cache/AnalysisCache.java | 2 +- .../randomcodespace/iq/cli/EnrichCommand.java | 12 ++++--- .../frontend/ReactComponentDetector.java | 3 -- .../iq/detector/go/GoStructuresDetector.java | 2 -- .../iq/query/TopologyService.java | 2 -- 8 files changed, 17 insertions(+), 38 deletions(-) diff --git a/src/main/java/io/github/randomcodespace/iq/CodeIqApplication.java b/src/main/java/io/github/randomcodespace/iq/CodeIqApplication.java index 7f0dfa56..dfca1dc2 100644 --- a/src/main/java/io/github/randomcodespace/iq/CodeIqApplication.java +++ b/src/main/java/io/github/randomcodespace/iq/CodeIqApplication.java @@ -54,8 +54,6 @@ public static void main(String[] args) { .findFirst() .orElse(""); boolean isServe = "serve".equalsIgnoreCase(command); - boolean isIndex = "index".equalsIgnoreCase(command); - boolean isEnrich = "enrich".equalsIgnoreCase(command); if (isServe) { app.setAdditionalProfiles("serving"); diff --git a/src/main/java/io/github/randomcodespace/iq/analyzer/Analyzer.java b/src/main/java/io/github/randomcodespace/iq/analyzer/Analyzer.java index 44c46ca6..0f911317 100644 --- a/src/main/java/io/github/randomcodespace/iq/analyzer/Analyzer.java +++ b/src/main/java/io/github/randomcodespace/iq/analyzer/Analyzer.java @@ -15,9 +15,6 @@ import io.github.randomcodespace.iq.detector.DetectorResult; import io.github.randomcodespace.iq.detector.DetectorUtils; import io.github.randomcodespace.iq.grammar.AntlrParserFactory; -import io.github.randomcodespace.iq.intelligence.FileClassification; -import io.github.randomcodespace.iq.intelligence.FileEntry; -import io.github.randomcodespace.iq.intelligence.FileInventory; import io.github.randomcodespace.iq.intelligence.RepositoryIdentity; import io.github.randomcodespace.iq.model.CodeEdge; import io.github.randomcodespace.iq.model.CodeNode; @@ -274,9 +271,8 @@ private AnalysisResult runWithCache(Path root, Integer parallelism, AnalysisCach int totalFiles = files.size(); report.accept("Found " + totalFiles + " files"); - // 1b. Resolve repository identity and build file inventory + // 1b. Resolve repository identity RepositoryIdentity repoIdentity = RepositoryIdentity.resolve(root); - FileInventory fileInventory = buildFileInventory(files, cache); // Compute language breakdown Map languageBreakdown = new HashMap<>(); @@ -384,9 +380,12 @@ private AnalysisResult runWithCache(Path root, Integer parallelism, AnalysisCach report.accept("Linking cross-file relationships..."); builder.runLinkers(linkers); - // Flush and collect deferred edges - GraphBuilder.FlushResult flushed = builder.flush(); - List recoveredEdges = builder.flushDeferred(); + // Flush buffered graph state and retry any deferred edges so the + // side effects (provenance stamping, edge validation, dropped-edge + // counters) still run even though we read the results straight off + // the builder below. + builder.flush(); + builder.flushDeferred(); // 5. Classify layers report.accept("Classifying layers..."); @@ -1619,22 +1618,6 @@ private DetectorResult analyzeFileRegexOnly(DiscoveredFile file, Path repoPath, return DetectorResult.of(allNodes, allEdges); } - /** - * Build a deterministic FileInventory from the list of discovered files. - * Content hashes are reused from {@code cache} when available (no re-read of files). - * Hashes remain null for files not yet present in the cache. - */ - private static FileInventory buildFileInventory(List files, AnalysisCache cache) { - List entries = new ArrayList<>(files.size()); - for (DiscoveredFile f : files) { - String relPath = f.path().toString().replace('\\', '/'); - FileClassification cls = FileEntry.classify(relPath, f.language()); - String contentHash = cache != null ? cache.getHashForPath(relPath) : null; - entries.add(new FileEntry(relPath, f.language(), f.sizeBytes(), contentHash, cls)); - } - return new FileInventory(entries); - } - /** * Get the current git HEAD commit SHA, or null if not a git repo. */ diff --git a/src/main/java/io/github/randomcodespace/iq/analyzer/FileDiscovery.java b/src/main/java/io/github/randomcodespace/iq/analyzer/FileDiscovery.java index 6eff6d1a..5a03e293 100644 --- a/src/main/java/io/github/randomcodespace/iq/analyzer/FileDiscovery.java +++ b/src/main/java/io/github/randomcodespace/iq/analyzer/FileDiscovery.java @@ -165,6 +165,7 @@ private void addGitDiscoveredFile(Path root, List result, String try { size = Files.size(absPath); } catch (IOException e) { + log.debug("Skipping {} -- could not read size", absPath, e); return; } long maxSize = CONFIG_LANGUAGES.contains(language) diff --git a/src/main/java/io/github/randomcodespace/iq/cache/AnalysisCache.java b/src/main/java/io/github/randomcodespace/iq/cache/AnalysisCache.java index e2e5c825..fa15ac01 100644 --- a/src/main/java/io/github/randomcodespace/iq/cache/AnalysisCache.java +++ b/src/main/java/io/github/randomcodespace/iq/cache/AnalysisCache.java @@ -35,7 +35,7 @@ * Uses H2 in embedded mode — pure Java, no JNI, MVCC concurrency, * fully compatible with virtual threads. */ -public class AnalysisCache implements Closeable { +public final class AnalysisCache implements Closeable { private static final Logger log = LoggerFactory.getLogger(AnalysisCache.class); diff --git a/src/main/java/io/github/randomcodespace/iq/cli/EnrichCommand.java b/src/main/java/io/github/randomcodespace/iq/cli/EnrichCommand.java index f768569f..6baf2132 100644 --- a/src/main/java/io/github/randomcodespace/iq/cli/EnrichCommand.java +++ b/src/main/java/io/github/randomcodespace/iq/cli/EnrichCommand.java @@ -22,6 +22,7 @@ import picocli.CommandLine.Command; import picocli.CommandLine.Parameters; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.text.NumberFormat; @@ -149,9 +150,12 @@ private int enrichFromCache(AnalysisCache cache, Path root, NumberFormat nf, Ins builder.addEdges(allEdges); builder.runLinkers(linkers); - // Flush and collect valid edges - GraphBuilder.FlushResult flushed = builder.flush(); - List recoveredEdges = builder.flushDeferred(); + // Flush buffered graph state and retry any deferred edges so the + // side effects (provenance stamping, edge validation, dropped-edge + // counters) still run even though we read enriched nodes/edges + // straight off the builder below. + builder.flush(); + builder.flushDeferred(); List enrichedNodes = new ArrayList<>(builder.getNodes()); List enrichedEdges = new ArrayList<>(builder.getEdges()); @@ -422,7 +426,7 @@ private int enrichFromCache(AnalysisCache cache, Path root, NumberFormat nf, Ins return 0; - } catch (Exception e) { + } catch (IOException | RuntimeException e) { log.error("Enrichment failed", e); CliOutput.error("Enrichment failed: " + e.getMessage()); return 1; diff --git a/src/main/java/io/github/randomcodespace/iq/detector/frontend/ReactComponentDetector.java b/src/main/java/io/github/randomcodespace/iq/detector/frontend/ReactComponentDetector.java index d346483f..7496bb79 100644 --- a/src/main/java/io/github/randomcodespace/iq/detector/frontend/ReactComponentDetector.java +++ b/src/main/java/io/github/randomcodespace/iq/detector/frontend/ReactComponentDetector.java @@ -110,9 +110,6 @@ record ComponentEntry(String name, String sourceId, int matchStart) {} // RENDERS edges: scope JSX tag search to each component's body section. // A component's body is from its match position to the next component's position. - Set allDetected = new HashSet<>(componentNames); - allDetected.addAll(hookNames); - componentEntries.sort(Comparator.comparingInt(ComponentEntry::matchStart)); for (int i = 0; i < componentEntries.size(); i++) { diff --git a/src/main/java/io/github/randomcodespace/iq/detector/go/GoStructuresDetector.java b/src/main/java/io/github/randomcodespace/iq/detector/go/GoStructuresDetector.java index b940cef3..bdf9e8ae 100644 --- a/src/main/java/io/github/randomcodespace/iq/detector/go/GoStructuresDetector.java +++ b/src/main/java/io/github/randomcodespace/iq/detector/go/GoStructuresDetector.java @@ -139,9 +139,7 @@ protected DetectorResult detectWithRegex(DetectorContext ctx) { // Methods Matcher mm = METHOD_RE.matcher(text); - Set methodPositions = new HashSet<>(); while (mm.find()) { - methodPositions.add(mm.start()); String receiver = mm.group(1); String methodName = mm.group(2); boolean exported = Character.isUpperCase(methodName.charAt(0)); diff --git a/src/main/java/io/github/randomcodespace/iq/query/TopologyService.java b/src/main/java/io/github/randomcodespace/iq/query/TopologyService.java index 7f3c6903..d8fd9620 100644 --- a/src/main/java/io/github/randomcodespace/iq/query/TopologyService.java +++ b/src/main/java/io/github/randomcodespace/iq/query/TopologyService.java @@ -195,14 +195,12 @@ public Map serviceDependents(String serviceName, List public Map blastRadius(String nodeId, List nodes, List edges) { // Build adjacency for BFS Map> adjacency = new HashMap<>(); - Map edgeKinds = new HashMap<>(); for (CodeEdge edge : edges) { if (!RUNTIME_EDGES.contains(edge.getKind())) continue; String src = edge.getSourceId(); String tgt = edge.getTarget() != null ? edge.getTarget().getId() : null; if (src == null || tgt == null) continue; adjacency.computeIfAbsent(src, k -> new ArrayList<>()).add(tgt); - edgeKinds.put(src + "->" + tgt, edge.getKind()); } // BFS from nodeId, max depth 5