mago-analyzer 1.12.0

A PHP static analyzer that can detect type errors in PHP code, and provide suggestions for fixing them.
Documentation
//! Function return type provider trait.

use mago_atom::starts_with_ignore_case;
use mago_codex::ttype::union::TUnion;

use crate::plugin::context::InvocationInfo;
use crate::plugin::context::ProviderContext;
use crate::plugin::provider::Provider;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FunctionTarget {
    Exact(&'static str),
    ExactMultiple(&'static [&'static str]),
    Prefix(&'static str),
    Namespace(&'static str),
}

impl FunctionTarget {
    #[inline]
    #[must_use]
    pub const fn exact(name: &'static str) -> Self {
        Self::Exact(name)
    }

    #[inline]
    #[must_use]
    pub const fn exact_multiple(names: &'static [&'static str]) -> Self {
        Self::ExactMultiple(names)
    }

    #[inline]
    #[must_use]
    pub const fn prefix(prefix: &'static str) -> Self {
        Self::Prefix(prefix)
    }

    #[inline]
    #[must_use]
    pub const fn namespace(ns: &'static str) -> Self {
        Self::Namespace(ns)
    }

    #[must_use]
    pub fn matches(&self, name: &str) -> bool {
        match self {
            FunctionTarget::Exact(target) => name.eq_ignore_ascii_case(target),
            FunctionTarget::ExactMultiple(targets) => targets.iter().any(|target| name.eq_ignore_ascii_case(target)),
            FunctionTarget::Prefix(prefix) => starts_with_ignore_case(name, prefix),
            FunctionTarget::Namespace(ns) => starts_with_ignore_case(name, ns),
        }
    }

    #[must_use]
    pub fn get_exact_names(&self) -> Option<Vec<&'static str>> {
        match self {
            FunctionTarget::Exact(name) => Some(vec![*name]),
            FunctionTarget::ExactMultiple(names) => Some(names.to_vec()),
            FunctionTarget::Prefix(_) | FunctionTarget::Namespace(_) => None,
        }
    }

    #[must_use]
    pub fn is_prefix(&self) -> bool {
        matches!(self, FunctionTarget::Prefix(_))
    }

    #[must_use]
    pub fn is_namespace(&self) -> bool {
        matches!(self, FunctionTarget::Namespace(_))
    }

    #[must_use]
    pub fn get_prefix(&self) -> Option<&'static str> {
        match self {
            FunctionTarget::Prefix(prefix) => Some(prefix),
            _ => None,
        }
    }

    #[must_use]
    pub fn get_namespace(&self) -> Option<&'static str> {
        match self {
            FunctionTarget::Namespace(ns) => Some(ns),
            _ => None,
        }
    }
}

pub trait FunctionReturnTypeProvider: Provider {
    fn targets() -> FunctionTarget
    where
        Self: Sized;

    fn get_return_type(
        &self,
        context: &ProviderContext<'_, '_, '_>,
        invocation: &InvocationInfo<'_, '_, '_>,
    ) -> Option<TUnion>;
}