Skip to content

aft_callgraph returns 0 callers for cross-file Python call sites #1126

Open

Description

@tobwen

Short description

aft_callgraph returns 0 callers for cross-file Python call sites; same-file callers resolve normally

What happened?

aft_callgraph callers finds no cross-file call sites in Python code. A function called from another file through an ordinary static import (top-level from mod import func or a function-local from mod import func inside a function body) is reported as having 0 callers, and the answer is presented as complete (no shown N of M envelope, no gap note). The same edge resolves in TypeScript.

Diagnostics

Reproduction (all files directly in the project root of a fresh directory, engine configured on it):

`mod.py`:

def toplevel_target():
    return 1


def local_target():
    return 2


def test_target():
    return 3


def same_file_caller():
    return toplevel_target()


`caller_toplevel.py`:

from mod import toplevel_target


def run_toplevel():
    return toplevel_target()


`caller_local.py`:

def run_local():
    from mod import local_target
    return local_target()


`tests/test_probe.py`:

class TestProbe:
    def test_local(self):
        from mod import test_target
        return test_target()


Requests and observed results:

- `{"command":"callers","file":"<root>/mod.py","symbol":"toplevel_target"}` -> `0 callers`
- `{"command":"callers","file":"<root>/mod.py","symbol":"local_target"}` -> `0 callers`
- `{"command":"callers","file":"<root>/mod.py","symbol":"test_target","includeTests":true}` -> `0 callers`
- `{"command":"call_tree","file":"<root>/caller_toplevel.py","symbol":"run_toplevel","depth":1}` ->
  `+ 1 unresolved external call: toplevel_target`
- `{"command":"call_tree","file":"<root>/caller_local.py","symbol":"run_local","depth":1}` ->
  `+ 1 unresolved external call: local_target`

After adding `same_file_caller` to `mod.py` (calls `toplevel_target` within the same file), `callers toplevel_target` returns exactly that one same-file caller — same-file Python edges resolve, cross-file Python edges do not. A TypeScript control (`ts_mod.ts` exporting `tsTarget`, `ts_caller.ts` importing `./ts_mod` and calling it) resolves the cross-file edge normally.

Expected: `callers` finds the cross-file call sites (documented as "Find all call sites of a symbol"), or — following the honest-zero-callers behavior introduced with #1015 — the reply discloses that unresolved call sites exist in the analyzed code instead of presenting a bare 0 as complete.

Observed: bare `0 callers` with no disclosure on the shipped release, while the call sites exist in plain `from`-import form (no dynamic import, no importlib/exec).

Plugin version

0.62.0

AFT binary version

0.62.0

Platform

linux x64

Log output (optional)

Activity

  1. aft-alfonso commented on Oct 30, 2026

    @aft-alfonso

    Thanks for the reproduction and the additional details in #1130. Python's cross-file imports were not being resolved, and function-local imports were omitted. The next release fixes these imports, including package-relative imports and import mod; mod.f(), without matching unrelated functions with the same name.

    Caller and impact results will also warn about unresolved calls with the queried name when some callers were found, while retaining the zero-caller warning already on main. This work is tracked in #1126 and covers the details from #1130 as well.

  2. aft-alfonso commented on Oct 31, 2026

    @aft-alfonso

    Thanks for the reproduction and the additional details in #1130. Python's cross-file imports were not being resolved, and function-local imports were omitted. The next release fixes these imports, including package-relative imports and import mod; mod.f(), without matching unrelated functions with the same name.

    Caller and impact results will also warn about unresolved calls with the queried name when some callers were found, while retaining the zero-caller warning already on main. This work is tracked in #1126 and covers the details from #1130 as well.

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

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions