diff options
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r-- | crates/ra_ide/src/completion/complete_trait_impl.rs | 9 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 16 | ||||
-rw-r--r-- | crates/ra_ide/src/display.rs | 62 | ||||
-rw-r--r-- | crates/ra_ide/src/display/function_signature.rs | 298 | ||||
-rw-r--r-- | crates/ra_ide/src/display/short_label.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/inlay_hints.rs | 76 |
6 files changed, 84 insertions, 379 deletions
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index 90f5b1c25..cf716540f 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs | |||
@@ -43,7 +43,7 @@ use crate::{ | |||
43 | completion::{ | 43 | completion::{ |
44 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, | 44 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, |
45 | }, | 45 | }, |
46 | display::function_signature::FunctionSignature, | 46 | display::function_declaration, |
47 | }; | 47 | }; |
48 | 48 | ||
49 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { | 49 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { |
@@ -125,8 +125,6 @@ fn add_function_impl( | |||
125 | ctx: &CompletionContext, | 125 | ctx: &CompletionContext, |
126 | func: hir::Function, | 126 | func: hir::Function, |
127 | ) { | 127 | ) { |
128 | let signature = FunctionSignature::from_hir(ctx.db, func); | ||
129 | |||
130 | let fn_name = func.name(ctx.db).to_string(); | 128 | let fn_name = func.name(ctx.db).to_string(); |
131 | 129 | ||
132 | let label = if !func.params(ctx.db).is_empty() { | 130 | let label = if !func.params(ctx.db).is_empty() { |
@@ -146,13 +144,14 @@ fn add_function_impl( | |||
146 | }; | 144 | }; |
147 | let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); | 145 | let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); |
148 | 146 | ||
147 | let function_decl = function_declaration(&func.source(ctx.db).value); | ||
149 | match ctx.config.snippet_cap { | 148 | match ctx.config.snippet_cap { |
150 | Some(cap) => { | 149 | Some(cap) => { |
151 | let snippet = format!("{} {{\n $0\n}}", signature); | 150 | let snippet = format!("{} {{\n $0\n}}", function_decl); |
152 | builder.snippet_edit(cap, TextEdit::replace(range, snippet)) | 151 | builder.snippet_edit(cap, TextEdit::replace(range, snippet)) |
153 | } | 152 | } |
154 | None => { | 153 | None => { |
155 | let header = format!("{} {{", signature); | 154 | let header = format!("{} {{", function_decl); |
156 | builder.text_edit(TextEdit::replace(range, header)) | 155 | builder.text_edit(TextEdit::replace(range, header)) |
157 | } | 156 | } |
158 | } | 157 | } |
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index e29b82017..c7b74e635 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -11,7 +11,7 @@ use crate::{ | |||
11 | completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind, | 11 | completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind, |
12 | CompletionKind, Completions, | 12 | CompletionKind, Completions, |
13 | }, | 13 | }, |
14 | display::{const_label, function_signature::FunctionSignature, macro_label, type_label}, | 14 | display::{const_label, function_declaration, macro_label, type_label}, |
15 | CompletionScore, RootDatabase, | 15 | CompletionScore, RootDatabase, |
16 | }; | 16 | }; |
17 | 17 | ||
@@ -195,7 +195,6 @@ impl Completions { | |||
195 | 195 | ||
196 | let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string()); | 196 | let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string()); |
197 | let ast_node = func.source(ctx.db).value; | 197 | let ast_node = func.source(ctx.db).value; |
198 | let function_signature = FunctionSignature::from(&ast_node); | ||
199 | 198 | ||
200 | let mut builder = | 199 | let mut builder = |
201 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone()) | 200 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone()) |
@@ -206,13 +205,14 @@ impl Completions { | |||
206 | }) | 205 | }) |
207 | .set_documentation(func.docs(ctx.db)) | 206 | .set_documentation(func.docs(ctx.db)) |
208 | .set_deprecated(is_deprecated(func, ctx.db)) | 207 | .set_deprecated(is_deprecated(func, ctx.db)) |
209 | .detail(function_signature.to_string()); | 208 | .detail(function_declaration(&ast_node)); |
210 | 209 | ||
211 | let params = function_signature | 210 | let params = ast_node |
212 | .parameter_names | 211 | .param_list() |
213 | .iter() | 212 | .into_iter() |
214 | .skip(if function_signature.has_self_param { 1 } else { 0 }) | 213 | .flat_map(|it| it.params()) |
215 | .map(|name| name.trim_start_matches('_').into()) | 214 | .flat_map(|it| it.pat()) |
215 | .map(|pat| pat.to_string().trim_start_matches('_').into()) | ||
216 | .collect(); | 216 | .collect(); |
217 | 217 | ||
218 | builder = builder.add_call_parens(ctx, name, Params::Named(params)); | 218 | builder = builder.add_call_parens(ctx, name, Params::Named(params)); |
diff --git a/crates/ra_ide/src/display.rs b/crates/ra_ide/src/display.rs index 1ec946369..6d4151dd8 100644 --- a/crates/ra_ide/src/display.rs +++ b/crates/ra_ide/src/display.rs | |||
@@ -1,7 +1,6 @@ | |||
1 | //! This module contains utilities for turning SyntaxNodes and HIR types | 1 | //! This module contains utilities for turning SyntaxNodes and HIR types |
2 | //! into types that may be used to render in a UI. | 2 | //! into types that may be used to render in a UI. |
3 | 3 | ||
4 | pub(crate) mod function_signature; | ||
5 | mod navigation_target; | 4 | mod navigation_target; |
6 | mod short_label; | 5 | mod short_label; |
7 | 6 | ||
@@ -10,13 +9,49 @@ use ra_syntax::{ | |||
10 | SyntaxKind::{ATTR, COMMENT}, | 9 | SyntaxKind::{ATTR, COMMENT}, |
11 | }; | 10 | }; |
12 | 11 | ||
13 | pub(crate) use navigation_target::{ToNav, TryToNav}; | 12 | use ast::VisibilityOwner; |
14 | pub(crate) use short_label::ShortLabel; | 13 | use stdx::format_to; |
15 | 14 | ||
16 | pub use navigation_target::NavigationTarget; | 15 | pub use navigation_target::NavigationTarget; |
16 | pub(crate) use navigation_target::{ToNav, TryToNav}; | ||
17 | pub(crate) use short_label::ShortLabel; | ||
17 | 18 | ||
18 | pub(crate) fn function_label(node: &ast::FnDef) -> String { | 19 | pub(crate) fn function_declaration(node: &ast::FnDef) -> String { |
19 | function_signature::FunctionSignature::from(node).to_string() | 20 | let mut buf = String::new(); |
21 | if let Some(vis) = node.visibility() { | ||
22 | format_to!(buf, "{} ", vis); | ||
23 | } | ||
24 | if node.async_token().is_some() { | ||
25 | format_to!(buf, "async "); | ||
26 | } | ||
27 | if node.const_token().is_some() { | ||
28 | format_to!(buf, "const "); | ||
29 | } | ||
30 | if node.unsafe_token().is_some() { | ||
31 | format_to!(buf, "unsafe "); | ||
32 | } | ||
33 | if let Some(abi) = node.abi() { | ||
34 | // Keyword `extern` is included in the string. | ||
35 | format_to!(buf, "{} ", abi); | ||
36 | } | ||
37 | if let Some(name) = node.name() { | ||
38 | format_to!(buf, "fn {}", name) | ||
39 | } | ||
40 | if let Some(type_params) = node.type_param_list() { | ||
41 | format_to!(buf, "{}", type_params); | ||
42 | } | ||
43 | if let Some(param_list) = node.param_list() { | ||
44 | format_to!(buf, "{}", param_list); | ||
45 | } | ||
46 | if let Some(ret_type) = node.ret_type() { | ||
47 | if ret_type.type_ref().is_some() { | ||
48 | format_to!(buf, " {}", ret_type); | ||
49 | } | ||
50 | } | ||
51 | if let Some(where_clause) = node.where_clause() { | ||
52 | format_to!(buf, "\n{}", where_clause); | ||
53 | } | ||
54 | buf | ||
20 | } | 55 | } |
21 | 56 | ||
22 | pub(crate) fn const_label(node: &ast::ConstDef) -> String { | 57 | pub(crate) fn const_label(node: &ast::ConstDef) -> String { |
@@ -41,23 +76,6 @@ pub(crate) fn type_label(node: &ast::TypeAliasDef) -> String { | |||
41 | label.trim().to_owned() | 76 | label.trim().to_owned() |
42 | } | 77 | } |
43 | 78 | ||
44 | pub(crate) fn generic_parameters<N: TypeParamsOwner>(node: &N) -> Vec<String> { | ||
45 | let mut res = vec![]; | ||
46 | if let Some(type_params) = node.type_param_list() { | ||
47 | res.extend(type_params.lifetime_params().map(|p| p.syntax().text().to_string())); | ||
48 | res.extend(type_params.type_params().map(|p| p.syntax().text().to_string())); | ||
49 | } | ||
50 | res | ||
51 | } | ||
52 | |||
53 | pub(crate) fn where_predicates<N: TypeParamsOwner>(node: &N) -> Vec<String> { | ||
54 | let mut res = vec![]; | ||
55 | if let Some(clause) = node.where_clause() { | ||
56 | res.extend(clause.predicates().map(|p| p.syntax().text().to_string())); | ||
57 | } | ||
58 | res | ||
59 | } | ||
60 | |||
61 | pub(crate) fn macro_label(node: &ast::MacroCall) -> String { | 79 | pub(crate) fn macro_label(node: &ast::MacroCall) -> String { |
62 | let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default(); | 80 | let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default(); |
63 | let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" }; | 81 | let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" }; |
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 | ||
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs index ae5695f61..cec3b04e8 100644 --- a/crates/ra_ide/src/inlay_hints.rs +++ b/crates/ra_ide/src/inlay_hints.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use hir::{Adt, HirDisplay, Semantics, Type}; | 1 | use hir::{Adt, Callable, HirDisplay, Semantics, Type}; |
2 | use ra_ide_db::RootDatabase; | 2 | use ra_ide_db::RootDatabase; |
3 | use ra_prof::profile; | 3 | use ra_prof::profile; |
4 | use ra_syntax::{ | 4 | use ra_syntax::{ |
@@ -7,7 +7,9 @@ use ra_syntax::{ | |||
7 | }; | 7 | }; |
8 | use stdx::to_lower_snake_case; | 8 | use stdx::to_lower_snake_case; |
9 | 9 | ||
10 | use crate::{display::function_signature::FunctionSignature, FileId}; | 10 | use crate::FileId; |
11 | use ast::NameOwner; | ||
12 | use either::Either; | ||
11 | 13 | ||
12 | #[derive(Clone, Debug, PartialEq, Eq)] | 14 | #[derive(Clone, Debug, PartialEq, Eq)] |
13 | pub struct InlayHintsConfig { | 15 | pub struct InlayHintsConfig { |
@@ -150,23 +152,26 @@ fn get_param_name_hints( | |||
150 | _ => return None, | 152 | _ => return None, |
151 | }; | 153 | }; |
152 | 154 | ||
153 | let fn_signature = get_fn_signature(sema, &expr)?; | 155 | let callable = get_callable(sema, &expr)?; |
154 | let n_params_to_skip = | 156 | let hints = callable |
155 | if fn_signature.has_self_param && matches!(&expr, ast::Expr::MethodCallExpr(_)) { | 157 | .params(sema.db) |
156 | 1 | 158 | .into_iter() |
157 | } else { | ||
158 | 0 | ||
159 | }; | ||
160 | let hints = fn_signature | ||
161 | .parameter_names | ||
162 | .iter() | ||
163 | .skip(n_params_to_skip) | ||
164 | .zip(args) | 159 | .zip(args) |
165 | .filter(|(param, arg)| should_show_param_name_hint(sema, &fn_signature, param, &arg)) | 160 | .filter_map(|((param, _ty), arg)| match param? { |
161 | Either::Left(self_param) => Some((self_param.to_string(), arg)), | ||
162 | Either::Right(pat) => { | ||
163 | let param_name = match pat { | ||
164 | ast::Pat::BindPat(it) => it.name()?.to_string(), | ||
165 | it => it.to_string(), | ||
166 | }; | ||
167 | Some((param_name, arg)) | ||
168 | } | ||
169 | }) | ||
170 | .filter(|(param_name, arg)| should_show_param_name_hint(sema, &callable, ¶m_name, &arg)) | ||
166 | .map(|(param_name, arg)| InlayHint { | 171 | .map(|(param_name, arg)| InlayHint { |
167 | range: arg.syntax().text_range(), | 172 | range: arg.syntax().text_range(), |
168 | kind: InlayKind::ParameterHint, | 173 | kind: InlayKind::ParameterHint, |
169 | label: param_name.into(), | 174 | label: param_name.to_string().into(), |
170 | }); | 175 | }); |
171 | 176 | ||
172 | acc.extend(hints); | 177 | acc.extend(hints); |
@@ -250,28 +255,26 @@ fn should_not_display_type_hint(db: &RootDatabase, bind_pat: &ast::BindPat, pat_ | |||
250 | 255 | ||
251 | fn should_show_param_name_hint( | 256 | fn should_show_param_name_hint( |
252 | sema: &Semantics<RootDatabase>, | 257 | sema: &Semantics<RootDatabase>, |
253 | fn_signature: &FunctionSignature, | 258 | callable: &Callable, |
254 | param_name: &str, | 259 | param_name: &str, |
255 | argument: &ast::Expr, | 260 | argument: &ast::Expr, |
256 | ) -> bool { | 261 | ) -> bool { |
257 | let param_name = param_name.trim_start_matches('_'); | 262 | let param_name = param_name.trim_start_matches('_'); |
263 | let fn_name = match callable.kind() { | ||
264 | hir::CallableKind::Function(it) => Some(it.name(sema.db).to_string()), | ||
265 | hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => None, | ||
266 | }; | ||
258 | if param_name.is_empty() | 267 | if param_name.is_empty() |
259 | || Some(param_name) == fn_signature.name.as_ref().map(|s| s.trim_start_matches('_')) | 268 | || Some(param_name) == fn_name.as_ref().map(|s| s.trim_start_matches('_')) |
260 | || is_argument_similar_to_param_name(sema, argument, param_name) | 269 | || is_argument_similar_to_param_name(sema, argument, param_name) |
261 | || param_name.starts_with("ra_fixture") | 270 | || param_name.starts_with("ra_fixture") |
262 | { | 271 | { |
263 | return false; | 272 | return false; |
264 | } | 273 | } |
265 | 274 | ||
266 | let parameters_len = if fn_signature.has_self_param { | ||
267 | fn_signature.parameters.len() - 1 | ||
268 | } else { | ||
269 | fn_signature.parameters.len() | ||
270 | }; | ||
271 | |||
272 | // avoid displaying hints for common functions like map, filter, etc. | 275 | // avoid displaying hints for common functions like map, filter, etc. |
273 | // or other obvious words used in std | 276 | // or other obvious words used in std |
274 | !(parameters_len == 1 && is_obvious_param(param_name)) | 277 | !(callable.n_params() == 1 && is_obvious_param(param_name)) |
275 | } | 278 | } |
276 | 279 | ||
277 | fn is_argument_similar_to_param_name( | 280 | fn is_argument_similar_to_param_name( |
@@ -318,27 +321,10 @@ fn is_obvious_param(param_name: &str) -> bool { | |||
318 | param_name.len() == 1 || is_obvious_param_name | 321 | param_name.len() == 1 || is_obvious_param_name |
319 | } | 322 | } |
320 | 323 | ||
321 | fn get_fn_signature(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<FunctionSignature> { | 324 | fn get_callable(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<Callable> { |
322 | match expr { | 325 | match expr { |
323 | ast::Expr::CallExpr(expr) => { | 326 | ast::Expr::CallExpr(expr) => sema.type_of_expr(&expr.expr()?)?.as_callable(sema.db), |
324 | // FIXME: Type::as_callable is broken for closures | 327 | ast::Expr::MethodCallExpr(expr) => sema.resolve_method_call_as_callable(expr), |
325 | let callable = sema.type_of_expr(&expr.expr()?)?.as_callable(sema.db)?; | ||
326 | match callable.kind() { | ||
327 | hir::CallableKind::Function(it) => { | ||
328 | Some(FunctionSignature::from_hir(sema.db, it.into())) | ||
329 | } | ||
330 | hir::CallableKind::TupleStruct(it) => { | ||
331 | FunctionSignature::from_struct(sema.db, it.into()) | ||
332 | } | ||
333 | hir::CallableKind::TupleEnumVariant(it) => { | ||
334 | FunctionSignature::from_enum_variant(sema.db, it.into()) | ||
335 | } | ||
336 | } | ||
337 | } | ||
338 | ast::Expr::MethodCallExpr(expr) => { | ||
339 | let fn_def = sema.resolve_method_call(&expr)?; | ||
340 | Some(FunctionSignature::from_hir(sema.db, fn_def)) | ||
341 | } | ||
342 | _ => None, | 328 | _ => None, |
343 | } | 329 | } |
344 | } | 330 | } |
@@ -360,7 +346,7 @@ mod tests { | |||
360 | let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); | 346 | let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); |
361 | let actual = | 347 | let actual = |
362 | inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::<Vec<_>>(); | 348 | inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::<Vec<_>>(); |
363 | assert_eq!(expected, actual); | 349 | assert_eq!(expected, actual, "\nExpected:\n{:#?}\n\nActual:\n{:#?}", expected, actual); |
364 | } | 350 | } |
365 | 351 | ||
366 | fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) { | 352 | fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) { |