diff options
Diffstat (limited to 'crates/ra_ide/src/display')
-rw-r--r-- | crates/ra_ide/src/display/function_signature.rs | 298 | ||||
-rw-r--r-- | crates/ra_ide/src/display/short_label.rs | 2 |
2 files changed, 1 insertions, 299 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) | ||
5 | use std::{ | ||
6 | convert::From, | ||
7 | fmt::{self, Display}, | ||
8 | }; | ||
9 | |||
10 | use hir::{Docs, Documentation, HasSource, HirDisplay}; | ||
11 | use ra_ide_db::RootDatabase; | ||
12 | use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; | ||
13 | use stdx::{split_delim, SepBy}; | ||
14 | |||
15 | use crate::display::{generic_parameters, where_predicates}; | ||
16 | |||
17 | #[derive(Debug)] | ||
18 | pub(crate) enum CallableKind { | ||
19 | Function, | ||
20 | StructConstructor, | ||
21 | VariantConstructor, | ||
22 | } | ||
23 | |||
24 | /// Contains information about a function signature | ||
25 | #[derive(Debug)] | ||
26 | pub(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)] | ||
53 | pub(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 | |||
62 | impl 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 | |||
153 | impl 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 | |||
251 | impl 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 | } | ||
diff --git a/crates/ra_ide/src/display/short_label.rs b/crates/ra_ide/src/display/short_label.rs index d37260e96..5588130a1 100644 --- a/crates/ra_ide/src/display/short_label.rs +++ b/crates/ra_ide/src/display/short_label.rs | |||
@@ -9,7 +9,7 @@ pub(crate) trait ShortLabel { | |||
9 | 9 | ||
10 | impl ShortLabel for ast::FnDef { | 10 | impl ShortLabel for ast::FnDef { |
11 | fn short_label(&self) -> Option<String> { | 11 | fn short_label(&self) -> Option<String> { |
12 | Some(crate::display::function_label(self)) | 12 | Some(crate::display::function_declaration(self)) |
13 | } | 13 | } |
14 | } | 14 | } |
15 | 15 | ||