aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/inlay_hints.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/inlay_hints.rs')
-rw-r--r--crates/ra_ide/src/inlay_hints.rs76
1 files changed, 31 insertions, 45 deletions
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 @@
1use hir::{Adt, HirDisplay, Semantics, Type}; 1use hir::{Adt, Callable, HirDisplay, Semantics, Type};
2use ra_ide_db::RootDatabase; 2use ra_ide_db::RootDatabase;
3use ra_prof::profile; 3use ra_prof::profile;
4use ra_syntax::{ 4use ra_syntax::{
@@ -7,7 +7,9 @@ use ra_syntax::{
7}; 7};
8use stdx::to_lower_snake_case; 8use stdx::to_lower_snake_case;
9 9
10use crate::{display::function_signature::FunctionSignature, FileId}; 10use crate::FileId;
11use ast::NameOwner;
12use either::Either;
11 13
12#[derive(Clone, Debug, PartialEq, Eq)] 14#[derive(Clone, Debug, PartialEq, Eq)]
13pub struct InlayHintsConfig { 15pub 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, &param_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
251fn should_show_param_name_hint( 256fn 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
277fn is_argument_similar_to_param_name( 280fn 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
321fn get_fn_signature(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<FunctionSignature> { 324fn 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) {