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