prop-flow: stop reporting live props as caller-dead - #940
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
verdictOfkeeps its signature;Site.kindgains a value.Released as 3.1.0.
Changes
The two holes
childrenis read off the JSX nesting rather than only the attributes. Thevalue a call site writes between the tags was invisible, so
<Panel><Body/></Panel>counted as a caller passing nothing and achildren?nested at every call site came back
caller-dead. Nesting now wins over anattribute of that name and over every spread, matching how JSX itself
resolves it
<Panel>{slot}</Panel>is treated as a pass-through like any othervalue, so a forwarded
childrenis traced to its source. Whitespace betweenthe tags, a lone
{/* comment */}and<Panel></Panel>reach nothing andstay omissions
unwrapToFntakes an optionalDeclarationResolverand follows a wrapperargument that only names the function:
function CardComponent(…) {}plusexport const Card = memo(CardComponent)was two components to the walk, soa 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 importresolves through the alias. A
seenset guards the cycle that onlyhalf-written code produces
of the symbol itself, so
<Card/>andCardComponentland on one entry. Theresolution is memoised per symbol —
symbolIdruns on every JSX tag andevery callee in the Program
findComponentsskip a file whose component is exportedthrough such a wrapper, reporting no components at all for
Card.tsxThe guard
caller-deadwhose sites include a pass-through that contributed nothingis now reported
manual. Both fixes above were one shape of the samefailure: 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 firstand the third are indistinguishable, and only the first may safely end in
"delete this"
Site.kind,silent, and thehint names it, so the row says which line to go and check. The kind prints
under every verdict as evidence; only
caller-deadis downgraded by it, andthe counts never move — a downgraded row still reads
passes=0. Aself-recursive pass-through is not a silence: the first visit counted that
subtree, and the repeat is meant to add nothing
caller-deadon purpose.spread.tsx: Leaf.notekeeps itsjustifiedverdict with asilentline in it, which is what settles theopen 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.tsxandwrapped-impl.tsxfor the two holes;silent.tsxfor the guard, carrying both acaller-deadthat a silentpass-through pulls back and one that bottoms out directly and must not move
Related issues
Closes #939