aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/call_info.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/call_info.rs')
-rw-r--r--crates/ra_ide_api/src/call_info.rs114
1 files changed, 75 insertions, 39 deletions
diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs
index 29fa7d30b..dbb3853d0 100644
--- a/crates/ra_ide_api/src/call_info.rs
+++ b/crates/ra_ide_api/src/call_info.rs
@@ -6,9 +6,8 @@ use ra_syntax::{
6 ast::{self, ArgListOwner}, 6 ast::{self, ArgListOwner},
7 algo::find_node_at_offset, 7 algo::find_node_at_offset,
8}; 8};
9use hir::Docs;
10 9
11use crate::{FilePosition, CallInfo, db::RootDatabase}; 10use crate::{FilePosition, CallInfo, FunctionSignature, db::RootDatabase};
12 11
13/// Computes parameter information for the given call expression. 12/// Computes parameter information for the given call expression.
14pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> { 13pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> {
@@ -27,10 +26,10 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
27 let fn_def = ast::FnDef::cast(fn_def).unwrap(); 26 let fn_def = ast::FnDef::cast(fn_def).unwrap();
28 let function = hir::source_binder::function_from_source(db, symbol.file_id, fn_def)?; 27 let function = hir::source_binder::function_from_source(db, symbol.file_id, fn_def)?;
29 28
30 let mut call_info = CallInfo::new(db, function, fn_def)?; 29 let mut call_info = CallInfo::new(db, function);
31 30
32 // If we have a calling expression let's find which argument we are on 31 // If we have a calling expression let's find which argument we are on
33 let num_params = call_info.parameters.len(); 32 let num_params = call_info.parameters().len();
34 let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some(); 33 let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some();
35 34
36 if num_params == 1 { 35 if num_params == 1 {
@@ -107,28 +106,15 @@ impl<'a> FnCallNode<'a> {
107} 106}
108 107
109impl CallInfo { 108impl CallInfo {
110 fn new(db: &RootDatabase, function: hir::Function, node: &ast::FnDef) -> Option<Self> { 109 fn new(db: &RootDatabase, function: hir::Function) -> Self {
111 let label = crate::completion::function_label(node)?; 110 let signature = FunctionSignature::from_hir(db, function);
112 let doc = function.docs(db);
113 111
114 Some(CallInfo { parameters: param_list(node), label, doc, active_parameter: None }) 112 CallInfo { signature, active_parameter: None }
115 } 113 }
116}
117
118fn param_list(node: &ast::FnDef) -> Vec<String> {
119 let mut res = vec![];
120 if let Some(param_list) = node.param_list() {
121 if let Some(self_param) = param_list.self_param() {
122 res.push(self_param.syntax().text().to_string())
123 }
124 114
125 // Maybe use param.pat here? See if we can just extract the name? 115 fn parameters(&self) -> &[String] {
126 //res.extend(param_list.params().map(|p| p.syntax().text().to_string())); 116 &self.signature.parameters
127 res.extend(
128 param_list.params().filter_map(|p| p.pat()).map(|pat| pat.syntax().text().to_string()),
129 );
130 } 117 }
131 res
132} 118}
133 119
134#[cfg(test)] 120#[cfg(test)]
@@ -139,6 +125,17 @@ mod tests {
139 125
140 use super::*; 126 use super::*;
141 127
128 // These are only used when testing
129 impl CallInfo {
130 fn doc(&self) -> Option<hir::Documentation> {
131 self.signature.doc.clone()
132 }
133
134 fn label(&self) -> String {
135 self.signature.to_string()
136 }
137 }
138
142 fn call_info(text: &str) -> CallInfo { 139 fn call_info(text: &str) -> CallInfo {
143 let (analysis, position) = single_file_with_position(text); 140 let (analysis, position) = single_file_with_position(text);
144 analysis.call_info(position).unwrap().unwrap() 141 analysis.call_info(position).unwrap().unwrap()
@@ -151,7 +148,7 @@ mod tests {
151fn bar() { foo(<|>3, ); }"#, 148fn bar() { foo(<|>3, ); }"#,
152 ); 149 );
153 150
154 assert_eq!(info.parameters, vec!("x".to_string(), "y".to_string())); 151 assert_eq!(info.parameters(), ["x: u32", "y: u32"]);
155 assert_eq!(info.active_parameter, Some(0)); 152 assert_eq!(info.active_parameter, Some(0));
156 } 153 }
157 154
@@ -162,7 +159,7 @@ fn bar() { foo(<|>3, ); }"#,
162fn bar() { foo(3, <|>); }"#, 159fn bar() { foo(3, <|>); }"#,
163 ); 160 );
164 161
165 assert_eq!(info.parameters, vec!("x".to_string(), "y".to_string())); 162 assert_eq!(info.parameters(), ["x: u32", "y: u32"]);
166 assert_eq!(info.active_parameter, Some(1)); 163 assert_eq!(info.active_parameter, Some(1));
167 } 164 }
168 165
@@ -173,18 +170,57 @@ fn bar() { foo(3, <|>); }"#,
173fn bar() { foo(<|>); }"#, 170fn bar() { foo(<|>); }"#,
174 ); 171 );
175 172
176 assert_eq!(info.parameters, vec!("x".to_string(), "y".to_string())); 173 assert_eq!(info.parameters(), ["x: u32", "y: u32"]);
174 assert_eq!(info.active_parameter, Some(0));
175 }
176
177 #[test]
178 fn test_fn_signature_two_args_first_generics() {
179 let info = call_info(
180 r#"fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 where T: Copy + Display, U: Debug {x + y}
181fn bar() { foo(<|>3, ); }"#,
182 );
183
184 assert_eq!(info.parameters(), ["x: T", "y: U"]);
185 assert_eq!(
186 info.label(),
187 r#"
188fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
189where T: Copy + Display,
190 U: Debug
191 "#
192 .trim()
193 );
177 assert_eq!(info.active_parameter, Some(0)); 194 assert_eq!(info.active_parameter, Some(0));
178 } 195 }
179 196
180 #[test] 197 #[test]
198 fn test_fn_signature_no_params() {
199 let info = call_info(
200 r#"fn foo<T>() -> T where T: Copy + Display {}
201fn bar() { foo(<|>); }"#,
202 );
203
204 assert!(info.parameters().is_empty());
205 assert_eq!(
206 info.label(),
207 r#"
208fn foo<T>() -> T
209where T: Copy + Display
210 "#
211 .trim()
212 );
213 assert!(info.active_parameter.is_none());
214 }
215
216 #[test]
181 fn test_fn_signature_for_impl() { 217 fn test_fn_signature_for_impl() {
182 let info = call_info( 218 let info = call_info(
183 r#"struct F; impl F { pub fn new() { F{}} } 219 r#"struct F; impl F { pub fn new() { F{}} }
184fn bar() {let _ : F = F::new(<|>);}"#, 220fn bar() {let _ : F = F::new(<|>);}"#,
185 ); 221 );
186 222
187 assert_eq!(info.parameters, Vec::<String>::new()); 223 assert!(info.parameters().is_empty());
188 assert_eq!(info.active_parameter, None); 224 assert_eq!(info.active_parameter, None);
189 } 225 }
190 226
@@ -206,7 +242,7 @@ fn bar() {
206}"#, 242}"#,
207 ); 243 );
208 244
209 assert_eq!(info.parameters, vec!["&self".to_string()]); 245 assert_eq!(info.parameters(), ["&self"]);
210 assert_eq!(info.active_parameter, None); 246 assert_eq!(info.active_parameter, None);
211 } 247 }
212 248
@@ -228,7 +264,7 @@ fn bar() {
228}"#, 264}"#,
229 ); 265 );
230 266
231 assert_eq!(info.parameters, vec!["&self".to_string(), "x".to_string()]); 267 assert_eq!(info.parameters(), ["&self", "x: i32"]);
232 assert_eq!(info.active_parameter, Some(1)); 268 assert_eq!(info.active_parameter, Some(1));
233 } 269 }
234 270
@@ -248,10 +284,10 @@ fn bar() {
248"#, 284"#,
249 ); 285 );
250 286
251 assert_eq!(info.parameters, vec!["j".to_string()]); 287 assert_eq!(info.parameters(), ["j: u32"]);
252 assert_eq!(info.active_parameter, Some(0)); 288 assert_eq!(info.active_parameter, Some(0));
253 assert_eq!(info.label, "fn foo(j: u32) -> u32".to_string()); 289 assert_eq!(info.label(), "fn foo(j: u32) -> u32");
254 assert_eq!(info.doc.map(|it| it.into()), Some("test".to_string())); 290 assert_eq!(info.doc().map(|it| it.into()), Some("test".to_string()));
255 } 291 }
256 292
257 #[test] 293 #[test]
@@ -276,11 +312,11 @@ pub fn do() {
276}"#, 312}"#,
277 ); 313 );
278 314
279 assert_eq!(info.parameters, vec!["x".to_string()]); 315 assert_eq!(info.parameters(), ["x: i32"]);
280 assert_eq!(info.active_parameter, Some(0)); 316 assert_eq!(info.active_parameter, Some(0));
281 assert_eq!(info.label, "pub fn add_one(x: i32) -> i32".to_string()); 317 assert_eq!(info.label(), "pub fn add_one(x: i32) -> i32");
282 assert_eq!( 318 assert_eq!(
283 info.doc.map(|it| it.into()), 319 info.doc().map(|it| it.into()),
284 Some( 320 Some(
285 r#"Adds one to the number given. 321 r#"Adds one to the number given.
286 322
@@ -322,11 +358,11 @@ pub fn do_it() {
322}"#, 358}"#,
323 ); 359 );
324 360
325 assert_eq!(info.parameters, vec!["x".to_string()]); 361 assert_eq!(info.parameters(), ["x: i32"]);
326 assert_eq!(info.active_parameter, Some(0)); 362 assert_eq!(info.active_parameter, Some(0));
327 assert_eq!(info.label, "pub fn add_one(x: i32) -> i32".to_string()); 363 assert_eq!(info.label(), "pub fn add_one(x: i32) -> i32");
328 assert_eq!( 364 assert_eq!(
329 info.doc.map(|it| it.into()), 365 info.doc().map(|it| it.into()),
330 Some( 366 Some(
331 r#"Adds one to the number given. 367 r#"Adds one to the number given.
332 368
@@ -375,10 +411,10 @@ pub fn foo() {
375"#, 411"#,
376 ); 412 );
377 413
378 assert_eq!(info.parameters, vec!["&mut self".to_string(), "ctx".to_string()]); 414 assert_eq!(info.parameters(), ["&mut self", "ctx: &mut Self::Context"]);
379 assert_eq!(info.active_parameter, Some(1)); 415 assert_eq!(info.active_parameter, Some(1));
380 assert_eq!( 416 assert_eq!(
381 info.doc.map(|it| it.into()), 417 info.doc().map(|it| it.into()),
382 Some( 418 Some(
383 r#"Method is called when writer finishes. 419 r#"Method is called when writer finishes.
384 420