1use std::sync::Arc;
2
3use dashmap::{DashMap, DashSet};
4
5use crate::storage::{
6 ClassStorage, EnumStorage, FunctionStorage, InterfaceStorage, MethodStorage, TraitStorage,
7};
8use mir_types::Union;
9
10#[derive(Debug, Default)]
15pub struct Codebase {
16 pub classes: DashMap<Arc<str>, ClassStorage>,
17 pub interfaces: DashMap<Arc<str>, InterfaceStorage>,
18 pub traits: DashMap<Arc<str>, TraitStorage>,
19 pub enums: DashMap<Arc<str>, EnumStorage>,
20 pub functions: DashMap<Arc<str>, FunctionStorage>,
21 pub constants: DashMap<Arc<str>, Union>,
22
23 pub referenced_methods: DashSet<Arc<str>>,
26 pub referenced_properties: DashSet<Arc<str>>,
28 pub referenced_functions: DashSet<Arc<str>>,
30
31 pub file_imports: DashMap<Arc<str>, std::collections::HashMap<String, String>>,
33 pub file_namespaces: DashMap<Arc<str>, String>,
35
36 finalized: std::sync::atomic::AtomicBool,
38}
39
40impl Codebase {
41 pub fn new() -> Self {
42 Self::default()
43 }
44
45 pub fn get_property(&self, fqcn: &str, prop_name: &str) -> Option<crate::storage::PropertyStorage> {
51 if let Some(cls) = self.classes.get(fqcn) {
53 if let Some(p) = cls.own_properties.get(prop_name) {
54 return Some(p.clone());
55 }
56 }
57
58 let all_parents = {
60 if let Some(cls) = self.classes.get(fqcn) {
61 cls.all_parents.clone()
62 } else {
63 return None;
64 }
65 };
66
67 for ancestor_fqcn in &all_parents {
68 if let Some(ancestor_cls) = self.classes.get(ancestor_fqcn.as_ref()) {
69 if let Some(p) = ancestor_cls.own_properties.get(prop_name) {
70 return Some(p.clone());
71 }
72 }
73 }
74
75 let trait_list = {
77 if let Some(cls) = self.classes.get(fqcn) {
78 cls.traits.clone()
79 } else {
80 vec![]
81 }
82 };
83 for trait_fqcn in &trait_list {
84 if let Some(tr) = self.traits.get(trait_fqcn.as_ref()) {
85 if let Some(p) = tr.own_properties.get(prop_name) {
86 return Some(p.clone());
87 }
88 }
89 }
90
91 None
92 }
93
94 pub fn get_method(&self, fqcn: &str, method_name: &str) -> Option<MethodStorage> {
96 let method_lower = method_name.to_lowercase();
98 let method_name = method_lower.as_str();
99 if let Some(cls) = self.classes.get(fqcn) {
101 if let Some(m) = cls.get_method(method_name) {
102 return Some(m.clone());
103 }
104 }
105 if let Some(iface) = self.interfaces.get(fqcn) {
107 if let Some(m) = iface.own_methods.get(method_name)
108 .or_else(|| iface.own_methods.iter().find(|(k, _)| k.as_ref().eq_ignore_ascii_case(method_name)).map(|(_, v)| v))
109 {
110 return Some(m.clone());
111 }
112 let parents = iface.all_parents.clone();
114 for parent_fqcn in &parents {
115 if let Some(parent_iface) = self.interfaces.get(parent_fqcn.as_ref()) {
116 if let Some(m) = parent_iface.own_methods.get(method_name)
117 .or_else(|| parent_iface.own_methods.iter().find(|(k, _)| k.as_ref().eq_ignore_ascii_case(method_name)).map(|(_, v)| v))
118 {
119 return Some(m.clone());
120 }
121 }
122 }
123 }
124 if let Some(tr) = self.traits.get(fqcn) {
126 if let Some(m) = tr.own_methods.get(method_name)
127 .or_else(|| tr.own_methods.iter().find(|(k, _)| k.as_ref().eq_ignore_ascii_case(method_name)).map(|(_, v)| v))
128 {
129 return Some(m.clone());
130 }
131 }
132 if let Some(e) = self.enums.get(fqcn) {
134 if let Some(m) = e.own_methods.get(method_name)
135 .or_else(|| e.own_methods.iter().find(|(k, _)| k.as_ref().eq_ignore_ascii_case(method_name)).map(|(_, v)| v))
136 {
137 return Some(m.clone());
138 }
139 if matches!(method_name, "cases" | "from" | "tryfrom") {
141 return Some(crate::storage::MethodStorage {
142 fqcn: Arc::from(fqcn),
143 name: Arc::from(method_name),
144 params: vec![],
145 return_type: Some(mir_types::Union::mixed()),
146 inferred_return_type: None,
147 visibility: crate::storage::Visibility::Public,
148 is_static: true,
149 is_abstract: false,
150 is_constructor: false,
151 template_params: vec![],
152 assertions: vec![],
153 throws: vec![],
154 is_final: false,
155 is_internal: false,
156 is_pure: false,
157 is_deprecated: false,
158 location: None,
159 });
160 }
161 }
162 None
163 }
164
165 pub fn extends_or_implements(&self, child: &str, ancestor: &str) -> bool {
167 if child == ancestor {
168 return true;
169 }
170 if let Some(cls) = self.classes.get(child) {
171 return cls.implements_or_extends(ancestor);
172 }
173 if let Some(iface) = self.interfaces.get(child) {
174 return iface.all_parents.iter().any(|p| p.as_ref() == ancestor);
175 }
176 if let Some(en) = self.enums.get(child) {
179 if en.interfaces.iter().any(|i| i.as_ref() == ancestor) {
181 return true;
182 }
183 if ancestor == "UnitEnum" || ancestor == "\\UnitEnum" {
185 return true;
186 }
187 if (ancestor == "BackedEnum" || ancestor == "\\BackedEnum") && en.scalar_type.is_some() {
189 return true;
190 }
191 }
192 false
193 }
194
195 pub fn type_exists(&self, fqcn: &str) -> bool {
197 self.classes.contains_key(fqcn)
198 || self.interfaces.contains_key(fqcn)
199 || self.traits.contains_key(fqcn)
200 || self.enums.contains_key(fqcn)
201 }
202
203 pub fn function_exists(&self, fqn: &str) -> bool {
204 self.functions.contains_key(fqn)
205 }
206
207 pub fn has_magic_get(&self, fqcn: &str) -> bool {
210 if let Some(cls) = self.classes.get(fqcn) {
211 if cls.own_methods.contains_key("__get") || cls.all_methods.contains_key("__get") {
212 return true;
213 }
214 let traits = cls.traits.clone();
216 drop(cls);
217 for tr in &traits {
218 if let Some(t) = self.traits.get(tr.as_ref()) {
219 if t.own_methods.contains_key("__get") {
220 return true;
221 }
222 }
223 }
224 let all_parents = {
226 if let Some(c) = self.classes.get(fqcn) { c.all_parents.clone() } else { vec![] }
227 };
228 for ancestor in &all_parents {
229 if let Some(anc) = self.classes.get(ancestor.as_ref()) {
230 if anc.own_methods.contains_key("__get") {
231 return true;
232 }
233 }
234 }
235 }
236 false
237 }
238
239 pub fn has_unknown_ancestor(&self, fqcn: &str) -> bool {
247 if let Some(iface) = self.interfaces.get(fqcn) {
249 let parents = iface.all_parents.clone();
250 drop(iface);
251 for p in &parents {
252 if !self.type_exists(p.as_ref()) {
253 return true;
254 }
255 }
256 return false;
257 }
258
259 let (parent, interfaces, traits, all_parents) = {
261 let Some(cls) = self.classes.get(fqcn) else { return false };
262 (
263 cls.parent.clone(),
264 cls.interfaces.clone(),
265 cls.traits.clone(),
266 cls.all_parents.clone(),
267 )
268 };
269
270 if let Some(ref p) = parent {
272 if !self.type_exists(p.as_ref()) {
273 return true;
274 }
275 }
276 for iface in &interfaces {
277 if !self.type_exists(iface.as_ref()) {
278 return true;
279 }
280 }
281 for tr in &traits {
282 if !self.type_exists(tr.as_ref()) {
283 return true;
284 }
285 }
286
287 for ancestor in &all_parents {
289 if !self.type_exists(ancestor.as_ref()) {
290 return true;
291 }
292 }
293
294 false
295 }
296
297 pub fn resolve_class_name(&self, file: &str, name: &str) -> String {
304 let name = name.trim_start_matches('\\');
305 if name.is_empty() {
306 return name.to_string();
307 }
308 if name.contains('\\') {
313 let first_segment = name.split('\\').next().unwrap_or(name);
315 if let Some(imports) = self.file_imports.get(file) {
316 if let Some(resolved_prefix) = imports.get(first_segment) {
317 let rest = &name[first_segment.len()..]; return format!("{}{}", resolved_prefix, rest);
319 }
320 }
321 if self.type_exists(name) {
323 return name.to_string();
324 }
325 if let Some(ns) = self.file_namespaces.get(file) {
327 let qualified = format!("{}\\{}", *ns, name);
328 if self.type_exists(&qualified) {
329 return qualified;
330 }
331 }
332 return name.to_string();
333 }
334 match name {
336 "self" | "parent" | "static" | "this" => return name.to_string(),
337 _ => {}
338 }
339 if let Some(imports) = self.file_imports.get(file) {
341 if let Some(resolved) = imports.get(name) {
342 return resolved.clone();
343 }
344 let name_lower = name.to_lowercase();
346 for (alias, resolved) in imports.iter() {
347 if alias.to_lowercase() == name_lower {
348 return resolved.clone();
349 }
350 }
351 }
352 if let Some(ns) = self.file_namespaces.get(file) {
354 let qualified = format!("{}\\{}", *ns, name);
355 if self.type_exists(&qualified) {
360 return qualified;
361 }
362 if self.type_exists(name) {
363 return name.to_string();
364 }
365 return qualified;
366 }
367 name.to_string()
368 }
369
370 pub fn mark_method_referenced(&self, fqcn: &str, method_name: &str) {
376 let key: Arc<str> = Arc::from(format!("{}::{}", fqcn, method_name.to_lowercase()).as_str());
377 self.referenced_methods.insert(key);
378 }
379
380 pub fn mark_property_referenced(&self, fqcn: &str, prop_name: &str) {
382 let key: Arc<str> = Arc::from(format!("{}::{}", fqcn, prop_name).as_str());
383 self.referenced_properties.insert(key);
384 }
385
386 pub fn mark_function_referenced(&self, fqn: &str) {
388 self.referenced_functions.insert(Arc::from(fqn));
389 }
390
391 pub fn is_method_referenced(&self, fqcn: &str, method_name: &str) -> bool {
392 let key = format!("{}::{}", fqcn, method_name.to_lowercase());
393 self.referenced_methods.contains(key.as_str())
394 }
395
396 pub fn is_property_referenced(&self, fqcn: &str, prop_name: &str) -> bool {
397 let key = format!("{}::{}", fqcn, prop_name);
398 self.referenced_properties.contains(key.as_str())
399 }
400
401 pub fn is_function_referenced(&self, fqn: &str) -> bool {
402 self.referenced_functions.contains(fqn)
403 }
404
405 pub fn finalize(&self) {
412 if self.finalized.load(std::sync::atomic::Ordering::SeqCst) {
413 return;
414 }
415
416 let class_keys: Vec<Arc<str>> = self.classes.iter().map(|e| e.key().clone()).collect();
418 for fqcn in &class_keys {
419 let parents = self.collect_class_ancestors(fqcn);
420 if let Some(mut cls) = self.classes.get_mut(fqcn.as_ref()) {
421 cls.all_parents = parents;
422 }
423 }
424
425 for fqcn in &class_keys {
427 let all_methods = self.build_method_table(fqcn);
428 if let Some(mut cls) = self.classes.get_mut(fqcn.as_ref()) {
429 cls.all_methods = all_methods;
430 }
431 }
432
433 let iface_keys: Vec<Arc<str>> = self.interfaces.iter().map(|e| e.key().clone()).collect();
435 for fqcn in &iface_keys {
436 let parents = self.collect_interface_ancestors(fqcn);
437 if let Some(mut iface) = self.interfaces.get_mut(fqcn.as_ref()) {
438 iface.all_parents = parents;
439 }
440 }
441
442 self.finalized.store(true, std::sync::atomic::Ordering::SeqCst);
443 }
444
445 fn collect_class_ancestors(&self, fqcn: &str) -> Vec<Arc<str>> {
450 let mut result = Vec::new();
451 let mut visited = std::collections::HashSet::new();
452 self.collect_class_ancestors_inner(fqcn, &mut result, &mut visited);
453 result
454 }
455
456 fn collect_class_ancestors_inner(
457 &self,
458 fqcn: &str,
459 out: &mut Vec<Arc<str>>,
460 visited: &mut std::collections::HashSet<String>,
461 ) {
462 if !visited.insert(fqcn.to_string()) {
463 return; }
465 let (parent, interfaces, traits) = {
466 if let Some(cls) = self.classes.get(fqcn) {
467 (
468 cls.parent.clone(),
469 cls.interfaces.clone(),
470 cls.traits.clone(),
471 )
472 } else {
473 return;
474 }
475 };
476
477 if let Some(p) = parent {
478 out.push(p.clone());
479 self.collect_class_ancestors_inner(&p, out, visited);
480 }
481 for iface in interfaces {
482 out.push(iface.clone());
483 self.collect_interface_ancestors_inner(&iface, out, visited);
484 }
485 for t in traits {
486 out.push(t);
487 }
488 }
489
490 fn collect_interface_ancestors(&self, fqcn: &str) -> Vec<Arc<str>> {
491 let mut result = Vec::new();
492 let mut visited = std::collections::HashSet::new();
493 self.collect_interface_ancestors_inner(fqcn, &mut result, &mut visited);
494 result
495 }
496
497 fn collect_interface_ancestors_inner(
498 &self,
499 fqcn: &str,
500 out: &mut Vec<Arc<str>>,
501 visited: &mut std::collections::HashSet<String>,
502 ) {
503 if !visited.insert(fqcn.to_string()) {
504 return;
505 }
506 let extends = {
507 if let Some(iface) = self.interfaces.get(fqcn) {
508 iface.extends.clone()
509 } else {
510 return;
511 }
512 };
513 for e in extends {
514 out.push(e.clone());
515 self.collect_interface_ancestors_inner(&e, out, visited);
516 }
517 }
518
519 fn build_method_table(&self, fqcn: &str) -> indexmap::IndexMap<Arc<str>, MethodStorage> {
522 use indexmap::IndexMap;
523 let mut table: IndexMap<Arc<str>, MethodStorage> = IndexMap::new();
524
525 let ancestors = {
527 if let Some(cls) = self.classes.get(fqcn) {
528 cls.all_parents.clone()
529 } else {
530 return table;
531 }
532 };
533
534 for ancestor_fqcn in ancestors.iter().rev() {
537 if let Some(ancestor) = self.classes.get(ancestor_fqcn.as_ref()) {
538 let ancestor_traits = ancestor.traits.clone();
540 for trait_fqcn in ancestor_traits.iter().rev() {
541 if let Some(tr) = self.traits.get(trait_fqcn.as_ref()) {
542 for (name, method) in &tr.own_methods {
543 table.insert(name.clone(), method.clone());
544 }
545 }
546 }
547 for (name, method) in &ancestor.own_methods {
549 table.insert(name.clone(), method.clone());
550 }
551 } else if let Some(iface) = self.interfaces.get(ancestor_fqcn.as_ref()) {
552 for (name, method) in &iface.own_methods {
553 table.insert(name.clone(), method.clone());
554 }
555 }
556 }
557
558 let trait_list = {
560 if let Some(cls) = self.classes.get(fqcn) {
561 cls.traits.clone()
562 } else {
563 vec![]
564 }
565 };
566 for trait_fqcn in &trait_list {
567 if let Some(tr) = self.traits.get(trait_fqcn.as_ref()) {
568 for (name, method) in &tr.own_methods {
569 table.insert(name.clone(), method.clone());
570 }
571 }
572 }
573
574 if let Some(cls) = self.classes.get(fqcn) {
576 for (name, method) in &cls.own_methods {
577 table.insert(name.clone(), method.clone());
578 }
579 }
580
581 table
582 }
583}