feat: add complexity metrics for Objective-C (#1923) - #2233
Conversation
tree-sitter-objc extends tree-sitter-c: if/else/for/while/switch/case/ logical-operator/conditional-expression node kinds are byte-identical to plain C (confirmed by parsing sample ObjC control flow and inspecting the S-expression), including the same else_clause wrapper (Pattern A). Wires COMPLEXITY_RULES/HALSTEAD_RULES (TS) and lang_rules()/halstead_rules() (native) for 'objc', extending C's rule shape with method_definition (the `-`/`+` method body) in functionNodes and catch_clause (from @try/@catch/@finally) as a branch/nesting node, the same treatment C++'s catch_clause already gets. message_expression/selector_expression are treated as compound Halstead operators, mirroring call_expression. Also fixes a native/WASM divergence this surfaced: the native ObjC extractor's handle_method ran complexity/CFG analysis unconditionally on both method_declaration (an @interface/@protocol signature, which never has a body) and method_definition, producing a spurious trivial complexity entry (cognitive 0, cyclomatic 1) for every interface declaration that duplicated the real method_definition entry under the same dotted name. Gated both on actual body presence and set bodyless accordingly; ported the same explicit bodyless signal to the TS/WASM extractor for defense-in-depth (its hasFuncBody skip logic otherwise relies on an endLine>line heuristic that a multi-line bodyless signature could slip past). Verified native and WASM produce byte-identical `codegraph complexity --health --json` output on a hand-built fixture covering if/else-if/ else, classic and fast-enumeration for loops, switch/case, @try/ @catch/@finally, ternary, and message sends. No README/CLAUDE.md/ROADMAP.md changes needed — none of them enumerate per-language complexity-metric coverage (docs check acknowledged). Refs #1923 Impact: 1 functions changed, 2 affected
Greptile SummaryAdds Objective-C complexity, Halstead, LOC, and maintainability metrics across the native and WASM analysis paths while preventing bodyless method declarations from receiving spurious complexity and CFG results.
Confidence Score: 5/5The PR appears safe to merge, with native and WASM Objective-C metric behavior consistently wired and no actionable defect identified. The mirrored rule sets classify the covered Objective-C constructs consistently, and explicit body detection prevents declaration-only methods from receiving complexity or CFG results. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart LR
Source["Objective-C source"] --> Parse["tree-sitter-objc"]
Parse --> Native["Native Rust extractor"]
Parse --> Wasm["TypeScript/WASM extractor"]
Native --> BodyCheck["Detect compound_statement"]
Wasm --> Bodyless["Set explicit bodyless flag"]
BodyCheck --> Metrics["Complexity + Halstead + LOC + MI"]
BodyCheck --> CFG["CFG"]
Bodyless --> Visitor["Shared analysis visitors"]
Visitor --> Metrics
Metrics --> Definition["Attach results to bodied definitions"]
CFG --> Definition
Reviews (1): Last reviewed commit: "feat: add complexity metrics for Objecti..." | Re-trigger Greptile |
Codegraph Impact Analysis1 functions changed → 4 callers affected across 3 files
|
|
Thanks for the review — 5/5 confidence, no actionable defects, nothing further to address here. |
Summary
Progress on #1923 — adds
objccomplexity/Halstead support (tier 2).tree-sitter-objc extends tree-sitter-c: if/else/for/while/switch/case/logical-operator/conditional-expression node kinds are byte-identical to plain C (confirmed by parsing sample ObjC control flow and inspecting the S-expression), including the same
else_clausewrapper (Pattern A). WiresCOMPLEXITY_RULES/HALSTEAD_RULES(TS) andlang_rules()/halstead_rules()(native) forobjc, extending C's rule shape with:method_definition(the-/+method body) added tofunctionNodesalongsidefunction_definitioncatch_clause(from@try/@catch/@finally) treated as a branch/nesting node, the same treatment C++'scatch_clausealready getsmessage_expression/selector_expressiontreated as compound Halstead operators, mirroringcall_expressionAlso fixes a native/WASM divergence this surfaced: the native ObjC extractor's
handle_methodran complexity/CFG analysis unconditionally on bothmethod_declaration(an@interface/@protocolsignature, which never has a body) andmethod_definition, producing a spurious trivial complexity entry (cognitive 0, cyclomatic 1) for every interface declaration that duplicated the realmethod_definitionentry under the same dotted name. Gated both on actual body presence and setbodylessaccordingly; ported the same explicitbodylesssignal to the TS/WASM extractor for defense-in-depth (itshasFuncBodyskip logic otherwise relies on anendLine > lineheuristic that a multi-line bodyless signature could slip past).Verification
npm run lint— cleannpm test— 267/267 test files, 4335 passed, 30 skipped, 2 todocargo test --lib(crates/codegraph-core) — 707/707 passedcodegraph complexity --health --jsonoutput on a hand-built fixture covering if/else-if/else, classic and fast-enumeration for loops, switch/case,@try/@catch/@finally, ternary, and message sends.Remaining scope on #1923
Tier 1 (c, cpp, kotlin, swift, scala, bash) and CUDA were already done. Dart is blocked on #2182 (grammar structural issue) — do not attempt until that's fixed. Remaining unattempted: zig, haskell, ocaml, ocaml-interface, fsharp, fsharp-signature, gleam, clojure, julia, r, erlang, solidity, groovy, verilog.
Test plan
npm run lintnpm testcargo test --libincrates/codegraph-core