Skip to content

fix(lua): track complexity for anonymous function-expression assignments - #2264

Merged
carlos-alm merged 1 commit into
mainfrom
fix/issue-2036-lua-anonymous-function-complexity
Aug 4, 2026
Merged

fix(lua): track complexity for anonymous function-expression assignments#2264
carlos-alm merged 1 commit into
mainfrom
fix/issue-2036-lua-anonymous-function-complexity

Conversation

@carlos-alm

Copy link
Copy Markdown
Contributor

Summary

  • Lua's M.foo = function(...) end module-table idiom and local f = function() end assign an anonymous function_definition node via a plain assignment_statement. Neither engine's extractor turned this into a Definition, and neither engine's complexity function-node list recognized function_definition as a function scope — so these functions silently got zero complexity/Halstead data.
  • Added Definition-creation for identifier/dotted anonymous-function assignments in both extractors (crates/codegraph-core/src/extractors/lua.rs, src/extractors/lua.ts), mirroring the existing named function_declaration handling (plain identifier → kind function; dotted dot_index_expression → kind method).
  • Added function_definition alongside function_declaration to LUA_RULES.function_nodes (native) and complexityLua.functionNodes (WASM), so nested anonymous functions (e.g. a callback literal passed as an argument) get correct scope/nesting attribution too — mirroring how JS already lists arrow_function/function_expression.

Verification

Built the issue's own repro (local M = {}; M.foo = function(x) if x then return 1 else return 2 end end + local f = function(x) return x + 1 end) through the full buildGraph pipeline with both engines. Both now produce identical, real complexity:

  • M.foo (method): cyclomatic=2, cognitive=2, maxNesting=1
  • f (function): cyclomatic=1, cognitive=0

Closes #2036

Test plan

  • cargo test -p codegraph-core --lib — 748 passed, including 3 new tests covering the module-table idiom, local anonymous assignment, and nested-callback scoping
  • npx vitest run tests/parsers/lua.test.ts — 26 passed, including 3 new extractor tests
  • npx vitest run tests/integration/issue-2036-lua-anonymous-function-complexity.test.ts — 4 passed (WASM + native dual-engine parity)
  • npm test — 273 files, 4422 tests passed
  • npm run lint — clean
  • codegraph diff-impact --staged -T — reviewed, scoped to the two new/changed functions

Lua's M.foo = function(...) end module-table idiom and local f =
function() end assign an anonymous function_definition node via a plain
assignment_statement, which neither engine's extractor turned into a
Definition, nor did the complexity function-node lists recognize
function_definition as a function scope. Both silently got zero
complexity/Halstead data.

Add Definition-creation for identifier/dotted anonymous-function
assignments in both extractors (mirroring the named function_declaration
path), and add function_definition to LUA_RULES.function_nodes /
complexityLua.functionNodes so nested anonymous functions get correct
scope and nesting attribution in both engines.

Closes #2036

Impact: 2 functions changed, 3 affected
@greptile-apps

greptile-apps Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds Lua Definition extraction and complexity scoping for anonymous function-expression assignments in both native and WASM engines.

  • Recognizes identifier and dotted assignment targets as functions or methods.
  • Adds function_definition to Lua complexity function-node rules.
  • Adds parser and dual-engine integration coverage for the new behavior.

Confidence Score: 4/5

The PR is not yet safe to merge because same-line anonymous-function assignments can still persist another function's complexity, Halstead, and CFG metrics.

The new WASM Definitions use the RHS start line, while analysis results are grouped by that line and unnamed same-line function expressions fall back to the first candidate, so the previously reported incorrect metric attribution remains reachable.

Files Needing Attention: src/extractors/lua.ts and src/ast-analysis/apply-results.ts

Important Files Changed

Filename Overview
crates/codegraph-core/src/ast_analysis/complexity.rs Adds anonymous Lua function expressions as native complexity scopes.
crates/codegraph-core/src/extractors/lua.rs Creates native Definitions and directly computes metrics and CFG for identifier or dotted anonymous-function assignments.
src/ast-analysis/rules/b3.ts Adds anonymous Lua function expressions to WASM complexity scope detection.
src/extractors/lua.ts Creates WASM-path Definitions for anonymous-function assignments, but the previously reported same-line result-matching collision remains.
tests/integration/issue-2036-lua-anonymous-function-complexity.test.ts Verifies native/WASM parity for ordinary anonymous assignments but does not cover distinct same-line functions.
tests/parsers/lua.test.ts Covers Definition extraction for module-table, local, and nested anonymous-function assignments.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Lua["Lua assignment"] --> Parse["Parse function_definition"]
  Parse --> Extract["Create named Definition from LHS"]
  Parse --> Analyze["Analyze RHS complexity and CFG"]
  Extract --> Merge["Merge analysis onto Definition"]
  Analyze --> Merge
  Merge --> Persist["Persist graph metrics"]
Loading

Reviews (2): Last reviewed commit: "fix(lua): track complexity for anonymous..." | Re-trigger Greptile

Comment thread src/extractors/lua.ts
ctx.definitions.push({
name,
kind,
line: nodeStartLine(rhs),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Same-line metrics collide

When multiple assigned anonymous functions begin on the same line, both Definitions use that line while their anonymous analysis nodes provide no assignment name for disambiguation, so result matching selects the first candidate for each Definition and persists duplicated complexity, Halstead, and CFG metrics instead of each function's own results.

Knowledge Base Used: AST Extraction

Fix in Claude Code

@carlos-alm

Copy link
Copy Markdown
Contributor Author

Confirmed and investigated — this is a real gap, but it's pre-existing shared infrastructure, not something this PR introduces. matchResultToDef in src/ast-analysis/apply-results.ts disambiguates same-line candidates via funcNode.childForFieldName('name'), which is always null for any anonymous function node (JS arrow/function expressions included), falling back to candidates[0].

I reproduced the identical failure mode with plain JS, no Lua involved:

const a = (x) => {
  if (x) { return 1; }
  return 0;
}, b = (x) => {
  return 2;
};

b's Definition gets a's complexity (cyclomatic 2/cognitive 1 instead of the correct 1/0) today, on main, unrelated to this PR — handleVarFnAssignment sets Definition.line from the enclosing statement, not each arrow function's own line, so b's line (1) collides with a's real result.

Filed #2265 with the repro and a suggested column-aware fix, scoped as its own PR since it touches the shared matching path used by every language (not just Lua) and deserves focused review rather than scope-creeping this fix. This PR's own scope — the issue's exact repro (M.foo and f on separate lines) — is unaffected and verified with identical dual-engine numbers.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Codegraph Impact Analysis

2 functions changed5 callers affected across 3 files

  • handleLuaAssignmentStatement in src/extractors/lua.ts:228 (4 transitive callers)
  • handleLuaFunctionExprAssignment in src/extractors/lua.ts:280 (3 transitive callers)

@carlos-alm

Copy link
Copy Markdown
Contributor Author

@greptileai

@carlos-alm
carlos-alm merged commit 403c1c2 into main Aug 4, 2026
37 of 39 checks passed
@carlos-alm
carlos-alm deleted the fix/issue-2036-lua-anonymous-function-complexity branch August 4, 2026 06:33
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 4, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

follow-up: Lua anonymous function expressions (local f = function() end) not tracked in complexity metrics

1 participant