refactor: decompose 5 high-complexity functions (CC reduction) - #236
Conversation
Spec artifacts for issue unbound-force#200 — decompose 5 high-complexity functions to reduce cyclomatic complexity (CC ≤15 target). Targets: writeOneResult (CC 32), runQuality (CC 32), detectASTReceiverMutations (CC 24), runCrap (CC 19), isPointerArgStore (CC 13). Artifacts: proposal.md, specs/decompose-functions.md, design.md, tasks.md (7 groups, 17 subtasks).
Decompose isPointerArgStore (13→3), detectASTReceiverMutations (24→11), runCrap (19→14), runQuality (32→14), writeOneResult (32→4). Extract ~15 helpers, add ~35 unit tests across 3 packages. No behavioral changes — all existing tests pass without modification. Closes unbound-force#200
em-redhat
left a comment
There was a problem hiding this comment.
PR #236 Review: refactor: decompose 5 high-complexity functions (CC reduction)
Walkthrough
| File | Change | Focus |
|---|---|---|
AGENTS.md |
Added recent-changes entry for decomposition | documentation |
cmd/gaze/main.go |
Extracted 8 helpers from runCrap and runQuality |
standard |
cmd/gaze/main_test.go |
~29 new tests for extracted helpers | test-quality |
internal/analysis/export_test.go |
3 exported test wrappers for handler functions | test-quality |
internal/analysis/mutation.go |
Simplified isPointerArgStore, extracted 3 handlers from detectASTReceiverMutations |
standard |
internal/analysis/mutation_test.go |
12 new tests for handlers + pointer arg store | test-quality |
internal/analysis/testdata/src/mutation/mutation.go |
2 new test fixtures | test-quality |
internal/report/report_test.go |
~13 new tests for writeEffectRows and writeVerboseSignals |
test-quality |
internal/report/text.go |
Extracted 4 helpers from writeOneResult (CC 32→4) |
standard |
openspec/changes/decompose-high-complexity-functions/* |
5 OpenSpec artifacts | documentation |
Constitution Alignment
| Principle | Status | Notes |
|---|---|---|
| I. Accuracy | N/A | Pure refactoring, no detection logic changes |
| II. Minimal Assumptions | N/A | No new assumptions introduced |
| III. Actionable Output | N/A | Output formatting preserved exactly |
| IV. Testability | PASS | ~52 new tests for extracted helpers; every helper is independently testable |
Findings
PASS: isPointerArgStore simplification is correct
The removal of UnOp, FieldAddr, and IndexAddr branches from isPointerArgStore is the boldest change in this PR. I verified that tracesToParamVisited already handles all three types recursively in its type switch. The outer function's manual unwrapping was structurally unreachable — tracesToParam(addr, param) at the top of the loop would already walk through any FieldAddr->UnOp->param chain. The two new test cases (SetDirect and NestedFieldAddrChain) confirm the simplified version still catches both direct and nested pointer arg stores.
PASS: detectASTReceiverMutations decomposition preserves semantics
The three extracted handlers (handleReceiverAssignStmt, handleReceiverIncDecStmt, handleReceiverCallExpr) faithfully replicate the inline logic. The return !found change (replacing return true) is correct — when a handler sets found=true, the AST inspection should stop, which is exactly what return false (via !found) achieves.
PASS: writeOneResult decomposition eliminates code duplication
The showClassify and else branches had heavily duplicated row-building and table construction logic. The extraction into writeEffectRows and buildEffectsTable eliminates this duplication. The additional writeTierSummary extraction goes beyond what the design doc specified (D3) but is well-justified by DRY principles (CS-004).
PASS: runCrap and runQuality decompositions
runCrap extracted 3 helpers. runQuality extracted 5 helpers (design D2 specified 2). The additional extractions (loadQualityConfig, setupQualityDeps, handleQualityEmptyResults, writeQualityReport) are well-motivated — each encapsulates a coherent responsibility. The D7 gate ordering (baseline before thresholds) is explicitly preserved in evaluateCrapGates.
PASS: Test quality
~52 new tests across 3 packages. All use standard library assertions (TC-001, TC-002). Test naming follows TestXxx_Description pattern (TC-003). Tests use DI patterns consistent with existing codebase. Tests verify specific expected values, not just err == nil (TC-009).
LOW: writeQualityEmptyResults naming
The function name could be confused with "writing an empty results file." A name like writeQualityNoMappings might be clearer. Non-blocking cosmetic observation.
Issue Alignment
Issue #200 acceptance criteria — all 6 items satisfied:
- ✅ Each function's CC reduced to ≤15
- ✅ Extracted helpers have unit tests (~52 new tests)
- ✅ All existing tests pass without modification
- ✅
go test -race -count=1 -short ./...passes - ✅
golangci-lint runreports zero issues - ✅ CRAPload does not increase
Verdict
APPROVE — Clean, well-tested refactoring that achieves all stated CC reduction targets. The isPointerArgStore simplification is correct (verified against tracesToParamVisited chain walking). No behavioral changes, no API surface changes, no security concerns. All 5 CI checks pass.
Summary
Decomposes 5 high-complexity functions to reduce cyclomatic complexity (CC) and CRAPload, continuing the work from #166. Closes #200.
isPointerArgStoredetectASTReceiverMutationsrunCraprunQualitywriteOneResultApproach:
isPointerArgStore: Removed structurally unreachable branches —tracesToParamalready walks FieldAddr/IndexAddr/UnOp chains internallydetectASTReceiverMutations: Extracted 3 per-node-type handlers (handleReceiverAssignStmt,handleReceiverIncDecStmt,handleReceiverCallExpr)runCrap: ExtractedresolveBaselineAndCompare,writeCrapOutputAndSummary,evaluateCrapGates(D7 gate ordering preserved)runQuality: ExtractedloadQualityConfig,setupQualityDeps,runQualityPerPackage,handleQualityEmptyResults,writeQualityReport,writeQualityEmptyResultswriteOneResult: ExtractedwriteEffectRows,buildEffectsTable,writeTierSummary,writeVerboseSignals~35 new unit tests added. No behavioral changes — all existing tests pass without modification.
How to Test
How to Demo
Pure refactoring — no user-visible behavioural changes. Run gaze crap ./... and gaze quality ./... to confirm identical output. Compare baseline JSON before and after if desired.
Key Files Changed
cmd/gaze/
internal/analysis/
internal/report/
openspec/changes/decompose-high-complexity-functions/
This PR was generated by /uf.finale (AI-assisted).