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 deprecated: Option<Arc<str>>,
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    #[serde(default)]
187    pub mixins: Vec<Arc<str>>,
188    pub template_params: Vec<TemplateParam>,
189    /// Type arguments from `@extends ParentClass<T1, T2>` — maps parent's template params to concrete types.
190    pub extends_type_args: Vec<Union>,
191    /// Type arguments from `@implements Interface<T1, T2>`.
192    #[serde(default)]
193    pub implements_type_args: Vec<(Arc<str>, Vec<Union>)>,
194    pub is_abstract: bool,
195    pub is_final: bool,
196    pub is_readonly: bool,
197    /// Populated during finalization: all ancestor FQCNs (parents + interfaces, transitively).
198    pub all_parents: Vec<Arc<str>>,
199    pub deprecated: Option<Arc<str>>,
200    pub is_internal: bool,
201    pub location: Option<Location>,
202}
203
204impl ClassStorage {
205    pub fn get_method(&self, name: &str) -> Option<&MethodStorage> {
206        // PHP method names are case-insensitive; caller should pass lowercase name.
207        // Only searches own_methods — inherited method resolution is done by Codebase::get_method.
208        self.own_methods.get(name).map(Arc::as_ref).or_else(|| {
209            self.own_methods
210                .iter()
211                .find(|(k, _)| k.as_ref().eq_ignore_ascii_case(name))
212                .map(|(_, v)| v.as_ref())
213        })
214    }
215
216    pub fn get_property(&self, name: &str) -> Option<&PropertyStorage> {
217        self.own_properties.get(name)
218    }
219
220    pub fn implements_or_extends(&self, fqcn: &str) -> bool {
221        self.fqcn.as_ref() == fqcn || self.all_parents.iter().any(|p| p.as_ref() == fqcn)
222    }
223}
224
225// ---------------------------------------------------------------------------
226// InterfaceStorage
227// ---------------------------------------------------------------------------
228
229#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
230pub struct InterfaceStorage {
231    pub fqcn: Arc<str>,
232    pub short_name: Arc<str>,
233    pub extends: Vec<Arc<str>>,
234    pub own_methods: IndexMap<Arc<str>, Arc<MethodStorage>>,
235    pub own_constants: IndexMap<Arc<str>, ConstantStorage>,
236    pub template_params: Vec<TemplateParam>,
237    pub all_parents: Vec<Arc<str>>,
238    pub location: Option<Location>,
239}
240
241// ---------------------------------------------------------------------------
242// TraitStorage
243// ---------------------------------------------------------------------------
244
245#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
246pub struct TraitStorage {
247    pub fqcn: Arc<str>,
248    pub short_name: Arc<str>,
249    pub own_methods: IndexMap<Arc<str>, Arc<MethodStorage>>,
250    pub own_properties: IndexMap<Arc<str>, PropertyStorage>,
251    pub own_constants: IndexMap<Arc<str>, ConstantStorage>,
252    pub template_params: Vec<TemplateParam>,
253    /// Traits used by this trait (`use OtherTrait;` inside a trait body).
254    pub traits: Vec<Arc<str>>,
255    pub location: Option<Location>,
256}
257
258// ---------------------------------------------------------------------------
259// EnumStorage
260// ---------------------------------------------------------------------------
261
262#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
263pub struct EnumCaseStorage {
264    pub name: Arc<str>,
265    pub value: Option<Union>,
266    pub location: Option<Location>,
267}
268
269#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
270pub struct EnumStorage {
271    pub fqcn: Arc<str>,
272    pub short_name: Arc<str>,
273    pub scalar_type: Option<Union>,
274    pub interfaces: Vec<Arc<str>>,
275    pub cases: IndexMap<Arc<str>, EnumCaseStorage>,
276    pub own_methods: IndexMap<Arc<str>, Arc<MethodStorage>>,
277    pub own_constants: IndexMap<Arc<str>, ConstantStorage>,
278    pub location: Option<Location>,
279}
280
281// ---------------------------------------------------------------------------
282// FunctionStorage
283// ---------------------------------------------------------------------------
284
285#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
286pub struct FunctionStorage {
287    pub fqn: Arc<str>,
288    pub short_name: Arc<str>,
289    pub params: Vec<FnParam>,
290    pub return_type: Option<Union>,
291    pub inferred_return_type: Option<Union>,
292    pub template_params: Vec<TemplateParam>,
293    pub assertions: Vec<Assertion>,
294    pub throws: Vec<Arc<str>>,
295    pub deprecated: Option<Arc<str>>,
296    pub is_pure: bool,
297    pub location: Option<Location>,
298}
299
300impl FunctionStorage {
301    pub fn effective_return_type(&self) -> Option<&Union> {
302        self.return_type
303            .as_ref()
304            .or(self.inferred_return_type.as_ref())
305    }
306}
307
308// ---------------------------------------------------------------------------
309// StubSlice — serializable bundle of definitions from one extension's stubs
310// ---------------------------------------------------------------------------
311
312/// A snapshot of all PHP definitions contributed by a single stub file set.
313///
314/// Produced by `mir-stubs-gen` at code-generation time and deserialized at
315/// runtime to inject definitions into the `Codebase`.
316#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
317pub struct StubSlice {
318    pub classes: Vec<ClassStorage>,
319    pub interfaces: Vec<InterfaceStorage>,
320    pub traits: Vec<TraitStorage>,
321    pub enums: Vec<EnumStorage>,
322    pub functions: Vec<FunctionStorage>,
323    #[serde(default)]
324    pub constants: Vec<(Arc<str>, Union)>,
325    /// Source file this slice was collected from. `None` for bundled stub slices
326    /// that were pre-computed and are not tied to a specific on-disk file.
327    #[serde(default)]
328    pub file: Option<Arc<str>>,
329    /// Types of `@var`-annotated global variables collected from this file.
330    /// Populated by `DefinitionCollector`; merged into `Codebase::global_vars`
331    /// by [`crate::Codebase::inject_stub_slice`] when `file` is `Some`.
332    #[serde(default)]
333    pub global_vars: Vec<(Arc<str>, Union)>,
334}