Skip to main content

krait/lang/
go.rs

1/// Strip Go method receiver prefix from a symbol name.
2///
3/// Go struct methods are indexed with a receiver prefix:
4///   `"(*ReceiverType).MethodName"` or `"ReceiverType.MethodName"`
5///
6/// Returns the base name (everything after the last `")."`), or the original
7/// string if no receiver prefix is present.
8#[must_use]
9pub fn base_name(s: &str) -> &str {
10    s.rfind(").").map_or(s, |i| &s[i + 2..])
11}
12
13/// Check if a gopls document symbol name matches a `Receiver.Method` query.
14///
15/// gopls returns Go receiver methods as flat document symbol entries with names
16/// like `(*Handler).CreateSession` (pointer receiver) or `(Handler).CreateSession`
17/// (value receiver) — NOT as children of the struct.
18///
19/// Returns `true` when the symbol's receiver type (with `*` stripped) equals
20/// `receiver` and `base_name(symbol_name)` equals `method`.
21#[must_use]
22pub fn receiver_method_matches(symbol_name: &str, receiver: &str, method: &str) -> bool {
23    if base_name(symbol_name) != method {
24        return false;
25    }
26    // symbol_name has form "(*Receiver).Method" or "(Receiver).Method"
27    if let Some(paren_end) = symbol_name.find(").") {
28        let receiver_part = &symbol_name[1..paren_end]; // strip leading "("
29        let receiver_type = receiver_part.trim_start_matches('*');
30        return receiver_type == receiver;
31    }
32    false
33}
34
35#[cfg(test)]
36mod tests {
37    use super::*;
38
39    #[test]
40    fn strips_pointer_receiver() {
41        assert_eq!(
42            base_name("(*knowledgeService).CreateKnowledgeFromFile"),
43            "CreateKnowledgeFromFile"
44        );
45    }
46
47    #[test]
48    fn strips_value_receiver() {
49        assert_eq!(base_name("(userRepo).Save"), "Save");
50    }
51
52    #[test]
53    fn passthrough_no_receiver() {
54        assert_eq!(base_name("ProcessUsers"), "ProcessUsers");
55    }
56
57    #[test]
58    fn passthrough_empty() {
59        assert_eq!(base_name(""), "");
60    }
61
62    #[test]
63    fn receiver_method_matches_pointer() {
64        assert!(receiver_method_matches(
65            "(*Handler).CreateSession",
66            "Handler",
67            "CreateSession"
68        ));
69    }
70
71    #[test]
72    fn receiver_method_matches_value() {
73        assert!(receiver_method_matches(
74            "(userRepo).Save",
75            "userRepo",
76            "Save"
77        ));
78    }
79
80    #[test]
81    fn receiver_method_wrong_method() {
82        assert!(!receiver_method_matches(
83            "(*Handler).CreateSession",
84            "Handler",
85            "DeleteSession"
86        ));
87    }
88
89    #[test]
90    fn receiver_method_wrong_receiver() {
91        assert!(!receiver_method_matches(
92            "(*Handler).CreateSession",
93            "Router",
94            "CreateSession"
95        ));
96    }
97
98    #[test]
99    fn receiver_method_no_receiver_prefix() {
100        assert!(!receiver_method_matches("ProcessUsers", "ProcessUsers", ""));
101    }
102}