Skip to content

Fix Python @property read edges and call resolution - #1065

Open
Ha1baraA11 wants to merge 6 commits into
tirth8205:stagingfrom
Ha1baraA11:pr/code-review-graph-1060
Open

Ha1baraA11 wants to merge 6 commits into
tirth8205:stagingfrom
Ha1baraA11:pr/code-review-graph-1060

Conversation

@Ha1baraA11

Copy link
Copy Markdown
Contributor

Linked issue

Closes #1060

What & why

  • Emit a CALLS edge for reads of explicitly declared @property getters when the owner class is known from local or imported bindings.
  • Use the property's return annotation to resolve methods called on an assigned property value.
  • Keep property reads on unknown receivers unresolved; cover cross-file classes, same-named properties, and unknown receivers in regression tests.

How it was tested

uv run ruff check code_review_graph/  # passed
uv run pytest tests/ --tb=short -q  # 4,269 passed, 850 skipped, 2 xfailed, 2 xpassed
uv run mypy code_review_graph/ --ignore-missing-imports --no-strict-optional  # reports an error at code_review_graph/embeddings.py:253, an unchanged file

The full test suite ran on Python 3.12.13 with watchdog's polling observer because the native macOS FSEvents observer crashed during full-suite runs on this host.

Checklist

  • Tests added for new functionality
  • All tests pass: uv run pytest tests/ --tb=short -q
  • Linting passes: uv run ruff check code_review_graph/
  • Type checking passes: uv run mypy code_review_graph/ --ignore-missing-imports --no-strict-optional
  • Lines are at most 100 characters
  • Docs updated where behavior changed (README, docs/, docstrings)

@tirth8205

Copy link
Copy Markdown
Owner

Thank you for this PR.

I tested small examples on this branch and on staging.

Before I can merge it, please fix these:

  1. Reading a property through cls makes a getter read edge. code_review_graph/parser.py:6687-6688 treats cls like self. Example: @classmethod def inspect(cls): return cls.value gives C.inspect -> C.value. A @staticmethod with a parameter named self does the same.

  2. Writing to a property also makes a read edge. code_review_graph/parser.py:6414-6449 does not check for stores. Examples: self.value = 2, del self.value, self.value, x = 2, 3 and for self.value in range(3). Please keep the edge for self.value += 1. That one is correct.

Please add tests for both cases.

After you push the fix, I will test it again.

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

code-review-graph review

Overall risk: 0.40 (MEDIUM) — 24 changed function(s)/class(es), 0 affected flow(s), 18 test gap(s) (16 with no tested caller found, 2 reached only through a caller)

Risk-scored changes

Risk Level Symbol Location Tested
0.40 medium code_review_graph/parser.py::CodeParser.scan_declarations code_review_graph/parser.py:6238 no
0.40 medium code_review_graph/parser.py::CodeParser.bind_targets code_review_graph/parser.py:6343 no
0.40 medium code_review_graph/parser.py::CodeParser.first_parameter_name code_review_graph/parser.py:6357 no
0.40 medium code_review_graph/parser.py::CodeParser._python_property_definition code_review_graph/parser.py:6681 no
0.40 medium code_review_graph/parser.py::CodeParser._python_expression_class_evidence code_review_graph/parser.py:6807 no
0.40 medium code_review_graph/parser.py::CodeParser.bind code_review_graph/parser.py:7380 no
0.35 low code_review_graph/parser.py::_PyReceiverContext code_review_graph/parser.py:105 no
0.35 low code_review_graph/parser.py::CodeParser._collect_python_receiver_evidence code_review_graph/parser.py:6207 indirect
0.35 low code_review_graph/parser.py::CodeParser.instance_receiver_parameter code_review_graph/parser.py:6378 no
0.35 low code_review_graph/parser.py::CodeParser.class_receiver_parameter code_review_graph/parser.py:6387 no

Test gaps

  • code_review_graph/parser.py::_PyReceiverContext (code_review_graph/parser.py:105)
  • code_review_graph/parser.py::CodeParser.walk (code_review_graph/parser.py:6428)
  • code_review_graph/parser.py::CodeParser.scan_declarations (code_review_graph/parser.py:6238)
  • code_review_graph/parser.py::CodeParser.bind_targets (code_review_graph/parser.py:6343)
  • code_review_graph/parser.py::CodeParser.first_parameter_name (code_review_graph/parser.py:6357)
  • ...and 11 more with no direct test

Reached only through a caller

No test names these directly, but a tested caller reaches them along the call path shown. That is a path in the call graph, not a record of execution -- the caller's tests may never take this branch. Treat it as where to look, not as coverage: these count as gaps and are scored as untested.

  • code_review_graph/parser.py::CodeParser._extract_bytes (code_review_graph/parser.py:3196) — via code_review_graph/parser.py::CodeParser.parse_bytes, 1 hop(s)
  • code_review_graph/parser.py::CodeParser._collect_python_receiver_evidence (code_review_graph/parser.py:6207) — via code_review_graph/parser.py::CodeParser.parse_bytes, 2 hop(s)

Token savings: this graph-backed report used ~196,162 fewer tokens (~97%) than reading every changed file in full (estimated, chars/4 approximation).


Powered by code-review-graph — local-first analysis; no code leaves the CI runner.

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Python @property reads produce no edge, so callers_of and find_dead_code miss every consumer

2 participants