1use std::sync::Arc;
2
3use indexmap::IndexMap;
4use mir_types::{Location, Name, Type};
5use rustc_hash::FxHashMap;
6use serde::{Deserialize, Serialize};
7
8mod interned_types {
15 use super::*;
16 use std::sync::OnceLock;
17
18 fn intern_string() -> Arc<Type> {
19 Arc::new(Type::string())
20 }
21
22 fn intern_int() -> Arc<Type> {
23 Arc::new(Type::int())
24 }
25
26 fn intern_float() -> Arc<Type> {
27 Arc::new(Type::float())
28 }
29
30 fn intern_bool() -> Arc<Type> {
31 Arc::new(Type::bool())
32 }
33
34 fn intern_mixed() -> Arc<Type> {
35 Arc::new(Type::mixed())
36 }
37
38 fn intern_null() -> Arc<Type> {
39 Arc::new(Type::null())
40 }
41
42 fn intern_void() -> Arc<Type> {
43 Arc::new(Type::void())
44 }
45
46 static STRING: OnceLock<Arc<Type>> = OnceLock::new();
47 static INT: OnceLock<Arc<Type>> = OnceLock::new();
48 static FLOAT: OnceLock<Arc<Type>> = OnceLock::new();
49 static BOOL: OnceLock<Arc<Type>> = OnceLock::new();
50 static MIXED: OnceLock<Arc<Type>> = OnceLock::new();
51 static NULL: OnceLock<Arc<Type>> = OnceLock::new();
52 static VOID: OnceLock<Arc<Type>> = OnceLock::new();
53
54 pub fn string() -> Arc<Type> {
55 STRING.get_or_init(intern_string).clone()
56 }
57
58 pub fn int() -> Arc<Type> {
59 INT.get_or_init(intern_int).clone()
60 }
61
62 pub fn float() -> Arc<Type> {
63 FLOAT.get_or_init(intern_float).clone()
64 }
65
66 pub fn bool() -> Arc<Type> {
67 BOOL.get_or_init(intern_bool).clone()
68 }
69
70 pub fn mixed() -> Arc<Type> {
71 MIXED.get_or_init(intern_mixed).clone()
72 }
73
74 pub fn null() -> Arc<Type> {
75 NULL.get_or_init(intern_null).clone()
76 }
77
78 pub fn void() -> Arc<Type> {
79 VOID.get_or_init(intern_void).clone()
80 }
81
82 static GLOBAL_UNION_INTERN: std::sync::OnceLock<dashmap::DashMap<Type, Arc<Type>>> =
95 std::sync::OnceLock::new();
96
97 fn global_intern_table() -> &'static dashmap::DashMap<Type, Arc<Type>> {
98 GLOBAL_UNION_INTERN.get_or_init(dashmap::DashMap::default)
99 }
100
101 pub fn intern_or_wrap(union: Type) -> Arc<Type> {
103 if union.types.len() == 1 && !union.possibly_undefined && !union.from_docblock {
106 match &union.types[0] {
107 mir_types::Atomic::TString => return string(),
108 mir_types::Atomic::TInt => return int(),
109 mir_types::Atomic::TFloat => return float(),
110 mir_types::Atomic::TBool => return bool(),
111 mir_types::Atomic::TMixed => return mixed(),
112 mir_types::Atomic::TNull => return null(),
113 mir_types::Atomic::TVoid => return void(),
114 _ => {}
115 }
116 }
117 if union.types.is_empty() {
120 return Arc::new(union);
121 }
122 let table = global_intern_table();
124 if let Some(existing) = table.get(&union) {
125 return Arc::clone(existing.value());
126 }
127 let arc = Arc::new(union.clone());
128 match table.entry(union) {
132 dashmap::mapref::entry::Entry::Occupied(o) => Arc::clone(o.get()),
133 dashmap::mapref::entry::Entry::Vacant(v) => {
134 v.insert(Arc::clone(&arc));
135 arc
136 }
137 }
138 }
139}
140
141#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
146pub enum Visibility {
147 Public,
148 Protected,
149 Private,
150}
151
152impl Visibility {
153 pub fn is_at_least(&self, required: Visibility) -> bool {
154 *self <= required
155 }
156}
157
158impl std::fmt::Display for Visibility {
159 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160 match self {
161 Visibility::Public => write!(f, "public"),
162 Visibility::Protected => write!(f, "protected"),
163 Visibility::Private => write!(f, "private"),
164 }
165 }
166}
167
168fn serialize_template_bound<S>(value: &Option<Arc<Type>>, serializer: S) -> Result<S::Ok, S::Error>
169where
170 S: serde::Serializer,
171{
172 value.as_deref().serialize(serializer)
173}
174
175fn deserialize_template_bound<'de, D>(deserializer: D) -> Result<Option<Arc<Type>>, D::Error>
176where
177 D: serde::Deserializer<'de>,
178{
179 Option::<Type>::deserialize(deserializer).map(|opt| opt.map(interned_types::intern_or_wrap))
180}
181
182#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
183pub struct TemplateParam {
184 pub name: Name,
185 #[serde(
189 serialize_with = "serialize_template_bound",
190 deserialize_with = "deserialize_template_bound"
191 )]
192 pub bound: Option<Arc<Type>>,
193 pub defining_entity: Name,
195 pub variance: mir_types::Variance,
196}
197
198#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
199pub struct FnParam {
200 pub name: Name,
201 #[serde(
205 deserialize_with = "deserialize_param_type",
206 serialize_with = "serialize_param_type"
207 )]
208 pub ty: Option<Arc<Type>>,
209 #[serde(
213 default,
214 deserialize_with = "deserialize_param_type",
215 serialize_with = "serialize_param_type"
216 )]
217 pub out_ty: Option<Arc<Type>>,
218 pub has_default: bool,
221 pub is_variadic: bool,
222 pub is_byref: bool,
223 pub is_optional: bool,
224}
225
226impl std::hash::Hash for FnParam {
227 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
228 self.name.hash(state);
229 self.has_default.hash(state);
230 self.is_variadic.hash(state);
231 self.is_byref.hash(state);
232 self.is_optional.hash(state);
233 self.ty.as_deref().hash(state);
237 self.out_ty.as_deref().hash(state);
238 }
239}
240
241fn deserialize_param_type<'de, D>(deserializer: D) -> Result<Option<Arc<Type>>, D::Error>
243where
244 D: serde::Deserializer<'de>,
245{
246 Option::<Type>::deserialize(deserializer).map(|opt| opt.map(interned_types::intern_or_wrap))
247}
248
249fn serialize_param_type<S>(value: &Option<Arc<Type>>, serializer: S) -> Result<S::Ok, S::Error>
250where
251 S: serde::Serializer,
252{
253 let opt = value.as_ref().map(|arc| (**arc).clone());
254 opt.serialize(serializer)
255}
256
257fn deserialize_return_type<'de, D>(deserializer: D) -> Result<Option<Arc<Type>>, D::Error>
258where
259 D: serde::Deserializer<'de>,
260{
261 Option::<Type>::deserialize(deserializer).map(|opt| opt.map(interned_types::intern_or_wrap))
262}
263
264fn serialize_return_type<S>(value: &Option<Arc<Type>>, serializer: S) -> Result<S::Ok, S::Error>
265where
266 S: serde::Serializer,
267{
268 let opt = value.as_ref().map(|arc| (**arc).clone());
269 opt.serialize(serializer)
270}
271
272fn deserialize_params<'de, D>(deserializer: D) -> Result<Arc<[FnParam]>, D::Error>
273where
274 D: serde::Deserializer<'de>,
275{
276 Vec::<FnParam>::deserialize(deserializer).map(|v| Arc::from(v.into_boxed_slice()))
277}
278
279fn default_imports() -> Arc<FxHashMap<Name, Name>> {
280 Arc::new(FxHashMap::default())
281}
282
283fn deserialize_imports<'de, D>(deserializer: D) -> Result<Arc<FxHashMap<Name, Name>>, D::Error>
288where
289 D: serde::Deserializer<'de>,
290{
291 let raw = FxHashMap::<String, String>::deserialize(deserializer)?;
292 let mut out: FxHashMap<Name, Name> =
293 FxHashMap::with_capacity_and_hasher(raw.len(), Default::default());
294 for (k, v) in raw {
295 out.insert(Name::new(&k), Name::new(&v));
296 }
297 Ok(Arc::new(out))
298}
299
300fn serialize_imports<S>(
304 value: &Arc<FxHashMap<Name, Name>>,
305 serializer: S,
306) -> Result<S::Ok, S::Error>
307where
308 S: serde::Serializer,
309{
310 use serde::ser::SerializeMap;
311 let mut map = serializer.serialize_map(Some(value.len()))?;
312 for (k, v) in value.iter() {
313 map.serialize_entry(k.as_str(), v.as_str())?;
314 }
315 map.end()
316}
317
318fn serialize_params<S>(value: &Arc<[FnParam]>, serializer: S) -> Result<S::Ok, S::Error>
319where
320 S: serde::Serializer,
321{
322 value.as_ref().serialize(serializer)
323}
324
325pub fn wrap_param_type(ty: Option<Type>) -> Option<Arc<Type>> {
327 ty.map(interned_types::intern_or_wrap)
328}
329
330pub fn wrap_return_type(ty: Option<Type>) -> Option<Arc<Type>> {
332 ty.map(interned_types::intern_or_wrap)
333}
334
335pub fn wrap_property_type(ty: Option<Type>) -> Option<Arc<Type>> {
339 ty.map(interned_types::intern_or_wrap)
340}
341
342pub fn wrap_template_bound(ty: Option<Type>) -> Option<Arc<Type>> {
344 ty.map(interned_types::intern_or_wrap)
345}
346
347pub fn wrap_var_type(ty: Type) -> Arc<Type> {
352 interned_types::intern_or_wrap(ty)
353}
354
355#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
360pub enum AssertionKind {
361 Assert,
362 AssertIfTrue,
363 AssertIfFalse,
364}
365
366#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
367pub struct Assertion {
368 pub kind: AssertionKind,
369 pub param: Arc<str>,
370 pub ty: Type,
371}
372
373#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
378pub struct MethodDef {
379 pub name: Arc<str>,
380 pub fqcn: Arc<str>,
381 #[serde(
382 deserialize_with = "deserialize_params",
383 serialize_with = "serialize_params"
384 )]
385 pub params: Arc<[FnParam]>,
386 #[serde(
390 deserialize_with = "deserialize_return_type",
391 serialize_with = "serialize_return_type"
392 )]
393 pub return_type: Option<Arc<Type>>,
394 #[serde(
399 deserialize_with = "deserialize_return_type",
400 serialize_with = "serialize_return_type"
401 )]
402 pub inferred_return_type: Option<Arc<Type>>,
403 pub visibility: Visibility,
404 pub is_static: bool,
405 pub is_abstract: bool,
406 pub is_final: bool,
407 pub is_constructor: bool,
408 pub template_params: Vec<TemplateParam>,
409 pub assertions: Vec<Assertion>,
410 pub throws: Vec<Arc<str>>,
411 pub deprecated: Option<Arc<str>>,
412 pub is_internal: bool,
413 pub is_pure: bool,
414 #[serde(default)]
416 pub no_named_arguments: bool,
417 #[serde(default)]
419 pub is_override: bool,
420 pub location: Option<Location>,
421 #[serde(default)]
424 pub docstring: Option<Arc<str>>,
425 #[serde(default)]
428 pub is_virtual: bool,
429 #[serde(default)]
432 pub taint_sink_params: Vec<(Arc<str>, Arc<str>)>,
433 #[serde(default)]
436 pub if_this_is: Option<Arc<Type>>,
437 #[serde(default)]
441 pub is_inherit_doc: bool,
442 #[serde(default)]
446 pub is_mutation_free: bool,
447 #[serde(default)]
450 pub is_external_mutation_free: bool,
451}
452
453impl MethodDef {
454 pub fn effective_return_type(&self) -> Option<&Type> {
455 self.return_type
456 .as_deref()
457 .or(self.inferred_return_type.as_deref())
458 }
459}
460
461#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
466pub struct PropertyDef {
467 pub name: Arc<str>,
468 #[serde(
475 deserialize_with = "deserialize_param_type",
476 serialize_with = "serialize_param_type"
477 )]
478 pub ty: Option<Arc<Type>>,
479 #[serde(
480 deserialize_with = "deserialize_param_type",
481 serialize_with = "serialize_param_type"
482 )]
483 pub inferred_ty: Option<Arc<Type>>,
484 pub visibility: Visibility,
485 pub is_static: bool,
486 pub is_readonly: bool,
487 #[serde(
488 deserialize_with = "deserialize_param_type",
489 serialize_with = "serialize_param_type"
490 )]
491 pub default: Option<Arc<Type>>,
492 pub location: Option<Location>,
493 #[serde(default)]
495 pub deprecated: Option<Arc<str>>,
496 #[serde(default)]
502 pub has_native_type: bool,
503 #[serde(default)]
508 pub from_docblock: bool,
509 #[serde(default)]
513 pub has_native_readonly: bool,
514}
515
516#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
521pub struct ConstantDef {
522 pub name: Arc<str>,
523 pub ty: Type,
524 pub visibility: Option<Visibility>,
525 #[serde(default)]
526 pub is_final: bool,
527 pub location: Option<Location>,
528 #[serde(default)]
530 pub deprecated: Option<Arc<str>>,
531}
532
533#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
538pub struct ClassDef {
539 pub fqcn: Arc<str>,
540 pub short_name: Arc<str>,
541 pub parent: Option<Arc<str>>,
542 pub interfaces: Vec<Arc<str>>,
543 pub traits: Vec<Arc<str>>,
544 pub own_methods: IndexMap<Arc<str>, Arc<MethodDef>>,
545 pub own_properties: IndexMap<Arc<str>, PropertyDef>,
546 pub own_constants: IndexMap<Arc<str>, ConstantDef>,
547 #[serde(default)]
548 pub mixins: Vec<Arc<str>>,
549 pub template_params: Vec<TemplateParam>,
550 pub extends_type_args: Vec<Type>,
552 #[serde(default)]
554 pub implements_type_args: Vec<(Arc<str>, Vec<Type>)>,
555 pub is_abstract: bool,
556 pub is_final: bool,
557 pub is_readonly: bool,
558 pub deprecated: Option<Arc<str>>,
559 pub is_internal: bool,
560 #[serde(default)]
563 pub is_immutable: bool,
564 #[serde(default)]
568 pub attribute_flags: Option<i64>,
569 pub location: Option<Location>,
570 #[serde(default)]
574 pub trait_use_locations: Vec<(Arc<str>, Location)>,
575 #[serde(default)]
577 pub type_aliases: FxHashMap<Arc<str>, Type>,
578 #[serde(default)]
580 pub pending_import_types: Vec<(Arc<str>, Arc<str>, Arc<str>)>,
581 #[serde(default)]
585 pub trait_insteadof: IndexMap<Arc<str>, Vec<Arc<str>>>,
586 #[serde(default)]
595 #[allow(clippy::type_complexity)]
596 pub trait_aliases:
597 FxHashMap<Arc<str>, (Option<Arc<str>>, Arc<str>, Option<Visibility>, Arc<str>)>,
598}
599
600impl ClassDef {
601 pub fn get_method(&self, name: &str) -> Option<&MethodDef> {
602 self.own_methods.get(name).map(Arc::as_ref).or_else(|| {
606 self.own_methods
607 .iter()
608 .find(|(k, _)| k.as_ref().eq_ignore_ascii_case(name))
609 .map(|(_, v)| v.as_ref())
610 })
611 }
612
613 pub fn get_property(&self, name: &str) -> Option<&PropertyDef> {
614 self.own_properties.get(name)
615 }
616}
617
618#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
623pub struct InterfaceDef {
624 pub fqcn: Arc<str>,
625 pub short_name: Arc<str>,
626 pub extends: Vec<Arc<str>>,
627 pub own_methods: IndexMap<Arc<str>, Arc<MethodDef>>,
628 pub own_constants: IndexMap<Arc<str>, ConstantDef>,
629 pub template_params: Vec<TemplateParam>,
630 pub location: Option<Location>,
631 #[serde(default)]
633 pub deprecated: Option<Arc<str>>,
634 #[serde(default)]
636 pub own_properties: IndexMap<Arc<str>, PropertyDef>,
637 #[serde(default)]
639 pub seal_properties: bool,
640}
641
642#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
647pub struct TraitDef {
648 pub fqcn: Arc<str>,
649 pub short_name: Arc<str>,
650 pub own_methods: IndexMap<Arc<str>, Arc<MethodDef>>,
651 pub own_properties: IndexMap<Arc<str>, PropertyDef>,
652 pub own_constants: IndexMap<Arc<str>, ConstantDef>,
653 pub template_params: Vec<TemplateParam>,
654 pub traits: Vec<Arc<str>>,
656 pub location: Option<Location>,
657 #[serde(default)]
659 pub require_extends: Vec<Arc<str>>,
660 #[serde(default)]
662 pub require_implements: Vec<Arc<str>>,
663 #[serde(default)]
665 pub deprecated: Option<Arc<str>>,
666}
667
668#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
673pub struct EnumCaseDef {
674 pub name: Arc<str>,
675 pub value: Option<Type>,
676 pub location: Option<Location>,
677 #[serde(default)]
679 pub deprecated: Option<Arc<str>>,
680}
681
682#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
683pub struct EnumDef {
684 pub fqcn: Arc<str>,
685 pub short_name: Arc<str>,
686 pub scalar_type: Option<Type>,
687 pub interfaces: Vec<Arc<str>>,
688 pub cases: IndexMap<Arc<str>, EnumCaseDef>,
689 pub own_methods: IndexMap<Arc<str>, Arc<MethodDef>>,
690 pub own_constants: IndexMap<Arc<str>, ConstantDef>,
691 pub location: Option<Location>,
692}
693
694#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
699pub struct FunctionDef {
700 pub fqn: Arc<str>,
701 pub short_name: Arc<str>,
702 #[serde(
703 deserialize_with = "deserialize_params",
704 serialize_with = "serialize_params"
705 )]
706 pub params: Arc<[FnParam]>,
707 #[serde(
710 deserialize_with = "deserialize_return_type",
711 serialize_with = "serialize_return_type"
712 )]
713 pub return_type: Option<Arc<Type>>,
714 #[serde(
717 deserialize_with = "deserialize_return_type",
718 serialize_with = "serialize_return_type"
719 )]
720 pub inferred_return_type: Option<Arc<Type>>,
721 pub template_params: Vec<TemplateParam>,
722 pub assertions: Vec<Assertion>,
723 pub throws: Vec<Arc<str>>,
724 pub deprecated: Option<Arc<str>>,
725 pub is_pure: bool,
726 #[serde(default)]
728 pub no_named_arguments: bool,
729 pub location: Option<Location>,
730 #[serde(default)]
733 pub docstring: Option<Arc<str>>,
734 #[serde(default)]
737 pub taint_sink_params: Vec<(Arc<str>, Arc<str>)>,
738}
739
740impl FunctionDef {
741 pub fn effective_return_type(&self) -> Option<&Type> {
742 self.return_type
743 .as_deref()
744 .or(self.inferred_return_type.as_deref())
745 }
746}
747
748#[derive(Debug, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)]
758pub struct StubSlice {
759 pub classes: Vec<Arc<ClassDef>>,
760 pub interfaces: Vec<Arc<InterfaceDef>>,
761 pub traits: Vec<Arc<TraitDef>>,
762 pub enums: Vec<Arc<EnumDef>>,
763 pub functions: Vec<Arc<FunctionDef>>,
764 #[serde(default)]
765 pub constants: Vec<(Arc<str>, Type)>,
766 #[serde(default)]
769 pub file: Option<Arc<str>>,
770 #[serde(default)]
774 pub global_vars: Vec<(Arc<str>, Type)>,
775 #[serde(default)]
779 pub namespace: Option<Arc<str>>,
780 #[serde(
790 deserialize_with = "deserialize_imports",
791 serialize_with = "serialize_imports"
792 )]
793 #[serde(default = "default_imports")]
794 pub imports: Arc<FxHashMap<Name, Name>>,
795 #[serde(skip)]
798 pub is_deduped: bool,
799}
800
801use std::sync::Mutex;
806
807type ParamCache = Mutex<FxHashMap<Vec<FnParam>, Arc<[FnParam]>>>;
808
809static PARAM_DEDUP_CACHE: std::sync::OnceLock<ParamCache> = std::sync::OnceLock::new();
813
814pub fn deduplicate_params_in_slice(slice: &mut StubSlice) {
822 let cache: &ParamCache = PARAM_DEDUP_CACHE.get_or_init(|| Mutex::new(FxHashMap::default()));
823 let mut canonical_params = cache.lock().unwrap();
824
825 let mut deduplicate = |params: &mut Arc<[FnParam]>| {
826 if let Some(existing) = canonical_params.get(params.as_ref()) {
827 *params = existing.clone();
828 } else {
829 canonical_params.insert(params.as_ref().to_vec(), params.clone());
830 }
831 };
832
833 for cls in &mut slice.classes {
835 for method in Arc::make_mut(cls).own_methods.values_mut() {
836 deduplicate(&mut Arc::make_mut(method).params);
837 }
838 }
839
840 for iface in &mut slice.interfaces {
842 for method in Arc::make_mut(iface).own_methods.values_mut() {
843 deduplicate(&mut Arc::make_mut(method).params);
844 }
845 }
846
847 for tr in &mut slice.traits {
849 for method in Arc::make_mut(tr).own_methods.values_mut() {
850 deduplicate(&mut Arc::make_mut(method).params);
851 }
852 }
853
854 for en in &mut slice.enums {
856 for method in Arc::make_mut(en).own_methods.values_mut() {
857 deduplicate(&mut Arc::make_mut(method).params);
858 }
859 }
860
861 for func in &mut slice.functions {
863 deduplicate(&mut Arc::make_mut(func).params);
864 }
865 slice.is_deduped = true;
866}