1use ahash::HashSet;
2use ahash::RandomState;
3use indexmap::IndexMap;
4
5use mago_atom::Atom;
6use mago_atom::AtomMap;
7use mago_atom::AtomSet;
8use mago_atom::atom;
9
10use crate::is_method_abstract;
11use crate::metadata::CodebaseMetadata;
12use crate::metadata::class_like::ClassLikeMetadata;
13use crate::metadata::flags::MetadataFlags;
14use crate::metadata::function_like::FunctionLikeMetadata;
15use crate::misc::GenericParent;
16use crate::reference::ReferenceSource;
17use crate::reference::SymbolReferences;
18use crate::symbol::SymbolIdentifier;
19use crate::symbol::Symbols;
20use crate::ttype::TType;
21use crate::ttype::atomic::TAtomic;
22use crate::ttype::atomic::generic::TGenericParameter;
23use crate::ttype::atomic::populate_atomic_type;
24use crate::ttype::union::TUnion;
25use crate::ttype::union::populate_union_type;
26
27pub fn populate_codebase(
38 codebase: &mut CodebaseMetadata,
39 symbol_references: &mut SymbolReferences,
40 safe_symbols: AtomSet,
41 safe_symbol_members: HashSet<SymbolIdentifier>,
42) {
43 let mut class_likes_to_repopulate = Vec::new();
44 for (name, metadata) in codebase.class_likes.iter() {
45 if !metadata.flags.is_populated() || (metadata.flags.is_user_defined() && !safe_symbols.contains(name)) {
47 class_likes_to_repopulate.push(*name);
48 }
49 }
50
51 for class_like_name in &class_likes_to_repopulate {
52 if let Some(classlike_info) = codebase.class_likes.get_mut(class_like_name) {
53 classlike_info.flags &= !MetadataFlags::POPULATED;
54 classlike_info.declaring_property_ids.clear();
55 classlike_info.appearing_property_ids.clear();
56 classlike_info.declaring_method_ids.clear();
57 classlike_info.appearing_method_ids.clear();
58 }
59 }
60
61 for class_name in &class_likes_to_repopulate {
62 populate_class_like_metadata(class_name, codebase, symbol_references, &safe_symbols);
63 }
64
65 for (name, function_like_metadata) in codebase.function_likes.iter_mut() {
66 let force_repopulation = function_like_metadata.flags.is_user_defined() && !safe_symbols.contains(&name.0);
67
68 let reference_source = if name.1.is_empty() || function_like_metadata.get_kind().is_closure() {
69 ReferenceSource::Symbol(true, name.0)
71 } else {
72 ReferenceSource::ClassLikeMember(true, name.0, name.1)
74 };
75
76 populate_function_like_metadata(
77 function_like_metadata,
78 &codebase.symbols,
79 &reference_source,
80 symbol_references,
81 force_repopulation,
82 );
83 }
84
85 for (name, metadata) in codebase.class_likes.iter_mut() {
86 let userland_force_repopulation = metadata.flags.is_user_defined() && !safe_symbols.contains(name);
87 let class_like_reference_source = ReferenceSource::Symbol(true, *name);
88
89 for (property_name, property_metadata) in &mut metadata.properties {
90 let property_reference_source = ReferenceSource::ClassLikeMember(true, *name, *property_name);
91
92 if let Some(signature) = property_metadata.type_declaration_metadata.as_mut() {
93 populate_union_type(
94 &mut signature.type_union,
95 &codebase.symbols,
96 Some(&property_reference_source),
97 symbol_references,
98 userland_force_repopulation,
99 );
100 }
101
102 if let Some(signature) = property_metadata.type_metadata.as_mut() {
103 populate_union_type(
104 &mut signature.type_union,
105 &codebase.symbols,
106 Some(&property_reference_source),
107 symbol_references,
108 userland_force_repopulation,
109 );
110 }
111
112 if let Some(default) = property_metadata.default_type_metadata.as_mut() {
113 populate_union_type(
114 &mut default.type_union,
115 &codebase.symbols,
116 Some(&property_reference_source),
117 symbol_references,
118 userland_force_repopulation,
119 );
120 }
121 }
122
123 for map in metadata.template_extended_parameters.values_mut() {
124 for (_, v) in map {
125 if v.needs_population() || userland_force_repopulation {
126 populate_union_type(
127 v,
128 &codebase.symbols,
129 Some(&class_like_reference_source),
130 symbol_references,
131 userland_force_repopulation,
132 );
133 }
134 }
135 }
136
137 for (_, map) in &mut metadata.template_types {
138 for (_, v) in map {
139 if v.needs_population() || userland_force_repopulation {
140 populate_union_type(
141 v,
142 &codebase.symbols,
143 Some(&class_like_reference_source),
144 symbol_references,
145 userland_force_repopulation,
146 );
147 }
148 }
149 }
150
151 for (constant_name, constant) in &mut metadata.constants {
152 let constant_reference_source = ReferenceSource::ClassLikeMember(true, *name, *constant_name);
153
154 for attribute_metadata in &constant.attributes {
155 symbol_references.add_class_member_reference_to_symbol(
156 (*name, *constant_name),
157 attribute_metadata.name,
158 true,
159 );
160 }
161
162 if let Some(signature) = &mut constant.type_metadata {
163 populate_union_type(
164 &mut signature.type_union,
165 &codebase.symbols,
166 Some(&constant_reference_source),
167 symbol_references,
168 userland_force_repopulation,
169 );
170 }
171
172 if let Some(inferred) = &mut constant.inferred_type {
173 populate_atomic_type(
174 inferred,
175 &codebase.symbols,
176 Some(&constant_reference_source),
177 symbol_references,
178 userland_force_repopulation,
179 );
180 }
181 }
182
183 for (enum_case_name, enum_case) in &mut metadata.enum_cases {
184 let enum_case_reference_source = ReferenceSource::ClassLikeMember(true, *name, *enum_case_name);
185
186 for attribute_metadata in &enum_case.attributes {
187 symbol_references.add_class_member_reference_to_symbol(
188 (*name, *enum_case_name),
189 attribute_metadata.name,
190 true,
191 );
192 }
193
194 if let Some(value_type) = &mut enum_case.value_type {
195 populate_atomic_type(
196 value_type,
197 &codebase.symbols,
198 Some(&enum_case_reference_source),
199 symbol_references,
200 userland_force_repopulation,
201 );
202 }
203 }
204
205 if let Some(enum_type) = &mut metadata.enum_type {
206 populate_atomic_type(
207 enum_type,
208 &codebase.symbols,
209 Some(&ReferenceSource::Symbol(true, *name)),
210 symbol_references,
211 userland_force_repopulation,
212 );
213 }
214 }
215
216 for (name, constant) in &mut codebase.constants {
217 for attribute_metadata in &constant.attributes {
218 symbol_references.add_symbol_reference_to_symbol(*name, attribute_metadata.name, true);
219 }
220
221 if let Some(inferred_type) = &mut constant.inferred_type {
222 populate_union_type(
223 inferred_type,
224 &codebase.symbols,
225 Some(&ReferenceSource::Symbol(true, *name)),
226 symbol_references,
227 !safe_symbols.contains(name),
228 );
229 }
230 }
231
232 let mut direct_classlike_descendants = AtomMap::default();
233 let mut all_classlike_descendants = AtomMap::default();
234
235 for (class_like_name, class_like_metadata) in &codebase.class_likes {
236 for parent_interface in &class_like_metadata.all_parent_interfaces {
237 all_classlike_descendants
238 .entry(*parent_interface)
239 .or_insert_with(AtomSet::default)
240 .insert(*class_like_name);
241 }
242
243 for parent_interface in &class_like_metadata.direct_parent_interfaces {
244 direct_classlike_descendants
245 .entry(*parent_interface)
246 .or_insert_with(AtomSet::default)
247 .insert(*class_like_name);
248 }
249
250 for parent_class in &class_like_metadata.all_parent_classes {
251 all_classlike_descendants.entry(*parent_class).or_insert_with(AtomSet::default).insert(*class_like_name);
252 }
253
254 for used_trait in &class_like_metadata.used_traits {
255 all_classlike_descendants.entry(*used_trait).or_default().insert(*class_like_name);
256 }
257
258 if let Some(parent_class) = &class_like_metadata.direct_parent_class {
259 direct_classlike_descendants.entry(*parent_class).or_insert_with(AtomSet::default).insert(*class_like_name);
260 }
261 }
262
263 codebase.all_class_like_descendants = all_classlike_descendants;
264 codebase.direct_classlike_descendants = direct_classlike_descendants;
265 codebase.safe_symbols = safe_symbols;
266 codebase.safe_symbol_members = safe_symbol_members;
267}
268
269fn populate_function_like_metadata(
274 metadata: &mut FunctionLikeMetadata,
275 codebase_symbols: &Symbols,
276 reference_source: &ReferenceSource,
277 symbol_references: &mut SymbolReferences,
278 force_type_population: bool,
279) {
280 if metadata.flags.is_populated() && !force_type_population {
282 return;
283 }
284
285 for attribute_metadata in metadata.get_attributes() {
286 match reference_source {
287 ReferenceSource::Symbol(_, a) => {
288 symbol_references.add_symbol_reference_to_symbol(*a, attribute_metadata.name, true)
289 }
290 ReferenceSource::ClassLikeMember(_, a, b) => {
291 symbol_references.add_class_member_reference_to_symbol((*a, *b), attribute_metadata.name, true)
292 }
293 }
294 }
295
296 if let Some(return_type) = metadata.return_type_declaration_metadata.as_mut() {
297 populate_union_type(
298 &mut return_type.type_union,
299 codebase_symbols,
300 Some(reference_source),
301 symbol_references,
302 force_type_population,
303 );
304 }
305
306 if let Some(return_type) = metadata.return_type_metadata.as_mut() {
307 populate_union_type(
308 &mut return_type.type_union,
309 codebase_symbols,
310 Some(reference_source),
311 symbol_references,
312 force_type_population,
313 );
314 }
315
316 for parameter_metadata in metadata.get_parameters_mut() {
317 if let Some(type_metadata) = parameter_metadata.type_metadata.as_mut() {
318 populate_union_type(
319 &mut type_metadata.type_union,
320 codebase_symbols,
321 Some(reference_source),
322 symbol_references,
323 force_type_population,
324 );
325 }
326
327 if let Some(type_metadata) = parameter_metadata.out_type.as_mut() {
328 populate_union_type(
329 &mut type_metadata.type_union,
330 codebase_symbols,
331 Some(reference_source),
332 symbol_references,
333 force_type_population,
334 );
335 }
336
337 if let Some(type_metadata) = parameter_metadata.default_type.as_mut() {
338 populate_union_type(
339 &mut type_metadata.type_union,
340 codebase_symbols,
341 Some(reference_source),
342 symbol_references,
343 force_type_population,
344 );
345 }
346
347 for attribute_metadata in ¶meter_metadata.attributes {
348 match reference_source {
349 ReferenceSource::Symbol(in_signature, a) => {
350 symbol_references.add_symbol_reference_to_symbol(*a, attribute_metadata.name, *in_signature)
351 }
352 ReferenceSource::ClassLikeMember(in_signature, a, b) => symbol_references
353 .add_class_member_reference_to_symbol((*a, *b), attribute_metadata.name, *in_signature),
354 }
355 }
356 }
357
358 for (_, type_parameter_map) in &mut metadata.template_types {
359 for (_, type_parameter) in type_parameter_map {
360 if force_type_population || type_parameter.needs_population() {
361 populate_union_type(
362 type_parameter,
363 codebase_symbols,
364 Some(reference_source),
365 symbol_references,
366 force_type_population,
367 );
368 }
369 }
370 }
371
372 if let Some(type_resolution_context) = metadata.type_resolution_context.as_mut() {
373 for (_, type_parameter_map) in type_resolution_context.get_template_definitions_mut() {
374 for (_, type_parameter) in type_parameter_map {
375 if force_type_population || type_parameter.needs_population() {
376 populate_union_type(
377 type_parameter,
378 codebase_symbols,
379 Some(reference_source),
380 symbol_references,
381 force_type_population,
382 );
383 }
384 }
385 }
386 }
387
388 if let Some(method_metadata) = metadata.method_metadata.as_mut() {
389 for where_constraint in method_metadata.where_constraints.values_mut() {
390 populate_union_type(
391 &mut where_constraint.type_union,
392 codebase_symbols,
393 Some(reference_source),
394 symbol_references,
395 force_type_population,
396 );
397 }
398 }
399
400 for thrown_type in &mut metadata.thrown_types {
401 populate_union_type(
402 &mut thrown_type.type_union,
403 codebase_symbols,
404 Some(reference_source),
405 symbol_references,
406 force_type_population,
407 );
408 }
409
410 for assertions in metadata.assertions.values_mut() {
411 for assertion in assertions {
412 if let Some(assertion_type) = assertion.get_type_mut() {
413 populate_atomic_type(
414 assertion_type,
415 codebase_symbols,
416 Some(reference_source),
417 symbol_references,
418 force_type_population,
419 );
420 }
421 }
422 }
423
424 for assertions in metadata.if_true_assertions.values_mut() {
425 for assertion in assertions {
426 if let Some(assertion_type) = assertion.get_type_mut() {
427 populate_atomic_type(
428 assertion_type,
429 codebase_symbols,
430 Some(reference_source),
431 symbol_references,
432 force_type_population,
433 );
434 }
435 }
436 }
437
438 for assertions in metadata.if_false_assertions.values_mut() {
439 for assertion in assertions {
440 if let Some(assertion_type) = assertion.get_type_mut() {
441 populate_atomic_type(
442 assertion_type,
443 codebase_symbols,
444 Some(reference_source),
445 symbol_references,
446 force_type_population,
447 );
448 }
449 }
450 }
451
452 metadata.flags |= MetadataFlags::POPULATED;
453}
454
455fn populate_class_like_metadata(
461 classlike_name: &Atom,
462 codebase: &mut CodebaseMetadata,
463 symbol_references: &mut SymbolReferences,
464 safe_symbols: &AtomSet,
465) {
466 if let Some(metadata) = codebase.class_likes.get(classlike_name)
467 && metadata.flags.is_populated()
468 {
469 return; }
471
472 let mut metadata = if let Some(metadata) = codebase.class_likes.remove(classlike_name) {
473 metadata
474 } else {
475 return;
476 };
477
478 for attribute_metadata in &metadata.attributes {
479 symbol_references.add_symbol_reference_to_symbol(metadata.name, attribute_metadata.name, true);
480 }
481
482 for property_name in metadata.get_property_names() {
483 metadata.add_declaring_property_id(property_name, *classlike_name);
484 }
485
486 for method_name in &metadata.methods {
487 metadata.appearing_method_ids.insert(*method_name, *classlike_name);
488 metadata.declaring_method_ids.insert(*method_name, *classlike_name);
489 }
490
491 let force_repopulation = !safe_symbols.contains(classlike_name);
492 for parameter_types in metadata.template_extended_offsets.values_mut() {
493 for parameter_type in parameter_types {
494 populate_union_type(
495 parameter_type,
496 &codebase.symbols,
497 Some(&ReferenceSource::Symbol(true, *classlike_name)),
498 symbol_references,
499 force_repopulation,
500 );
501 }
502 }
503
504 for trait_name in metadata.used_traits.iter().copied().collect::<Vec<_>>() {
505 populate_metadata_from_trait(&mut metadata, codebase, trait_name, symbol_references, safe_symbols);
506 }
507
508 if let Some(parent_classname) = metadata.direct_parent_class {
509 populate_metadata_from_parent_class_like(
510 &mut metadata,
511 codebase,
512 parent_classname,
513 symbol_references,
514 safe_symbols,
515 );
516 }
517
518 let direct_parent_interfaces = metadata.direct_parent_interfaces.clone();
519 for direct_parent_interface in direct_parent_interfaces {
520 populate_interface_metadata_from_parent_interface(
521 &mut metadata,
522 codebase,
523 direct_parent_interface,
524 symbol_references,
525 safe_symbols,
526 );
527 }
528
529 for required_class in metadata.require_extends.iter().copied().collect::<Vec<_>>() {
530 populate_metadata_from_required_class_like(
531 &mut metadata,
532 codebase,
533 required_class,
534 symbol_references,
535 safe_symbols,
536 );
537 }
538
539 for required_interface in metadata.require_implements.iter().copied().collect::<Vec<_>>() {
540 populate_interface_metadata_from_parent_interface(
541 &mut metadata,
542 codebase,
543 required_interface,
544 symbol_references,
545 safe_symbols,
546 );
547 }
548
549 if metadata.flags.is_readonly() {
551 for property_metadata in metadata.properties.values_mut() {
552 if !property_metadata.flags.is_static() {
553 property_metadata.flags |= MetadataFlags::READONLY;
554 }
555 }
556 }
557
558 metadata.mark_as_populated();
559 codebase.class_likes.insert(*classlike_name, metadata);
560}
561
562fn populate_interface_metadata_from_parent_interface(
564 metadata: &mut ClassLikeMetadata,
565 codebase: &mut CodebaseMetadata,
566 parent_interface: Atom,
567 symbol_references: &mut SymbolReferences,
568 safe_symbols: &AtomSet,
569) {
570 populate_class_like_metadata(&parent_interface, codebase, symbol_references, safe_symbols);
571
572 symbol_references.add_symbol_reference_to_symbol(metadata.name, parent_interface, true);
573
574 let parent_interface_metadata = if let Some(parent_meta) = codebase.class_likes.get(&parent_interface) {
575 parent_meta
576 } else {
577 metadata.invalid_dependencies.insert(parent_interface);
578 return;
579 };
580
581 for (interface_constant_name, interface_constant_metadata) in &parent_interface_metadata.constants {
582 if !metadata.constants.contains_key(interface_constant_name) {
583 metadata.constants.insert(*interface_constant_name, interface_constant_metadata.clone());
584 }
585 }
586
587 metadata.all_parent_interfaces.extend(parent_interface_metadata.all_parent_interfaces.iter().copied());
588 metadata.invalid_dependencies.extend(parent_interface_metadata.invalid_dependencies.iter().copied());
589
590 if let Some(inheritors) = &parent_interface_metadata.permitted_inheritors {
591 metadata.permitted_inheritors.get_or_insert_default().extend(inheritors.iter().copied());
592 }
593
594 extend_template_parameters(metadata, parent_interface_metadata);
596 inherit_methods_from_parent(metadata, parent_interface_metadata, codebase);
599 inherit_properties_from_parent(metadata, parent_interface_metadata);
600}
601
602fn populate_metadata_from_parent_class_like(
604 metadata: &mut ClassLikeMetadata,
605 codebase: &mut CodebaseMetadata,
606 parent_class: Atom,
607 symbol_references: &mut SymbolReferences,
608 safe_symbols: &AtomSet,
609) {
610 populate_class_like_metadata(&parent_class, codebase, symbol_references, safe_symbols);
611
612 symbol_references.add_symbol_reference_to_symbol(metadata.name, parent_class, true);
613
614 let parent_metadata = if let Some(parent_meta) = codebase.class_likes.get(&parent_class) {
615 parent_meta
616 } else {
617 metadata.invalid_dependencies.insert(parent_class);
618 return;
619 };
620
621 metadata.all_parent_classes.extend(parent_metadata.all_parent_classes.iter().copied());
622 metadata.all_parent_interfaces.extend(parent_metadata.all_parent_interfaces.iter().copied());
623 metadata.used_traits.extend(parent_metadata.used_traits.iter().copied());
624 metadata.invalid_dependencies.extend(parent_metadata.invalid_dependencies.iter().copied());
625
626 if let Some(inheritors) = &parent_metadata.permitted_inheritors {
627 metadata.permitted_inheritors.get_or_insert_default().extend(inheritors.iter().copied());
628 }
629
630 extend_template_parameters(metadata, parent_metadata);
631
632 inherit_methods_from_parent(metadata, parent_metadata, codebase);
633 inherit_properties_from_parent(metadata, parent_metadata);
634
635 for (parent_constant_name, parent_constant_metadata) in &parent_metadata.constants {
636 if !metadata.constants.contains_key(parent_constant_name) {
637 metadata.constants.insert(*parent_constant_name, parent_constant_metadata.clone());
638 }
639 }
640
641 if parent_metadata.flags.has_consistent_templates() {
642 metadata.flags |= MetadataFlags::CONSISTENT_TEMPLATES;
643 }
644}
645
646fn populate_metadata_from_required_class_like(
648 metadata: &mut ClassLikeMetadata,
649 codebase: &mut CodebaseMetadata,
650 parent_class: Atom,
651 symbol_references: &mut SymbolReferences,
652 safe_symbols: &AtomSet,
653) {
654 populate_class_like_metadata(&parent_class, codebase, symbol_references, safe_symbols);
655
656 symbol_references.add_symbol_reference_to_symbol(metadata.name, parent_class, true);
657
658 let parent_metadata = if let Some(parent_meta) = codebase.class_likes.get(&parent_class) {
659 parent_meta
660 } else {
661 metadata.invalid_dependencies.insert(parent_class);
662 return;
663 };
664
665 metadata.require_extends.extend(parent_metadata.all_parent_classes.iter().copied());
666 metadata.require_implements.extend(parent_metadata.all_parent_interfaces.iter().copied());
667}
668
669fn populate_metadata_from_trait(
671 metadata: &mut ClassLikeMetadata,
672 codebase: &mut CodebaseMetadata,
673 trait_name: Atom,
674 symbol_references: &mut SymbolReferences,
675 safe_symbols: &AtomSet,
676) {
677 populate_class_like_metadata(&trait_name, codebase, symbol_references, safe_symbols);
678
679 symbol_references.add_symbol_reference_to_symbol(metadata.name, trait_name, true);
680
681 let Some(trait_metadata) = codebase.class_likes.get(&trait_name) else {
682 metadata.invalid_dependencies.insert(trait_name);
683 return;
684 };
685
686 for (trait_constant_name, trait_constant_metadata) in &trait_metadata.constants {
688 if !metadata.constants.contains_key(trait_constant_name) {
689 metadata.constants.insert(*trait_constant_name, trait_constant_metadata.clone());
690 }
691 }
692
693 metadata.all_parent_interfaces.extend(trait_metadata.direct_parent_interfaces.iter().copied());
695
696 metadata.invalid_dependencies.extend(trait_metadata.invalid_dependencies.iter().copied());
698
699 extend_template_parameters(metadata, trait_metadata);
701
702 inherit_methods_from_parent(metadata, trait_metadata, codebase);
704 inherit_properties_from_parent(metadata, trait_metadata);
705}
706
707fn inherit_methods_from_parent(
710 metadata: &mut ClassLikeMetadata,
711 parent_metadata: &ClassLikeMetadata,
712 codebase: &CodebaseMetadata,
713) {
714 let class_like_name = metadata.name;
715 let is_trait = metadata.kind.is_trait();
716
717 for (method_name, appearing_class_like) in &parent_metadata.appearing_method_ids {
718 if metadata.has_appearing_method(method_name) {
719 continue;
720 }
721
722 metadata
723 .appearing_method_ids
724 .insert(*method_name, if is_trait { class_like_name } else { *appearing_class_like });
725
726 if codebase.function_likes.contains_key(&(class_like_name, *method_name)) {
727 metadata.potential_declaring_method_ids.insert(*method_name, AtomSet::from_iter([class_like_name]));
728 } else {
729 if let Some(parent_potential_method_ids) = parent_metadata.get_potential_declaring_method_id(method_name) {
730 metadata.potential_declaring_method_ids.insert(*method_name, parent_potential_method_ids.clone());
731 }
732
733 metadata.add_potential_declaring_method(*method_name, class_like_name);
734 metadata.add_potential_declaring_method(*method_name, parent_metadata.name);
735 }
736 }
737
738 for (method_name, declaring_class) in &parent_metadata.inheritable_method_ids {
739 if !method_name.eq(&atom("__construct")) || parent_metadata.flags.has_consistent_constructor() {
740 if !parent_metadata.kind.is_trait() || is_method_abstract(codebase, declaring_class, method_name) {
741 metadata.add_overridden_method_parent(*method_name, *declaring_class);
742 }
743
744 if let Some(map) = metadata.overridden_method_ids.get_mut(method_name)
745 && let Some(overridden_method_ids) = parent_metadata.overridden_method_ids.get(method_name)
746 {
747 map.extend(overridden_method_ids.iter().copied());
748 }
749 }
750
751 let mut aliased_method_names = vec![*method_name];
752 if parent_metadata.kind.is_trait() {
753 aliased_method_names
754 .extend(metadata.get_trait_alias_map().iter().filter(|(_, v)| *v == method_name).map(|(k, _)| *k));
755 }
756
757 for aliased_method_name in aliased_method_names {
758 let implementing_method_id = metadata.declaring_method_ids.get(&aliased_method_name);
759 if let Some(implementing_method_id) = implementing_method_id
760 && !is_method_abstract(codebase, implementing_method_id, &aliased_method_name)
761 {
762 continue;
763 }
764
765 metadata.declaring_method_ids.insert(aliased_method_name, *declaring_class);
766 metadata.inheritable_method_ids.insert(aliased_method_name, *declaring_class);
767 }
768 }
769}
770
771fn inherit_properties_from_parent(metadata: &mut ClassLikeMetadata, parent_metadata: &ClassLikeMetadata) {
774 let classlike_name = metadata.name;
775 let is_trait = metadata.kind.is_trait();
776 let parent_is_trait = parent_metadata.kind.is_trait();
777
778 for (property_name, appearing_classlike) in &parent_metadata.appearing_property_ids {
779 if metadata.has_appearing_property(property_name) {
780 continue;
781 }
782
783 if !parent_is_trait
784 && let Some(parent_property_metadata) = parent_metadata.properties.get(property_name)
785 && parent_property_metadata.is_final()
786 {
787 continue;
788 }
789
790 metadata
791 .appearing_property_ids
792 .insert(*property_name, if is_trait { classlike_name } else { *appearing_classlike });
793 }
794
795 for (property_name, declaring_classlike) in &parent_metadata.declaring_property_ids {
796 if metadata.declaring_property_ids.contains_key(property_name) {
797 continue;
798 }
799
800 if !parent_is_trait
801 && let Some(parent_property_metadata) = parent_metadata.properties.get(property_name)
802 && parent_property_metadata.is_final()
803 {
804 continue;
805 }
806
807 metadata.declaring_property_ids.insert(*property_name, *declaring_classlike);
808 }
809
810 for (property_name, inheritable_classlike) in &parent_metadata.inheritable_property_ids {
811 let mut is_overridable = true;
812 if !parent_is_trait {
813 if let Some(parent_property_metadata) = parent_metadata.properties.get(property_name)
814 && parent_property_metadata.is_final()
815 {
816 is_overridable = false;
817 }
818
819 if is_overridable {
820 metadata.overridden_property_ids.entry(*property_name).or_default().insert(*inheritable_classlike);
821 }
822 }
823
824 if is_overridable {
825 metadata.inheritable_property_ids.insert(*property_name, *inheritable_classlike);
826 }
827 }
828}
829
830fn extend_template_parameters(metadata: &mut ClassLikeMetadata, parent_metadata: &ClassLikeMetadata) {
833 let parent_name = parent_metadata.name;
834
835 if !parent_metadata.template_types.is_empty() {
836 metadata.template_extended_parameters.entry(parent_name).or_default();
837
838 if let Some(parent_offsets) = metadata.template_extended_offsets.get(&parent_name).cloned() {
839 let parent_template_type_names = parent_metadata.get_template_type_names();
840
841 for (i, extended_type_arc) in parent_offsets.into_iter().enumerate() {
842 if let Some(mapped_name) = parent_template_type_names.get(i).copied() {
843 metadata.add_template_extended_parameter(parent_name, mapped_name, extended_type_arc);
844 }
845 }
846
847 let current_child_extended_params = metadata.template_extended_parameters.clone();
848 for (grandparent_fqcn, type_map) in &parent_metadata.template_extended_parameters {
849 for (template_name, type_to_resolve_arc) in type_map {
850 let resolved_type = extend_type(type_to_resolve_arc, ¤t_child_extended_params);
851
852 metadata.add_template_extended_parameter(*grandparent_fqcn, *template_name, resolved_type);
853 }
854 }
855 } else {
856 for (parameter_name, parameter_type_map) in &parent_metadata.template_types {
857 for (_, parameter_type) in parameter_type_map {
858 metadata.add_template_extended_parameter(parent_name, *parameter_name, parameter_type.clone());
859 }
860 }
861
862 metadata.extend_template_extended_parameters(parent_metadata.template_extended_parameters.clone());
863 }
864 } else {
865 metadata.extend_template_extended_parameters(parent_metadata.template_extended_parameters.clone());
867 }
868}
869
870fn extend_type(
876 extended_type: &TUnion,
877 template_extended_parameters: &AtomMap<IndexMap<Atom, TUnion, RandomState>>,
878) -> TUnion {
879 if !extended_type.has_template() {
880 return extended_type.clone();
881 }
882
883 let mut extended_types = Vec::new();
884
885 let mut worklist = extended_type.types.clone().into_owned();
886 while let Some(atomic_type) = worklist.pop() {
887 if let TAtomic::GenericParameter(TGenericParameter {
888 parameter_name,
889 defining_entity: GenericParent::ClassLike(defining_entity),
890 ..
891 }) = &atomic_type
892 && let Some(extended_parameters) = template_extended_parameters.get(defining_entity)
893 && let Some(referenced_type) = extended_parameters.get(parameter_name)
894 {
895 extended_types.extend(referenced_type.types.clone().into_owned());
896 continue;
897 }
898
899 extended_types.push(atomic_type);
900 }
901
902 TUnion::from_vec(extended_types)
903}