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 p.has_default {
20                s.push_str(" = ...");
21            }
22            s
23        })
24        .collect::<Vec<_>>()
25        .join(", ")
26}
27
28pub(crate) fn callable_info_for_name(
29    session: &mir_analyzer::AnalysisSession,
30    symbol: &mir_analyzer::Name,
31) -> Option<CallableInfo> {
32    let db = session.snapshot_db();
33    match symbol {
34        mir_analyzer::Name::Function(fqn) => {
35            let short = fqn.rsplit('\\').next().unwrap_or(fqn.as_ref());
36            if mir_analyzer::is_builtin_function(short) {
37                return None;
38            }
39            let f = mir_analyzer::db::find_function(
40                &db,
41                mir_analyzer::db::Fqcn::from_str(&db, fqn.as_ref()),
42            )?;
43            Some(CallableInfo {
44                params: format_declared_params(&f.params),
45                return_type: f.effective_return_type().map(ToString::to_string),
46                documentation: f.docstring.as_deref().map(str::to_string),
47            })
48        }
49        mir_analyzer::Name::Method { class, name } => {
50            let (_, m) = mir_analyzer::db::find_method_in_chain(
51                &db,
52                mir_analyzer::db::Fqcn::from_str(&db, class.as_ref()),
53                name.as_ref(),
54            )?;
55            Some(CallableInfo {
56                params: format_declared_params(&m.params),
57                return_type: m
58                    .return_type
59                    .as_deref()
60                    .or(m.inferred_return_type.as_deref())
61                    .map(ToString::to_string),
62                documentation: m.docstring.as_deref().map(str::to_string),
63            })
64        }
65        mir_analyzer::Name::Class(fqcn) => {
66            let (_, m) = mir_analyzer::db::find_method_in_chain(
67                &db,
68                mir_analyzer::db::Fqcn::from_str(&db, fqcn.as_ref()),
69                "__construct",
70            )?;
71            Some(CallableInfo {
72                params: format_declared_params(&m.params),
73                return_type: None,
74                documentation: m.docstring.as_deref().map(str::to_string),
75            })
76        }
77        _ => None,
78    }
79}