aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/display/function_signature.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/display/function_signature.rs')
-rw-r--r--crates/ra_ide/src/display/function_signature.rs334
1 files changed, 0 insertions, 334 deletions
diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs
deleted file mode 100644
index a98264fb3..000000000
--- a/crates/ra_ide/src/display/function_signature.rs
+++ /dev/null
@@ -1,334 +0,0 @@
1//! FIXME: write short doc here
2
3// FIXME: this modules relies on strings and AST way too much, and it should be
4// rewritten (matklad 2020-05-07)
5use std::{
6 convert::From,
7 fmt::{self, Display},
8};
9
10use hir::{Docs, Documentation, HasSource, HirDisplay};
11use ra_ide_db::RootDatabase;
12use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner};
13use stdx::{split_delim, SepBy};
14
15use crate::display::{generic_parameters, where_predicates};
16
17#[derive(Debug)]
18pub enum CallableKind {
19 Function,
20 StructConstructor,
21 VariantConstructor,
22 Macro,
23}
24
25/// Contains information about a function signature
26#[derive(Debug)]
27pub struct FunctionSignature {
28 pub kind: CallableKind,
29 /// Optional visibility
30 pub visibility: Option<String>,
31 /// Qualifiers like `async`, `unsafe`, ...
32 pub qualifier: FunctionQualifier,
33 /// Name of the function
34 pub name: Option<String>,
35 /// Documentation for the function
36 pub doc: Option<Documentation>,
37 /// Generic parameters
38 pub generic_parameters: Vec<String>,
39 /// Parameters of the function
40 pub parameters: Vec<String>,
41 /// Parameter names of the function
42 pub parameter_names: Vec<String>,
43 /// Parameter types of the function
44 pub parameter_types: Vec<String>,
45 /// Optional return type
46 pub ret_type: Option<String>,
47 /// Where predicates
48 pub where_predicates: Vec<String>,
49 /// Self param presence
50 pub has_self_param: bool,
51}
52
53#[derive(Debug, Default)]
54pub struct FunctionQualifier {
55 // `async` and `const` are mutually exclusive. Do we need to enforcing it here?
56 pub is_async: bool,
57 pub is_const: bool,
58 pub is_unsafe: bool,
59 /// The string `extern ".."`
60 pub extern_abi: Option<String>,
61}
62
63impl FunctionSignature {
64 pub(crate) fn with_doc_opt(mut self, doc: Option<Documentation>) -> Self {
65 self.doc = doc;
66 self
67 }
68
69 pub(crate) fn from_hir(db: &RootDatabase, function: hir::Function) -> Self {
70 let doc = function.docs(db);
71 let ast_node = function.source(db).value;
72 FunctionSignature::from(&ast_node).with_doc_opt(doc)
73 }
74
75 pub(crate) fn from_struct(db: &RootDatabase, st: hir::Struct) -> Option<Self> {
76 let node: ast::StructDef = st.source(db).value;
77 if let ast::StructKind::Record(_) = node.kind() {
78 return None;
79 };
80
81 let mut params = vec![];
82 let mut parameter_types = vec![];
83 for field in st.fields(db).into_iter() {
84 let ty = field.signature_ty(db);
85 let raw_param = format!("{}", ty.display(db));
86
87 if let Some(param_type) = raw_param.split(':').nth(1).and_then(|it| it.get(1..)) {
88 parameter_types.push(param_type.to_string());
89 } else {
90 // useful when you have tuple struct
91 parameter_types.push(raw_param.clone());
92 }
93 params.push(raw_param);
94 }
95
96 Some(
97 FunctionSignature {
98 kind: CallableKind::StructConstructor,
99 visibility: node.visibility().map(|n| n.syntax().text().to_string()),
100 // Do we need `const`?
101 qualifier: Default::default(),
102 name: node.name().map(|n| n.text().to_string()),
103 ret_type: node.name().map(|n| n.text().to_string()),
104 parameters: params,
105 parameter_names: vec![],
106 parameter_types,
107 generic_parameters: generic_parameters(&node),
108 where_predicates: where_predicates(&node),
109 doc: None,
110 has_self_param: false,
111 }
112 .with_doc_opt(st.docs(db)),
113 )
114 }
115
116 pub(crate) fn from_enum_variant(db: &RootDatabase, variant: hir::EnumVariant) -> Option<Self> {
117 let node: ast::EnumVariant = variant.source(db).value;
118 match node.kind() {
119 ast::StructKind::Record(_) | ast::StructKind::Unit => return None,
120 _ => (),
121 };
122
123 let parent_name = variant.parent_enum(db).name(db).to_string();
124
125 let name = format!("{}::{}", parent_name, variant.name(db));
126
127 let mut params = vec![];
128 let mut parameter_types = vec![];
129 for field in variant.fields(db).into_iter() {
130 let ty = field.signature_ty(db);
131 let raw_param = format!("{}", ty.display(db));
132 if let Some(param_type) = raw_param.split(':').nth(1).and_then(|it| it.get(1..)) {
133 parameter_types.push(param_type.to_string());
134 } else {
135 // The unwrap_or_else is useful when you have tuple
136 parameter_types.push(raw_param);
137 }
138 let name = field.name(db);
139
140 params.push(format!("{}: {}", name, ty.display(db)));
141 }
142
143 Some(
144 FunctionSignature {
145 kind: CallableKind::VariantConstructor,
146 visibility: None,
147 // Do we need `const`?
148 qualifier: Default::default(),
149 name: Some(name),
150 ret_type: None,
151 parameters: params,
152 parameter_names: vec![],
153 parameter_types,
154 generic_parameters: vec![],
155 where_predicates: vec![],
156 doc: None,
157 has_self_param: false,
158 }
159 .with_doc_opt(variant.docs(db)),
160 )
161 }
162
163 pub(crate) fn from_macro(db: &RootDatabase, macro_def: hir::MacroDef) -> Option<Self> {
164 let node: ast::MacroCall = macro_def.source(db).value;
165
166 let params = vec![];
167
168 Some(
169 FunctionSignature {
170 kind: CallableKind::Macro,
171 visibility: None,
172 qualifier: Default::default(),
173 name: node.name().map(|n| n.text().to_string()),
174 ret_type: None,
175 parameters: params,
176 parameter_names: vec![],
177 parameter_types: vec![],
178 generic_parameters: vec![],
179 where_predicates: vec![],
180 doc: None,
181 has_self_param: false,
182 }
183 .with_doc_opt(macro_def.docs(db)),
184 )
185 }
186}
187
188impl From<&'_ ast::FnDef> for FunctionSignature {
189 fn from(node: &ast::FnDef) -> FunctionSignature {
190 fn param_list(node: &ast::FnDef) -> (bool, Vec<String>, Vec<String>) {
191 let mut res = vec![];
192 let mut res_types = vec![];
193 let mut has_self_param = false;
194 if let Some(param_list) = node.param_list() {
195 if let Some(self_param) = param_list.self_param() {
196 has_self_param = true;
197 let raw_param = self_param.syntax().text().to_string();
198
199 res_types.push(
200 raw_param
201 .split(':')
202 .nth(1)
203 .and_then(|it| it.get(1..))
204 .unwrap_or_else(|| "Self")
205 .to_string(),
206 );
207 res.push(raw_param);
208 }
209
210 // macro-generated functions are missing whitespace
211 fn fmt_param(param: ast::Param) -> String {
212 let text = param.syntax().text().to_string();
213 match split_delim(&text, ':') {
214 Some((left, right)) => format!("{}: {}", left.trim(), right.trim()),
215 _ => text,
216 }
217 }
218
219 res.extend(param_list.params().map(fmt_param));
220 res_types.extend(param_list.params().map(|param| {
221 let param_text = param.syntax().text().to_string();
222 match param_text.split(':').nth(1).and_then(|it| it.get(1..)) {
223 Some(it) => it.to_string(),
224 None => param_text,
225 }
226 }));
227 }
228 (has_self_param, res, res_types)
229 }
230
231 fn param_name_list(node: &ast::FnDef) -> Vec<String> {
232 let mut res = vec![];
233 if let Some(param_list) = node.param_list() {
234 if let Some(self_param) = param_list.self_param() {
235 res.push(self_param.syntax().text().to_string())
236 }
237
238 res.extend(
239 param_list
240 .params()
241 .map(|param| {
242 Some(
243 param
244 .pat()?
245 .syntax()
246 .descendants()
247 .find_map(ast::Name::cast)?
248 .text()
249 .to_string(),
250 )
251 })
252 .map(|param| param.unwrap_or_default()),
253 );
254 }
255 res
256 }
257
258 let (has_self_param, parameters, parameter_types) = param_list(node);
259
260 FunctionSignature {
261 kind: CallableKind::Function,
262 visibility: node.visibility().map(|n| n.syntax().text().to_string()),
263 qualifier: FunctionQualifier {
264 is_async: node.async_token().is_some(),
265 is_const: node.const_token().is_some(),
266 is_unsafe: node.unsafe_token().is_some(),
267 extern_abi: node.abi().map(|n| n.to_string()),
268 },
269 name: node.name().map(|n| n.text().to_string()),
270 ret_type: node
271 .ret_type()
272 .and_then(|r| r.type_ref())
273 .map(|n| n.syntax().text().to_string()),
274 parameters,
275 parameter_names: param_name_list(node),
276 parameter_types,
277 generic_parameters: generic_parameters(node),
278 where_predicates: where_predicates(node),
279 // docs are processed separately
280 doc: None,
281 has_self_param,
282 }
283 }
284}
285
286impl Display for FunctionSignature {
287 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
288 if let Some(t) = &self.visibility {
289 write!(f, "{} ", t)?;
290 }
291
292 if self.qualifier.is_async {
293 write!(f, "async ")?;
294 }
295
296 if self.qualifier.is_const {
297 write!(f, "const ")?;
298 }
299
300 if self.qualifier.is_unsafe {
301 write!(f, "unsafe ")?;
302 }
303
304 if let Some(extern_abi) = &self.qualifier.extern_abi {
305 // Keyword `extern` is included in the string.
306 write!(f, "{} ", extern_abi)?;
307 }
308
309 if let Some(name) = &self.name {
310 match self.kind {
311 CallableKind::Function => write!(f, "fn {}", name)?,
312 CallableKind::StructConstructor => write!(f, "struct {}", name)?,
313 CallableKind::VariantConstructor => write!(f, "{}", name)?,
314 CallableKind::Macro => write!(f, "{}!", name)?,
315 }
316 }
317
318 if !self.generic_parameters.is_empty() {
319 write!(f, "{}", self.generic_parameters.iter().sep_by(", ").surround_with("<", ">"))?;
320 }
321
322 write!(f, "{}", self.parameters.iter().sep_by(", ").surround_with("(", ")"))?;
323
324 if let Some(t) = &self.ret_type {
325 write!(f, " -> {}", t)?;
326 }
327
328 if !self.where_predicates.is_empty() {
329 write!(f, "\nwhere {}", self.where_predicates.iter().sep_by(",\n "))?;
330 }
331
332 Ok(())
333 }
334}