aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide
diff options
context:
space:
mode:
authorimtsuki <[email protected]>2020-01-14 17:02:01 +0000
committerimtsuki <[email protected]>2020-01-14 17:18:52 +0000
commitc390e92fdd25ced46c589bfbff94e4b0bc4d9c38 (patch)
treebd33983bd3d77c1442f7814d595cbf0506f421da /crates/ra_ide
parentd8d8c20077702b8537086d49914d02654a46ebc5 (diff)
Add inlay parameter name hints for function calls
Signed-off-by: imtsuki <[email protected]>
Diffstat (limited to 'crates/ra_ide')
-rw-r--r--crates/ra_ide/src/display/function_signature.rs22
-rw-r--r--crates/ra_ide/src/inlay_hints.rs141
2 files changed, 161 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..b0eb1f194 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,22 @@ 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(
173 param_list
174 .params()
175 .map(|param| param.pat().unwrap().syntax().text().to_string()),
176 );
177 }
178 res
179 }
180
160 FunctionSignature { 181 FunctionSignature {
161 kind: CallableKind::Function, 182 kind: CallableKind::Function,
162 visibility: node.visibility().map(|n| n.syntax().text().to_string()), 183 visibility: node.visibility().map(|n| n.syntax().text().to_string()),
@@ -166,6 +187,7 @@ impl From<&'_ ast::FnDef> for FunctionSignature {
166 .and_then(|r| r.type_ref()) 187 .and_then(|r| r.type_ref())
167 .map(|n| n.syntax().text().to_string()), 188 .map(|n| n.syntax().text().to_string()),
168 parameters: param_list(node), 189 parameters: param_list(node),
190 parameter_names: param_name_list(node),
169 generic_parameters: generic_parameters(node), 191 generic_parameters: generic_parameters(node),
170 where_predicates: where_predicates(node), 192 where_predicates: where_predicates(node),
171 // docs are processed separately 193 // docs are processed separately
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index 977aafc51..83e4588c1 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};
4use once_cell::unsync::Lazy; 4use once_cell::unsync::Lazy;
5use ra_prof::profile; 5use ra_prof::profile;
6use ra_syntax::{ 6use 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
11use crate::{db::RootDatabase, FileId}; 11use crate::{db::RootDatabase, FileId, FunctionSignature};
12 12
13#[derive(Debug, PartialEq, Eq)] 13#[derive(Debug, PartialEq, Eq)]
14pub enum InlayKind { 14pub 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}
101fn 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
137fn 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
95fn get_pat_type_hints( 165fn 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#"
683struct Test {}
684
685impl Test {
686 fn method(&self, param: i32) -> i32 {
687 param * 2
688 }
689}
690
691fn test_func(foo: i32, bar: i32, msg: &str, _: i32, last: i32) -> i32 {
692 foo + bar
693}
694
695fn 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: [322; 325),
733 kind: ParameterHint,
734 label: "param",
735 },
736 InlayHint {
737 range: [349; 353),
738 kind: ParameterHint,
739 label: "param",
740 },
741 ]
742 "###
743 );
744 }
608} 745}