Repository navigation
Phase 2: chain stitching → usable tool - #4
Merged
Merged
Conversation
…okup Adds MethodIndex::allClasses() (additive) so ClassHierarchy can enumerate method-less marker interfaces and DTOs when computing implementationsOf.
Resolves a ForwardSite to ResolvedTarget/ExternalTarget/TruncatedResolution per the frozen rules. ReceiverTyper owns hint->FQCN. Note: Phase 1 stores the method name in CalleeRef->name and the class in receiverHint for static calls, and leaves same-namespace function names unqualified, so function resolution tries the namespaced candidate before the global one.
ForwardCollector now tracks whether every use of a parameter is a $this->prop = $p store; ParamInfo gains storedOnly (also true for promoted constructor properties), which ChainBuilder maps to the 'stored' terminal.
Walks the forward graph from origins (and entry-less cycles) to terminals, emitting one Finding per root-to-terminal path. The walk, path accumulation (PartialChain), and terminal descriptor (Terminal) are separate small classes, with a per-run ChainTraversal, to keep each PHPMD-clean and honor the few-parameters rule as the plan anticipates.
Default invocation now runs FileLocator -> Indexer -> resolver -> ChainBuilder, filters hops >= limit, renders aligned text, and returns 1/0. Non-text formats exit 2 until Phase 3. TextReporter uses a uniform two-space column separator (the plan's byte example incidentally shows three spaces before the terminal note).
With --explain each finding is followed by its per-edge resolution trace under an 'explain:' header; without the flag the output is byte-for-byte unchanged.
FixtureTest gains a findings harness (expected-findings.json, chain flattened to FQMNs). New fixtures pin one frozen-semantics rule each end-to-end: use-breaks-chain, interface-single-impl, interface-multi-impl (truncation + note), variadic-decorator, recursion, static-function-mix; classifier-smoke gains its expected-findings.json.
Adds a report-only dogfood step (bin/phptramp --folder src --limit 99) to the static CI job, updates README status to Phase 2 and the example to the real hop labels, and checks off Phase 2 in docs/plan.md and docs/plans/phase-2.md.
Raises diff-scoped MSI from 84% to 94% by pinning behaviours the suite left unverified: real resolution-trace strings, static::/parent:: and function-caller resolution, static calls to unknown classes, the union truncation reason, proper-origin detection when the origin is declared last, used-terminals that also forward, the cyclic-hierarchy guard, and storedOnly on the closure/arrow/ by-ref/store-and-forward paths. The remaining escaped mutants are equivalent (bijective key reorderings, in-file sort-index fall-through, class/fqmn yielding the same namespace) or defensive-unreachable branches.
Applies /simplify cleanup (behaviour-preserving): - Hoist the thrice-duplicated 'find parameter by name' loop onto MethodInfo::paramNamed(); CallResolver, ReceiverTyper and ChainTraversal now delegate to it. - Make Resolution behavioural (describe()) so ChainTraversal::traceTarget() and its dead defensive 'unknown' branch disappear and a future fourth Resolution type becomes a compile error rather than a silent fallback. - Drop the unused $hops parameter from TextReporter::label() and extract a shared labelledLine() so note rows and hop rows format through one path. Deferred to Phase 6 (performance): memoizing CallResolver::resolve() (each forward is resolved in both incomingTargets() and walk()) and an inverted implementations index in ClassHierarchy.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements Phase 2 (docs/plans/phase-2.md): cross-file tramp-data chain stitching.
phptramp --folder src --limit 3now stitches forwarding chains across files, prints text findings, and exits0/1/2.Closes #3
What landed (one commit per task, strict fixture-first TDD)
ClassKindonClassInfo— the resolver can tell a concrete class from an interface/abstract type.ClassHierarchy— trait flattening, parent-chain method lookup, andimplementationsOfacross the whole index (with cycle guards). Adds an additiveMethodIndex::allClasses().CallResolver(+ReceiverTyper,Resolution/ResolvedTarget/ExternalTarget/TruncatedResolution) — resolves aForwardSiteper the frozen rules 1–4.storedOnlyonParamInfo— classifies$this->x = $pstores (and promoted properties) so the chain terminal readsstored.ChainBuilder— walks the forward graph from origins (and entry-less cycles) to terminals, oneFindingper root-to-terminal path.TextReporter, default pipeline, exit codes — aligned text output; non-text formats exit 2 until Phase 3.--explain— per-edge resolution traces.expected-findings.json) and a report-only dogfood CI step.Notable decisions (flagged in commit bodies)
CalleeRef->name; Phase 1 actually stores the method there and the class inreceiverHint, and leaves same-namespace function names unqualified — the resolver follows real Phase 1 output.MethodIndex::allClasses()was added (not in the sketch) becauseimplementationsOfmust enumerate method-less marker interfaces/DTOs.Verification
composer checkgreen (154 tests, 431 assertions).src/end-to-end.Performance (memoizing
resolve(), an inverted implementations index) is intentionally deferred to Phase 6.