Skip to main content

mago_analyzer/plugin/libraries/stdlib/enum/
cases.rs

1//! `UnitEnum::cases()` return type provider.
2
3use std::sync::Arc;
4
5use mago_codex::ttype::atomic::TAtomic;
6use mago_codex::ttype::atomic::array::TArray;
7use mago_codex::ttype::atomic::array::list::TList;
8use mago_codex::ttype::atomic::object::TObject;
9use mago_codex::ttype::atomic::object::r#enum::TEnum;
10use mago_codex::ttype::union::TUnion;
11
12use crate::plugin::context::InvocationInfo;
13use crate::plugin::context::ProviderContext;
14use crate::plugin::provider::Provider;
15use crate::plugin::provider::ProviderMeta;
16use crate::plugin::provider::method::MethodReturnTypeProvider;
17use crate::plugin::provider::method::MethodTarget;
18
19static META: ProviderMeta =
20    ProviderMeta::new("php::enum::cases", "UnitEnum::cases", "Returns non-empty-list for enums with at least one case");
21
22// Use wildcard for class since all enums implement UnitEnum
23static TARGETS: [MethodTarget; 1] = [MethodTarget::any_class(b"cases")];
24
25/// Provider for the `UnitEnum::cases()` method.
26///
27/// Returns `non-empty-list<EnumType>` for enums with at least one case,
28/// or `list<EnumType>` for enums with no cases (edge case).
29#[derive(Default)]
30pub struct EnumCasesProvider;
31
32impl Provider for EnumCasesProvider {
33    fn meta() -> &'static ProviderMeta {
34        &META
35    }
36}
37
38impl MethodReturnTypeProvider for EnumCasesProvider {
39    fn targets() -> &'static [MethodTarget] {
40        &TARGETS
41    }
42
43    fn get_return_type(
44        &self,
45        _context: &ProviderContext<'_, '_, '_>,
46        _class_name: &[u8],
47        _method_name: &[u8],
48        invocation_info: &InvocationInfo<'_, '_, '_>,
49    ) -> Option<TUnion> {
50        let class_metadata = invocation_info.invocation.target.get_method_context()?.class_like_metadata;
51
52        if !class_metadata.kind.is_enum() {
53            return None;
54        }
55
56        let enum_type = TUnion::from_atomic(TAtomic::Object(TObject::Enum(TEnum {
57            name: class_metadata.original_name,
58            case: None,
59        })));
60
61        if class_metadata.enum_cases.is_empty() {
62            Some(TUnion::from_atomic(TAtomic::Array(TArray::List(TList::new(Arc::new(enum_type))))))
63        } else {
64            Some(TUnion::from_atomic(TAtomic::Array(TArray::List(TList::new_non_empty(Arc::new(enum_type))))))
65        }
66    }
67}