Skip to content

feat(golang): Implement calls, closures, and control flow statements (PR-06 complete) - #525

Merged
shivasurya merged 4 commits into
mainfrom
shiva/golang-pr06-calls-closures
Feb 15, 2026
Merged

shivasurya merged 4 commits into
mainfrom
shiva/golang-pr06-calls-closures

Conversation

@shivasurya

@shivasurya shivasurya commented Feb 14, 2026 •

Copy link
Copy Markdown
Owner

Summary

Complete implementation of PR-06 (Calls, Closures & Statements), broken down into three focused sub-PRs for easier review. Implements call expressions, function literals, defer/go statements, and control flow statements (return, for, if).

Changes

PR-06a: Call Expressions (#cf466cd)

New Files:

  • graph/golang/calls.go (111 lines)

    • CallInfo struct: FunctionName, ObjectName, Arguments, IsSelector
    • ParseCallExpression: Handles simple calls, method calls, package calls
    • ParseSelectorExpression: Extracts object and field from selector_expression
    • extractArguments: Helper to extract arguments from argument_list
  • graph/golang/calls_test.go (185 lines)

    • 6 test cases for ParseCallExpression (simple, method, package, no args, chained, complex)
    • 3 test cases for ParseSelectorExpression
    • Nil/error handling tests

Modified Files:

  • parser_golang.go

    • Added parseGoCallExpression dispatcher (lines 227-274)
    • Creates Type: "call" or "method_expression" nodes
    • CRITICAL: Uses graph.AddEdge(currentContext, callNode) for parent-child linking
    • Stores ObjectName in Interface field for method calls
  • parser.go

    • Filled call_expression stub (lines 105-108)

PR-06b: Closures, Defer & Go Statements (#3d1b667)

New Files:

  • graph/golang/closures.go (93 lines)

    • ClosureInfo struct: Params, ReturnType, LineNumber, StartByte, EndByte
    • ParseFuncLiteral: Handles func literals with params/returns
    • ParseDeferStatement: Extracts call from defer statement
    • ParseGoStatement: Extracts call from go statement
  • graph/golang/closures_test.go (259 lines)

    • 5 test cases for ParseFuncLiteral (simple, no params, multi params, multi returns, IIFE)
    • 3 test cases for ParseDeferStatement (method, function, with args)
    • 3 test cases for ParseGoStatement (function, method, closure)
    • Nil/error handling tests

Modified Files:

  • parser_golang.go (added lines 277-394)

    • anonCounters map for tracking anonymous function names per parent
    • generateAnonName: Generates $anon_N names scoped to parent context
    • parseGoFuncLiteral: Creates func_literal nodes, returns node as currentContext
    • parseGoDeferStatement: Creates defer_call nodes with edge to parent
    • parseGoGoStatement: Creates go_call nodes with edge to parent
  • helpers.go

    • Fixed ExtractParameters to initialize with empty slices (not nil)
  • parser.go

    • Filled func_literal stub (returns currentContext for body traversal)
    • Filled defer_statement stub
    • Filled go_statement stub

PR-06c: Control Flow Statements (#2067448)

New Files:

  • graph/golang/statements.go (177 lines)

    • ReturnInfo struct: Values, LineNumber, StartByte, EndByte
    • ParseReturnStatement: Handles single/multiple return values
    • ForInfo struct: IsRange, Condition, Init, Update, Left, Right
    • ParseForStatement: Handles C-style, range, while-style, infinite loops
    • IfInfo struct: Condition, LineNumber, StartByte, EndByte
    • ParseIfStatement: Extracts if statement condition
  • graph/golang/statements_test.go (306 lines)

    • 5 test cases for ParseReturnStatement
    • 5 test cases for ParseForStatement
    • 4 test cases for ParseIfStatement
    • Nil/error handling tests

Modified Files:

  • parser_golang.go (added lines 417-556)

    • parseGoReturnStatement: Creates ReturnStmt model nodes
    • parseGoForStatement: Creates ForStmt model nodes
    • parseGoIfStatement: Creates IfStmt model nodes
    • joinStrings: Helper to join string slices with commas
    • Uses GenerateSha256 for statement IDs (NOT GenerateMethodID)
    • Does NOT create edges for statement nodes (Python pattern)
  • parser.go

    • Added Go handler to return_statement case (line 30-32)
    • Added Go handler to for_statement case (line 66-68)
    • Added Go handler to if_statement case (line 59-61)
  • Lint fixes: Added comment periods, refactored to switch statement

Test Results

go build ./...                      # ✅ passes
go vet ./...                        # ✅ passes
golangci-lint run                   # ✅ passes
go test -v ./graph/golang/...      # ✅ all pass, 94.6% coverage
go test ./graph/...                # ✅ no regressions

Coverage Details

  • PR-06a: ParseCallExpression 76.2%, ParseSelectorExpression 100%, extractArguments 100%
  • PR-06b: ParseFuncLiteral 100%, ParseDeferStatement 100%, ParseGoStatement 100%
  • PR-06c: ParseReturnStatement 100%, ParseForStatement 100%, ParseIfStatement 100%

Examples

PR-06a: Call Expressions

Code Node Type Name Interface Arguments
fmt.Println("hello") method_expression Println ["fmt"] [""hello""]
foo(x, y) call foo - ["x", "y"]
obj.Method(a, b) method_expression Method ["obj"] ["a", "b"]
bar() call bar - []

PR-06b: Closures, Defer & Go

Code Node Type Name Params ReturnType
func(x int) int { return x + 1 } func_literal $anon_1 ["x"] "int"
defer f.Close() defer_call Close - -
go handler(conn) go_call handler - -

PR-06c: Control Flow Statements

Code Node Type Values/Condition
return 42 ReturnStmt Values: ["42"]
return 0, nil ReturnStmt Values: ["0", "nil"]
for i := 0; i < 10; i++ {} ForStmt IsRange: false, Condition: "i < 10"
for _, v := range items {} ForStmt IsRange: true, Left: "_, v", Right: "items"
if err != nil {} IfStmt Condition: "err != nil"

Design Decisions

PR-06a: Call Expressions

  1. Edge creation: Uses graph.AddEdge(currentContext, callNode) for parent-child linking (CRITICAL for call graph construction in PR-08)
  2. Node.Interface overloading: Stores ObjectName in Interface field for method/package calls
  3. Empty slice initialization: arguments := []string{} for consistency
  4. IIFE handling: func_literal case deferred to PR-06b

PR-06b: Closures

  1. Anonymous naming: $anon_N scoped to parent function using anonCounters map
  2. func_literal returns node: Becomes currentContext for closure body traversal
  3. defer/go create edges: Uses graph.AddEdge pattern for parent-child linking
  4. Empty slices: ExtractParameters now initializes with []string{} for consistency

PR-06c: Statements

  1. Statement IDs: Uses GenerateSha256 following Python pattern (NOT GenerateMethodID)
  2. No edge creation: Statement nodes don't create edges (Python pattern)
  3. model objects: Creates minimal model.ReturnStmt, model.ForStmt, model.IfStmt wrappers
  4. While-style loops: Stores condition in Init field for consistency
  5. Switch statement: Refactored if-else chain for gocritic lint compliance

Stack

Verification Against PR-06 Doc

PR-06a

✅ CallInfo struct matches spec
✅ ParseCallExpression handles simple/method/package calls
✅ ParseSelectorExpression extracts object and field
✅ graph.AddEdge creates parent-child relationship
✅ Tests cover all call types from doc examples

PR-06b

✅ ClosureInfo struct matches spec
✅ ParseFuncLiteral handles params and return types
✅ ParseDeferStatement/ParseGoStatement extract calls
✅ Anonymous function naming: $anon_N scoped to parent
✅ func_literal returns node for currentContext
✅ defer/go create edges with graph.AddEdge

PR-06c

✅ ReturnInfo/ForInfo/IfInfo structs match spec
✅ ParseReturnStatement handles single/multiple values
✅ ParseForStatement handles C-style, range, while-style, infinite loops
✅ ParseIfStatement extracts condition
✅ Statement nodes use GenerateSha256 (not GenerateMethodID)
✅ Statement nodes don't create edges

🤖 Generated with Claude Code

@safedep

safedep Bot commented Feb 14, 2026 •

Copy link
Copy Markdown

SafeDep Report Summary

Green Malicious Packages Badge Green Vulnerable Packages Badge Green Risky License Badge

No dependency changes detected. Nothing to scan.

This report is generated by SafeDep Github App

@codecov

codecov Bot commented Feb 14, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.20891% with 89 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.82%. Comparing base (31b7631) to head (88ad1e7).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
sast-engine/graph/parser_golang.go 61.45% 66 Missing and 8 partials ⚠️
sast-engine/graph/golang/calls.go 89.13% 4 Missing and 1 partial ⚠️
sast-engine/graph/golang/statements.go 94.36% 3 Missing and 1 partial ⚠️
sast-engine/graph/parser.go 71.42% 2 Missing and 2 partials ⚠️
sast-engine/graph/golang/closures.go 93.75% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #525      +/-   ##
==========================================
- Coverage   83.02%   82.82%   -0.20%     
==========================================
  Files         127      130       +3     
  Lines       14836    15193     +357     
==========================================
+ Hits        12317    12583     +266     
- Misses       2061     2139      +78     
- Partials      458      471      +13     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

shivasurya added a commit that referenced this pull request Feb 14, 2026
Implements closure and concurrency statement parsing as the second part of PR-06 breakdown:

**New Files:**
- graph/golang/closures.go (93 lines)
  - ClosureInfo struct with Params, ReturnType, LineNumber, StartByte, EndByte
  - ParseFuncLiteral: handles func literals with params/returns
  - ParseDeferStatement: extracts call from defer statement
  - ParseGoStatement: extracts call from go statement

- graph/golang/closures_test.go (259 lines)
  - 5 test cases for ParseFuncLiteral (simple, no params, multi params, multi returns, IIFE)
  - 3 test cases for ParseDeferStatement (method, function, with args)
  - 3 test cases for ParseGoStatement (function, method, closure)
  - Nil/error handling tests

**Modified Files:**
- parser_golang.go (added lines 227-394)
  - anonCounters map for tracking anonymous function names per parent
  - generateAnonName: generates $anon_N names scoped to parent context
  - parseGoFuncLiteral: creates func_literal nodes, returns node as currentContext
  - parseGoDeferStatement: creates defer_call nodes with edge to parent
  - parseGoGoStatement: creates go_call nodes with edge to parent

- parser.go
  - Filled func_literal stub (returns currentContext for body traversal)
  - Filled defer_statement stub
  - Filled go_statement stub

- helpers.go
  - Fixed ExtractParameters to initialize with empty slices (not nil)

**Verification:**
- go build ./... passes
- go vet ./... passes
- go test ./graph/golang/... passes with 94.6% coverage
- go test ./graph/... passes (no regressions)

**Test Examples:**
- func(x int) int { return x + 1 } → Type: "func_literal", Name: "$anon_1", Params: ["x"], ReturnType: "int"
- defer f.Close() → Type: "defer_call", Name: "Close", Interface: ["f"]
- go handler(conn) → Type: "go_call", Name: "handler", Arguments: ["conn"]

**Design Decisions:**
1. Anonymous naming: $anon_N scoped to parent function using anonCounters map
2. func_literal returns node: Becomes currentContext for closure body traversal
3. defer/go create edges: Uses graph.AddEdge(currentContext, node) pattern
4. Empty slices: ExtractParameters now initializes with []string{} for consistency

Stacked on: PR-06a (#525)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
shivasurya added a commit that referenced this pull request Feb 14, 2026
Implements control flow statement parsing as the final part of PR-06 breakdown:

**New Files:**
- graph/golang/statements.go (177 lines)
  - ReturnInfo struct with Values, LineNumber, StartByte, EndByte
  - ParseReturnStatement: handles single/multiple return values
  - ForInfo struct with IsRange, Condition, Init, Update, Left, Right fields
  - ParseForStatement: handles C-style, range, while-style, and infinite loops
  - IfInfo struct with Condition, LineNumber, StartByte, EndByte
  - ParseIfStatement: extracts if statement condition

- graph/golang/statements_test.go (306 lines)
  - 5 test cases for ParseReturnStatement (single, multiple, expression, no values, function call)
  - 5 test cases for ParseForStatement (C-style, range with index/value, range with blank, infinite, while-style)
  - 4 test cases for ParseIfStatement (simple, complex condition, function call, with assignment)
  - Nil/error handling tests

**Modified Files:**
- parser_golang.go (added lines 417-556)
  - parseGoReturnStatement: creates ReturnStmt model nodes with model.ReturnStmt
  - parseGoForStatement: creates ForStmt model nodes with model.ForStmt
  - parseGoIfStatement: creates IfStmt model nodes with model.IfStmt
  - joinStrings: helper to join string slices with commas
  - Uses GenerateSha256 for statement IDs (NOT GenerateMethodID)
  - Does NOT create edges for statement nodes (Python pattern)

- parser.go
  - Added Go handler to return_statement case (line 30-32)
  - Added Go handler to for_statement case (line 66-68)
  - Added Go handler to if_statement case (line 59-61)

- Lint fixes (comment periods added to all files, switch statement refactor)

**Verification:**
- go build ./... passes
- go vet ./... passes
- go test ./graph/golang/... passes with 94.6% coverage
- go test ./graph/... passes (no regressions)
- golangci-lint run passes (fixed comment periods, switch statement)

**Test Examples:**
- return 42 → Type: "ReturnStmt", Values: ["42"]
- return 0, nil → Type: "ReturnStmt", Values: ["0", "nil"]
- for i := 0; i < 10; i++ {} → Type: "ForStmt", IsRange: false, Condition: "i < 10"
- for _, v := range items {} → Type: "ForStmt", IsRange: true, Left: "_, v", Right: "items"
- if err != nil { } → Type: "IfStmt", Condition: "err != nil"

**Design Decisions:**
1. Statement IDs: Uses GenerateSha256 following Python pattern (NOT GenerateMethodID)
2. No edge creation: Statement nodes don't create edges (Python pattern)
3. model objects: Creates minimal model.ReturnStmt, model.ForStmt, model.IfStmt wrappers
4. While-style loops: Stores condition in Init field for consistency
5. Switch statement: Refactored if-else chain for better performance

Stacked on: PR-06a (#525), PR-06b

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@shivasurya shivasurya changed the title feat(golang): Add call expression parsing (PR-06a) feat(golang): Implement calls, closures, and control flow statements (PR-06 complete) Feb 14, 2026
@shivasurya
shivasurya force-pushed the shiva/golang-pr06-calls-closures branch from bc3041f to fb3a103 Compare February 14, 2026 21:43

shivasurya commented Feb 15, 2026 •

Copy link
Copy Markdown
Owner Author

Merge activity

  • Feb 15, 4:00 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Feb 15, 4:09 AM UTC: Graphite rebased this pull request as part of a merge.
  • Feb 15, 4:10 AM UTC: @shivasurya merged this pull request with Graphite.

@shivasurya
shivasurya changed the base branch from shiva/golang-pr05-variables to graphite-base/525 February 15, 2026 04:07
@shivasurya
shivasurya changed the base branch from graphite-base/525 to main February 15, 2026 04:08
shivasurya and others added 4 commits February 15, 2026 04:09
Implements call expression parsing as the first part of PR-06 breakdown:

**New Files:**
- graph/golang/calls.go (111 lines)
  - CallInfo struct with FunctionName, ObjectName, Arguments, IsSelector
  - ParseCallExpression: handles simple calls, method calls, package calls
  - ParseSelectorExpression: extracts object and field from selector
  - extractArguments: helper for extracting argument list

- graph/golang/calls_test.go (185 lines)
  - 6 test cases for ParseCallExpression (simple, method, package, no args, chained, complex args)
  - 3 test cases for ParseSelectorExpression
  - Nil/error handling tests

**Modified Files:**
- parser_golang.go
  - parseGoCallExpression dispatcher creates call/method_expression nodes
  - CRITICAL: Uses graph.AddEdge(currentContext, callNode) for parent-child linking
  - Stores ObjectName in Interface field for method calls

- parser.go
  - Filled call_expression stub with parseGoCallExpression call

**Verification:**
- go build ./... passes
- go vet ./... passes
- go test ./graph/golang/... passes with 94.0% coverage
- go test ./graph/... passes (no regressions)
- ParseCallExpression: 76.2% (func_literal case deferred to PR-06b)

**Test Examples:**
- fmt.Println("hello") → Type: "method_expression", Name: "Println", Interface: ["fmt"]
- foo(x, y) → Type: "call", Name: "foo", Arguments: ["x", "y"]
- obj.Method(a) → Type: "method_expression", Name: "Method", Interface: ["obj"]

Stacked on: shiva/golang-pr05-variables

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements closure and concurrency statement parsing as the second part of PR-06 breakdown:

**New Files:**
- graph/golang/closures.go (93 lines)
  - ClosureInfo struct with Params, ReturnType, LineNumber, StartByte, EndByte
  - ParseFuncLiteral: handles func literals with params/returns
  - ParseDeferStatement: extracts call from defer statement
  - ParseGoStatement: extracts call from go statement

- graph/golang/closures_test.go (259 lines)
  - 5 test cases for ParseFuncLiteral (simple, no params, multi params, multi returns, IIFE)
  - 3 test cases for ParseDeferStatement (method, function, with args)
  - 3 test cases for ParseGoStatement (function, method, closure)
  - Nil/error handling tests

**Modified Files:**
- parser_golang.go (added lines 227-394)
  - anonCounters map for tracking anonymous function names per parent
  - generateAnonName: generates $anon_N names scoped to parent context
  - parseGoFuncLiteral: creates func_literal nodes, returns node as currentContext
  - parseGoDeferStatement: creates defer_call nodes with edge to parent
  - parseGoGoStatement: creates go_call nodes with edge to parent

- parser.go
  - Filled func_literal stub (returns currentContext for body traversal)
  - Filled defer_statement stub
  - Filled go_statement stub

- helpers.go
  - Fixed ExtractParameters to initialize with empty slices (not nil)

**Verification:**
- go build ./... passes
- go vet ./... passes
- go test ./graph/golang/... passes with 94.6% coverage
- go test ./graph/... passes (no regressions)

**Test Examples:**
- func(x int) int { return x + 1 } → Type: "func_literal", Name: "$anon_1", Params: ["x"], ReturnType: "int"
- defer f.Close() → Type: "defer_call", Name: "Close", Interface: ["f"]
- go handler(conn) → Type: "go_call", Name: "handler", Arguments: ["conn"]

**Design Decisions:**
1. Anonymous naming: $anon_N scoped to parent function using anonCounters map
2. func_literal returns node: Becomes currentContext for closure body traversal
3. defer/go create edges: Uses graph.AddEdge(currentContext, node) pattern
4. Empty slices: ExtractParameters now initializes with []string{} for consistency

Stacked on: PR-06a (#525)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements control flow statement parsing as the final part of PR-06 breakdown:

**New Files:**
- graph/golang/statements.go (177 lines)
  - ReturnInfo struct with Values, LineNumber, StartByte, EndByte
  - ParseReturnStatement: handles single/multiple return values
  - ForInfo struct with IsRange, Condition, Init, Update, Left, Right fields
  - ParseForStatement: handles C-style, range, while-style, and infinite loops
  - IfInfo struct with Condition, LineNumber, StartByte, EndByte
  - ParseIfStatement: extracts if statement condition

- graph/golang/statements_test.go (306 lines)
  - 5 test cases for ParseReturnStatement (single, multiple, expression, no values, function call)
  - 5 test cases for ParseForStatement (C-style, range with index/value, range with blank, infinite, while-style)
  - 4 test cases for ParseIfStatement (simple, complex condition, function call, with assignment)
  - Nil/error handling tests

**Modified Files:**
- parser_golang.go (added lines 417-556)
  - parseGoReturnStatement: creates ReturnStmt model nodes with model.ReturnStmt
  - parseGoForStatement: creates ForStmt model nodes with model.ForStmt
  - parseGoIfStatement: creates IfStmt model nodes with model.IfStmt
  - joinStrings: helper to join string slices with commas
  - Uses GenerateSha256 for statement IDs (NOT GenerateMethodID)
  - Does NOT create edges for statement nodes (Python pattern)

- parser.go
  - Added Go handler to return_statement case (line 30-32)
  - Added Go handler to for_statement case (line 66-68)
  - Added Go handler to if_statement case (line 59-61)

- Lint fixes (comment periods added to all files, switch statement refactor)

**Verification:**
- go build ./... passes
- go vet ./... passes
- go test ./graph/golang/... passes with 94.6% coverage
- go test ./graph/... passes (no regressions)
- golangci-lint run passes (fixed comment periods, switch statement)

**Test Examples:**
- return 42 → Type: "ReturnStmt", Values: ["42"]
- return 0, nil → Type: "ReturnStmt", Values: ["0", "nil"]
- for i := 0; i < 10; i++ {} → Type: "ForStmt", IsRange: false, Condition: "i < 10"
- for _, v := range items {} → Type: "ForStmt", IsRange: true, Left: "_, v", Right: "items"
- if err != nil { } → Type: "IfStmt", Condition: "err != nil"

**Design Decisions:**
1. Statement IDs: Uses GenerateSha256 following Python pattern (NOT GenerateMethodID)
2. No edge creation: Statement nodes don't create edges (Python pattern)
3. model objects: Creates minimal model.ReturnStmt, model.ForStmt, model.IfStmt wrappers
4. While-style loops: Stores condition in Init field for consistency
5. Switch statement: Refactored if-else chain for better performance

Stacked on: PR-06a (#525), PR-06b

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove unnecessary uint32() conversions in calls.go, closures.go, statements.go
  (StartPoint().Row already returns uint32)
- Preallocate vars slice with capacity in variables.go for better performance
- Fixes all remaining golangci-lint issues (unconvert, prealloc)

Verification:
- golangci-lint run passes (0 issues)
- go test ./graph/golang/... passes
@shivasurya
shivasurya force-pushed the shiva/golang-pr06-calls-closures branch from fb3a103 to 88ad1e7 Compare February 15, 2026 04:09
@github-actions

Copy link
Copy Markdown

Code Pathfinder Security Scan

Pass Critical High Medium Low Info

No security issues detected.

Metric Value
Files Scanned 10
Rules 38

Powered by Code Pathfinder

@shivasurya
shivasurya merged commit 8d5a2ee into main Feb 15, 2026
5 checks passed
@shivasurya
shivasurya deleted the shiva/golang-pr06-calls-closures branch February 15, 2026 04:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant