aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide')
-rw-r--r--crates/ra_ide/src/completion.rs2
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs239
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs12
-rw-r--r--crates/ra_ide/src/completion/completion_item.rs72
-rw-r--r--crates/ra_ide/src/completion/presentation.rs1
-rw-r--r--crates/ra_ide/src/display/function_signature.rs70
-rw-r--r--crates/ra_ide/src/lib.rs19
7 files changed, 389 insertions, 26 deletions
diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs
index 4a1a2a04a..19bc4321c 100644
--- a/crates/ra_ide/src/completion.rs
+++ b/crates/ra_ide/src/completion.rs
@@ -29,7 +29,7 @@ use crate::{
29}; 29};
30 30
31pub use crate::completion::completion_item::{ 31pub use crate::completion::completion_item::{
32 CompletionItem, CompletionItemKind, InsertTextFormat, 32 CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat,
33}; 33};
34 34
35#[derive(Clone, Debug, PartialEq, Eq)] 35#[derive(Clone, Debug, PartialEq, Eq)]
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs
index f433faef3..c16357a7e 100644
--- a/crates/ra_ide/src/completion/complete_dot.rs
+++ b/crates/ra_ide/src/completion/complete_dot.rs
@@ -2,12 +2,16 @@
2 2
3use hir::{HasVisibility, Type}; 3use hir::{HasVisibility, Type};
4 4
5use crate::completion::completion_item::CompletionKind;
6use crate::{ 5use crate::{
7 completion::{completion_context::CompletionContext, completion_item::Completions}, 6 completion::{
7 completion_context::CompletionContext,
8 completion_item::{CompletionKind, Completions},
9 },
10 // CallInfo,
8 CompletionItem, 11 CompletionItem,
9}; 12};
10use rustc_hash::FxHashSet; 13use rustc_hash::FxHashSet;
14// use std::cmp::Ordering;
11 15
12/// Complete dot accesses, i.e. fields or methods (and .await syntax). 16/// Complete dot accesses, i.e. fields or methods (and .await syntax).
13pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { 17pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
@@ -104,6 +108,237 @@ mod tests {
104 } 108 }
105 109
106 #[test] 110 #[test]
111 fn test_struct_field_completion_in_func_call() {
112 assert_debug_snapshot!(
113 do_ref_completion(
114 r"
115 struct A { another_field: i64, the_field: u32, my_string: String }
116 fn test(my_param: u32) -> u32 { my_param }
117 fn foo(a: A) {
118 test(a.<|>)
119 }
120 ",
121 ),
122 @r###"
123 [
124 CompletionItem {
125 label: "another_field",
126 source_range: [201; 201),
127 delete: [201; 201),
128 insert: "another_field",
129 kind: Field,
130 detail: "i64",
131 },
132 CompletionItem {
133 label: "my_string",
134 source_range: [201; 201),
135 delete: [201; 201),
136 insert: "my_string",
137 kind: Field,
138 detail: "{unknown}",
139 },
140 CompletionItem {
141 label: "the_field",
142 source_range: [201; 201),
143 delete: [201; 201),
144 insert: "the_field",
145 kind: Field,
146 detail: "u32",
147 score: TypeMatch,
148 },
149 ]
150 "###
151 );
152 }
153
154 #[test]
155 fn test_struct_field_completion_in_func_call_with_type_and_name() {
156 assert_debug_snapshot!(
157 do_ref_completion(
158 r"
159 struct A { another_field: i64, another_good_type: u32, the_field: u32 }
160 fn test(the_field: u32) -> u32 { the_field }
161 fn foo(a: A) {
162 test(a.<|>)
163 }
164 ",
165 ),
166 @r###"
167 [
168 CompletionItem {
169 label: "another_field",
170 source_range: [208; 208),
171 delete: [208; 208),
172 insert: "another_field",
173 kind: Field,
174 detail: "i64",
175 },
176 CompletionItem {
177 label: "another_good_type",
178 source_range: [208; 208),
179 delete: [208; 208),
180 insert: "another_good_type",
181 kind: Field,
182 detail: "u32",
183 score: TypeMatch,
184 },
185 CompletionItem {
186 label: "the_field",
187 source_range: [208; 208),
188 delete: [208; 208),
189 insert: "the_field",
190 kind: Field,
191 detail: "u32",
192 score: TypeAndNameMatch,
193 },
194 ]
195 "###
196 );
197 }
198
199 #[test]
200 fn test_struct_field_completion_in_record_lit() {
201 assert_debug_snapshot!(
202 do_ref_completion(
203 r"
204 struct A { another_field: i64, another_good_type: u32, the_field: u32 }
205 struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 }
206 fn foo(a: A) {
207 let b = B {
208 the_field: a.<|>
209 };
210 }
211 ",
212 ),
213 @r###"
214 [
215 CompletionItem {
216 label: "another_field",
217 source_range: [270; 270),
218 delete: [270; 270),
219 insert: "another_field",
220 kind: Field,
221 detail: "i64",
222 },
223 CompletionItem {
224 label: "another_good_type",
225 source_range: [270; 270),
226 delete: [270; 270),
227 insert: "another_good_type",
228 kind: Field,
229 detail: "u32",
230 score: TypeMatch,
231 },
232 CompletionItem {
233 label: "the_field",
234 source_range: [270; 270),
235 delete: [270; 270),
236 insert: "the_field",
237 kind: Field,
238 detail: "u32",
239 score: TypeAndNameMatch,
240 },
241 ]
242 "###
243 );
244 }
245
246 #[test]
247 fn test_struct_field_completion_in_record_lit_and_fn_call() {
248 assert_debug_snapshot!(
249 do_ref_completion(
250 r"
251 struct A { another_field: i64, another_good_type: u32, the_field: u32 }
252 struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 }
253 fn test(the_field: i64) -> i64 { the_field }
254 fn foo(a: A) {
255 let b = B {
256 the_field: test(a.<|>)
257 };
258 }
259 ",
260 ),
261 @r###"
262 [
263 CompletionItem {
264 label: "another_field",
265 source_range: [336; 336),
266 delete: [336; 336),
267 insert: "another_field",
268 kind: Field,
269 detail: "i64",
270 score: TypeMatch,
271 },
272 CompletionItem {
273 label: "another_good_type",
274 source_range: [336; 336),
275 delete: [336; 336),
276 insert: "another_good_type",
277 kind: Field,
278 detail: "u32",
279 },
280 CompletionItem {
281 label: "the_field",
282 source_range: [336; 336),
283 delete: [336; 336),
284 insert: "the_field",
285 kind: Field,
286 detail: "u32",
287 },
288 ]
289 "###
290 );
291 }
292
293 #[test]
294 fn test_struct_field_completion_in_fn_call_and_record_lit() {
295 assert_debug_snapshot!(
296 do_ref_completion(
297 r"
298 struct A { another_field: i64, another_good_type: u32, the_field: u32 }
299 struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 }
300 fn test(the_field: i64) -> i64 { the_field }
301 fn foo(a: A) {
302 test(B {
303 the_field: a.<|>
304 });
305 }
306 ",
307 ),
308 @r###"
309 [
310 CompletionItem {
311 label: "another_field",
312 source_range: [328; 328),
313 delete: [328; 328),
314 insert: "another_field",
315 kind: Field,
316 detail: "i64",
317 },
318 CompletionItem {
319 label: "another_good_type",
320 source_range: [328; 328),
321 delete: [328; 328),
322 insert: "another_good_type",
323 kind: Field,
324 detail: "u32",
325 score: TypeMatch,
326 },
327 CompletionItem {
328 label: "the_field",
329 source_range: [328; 328),
330 delete: [328; 328),
331 insert: "the_field",
332 kind: Field,
333 detail: "u32",
334 score: TypeAndNameMatch,
335 },
336 ]
337 "###
338 );
339 }
340
341 #[test]
107 fn test_struct_field_completion_self() { 342 fn test_struct_field_completion_self() {
108 assert_debug_snapshot!( 343 assert_debug_snapshot!(
109 do_ref_completion( 344 do_ref_completion(
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs
index 8b3401595..46e243192 100644
--- a/crates/ra_ide/src/completion/completion_context.rs
+++ b/crates/ra_ide/src/completion/completion_context.rs
@@ -21,6 +21,7 @@ pub(crate) struct CompletionContext<'a> {
21 pub(super) db: &'a RootDatabase, 21 pub(super) db: &'a RootDatabase,
22 pub(super) config: &'a CompletionConfig, 22 pub(super) config: &'a CompletionConfig,
23 pub(super) offset: TextUnit, 23 pub(super) offset: TextUnit,
24 pub(super) file_position: FilePosition,
24 /// The token before the cursor, in the original file. 25 /// The token before the cursor, in the original file.
25 pub(super) original_token: SyntaxToken, 26 pub(super) original_token: SyntaxToken,
26 /// The token before the cursor, in the macro-expanded file. 27 /// The token before the cursor, in the macro-expanded file.
@@ -31,6 +32,7 @@ pub(crate) struct CompletionContext<'a> {
31 pub(super) use_item_syntax: Option<ast::UseItem>, 32 pub(super) use_item_syntax: Option<ast::UseItem>,
32 pub(super) record_lit_syntax: Option<ast::RecordLit>, 33 pub(super) record_lit_syntax: Option<ast::RecordLit>,
33 pub(super) record_pat_syntax: Option<ast::RecordPat>, 34 pub(super) record_pat_syntax: Option<ast::RecordPat>,
35 pub(super) record_field_syntax: Option<ast::RecordField>,
34 pub(super) impl_def: Option<ast::ImplDef>, 36 pub(super) impl_def: Option<ast::ImplDef>,
35 pub(super) is_param: bool, 37 pub(super) is_param: bool,
36 /// If a name-binding or reference to a const in a pattern. 38 /// If a name-binding or reference to a const in a pattern.
@@ -88,12 +90,14 @@ impl<'a> CompletionContext<'a> {
88 original_token, 90 original_token,
89 token, 91 token,
90 offset: position.offset, 92 offset: position.offset,
93 file_position: position,
91 krate, 94 krate,
92 name_ref_syntax: None, 95 name_ref_syntax: None,
93 function_syntax: None, 96 function_syntax: None,
94 use_item_syntax: None, 97 use_item_syntax: None,
95 record_lit_syntax: None, 98 record_lit_syntax: None,
96 record_pat_syntax: None, 99 record_pat_syntax: None,
100 record_field_syntax: None,
97 impl_def: None, 101 impl_def: None,
98 is_param: false, 102 is_param: false,
99 is_pat_binding_or_const: false, 103 is_pat_binding_or_const: false,
@@ -268,6 +272,14 @@ impl<'a> CompletionContext<'a> {
268 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) 272 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
269 .find_map(ast::FnDef::cast); 273 .find_map(ast::FnDef::cast);
270 274
275 self.record_field_syntax = self
276 .sema
277 .ancestors_with_macros(self.token.parent())
278 .take_while(|it| {
279 it.kind() != SOURCE_FILE && it.kind() != MODULE && it.kind() != CALL_EXPR
280 })
281 .find_map(ast::RecordField::cast);
282
271 let parent = match name_ref.syntax().parent() { 283 let parent = match name_ref.syntax().parent() {
272 Some(it) => it, 284 Some(it) => it,
273 None => return, 285 None => return,
diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs
index bc0f1aff5..a3ae9c86b 100644
--- a/crates/ra_ide/src/completion/completion_item.rs
+++ b/crates/ra_ide/src/completion/completion_item.rs
@@ -2,7 +2,9 @@
2 2
3use std::fmt; 3use std::fmt;
4 4
5use hir::Documentation; 5use super::completion_context::CompletionContext;
6use crate::call_info::call_info;
7use hir::{Documentation, HirDisplay};
6use ra_syntax::TextRange; 8use ra_syntax::TextRange;
7use ra_text_edit::TextEdit; 9use ra_text_edit::TextEdit;
8 10
@@ -51,6 +53,9 @@ pub struct CompletionItem {
51 /// If completing a function call, ask the editor to show parameter popup 53 /// If completing a function call, ask the editor to show parameter popup
52 /// after completion. 54 /// after completion.
53 trigger_call_info: bool, 55 trigger_call_info: bool,
56
57 /// Score is usefull to pre select or display in better order completion items
58 score: Option<CompletionScore>,
54} 59}
55 60
56// We use custom debug for CompletionItem to make `insta`'s diffs more readable. 61// We use custom debug for CompletionItem to make `insta`'s diffs more readable.
@@ -80,6 +85,9 @@ impl fmt::Debug for CompletionItem {
80 if self.deprecated { 85 if self.deprecated {
81 s.field("deprecated", &true); 86 s.field("deprecated", &true);
82 } 87 }
88 if let Some(score) = &self.score {
89 s.field("score", score);
90 }
83 if self.trigger_call_info { 91 if self.trigger_call_info {
84 s.field("trigger_call_info", &true); 92 s.field("trigger_call_info", &true);
85 } 93 }
@@ -147,6 +155,7 @@ impl CompletionItem {
147 text_edit: None, 155 text_edit: None,
148 deprecated: None, 156 deprecated: None,
149 trigger_call_info: None, 157 trigger_call_info: None,
158 score: None,
150 } 159 }
151 } 160 }
152 /// What user sees in pop-up in the UI. 161 /// What user sees in pop-up in the UI.
@@ -186,6 +195,14 @@ impl CompletionItem {
186 self.deprecated 195 self.deprecated
187 } 196 }
188 197
198 pub fn score(&self) -> Option<CompletionScore> {
199 self.score.clone()
200 }
201
202 pub fn set_score(&mut self, score: CompletionScore) {
203 self.score = Some(score);
204 }
205
189 pub fn trigger_call_info(&self) -> bool { 206 pub fn trigger_call_info(&self) -> bool {
190 self.trigger_call_info 207 self.trigger_call_info
191 } 208 }
@@ -206,6 +223,7 @@ pub(crate) struct Builder {
206 text_edit: Option<TextEdit>, 223 text_edit: Option<TextEdit>,
207 deprecated: Option<bool>, 224 deprecated: Option<bool>,
208 trigger_call_info: Option<bool>, 225 trigger_call_info: Option<bool>,
226 score: Option<CompletionScore>,
209} 227}
210 228
211impl Builder { 229impl Builder {
@@ -235,6 +253,7 @@ impl Builder {
235 completion_kind: self.completion_kind, 253 completion_kind: self.completion_kind,
236 deprecated: self.deprecated.unwrap_or(false), 254 deprecated: self.deprecated.unwrap_or(false),
237 trigger_call_info: self.trigger_call_info.unwrap_or(false), 255 trigger_call_info: self.trigger_call_info.unwrap_or(false),
256 score: self.score,
238 } 257 }
239 } 258 }
240 pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder { 259 pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder {
@@ -285,6 +304,51 @@ impl Builder {
285 self.deprecated = Some(deprecated); 304 self.deprecated = Some(deprecated);
286 self 305 self
287 } 306 }
307 #[allow(unused)]
308 pub(crate) fn compute_score(mut self, ctx: &CompletionContext) -> Builder {
309 let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax {
310 if let Some((struct_field, _)) = ctx.sema.resolve_record_field(record_field) {
311 (
312 struct_field.name(ctx.db).to_string(),
313 struct_field.signature_ty(ctx.db).display(ctx.db).to_string(),
314 )
315 } else {
316 return self;
317 }
318 } else if let Some(call_info) = call_info(ctx.db, ctx.file_position) {
319 if call_info.active_parameter_type().is_some()
320 && call_info.active_parameter_name().is_some()
321 {
322 (
323 call_info.active_parameter_name().unwrap(),
324 call_info.active_parameter_type().unwrap(),
325 )
326 } else {
327 return self;
328 }
329 } else {
330 return self;
331 };
332
333 // Compute score
334 // For the same type
335 if let Some(a_parameter_type) = &self.detail {
336 if &active_type == a_parameter_type {
337 // If same type + same name then go top position
338 if active_name == self.label {
339 return self.set_score(CompletionScore::TypeAndNameMatch);
340 } else {
341 return self.set_score(CompletionScore::TypeMatch);
342 }
343 }
344 }
345
346 self
347 }
348 pub(crate) fn set_score(mut self, score: CompletionScore) -> Builder {
349 self.score = Some(score);
350 self
351 }
288 pub(crate) fn trigger_call_info(mut self) -> Builder { 352 pub(crate) fn trigger_call_info(mut self) -> Builder {
289 self.trigger_call_info = Some(true); 353 self.trigger_call_info = Some(true);
290 self 354 self
@@ -297,6 +361,12 @@ impl<'a> Into<CompletionItem> for Builder {
297 } 361 }
298} 362}
299 363
364#[derive(Debug, Clone)]
365pub enum CompletionScore {
366 TypeMatch,
367 TypeAndNameMatch,
368}
369
300/// Represents an in-progress set of completions being built. 370/// Represents an in-progress set of completions being built.
301#[derive(Debug, Default)] 371#[derive(Debug, Default)]
302pub(crate) struct Completions { 372pub(crate) struct Completions {
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs
index 55f75b15a..5c3360ce4 100644
--- a/crates/ra_ide/src/completion/presentation.rs
+++ b/crates/ra_ide/src/completion/presentation.rs
@@ -31,6 +31,7 @@ impl Completions {
31 .detail(ty.display(ctx.db).to_string()) 31 .detail(ty.display(ctx.db).to_string())
32 .set_documentation(field.docs(ctx.db)) 32 .set_documentation(field.docs(ctx.db))
33 .set_deprecated(is_deprecated) 33 .set_deprecated(is_deprecated)
34 .compute_score(ctx)
34 .add_to(self); 35 .add_to(self);
35 } 36 }
36 37
diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs
index b967a6816..2d175882b 100644
--- a/crates/ra_ide/src/display/function_signature.rs
+++ b/crates/ra_ide/src/display/function_signature.rs
@@ -36,6 +36,8 @@ pub struct FunctionSignature {
36 pub parameters: Vec<String>, 36 pub parameters: Vec<String>,
37 /// Parameter names of the function 37 /// Parameter names of the function
38 pub parameter_names: Vec<String>, 38 pub parameter_names: Vec<String>,
39 /// Parameter types of the function
40 pub parameter_types: Vec<String>,
39 /// Optional return type 41 /// Optional return type
40 pub ret_type: Option<String>, 42 pub ret_type: Option<String>,
41 /// Where predicates 43 /// Where predicates
@@ -62,14 +64,20 @@ impl FunctionSignature {
62 return None; 64 return None;
63 }; 65 };
64 66
65 let params = st 67 let mut params = vec![];
66 .fields(db) 68 let mut parameter_types = vec![];
67 .into_iter() 69 for field in st.fields(db).into_iter() {
68 .map(|field: hir::StructField| { 70 let ty = field.signature_ty(db);
69 let ty = field.signature_ty(db); 71 let raw_param = format!("{}", ty.display(db));
70 format!("{}", ty.display(db)) 72
71 }) 73 if let Some(param_type) = raw_param.split(':').nth(1) {
72 .collect(); 74 parameter_types.push(param_type[1..].to_string());
75 } else {
76 // The unwrap_or_else is useful when you have tuple struct
77 parameter_types.push(raw_param.clone());
78 }
79 params.push(raw_param);
80 }
73 81
74 Some( 82 Some(
75 FunctionSignature { 83 FunctionSignature {
@@ -79,6 +87,7 @@ impl FunctionSignature {
79 ret_type: node.name().map(|n| n.text().to_string()), 87 ret_type: node.name().map(|n| n.text().to_string()),
80 parameters: params, 88 parameters: params,
81 parameter_names: vec![], 89 parameter_names: vec![],
90 parameter_types,
82 generic_parameters: generic_parameters(&node), 91 generic_parameters: generic_parameters(&node),
83 where_predicates: where_predicates(&node), 92 where_predicates: where_predicates(&node),
84 doc: None, 93 doc: None,
@@ -99,15 +108,21 @@ impl FunctionSignature {
99 108
100 let name = format!("{}::{}", parent_name, variant.name(db)); 109 let name = format!("{}::{}", parent_name, variant.name(db));
101 110
102 let params = variant 111 let mut params = vec![];
103 .fields(db) 112 let mut parameter_types = vec![];
104 .into_iter() 113 for field in variant.fields(db).into_iter() {
105 .map(|field: hir::StructField| { 114 let ty = field.signature_ty(db);
106 let name = field.name(db); 115 let raw_param = format!("{}", ty.display(db));
107 let ty = field.signature_ty(db); 116 if let Some(param_type) = raw_param.split(':').nth(1) {
108 format!("{}: {}", name, ty.display(db)) 117 parameter_types.push(param_type[1..].to_string());
109 }) 118 } else {
110 .collect(); 119 // The unwrap_or_else is useful when you have tuple
120 parameter_types.push(raw_param);
121 }
122 let name = field.name(db);
123
124 params.push(format!("{}: {}", name, ty.display(db)));
125 }
111 126
112 Some( 127 Some(
113 FunctionSignature { 128 FunctionSignature {
@@ -117,6 +132,7 @@ impl FunctionSignature {
117 ret_type: None, 132 ret_type: None,
118 parameters: params, 133 parameters: params,
119 parameter_names: vec![], 134 parameter_names: vec![],
135 parameter_types,
120 generic_parameters: vec![], 136 generic_parameters: vec![],
121 where_predicates: vec![], 137 where_predicates: vec![],
122 doc: None, 138 doc: None,
@@ -139,6 +155,7 @@ impl FunctionSignature {
139 ret_type: None, 155 ret_type: None,
140 parameters: params, 156 parameters: params,
141 parameter_names: vec![], 157 parameter_names: vec![],
158 parameter_types: vec![],
142 generic_parameters: vec![], 159 generic_parameters: vec![],
143 where_predicates: vec![], 160 where_predicates: vec![],
144 doc: None, 161 doc: None,
@@ -151,18 +168,28 @@ impl FunctionSignature {
151 168
152impl From<&'_ ast::FnDef> for FunctionSignature { 169impl From<&'_ ast::FnDef> for FunctionSignature {
153 fn from(node: &ast::FnDef) -> FunctionSignature { 170 fn from(node: &ast::FnDef) -> FunctionSignature {
154 fn param_list(node: &ast::FnDef) -> (bool, Vec<String>) { 171 fn param_list(node: &ast::FnDef) -> (bool, Vec<String>, Vec<String>) {
155 let mut res = vec![]; 172 let mut res = vec![];
173 let mut res_types = vec![];
156 let mut has_self_param = false; 174 let mut has_self_param = false;
157 if let Some(param_list) = node.param_list() { 175 if let Some(param_list) = node.param_list() {
158 if let Some(self_param) = param_list.self_param() { 176 if let Some(self_param) = param_list.self_param() {
159 has_self_param = true; 177 has_self_param = true;
160 res.push(self_param.syntax().text().to_string()) 178 let raw_param = self_param.syntax().text().to_string();
179
180 // FIXME: better solution ?
181 res_types.push(
182 raw_param.split(':').nth(1).unwrap_or_else(|| " Self")[1..].to_string(),
183 );
184 res.push(raw_param);
161 } 185 }
162 186
163 res.extend(param_list.params().map(|param| param.syntax().text().to_string())); 187 res.extend(param_list.params().map(|param| param.syntax().text().to_string()));
188 res_types.extend(param_list.params().map(|param| {
189 param.syntax().text().to_string().split(':').nth(1).unwrap()[1..].to_string()
190 }));
164 } 191 }
165 (has_self_param, res) 192 (has_self_param, res, res_types)
166 } 193 }
167 194
168 fn param_name_list(node: &ast::FnDef) -> Vec<String> { 195 fn param_name_list(node: &ast::FnDef) -> Vec<String> {
@@ -192,7 +219,7 @@ impl From<&'_ ast::FnDef> for FunctionSignature {
192 res 219 res
193 } 220 }
194 221
195 let (has_self_param, parameters) = param_list(node); 222 let (has_self_param, parameters, parameter_types) = param_list(node);
196 223
197 FunctionSignature { 224 FunctionSignature {
198 kind: CallableKind::Function, 225 kind: CallableKind::Function,
@@ -204,6 +231,7 @@ impl From<&'_ ast::FnDef> for FunctionSignature {
204 .map(|n| n.syntax().text().to_string()), 231 .map(|n| n.syntax().text().to_string()),
205 parameters, 232 parameters,
206 parameter_names: param_name_list(node), 233 parameter_names: param_name_list(node),
234 parameter_types,
207 generic_parameters: generic_parameters(node), 235 generic_parameters: generic_parameters(node),
208 where_predicates: where_predicates(node), 236 where_predicates: where_predicates(node),
209 // docs are processed separately 237 // docs are processed separately
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index 5599f143f..ddaa30a16 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -67,7 +67,9 @@ use crate::display::ToNav;
67pub use crate::{ 67pub use crate::{
68 assists::{Assist, AssistId}, 68 assists::{Assist, AssistId},
69 call_hierarchy::CallItem, 69 call_hierarchy::CallItem,
70 completion::{CompletionConfig, CompletionItem, CompletionItemKind, InsertTextFormat}, 70 completion::{
71 CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat,
72 },
71 diagnostics::Severity, 73 diagnostics::Severity,
72 display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, 74 display::{file_structure, FunctionSignature, NavigationTarget, StructureNode},
73 expand_macro::ExpandedMacro, 75 expand_macro::ExpandedMacro,
@@ -127,6 +129,21 @@ pub struct CallInfo {
127 pub active_parameter: Option<usize>, 129 pub active_parameter: Option<usize>,
128} 130}
129 131
132impl CallInfo {
133 pub fn active_parameter_type(&self) -> Option<String> {
134 if let Some(id) = self.active_parameter {
135 return self.signature.parameter_types.get(id).map(|param_ty| param_ty.clone());
136 }
137 None
138 }
139 pub fn active_parameter_name(&self) -> Option<String> {
140 if let Some(id) = self.active_parameter {
141 return self.signature.parameter_names.get(id).map(|param_ty| param_ty.clone());
142 }
143 None
144 }
145}
146
130/// `AnalysisHost` stores the current state of the world. 147/// `AnalysisHost` stores the current state of the world.
131#[derive(Debug)] 148#[derive(Debug)]
132pub struct AnalysisHost { 149pub struct AnalysisHost {