Skip to main content

mago_analyzer/plugin/libraries/psr_container/
get.rs

1//! `Psr\Container\ContainerInterface::get()` return type provider.
2
3use mago_codex::ttype::atomic::TAtomic;
4use mago_codex::ttype::atomic::object::TObject;
5use mago_codex::ttype::atomic::object::named::TNamedObject;
6use mago_codex::ttype::union::TUnion;
7
8use crate::plugin::context::InvocationInfo;
9use crate::plugin::context::ProviderContext;
10use crate::plugin::provider::Provider;
11use crate::plugin::provider::ProviderMeta;
12use crate::plugin::provider::method::MethodReturnTypeProvider;
13use crate::plugin::provider::method::MethodTarget;
14
15static META: ProviderMeta = ProviderMeta::new(
16    "psr::container::get",
17    "ContainerInterface::get",
18    "Returns the object type matching the class-string argument",
19);
20
21// Use wildcard for class since many classes implement ContainerInterface
22static TARGETS: [MethodTarget; 1] = [MethodTarget::any_class(b"get")];
23
24/// Provider for the `Psr\Container\ContainerInterface::get()` method.
25///
26/// When called with a class-string argument like `SomeService::class`,
27/// returns the object type of that class instead of `mixed`.
28#[derive(Default)]
29pub struct ContainerGetProvider;
30
31impl Provider for ContainerGetProvider {
32    fn meta() -> &'static ProviderMeta {
33        &META
34    }
35}
36
37impl MethodReturnTypeProvider for ContainerGetProvider {
38    fn targets() -> &'static [MethodTarget] {
39        &TARGETS
40    }
41
42    fn get_return_type(
43        &self,
44        context: &ProviderContext<'_, '_, '_>,
45        class_name: &[u8],
46        _method_name: &[u8],
47        invocation: &InvocationInfo<'_, '_, '_>,
48    ) -> Option<TUnion> {
49        if !context.is_instance_of(class_name, b"Psr\\Container\\ContainerInterface") {
50            return None;
51        }
52
53        let id_arg = invocation.get_argument(0, &[b"id"])?;
54        let id_type = context.get_expression_type(id_arg)?;
55
56        // Extract class-string value (handles SomeClass::class)
57        let service_class = id_type.get_single_class_string_value()?;
58
59        // Return object type of that class
60        Some(TUnion::from_atomic(TAtomic::Object(TObject::Named(TNamedObject::new(service_class)))))
61    }
62}