Skip to main content

mago_codex/metadata/
parameter.rs

1use mago_span::HasSpan;
2use mago_span::Span;
3
4use crate::metadata::attribute::AttributeMetadata;
5use crate::metadata::flags::MetadataFlags;
6use crate::metadata::ttype::TypeMetadata;
7use crate::misc::VariableIdentifier;
8
9/// Contains metadata associated with a single parameter within a function, method, or closure signature.
10///
11/// This captures details like the parameter's name, type hint, attributes, default value,
12/// pass-by-reference status, variadic nature, and other PHP features like property promotion.
13#[derive(Debug, Clone, PartialEq, Eq, Hash)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15#[non_exhaustive]
16pub struct FunctionLikeParameterMetadata {
17    /// Attributes attached to the parameter declaration.
18    pub attributes: Vec<AttributeMetadata>,
19
20    /// The identifier (name) of the parameter, including the leading '$'.
21    pub name: VariableIdentifier,
22
23    /// The native type declaration from the function signature.
24    ///
25    /// This is the type hint specified in the code (e.g., `string $name`), not from docblocks.
26    /// Can be `None` if no type hint is specified in the signature.
27    pub type_declaration_metadata: Option<TypeMetadata>,
28
29    /// The explicit type declaration (type hint) or docblock type (`@param`).
30    ///
31    /// If there's a docblock `@param` annotation, this will contain that type (with `from_docblock=true`).
32    /// Otherwise, this will be the same as `type_declaration_metadata`.
33    /// Can be `None` if no type is specified.
34    pub type_metadata: Option<TypeMetadata>,
35
36    /// The type specified by a `@param-out` docblock tag.
37    ///
38    /// This indicates the expected type of a pass-by-reference parameter *after* the function executes.
39    pub out_type: Option<TypeMetadata>,
40
41    /// The type specified by a `@param-closure-this` docblock tag.
42    ///
43    /// When this parameter receives a closure, that closure is invoked with `$this` bound to an
44    /// instance of this type. A closure literal passed here is analyzed with `$this` set accordingly.
45    pub closure_this_type: Option<TypeMetadata>,
46
47    /// The inferred type of the parameter's default value, if `has_default` is true and the
48    /// type could be determined.
49    ///
50    /// `None` if there is no default or the default value's type couldn't be inferred.
51    pub default_type: Option<TypeMetadata>,
52
53    /// The source code location (span) covering the entire parameter declaration.
54    pub span: Span,
55
56    /// The specific source code location (span) of the parameter's name identifier.
57    pub name_span: Span,
58
59    /// Flags indicating various properties of the parameter.
60    pub flags: MetadataFlags,
61}
62
63/// Contains metadata associated with a single parameter within a function, method, or closure signature.
64///
65/// This captures details like the parameter's name, type hint, attributes, default value,
66/// pass-by-reference status, variadic nature, and other PHP features like property promotion.
67impl FunctionLikeParameterMetadata {
68    /// Creates new `FunctionLikeParameterMetadata` for a basic parameter.
69    /// Initializes most flags to false and optional fields to None.
70    ///
71    /// # Arguments
72    ///
73    /// * `name`: The identifier (name) of the parameter (e.g., `$userId`).
74    /// * `span`: The source code location covering the entire parameter declaration.
75    /// * `name_span`: The source code location of the parameter's name identifier (`$userId`).
76    #[must_use]
77    pub fn new(name: VariableIdentifier, span: Span, name_span: Span, flags: MetadataFlags) -> Self {
78        Self {
79            attributes: Vec::new(),
80            name,
81            flags,
82            span,
83            name_span,
84            type_declaration_metadata: None,
85            type_metadata: None,
86            out_type: None,
87            closure_this_type: None,
88            default_type: None,
89        }
90    }
91
92    /// Returns a reference to the parameter's name identifier (e.g., `$userId`).
93    #[inline]
94    #[must_use]
95    pub fn get_name(&self) -> &VariableIdentifier {
96        &self.name
97    }
98
99    /// Returns the span covering the entire parameter declaration.
100    #[inline]
101    #[must_use]
102    pub fn get_span(&self) -> Span {
103        self.span
104    }
105
106    /// Returns the span covering the parameter's name identifier.
107    #[inline]
108    #[must_use]
109    pub fn get_name_span(&self) -> Span {
110        self.name_span
111    }
112
113    /// Returns a reference to the parameter's type metadata (effective type with docblock).
114    #[inline]
115    #[must_use]
116    pub fn get_type_metadata(&self) -> Option<&TypeMetadata> {
117        self.type_metadata.as_ref()
118    }
119
120    /// Returns a reference to the parameter's native type declaration metadata.
121    #[inline]
122    #[must_use]
123    pub fn get_type_declaration_metadata(&self) -> Option<&TypeMetadata> {
124        self.type_declaration_metadata.as_ref()
125    }
126
127    /// Returns a reference to the inferred type of the default value, if known.
128    #[inline]
129    #[must_use]
130    pub fn get_default_type(&self) -> Option<&TypeMetadata> {
131        self.default_type.as_ref()
132    }
133
134    /// Sets the attributes, replacing any existing ones.
135    pub fn set_attributes(&mut self, attributes: impl IntoIterator<Item = AttributeMetadata>) {
136        self.attributes = attributes.into_iter().collect();
137    }
138
139    /// Returns a new instance with the attributes replaced.
140    #[must_use]
141    pub fn with_attributes(mut self, attributes: impl IntoIterator<Item = AttributeMetadata>) -> Self {
142        self.set_attributes(attributes);
143        self
144    }
145
146    /// Sets the parameter's type metadata (effective type with docblock).
147    #[inline]
148    pub fn set_type_metadata(&mut self, type_metadata: Option<TypeMetadata>) {
149        self.type_metadata = type_metadata;
150    }
151
152    /// Sets the parameter's native type declaration metadata.
153    ///
154    /// If `type_metadata` is not set, it will be initialized with the same value.
155    #[inline]
156    pub fn set_type_declaration_metadata(&mut self, type_declaration: Option<TypeMetadata>) {
157        if self.type_metadata.is_none() {
158            self.type_metadata.clone_from(&type_declaration);
159        }
160
161        self.type_declaration_metadata = type_declaration;
162    }
163}
164
165impl HasSpan for FunctionLikeParameterMetadata {
166    fn span(&self) -> Span {
167        self.span
168    }
169}