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    /// Type aliases declared on this class via `@psalm-type` / `@phpstan-type`.
203    #[serde(default)]
204    pub type_aliases: std::collections::HashMap<Arc<str>, Union>,
205    /// Raw import-type declarations (`(local_name, original_name, from_class)`) — resolved during finalization.
206    #[serde(default)]
207    pub pending_import_types: Vec<(Arc<str>, Arc<str>, Arc<str>)>,
208}
209
210impl ClassStorage {
211    pub fn get_method(&self, name: &str) -> Option<&MethodStorage> {
212        // PHP method names are case-insensitive; caller should pass lowercase name.
213        // Only searches own_methods — inherited method resolution is done by Codebase::get_method.
214        self.own_methods.get(name).map(Arc::as_ref).or_else(|| {
215            self.own_methods
216                .iter()
217                .find(|(k, _)| k.as_ref().eq_ignore_ascii_case(name))
218                .map(|(_, v)| v.as_ref())
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>, Arc<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>, Arc<MethodStorage>>,
256    pub own_properties: IndexMap<Arc<str>, PropertyStorage>,
257    pub own_constants: IndexMap<Arc<str>, ConstantStorage>,
258    pub template_params: Vec<TemplateParam>,
259    /// Traits used by this trait (`use OtherTrait;` inside a trait body).
260    pub traits: Vec<Arc<str>>,
261    pub location: Option<Location>,
262    /// `@psalm-require-extends` / `@phpstan-require-extends` — FQCNs that using classes must extend.
263    #[serde(default)]
264    pub require_extends: Vec<Arc<str>>,
265    /// `@psalm-require-implements` / `@phpstan-require-implements` — FQCNs that using classes must implement.
266    #[serde(default)]
267    pub require_implements: Vec<Arc<str>>,
268}
269
270// ---------------------------------------------------------------------------
271// EnumStorage
272// ---------------------------------------------------------------------------
273
274#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
275pub struct EnumCaseStorage {
276    pub name: Arc<str>,
277    pub value: Option<Union>,
278    pub location: Option<Location>,
279}
280
281#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
282pub struct EnumStorage {
283    pub fqcn: Arc<str>,
284    pub short_name: Arc<str>,
285    pub scalar_type: Option<Union>,
286    pub interfaces: Vec<Arc<str>>,
287    pub cases: IndexMap<Arc<str>, EnumCaseStorage>,
288    pub own_methods: IndexMap<Arc<str>, Arc<MethodStorage>>,
289    pub own_constants: IndexMap<Arc<str>, ConstantStorage>,
290    pub location: Option<Location>,
291}
292
293// ---------------------------------------------------------------------------
294// FunctionStorage
295// ---------------------------------------------------------------------------
296
297#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
298pub struct FunctionStorage {
299    pub fqn: Arc<str>,
300    pub short_name: Arc<str>,
301    pub params: Vec<FnParam>,
302    pub return_type: Option<Union>,
303    pub inferred_return_type: Option<Union>,
304    pub template_params: Vec<TemplateParam>,
305    pub assertions: Vec<Assertion>,
306    pub throws: Vec<Arc<str>>,
307    pub deprecated: Option<Arc<str>>,
308    pub is_pure: bool,
309    pub location: Option<Location>,
310}
311
312impl FunctionStorage {
313    pub fn effective_return_type(&self) -> Option<&Union> {
314        self.return_type
315            .as_ref()
316            .or(self.inferred_return_type.as_ref())
317    }
318}
319
320// ---------------------------------------------------------------------------
321// StubSlice — serializable bundle of definitions from one extension's stubs
322// ---------------------------------------------------------------------------
323
324/// A snapshot of all PHP definitions contributed by a single stub file set.
325///
326/// Produced by `mir-stubs-gen` at code-generation time and deserialized at
327/// runtime to inject definitions into the `Codebase`.
328#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
329pub struct StubSlice {
330    pub classes: Vec<ClassStorage>,
331    pub interfaces: Vec<InterfaceStorage>,
332    pub traits: Vec<TraitStorage>,
333    pub enums: Vec<EnumStorage>,
334    pub functions: Vec<FunctionStorage>,
335    #[serde(default)]
336    pub constants: Vec<(Arc<str>, Union)>,
337    /// Source file this slice was collected from. `None` for bundled stub slices
338    /// that were pre-computed and are not tied to a specific on-disk file.
339    #[serde(default)]
340    pub file: Option<Arc<str>>,
341    /// Types of `@var`-annotated global variables collected from this file.
342    /// Populated by `DefinitionCollector`; merged into `Codebase::global_vars`
343    /// by [`crate::Codebase::inject_stub_slice`] when `file` is `Some`.
344    #[serde(default)]
345    pub global_vars: Vec<(Arc<str>, Union)>,
346}