Skip to content

[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) #640

Description

@Christian-Prather

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions