# How the Refactor Tool in code-review-graph Detects Dead Code and Suggests Renames

> Discover how the code-review-graph refactor tool finds dead code and suggests renames. Learn about its graph traversal and heuristic analysis for efficient code cleanup.

- Repository: [Tirth Kanani/code-review-graph](https://github.com/tirth8205/code-review-graph)
- Tags: how-to-guide
- Published: 2026-07-26

---

**The refactor tool in code-review-graph detects dead code by traversing the graph database in [`code_review_graph/refactor.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py), applying multi-layered heuristics to filter out entry points and framework-managed symbols before flagging functions and classes with no callers, importers, or test references.**

The **code-review-graph** repository implements a sophisticated static analysis engine that builds a comprehensive graph of code relationships. The dead-code detection logic lives primarily in the `find_dead_code` function within [`code_review_graph/refactor.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py), which analyzes this graph to identify symbols that can be safely removed or renamed. By combining entry-point filtering, plausible-caller heuristics, and framework-aware exclusions, the tool minimizes false positives while surfacing genuinely unused code.

## Entry-Point and Test File Filtering

Before analyzing call relationships, the tool eliminates obvious entry points that are intentionally invoked by external systems rather than internal code.

The helper `_is_entry_point` (lines [185‑197](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L185-L197)) filters functions bearing framework decorators or conventional entry names like `main` or `handle_*`. Similarly, `_is_test_file` (lines [208‑110](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L208-L110)) identifies and excludes test nodes and files matching common test-file patterns, ensuring that test-only usage does not mask production dead code.

## Context Gathering from the Graph Database

The analyzer enriches its dead-code detection by gathering three critical contexts from the `GraphStore`:

- **Type-referenced class names** – The `_collect_type_referenced_names` function (lines [229‑238](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L229-L238)) scans function signatures for capitalized identifiers, preserving classes that appear only in type annotations.
- **Class hierarchy** – The tool builds a map of `class → [base names]` from `INHERITS` edges (lines [279‑287](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L279-L287)) to understand inheritance relationships.
- **Import graph** – The `importer_files` structure (lines [288‑296](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L288-L296)) tracks which files import which symbols, enabling cross-file reachability analysis.

## The Plausible-Caller Heuristic

Bare-name `CALLS` edges in the graph are inherently ambiguous. The `_is_plausible_caller` helper (lines [306‑346](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L306-L346)) resolves this by validating caller relationships against three criteria:

1. The edge originates from the same file as the target symbol.
2. The symbol name is globally unique, eliminating ambiguity.
3. The importing file’s import path plausibly points to the target file, accounting for 2-hop re-exports and monorepo package alias heuristics.

Only edges satisfying one of these conditions are treated as genuine callers during dead-code analysis.

## Excluding Framework-Managed and Special Symbols

A comprehensive set of early-return checks eliminates symbols that are intentionally uncalled but still required by frameworks or language features:

- **Dunder methods and constructors** – Lines [360‑368](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L360-L368) skip `__init__`, `__repr__`, and ambient [`.d.ts`](https://github.com/tirth8205/code-review-graph/blob/main/.d.ts) declarations.
- **Mock and stub variables** – The `_MOCK_NAME_RE` pattern (lines [69‑75](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L69-L75)) ignores test-specific variables.
- **Framework-managed classes** – Detection via `_FRAMEWORK_BASE_CLASSES` (lines [25‑34](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L25-L34)) and validation at lines [389‑393](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L389-L393) handles Django models, Pydantic classes, and similar framework entries.
- **Infrastructure-as-Code classes** – The `_CDK_CLASS_SUFFIXES` list (lines [36‑38](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L36-L38)) preserves CDK constructs.
- **Decorator-driven indirect invocation** – Lines [424‑440](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L424-L440) recognize `@property`, `@abstractmethod`, and similar decorators that imply external invocation patterns.
- **Abstract-method overrides** – Lines [445‑471](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L445-L471) detect methods overriding abstract base classes.

## Core Dead-Code Decision Algorithm

For each remaining candidate symbol, `find_dead_code` aggregates five categories of graph edges to determine liveness:

- **CALLS** edges (`has_callers`) – Both qualified and plausible bare-name callers (lines [474‑500](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L474-L500)).
- **TESTED_BY** edges (`has_test_refs`) – Test coverage relationships (lines [498‑525](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L498-L525)).
- **IMPORTS_FROM** edges (`has_importers`) – Cross-file imports (lines [529‑531](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L529-L531)).
- **REFERENCES** edges (`has_references`) – Values stored in data structures (line [531](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L531)).
- **INHERITS** edges (`has_subclasses`) – Subclass relationships (line [532](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L532)).

If none of these signals exist, the symbol is flagged as dead. For classes, the tool performs an additional check to ensure no members are called (lines [534‑549](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L534-L549)). Polymorphic dispatch is also considered: methods overriding abstract bases are kept alive if the base method has callers (lines [558‑580](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L558-L580)).

Finally, dead symbols are assembled into records containing the name, qualified name, kind, location, line number, and language (lines [882‑898](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L882-L898)).

## From Detection to Rename Suggestions

While `find_dead_code` identifies unused symbols, the broader refactor tool leverages these findings through the `suggest_refactorings` pipeline. This downstream processor consumes the dead symbol list and generates specific recommendations, which may include renaming symbols to follow deprecation patterns or removing them entirely. The graph-based approach ensures that suggested renames account for all import relationships and call sites, preventing breaking changes in dependent code.

```python
from code_review_graph.graph import GraphStore
from code_review_graph.refactor import find_dead_code

# Build a GraphStore from your repository

store = GraphStore.from_path("/path/to/repo")

# Detect dead code across the whole project

dead_symbols = find_dead_code(store)

for sym in dead_symbols:
    print(f"{sym['kind']} {sym['qualified_name']} → {sym['file_path']}:{sym['line']}")

```

## Summary

- The **refactor tool** operates in [`code_review_graph/refactor.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py), using the `find_dead_code` function to traverse a `GraphStore` of code relationships.
- **Entry-point filtering** removes framework handlers, conventional names like `main`, and test files before analysis begins.
- The **plausible-caller heuristic** validates bare-name calls by checking same-file origin, global uniqueness, or import-path compatibility.
- **Framework-aware exclusions** prevent false positives for Django models, Pydantic classes, CDK constructs, and decorator-managed methods.
- Dead-code detection requires zero incoming **CALLS**, **TESTED_BY**, **IMPORTS_FROM**, **REFERENCES**, or **INHERITS** edges, with special handling for class members and polymorphic dispatch.
- Findings feed into the **`suggest_refactorings`** pipeline to generate removal or rename recommendations.

## Frequently Asked Questions

### How does the tool avoid false positives for framework-managed code?

The analyzer maintains allowlists of framework patterns. It detects Django and Pydantic classes via `_FRAMEWORK_BASE_CLASSES` (lines [25‑34](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L25-L34)), recognizes CDK constructs through `_CDK_CLASS_SUFFIXES` (lines [36‑38](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L36-L38)), and identifies decorator-driven invocation through patterns like `@property` and `@abstractmethod` (lines [424‑440](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L424-L440)).

### What graph edges does the dead-code analyzer check?

The algorithm examines five edge types: **CALLS** for direct invocations, **TESTED_BY** for test coverage, **IMPORTS_FROM** for cross-file imports, **REFERENCES** for data structure usage, and **INHERITS** for subclass relationships. A symbol must have at least one of these edges to be considered alive.

### How does the plausible-caller heuristic handle ambiguous bare-name calls?

The `_is_plausible_caller` function (lines [306‑346](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L306-L346)) resolves ambiguity by treating a call as valid only if it originates from the same file, targets a globally unique name, or matches import-path heuristics including re-export chains and monorepo aliases.

### Can the tool detect dead classes as well as functions?

Yes. Class detection follows the same edge-analysis logic but adds a member-check phase (lines [534‑549](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L534-L549)) to ensure no class methods are called. Classes appearing only in type annotations are preserved via `_collect_type_referenced_names` (lines [229‑238](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L229-L238)).