# How Refactoring Tools for Rename Preview and Dead Code Detection Work in code‑review‑graph

> Explore how code-review-graph refactoring tools analyze static relationships for rename preview and dead code detection without program execution. Understand symbol renames and unused code identification.

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

---

**The refactoring tools in code‑review‑graph operate through a graph‑aware module that analyzes static relationships to preview symbol renames and identify unused code without executing the program.**

The `code_review_graph.refactor` module provides the core algorithms, while user‑facing wrappers in [`code_review_graph/tools/refactor_tools.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/tools/refactor_tools.py) expose these capabilities to developers. These **refactoring tools for rename preview and dead code detection** leverage the `GraphStore` populated by the parser to perform purely static analysis, avoiding filesystem operations until changes are explicitly applied.

## Architecture Overview

Both tools share a common foundation in the graph store abstraction. The `GraphStore` provides fast edge queries (`get_edges_by_target`, `search_edges_by_target_name`) and node lookups, enabling the tools to trace symbol relationships across the entire codebase. All operations remain in‑memory until a refactor is applied, ensuring safe, preview‑first workflows.

The entry points `refactor_func(mode="rename")` and `refactor_func(mode="dead_code")` in [`code_review_graph/tools/refactor_tools.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/tools/refactor_tools.py) delegate to `rename_preview` and `find_dead_code` respectively, handling input validation and result formatting.

## Rename Preview Tool

The rename preview functionality generates a complete list of edits required to safely rename a symbol across the codebase.

### Graph‑Based Symbol Resolution

When `rename_preview` (defined in [`code_review_graph/refactor.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py)) receives an `old_name` and `new_name`, it first queries the graph store to locate the target symbol:

```python
candidates = store.search_nodes(old_name, limit=10)
node = next((c for c in candidates if c.name == old_name), candidates[0] if candidates else None)

```

The function then traverses **CALLS** and **IMPORTS_FROM** edges to collect every definition site, call site, and import reference for the symbol.

### Edit Generation and Storage

For each discovered location, the tool constructs an edit dictionary specifying the file path, line number, old text, new text, and confidence level:

```python
edits = [{
    "file": node.file_path,
    "line": node.line_start,
    "old": old_name,
    "new": new_name,
    "confidence": "high",
}]

```

The preview is stored in a thread‑safe dictionary `_pending_refactors` protected by `_refactor_lock`, keyed by a unique 8‑character `refactor_id` generated via `uuid.uuid4().hex[:8]`. This allows subsequent application or inspection of the planned changes without immediately modifying source files.

## Dead Code Detection Tool

The `find_dead_code` function identifies functions and classes that lack any meaningful inbound relationships, indicating they are unreachable or unused.

### Filtering Heuristics

Before analyzing relationships, the tool aggressively filters out symbols that are clearly not dead code. In [`code_review_graph/refactor.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py), the implementation skips:

- Test nodes and files (detected via `node.is_test` or `_is_test_file`)
- Dunder methods (`__init__`, `__str__`, etc.)
- Entry points (functions matching `_is_entry_point` patterns)
- Framework‑managed classes (ORM models, Pydantic schemas, CDK constructs, Angular/NestJS components)
- Symbols referenced only in type annotations
- Constructors and mock/stub variables

### Edge Analysis and Caller Validation

For remaining candidates, the tool inspects incoming edges of kinds **CALLS**, **TESTED_BY**, **IMPORTS_FROM**, **REFERENCES**, and **INHERITS**. It also builds auxiliary structures including a type‑referenced name set, class hierarchy map, and import graph to validate bare‑name call edges:

```python
incoming = store.get_edges_by_target(node.qualified_name)

# augment with bare-name edges that pass plausibility check

if not any(e.kind == "CALLS" for e in incoming):
    bare = store.search_edges_by_target_name(node.name, kind="CALLS")
    incoming += [e for e in bare if _is_plausible_caller(e.file_path, node.file_path, node.name)]

```

A node is marked dead only if it lacks all relationship types and has no plausible callers. The resulting report includes sanitized metadata: `name`, `qualified_name`, `kind`, `file_path`, and `line`.

## Practical Usage Examples

Generate a rename preview before applying changes:

```python
from code_review_graph.tools.refactor_tools import refactor_func, apply_refactor_func

# Preview renaming a function

preview = refactor_func(
    mode="rename",
    old_name="old_func",
    new_name="new_func",
)
print(preview["summary"])

# Output: "Rename preview: old_func -> new_func, 12 edit(s). Use apply_refactor_tool(... ) to apply."

```

Detect dead code across the repository:

```python

# List dead symbols

dead = refactor_func(mode="dead_code")
print(f"Found {dead['total']} dead symbols")
for sym in dead["dead_code"]:
    print(f"{sym['kind']}: {sym['qualified_name']} ({sym['file_path']}:{sym['line']})")

```

Apply a stored refactor with dry‑run verification:

```python

# Dry run to see diff

dry = apply_refactor_func(refactor_id=preview["refactor_id"], dry_run=True)
print("\n".join(dry["diffs"].values()))

# Apply changes

result = apply_refactor_func(refactor_id=preview["refactor_id"], dry_run=False)
print(result["summary"])

```

## Summary

- **Rename preview** traces symbol relationships through the graph to generate comprehensive edit lists, storing previews in a thread‑safe dictionary keyed by unique IDs.
- **Dead code detection** combines aggressive filtering heuristics with multi‑edge relationship analysis to identify unused functions and classes without false positives from framework code or tests.
- Both tools reside in [`code_review_graph/refactor.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py) and are exposed through [`code_review_graph/tools/refactor_tools.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/tools/refactor_tools.py), utilizing the `GraphStore` for purely static analysis.

## Frequently Asked Questions

### How does the rename preview tool handle symbol conflicts?

The tool validates symbol existence through `store.search_nodes` and confidence scores. If multiple candidates match the old name, it selects the exact match or the first candidate, allowing developers to verify the preview before application rather than guessing intent.

### Can dead code detection distinguish between test utilities and production dead code?

Yes. The implementation explicitly filters nodes where `is_test` is true or `file_path` matches test patterns. It also excludes mock objects, stub variables, and symbols within test directories, ensuring production‑only analysis while preserving testing infrastructure.

### What edge types indicate a symbol is actually used?

According to the source code in [`code_review_graph/refactor.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/refactor.py), the presence of **CALLS**, **TESTED_BY**, **IMPORTS_FROM**, **REFERENCES**, or **INHERITS** edges prevents a symbol from being marked dead. The tool also validates bare‑name calls through import relationships using `_is_plausible_caller`.

### Is the refactor preview storage persistent across sessions?

No. The `_pending_refactors` dictionary exists only in memory and includes expiration handling via `_cleanup_expired()`. Previews must be applied during the same session they are generated, or the `refactor_id` becomes invalid.