MCPcopy Create free account
hub / github.com/PHPantom-dev/phpantom_lsp / enrich_method_from_ancestor

Function enrich_method_from_ancestor

src/inheritance.rs:154–214  ·  view source on GitHub ↗

Enrich a child method with docblock information from an ancestor method. Propagates return types, parameter types, descriptions, template parameters, conditional return types, and type assertions from the ancestor when the child lacks its own docblock overrides. Return type rule:** If the child's `return_type` equals its `native_return_type` (no docblock), and the ancestor's `return_type` differ

(existing: &mut MethodInfo, ancestor: &MethodInfo)

Source from the content-addressed store, hash-verified

152/// **Description rule:** Inherit `description` and `return_description`
153/// when the child has `None`.
154pub(crate) fn enrich_method_from_ancestor(existing: &mut MethodInfo, ancestor: &MethodInfo) {
155 // ── Return type ─────────────────────────────────────────────
156 // Propagate when (a) the child has no return type at all, or
157 // (b) the child's effective type equals its native type (no
158 // docblock override) and the ancestor has a richer docblock type.
159 if existing.return_type.is_none() && ancestor.return_type.is_some()
160 || lacks_docblock_override(&existing.return_type, &existing.native_return_type)
161 && ancestor_has_richer_type(&ancestor.return_type, &ancestor.native_return_type)
162 {
163 existing.return_type = ancestor.return_type.clone();
164 }
165
166 // ── Template parameters ─────────────────────────────────────
167 if existing.template_params.is_empty() && !ancestor.template_params.is_empty() {
168 existing.template_params = ancestor.template_params.clone();
169 existing.template_param_bounds = ancestor.template_param_bounds.clone();
170 existing.template_bindings = ancestor.template_bindings.clone();
171 // Template return types like `T` only make sense when the
172 // template params are present — inherit the return type too
173 // if we haven't already set it.
174 if existing.return_type.is_none() {
175 existing.return_type = ancestor.return_type.clone();
176 }
177 }
178
179 // ── Conditional return type ─────────────────────────────────
180 if existing.conditional_return.is_none() && ancestor.conditional_return.is_some() {
181 existing.conditional_return = ancestor.conditional_return.clone();
182 }
183
184 // ── Type assertions ─────────────────────────────────────────
185 if existing.type_assertions.is_empty() && !ancestor.type_assertions.is_empty() {
186 existing.type_assertions = ancestor.type_assertions.clone();
187 }
188
189 // ── Parameters ──────────────────────────────────────────────
190 // For constructors, use **name-based** matching instead of
191 // positional. PHP constructors don't follow Liskov substitution
192 // — a child constructor can have a completely different signature
193 // (different parameter count, order, types). Positional
194 // enrichment would incorrectly map ancestor param types onto
195 // unrelated child params (e.g. Exception's `$code` type `int`
196 // onto a child's `$message` param at position 1).
197 //
198 // This follows PHPStan's `PhpDocInheritanceResolver`: for
199 // `__construct` the positional parameter name list falls back to
200 // the child's own names, so only same-named parameters inherit.
201 if existing.name == "__construct" {
202 enrich_constructor_parameters_by_name(&mut existing.parameters, &ancestor.parameters);
203 } else {
204 enrich_parameters_from_ancestor(&mut existing.parameters, &ancestor.parameters);
205 }
206
207 // ── Descriptions ────────────────────────────────────────────
208 if existing.description.is_none() && ancestor.description.is_some() {
209 existing.description = ancestor.description.clone();
210 }
211 if existing.return_description.is_none() && ancestor.return_description.is_some() {

Callers 2

Calls 6

lacks_docblock_overrideFunction · 0.85
ancestor_has_richer_typeFunction · 0.85
cloneMethod · 0.80
is_emptyMethod · 0.45

Tested by

no test coverage detected