php_lsp/analysis/
callable_info.rs1pub(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}