aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_ide/src/inlay_hints.rs127
-rw-r--r--crates/ra_syntax/src/ast.rs2
2 files changed, 59 insertions, 70 deletions
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index 35e3f782d..69098a630 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -5,7 +5,7 @@ use ra_ide_db::RootDatabase;
5use ra_prof::profile; 5use ra_prof::profile;
6use ra_syntax::{ 6use ra_syntax::{
7 ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner}, 7 ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner},
8 match_ast, SmolStr, SyntaxNode, TextRange, 8 match_ast, SmolStr, TextRange,
9}; 9};
10 10
11use crate::{FileId, FunctionSignature}; 11use crate::{FileId, FunctionSignature};
@@ -28,50 +28,76 @@ pub(crate) fn inlay_hints(
28 file_id: FileId, 28 file_id: FileId,
29 max_inlay_hint_length: Option<usize>, 29 max_inlay_hint_length: Option<usize>,
30) -> Vec<InlayHint> { 30) -> Vec<InlayHint> {
31 let _p = profile("inlay_hints");
31 let sema = Semantics::new(db); 32 let sema = Semantics::new(db);
32 let file = sema.parse(file_id); 33 let file = sema.parse(file_id);
34
33 let mut res = Vec::new(); 35 let mut res = Vec::new();
34 for node in file.syntax().descendants() { 36 for node in file.syntax().descendants() {
35 get_inlay_hints(&mut res, &sema, &node, max_inlay_hint_length); 37 match_ast! {
38 match node {
39 ast::CallExpr(it) => { get_param_name_hints(&mut res, &sema, ast::Expr::from(it)); },
40 ast::MethodCallExpr(it) => { get_param_name_hints(&mut res, &sema, ast::Expr::from(it)); },
41 ast::BindPat(it) => { get_bind_pat_hints(&mut res, &sema, max_inlay_hint_length, it); },
42 _ => (),
43 }
44 }
36 } 45 }
37 res 46 res
38} 47}
39 48
40fn get_inlay_hints( 49fn get_param_name_hints(
50 acc: &mut Vec<InlayHint>,
51 sema: &Semantics<RootDatabase>,
52 expr: ast::Expr,
53) -> Option<()> {
54 let args = match &expr {
55 ast::Expr::CallExpr(expr) => expr.arg_list()?.args(),
56 ast::Expr::MethodCallExpr(expr) => expr.arg_list()?.args(),
57 _ => return None,
58 };
59 let args_count = args.clone().count();
60
61 let fn_signature = get_fn_signature(sema, &expr)?;
62 let n_params_to_skip =
63 if fn_signature.has_self_param && fn_signature.parameter_names.len() > args_count {
64 1
65 } else {
66 0
67 };
68 let hints = fn_signature
69 .parameter_names
70 .iter()
71 .skip(n_params_to_skip)
72 .zip(args)
73 .filter(|(param, arg)| should_show_param_hint(&fn_signature, param, &arg))
74 .map(|(param_name, arg)| InlayHint {
75 range: arg.syntax().text_range(),
76 kind: InlayKind::ParameterHint,
77 label: param_name.into(),
78 });
79
80 acc.extend(hints);
81 Some(())
82}
83
84fn get_bind_pat_hints(
41 acc: &mut Vec<InlayHint>, 85 acc: &mut Vec<InlayHint>,
42 sema: &Semantics<RootDatabase>, 86 sema: &Semantics<RootDatabase>,
43 node: &SyntaxNode,
44 max_inlay_hint_length: Option<usize>, 87 max_inlay_hint_length: Option<usize>,
88 pat: ast::BindPat,
45) -> Option<()> { 89) -> Option<()> {
46 let _p = profile("get_inlay_hints"); 90 let ty = sema.type_of_pat(&pat.clone().into())?;
47 let db = sema.db;
48 match_ast! {
49 match node {
50 ast::CallExpr(it) => {
51 get_param_name_hints(acc, sema, ast::Expr::from(it));
52 },
53 ast::MethodCallExpr(it) => {
54 get_param_name_hints(acc, sema, ast::Expr::from(it));
55 },
56 ast::BindPat(it) => {
57 let pat = ast::Pat::from(it.clone());
58 let ty = sema.type_of_pat(&pat)?;
59
60 if should_not_display_type_hint(db, &it, &ty) {
61 return None;
62 }
63 91
64 acc.push( 92 if should_not_display_type_hint(sema.db, &pat, &ty) {
65 InlayHint { 93 return None;
66 range: pat.syntax().text_range(), 94 }
67 kind: InlayKind::TypeHint, 95
68 label: ty.display_truncated(db, max_inlay_hint_length).to_string().into(), 96 acc.push(InlayHint {
69 } 97 range: pat.syntax().text_range(),
70 ); 98 kind: InlayKind::TypeHint,
71 }, 99 label: ty.display_truncated(sema.db, max_inlay_hint_length).to_string().into(),
72 _ => (), 100 });
73 }
74 };
75 Some(()) 101 Some(())
76} 102}
77 103
@@ -120,43 +146,6 @@ fn should_not_display_type_hint(db: &RootDatabase, bind_pat: &ast::BindPat, pat_
120 false 146 false
121} 147}
122 148
123fn get_param_name_hints(
124 acc: &mut Vec<InlayHint>,
125 sema: &Semantics<RootDatabase>,
126 expr: ast::Expr,
127) -> Option<()> {
128 let args = match &expr {
129 ast::Expr::CallExpr(expr) => expr.arg_list()?.args(),
130 ast::Expr::MethodCallExpr(expr) => expr.arg_list()?.args(),
131 _ => return None,
132 }
133 .into_iter()
134 // we need args len to determine whether to skip or not the &self parameter
135 .collect::<Vec<_>>();
136
137 let fn_signature = get_fn_signature(sema, &expr)?;
138 let n_params_to_skip =
139 if fn_signature.has_self_param && fn_signature.parameter_names.len() > args.len() {
140 1
141 } else {
142 0
143 };
144 let hints = fn_signature
145 .parameter_names
146 .iter()
147 .skip(n_params_to_skip)
148 .zip(args)
149 .filter(|(param, arg)| should_show_param_hint(&fn_signature, param, &arg))
150 .map(|(param_name, arg)| InlayHint {
151 range: arg.syntax().text_range(),
152 kind: InlayKind::ParameterHint,
153 label: param_name.into(),
154 });
155
156 acc.extend(hints);
157 Some(())
158}
159
160fn should_show_param_hint( 149fn should_show_param_hint(
161 fn_signature: &FunctionSignature, 150 fn_signature: &FunctionSignature,
162 param_name: &str, 151 param_name: &str,
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index 9cc7930f7..4a70c712f 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -59,7 +59,7 @@ pub trait AstToken {
59} 59}
60 60
61/// An iterator over `SyntaxNode` children of a particular AST type. 61/// An iterator over `SyntaxNode` children of a particular AST type.
62#[derive(Debug)] 62#[derive(Debug, Clone)]
63pub struct AstChildren<N> { 63pub struct AstChildren<N> {
64 inner: SyntaxNodeChildren, 64 inner: SyntaxNodeChildren,
65 ph: PhantomData<N>, 65 ph: PhantomData<N>,