fix(lua): track complexity for anonymous function-expression assignments - #2264
Conversation
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 SummaryThe PR adds Lua Definition extraction and complexity scoping for anonymous function-expression assignments in both native and WASM engines.
Confidence Score: 4/5The 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
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"]
Reviews (2): Last reviewed commit: "fix(lua): track complexity for anonymous..." | Re-trigger Greptile |
| ctx.definitions.push({ | ||
| name, | ||
| kind, | ||
| line: nodeStartLine(rhs), |
There was a problem hiding this comment.
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
|
Confirmed and investigated — this is a real gap, but it's pre-existing shared infrastructure, not something this PR introduces. 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;
};
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 ( |
Codegraph Impact Analysis2 functions changed → 5 callers affected across 3 files
|
Summary
M.foo = function(...) endmodule-table idiom andlocal f = function() endassign an anonymousfunction_definitionnode via a plainassignment_statement. Neither engine's extractor turned this into aDefinition, and neither engine's complexity function-node list recognizedfunction_definitionas a function scope — so these functions silently got zero complexity/Halstead data.crates/codegraph-core/src/extractors/lua.rs,src/extractors/lua.ts), mirroring the existing namedfunction_declarationhandling (plain identifier → kindfunction; dotteddot_index_expression→ kindmethod).function_definitionalongsidefunction_declarationtoLUA_RULES.function_nodes(native) andcomplexityLua.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 listsarrow_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 fullbuildGraphpipeline with both engines. Both now produce identical, real complexity:M.foo(method): cyclomatic=2, cognitive=2, maxNesting=1f(function): cyclomatic=1, cognitive=0Closes #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 scopingnpx vitest run tests/parsers/lua.test.ts— 26 passed, including 3 new extractor testsnpx 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 passednpm run lint— cleancodegraph diff-impact --staged -T— reviewed, scoped to the two new/changed functions