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

Function resolve_class_with_inheritance

src/inheritance.rs:330–629  ·  view source on GitHub ↗

Resolve a class together with all inherited members from its parent chain. Walks up the `extends` chain via `class_loader`, collecting public and protected methods, properties, and constants from each ancestor. If a child already defines a member with the same name as a parent member, the child's version wins (even if the signatures differ). Private members are never inherited. When the child d

(
    class: &ClassInfo,
    class_loader: &dyn Fn(&str) -> Option<Arc<ClassInfo>>,
)

Source from the content-addressed store, hash-verified

328///
329/// A depth limit of 20 prevents infinite loops from circular inheritance.
330pub(crate) fn resolve_class_with_inheritance(
331 class: &ClassInfo,
332 class_loader: &dyn Fn(&str) -> Option<Arc<ClassInfo>>,
333) -> ClassInfo {
334 let mut merged = class.clone();
335
336 // Build dedup sets from the class's own members. These are passed
337 // through trait merging and the parent chain walk so that every
338 // addition is tracked in O(1) across all recursion levels.
339 let mut dedup = MergeDedup::from_class(&merged);
340
341 // 1. Merge traits used by this class.
342 // PHP precedence: class methods > trait methods > inherited methods.
343 // Since `merged` already contains the class's own members, we only
344 // add trait members that don't collide with existing ones.
345 merge_traits_into(
346 &mut merged,
347 &class.used_traits,
348 &TraitContext {
349 use_generics: &class.use_generics,
350 precedences: &class.trait_precedences,
351 aliases: &class.trait_aliases,
352 },
353 class_loader,
354 0,
355 &mut dedup,
356 &class.fqn(),
357 );
358
359 // 2. Walk up the `extends` chain and merge parent members.
360 //
361 // `current` holds a reference to the class whose `parent_class`,
362 // `extends_generics`, `used_traits`, etc. we read at each level.
363 // For the first iteration this is the root `class` (a borrow —
364 // zero allocation). After that it becomes the `Arc<ClassInfo>`
365 // returned by `class_loader` (a cheap Arc move).
366 let mut current: ClassRef<'_> = ClassRef::Borrowed(class);
367 let mut depth = 0;
368
369 // The substitution map accumulates as we walk the chain.
370 // It maps template parameter names → concrete types, and is
371 // re-computed at each level based on the `@extends` generics
372 // of the current class and the `@template` params of the parent.
373 let mut active_subs: HashMap<String, PhpType> = HashMap::new();
374
375 // Seed the initial substitution map from the root class's
376 // `@extends` generics. If the root class has
377 // `@extends Collection<int, Language>`, this will be applied
378 // when we load `Collection` as the first parent.
379 //
380 // We don't apply it yet — it's matched against the parent's
381 // template_params in the loop below.
382
383 while let Some(ref parent_name) = current.parent_class {
384 depth += 1;
385 if depth > MAX_INHERITANCE_DEPTH {
386 break;
387 }

Calls 15

merge_traits_intoFunction · 0.85
build_substitution_mapFunction · 0.85
is_factory_classFunction · 0.85
factory_to_model_fqnFunction · 0.85
cloneMethod · 0.80
fqnMethod · 0.80
as_strMethod · 0.80
iterMethod · 0.80