Skip to main content

mir_codebase/
storage.rs

1use std::sync::Arc;
2
3use indexmap::IndexMap;
4use mir_types::Union;
5use serde::{Deserialize, Serialize};
6
7// ---------------------------------------------------------------------------
8// Shared primitives
9// ---------------------------------------------------------------------------
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
12pub enum Visibility {
13    Public,
14    Protected,
15    Private,
16}
17
18impl Visibility {
19    pub fn is_at_least(&self, required: Visibility) -> bool {
20        *self <= required
21    }
22}
23
24impl std::fmt::Display for Visibility {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        match self {
27            Visibility::Public => write!(f, "public"),
28            Visibility::Protected => write!(f, "protected"),
29            Visibility::Private => write!(f, "private"),
30        }
31    }
32}
33
34#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
35pub struct TemplateParam {
36    pub name: Arc<str>,
37    pub bound: Option<Union>,
38    /// The entity (class or function FQN) that declared this template param.
39    pub defining_entity: Arc<str>,
40}
41
42#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
43pub struct FnParam {
44    pub name: Arc<str>,
45    pub ty: Option<Union>,
46    pub default: Option<Union>,
47    pub is_variadic: bool,
48    pub is_byref: bool,
49    pub is_optional: bool,
50}
51
52// ---------------------------------------------------------------------------
53// Location — file + byte offsets
54// ---------------------------------------------------------------------------
55
56#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
57pub struct Location {
58    pub file: Arc<str>,
59    /// Byte offset of the start of the declaration in the source.
60    pub start: u32,
61    pub end: u32,
62    /// 1-based line number of the declaration.
63    pub line: u32,
64    /// 0-based column offset of the declaration.
65    pub col: u16,
66}
67
68impl Location {
69    pub fn new(file: Arc<str>, start: u32, end: u32) -> Self {
70        Self {
71            file,
72            start,
73            end,
74            line: 1,
75            col: 0,
76        }
77    }
78
79    pub fn with_line_col(file: Arc<str>, start: u32, end: u32, line: u32, col: u16) -> Self {
80        Self {
81            file,
82            start,
83            end,
84            line,
85            col,
86        }
87    }
88}
89
90// ---------------------------------------------------------------------------
91// Assertion — `@psalm-assert`, `@psalm-assert-if-true`, etc.
92// ---------------------------------------------------------------------------
93
94#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
95pub enum AssertionKind {
96    Assert,
97    AssertIfTrue,
98    AssertIfFalse,
99}
100
101#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
102pub struct Assertion {
103    pub kind: AssertionKind,
104    pub param: Arc<str>,
105    pub ty: Union,
106}
107
108// ---------------------------------------------------------------------------
109// MethodStorage
110// ---------------------------------------------------------------------------
111
112#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
113pub struct MethodStorage {
114    pub name: Arc<str>,
115    pub fqcn: Arc<str>,
116    pub params: Vec<FnParam>,
117    /// Type from annotation (`@return` / native type hint). `None` means unannotated.
118    pub return_type: Option<Union>,
119    /// Type inferred from body analysis (filled in during pass 2).
120    pub inferred_return_type: Option<Union>,
121    pub visibility: Visibility,
122    pub is_static: bool,
123    pub is_abstract: bool,
124    pub is_final: bool,
125    pub is_constructor: bool,
126    pub template_params: Vec<TemplateParam>,
127    pub assertions: Vec<Assertion>,
128    pub throws: Vec<Arc<str>>,
129    pub is_deprecated: bool,
130    pub is_internal: bool,
131    pub is_pure: bool,
132    pub location: Option<Location>,
133}
134
135impl MethodStorage {
136    pub fn effective_return_type(&self) -> Option<&Union> {
137        self.return_type
138            .as_ref()
139            .or(self.inferred_return_type.as_ref())
140    }
141}
142
143// ---------------------------------------------------------------------------
144// PropertyStorage
145// ---------------------------------------------------------------------------
146
147#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
148pub struct PropertyStorage {
149    pub name: Arc<str>,
150    pub ty: Option<Union>,
151    pub inferred_ty: Option<Union>,
152    pub visibility: Visibility,
153    pub is_static: bool,
154    pub is_readonly: bool,
155    pub default: Option<Union>,
156    pub location: Option<Location>,
157}
158
159// ---------------------------------------------------------------------------
160// ConstantStorage
161// ---------------------------------------------------------------------------
162
163#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
164pub struct ConstantStorage {
165    pub name: Arc<str>,
166    pub ty: Union,
167    pub visibility: Option<Visibility>,
168    pub location: Option<Location>,
169}
170
171// ---------------------------------------------------------------------------
172// ClassStorage
173// ---------------------------------------------------------------------------
174
175#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
176pub struct ClassStorage {
177    pub fqcn: Arc<str>,
178    pub short_name: Arc<str>,
179    pub parent: Option<Arc<str>>,
180    pub interfaces: Vec<Arc<str>>,
181    pub traits: Vec<Arc<str>>,
182    pub own_methods: IndexMap<Arc<str>, MethodStorage>,
183    pub own_properties: IndexMap<Arc<str>, PropertyStorage>,
184    pub own_constants: IndexMap<Arc<str>, ConstantStorage>,
185    pub template_params: Vec<TemplateParam>,
186    pub is_abstract: bool,
187    pub is_final: bool,
188    pub is_readonly: bool,
189    /// Populated during codebase finalization: all inherited methods (parent chain + traits).
190    pub all_methods: IndexMap<Arc<str>, MethodStorage>,
191    /// Populated during finalization: all ancestor FQCNs (parents + interfaces, transitively).
192    pub all_parents: Vec<Arc<str>>,
193    pub is_deprecated: bool,
194    pub is_internal: bool,
195    pub location: Option<Location>,
196}
197
198impl ClassStorage {
199    pub fn get_method(&self, name: &str) -> Option<&MethodStorage> {
200        // PHP method names are case-insensitive; caller should pass lowercase name.
201        // Fast path: exact match (works when keys are stored lowercase).
202        if let Some(m) = self
203            .all_methods
204            .get(name)
205            .or_else(|| self.own_methods.get(name))
206        {
207            return Some(m);
208        }
209        // Fallback: case-insensitive scan (handles stubs stored with original case).
210        self.all_methods
211            .iter()
212            .find(|(k, _)| k.as_ref().eq_ignore_ascii_case(name))
213            .map(|(_, v)| v)
214            .or_else(|| {
215                self.own_methods
216                    .iter()
217                    .find(|(k, _)| k.as_ref().eq_ignore_ascii_case(name))
218                    .map(|(_, v)| v)
219            })
220    }
221
222    pub fn get_property(&self, name: &str) -> Option<&PropertyStorage> {
223        self.own_properties.get(name)
224    }
225
226    pub fn implements_or_extends(&self, fqcn: &str) -> bool {
227        self.fqcn.as_ref() == fqcn || self.all_parents.iter().any(|p| p.as_ref() == fqcn)
228    }
229}
230
231// ---------------------------------------------------------------------------
232// InterfaceStorage
233// ---------------------------------------------------------------------------
234
235#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
236pub struct InterfaceStorage {
237    pub fqcn: Arc<str>,
238    pub short_name: Arc<str>,
239    pub extends: Vec<Arc<str>>,
240    pub own_methods: IndexMap<Arc<str>, MethodStorage>,
241    pub own_constants: IndexMap<Arc<str>, ConstantStorage>,
242    pub template_params: Vec<TemplateParam>,
243    pub all_parents: Vec<Arc<str>>,
244    pub location: Option<Location>,
245}
246
247// ---------------------------------------------------------------------------
248// TraitStorage
249// ---------------------------------------------------------------------------
250
251#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
252pub struct TraitStorage {
253    pub fqcn: Arc<str>,
254    pub short_name: Arc<str>,
255    pub own_methods: IndexMap<Arc<str>, MethodStorage>,
256    pub own_properties: IndexMap<Arc<str>, PropertyStorage>,
257    pub own_constants: IndexMap<Arc<str>, ConstantStorage>,
258    pub template_params: Vec<TemplateParam>,
259    pub location: Option<Location>,
260}
261
262// ---------------------------------------------------------------------------
263// EnumStorage
264// ---------------------------------------------------------------------------
265
266#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
267pub struct EnumCaseStorage {
268    pub name: Arc<str>,
269    pub value: Option<Union>,
270    pub location: Option<Location>,
271}
272
273#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
274pub struct EnumStorage {
275    pub fqcn: Arc<str>,
276    pub short_name: Arc<str>,
277    pub scalar_type: Option<Union>,
278    pub interfaces: Vec<Arc<str>>,
279    pub cases: IndexMap<Arc<str>, EnumCaseStorage>,
280    pub own_methods: IndexMap<Arc<str>, MethodStorage>,
281    pub own_constants: IndexMap<Arc<str>, ConstantStorage>,
282    pub location: Option<Location>,
283}
284
285// ---------------------------------------------------------------------------
286// FunctionStorage
287// ---------------------------------------------------------------------------
288
289#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
290pub struct FunctionStorage {
291    pub fqn: Arc<str>,
292    pub short_name: Arc<str>,
293    pub params: Vec<FnParam>,
294    pub return_type: Option<Union>,
295    pub inferred_return_type: Option<Union>,
296    pub template_params: Vec<TemplateParam>,
297    pub assertions: Vec<Assertion>,
298    pub throws: Vec<Arc<str>>,
299    pub is_deprecated: bool,
300    pub is_pure: bool,
301    pub location: Option<Location>,
302}
303
304impl FunctionStorage {
305    pub fn effective_return_type(&self) -> Option<&Union> {
306        self.return_type
307            .as_ref()
308            .or(self.inferred_return_type.as_ref())
309    }
310}