Skip to content

Commit 6bba200

Browse files
shivasuryaclaude
andauthored
refactor: Remove all type aliases and wrapper functions from callgraph package (#379)
* refactor: Remove all type aliases and wrapper functions from callgraph package Complete cleanup of backward compatibility layer in callgraph package. All external consumers now use proper sub-package imports. **Deleted (26 files):** - Type aliases: types.go, statement.go, taint_summary.go - Wrapper functions: builder.go, patterns.go, registry.go - All other alias/wrapper files (imports.go, callsites.go, cfg.go, etc.) - 10 test files testing private functions **Updated external consumers:** - cmd package (6 files): Use registry.BuildModuleRegistry(), builder.BuildCallGraph() - dsl package (8 files): Use core.CallGraph, core.CallSite - diagnostic package: Use extraction.ParsePythonFile(), cfg.BuildCFG(), taint.AnalyzeIntraProceduralTaint() **Created:** - graph/callgraph/doc.go: Comprehensive package documentation - graph/callgraph/integration.go: Public API (InitializeCallGraph, AnalyzePatterns) **Test updates:** - Updated 10+ test files with correct package imports - Removed test files for internal/private functions All tests passing, build successful, linting clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * fix: Add source and sink code snippets to analyze command output The analyze command was not displaying source and sink code snippets. Updated AnalyzePatterns() to look up call site locations and read code snippets from the source files. Changes: - Look up source/sink locations from CallSites in the call graph - Read code snippets from source files using new getCodeSnippet() helper - Properly convert Line (int) to SourceLine/SinkLine (uint32) Example output now includes: Source: test.vulnerable() calls builtins.input() at /tmp/test_project/test.py:2 2 | user_input = input("Enter: ") 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * test: Add comprehensive tests for integration.go (98% coverage) Added test coverage for callgraph integration functions: - InitializeCallGraph: Tests initialization with various scenarios - AnalyzePatterns: Tests security pattern detection and code snippet population - getCodeSnippet: Tests code snippet extraction from files Coverage improvements: - integration.go: 6.66% → 98.0% - InitializeCallGraph: 88.9% - AnalyzePatterns: 100.0% - getCodeSnippet: 100.0% All tests passing, linting clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> --------- Co-authored-by: Claude <[email protected]>
1 parent 4f1c5a8 commit 6bba200

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+709
-5585
lines changed

sourcecode-parser/cmd/ci.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import (
99
sarif "github.com/owenrumney/go-sarif/v2/sarif"
1010
"github.com/shivasurya/code-pathfinder/sourcecode-parser/dsl"
1111
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph"
12-
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph"
12+
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph/builder"
13+
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph/core"
14+
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph/registry"
1315
"github.com/spf13/cobra"
1416
)
1517

@@ -53,15 +55,15 @@ Examples:
5355

5456
// Build module registry
5557
log.Printf("Building module registry...\n")
56-
registry, err := callgraph.BuildModuleRegistry(projectPath)
58+
moduleRegistry, err := registry.BuildModuleRegistry(projectPath)
5759
if err != nil {
5860
log.Printf("Warning: failed to build module registry: %v\n", err)
59-
registry = callgraph.NewModuleRegistry()
61+
moduleRegistry = core.NewModuleRegistry()
6062
}
6163

6264
// Build callgraph
6365
log.Printf("Building callgraph...\n")
64-
cg, err := callgraph.BuildCallGraph(codeGraph, registry, projectPath)
66+
cg, err := builder.BuildCallGraph(codeGraph, moduleRegistry, projectPath)
6567
if err != nil {
6668
return fmt.Errorf("failed to build callgraph: %w", err)
6769
}

sourcecode-parser/cmd/query.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import (
66

77
"github.com/shivasurya/code-pathfinder/sourcecode-parser/dsl"
88
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph"
9-
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph"
9+
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph/builder"
10+
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph/core"
11+
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph/registry"
1012
"github.com/spf13/cobra"
1113
)
1214

@@ -45,15 +47,15 @@ Examples:
4547

4648
// Build module registry
4749
log.Printf("Building module registry...\n")
48-
registry, err := callgraph.BuildModuleRegistry(projectPath)
50+
moduleRegistry, err := registry.BuildModuleRegistry(projectPath)
4951
if err != nil {
5052
log.Printf("Warning: failed to build module registry: %v\n", err)
51-
registry = callgraph.NewModuleRegistry()
53+
moduleRegistry = core.NewModuleRegistry()
5254
}
5355

5456
// Build callgraph
5557
log.Printf("Building callgraph...\n")
56-
cg, err := callgraph.BuildCallGraph(codeGraph, registry, projectPath)
58+
cg, err := builder.BuildCallGraph(codeGraph, moduleRegistry, projectPath)
5759
if err != nil {
5860
return fmt.Errorf("failed to build callgraph: %w", err)
5961
}

sourcecode-parser/cmd/resolution_report.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@ import (
66

77
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph"
88
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph"
9+
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph/core"
910
"github.com/spf13/cobra"
1011
)
1112

13+
// Note: callgraph.InitializeCallGraph is used from the callgraph root package integration
14+
1215
var resolutionReportCmd = &cobra.Command{
1316
Use: "resolution-report",
1417
Short: "Generate a diagnostic report on call resolution statistics",
@@ -79,7 +82,7 @@ type resolutionStatistics struct {
7982
FailuresByReason map[string]int // Category -> count
8083
PatternCounts map[string]int // Target pattern -> count
8184
FrameworkCounts map[string]int // Framework prefix -> count (for external_framework category)
82-
UnresolvedByFQN map[string]callgraph.CallSite // For detailed inspection
85+
UnresolvedByFQN map[string]core.CallSite // For detailed inspection
8386

8487
// Phase 2: Type inference statistics
8588
TypeInferenceResolved int // Calls resolved via type inference
@@ -100,12 +103,12 @@ type resolutionStatistics struct {
100103
}
101104

102105
// aggregateResolutionStatistics analyzes the call graph and collects statistics.
103-
func aggregateResolutionStatistics(cg *callgraph.CallGraph) *resolutionStatistics {
106+
func aggregateResolutionStatistics(cg *core.CallGraph) *resolutionStatistics {
104107
stats := &resolutionStatistics{
105108
FailuresByReason: make(map[string]int),
106109
PatternCounts: make(map[string]int),
107110
FrameworkCounts: make(map[string]int),
108-
UnresolvedByFQN: make(map[string]callgraph.CallSite),
111+
UnresolvedByFQN: make(map[string]core.CallSite),
109112
TypesBySource: make(map[string]int),
110113
ConfidenceDistribution: make(map[string]int),
111114
StdlibByModule: make(map[string]int),

sourcecode-parser/cmd/resolution_report_test.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package cmd
33
import (
44
"testing"
55

6-
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph"
6+
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph/core"
77
"github.com/stretchr/testify/assert"
88
)
99

@@ -12,31 +12,31 @@ import (
1212

1313
func TestAggregateResolutionStatistics(t *testing.T) {
1414
// Create a mock call graph with various call sites
15-
cg := callgraph.NewCallGraph()
15+
cg := core.NewCallGraph()
1616

1717
// Add resolved call sites
18-
cg.AddCallSite("test.func1", callgraph.CallSite{
18+
cg.AddCallSite("test.func1", core.CallSite{
1919
Target: "print",
2020
Resolved: true,
2121
TargetFQN: "builtins.print",
2222
})
2323

2424
// Add unresolved call sites with different failure reasons
25-
cg.AddCallSite("test.func2", callgraph.CallSite{
25+
cg.AddCallSite("test.func2", core.CallSite{
2626
Target: "models.ForeignKey",
2727
Resolved: false,
2828
TargetFQN: "django.db.models.ForeignKey",
2929
FailureReason: "external_framework",
3030
})
3131

32-
cg.AddCallSite("test.func3", callgraph.CallSite{
32+
cg.AddCallSite("test.func3", core.CallSite{
3333
Target: "Task.objects.filter",
3434
Resolved: false,
3535
TargetFQN: "tasks.models.Task.objects.filter",
3636
FailureReason: "orm_pattern",
3737
})
3838

39-
cg.AddCallSite("test.func4", callgraph.CallSite{
39+
cg.AddCallSite("test.func4", core.CallSite{
4040
Target: "response.json",
4141
Resolved: false,
4242
TargetFQN: "response.json",
@@ -161,26 +161,26 @@ func TestDetermineStdlibType(t *testing.T) {
161161

162162
func TestAggregateResolutionStatistics_WithStdlib(t *testing.T) {
163163
// Create a mock call graph with stdlib call sites
164-
cg := callgraph.NewCallGraph()
164+
cg := core.NewCallGraph()
165165

166166
// Add stdlib resolved via builtin registry
167-
cg.AddCallSite("test.func1", callgraph.CallSite{
167+
cg.AddCallSite("test.func1", core.CallSite{
168168
Target: "getcwd",
169169
Resolved: true,
170170
TargetFQN: "os.getcwd",
171171
TypeSource: "builtin",
172172
})
173173

174174
// Add stdlib resolved via annotation
175-
cg.AddCallSite("test.func2", callgraph.CallSite{
175+
cg.AddCallSite("test.func2", core.CallSite{
176176
Target: "dumps",
177177
Resolved: true,
178178
TargetFQN: "json.dumps",
179179
TypeSource: "stdlib_annotation",
180180
})
181181

182182
// Add stdlib resolved via type inference
183-
cg.AddCallSite("test.func3", callgraph.CallSite{
183+
cg.AddCallSite("test.func3", core.CallSite{
184184
Target: "Path",
185185
Resolved: true,
186186
TargetFQN: "pathlib.Path",
@@ -189,7 +189,7 @@ func TestAggregateResolutionStatistics_WithStdlib(t *testing.T) {
189189
})
190190

191191
// Add non-stdlib resolved call
192-
cg.AddCallSite("test.func4", callgraph.CallSite{
192+
cg.AddCallSite("test.func4", core.CallSite{
193193
Target: "myfunction",
194194
Resolved: true,
195195
TargetFQN: "myproject.utils.myfunction",

sourcecode-parser/cmd/scan.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import (
88

99
"github.com/shivasurya/code-pathfinder/sourcecode-parser/dsl"
1010
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph"
11-
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph"
11+
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph/builder"
12+
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph/core"
13+
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph/registry"
1214
"github.com/spf13/cobra"
1315
)
1416

@@ -52,16 +54,16 @@ Examples:
5254

5355
// Step 2: Build module registry
5456
log.Printf("Building module registry...\n")
55-
registry, err := callgraph.BuildModuleRegistry(projectPath)
57+
moduleRegistry, err := registry.BuildModuleRegistry(projectPath)
5658
if err != nil {
5759
log.Printf("Warning: failed to build module registry: %v\n", err)
5860
// Create empty registry as fallback
59-
registry = callgraph.NewModuleRegistry()
61+
moduleRegistry = core.NewModuleRegistry()
6062
}
6163

6264
// Step 3: Build callgraph
6365
log.Printf("Building callgraph...\n")
64-
cg, err := callgraph.BuildCallGraph(codeGraph, registry, projectPath)
66+
cg, err := builder.BuildCallGraph(codeGraph, moduleRegistry, projectPath)
6567
if err != nil {
6668
return fmt.Errorf("failed to build callgraph: %w", err)
6769
}
@@ -105,7 +107,7 @@ Examples:
105107
},
106108
}
107109

108-
func countTotalCallSites(cg *callgraph.CallGraph) int {
110+
func countTotalCallSites(cg *core.CallGraph) int {
109111
total := 0
110112
for _, sites := range cg.CallSites {
111113
total += len(sites)

sourcecode-parser/cmd/scan_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"testing"
88

99
"github.com/shivasurya/code-pathfinder/sourcecode-parser/dsl"
10-
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph"
10+
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph/core"
1111
"github.com/stretchr/testify/assert"
1212
)
1313

@@ -25,28 +25,28 @@ func createTestRuleScan(id, name, severity, cwe, owasp, description string) dsl.
2525

2626
func TestCountTotalCallSites(t *testing.T) {
2727
t.Run("counts call sites across all functions", func(t *testing.T) {
28-
cg := callgraph.NewCallGraph()
29-
cg.CallSites["func1"] = []callgraph.CallSite{
30-
{Target: "foo", Location: callgraph.Location{Line: 10}},
31-
{Target: "bar", Location: callgraph.Location{Line: 20}},
28+
cg := core.NewCallGraph()
29+
cg.CallSites["func1"] = []core.CallSite{
30+
{Target: "foo", Location: core.Location{Line: 10}},
31+
{Target: "bar", Location: core.Location{Line: 20}},
3232
}
33-
cg.CallSites["func2"] = []callgraph.CallSite{
34-
{Target: "baz", Location: callgraph.Location{Line: 30}},
33+
cg.CallSites["func2"] = []core.CallSite{
34+
{Target: "baz", Location: core.Location{Line: 30}},
3535
}
3636

3737
total := countTotalCallSites(cg)
3838
assert.Equal(t, 3, total)
3939
})
4040

4141
t.Run("returns zero for empty callgraph", func(t *testing.T) {
42-
cg := callgraph.NewCallGraph()
42+
cg := core.NewCallGraph()
4343
total := countTotalCallSites(cg)
4444
assert.Equal(t, 0, total)
4545
})
4646

4747
t.Run("handles function with no call sites", func(t *testing.T) {
48-
cg := callgraph.NewCallGraph()
49-
cg.CallSites["func1"] = []callgraph.CallSite{}
48+
cg := core.NewCallGraph()
49+
cg.CallSites["func1"] = []core.CallSite{}
5050
total := countTotalCallSites(cg)
5151
assert.Equal(t, 0, total)
5252
})

sourcecode-parser/diagnostic/analyzer.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import (
55
"strings"
66

77
sitter "github.com/smacker/go-tree-sitter"
8-
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph"
8+
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph/analysis/taint"
9+
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph/core"
10+
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph/extraction"
911
)
1012

1113
// FunctionTaintResult represents the structured taint analysis result for a single function.
@@ -82,7 +84,7 @@ func AnalyzeSingleFunction(
8284

8385
// Parse function source code
8486
sourceCode := []byte(fn.SourceCode)
85-
tree, err := callgraph.ParsePythonFile(sourceCode)
87+
tree, err := extraction.ParsePythonFile(sourceCode)
8688
if err != nil {
8789
result.AnalysisError = true
8890
result.ErrorMessage = fmt.Sprintf("Parse error: %v", err)
@@ -98,18 +100,18 @@ func AnalyzeSingleFunction(
98100
}
99101

100102
// Extract statements (using existing logic from statement_extraction.go)
101-
statements, err := callgraph.ExtractStatements(fn.FilePath, sourceCode, functionNode)
103+
statements, err := extraction.ExtractStatements(fn.FilePath, sourceCode, functionNode)
102104
if err != nil {
103105
result.AnalysisError = true
104106
result.ErrorMessage = fmt.Sprintf("Statement extraction error: %v", err)
105107
return result, nil
106108
}
107109

108110
// Build def-use chains (using existing logic from statement.go)
109-
defUseChain := callgraph.BuildDefUseChains(statements)
111+
defUseChain := core.BuildDefUseChains(statements)
110112

111113
// Run taint analysis (using existing logic from taint.go)
112-
taintSummary := callgraph.AnalyzeIntraProceduralTaint(
114+
taintSummary := taint.AnalyzeIntraProceduralTaint(
113115
fn.FQN,
114116
statements,
115117
defUseChain,

sourcecode-parser/diagnostic/analyzer_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package diagnostic
33
import (
44
"testing"
55

6-
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph"
6+
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph/extraction"
77
"github.com/stretchr/testify/assert"
88
"github.com/stretchr/testify/require"
99
)
@@ -131,7 +131,7 @@ def function_two():
131131
pass
132132
`)
133133

134-
tree, err := callgraph.ParsePythonFile(sourceCode)
134+
tree, err := extraction.ParsePythonFile(sourceCode)
135135
require.NoError(t, err)
136136
require.NotNil(t, tree)
137137

sourcecode-parser/dsl/call_matcher.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@ package dsl
33
import (
44
"strings"
55

6-
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph"
6+
"github.com/shivasurya/code-pathfinder/sourcecode-parser/graph/callgraph/core"
77
)
88

99
// CallMatcherExecutor executes call_matcher IR against callgraph.
1010
type CallMatcherExecutor struct {
1111
IR *CallMatcherIR
12-
CallGraph *callgraph.CallGraph
12+
CallGraph *core.CallGraph
1313
}
1414

1515
// NewCallMatcherExecutor creates a new executor.
16-
func NewCallMatcherExecutor(ir *CallMatcherIR, cg *callgraph.CallGraph) *CallMatcherExecutor {
16+
func NewCallMatcherExecutor(ir *CallMatcherIR, cg *core.CallGraph) *CallMatcherExecutor {
1717
return &CallMatcherExecutor{
1818
IR: ir,
1919
CallGraph: cg,
@@ -33,8 +33,8 @@ func NewCallMatcherExecutor(ir *CallMatcherIR, cg *callgraph.CallGraph) *CallMat
3333
// C = avg call sites per function (~5-10)
3434
// P = number of patterns (~2-5)
3535
// Typical: 1000 functions * 7 calls * 3 patterns = 21,000 comparisons (fast!)
36-
func (e *CallMatcherExecutor) Execute() []callgraph.CallSite {
37-
matches := []callgraph.CallSite{}
36+
func (e *CallMatcherExecutor) Execute() []core.CallSite {
37+
matches := []core.CallSite{}
3838

3939
// Iterate over all functions' call sites
4040
for _, callSites := range e.CallGraph.CallSites {
@@ -49,7 +49,7 @@ func (e *CallMatcherExecutor) Execute() []callgraph.CallSite {
4949
}
5050

5151
// matchesCallSite checks if a call site matches any pattern.
52-
func (e *CallMatcherExecutor) matchesCallSite(cs *callgraph.CallSite) bool {
52+
func (e *CallMatcherExecutor) matchesCallSite(cs *core.CallSite) bool {
5353
target := cs.Target
5454

5555
for _, pattern := range e.IR.Patterns {
@@ -103,7 +103,7 @@ func (e *CallMatcherExecutor) matchesPattern(target, pattern string) bool {
103103

104104
// CallMatchResult represents a match with additional context.
105105
type CallMatchResult struct {
106-
CallSite callgraph.CallSite
106+
CallSite core.CallSite
107107
MatchedBy string // Which pattern matched
108108
FunctionFQN string // Which function contains this call
109109
SourceFile string // Which file
@@ -132,7 +132,7 @@ func (e *CallMatcherExecutor) ExecuteWithContext() []CallMatchResult {
132132
}
133133

134134
// getMatchedPattern returns which pattern matched (or empty string if no match).
135-
func (e *CallMatcherExecutor) getMatchedPattern(cs *callgraph.CallSite) string {
135+
func (e *CallMatcherExecutor) getMatchedPattern(cs *core.CallSite) string {
136136
for _, pattern := range e.IR.Patterns {
137137
if e.matchesPattern(cs.Target, pattern) {
138138
return pattern

0 commit comments

Comments
 (0)