FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

refactor: replace CFG processStatement switch with handler-table dispatch (TS + Rust) by carlos-alm · Pull Request #1590 · optave/ops-codegraph-tool · GitHub

refactor: replace CFG processStatement switch with handler-table dispatch (TS + Rust) - #1590

Merged
carlos-alm merged 5 commits into
mainfrom
refactor/titan-cfg-handler-table
Jun 17, 2026
Merged

refactor: replace CFG processStatement switch with handler-table dispatch (TS + Rust)#1590
carlos-alm merged 5 commits into
mainfrom
refactor/titan-cfg-handler-table

Conversation

Copy link
Copy Markdown
Contributor

Summary

  • Replace the 14-function switch statement in src/ast-analysis/visitors/cfg-visitor.ts::processStatement with a handler-table dispatch pattern — breaks the cyclomatic complexity spike and removes the 14-arm switch
  • Mirror the same handler-table pattern for Rust CFG in crates/codegraph-core/src/ast_analysis/cfg.rs
  • Decompose dataflow.rs and csharp.rs complexity in the same Rust commit

Titan Audit Context

  • Phase: decomposition (Pillar I Rule 1: cognitive complexity)
  • Domain: ast-analysis (TS + Rust)
  • Commits: 2
  • Depends on: none

Changes

  • src/ast-analysis/visitors/cfg-visitor.ts — processStatement cyc: 23→5; handler table with 14 entries
  • src/ast-analysis/engine.ts — minor supporting changes
  • crates/codegraph-core/src/ast_analysis/cfg.rs — handler-table pattern; 14-fn cycle broken
  • crates/codegraph-core/src/ast_analysis/dataflow.rs — decomposed
  • crates/codegraph-core/src/extractors/csharp.rs — match_csharp_type_map cog 82→extracted helpers

Metrics Impact

  • processStatement (TS): cog reduced 23→5, all FAIL thresholds cleared
  • processStatement (Rust): 14-function cyclomatic cycle broken
  • allNativeDataComplete cyc: 24→12
  • fileNeedsWasmTree cyc: 23→11

Test plan

  • CI passes (lint + build + tests)
  • codegraph check --cycles passes (no new cycles)
  • No new functions above complexity FAIL thresholds

…complexity

docs check acknowledged — pure internal Rust refactor, no API/language/CLI changes

greptile-apps Bot commented Jun 17, 2026
edited
Loading

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR is a pure complexity-decomposition refactor across the TypeScript CFG visitor and three Rust modules — no new features or behavioral changes. The cyclomatic reduction targets (processStatement 23→5, allNativeDataComplete 24→12, fileNeedsWasmTree 23→11, match_csharp_type_map cog 82→helpers) are all achieved cleanly.

  • cfg-visitor.ts: Replaces the 14-arm if-chain with a two-tier Map + 4-entry fallback dispatch table; the processLabeled forward-reference pattern correctly defers resolution until after processStatement is defined, so mutual recursion through the closure is safe.
  • engine.ts: Extracts four fileNeedsWasm* predicates shared between fileNeedsWasmTree and allNativeDataComplete; the debug paths in allNativeDataComplete now use a secondary .find() to recover the offending function name, preserving per-function granularity.
  • cfg.rs / dataflow.rs / csharp.rs: Large methods are split into focused helpers with doc-comments; all logic is a faithful lift-and-extract of the original branches.

Confidence Score: 5/5

Safe to merge — all changes are mechanical decompositions of existing logic with no behavioral differences.

Every extracted helper is a direct lift of the original code path: the Rust helpers preserve identical edge-wiring, the TS dispatch table builds once per visitor and correctly handles the processLabeled forward-reference through a closure, and the engine predicates are shared faithfully between fileNeedsWasmTree and allNativeDataComplete. No logic has been dropped or reordered in a way that could alter CFG construction or dataflow output.

No files require special attention.

Important Files Changed

Filename Overview
src/ast-analysis/visitors/cfg-visitor.ts Replaces the 14-arm if-chain in processStatement with a two-tier dispatch (Map for O(1) single-type lookups + 4-entry fallback array for multi-predicate matchers like isIfNode/isForNode); buildStatementProcessors builds the table once per createCfgVisitor call and uses a well-handled forward reference for the mutually-recursive processLabeled closure.
src/ast-analysis/engine.ts Extracts four fileNeedsWasm* predicates reused by both fileNeedsWasmTree and allNativeDataComplete; allNativeDataComplete now recovers the offending function name via a separate .find() call, preserving debug granularity.
crates/codegraph-core/src/ast_analysis/cfg.rs Decomposes the large process_if_depth, process_switch, and process_try_catch methods into focused helpers; logic is preserved faithfully across all 12 extracted functions.
crates/codegraph-core/src/ast_analysis/dataflow.rs Extracts resolve_var_declarator_nodes, emit_destructuring_assignments, and resolve_mutation_method_receiver; call sites are straightforward drop-in replacements.
crates/codegraph-core/src/extractors/csharp.rs Splits match_csharp_type_map into handle_csharp_var_decl_type_map and handle_csharp_param_type_map; logic is a clean early-return rewrite of the original nested ifs.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["createCfgVisitor(cfgRules)"] --> B["buildStatementProcessors(cfgRules)"]
    B --> C["buildStatementDispatch(cfgRules, processLabeled)"]
    C --> D["map: Map<string, StatementHandler>\n(labeled, return, throw, break,\ncontinue, do, infinite, try)"]
    C --> E["fallback: StatementEntry[4]\n(isIfNode/unless, isForNode,\nisWhileNode/until, isSwitchNode)"]
    B --> F["processStatement closure"]
    F --> H{"dispatch.map.get(type)?"}
    H -- "hit O(1)" --> I["mapHandler(...)"]
    H -- "miss" --> J{"fallback.find(...)?"}
    J -- "hit O(4)" --> K["fallbackEntry.handle(...)"]
    J -- "miss" --> L["update block lines, return currentBlock"]
    I --> M["return CfgBlockInternal | null"]
    K --> M
    L --> M
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["createCfgVisitor(cfgRules)"] --> B["buildStatementProcessors(cfgRules)"]
    B --> C["buildStatementDispatch(cfgRules, processLabeled)"]
    C --> D["map: Map<string, StatementHandler>\n(labeled, return, throw, break,\ncontinue, do, infinite, try)"]
    C --> E["fallback: StatementEntry[4]\n(isIfNode/unless, isForNode,\nisWhileNode/until, isSwitchNode)"]
    B --> F["processStatement closure"]
    F --> H{"dispatch.map.get(type)?"}
    H -- "hit O(1)" --> I["mapHandler(...)"]
    H -- "miss" --> J{"fallback.find(...)?"}
    J -- "hit O(4)" --> K["fallbackEntry.handle(...)"]
    J -- "miss" --> L["update block lines, return currentBlock"]
    I --> M["return CfgBlockInternal | null"]
    K --> M
    L --> M
Loading

Reviews (3): Last reviewed commit: "docs: restore clarifying comment about d..." | Re-trigger Greptile

Comment on lines +717 to 724
if (doComplexity && fileNeedsWasmComplexity(symbols, ext, langId)) {
debug(`allNativeDataComplete: ${relPath} missing complexity`);
return false;
}
if (doCfg && fileNeedsWasmCfg(symbols, ext, langId)) {
debug(`allNativeDataComplete: ${relPath} missing cfg blocks`);
return false;
}

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.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Debug logs lose per-function granularity

Before this refactor, when allNativeDataComplete found a missing complexity or CFG entry it emitted ${relPath}:${def.name} missing complexity — including the offending function name. The new code delegates to fileNeedsWasmComplexity / fileNeedsWasmCfg, which only know about the file, so the debug lines now say ${relPath} missing complexity without specifying which function triggered the return. When chasing down why a particular file keeps being re-analysed by WASM the function name was the most actionable piece of context.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Fixed — restored per-function name in WASM fallback debug logs by using Array.find on the definitions array to surface the offending function: ${relPath}:${offender?.name ?? '?'} missing complexity / missing cfg blocks.

Comment on lines 1381 to 1384
finally_handler = Some(child);
}
if matches_opt(child.kind(), self.rules.else_node) {
// Only treat as try-else if it's a direct child of the try statement
// (not the else_clause of an if inside the try body)
else_handler = Some(child);

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.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Clarifying comment removed from collect_try_handlers

The deleted line read: "Only treat as try-else if it's a direct child of the try statement (not the else_clause of an if inside the try body)". That comment explained why iterating only over direct children of try_stmt is both necessary and sufficient — without it a reader has to re-derive that the loop is not recursive and cannot accidentally pick up else_clause nodes from nested if statements. Worth preserving as a doc-comment on the extracted function.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Fixed — restored as a doc-comment on collect_try_handlers explaining that direct-child iteration is both necessary and sufficient, and that the loop cannot accidentally pick up else_clause nodes from nested if statements.

github-actions Bot commented Jun 17, 2026
edited
Loading

Copy link
Copy Markdown
Contributor

Codegraph Impact Analysis

43 functions changed57 callers affected across 13 files

  • CfgBuilder<'a>.process_if_depth in crates/codegraph-core/src/ast_analysis/cfg.rs:908 (6 transitive callers)
  • CfgBuilder<'a>.process_if_true_branch in crates/codegraph-core/src/ast_analysis/cfg.rs:930 (6 transitive callers)
  • CfgBuilder<'a>.process_if_false_branch in crates/codegraph-core/src/ast_analysis/cfg.rs:948 (5 transitive callers)
  • CfgBuilder<'a>.process_if_alternative_c in crates/codegraph-core/src/ast_analysis/cfg.rs:974 (4 transitive callers)
  • CfgBuilder<'a>.process_if_else_clause in crates/codegraph-core/src/ast_analysis/cfg.rs:994 (4 transitive callers)
  • CfgBuilder<'a>.process_switch in crates/codegraph-core/src/ast_analysis/cfg.rs:1233 (5 transitive callers)
  • CfgBuilder<'a>.process_switch_case in crates/codegraph-core/src/ast_analysis/cfg.rs:1269 (3 transitive callers)
  • CfgBuilder<'a>.extract_case_stmts in crates/codegraph-core/src/ast_analysis/cfg.rs:1299 (3 transitive callers)
  • CfgBuilder<'a>.process_try_catch in crates/codegraph-core/src/ast_analysis/cfg.rs:1320 (5 transitive callers)
  • CfgBuilder<'a>.process_try_body in crates/codegraph-core/src/ast_analysis/cfg.rs:1347 (3 transitive callers)
  • CfgBuilder<'a>.collect_try_handlers in crates/codegraph-core/src/ast_analysis/cfg.rs:1376 (3 transitive callers)
  • CfgBuilder<'a>.process_try_else in crates/codegraph-core/src/ast_analysis/cfg.rs:1396 (3 transitive callers)
  • CfgBuilder<'a>.process_catch_handlers in crates/codegraph-core/src/ast_analysis/cfg.rs:1410 (3 transitive callers)
  • CfgBuilder<'a>.wire_finally_or_join in crates/codegraph-core/src/ast_analysis/cfg.rs:1430 (3 transitive callers)
  • CfgBuilder<'a>.process_finally_block in crates/codegraph-core/src/ast_analysis/cfg.rs:1446 (4 transitive callers)
  • resolve_var_declarator_nodes in crates/codegraph-core/src/ast_analysis/dataflow.rs:1110 (3 transitive callers)
  • emit_destructuring_assignments in crates/codegraph-core/src/ast_analysis/dataflow.rs:1162 (3 transitive callers)
  • handle_var_declarator in crates/codegraph-core/src/ast_analysis/dataflow.rs:1185 (6 transitive callers)
  • resolve_mutation_method_receiver in crates/codegraph-core/src/ast_analysis/dataflow.rs:1376 (3 transitive callers)
  • handle_expr_stmt_mutation in crates/codegraph-core/src/ast_analysis/dataflow.rs:1433 (6 transitive callers)

Copy link
Copy Markdown
Contributor Author

Addressed all 3 Greptile findings:

  • dispatch converted to Map<string, StatementHandler> for O(1) lookup; multi-predicate entries (isIfNode/isForNode/isWhileNode/isSwitchNode) kept in a short fallback array scanned only on a map miss
  • per-function name restored in WASM fallback debug logs (fileNeedsWasmComplexity / fileNeedsWasmCfg) using Array.find to surface the offending function name
  • clarifying direct-child constraint comment restored as a doc-comment on collect_try_handlers

Copy link
Copy Markdown
Contributor Author

@greptileai

carlos-alm merged commit 82bcfb4 into main Jun 17, 2026
37 checks passed
carlos-alm deleted the refactor/titan-cfg-handler-table branch June 17, 2026 22:46
github-actions Bot locked and limited conversation to collaborators Jun 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
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.

1 participant


Back | FazBrowse Home | New Git URL