repowise-dev / repowise-dev/repowise

[Bug] Dead-code unused_export FPs: Rust intra-crate + tests/ consumers, Lambda string handlers, doc-referenced examples (5/5 in a safe-to-delete batch)

Open
#640 5 comments 0 reactions 1 assignee View on GitHub

@crizah is already working on this.

Since Aug 14, 2026.

bug help wanted
Dominant language
Python
Stars
6.7k
Forks
711
Avg merge
1d 13h
Merged PRs (30d)
439

Description

Describe the Bug

We ran a cleanup pass over a get_dead_code high-confidence, safe_to_delete-tier batch (5 unused_export findings) on a mixed Rust/JS/terraform monorepo. After manual verification, 5/5 were false positives, falling into four distinct classes. Filing them together since they share a theme: "no importers" is being computed from import-statement graph edges only, which misses same-crate references, string-based entry points, external-test consumers, and documentation references.

FP classes

1. Rust: intra-crate references produce no graph edges (same root cause as #628, not Go-specific)

pub structs flagged as unused_export at high confidence while being used extensively within their own crate — embedded in pub enum variants, held as struct fields, constructed and consumed across sibling modules. Rust intra-crate references need no use of the symbol (path-qualified or same-module access), so they produce no import edges, and the symbol appears to have zero importers. The pub visibility is required because the symbol appears inside other pub items.

// lib.rs
pub mod transport;

// transport/state.rs
pub struct RecvState { /* ... */ }   // ← flagged: "no importers"

// transport/types.rs — same crate, no `use` needed via super::
pub enum Event {
    Received { state: Option<super::RecvState> },  // pub position forces pub visibility
}
2. Rust: integration tests under tests/ not counted as consumers

A pub report struct returned by a pub fn, flagged as unused — but its fields are asserted one-by-one in the crate's tests/*.rs integration tests. Those compile as external crates, which is exactly why the symbol must stay pub. If the graph skips tests/ dirs (or treats them as non-importers), every symbol whose only external consumer is an integration test looks dead.

3. String-based entry points: AWS Lambda handler referenced from terraform
// lambda/broker.mjs
export const handler = async () => { /* ... */ };  // ← flagged: "no importers"
# main.tf
handler = "broker.handler"   # AWS invokes the export by name at runtime

Similar in spirit to the framework-awareness you already ship (Flask/FastAPI/Rails routes): handler/lambda_handler exports in files referenced by IaC (aws_lambda_function handler attributes, SAM/serverless.yml) are runtime entry points. Even just special-casing the export name handler in .mjs/.js/.py under a confidence penalty would kill this class.

4. Documentation-referenced example files

A .ts example file whose exported helpers are flagged, but the file exists as a reference implementation pointed at by adjacent markdown docs ("See foo-example.ts in this directory for the complete implementation"). No importers is expected and correct — it's illustrative code, not application code. A markdown-mention check (filename appearing in sibling .md files) or a docs/examples path heuristic would down-rank these.

Expected Behavior

None of the above should land in the high-confidence / safe_to_delete tier. Classes 1–2 arguably shouldn't be flagged at all (real references exist in the graph's source language); classes 3–4 should at least drop to low confidence (dynamic/string reference risk).

Actual Behavior

All five findings surfaced as unused_export, high-confidence, safe-to-delete tier, reason "Public symbol 'X' has no importers". 5/5 manually verified as live.

Environment

  • OS: Amazon Linux 2023
  • Python version: 3.12
  • Repowise version: 0.25.0
  • Installation method: uv tool install

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.