diff options
Diffstat (limited to 'crates/ra_ide')
-rw-r--r-- | crates/ra_ide/src/display/function_signature.rs | 20 | ||||
-rw-r--r-- | crates/ra_ide/src/inlay_hints.rs | 141 |
2 files changed, 159 insertions, 2 deletions
diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs index 324ad9552..ddc53a52b 100644 --- a/crates/ra_ide/src/display/function_signature.rs +++ b/crates/ra_ide/src/display/function_signature.rs | |||
@@ -34,6 +34,8 @@ pub struct FunctionSignature { | |||
34 | pub generic_parameters: Vec<String>, | 34 | pub generic_parameters: Vec<String>, |
35 | /// Parameters of the function | 35 | /// Parameters of the function |
36 | pub parameters: Vec<String>, | 36 | pub parameters: Vec<String>, |
37 | /// Parameter names of the function | ||
38 | pub parameter_names: Vec<String>, | ||
37 | /// Optional return type | 39 | /// Optional return type |
38 | pub ret_type: Option<String>, | 40 | pub ret_type: Option<String>, |
39 | /// Where predicates | 41 | /// Where predicates |
@@ -75,6 +77,7 @@ impl FunctionSignature { | |||
75 | name: node.name().map(|n| n.text().to_string()), | 77 | name: node.name().map(|n| n.text().to_string()), |
76 | ret_type: node.name().map(|n| n.text().to_string()), | 78 | ret_type: node.name().map(|n| n.text().to_string()), |
77 | parameters: params, | 79 | parameters: params, |
80 | parameter_names: vec![], | ||
78 | generic_parameters: generic_parameters(&node), | 81 | generic_parameters: generic_parameters(&node), |
79 | where_predicates: where_predicates(&node), | 82 | where_predicates: where_predicates(&node), |
80 | doc: None, | 83 | doc: None, |
@@ -114,6 +117,7 @@ impl FunctionSignature { | |||
114 | name: Some(name), | 117 | name: Some(name), |
115 | ret_type: None, | 118 | ret_type: None, |
116 | parameters: params, | 119 | parameters: params, |
120 | parameter_names: vec![], | ||
117 | generic_parameters: vec![], | 121 | generic_parameters: vec![], |
118 | where_predicates: vec![], | 122 | where_predicates: vec![], |
119 | doc: None, | 123 | doc: None, |
@@ -134,6 +138,7 @@ impl FunctionSignature { | |||
134 | name: node.name().map(|n| n.text().to_string()), | 138 | name: node.name().map(|n| n.text().to_string()), |
135 | ret_type: None, | 139 | ret_type: None, |
136 | parameters: params, | 140 | parameters: params, |
141 | parameter_names: vec![], | ||
137 | generic_parameters: vec![], | 142 | generic_parameters: vec![], |
138 | where_predicates: vec![], | 143 | where_predicates: vec![], |
139 | doc: None, | 144 | doc: None, |
@@ -157,6 +162,20 @@ impl From<&'_ ast::FnDef> for FunctionSignature { | |||
157 | res | 162 | res |
158 | } | 163 | } |
159 | 164 | ||
165 | fn param_name_list(node: &ast::FnDef) -> Vec<String> { | ||
166 | let mut res = vec![]; | ||
167 | if let Some(param_list) = node.param_list() { | ||
168 | if let Some(self_param) = param_list.self_param() { | ||
169 | res.push(self_param.syntax().text().to_string()) | ||
170 | } | ||
171 | |||
172 | res.extend(param_list.params().map(|param| { | ||
173 | param.pat().map(|pat| pat.syntax().text().to_string()).unwrap_or_default() | ||
174 | })); | ||
175 | } | ||
176 | res | ||
177 | } | ||
178 | |||
160 | FunctionSignature { | 179 | FunctionSignature { |
161 | kind: CallableKind::Function, | 180 | kind: CallableKind::Function, |
162 | visibility: node.visibility().map(|n| n.syntax().text().to_string()), | 181 | visibility: node.visibility().map(|n| n.syntax().text().to_string()), |
@@ -166,6 +185,7 @@ impl From<&'_ ast::FnDef> for FunctionSignature { | |||
166 | .and_then(|r| r.type_ref()) | 185 | .and_then(|r| r.type_ref()) |
167 | .map(|n| n.syntax().text().to_string()), | 186 | .map(|n| n.syntax().text().to_string()), |
168 | parameters: param_list(node), | 187 | parameters: param_list(node), |
188 | parameter_names: param_name_list(node), | ||
169 | generic_parameters: generic_parameters(node), | 189 | generic_parameters: generic_parameters(node), |
170 | where_predicates: where_predicates(node), | 190 | where_predicates: where_predicates(node), |
171 | // docs are processed separately | 191 | // docs are processed separately |
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs index 977aafc51..8cb0c70dd 100644 --- a/crates/ra_ide/src/inlay_hints.rs +++ b/crates/ra_ide/src/inlay_hints.rs | |||
@@ -4,15 +4,16 @@ use hir::{HirDisplay, SourceAnalyzer}; | |||
4 | use once_cell::unsync::Lazy; | 4 | use once_cell::unsync::Lazy; |
5 | use ra_prof::profile; | 5 | use ra_prof::profile; |
6 | use ra_syntax::{ | 6 | use ra_syntax::{ |
7 | ast::{self, AstNode, TypeAscriptionOwner}, | 7 | ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner}, |
8 | match_ast, SmolStr, SourceFile, SyntaxKind, SyntaxNode, TextRange, | 8 | match_ast, SmolStr, SourceFile, SyntaxKind, SyntaxNode, TextRange, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | use crate::{db::RootDatabase, FileId}; | 11 | use crate::{db::RootDatabase, FileId, FunctionSignature}; |
12 | 12 | ||
13 | #[derive(Debug, PartialEq, Eq)] | 13 | #[derive(Debug, PartialEq, Eq)] |
14 | pub enum InlayKind { | 14 | pub enum InlayKind { |
15 | TypeHint, | 15 | TypeHint, |
16 | ParameterHint, | ||
16 | } | 17 | } |
17 | 18 | ||
18 | #[derive(Debug)] | 19 | #[derive(Debug)] |
@@ -87,10 +88,79 @@ fn get_inlay_hints( | |||
87 | .collect(), | 88 | .collect(), |
88 | ) | 89 | ) |
89 | }, | 90 | }, |
91 | ast::CallExpr(it) => { | ||
92 | get_param_name_hints(db, &analyzer, ast::Expr::from(it)) | ||
93 | }, | ||
94 | ast::MethodCallExpr(it) => { | ||
95 | get_param_name_hints(db, &analyzer, ast::Expr::from(it)) | ||
96 | }, | ||
90 | _ => None, | 97 | _ => None, |
91 | } | 98 | } |
92 | } | 99 | } |
93 | } | 100 | } |
101 | fn get_param_name_hints( | ||
102 | db: &RootDatabase, | ||
103 | analyzer: &SourceAnalyzer, | ||
104 | expr: ast::Expr, | ||
105 | ) -> Option<Vec<InlayHint>> { | ||
106 | let args = match &expr { | ||
107 | ast::Expr::CallExpr(expr) => Some(expr.arg_list()?.args()), | ||
108 | ast::Expr::MethodCallExpr(expr) => Some(expr.arg_list()?.args()), | ||
109 | _ => None, | ||
110 | }?; | ||
111 | |||
112 | let mut parameters = get_fn_signature(db, analyzer, &expr)?.parameter_names.into_iter(); | ||
113 | |||
114 | if let ast::Expr::MethodCallExpr(_) = &expr { | ||
115 | parameters.next(); | ||
116 | }; | ||
117 | |||
118 | let hints = parameters | ||
119 | .zip(args) | ||
120 | .filter_map(|(param, arg)| { | ||
121 | if arg.syntax().kind() == SyntaxKind::LITERAL { | ||
122 | Some((arg.syntax().text_range(), param)) | ||
123 | } else { | ||
124 | None | ||
125 | } | ||
126 | }) | ||
127 | .map(|(range, param_name)| InlayHint { | ||
128 | range, | ||
129 | kind: InlayKind::ParameterHint, | ||
130 | label: param_name.into(), | ||
131 | }) | ||
132 | .collect(); | ||
133 | |||
134 | Some(hints) | ||
135 | } | ||
136 | |||
137 | fn get_fn_signature( | ||
138 | db: &RootDatabase, | ||
139 | analyzer: &SourceAnalyzer, | ||
140 | expr: &ast::Expr, | ||
141 | ) -> Option<FunctionSignature> { | ||
142 | match expr { | ||
143 | ast::Expr::CallExpr(expr) => { | ||
144 | // FIXME: Type::as_callable is broken for closures | ||
145 | let callable_def = analyzer.type_of(db, &expr.expr()?)?.as_callable()?; | ||
146 | match callable_def { | ||
147 | hir::CallableDef::FunctionId(it) => { | ||
148 | let fn_def = it.into(); | ||
149 | Some(FunctionSignature::from_hir(db, fn_def)) | ||
150 | } | ||
151 | hir::CallableDef::StructId(it) => FunctionSignature::from_struct(db, it.into()), | ||
152 | hir::CallableDef::EnumVariantId(it) => { | ||
153 | FunctionSignature::from_enum_variant(db, it.into()) | ||
154 | } | ||
155 | } | ||
156 | } | ||
157 | ast::Expr::MethodCallExpr(expr) => { | ||
158 | let fn_def = analyzer.resolve_method_call(&expr)?; | ||
159 | Some(FunctionSignature::from_hir(db, fn_def)) | ||
160 | } | ||
161 | _ => None, | ||
162 | } | ||
163 | } | ||
94 | 164 | ||
95 | fn get_pat_type_hints( | 165 | fn get_pat_type_hints( |
96 | db: &RootDatabase, | 166 | db: &RootDatabase, |
@@ -605,4 +675,71 @@ fn main() { | |||
605 | "### | 675 | "### |
606 | ); | 676 | ); |
607 | } | 677 | } |
678 | |||
679 | #[test] | ||
680 | fn function_call_parameter_hint() { | ||
681 | let (analysis, file_id) = single_file( | ||
682 | r#" | ||
683 | struct Test {} | ||
684 | |||
685 | impl Test { | ||
686 | fn method(&self, param: i32) -> i32 { | ||
687 | param * 2 | ||
688 | } | ||
689 | } | ||
690 | |||
691 | fn test_func(foo: i32, bar: i32, msg: &str, _: i32, last: i32) -> i32 { | ||
692 | foo + bar | ||
693 | } | ||
694 | |||
695 | fn main() { | ||
696 | let not_literal = 1; | ||
697 | let _: i32 = test_func(1, 2, "hello", 3, not_literal); | ||
698 | let t: Test = Test {}; | ||
699 | t.method(123); | ||
700 | Test::method(&t, 3456); | ||
701 | }"#, | ||
702 | ); | ||
703 | |||
704 | assert_debug_snapshot!(analysis.inlay_hints(file_id, None).unwrap(), @r###" | ||
705 | [ | ||
706 | InlayHint { | ||
707 | range: [207; 218), | ||
708 | kind: TypeHint, | ||
709 | label: "i32", | ||
710 | }, | ||
711 | InlayHint { | ||
712 | range: [251; 252), | ||
713 | kind: ParameterHint, | ||
714 | label: "foo", | ||
715 | }, | ||
716 | InlayHint { | ||
717 | range: [254; 255), | ||
718 | kind: ParameterHint, | ||
719 | label: "bar", | ||
720 | }, | ||
721 | InlayHint { | ||
722 | range: [257; 264), | ||
723 | kind: ParameterHint, | ||
724 | label: "msg", | ||
725 | }, | ||
726 | InlayHint { | ||
727 | range: [266; 267), | ||
728 | kind: ParameterHint, | ||
729 | label: "_", | ||
730 | }, | ||
731 | InlayHint { | ||
732 | range: [323; 326), | ||
733 | kind: ParameterHint, | ||
734 | label: "param", | ||
735 | }, | ||
736 | InlayHint { | ||
737 | range: [350; 354), | ||
738 | kind: ParameterHint, | ||
739 | label: "param", | ||
740 | }, | ||
741 | ] | ||
742 | "### | ||
743 | ); | ||
744 | } | ||
608 | } | 745 | } |