workspacer_syntax/
generate_function_signature.rs1crate::ix!();
3
4pub fn post_process_spacing(signature: &str) -> String {
6 signature
7 .replace(")->", ") ->")
8 .replace(">where", "> where")
9}
10
11#[derive(Debug, Clone)]
12pub struct FnSignatureGenerator(ast::Fn);
13
14impl GenerateSignature for ast::Fn {
15 fn generate_signature_with_opts(&self, opts: &SignatureOptions) -> String {
16 use tracing::{debug, trace};
17
18 trace!("Generating signature for ast::Fn with opts: {:?}", opts);
19
20 let doc_text = if *opts.include_docs() {
22 extract_docs(&self.syntax())
23 .map(|d| format!("{}\n", d))
24 .unwrap_or_default()
25 } else {
26 "".to_string()
27 };
28
29 let vis_str = self
31 .visibility()
32 .map(|v| format!("{} ", v.syntax().text()))
33 .unwrap_or_default();
34
35 let async_str = if let Some(token) = self.async_token() {
36 format!("{} ", token.text())
37 } else {
38 "".to_string()
39 };
40
41 let fn_keyword = "fn";
42 let name_str = self
43 .name()
44 .map(|n| n.text().to_string())
45 .unwrap_or_else(|| "<anon>".to_string());
46
47 let generic_params = self
49 .generic_param_list()
50 .map(|gp| gp.syntax().text().to_string())
51 .unwrap_or_default();
52
53 let mut param_texts = Vec::new();
55 if let Some(plist) = self.param_list() {
56 debug!(?plist, "Found param_list for fn");
57 if let Some(sp) = plist.self_param() {
58 let has_amp = sp.amp_token().is_some();
59 let has_mut = sp.mut_token().is_some();
60 let lifetime_str = sp
61 .lifetime()
62 .map(|lt| lt.syntax().text().to_string())
63 .unwrap_or_default();
64
65 let mut pieces = String::new();
66 if has_amp {
67 pieces.push('&');
68 if !lifetime_str.is_empty() {
69 pieces.push_str(&lifetime_str);
70 pieces.push(' ');
71 }
72 }
73 if has_mut {
74 pieces.push_str("mut ");
75 }
76 pieces.push_str("self");
77 param_texts.push(pieces.trim_end().to_string());
78 }
79
80 for param in plist.params() {
81 if let Some(normal) = ast::Param::cast(param.syntax().clone()) {
82 let pat_str = normal
83 .pat()
84 .map(|p| p.syntax().text().to_string())
85 .unwrap_or_default();
86 let ty_str = normal
87 .ty()
88 .map(|t| t.syntax().text().to_string())
89 .unwrap_or_default();
90 if !pat_str.is_empty() && !ty_str.is_empty() {
91 param_texts.push(format!("{}: {}", pat_str, ty_str));
92 } else if !ty_str.is_empty() {
93 param_texts.push(ty_str);
94 } else if !pat_str.is_empty() {
95 param_texts.push(pat_str);
96 } else {
97 param_texts.push("<unknown_param>".to_string());
98 }
99 } else {
100 param_texts.push("<unrecognized_param>".to_string());
101 }
102 }
103 }
104 let params_str = param_texts.join(", ");
105
106 let ret_str = if let Some(ret_type) = self.ret_type() {
108 if let Some(ty_node) = ret_type.ty() {
109 format!(" -> {}", ty_node.syntax().text())
110 } else {
111 "".to_string()
112 }
113 } else {
114 "".to_string()
115 };
116
117 let where_str = if let Some(wc) = self.where_clause() {
119 format!(" {}", wc.syntax().text())
120 } else {
121 "".to_string()
122 };
123
124 let raw_sig = format!(
127 "{vis_str}{async_str}{fn_keyword} {name_str}{generic_params}({params_str}){ret_str}{where_str}"
128 );
129
130 let combined = match opts.add_semicolon() {
131 true => format!("{doc_text}{raw_sig};"),
132 false => format!("{doc_text}{raw_sig}"),
133 };
134
135 post_process_spacing(&combined)
136 }
137}