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::flags::MetadataFlags;
17use crate::metadata::property::PropertyMetadata;
18use crate::misc::GenericParent;
19use crate::symbol::SymbolKind;
20use crate::ttype::atomic::TAtomic;
21use crate::ttype::template::variance::Variance;
22use crate::ttype::union::TUnion;
23use crate::visibility::Visibility;
24
25type TemplateTuple = (StringIdentifier, Vec<(GenericParent, TUnion)>);
26
27#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
32pub struct ClassLikeMetadata {
33 pub name: StringIdentifier,
34 pub original_name: StringIdentifier,
35 pub span: Span,
36 pub direct_parent_interfaces: Vec<StringIdentifier>,
37 pub all_parent_interfaces: Vec<StringIdentifier>,
38 pub direct_parent_class: Option<StringIdentifier>,
39 pub require_extends: Vec<StringIdentifier>,
40 pub require_implements: Vec<StringIdentifier>,
41 pub all_parent_classes: Vec<StringIdentifier>,
42 pub used_traits: HashSet<StringIdentifier>,
43 pub trait_alias_map: HashMap<StringIdentifier, StringIdentifier>,
44 pub trait_visibility_map: HashMap<StringIdentifier, Visibility>,
45 pub trait_final_map: HashSet<StringIdentifier>,
46 pub child_class_likes: Option<HashSet<StringIdentifier>>,
47 pub name_span: Option<Span>,
48 pub kind: SymbolKind,
49 pub template_types: Vec<TemplateTuple>,
50 pub template_readonly: HashSet<StringIdentifier>,
51 pub template_variance: HashMap<usize, Variance>,
52 pub template_extended_offsets: HashMap<StringIdentifier, Vec<TUnion>>,
53 pub template_extended_parameters: HashMap<StringIdentifier, IndexMap<StringIdentifier, TUnion, RandomState>>,
54 pub template_type_extends_count: HashMap<StringIdentifier, usize>,
55 pub template_type_implements_count: HashMap<StringIdentifier, usize>,
56 pub template_type_uses_count: HashMap<StringIdentifier, usize>,
57 pub methods: Vec<StringIdentifier>,
58 pub pseudo_methods: Vec<StringIdentifier>,
59 pub static_pseudo_methods: Vec<StringIdentifier>,
60 pub declaring_method_ids: HashMap<StringIdentifier, StringIdentifier>,
61 pub appearing_method_ids: HashMap<StringIdentifier, StringIdentifier>,
62 pub overridden_method_ids: HashMap<StringIdentifier, HashSet<StringIdentifier>>,
63 pub inheritable_method_ids: HashMap<StringIdentifier, StringIdentifier>,
64 pub potential_declaring_method_ids: HashMap<StringIdentifier, HashSet<StringIdentifier>>,
65 pub properties: HashMap<StringIdentifier, PropertyMetadata>,
66 pub appearing_property_ids: HashMap<StringIdentifier, StringIdentifier>,
67 pub declaring_property_ids: HashMap<StringIdentifier, StringIdentifier>,
68 pub inheritable_property_ids: HashMap<StringIdentifier, StringIdentifier>,
69 pub overridden_property_ids: HashMap<StringIdentifier, Vec<StringIdentifier>>,
70 pub initialized_properties: Vec<StringIdentifier>,
71 pub constants: IndexMap<StringIdentifier, ClassLikeConstantMetadata, RandomState>,
72 pub enum_cases: IndexMap<StringIdentifier, EnumCaseMetadata, RandomState>,
73 pub invalid_dependencies: Vec<StringIdentifier>,
74 pub attributes: Vec<AttributeMetadata>,
75 pub enum_type: Option<TAtomic>,
76 pub has_sealed_methods: Option<bool>,
77 pub has_sealed_properties: Option<bool>,
78 pub permitted_inheritors: Option<HashSet<StringIdentifier>>,
79 pub issues: Vec<Issue>,
80 pub attribute_flags: Option<AttributeFlags>,
81 pub flags: MetadataFlags,
82}
83
84impl ClassLikeMetadata {
85 pub fn new(
86 name: StringIdentifier,
87 original_name: StringIdentifier,
88 span: Span,
89 name_span: Option<Span>,
90 flags: MetadataFlags,
91 ) -> ClassLikeMetadata {
92 ClassLikeMetadata {
93 constants: IndexMap::with_hasher(RandomState::new()),
94 enum_cases: IndexMap::with_hasher(RandomState::new()),
95 flags,
96 kind: SymbolKind::Class,
97 direct_parent_interfaces: vec![],
98 all_parent_classes: vec![],
99 appearing_method_ids: HashMap::default(),
100 attributes: Vec::new(),
101 all_parent_interfaces: vec![],
102 declaring_method_ids: HashMap::default(),
103 appearing_property_ids: HashMap::default(),
104 declaring_property_ids: HashMap::default(),
105 direct_parent_class: None,
106 require_extends: vec![],
107 require_implements: vec![],
108 inheritable_method_ids: HashMap::default(),
109 enum_type: None,
110 inheritable_property_ids: HashMap::default(),
111 initialized_properties: vec![],
112 invalid_dependencies: Vec::new(),
113 span,
114 name_span,
115 methods: vec![],
116 pseudo_methods: vec![],
117 static_pseudo_methods: vec![],
118 overridden_method_ids: HashMap::default(),
119 overridden_property_ids: HashMap::default(),
120 potential_declaring_method_ids: HashMap::default(),
121 properties: HashMap::default(),
122 template_variance: HashMap::default(),
123 template_type_extends_count: HashMap::default(),
124 template_extended_parameters: HashMap::default(),
125 template_extended_offsets: HashMap::default(),
126 template_type_implements_count: HashMap::default(),
127 template_type_uses_count: HashMap::default(),
128 template_types: vec![],
129 used_traits: HashSet::default(),
130 trait_alias_map: HashMap::default(),
131 trait_visibility_map: HashMap::default(),
132 trait_final_map: HashSet::default(),
133 name,
134 original_name,
135 child_class_likes: None,
136 template_readonly: HashSet::default(),
137 has_sealed_methods: None,
138 has_sealed_properties: None,
139 permitted_inheritors: None,
140 issues: vec![],
141 attribute_flags: None,
142 }
143 }
144
145 #[inline]
147 pub fn get_trait_alias_map(&self) -> &HashMap<StringIdentifier, StringIdentifier> {
148 &self.trait_alias_map
149 }
150
151 #[inline]
153 pub fn get_template_type_names(&self) -> Vec<StringIdentifier> {
154 self.template_types.iter().map(|(name, _)| *name).collect()
155 }
156
157 #[inline]
159 pub fn get_template_type(&self, name: &StringIdentifier) -> Option<&Vec<(GenericParent, TUnion)>> {
160 self.template_types.iter().find_map(|(param_name, types)| if param_name == name { Some(types) } else { None })
161 }
162
163 #[inline]
165 pub fn get_template_type_with_index(
166 &self,
167 name: &StringIdentifier,
168 ) -> Option<(usize, &Vec<(GenericParent, TUnion)>)> {
169 self.template_types
170 .iter()
171 .enumerate()
172 .find_map(|(index, (param_name, types))| if param_name == name { Some((index, types)) } else { None })
173 }
174
175 pub fn get_template_for_index(&self, index: usize) -> Option<(StringIdentifier, &Vec<(GenericParent, TUnion)>)> {
176 self.template_types.get(index).map(|(name, types)| (*name, types))
177 }
178
179 pub fn get_template_name_for_index(&self, index: usize) -> Option<StringIdentifier> {
180 self.template_types.get(index).map(|(name, _)| *name)
181 }
182
183 pub fn get_template_index_for_name(&self, name: &StringIdentifier) -> Option<usize> {
184 self.template_types.iter().position(|(param_name, _)| param_name == name)
185 }
186
187 #[inline]
189 pub fn has_parent(&self, parent: &StringIdentifier) -> bool {
190 self.all_parent_classes.contains(parent) || self.all_parent_interfaces.contains(parent)
191 }
192
193 #[inline]
195 pub fn has_template_extended_parameter(&self, parent: &StringIdentifier) -> bool {
196 self.template_extended_parameters.contains_key(parent)
197 }
198
199 #[inline]
201 pub fn get_methods(&self) -> &[StringIdentifier] {
202 &self.methods
203 }
204
205 #[inline]
207 pub fn has_method(&self, method: &StringIdentifier) -> bool {
208 self.methods.contains(method)
209 }
210
211 #[inline]
213 pub fn get_declaring_method_ids(&self) -> &HashMap<StringIdentifier, StringIdentifier> {
214 &self.declaring_method_ids
215 }
216
217 #[inline]
219 pub fn get_appearing_method_ids(&self) -> &HashMap<StringIdentifier, StringIdentifier> {
220 &self.appearing_method_ids
221 }
222
223 #[inline]
225 pub fn has_appearing_method(&self, method: &StringIdentifier) -> bool {
226 self.appearing_method_ids.contains_key(method)
227 }
228
229 #[inline]
231 pub fn get_overridden_method_ids(&self) -> &HashMap<StringIdentifier, HashSet<StringIdentifier>> {
232 &self.overridden_method_ids
233 }
234
235 #[inline]
237 pub fn get_overridden_method_id(&self, method: &StringIdentifier) -> Option<&HashSet<StringIdentifier>> {
238 self.overridden_method_ids.get(method)
239 }
240
241 #[inline]
243 pub fn get_overridden_method_id_mut(
244 &mut self,
245 method: &StringIdentifier,
246 ) -> Option<&mut HashSet<StringIdentifier>> {
247 self.overridden_method_ids.get_mut(method)
248 }
249
250 #[inline]
252 pub fn get_potential_declaring_method_id(&self, method: &StringIdentifier) -> Option<&HashSet<StringIdentifier>> {
253 self.potential_declaring_method_ids.get(method)
254 }
255
256 #[inline]
258 pub fn get_property_names(&self) -> Vec<StringIdentifier> {
259 self.properties.keys().copied().collect()
260 }
261
262 #[inline]
264 pub fn has_appearing_property(&self, name: &StringIdentifier) -> bool {
265 self.appearing_property_ids.contains_key(name)
266 }
267
268 #[inline]
270 pub fn has_declaring_property(&self, name: &StringIdentifier) -> bool {
271 self.declaring_property_ids.contains_key(name)
272 }
273
274 #[inline]
276 pub fn take_issues(&mut self) -> Vec<Issue> {
277 std::mem::take(&mut self.issues)
278 }
279
280 #[inline]
282 pub fn add_direct_parent_interface(&mut self, interface: StringIdentifier) {
283 self.direct_parent_interfaces.push(interface);
284 self.all_parent_interfaces.push(interface);
285 }
286
287 #[inline]
289 pub fn add_all_parent_interface(&mut self, interface: StringIdentifier) {
290 self.all_parent_interfaces.push(interface);
291 }
292
293 #[inline]
295 pub fn add_all_parent_interfaces(&mut self, interfaces: impl IntoIterator<Item = StringIdentifier>) {
296 self.all_parent_interfaces.extend(interfaces);
297 }
298
299 #[inline]
301 pub fn add_require_extend(&mut self, require: StringIdentifier) {
302 self.require_extends.push(require);
303 }
304
305 #[inline]
307 pub fn add_require_implement(&mut self, require: StringIdentifier) {
308 self.require_implements.push(require);
309 }
310
311 #[inline]
313 pub fn add_all_parent_classes(&mut self, classes: impl IntoIterator<Item = StringIdentifier>) {
314 self.all_parent_classes.extend(classes);
315 }
316
317 #[inline]
319 pub fn add_used_trait(&mut self, trait_name: StringIdentifier) -> bool {
320 self.used_traits.insert(trait_name)
321 }
322
323 #[inline]
325 pub fn add_used_traits(&mut self, traits: impl IntoIterator<Item = StringIdentifier>) {
326 self.used_traits.extend(traits);
327 }
328
329 #[inline]
331 pub fn add_trait_alias(&mut self, method: StringIdentifier, alias: StringIdentifier) -> Option<StringIdentifier> {
332 self.trait_alias_map.insert(method, alias)
333 }
334
335 #[inline]
337 pub fn add_trait_visibility(&mut self, method: StringIdentifier, visibility: Visibility) -> Option<Visibility> {
338 self.trait_visibility_map.insert(method, visibility)
339 }
340
341 #[inline]
343 pub fn add_trait_final(&mut self, method: StringIdentifier) -> bool {
344 self.trait_final_map.insert(method)
345 }
346
347 #[inline]
349 pub fn add_template_type(&mut self, template: TemplateTuple) {
350 self.template_types.push(template);
351 }
352 #[inline]
354 pub fn add_template_readonly(&mut self, template_name: StringIdentifier) -> bool {
355 self.template_readonly.insert(template_name)
356 }
357
358 #[inline]
360 pub fn add_template_variance_parameter(&mut self, index: usize, variance: Variance) -> Option<Variance> {
361 self.template_variance.insert(index, variance)
362 }
363
364 #[inline]
366 pub fn add_template_extended_offset(&mut self, name: StringIdentifier, types: Vec<TUnion>) -> Option<Vec<TUnion>> {
367 self.template_extended_offsets.insert(name, types)
368 }
369
370 #[inline]
372 pub fn extend_template_extended_parameters(
373 &mut self,
374 template_extended_parameters: HashMap<StringIdentifier, IndexMap<StringIdentifier, TUnion, RandomState>>,
375 ) {
376 self.template_extended_parameters.extend(template_extended_parameters);
377 }
378
379 #[inline]
381 pub fn add_template_extended_parameter(
382 &mut self,
383 parent_fqcn: StringIdentifier,
384 parameter_name: StringIdentifier,
385 parameter_type: TUnion,
386 ) -> Option<TUnion> {
387 self.template_extended_parameters.entry(parent_fqcn).or_default().insert(parameter_name, parameter_type)
388 }
389
390 #[inline]
392 pub fn add_method(&mut self, method: StringIdentifier) {
393 self.methods.push(method);
394 }
395
396 #[inline]
398 pub fn add_declaring_method_id(
399 &mut self,
400 method: StringIdentifier,
401 declaring_fqcn: StringIdentifier,
402 ) -> Option<StringIdentifier> {
403 self.add_appearing_method_id(method, declaring_fqcn);
404 self.declaring_method_ids.insert(method, declaring_fqcn)
405 }
406
407 #[inline]
409 pub fn add_appearing_method_id(
410 &mut self,
411 method: StringIdentifier,
412 appearing_fqcn: StringIdentifier,
413 ) -> Option<StringIdentifier> {
414 self.appearing_method_ids.insert(method, appearing_fqcn)
415 }
416
417 #[inline]
419 pub fn add_overridden_method_parent(&mut self, method: StringIdentifier, parent_fqcn: StringIdentifier) -> bool {
420 self.overridden_method_ids.entry(method).or_default().insert(parent_fqcn)
421 }
422
423 #[inline]
425 pub fn add_potential_declaring_method(
426 &mut self,
427 method: StringIdentifier,
428 potential_fqcn: StringIdentifier,
429 ) -> bool {
430 self.potential_declaring_method_ids.entry(method).or_default().insert(potential_fqcn)
431 }
432
433 #[inline]
435 pub fn add_property(
436 &mut self,
437 name: StringIdentifier,
438 property_metadata: PropertyMetadata,
439 ) -> Option<PropertyMetadata> {
440 let class_name = self.name;
441
442 self.add_declaring_property_id(name, class_name);
443 if property_metadata.flags.has_default() {
444 self.initialized_properties.push(name);
445 }
446
447 if !property_metadata.is_final() {
448 self.inheritable_property_ids.insert(name, class_name);
449 }
450
451 self.properties.insert(name, property_metadata)
452 }
453
454 #[inline]
456 pub fn add_property_metadata(&mut self, property_metadata: PropertyMetadata) -> Option<PropertyMetadata> {
457 let name = property_metadata.get_name().0;
458
459 self.add_property(name, property_metadata)
460 }
461
462 #[inline]
464 pub fn add_declaring_property_id(
465 &mut self,
466 prop: StringIdentifier,
467 declaring_fqcn: StringIdentifier,
468 ) -> Option<StringIdentifier> {
469 self.appearing_property_ids.insert(prop, declaring_fqcn);
470
471 self.declaring_property_ids.insert(prop, declaring_fqcn)
472 }
473
474 #[inline]
475 pub fn mark_as_populated(&mut self) {
476 self.flags |= MetadataFlags::POPULATED;
477 self.shrink_to_fit();
478 }
479
480 #[inline]
481 pub fn shrink_to_fit(&mut self) {
482 self.properties.shrink_to_fit();
483 self.initialized_properties.shrink_to_fit();
484 self.appearing_property_ids.shrink_to_fit();
485 self.declaring_property_ids.shrink_to_fit();
486 self.inheritable_property_ids.shrink_to_fit();
487 self.overridden_property_ids.shrink_to_fit();
488 self.appearing_method_ids.shrink_to_fit();
489 self.declaring_method_ids.shrink_to_fit();
490 self.inheritable_method_ids.shrink_to_fit();
491 self.overridden_method_ids.shrink_to_fit();
492 self.potential_declaring_method_ids.shrink_to_fit();
493 self.attributes.shrink_to_fit();
494 self.constants.shrink_to_fit();
495 self.enum_cases.shrink_to_fit();
496 }
497}