diff options
-rw-r--r-- | crates/ra_ide/src/inlay_hints.rs | 127 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast.rs | 2 |
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; | |||
5 | use ra_prof::profile; | 5 | use ra_prof::profile; |
6 | use ra_syntax::{ | 6 | use 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 | ||
11 | use crate::{FileId, FunctionSignature}; | 11 | use 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 | ||
40 | fn get_inlay_hints( | 49 | fn 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 | |||
84 | fn 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 | ||
123 | fn 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 | |||
160 | fn should_show_param_hint( | 149 | fn 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)] |
63 | pub struct AstChildren<N> { | 63 | pub struct AstChildren<N> { |
64 | inner: SyntaxNodeChildren, | 64 | inner: SyntaxNodeChildren, |
65 | ph: PhantomData<N>, | 65 | ph: PhantomData<N>, |