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

> Learn how the refactor tool in code-review-graph detects dead code by analyzing dependency graph edges and filtering framework elements.

- Repository: [Tirth Kanani/code-review-graph](https://github.com/tirth8205/code-review-graph)
- Tags: internals
- Published: 2026-07-22

---

**The refactor tool detects dead code by traversing the Code-Review-Graph engine's dependency graph and flagging symbols that lack CALLS, TESTED_BY, IMPORTS_FROM, REFERENCES, or INHERITS edges while filtering out framework entry points and intentionally alive constructs.**

The dead code detection system in the **code-review-graph** repository analyzes static relationships within your codebase to identify removable symbols. Located in [`code_review_graph/refactor.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py), the `find_dead_code` function implements a multi-stage heuristic that distinguishes truly unused code from symbols that appear unused but serve framework or architectural purposes. This analysis examines six distinct signal types to determine whether a function or class can be safely deleted.

## Filtering Entry Points and Test Files

Before analyzing symbol usage, the tool eliminates obvious entry points and test infrastructure that should never be considered dead.

The `_is_entry_point` function (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` and `handle_*`. Simultaneously, `_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 patterns, ensuring test utilities are not flagged as dead code.

## Gathering Context from the Graph Structure

The algorithm builds contextual maps to make informed decisions about symbol reachability.

**Type-referenced class names** are collected by `_collect_type_referenced_names` (lines [229-238](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L229-L238)), scanning function signatures for capitalized identifiers to preserve classes used only in type annotations. The **class hierarchy** is mapped from `INHERITS` edges (lines [279-287](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L279-L287)), and the **import graph** is constructed via `importer_files` (lines [288-296](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L288-L296)) to support caller resolution heuristics.

## The Plausible-Caller Heuristic

Bare-name `CALLS` edges present ambiguity because they lack qualified module paths. The `_is_plausible_caller` function (lines [306-346](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L306-L346)) validates these edges only when the call originates from the same file, the symbol name is globally unique, or the importing file's path plausibly points to the target through re-exports or monorepo package aliases.

## Excluding Known-Alive Constructs

A comprehensive set of early-return checks prevents false positives for symbols that are intentionally not called directly but remain alive through framework contracts.

The tool skips **dunder methods**, constructors, and ambient [`.d.ts`](https://github.com/tirth8205/code-review-graph/blob/main/.d.ts) declarations (lines [360-368](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L360-L368)), along with **mock and stub variables** in test files identified by `_MOCK_NAME_RE` (lines [69-75](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L69-L75)). **Framework-managed classes** such as Django models and Pydantic schemas are detected via `_FRAMEWORK_BASE_CLASSES` and decorator checks (lines [25-34](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L25-L34) and [389-393](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L389-L393)), while **CDK/IaC classes** are identified by suffix patterns in `_CDK_CLASS_SUFFIXES` (lines [36-38](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L36-L38)).

Additional protections cover **decorated properties and abstract methods** (lines [424-440](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L424-L440)) and **abstract-method overrides** (lines [445-471](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L445-L471)), ensuring these symbols are never flagged for removal.

## Core Dead-Code Decision Logic

For each remaining candidate, `find_dead_code` aggregates five critical signal types from the graph edges:

- **CALLS** edges (`has_callers`): 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 references with bare-name fallbacks (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 are present, the symbol qualifies as dead code. For classes, an additional check ensures no member methods are called (lines [534-549](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L534-L549)). **Polymorphic dispatch** is handled by checking if overriding methods should be kept alive when their abstract base has callers (lines [558-580](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L558-L580)).

Confirmed dead symbols are recorded with metadata including name, qualified name, kind, file path, and line number (lines [882-898](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L882-L898)) before being returned to downstream pipelines like `suggest_refactorings`.

## Practical Usage Example

```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']}")

```

This example demonstrates the standard workflow: instantiate a `GraphStore`, execute `find_dead_code`, and process the returned dictionaries containing symbol metadata and locations.

## Summary

- **Entry-point filtering** removes framework entry points, main functions, and test files before analysis begins.
- **Graph context gathering** collects type annotations, inheritance hierarchies, and import relationships to support accurate heuristics.
- **Plausible-caller validation** resolves ambiguous bare-name calls using file locality, uniqueness checks, and import path analysis.
- **Known-alive filtering** preserves dunder methods, framework-managed classes, abstract methods, and CDK/IaC constructs that appear uncalled but serve architectural purposes.
- **Edge-based detection** considers CALLS, TESTED_BY, IMPORTS_FROM, REFERENCES, and INHERITS signals to determine symbol liveness, with special handling for polymorphic dispatch.

## Frequently Asked Questions

### What specific signals indicate that code is alive rather than dead?

The refactor tool considers five primary edge types as liveness signals: **CALLS** edges from other functions, **TESTED_BY** edges indicating test coverage, **IMPORTS_FROM** edges showing cross-file imports, **REFERENCES** edges for values stored in data structures, and **INHERITS** edges for subclass relationships. Additionally, symbols are kept alive if they override abstract methods with active callers or if they match framework-managed patterns detected through decorators and base class inheritance.

### How does the tool handle polymorphic dispatch and abstract methods?

According to the source code in [`refactor.py`](https://github.com/tirth8205/code-review-graph/blob/main/refactor.py) (lines [558-580](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L558-L580)), the detector checks whether an overriding method belongs to a class that inherits from an abstract base. If the abstract base method has callers, the concrete implementation is considered alive even if it has no direct callers, preserving polymorphic dispatch chains. Abstract method declarations themselves are filtered out earlier in the process (lines [424-440](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L424-L440)).

### What framework-specific patterns does the dead code detector recognize?

The tool maintains lists of **framework base classes** (`_FRAMEWORK_BASE_CLASSES`, lines [25-34](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L25-L34)) for Django, Pydantic, and similar frameworks, plus **CDK class suffixes** (`_CDK_CLASS_SUFFIXES`, lines [36-38](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py#L36-L38)) for infrastructure-as-code patterns. It also detects framework-specific decorators and entry-point naming conventions through `_is_entry_point` and `_has_framework_decorator` to prevent false positives on framework-managed lifecycle methods.

### Can I use this dead code detection on a non-Python repository?

While the `code_review_graph` repository primarily targets Python codebases, the graph-based analysis approach is language-agnostic in principle. The `GraphStore` class in [`code_review_graph/graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/graph.py) abstracts the underlying storage, and the dead code logic operates on graph edges rather than Python AST specifics. However, the current implementation includes Python-specific heuristics such as dunder method detection and Pythonic decorator handling in [`refactor.py`](https://github.com/tirth8205/code-review-graph/blob/main/refactor.py), so adapting it for other languages would require extending the heuristics to recognize language-specific alive-code patterns.