Skip to content

prop-flow: stop reporting live props as caller-dead - #940

Merged
fxOne merged 2 commits into
masterfrom
prop-flow-children-and-wrapper-alias
Aug 27, 2026
Merged

prop-flow: stop reporting live props as caller-dead#940
fxOne merged 2 commits into
masterfrom
prop-flow-children-and-wrapper-alias

Conversation

@fxOne

@fxOne fxOne commented Aug 27, 2026

Copy link
Copy Markdown
Owner

Summary

Two ways a prop that every call site passes could be reported caller-dead
whose advice is "inline the default, remove the prop" — on live code, plus the
guard for the ways that are left. Nothing in the library API or the CLI
arguments moves and verdictOf keeps its signature; Site.kind gains a value.
Released as 3.1.0.

Changes

The two holes

  • children is read off the JSX nesting rather than only the attributes. The
    value a call site writes between the tags was invisible, so
    <Panel><Body/></Panel> counted as a caller passing nothing and a children?
    nested at every call site came back caller-dead. Nesting now wins over an
    attribute of that name and over every spread, matching how JSX itself
    resolves it
  • A lone <Panel>{slot}</Panel> is treated as a pass-through like any other
    value, so a forwarded children is traced to its source. Whitespace between
    the tags, a lone {/* comment */} and <Panel></Panel> reach nothing and
    stay omissions
  • unwrapToFn takes an optional DeclarationResolver and follows a wrapper
    argument that only names the function: function CardComponent(…) {} plus
    export const Card = memo(CardComponent) was two components to the walk, so
    a pass-through climbing out of the body arrived at an empty usage list. The
    wrapped function may live in another file — memo(CardImpl) over an import
    resolves through the alias. A seen set guards the cycle that only
    half-written code produces
  • The usage index keys on the component function a symbol resolves to instead
    of the symbol itself, so <Card/> and CardComponent land on one entry. The
    resolution is memoised per symbol — symbolId runs on every JSX tag and
    every callee in the Program
  • The same gap made findComponents skip a file whose component is exported
    through such a wrapper, reporting no components at all for Card.tsx

The guard

  • A caller-dead whose sites include a pass-through that contributed nothing
    is now reported manual. Both fixes above were one shape of the same
    failure: the subtree came back a silent 0/0/0, the omissions written
    elsewhere were all that was left, and the walk concluded nobody passes a prop
    that is passed on every render. Three reasons a subtree comes back empty —
    the component really is dead, it is called rather than rendered (already
    manual), or the walk filed its call sites under a different key. The first
    and the third are indistinguishable, and only the first may safely end in
    "delete this"
  • Such a pass-through is reported under a new Site.kind, silent, and the
    hint names it, so the row says which line to go and check. The kind prints
    under every verdict as evidence; only caller-dead is downgraded by it, and
    the counts never move — a downgraded row still reads passes=0. A
    self-recursive pass-through is not a silence: the first visit counted that
    subtree, and the repeat is meant to add nothing
  • Scoped to caller-dead on purpose. spread.tsx: Leaf.note keeps its
    justified verdict with a silent line in it, which is what settles the
    open question in prop-flow: downgrade caller-dead when a pass-through contributed nothing #939: the fixture's stance — "a dead component contributing
    nothing is the honest answer" — needed no renegotiation, because the
    downgrade never reaches a verdict nobody acts destructively on

Fixtures

  • children.tsx, wrapped.tsx and wrapped-impl.tsx for the two holes;
    silent.tsx for the guard, carrying both a caller-dead that a silent
    pass-through pulls back and one that bottoms out directly and must not move
  • Tests over the unwrap helper, the usage index, the analyzer and the hint

Related issues

Closes #939

@fxOne fxOne changed the title prop-flow: fix two false caller-dead verdicts on live props prop-flow: stop reporting live props as caller-dead Aug 27, 2026
@fxOne
fxOne merged commit c034057 into master Aug 27, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

prop-flow: downgrade caller-dead when a pass-through contributed nothing

1 participant