Skip to main content

mago_analyzer/plugin/libraries/stdlib/reflection/
class_has_method.rs

1//! `ReflectionClass<T>::hasMethod()` assertion provider.
2
3use mago_codex::assertion::Assertion;
4use mago_word::word;
5
6use crate::plugin::context::InvocationInfo;
7use crate::plugin::context::ProviderContext;
8use crate::plugin::provider::Provider;
9use crate::plugin::provider::ProviderMeta;
10use crate::plugin::provider::assertion::InvocationAssertions;
11use crate::plugin::provider::assertion::MethodAssertionProvider;
12use crate::plugin::provider::method::MethodTarget;
13
14static META: ProviderMeta = ProviderMeta::new(
15    "reflection::class::has_method",
16    "ReflectionClass::hasMethod",
17    "Narrows the argument to a method name of the reflected class when true",
18);
19
20static TARGETS: [MethodTarget; 1] = [MethodTarget::any_class(b"hasMethod")];
21
22/// Provider for `ReflectionClass<T>::hasMethod($name)`.
23///
24/// When the call returns true, `$name` is one of `T`'s method names, so it is
25/// narrowed to the union of `T`'s method-name literals (e.g. `'greet'|'count'`)
26/// inside the truthy branch. This lets `if ($reflection->hasMethod($name)) {
27/// $object->{$name}(); }` resolve the dynamic call.
28#[derive(Default)]
29pub struct ReflectionClassHasMethodAssertionProvider;
30
31impl Provider for ReflectionClassHasMethodAssertionProvider {
32    fn meta() -> &'static ProviderMeta {
33        &META
34    }
35}
36
37impl MethodAssertionProvider for ReflectionClassHasMethodAssertionProvider {
38    fn targets() -> &'static [MethodTarget] {
39        &TARGETS
40    }
41
42    fn get_assertions(
43        &self,
44        context: &ProviderContext<'_, '_, '_>,
45        _class_name: &[u8],
46        _method_name: &[u8],
47        invocation: &InvocationInfo<'_, '_, '_>,
48    ) -> Option<InvocationAssertions> {
49        let reflected_class = super::reflected_class_name(context, invocation, b"ReflectionClass")?;
50        let method_names = super::method_name_union(context.codebase(), reflected_class)?;
51
52        let mut assertions = InvocationAssertions::new();
53        assertions.add_if_true(word("$name"), vec![Assertion::InArray(method_names)]);
54
55        Some(assertions)
56    }
57}