fix(parsers/php): resolve $this->/self:: calls into used traits#131
fix(parsers/php): resolve $this->/self:: calls into used traits#131gadievron wants to merge 1 commit into
Conversation
|
Finding F12 (HIGH). |
322624f to
4058a1c
Compare
A class that composes a method via an in-class `use TraitName;` had no call edge from `$this->m()` / `self::m()` to the trait's method: `_resolve_self_call` only considered methods physically declared in the class body, never the methods pulled in from used traits. - function_extractor.py: capture in-class `use_declaration` trait names onto a new `traits` field on the class record (grouped + namespaced uses reduced to the unqualified trait name). - call_graph_builder.py: build a `traits_by_class` index and make `_resolve_self_call` fall back to the used traits' methods (cross-file, via `_resolve_class_call`) when no own method matches. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
0de365d to
f7d32ac
Compare
|
Rebased onto origin/master (post-release #133 / Wave 1). Conflicts resolved by UNION — both this PR's fix and the Wave-1 parser fixes are preserved; no Wave-1 change reverted (independently judge-verified). Force-pushed with --force-with-lease. Rebased onto the newly-rebased #127 (kept stacked, base pr/zig-php-generic-anon). Merge AFTER #127. PHP tests green (22); #127 anon-class handling intact. |
|
Closing as already resolved on current master. This fix's behavior shipped via the parser-fix-stack release (#133/#134); confirmed by independent reproduction — the original bug (reconstructed from its bug-pipeline investigation) no longer manifests on master, not merely by line-presence. Part of a full validated sweep of the open-PR corpus. |
fix(parsers/php): resolve $this->/self:: calls into used traits
Base:
pr/zig-php-generic-anon· Depends-on: #127 · Type: bug fix · Finding: F12 (HIGH)What
parsers/php/function_extractor.py— capture in-classuse_declarationtraitnames onto a new
traitsfield on the class record (_extract_trait_names).parsers/php/call_graph_builder.py— build atraits_by_classindex and make_resolve_self_callfall back to the used traits' methods when no own methodmatches.
Why
$this->method()/self::method()calls into a method defined in aused traitwere never resolved:
_resolve_self_callonly indexed methods physically in theclass body, and trait
usewas never recorded as a class→trait composition. Traitmethods live under the trait's own key, so the edges were dropped. Measured: of
trait methods, symfony 77% orphaned (425/553), laravel 68%, composer 71%, guzzle
86% — a major contributor to PHP's high isolated-function ratio.
Tests
tests/test_php_trait_self_call.py(new): traitT{ g() }, classC{ use T; f(){ $this->g(); } h(){ self::g(); } }; asserts edges C::f→T::g andC::h→T::g (builder-dict + end-to-end extractor layers).
'a.php:T.g' not in []).test_php_schema_completeness— the new
traitsfield doesn't break the schema).Scope / siblings
Ruby has the same shape (
include/extend/prependmixins never recorded as aclass→module composition;
_resolve_self_callhas no mixin fallback) — confirmedsibling, tracked separately, not fixed here.
Upstream coordination
No open PR adds trait-composition resolution. PR #122 (php/ruby) handles only
conditional-branch same-name collisions, not traits — non-overlapping. Must merge
after #127.
Author notes
traitscapture infunction_extractor.py;traits_by_class+_resolve_self_calltrait fallback incall_graph_builder.py.$this->g()/self::g()wheregis defined in aused trait.live in fix(zig,php parsers): attribute generic-container & anonymous-class methods correctly #127; rebasing onto master would duplicate/conflict with them.