Skip to main content

mago_codex/metadata/
property_hook.rs

1use serde::Deserialize;
2use serde::Serialize;
3
4use mago_atom::Atom;
5use mago_reporting::Issue;
6use mago_span::Span;
7
8use crate::metadata::attribute::AttributeMetadata;
9use crate::metadata::flags::MetadataFlags;
10use crate::metadata::parameter::FunctionLikeParameterMetadata;
11use crate::metadata::ttype::TypeMetadata;
12
13/// Metadata for a property hook (get or set).
14///
15/// PHP 8.4 introduced property hooks, which allow defining custom get/set behavior
16/// for properties. This struct stores the metadata for a single hook.
17#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
18#[non_exhaustive]
19pub struct PropertyHookMetadata {
20    /// The hook name ("get" or "set").
21    pub name: Atom,
22
23    /// Span of the hook declaration.
24    pub span: Span,
25
26    /// Hook modifiers (final, etc.).
27    pub flags: MetadataFlags,
28
29    /// For set hooks: the parameter (explicit or implicit $value).
30    /// None for get hooks.
31    pub parameter: Option<FunctionLikeParameterMetadata>,
32
33    /// Whether the hook returns by reference (&get).
34    pub returns_by_ref: bool,
35
36    /// Whether this is an abstract hook (no body, just semicolon).
37    pub is_abstract: bool,
38
39    /// Attributes on the hook.
40    pub attributes: Vec<AttributeMetadata>,
41
42    /// Return type from @return docblock (for get hooks).
43    pub return_type_metadata: Option<TypeMetadata>,
44
45    /// Whether this hook has a docblock comment.
46    pub has_docblock: bool,
47
48    /// Issues from parsing the docblock.
49    pub issues: Vec<Issue>,
50}
51
52impl PropertyHookMetadata {
53    /// Creates a new `PropertyHookMetadata` with the given name and span.
54    #[inline]
55    #[must_use]
56    pub fn new(name: Atom, span: Span) -> Self {
57        Self {
58            name,
59            span,
60            flags: MetadataFlags::empty(),
61            parameter: None,
62            returns_by_ref: false,
63            is_abstract: false,
64            attributes: Vec::new(),
65            return_type_metadata: None,
66            has_docblock: false,
67            issues: Vec::new(),
68        }
69    }
70
71    /// Returns whether this is a get hook.
72    #[inline]
73    #[must_use]
74    pub fn is_get(&self) -> bool {
75        self.name.as_str() == "get"
76    }
77
78    /// Returns whether this is a set hook.
79    #[inline]
80    #[must_use]
81    pub fn is_set(&self) -> bool {
82        self.name.as_str() == "set"
83    }
84
85    /// Sets the flags for this hook.
86    #[inline]
87    #[must_use]
88    pub fn with_flags(mut self, flags: MetadataFlags) -> Self {
89        self.flags = flags;
90        self
91    }
92
93    /// Sets the parameter for this hook (for set hooks).
94    #[inline]
95    #[must_use]
96    pub fn with_parameter(mut self, parameter: Option<FunctionLikeParameterMetadata>) -> Self {
97        self.parameter = parameter;
98        self
99    }
100
101    /// Sets whether the hook returns by reference.
102    #[inline]
103    #[must_use]
104    pub fn with_returns_by_ref(mut self, returns_by_ref: bool) -> Self {
105        self.returns_by_ref = returns_by_ref;
106        self
107    }
108
109    /// Sets whether this is an abstract hook.
110    #[inline]
111    #[must_use]
112    pub fn with_is_abstract(mut self, is_abstract: bool) -> Self {
113        self.is_abstract = is_abstract;
114        self
115    }
116
117    /// Sets the attributes for this hook.
118    #[inline]
119    #[must_use]
120    pub fn with_attributes(mut self, attributes: Vec<AttributeMetadata>) -> Self {
121        self.attributes = attributes;
122        self
123    }
124
125    /// Sets the return type metadata from docblock (for get hooks).
126    #[inline]
127    #[must_use]
128    pub fn with_return_type_metadata(mut self, return_type_metadata: Option<TypeMetadata>) -> Self {
129        self.return_type_metadata = return_type_metadata;
130        self
131    }
132
133    /// Sets whether this hook has a docblock.
134    #[inline]
135    #[must_use]
136    pub fn with_has_docblock(mut self, has_docblock: bool) -> Self {
137        self.has_docblock = has_docblock;
138        self
139    }
140
141    /// Sets the issues from parsing the docblock.
142    #[inline]
143    #[must_use]
144    pub fn with_issues(mut self, issues: Vec<Issue>) -> Self {
145        self.issues = issues;
146        self
147    }
148
149    /// Takes the issues, leaving an empty vector.
150    #[inline]
151    pub fn take_issues(&mut self) -> Vec<Issue> {
152        std::mem::take(&mut self.issues)
153    }
154}