mago_reflection/class_like/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
use ahash::HashMap;
use ahash::HashSet;
use serde::Deserialize;
use serde::Serialize;

use mago_interner::StringIdentifier;
use mago_reporting::IssueCollection;
use mago_source::HasSource;
use mago_source::SourceIdentifier;
use mago_span::HasSpan;
use mago_span::Span;

use crate::attribute::AttributeReflection;
use crate::class_like::constant::ClassLikeConstantReflection;
use crate::class_like::enum_case::EnumCaseReflection;
use crate::class_like::inheritance::InheritanceReflection;
use crate::class_like::member::MemeberCollection;
use crate::class_like::property::PropertyReflection;
use crate::function_like::FunctionLikeReflection;
use crate::identifier::ClassLikeName;
use crate::identifier::Name;
use crate::r#type::TypeReflection;
use crate::Reflection;

pub mod constant;
pub mod enum_case;
pub mod inheritance;
pub mod member;
pub mod property;

/// Represents reflection data for a PHP class, interface, enum, or trait.
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct ClassLikeReflection {
    /// Attributes (e.g., annotations) associated with the class-like entity.
    pub attribute_reflections: Vec<AttributeReflection>,

    /// The name of the class-like entity, such as its fully qualified name.
    pub name: ClassLikeName,

    /// Inheritance information for the class-like entity, including parent classes and implemented interfaces.
    pub inheritance: InheritanceReflection,

    /// Constants defined in the class-like entity.
    pub constants: HashMap<StringIdentifier, ClassLikeConstantReflection>,

    /// Enum cases defined in the class-like entity, if it is an enum.
    pub cases: MemeberCollection<EnumCaseReflection>,

    /// Properties defined in the class-like entity.
    pub properties: MemeberCollection<PropertyReflection>,

    /// Methods defined in the class-like entity.
    pub methods: MemeberCollection<FunctionLikeReflection>,

    /// Traits used by the class-like entity.
    pub used_traits: HashSet<StringIdentifier>,

    /// The backing type of the entity, used if it is an enum.
    pub backing_type: Option<TypeReflection>,

    /// Whether the class-like entity is declared as `final`.
    pub is_final: bool,

    /// Whether the class-like entity is declared as `readonly`.
    pub is_readonly: bool,

    /// Whether the class-like entity is declared as `abstract`.
    pub is_abstract: bool,

    /// Whether the entity is an anonymous class.
    pub is_anonymous: bool,

    /// The span in the source code where the class-like entity is declared.
    pub span: Span,

    /// Indicates whether the reflection is fully populated with all metadata.
    pub is_populated: bool,

    /// Issues encountered while processing the class-like entity.
    pub issues: IssueCollection,
}

impl ClassLikeReflection {
    /// Checks if this class-like entity is a trait.
    pub fn is_trait(&self) -> bool {
        matches!(self.name, ClassLikeName::Trait(_))
    }

    /// Checks if this class-like entity is an interface.
    pub fn is_interface(&self) -> bool {
        matches!(self.name, ClassLikeName::Interface(_))
    }

    /// Checks if this class-like entity is a class.
    pub fn is_class(&self) -> bool {
        matches!(self.name, ClassLikeName::Class(_))
    }

    /// Checks if this class-like entity is an enum.
    pub fn is_enum(&self) -> bool {
        matches!(self.name, ClassLikeName::Enum(_))
    }

    /// Checks if this class-like entity is a trait.
    pub fn is_anonymous_class(&self) -> bool {
        matches!(self.name, ClassLikeName::AnonymousClass(_))
    }

    /// Checks if this class-like entity extends the given class.
    pub fn extends_class(&self, class_like_identifier: &Name) -> bool {
        self.inheritance.all_extended_classes.contains(class_like_identifier)
    }

    /// Checks if this class-like entity implements the given interface.
    pub fn implements_interface(&self, interface_identifier: &Name) -> bool {
        self.inheritance.all_implemented_interfaces.contains(interface_identifier)
    }

    /// Checks if this interface extends the given interface.
    pub fn extends_interface(&self, interface_identifier: &Name) -> bool {
        self.inheritance.all_extended_interfaces.contains(interface_identifier)
    }

    /// Checks if this class-like entity uses the given trait.
    pub fn uses_trait(&self, trait_identifier: &StringIdentifier) -> bool {
        self.used_traits.contains(trait_identifier)
    }

    /// Checks if this class-like entity contains a constant with the given name.
    pub fn has_constant(&self, constant_name: &StringIdentifier) -> bool {
        self.constants.contains_key(constant_name)
    }

    /// Checks if this class-like entity contains an enum case with the given name.
    pub fn has_enum_case(&self, case_name: &StringIdentifier) -> bool {
        self.cases.appering_members.contains_key(case_name)
    }

    /// Checks if this class-like entity has a property with the given name.
    pub fn has_property(&self, property_name: &StringIdentifier) -> bool {
        self.properties.appering_members.contains_key(property_name)
    }

    /// Checks if this class-like entity has a method with the given name.
    pub fn has_method(&self, method_name: &StringIdentifier) -> bool {
        self.methods.appering_members.contains_key(method_name)
    }

    /// Retrieves a constant by name, if it exists.
    pub fn get_constant(&self, constant_name: &StringIdentifier) -> Option<&ClassLikeConstantReflection> {
        self.constants.get(constant_name)
    }

    /// Retrieves an enum case by name, if it exists.
    pub fn get_enum_case(&self, case_name: &StringIdentifier) -> Option<&EnumCaseReflection> {
        self.cases.members.get(case_name)
    }

    /// Retrieves a property by name, if it exists.
    pub fn get_property(&self, property_name: &StringIdentifier) -> Option<&PropertyReflection> {
        self.properties.members.get(property_name)
    }

    /// Retrieves a method by name, if it exists.
    pub fn get_method(&self, method_name: &StringIdentifier) -> Option<&FunctionLikeReflection> {
        self.methods.members.get(method_name)
    }
}

impl HasSpan for ClassLikeReflection {
    /// Returns the span of the class-like entity in the source code.
    ///
    /// The span covers the entire declaration of the entity, including its attributes,
    /// inheritance, and body.
    fn span(&self) -> Span {
        self.span
    }
}

impl HasSource for ClassLikeReflection {
    /// Returns the source identifier of the file containing this class-like entity.
    ///
    /// The source identifier provides metadata about the origin of the entity,
    /// such as whether it is user-defined, vendor-provided, or built-in.
    fn source(&self) -> SourceIdentifier {
        self.span.source()
    }
}

impl Reflection for ClassLikeReflection {
    /// Returns the source category of the class-like entity.
    ///
    /// The category indicates whether the entity is part of the project (`UserDefined`),
    /// vendor-provided (`Vendor`), or built-in (`BuiltIn`).
    fn get_category(&self) -> crate::SourceCategory {
        self.source().category()
    }

    /// Indicates whether the class-like entity's reflection data is fully populated.
    ///
    /// If `is_populated` is `false`, additional processing may be required to resolve
    /// all metadata for this entity.
    fn is_populated(&self) -> bool {
        self.is_populated
    }

    /// Returns the issues encountered while processing the class-like entity.
    fn get_issues(&self) -> &IssueCollection {
        &self.issues
    }
}