Skip to main content

php_lsp/analysis/
callable_info.rs

1pub(crate) struct CallableInfo {
2    pub params: String,
3    pub return_type: Option<String>,
4    pub documentation: Option<String>,
5}
6
7pub(crate) fn format_declared_params(params: &[mir_analyzer::DeclaredParam]) -> String {
8    params
9        .iter()
10        .map(|p| {
11            let mut s = String::new();
12            if let Some(ty) = &p.ty {
13                s.push_str(&format!("{ty} "));
14            }
15            if p.is_variadic {
16                s.push_str("...");
17            }
18            s.push_str(&format!("${}", p.name.as_str().trim_start_matches('$')));
19            if let Some(text) = &p.default_text {
20                s.push_str(&format!(" = {text}"));
21            } else if p.has_default {
22                s.push_str(" = ...");
23            }
24            s
25        })
26        .collect::<Vec<_>>()
27        .join(", ")
28}
29
30pub(crate) fn callable_info_for_name(
31    db: &mir_analyzer::db::MirDbStorage,
32    symbol: &mir_analyzer::Name,
33) -> Option<CallableInfo> {
34    match symbol {
35        mir_analyzer::Name::Function(fqn) => {
36            let short = fqn.rsplit('\\').next().unwrap_or(fqn.as_ref());
37            if mir_analyzer::is_builtin_function(short) {
38                return None;
39            }
40            let f = mir_analyzer::db::find_function(
41                db,
42                mir_analyzer::db::Fqcn::from_str(db, fqn.as_ref()),
43            )?;
44            Some(CallableInfo {
45                params: format_declared_params(&f.params),
46                return_type: f.effective_return_type().map(ToString::to_string),
47                documentation: f.docstring.as_deref().map(str::to_string),
48            })
49        }
50        mir_analyzer::Name::Method { class, name } => {
51            let (_, m) = mir_analyzer::db::find_method_in_chain(
52                db,
53                mir_analyzer::db::Fqcn::from_str(db, class.as_ref()),
54                name.as_ref(),
55            )?;
56            Some(CallableInfo {
57                params: format_declared_params(&m.params),
58                return_type: m
59                    .return_type
60                    .as_deref()
61                    .or(m.inferred_return_type.as_deref())
62                    .map(ToString::to_string),
63                documentation: m.docstring.as_deref().map(str::to_string),
64            })
65        }
66        mir_analyzer::Name::Class(fqcn) => {
67            let (_, m) = mir_analyzer::db::find_method_in_chain(
68                db,
69                mir_analyzer::db::Fqcn::from_str(db, fqcn.as_ref()),
70                "__construct",
71            )?;
72            Some(CallableInfo {
73                params: format_declared_params(&m.params),
74                return_type: None,
75                documentation: m.docstring.as_deref().map(str::to_string),
76            })
77        }
78        _ => None,
79    }
80}