mago_analyzer/plugin/provider/
method.rs1use mago_atom::Atom;
4use mago_atom::ascii_lowercase_atom;
5use mago_atom::concat_atom;
6use mago_atom::starts_with_ignore_case;
7use mago_codex::ttype::union::TUnion;
8
9use crate::plugin::context::InvocationInfo;
10use crate::plugin::context::ProviderContext;
11use crate::plugin::provider::Provider;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub struct MethodTarget {
15 pub class: &'static str,
16 pub method: &'static str,
17}
18
19impl MethodTarget {
20 #[inline]
21 #[must_use]
22 pub const fn exact(class: &'static str, method: &'static str) -> Self {
23 Self { class, method }
24 }
25
26 #[inline]
27 #[must_use]
28 pub const fn all_methods(class: &'static str) -> Self {
29 Self { class, method: "*" }
30 }
31
32 #[inline]
33 #[must_use]
34 pub const fn any_class(method: &'static str) -> Self {
35 Self { class: "*", method }
36 }
37
38 #[must_use]
39 pub fn matches(&self, class_name: &str, method_name: &str) -> bool {
40 self.matches_class(class_name) && self.matches_method(method_name)
41 }
42
43 fn matches_class(&self, class_name: &str) -> bool {
44 if self.class == "*" {
45 return true;
46 }
47
48 if self.class.ends_with('*') {
49 starts_with_ignore_case(class_name, &self.class[..self.class.len() - 1])
50 } else {
51 class_name.eq_ignore_ascii_case(self.class)
52 }
53 }
54
55 fn matches_method(&self, method_name: &str) -> bool {
56 if self.method == "*" {
57 return true;
58 }
59
60 if self.method.ends_with('*') {
61 starts_with_ignore_case(method_name, &self.method[..self.method.len() - 1])
62 } else {
63 method_name.eq_ignore_ascii_case(self.method)
64 }
65 }
66
67 #[must_use]
68 pub fn is_exact(&self) -> bool {
69 !self.class.contains('*') && !self.method.contains('*')
70 }
71
72 #[must_use]
73 pub fn index_key(&self) -> Option<Atom> {
74 if self.is_exact() {
75 Some(concat_atom!(
76 ascii_lowercase_atom(self.class).as_str(),
77 "::",
78 ascii_lowercase_atom(self.method).as_str()
79 ))
80 } else {
81 None
82 }
83 }
84}
85
86pub trait MethodReturnTypeProvider: Provider {
87 fn targets() -> &'static [MethodTarget]
88 where
89 Self: Sized;
90
91 fn get_return_type(
92 &self,
93 context: &ProviderContext<'_, '_, '_>,
94 class_name: &str,
95 method_name: &str,
96 invocation: &InvocationInfo<'_, '_, '_>,
97 ) -> Option<TUnion>;
98}