aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/inlay_hints.rs
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/src/inlay_hints.rs
parentd8d8c20077702b8537086d49914d02654a46ebc5 (diff)
Add inlay parameter name hints for function calls
Signed-off-by: imtsuki <[email protected]>
Diffstat (limited to 'crates/ra_ide/src/inlay_hints.rs')
-rw-r--r--crates/ra_ide/src/inlay_hints.rs141
1 files changed, 139 insertions, 2 deletions
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}