fix(resolution): calls through an imported singleton resolve to the method (#1315)

reproStore.notifyJoinGuildStatus() after `import { reproStore }`
resolved its calls edge to the exported CONSTANT (resolvedBy:'import'),
while the identical same-file call resolved to the method via
local-variable receiver inference (#1108) — so `callers <method>`
missed every cross-file use and a widely-used method could look
unused (#1292).

resolveViaImport's member-descend now handles imported VALUES alongside
the #825 static-member case: when the base resolves to a
constant/variable, the value's type is inferred from ITS OWN
declaration lines in the exporting file (the shared #1108 pattern
table: `= new T(...)` initializers and type annotations) and the member
is resolved AND VALIDATED on that type via resolveMethodOnType. A
failed inference or validation keeps the existing constant edge —
never a fabricated one. Calls only; plain member reads still reference
the value.

excalidraw control: byte-identical graph (10,653 nodes / 19,483 calls
edges before and after).

Fixes #1292

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Colby Mchenry
2026-07-16 15:36:33 -05:00
committed by GitHub
co-authored by Claude Fable 5
parent ce983a08fe
commit 2ec877b08c
4 changed files with 117 additions and 2 deletions
+2 -2
View File
@@ -1075,7 +1075,7 @@ const NON_TYPE_RECEIVER_TOKENS = new Set([
* args and pointer/ref markers, take the last `.`/`::`-qualified segment, and
* reject obvious non-types.
*/
function normalizeInferredTypeName(raw: string): string | null {
export function normalizeInferredTypeName(raw: string): string | null {
const cleaned = raw.replace(/<[^>]*>/g, '').replace(/[&*]/g, '').trim();
const seg = cleaned.split(/[.:]+/).filter(Boolean).pop();
if (!seg) return null;
@@ -1090,7 +1090,7 @@ function normalizeInferredTypeName(raw: string): string | null {
* PascalCase is required in the capture where the language convention allows,
* as a cheap false-positive guard on top of resolveMethodOnType's validation.
*/
function localReceiverTypePatterns(language: Language, r: string): RegExp[] {
export function localReceiverTypePatterns(language: Language, r: string): RegExp[] {
switch (language) {
case 'typescript':
case 'javascript':