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