aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-01-15 10:24:51 +0000
committerGitHub <[email protected]>2020-01-15 10:24:51 +0000
commit876f92d547af5f39170350f3995647ec934f590b (patch)
treeb2dfc9053f910d1f64f3d899628cdaf482953aee /crates/ra_ide
parentbc8be6bcdb7ea9b23cc6723769e6071a705cb88b (diff)
parentd854ad8f279e5a3a4b3908bf5b0afdaba3d37bc9 (diff)
Merge #2843
2843: Add inlay parameter name hints for call expr r=matklad a=imtsuki This patch adds Intellij-like parameter name hints for literal values in function calls. <img width="624" alt="Screenshot" src="https://user-images.githubusercontent.com/8423594/72366533-68d7f800-3735-11ea-9279-cf193ca8ca2f.png"> Signed-off-by: imtsuki <[email protected]> Co-authored-by: imtsuki <[email protected]>
Diffstat (limited to 'crates/ra_ide')
-rw-r--r--crates/ra_ide/src/display/function_signature.rs20
-rw-r--r--crates/ra_ide/src/inlay_hints.rs141
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};
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: [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}