Skip to content

fix: nested call context misattribution and multi-line import capture#1292

Open
MorningStar0709 wants to merge 1 commit into
CodeGraphContext:mainfrom
MorningStar0709:fix/nested-call-context-resolution
Open

fix: nested call context misattribution and multi-line import capture#1292
MorningStar0709 wants to merge 1 commit into
CodeGraphContext:mainfrom
MorningStar0709:fix/nested-call-context-resolution

Conversation

@MorningStar0709

Copy link
Copy Markdown
Contributor

Summary

Fixes two related bugs in the Python parser that cause dead-code false positives and missing cross-file CALLS edges.

Root Cause

Bug 1: Nested call context misattribution

When a function call is nested inside a method call's arguments, e.g.:

results.append(_helper(data))

The _walk_call_tree method propagated called_name (the method name append) as the enclosing_caller for nested calls. Since append is not a Function node in the graph, this creates orphan CALLS edges (pointing to nothing), causing the dead-code analysis to incorrectly report _helper as unused.

Bug 2: Multi-line from...import only captures first name

_find_imports used child_by_field_name('name') (singular) which only returns the first import name from a tree-sitter node. For multi-line imports like:

from pkg.utils import (
    VERSION,
    _configure_stdio,
    _get_logs_dir,
    _setup_logging,
    ROOT,
)

Only VERSION was captured; the remaining 4 names were silently dropped. This breaks cross-file CALLS edge resolution for all subsequent imports in the same statement.

Changes

src/codegraphcontext/tools/languages/python.py

Nested call context fix:

  • Build local_names (set of all locally defined function/class names) before calling _find_calls
  • Thread local_names through _find_calls_walk_call_tree_record_call
  • In _record_call: only use enclosing_caller as context when it is in local_names; otherwise fall back to _get_parent_context (which returns the actual enclosing function)
  • In _walk_call_tree: only propagate called_name as next enclosing_caller for direct calls (identifier type); attribute calls (obj.method()) should not act as nested callers since they are method invocations, not local function definitions

Multi-line import fix:

  • Replace child_by_field_name('name') with children_by_field_name('name') in _find_imports to capture ALL imported names from from...import statements

tests/unit/parsers/test_python_parser.py

New tests:

  • test_nested_call_inside_method_uses_enclosing_function_context — verifies results.append(_helper(data)) attributes _helper's context to the enclosing function, not append
  • test_method_name_collision_uses_enclosing_function_context — verifies that when a local function shares a name with a method (e.g. def append(...) + results.append(append(data))), the inner call still attributes to the enclosing function
  • test_multiline_from_import_captures_all_names — verifies all 5 names in a parenthesized import are captured
  • test_multiline_from_import_with_alias — verifies from X import Y as Z captures both name and alias correctly

Fixed stale test:

  • test_parse_simple_function — updated to filter out synthetic <module> frame injected by _attach_module_context before asserting function count

Testing

9 passed in 0.42s

All 9 Python parser tests pass, including:

  • 5 pre-existing tests (no regressions)
  • 4 new tests covering the fixed scenarios

Full parser test suite (165 tests) also passes with no regressions.

Impact

  • Dead-code false positives: Functions called inside method arguments (e.g. list.append(helper()), all(check(x) for x in ...)) are now correctly attributed to their enclosing function, preventing orphan CALLS edges
  • Cross-file CALLS edges: Multi-line from...import statements now correctly capture all imported names, enabling proper cross-file call resolution
  • Backward compatible: All changes use optional parameters with None defaults; existing behavior is preserved when local_names is not provided

… capture

Two related bugs in the Python parser that cause dead-code false
positives and missing cross-file CALLS edges:

1. Nested call context misattribution (Type A)
   When a function call is nested inside a method's arguments
   (e.g. results.append(_helper(data))), the inner call's context
   was incorrectly set to the method name ("append") instead of the
   enclosing function ("process"). Since method names are not
   Function nodes in the graph, this creates orphan CALLS edges and
   causes dead-code analysis to report false positives.

   Fix: Pass local_names (set of locally defined function/class
   names) through _walk_call_tree. In _record_call, only use
   enclosing_caller as context when it is in local_names; otherwise
   fall back to _get_parent_context. In _walk_call_tree, only
   propagate called_name as next enclosing_caller for direct calls
   (identifier type); attribute calls (obj.method()) should not act
   as nested callers.

2. Multi-line from...import capture (Type B1)
   _find_imports used child_by_field_name('name') which only returns
   the first import name. For multi-line imports like
   from pkg import (a, b, c, d, e), only 'a' was captured and the
   remaining 4 names were silently dropped, breaking cross-file
   CALLS edge resolution.

   Fix: Use children_by_field_name('name') to capture ALL imported
   names from from...import statements.

3. Stale test assertion fix
   test_parse_simple_function expected len(funcs) == 1 but
   _attach_module_context injects a synthetic <module> frame.
   Updated to filter out <module> before asserting.

Tests:
- test_nested_call_inside_method_uses_enclosing_function_context
- test_method_name_collision_uses_enclosing_function_context
- test_multiline_from_import_captures_all_names
- test_multiline_from_import_with_alias

All 9 Python parser tests pass.
@vercel

vercel Bot commented Jun 20, 2026

Copy link
Copy Markdown

@MorningStar0709 is attempting to deploy a commit to the shashankss1205's projects Team on Vercel.

A member of the Team first needs to authorize it.

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

Labels

None yet

Projects

Status: Backlog tasks

Development

Successfully merging this pull request may close these issues.

1 participant