Skip to content

TypeScript: calls through an imported singleton instance resolve to the exported constant instead of the class method #1292

Description

@lxy32167

Summary

In TypeScript, an instance method call through a singleton is resolved correctly
when the singleton is used in the file where it is created, but the equivalent
call is mis-resolved after importing that singleton from another file.

For the imported call, CodeGraph emits a calls edge to the exported constant
instead of the class method. As a result, codegraph callers <method> misses the
cross-file caller and can make the method appear unused.

This reproduces on a fresh index built with CodeGraph 1.4.1.

Minimal reproduction

src/store.ts:

export class ReproStore {
  notifyJoinGuildStatus(): void {
    console.log('notified');
  }
}

export const reproStore = new ReproStore();

export function callInDefinitionFile(): void {
  reproStore.notifyJoinGuildStatus();
}

src/caller.ts:

import { reproStore } from './store';

export function callFromImportedFile(): void {
  reproStore.notifyJoinGuildStatus();
}

Build a fresh index and query the method and exported constant:

codegraph init .
codegraph callers notifyJoinGuildStatus -p . -j
codegraph callers reproStore -p . -j

Actual behavior

codegraph callers notifyJoinGuildStatus returns only the same-file caller:

callInDefinitionFile -> ReproStore::notifyJoinGuildStatus

The cross-file caller is instead attached to the exported constant:

callFromImportedFile -> reproStore

The corresponding graph edges are resolved as follows:

callInDefinitionFile
  -> notifyJoinGuildStatus (method)
     {"confidence":0.8,"resolvedBy":"instance-method","refName":"reproStore.notifyJoinGuildStatus"}

callFromImportedFile
  -> reproStore (constant)
     {"confidence":0.9,"resolvedBy":"import","refName":"reproStore.notifyJoinGuildStatus"}

Expected behavior

Both functions should have a calls edge to
ReproStore::notifyJoinGuildStatus:

callInDefinitionFile  -> ReproStore::notifyJoinGuildStatus
callFromImportedFile  -> ReproStore::notifyJoinGuildStatus

The import may still reference the reproStore constant, but the member
invocation should not be represented as a call to that constant.

Environment

CodeGraph: 1.4.1
Language: TypeScript
Platform: macOS arm64
Index: full rebuild; pendingRefs=0

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