Skip to main content

mago_syntax/ast/ast/class_like/
method.rs

1use serde::Serialize;
2use strum::Display;
3
4use mago_span::HasSpan;
5use mago_span::Span;
6
7use crate::ast::ast::attribute::AttributeList;
8use crate::ast::ast::block::Block;
9use crate::ast::ast::function_like::parameter::FunctionLikeParameterList;
10use crate::ast::ast::function_like::r#return::FunctionLikeReturnTypeHint;
11use crate::ast::ast::identifier::LocalIdentifier;
12use crate::ast::ast::keyword::Keyword;
13use crate::ast::ast::modifier::Modifier;
14use crate::ast::sequence::Sequence;
15
16/// Represents a method statement in PHP.
17///
18/// Example:
19///
20/// ```php
21/// class Foo {
22///    public function bar() {
23///       return 'baz';
24///    }
25/// }
26/// ```
27#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
28pub struct Method<'arena> {
29    pub attribute_lists: Sequence<'arena, AttributeList<'arena>>,
30    pub modifiers: Sequence<'arena, Modifier<'arena>>,
31    pub function: Keyword<'arena>,
32    pub ampersand: Option<Span>,
33    pub name: LocalIdentifier<'arena>,
34    pub parameter_list: FunctionLikeParameterList<'arena>,
35    pub return_type_hint: Option<FunctionLikeReturnTypeHint<'arena>>,
36    pub body: MethodBody<'arena>,
37}
38
39/// Represents the body of a method statement in PHP.
40#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord, Display)]
41#[serde(tag = "type", content = "value")]
42#[repr(u8)]
43pub enum MethodBody<'arena> {
44    Abstract(MethodAbstractBody),
45    Concrete(Block<'arena>),
46}
47
48/// Represents the abstract body of a method statement in PHP.
49///
50/// Example:
51///
52/// ```php
53/// <?php
54///
55/// abstract class Foo {
56///   abstract public function bar();
57/// }
58///
59/// ```
60#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
61pub struct MethodAbstractBody {
62    pub semicolon: Span,
63}
64
65impl Method<'_> {
66    /// Returns `true` if the method contains any promoted properties.
67    pub fn has_promoted_properties(&self) -> bool {
68        self.parameter_list
69            .parameters
70            .iter()
71            .any(super::super::function_like::parameter::FunctionLikeParameter::is_promoted_property)
72    }
73
74    /// Returns `true` if the method is abstract.
75    #[inline]
76    #[must_use]
77    pub const fn is_abstract(&self) -> bool {
78        matches!(self.body, MethodBody::Abstract(_))
79    }
80
81    /// Returns `true` if the method is static.
82    #[inline]
83    pub fn is_static(&self) -> bool {
84        self.modifiers.iter().any(super::super::modifier::Modifier::is_static)
85    }
86}
87
88impl HasSpan for Method<'_> {
89    fn span(&self) -> Span {
90        if let Some(attribute_list) = self.attribute_lists.first() {
91            return Span::between(attribute_list.span(), self.body.span());
92        }
93
94        if let Some(modifier) = self.modifiers.first() {
95            return Span::between(modifier.span(), self.body.span());
96        }
97
98        Span::between(self.function.span, self.body.span())
99    }
100}
101
102impl HasSpan for MethodBody<'_> {
103    fn span(&self) -> Span {
104        match self {
105            MethodBody::Abstract(body) => body.span(),
106            MethodBody::Concrete(body) => body.span(),
107        }
108    }
109}
110
111impl HasSpan for MethodAbstractBody {
112    fn span(&self) -> Span {
113        self.semicolon
114    }
115}