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 Unicode char-count (code-point) column offset of the declaration start.
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>, Arc<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 finalization: all ancestor FQCNs (parents + interfaces, transitively).
191    pub all_parents: Vec<Arc<str>>,
192    pub is_deprecated: bool,
193    pub is_internal: bool,
194    pub location: Option<Location>,
195}
196
197impl ClassStorage {
198    pub fn get_method(&self, name: &str) -> Option<&MethodStorage> {
199        // PHP method names are case-insensitive; caller should pass lowercase name.
200        // Only searches own_methods — inherited method resolution is done by Codebase::get_method.
201        self.own_methods.get(name).map(Arc::as_ref).or_else(|| {
202            self.own_methods
203                .iter()
204                .find(|(k, _)| k.as_ref().eq_ignore_ascii_case(name))
205                .map(|(_, v)| v.as_ref())
206        })
207    }
208
209    pub fn get_property(&self, name: &str) -> Option<&PropertyStorage> {
210        self.own_properties.get(name)
211    }
212
213    pub fn implements_or_extends(&self, fqcn: &str) -> bool {
214        self.fqcn.as_ref() == fqcn || self.all_parents.iter().any(|p| p.as_ref() == fqcn)
215    }
216}
217
218// ---------------------------------------------------------------------------
219// InterfaceStorage
220// ---------------------------------------------------------------------------
221
222#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
223pub struct InterfaceStorage {
224    pub fqcn: Arc<str>,
225    pub short_name: Arc<str>,
226    pub extends: Vec<Arc<str>>,
227    pub own_methods: IndexMap<Arc<str>, Arc<MethodStorage>>,
228    pub own_constants: IndexMap<Arc<str>, ConstantStorage>,
229    pub template_params: Vec<TemplateParam>,
230    pub all_parents: Vec<Arc<str>>,
231    pub location: Option<Location>,
232}
233
234// ---------------------------------------------------------------------------
235// TraitStorage
236// ---------------------------------------------------------------------------
237
238#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
239pub struct TraitStorage {
240    pub fqcn: Arc<str>,
241    pub short_name: Arc<str>,
242    pub own_methods: IndexMap<Arc<str>, Arc<MethodStorage>>,
243    pub own_properties: IndexMap<Arc<str>, PropertyStorage>,
244    pub own_constants: IndexMap<Arc<str>, ConstantStorage>,
245    pub template_params: Vec<TemplateParam>,
246    /// Traits used by this trait (`use OtherTrait;` inside a trait body).
247    pub traits: Vec<Arc<str>>,
248    pub location: Option<Location>,
249}
250
251// ---------------------------------------------------------------------------
252// EnumStorage
253// ---------------------------------------------------------------------------
254
255#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
256pub struct EnumCaseStorage {
257    pub name: Arc<str>,
258    pub value: Option<Union>,
259    pub location: Option<Location>,
260}
261
262#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
263pub struct EnumStorage {
264    pub fqcn: Arc<str>,
265    pub short_name: Arc<str>,
266    pub scalar_type: Option<Union>,
267    pub interfaces: Vec<Arc<str>>,
268    pub cases: IndexMap<Arc<str>, EnumCaseStorage>,
269    pub own_methods: IndexMap<Arc<str>, Arc<MethodStorage>>,
270    pub own_constants: IndexMap<Arc<str>, ConstantStorage>,
271    pub location: Option<Location>,
272}
273
274// ---------------------------------------------------------------------------
275// FunctionStorage
276// ---------------------------------------------------------------------------
277
278#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
279pub struct FunctionStorage {
280    pub fqn: Arc<str>,
281    pub short_name: Arc<str>,
282    pub params: Vec<FnParam>,
283    pub return_type: Option<Union>,
284    pub inferred_return_type: Option<Union>,
285    pub template_params: Vec<TemplateParam>,
286    pub assertions: Vec<Assertion>,
287    pub throws: Vec<Arc<str>>,
288    pub is_deprecated: bool,
289    pub is_pure: bool,
290    pub location: Option<Location>,
291}
292
293impl FunctionStorage {
294    pub fn effective_return_type(&self) -> Option<&Union> {
295        self.return_type
296            .as_ref()
297            .or(self.inferred_return_type.as_ref())
298    }
299}