Skip to content

matchFuzzy resolves onto a nested function that matchByExactName had already rejected as lexically unreachable #1708

Description

@bompus

What happens

matchByExactName filters its candidates with isLexicallyReachable (#1230): a function node whose qualified name puts it inside another function is only a candidate for references from inside that container. matchFuzzy does not apply that filter. So when the only project symbol with a given (lower-cased) name is a nested function, exact-match correctly returns null, the ref falls through to fuzzy, and fuzzy adopts the nested function as its "unique" candidate at confidence 0.5.

Trigger: any common method name called on a receiver the extractor collapses to a bare name (res.text(), items.push(x), set.clear()), when some file in the repo happens to declare a closure with that name (const text = () => … inside a function, function push() {} inside buildRows).

Measured

Real TS repo, 584 files, on main + #1706:

  • 11 fuzzy calls edges land on nested functions, 9 of them from a different file than the closure. Six calls named isOpen from various components resolve to useOverlayStack::isOpen, a closure inside a composable, because it is the only symbol with that name.

Same repo with #1679 (#1669, which extracts closures that were previously invisible, so many more nested functions exist to be hit):

  • fuzzy calls edges rise from 89 to 226. 160 of them land on nested functions, 139 cross-file: 72 .text() calls (Response#text, test-utils wrapper.text()) resolve to readSeedFailureState::text, 41 .push() calls to buildRows::push, 10 to captureListeners::event, 7 to resolveClosestName::fallback, 6 to startWarRoomBlankBoardHeal::clear.

So #1679 is not the bug, it just multiplies the targets; the gap is in matchFuzzy.

Proposed fix

Apply the same reachability filter in matchFuzzy:

const callableCandidates = applyLanguageGate(
  candidates.filter((n) => callableKinds.has(n.kind) && isLexicallyReachable(n, ref, context)),
  ref
);

Measured on the same repo with that one change: 41,378 → 41,367 edges, fuzzy 26 → 15, fuzzy-onto-nested-function 11 → 0, nothing else moves. With #1679 applied it should take the 160 closure hits back out the same way (not measured). PR to follow with a test (two files, a closure named text in one, a res.text() call in the other, assert no calls edge).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions