1use ahash::HashMap;
2use ahash::HashSet;
3use ahash::RandomState;
4use indexmap::IndexMap;
5use serde::Deserialize;
6use serde::Serialize;
7
8use mago_interner::StringIdentifier;
9use mago_reporting::Issue;
10use mago_span::Span;
11
12use crate::flags::attribute::AttributeFlags;
13use crate::metadata::attribute::AttributeMetadata;
14use crate::metadata::class_like_constant::ClassLikeConstantMetadata;
15use crate::metadata::enum_case::EnumCaseMetadata;
16use crate::metadata::property::PropertyMetadata;
17use crate::misc::GenericParent;
18use crate::symbol::SymbolKind;
19use crate::ttype::atomic::TAtomic;
20use crate::ttype::template::variance::Variance;
21use crate::ttype::union::TUnion;
22use crate::visibility::Visibility;
23
24type TemplateTuple = (StringIdentifier, Vec<(GenericParent, TUnion)>);
25
26#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
31pub struct ClassLikeMetadata {
32 pub name: StringIdentifier,
33 pub original_name: StringIdentifier,
34 pub span: Span,
35 pub direct_parent_interfaces: Vec<StringIdentifier>,
36 pub all_parent_interfaces: Vec<StringIdentifier>,
37 pub direct_parent_class: Option<StringIdentifier>,
38 pub require_extends: Vec<StringIdentifier>,
39 pub require_implements: Vec<StringIdentifier>,
40 pub all_parent_classes: Vec<StringIdentifier>,
41 pub used_traits: HashSet<StringIdentifier>,
42 pub trait_alias_map: HashMap<StringIdentifier, StringIdentifier>,
43 pub trait_visibility_map: HashMap<StringIdentifier, Visibility>,
44 pub trait_final_map: HashSet<StringIdentifier>,
45 pub child_class_likes: Option<HashSet<StringIdentifier>>,
46 pub name_span: Option<Span>,
47 pub is_abstract: bool,
48 pub is_final: bool,
49 pub is_immutable: bool,
50 pub is_readonly: bool,
51 pub is_deprecated: bool,
52 pub is_enum_interface: bool,
53 pub specialized_instance: bool,
54 pub is_populated: bool,
55 pub is_internal: bool,
56 pub is_mutation_free: bool,
57 pub is_external_mutation_free: bool,
58 pub allows_private_mutation: bool,
59 pub has_consistent_constructor: bool,
60 pub has_consistent_templates: bool,
61 pub kind: SymbolKind,
62 pub template_types: Vec<TemplateTuple>,
63 pub template_readonly: HashSet<StringIdentifier>,
64 pub template_variance: HashMap<usize, Variance>,
65 pub template_extended_offsets: HashMap<StringIdentifier, Vec<TUnion>>,
66 pub template_extended_parameters: HashMap<StringIdentifier, IndexMap<StringIdentifier, TUnion, RandomState>>,
67 pub template_type_extends_count: HashMap<StringIdentifier, usize>,
68 pub template_type_implements_count: HashMap<StringIdentifier, usize>,
69 pub template_type_uses_count: HashMap<StringIdentifier, usize>,
70 pub methods: Vec<StringIdentifier>,
71 pub pseudo_methods: Vec<StringIdentifier>,
72 pub static_pseudo_methods: Vec<StringIdentifier>,
73 pub declaring_method_ids: HashMap<StringIdentifier, StringIdentifier>,
74 pub appearing_method_ids: HashMap<StringIdentifier, StringIdentifier>,
75 pub overridden_method_ids: HashMap<StringIdentifier, HashSet<StringIdentifier>>,
76 pub inheritable_method_ids: HashMap<StringIdentifier, StringIdentifier>,
77 pub potential_declaring_method_ids: HashMap<StringIdentifier, HashSet<StringIdentifier>>,
78 pub properties: HashMap<StringIdentifier, PropertyMetadata>,
79 pub appearing_property_ids: HashMap<StringIdentifier, StringIdentifier>,
80 pub declaring_property_ids: HashMap<StringIdentifier, StringIdentifier>,
81 pub inheritable_property_ids: HashMap<StringIdentifier, StringIdentifier>,
82 pub overridden_property_ids: HashMap<StringIdentifier, Vec<StringIdentifier>>,
83 pub initialized_properties: Vec<StringIdentifier>,
84 pub constants: IndexMap<StringIdentifier, ClassLikeConstantMetadata, RandomState>,
85 pub enum_cases: IndexMap<StringIdentifier, EnumCaseMetadata, RandomState>,
86 pub invalid_dependencies: Vec<StringIdentifier>,
87 pub attributes: Vec<AttributeMetadata>,
88 pub enum_type: Option<TAtomic>,
89 pub has_sealed_methods: Option<bool>,
90 pub has_sealed_properties: Option<bool>,
91 pub permitted_inheritors: Option<HashSet<StringIdentifier>>,
92 pub issues: Vec<Issue>,
93 pub attribute_flags: Option<AttributeFlags>,
94 pub unchecked: bool,
95}
96
97impl ClassLikeMetadata {
98 pub fn new(
99 name: StringIdentifier,
100 original_name: StringIdentifier,
101 span: Span,
102 name_span: Option<Span>,
103 ) -> ClassLikeMetadata {
104 ClassLikeMetadata {
105 constants: IndexMap::with_hasher(RandomState::new()),
106 enum_cases: IndexMap::with_hasher(RandomState::new()),
107 specialized_instance: false,
108 is_populated: false,
109 is_deprecated: false,
110 is_abstract: false,
111 is_final: false,
112 is_readonly: false,
113 is_immutable: false,
114 is_internal: false,
115 is_mutation_free: false,
116 is_external_mutation_free: false,
117 allows_private_mutation: false,
118 has_consistent_constructor: false,
119 has_consistent_templates: false,
120 is_enum_interface: false,
121 kind: SymbolKind::Class,
122 direct_parent_interfaces: vec![],
123 all_parent_classes: vec![],
124 appearing_method_ids: HashMap::default(),
125 attributes: Vec::new(),
126 all_parent_interfaces: vec![],
127 declaring_method_ids: HashMap::default(),
128 appearing_property_ids: HashMap::default(),
129 declaring_property_ids: HashMap::default(),
130 direct_parent_class: None,
131 require_extends: vec![],
132 require_implements: vec![],
133 inheritable_method_ids: HashMap::default(),
134 enum_type: None,
135 inheritable_property_ids: HashMap::default(),
136 initialized_properties: vec![],
137 invalid_dependencies: Vec::new(),
138 span,
139 name_span,
140 methods: vec![],
141 pseudo_methods: vec![],
142 static_pseudo_methods: vec![],
143 overridden_method_ids: HashMap::default(),
144 overridden_property_ids: HashMap::default(),
145 potential_declaring_method_ids: HashMap::default(),
146 properties: HashMap::default(),
147 template_variance: HashMap::default(),
148 template_type_extends_count: HashMap::default(),
149 template_extended_parameters: HashMap::default(),
150 template_extended_offsets: HashMap::default(),
151 template_type_implements_count: HashMap::default(),
152 template_type_uses_count: HashMap::default(),
153 template_types: vec![],
154 used_traits: HashSet::default(),
155 trait_alias_map: HashMap::default(),
156 trait_visibility_map: HashMap::default(),
157 trait_final_map: HashSet::default(),
158 name,
159 original_name,
160 child_class_likes: None,
161 template_readonly: HashSet::default(),
162 has_sealed_methods: None,
163 has_sealed_properties: None,
164 permitted_inheritors: None,
165 issues: vec![],
166 attribute_flags: None,
167 unchecked: false,
168 }
169 }
170
171 #[inline]
173 pub fn is_user_defined(&self) -> bool {
174 self.span.start.source.category().is_user_defined()
175 }
176
177 #[inline]
179 pub fn get_trait_alias_map(&self) -> &HashMap<StringIdentifier, StringIdentifier> {
180 &self.trait_alias_map
181 }
182
183 #[inline]
185 pub fn get_template_type_names(&self) -> Vec<StringIdentifier> {
186 self.template_types.iter().map(|(name, _)| *name).collect()
187 }
188
189 #[inline]
191 pub fn get_template_type(&self, name: &StringIdentifier) -> Option<&Vec<(GenericParent, TUnion)>> {
192 self.template_types.iter().find_map(|(param_name, types)| if param_name == name { Some(types) } else { None })
193 }
194
195 #[inline]
197 pub fn get_template_type_with_index(
198 &self,
199 name: &StringIdentifier,
200 ) -> Option<(usize, &Vec<(GenericParent, TUnion)>)> {
201 self.template_types
202 .iter()
203 .enumerate()
204 .find_map(|(index, (param_name, types))| if param_name == name { Some((index, types)) } else { None })
205 }
206
207 pub fn get_template_for_index(&self, index: usize) -> Option<(StringIdentifier, &Vec<(GenericParent, TUnion)>)> {
208 self.template_types.get(index).map(|(name, types)| (*name, types))
209 }
210
211 pub fn get_template_name_for_index(&self, index: usize) -> Option<StringIdentifier> {
212 self.template_types.get(index).map(|(name, _)| *name)
213 }
214
215 pub fn get_template_index_for_name(&self, name: &StringIdentifier) -> Option<usize> {
216 self.template_types.iter().position(|(param_name, _)| param_name == name)
217 }
218
219 #[inline]
221 pub fn has_parent(&self, parent: &StringIdentifier) -> bool {
222 self.all_parent_classes.contains(parent) || self.all_parent_interfaces.contains(parent)
223 }
224
225 #[inline]
227 pub fn has_template_extended_parameter(&self, parent: &StringIdentifier) -> bool {
228 self.template_extended_parameters.contains_key(parent)
229 }
230
231 #[inline]
233 pub fn get_methods(&self) -> &[StringIdentifier] {
234 &self.methods
235 }
236
237 #[inline]
239 pub fn has_method(&self, method: &StringIdentifier) -> bool {
240 self.methods.contains(method)
241 }
242
243 #[inline]
245 pub fn get_declaring_method_ids(&self) -> &HashMap<StringIdentifier, StringIdentifier> {
246 &self.declaring_method_ids
247 }
248
249 #[inline]
251 pub fn get_appearing_method_ids(&self) -> &HashMap<StringIdentifier, StringIdentifier> {
252 &self.appearing_method_ids
253 }
254
255 #[inline]
257 pub fn has_appearing_method(&self, method: &StringIdentifier) -> bool {
258 self.appearing_method_ids.contains_key(method)
259 }
260
261 #[inline]
263 pub fn get_overridden_method_ids(&self) -> &HashMap<StringIdentifier, HashSet<StringIdentifier>> {
264 &self.overridden_method_ids
265 }
266
267 #[inline]
269 pub fn get_overridden_method_id(&self, method: &StringIdentifier) -> Option<&HashSet<StringIdentifier>> {
270 self.overridden_method_ids.get(method)
271 }
272
273 #[inline]
275 pub fn get_overridden_method_id_mut(
276 &mut self,
277 method: &StringIdentifier,
278 ) -> Option<&mut HashSet<StringIdentifier>> {
279 self.overridden_method_ids.get_mut(method)
280 }
281
282 #[inline]
284 pub fn get_potential_declaring_method_id(&self, method: &StringIdentifier) -> Option<&HashSet<StringIdentifier>> {
285 self.potential_declaring_method_ids.get(method)
286 }
287
288 #[inline]
290 pub fn get_property_names(&self) -> Vec<StringIdentifier> {
291 self.properties.keys().copied().collect()
292 }
293
294 #[inline]
296 pub fn has_appearing_property(&self, name: &StringIdentifier) -> bool {
297 self.appearing_property_ids.contains_key(name)
298 }
299
300 #[inline]
302 pub fn has_declaring_property(&self, name: &StringIdentifier) -> bool {
303 self.declaring_property_ids.contains_key(name)
304 }
305
306 #[inline]
308 pub fn take_issues(&mut self) -> Vec<Issue> {
309 std::mem::take(&mut self.issues)
310 }
311
312 #[inline]
314 pub fn add_direct_parent_interface(&mut self, interface: StringIdentifier) {
315 self.direct_parent_interfaces.push(interface);
316 self.all_parent_interfaces.push(interface);
317 }
318
319 #[inline]
321 pub fn add_all_parent_interface(&mut self, interface: StringIdentifier) {
322 self.all_parent_interfaces.push(interface);
323 }
324
325 #[inline]
327 pub fn add_all_parent_interfaces(&mut self, interfaces: impl IntoIterator<Item = StringIdentifier>) {
328 self.all_parent_interfaces.extend(interfaces);
329 }
330
331 #[inline]
333 pub fn add_require_extend(&mut self, require: StringIdentifier) {
334 self.all_parent_classes.push(require);
335 self.require_extends.push(require);
336 }
337
338 #[inline]
340 pub fn add_require_implement(&mut self, require: StringIdentifier) {
341 self.all_parent_interfaces.push(require);
342 self.require_implements.push(require);
343 }
344
345 #[inline]
347 pub fn add_all_parent_classes(&mut self, classes: impl IntoIterator<Item = StringIdentifier>) {
348 self.all_parent_classes.extend(classes);
349 }
350
351 #[inline]
353 pub fn add_used_trait(&mut self, trait_name: StringIdentifier) -> bool {
354 self.used_traits.insert(trait_name)
355 }
356
357 #[inline]
359 pub fn add_used_traits(&mut self, traits: impl IntoIterator<Item = StringIdentifier>) {
360 self.used_traits.extend(traits);
361 }
362
363 #[inline]
365 pub fn add_trait_alias(&mut self, method: StringIdentifier, alias: StringIdentifier) -> Option<StringIdentifier> {
366 self.trait_alias_map.insert(method, alias)
367 }
368
369 #[inline]
371 pub fn add_trait_visibility(&mut self, method: StringIdentifier, visibility: Visibility) -> Option<Visibility> {
372 self.trait_visibility_map.insert(method, visibility)
373 }
374
375 #[inline]
377 pub fn add_trait_final(&mut self, method: StringIdentifier) -> bool {
378 self.trait_final_map.insert(method)
379 }
380
381 #[inline]
383 pub fn add_template_type(&mut self, template: TemplateTuple) {
384 self.template_types.push(template);
385 }
386 #[inline]
388 pub fn add_template_readonly(&mut self, template_name: StringIdentifier) -> bool {
389 self.template_readonly.insert(template_name)
390 }
391
392 #[inline]
394 pub fn add_template_variance_parameter(&mut self, index: usize, variance: Variance) -> Option<Variance> {
395 self.template_variance.insert(index, variance)
396 }
397
398 #[inline]
400 pub fn add_template_extended_offset(&mut self, name: StringIdentifier, types: Vec<TUnion>) -> Option<Vec<TUnion>> {
401 self.template_extended_offsets.insert(name, types)
402 }
403
404 #[inline]
406 pub fn extend_template_extended_parameters(
407 &mut self,
408 template_extended_parameters: HashMap<StringIdentifier, IndexMap<StringIdentifier, TUnion, RandomState>>,
409 ) {
410 self.template_extended_parameters.extend(template_extended_parameters);
411 }
412
413 #[inline]
415 pub fn add_template_extended_parameter(
416 &mut self,
417 parent_fqcn: StringIdentifier,
418 parameter_name: StringIdentifier,
419 parameter_type: TUnion,
420 ) -> Option<TUnion> {
421 self.template_extended_parameters.entry(parent_fqcn).or_default().insert(parameter_name, parameter_type)
422 }
423
424 #[inline]
426 pub fn add_method(&mut self, method: StringIdentifier) {
427 self.methods.push(method);
428 }
429
430 #[inline]
432 pub fn add_declaring_method_id(
433 &mut self,
434 method: StringIdentifier,
435 declaring_fqcn: StringIdentifier,
436 ) -> Option<StringIdentifier> {
437 self.add_appearing_method_id(method, declaring_fqcn);
438 self.declaring_method_ids.insert(method, declaring_fqcn)
439 }
440
441 #[inline]
443 pub fn add_appearing_method_id(
444 &mut self,
445 method: StringIdentifier,
446 appearing_fqcn: StringIdentifier,
447 ) -> Option<StringIdentifier> {
448 self.appearing_method_ids.insert(method, appearing_fqcn)
449 }
450
451 #[inline]
453 pub fn add_overridden_method_parent(&mut self, method: StringIdentifier, parent_fqcn: StringIdentifier) -> bool {
454 self.overridden_method_ids.entry(method).or_default().insert(parent_fqcn)
455 }
456
457 #[inline]
459 pub fn add_potential_declaring_method(
460 &mut self,
461 method: StringIdentifier,
462 potential_fqcn: StringIdentifier,
463 ) -> bool {
464 self.potential_declaring_method_ids.entry(method).or_default().insert(potential_fqcn)
465 }
466
467 #[inline]
469 pub fn add_property(
470 &mut self,
471 name: StringIdentifier,
472 property_metadata: PropertyMetadata,
473 ) -> Option<PropertyMetadata> {
474 let class_name = self.name;
475
476 self.add_declaring_property_id(name, class_name);
477 if property_metadata.has_default() {
478 self.initialized_properties.push(name);
479 }
480
481 if !property_metadata.is_final() {
482 self.inheritable_property_ids.insert(name, class_name);
483 }
484
485 self.properties.insert(name, property_metadata)
486 }
487
488 #[inline]
490 pub fn add_property_metadata(&mut self, property_metadata: PropertyMetadata) -> Option<PropertyMetadata> {
491 let name = property_metadata.get_name().0;
492
493 self.add_property(name, property_metadata)
494 }
495
496 #[inline]
498 pub fn add_declaring_property_id(
499 &mut self,
500 prop: StringIdentifier,
501 declaring_fqcn: StringIdentifier,
502 ) -> Option<StringIdentifier> {
503 self.appearing_property_ids.insert(prop, declaring_fqcn);
504
505 self.declaring_property_ids.insert(prop, declaring_fqcn)
506 }
507
508 #[inline]
509 pub fn mark_as_populated(&mut self) {
510 self.is_populated = true;
511 self.shrink_to_fit();
512 }
513
514 #[inline]
515 pub fn shrink_to_fit(&mut self) {
516 self.properties.shrink_to_fit();
517 self.initialized_properties.shrink_to_fit();
518 self.appearing_property_ids.shrink_to_fit();
519 self.declaring_property_ids.shrink_to_fit();
520 self.inheritable_property_ids.shrink_to_fit();
521 self.overridden_property_ids.shrink_to_fit();
522 self.appearing_method_ids.shrink_to_fit();
523 self.declaring_method_ids.shrink_to_fit();
524 self.inheritable_method_ids.shrink_to_fit();
525 self.overridden_method_ids.shrink_to_fit();
526 self.potential_declaring_method_ids.shrink_to_fit();
527 self.attributes.shrink_to_fit();
528 self.constants.shrink_to_fit();
529 self.enum_cases.shrink_to_fit();
530 }
531}