aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api
diff options
context:
space:
mode:
authorVille Penttinen <[email protected]>2019-03-12 07:24:46 +0000
committerVille Penttinen <[email protected]>2019-04-09 12:45:04 +0100
commit0e49abb7fbe9239b97f0b7168ec359014c63f8c0 (patch)
treeb76168a2cf9f09336e446dcc584879a918681055 /crates/ra_ide_api
parent5f700179fc7ed16d2848a6dbc7cf23da3b8df6c7 (diff)
Refactor CallInfo function signatures to new FunctionSignature type
This is used by CallInfo to create a pretty printed function signature that can be used with completions and other places as well.
Diffstat (limited to 'crates/ra_ide_api')
-rw-r--r--crates/ra_ide_api/src/call_info.rs85
-rw-r--r--crates/ra_ide_api/src/completion.rs61
-rw-r--r--crates/ra_ide_api/src/completion/complete_scope.rs2
-rw-r--r--crates/ra_ide_api/src/display.rs51
-rw-r--r--crates/ra_ide_api/src/lib.rs29
5 files changed, 177 insertions, 51 deletions
diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs
index 29fa7d30b..a65119315 100644
--- a/crates/ra_ide_api/src/call_info.rs
+++ b/crates/ra_ide_api/src/call_info.rs
@@ -30,7 +30,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
30 let mut call_info = CallInfo::new(db, function, fn_def)?; 30 let mut call_info = CallInfo::new(db, function, fn_def)?;
31 31
32 // If we have a calling expression let's find which argument we are on 32 // If we have a calling expression let's find which argument we are on
33 let num_params = call_info.parameters.len(); 33 let num_params = call_info.parameters().len();
34 let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some(); 34 let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some();
35 35
36 if num_params == 1 { 36 if num_params == 1 {
@@ -108,27 +108,26 @@ impl<'a> FnCallNode<'a> {
108 108
109impl CallInfo { 109impl CallInfo {
110 fn new(db: &RootDatabase, function: hir::Function, node: &ast::FnDef) -> Option<Self> { 110 fn new(db: &RootDatabase, function: hir::Function, node: &ast::FnDef) -> Option<Self> {
111 let label = crate::completion::function_label(node)?; 111 let sig = crate::completion::function_signature(node)?;
112 let doc = function.docs(db); 112 let doc = function.docs(db);
113 let sig = sig.with_doc_opt(doc);
113 114
114 Some(CallInfo { parameters: param_list(node), label, doc, active_parameter: None }) 115 Some(CallInfo { signature: sig, active_parameter: None })
115 } 116 }
116}
117 117
118fn param_list(node: &ast::FnDef) -> Vec<String> { 118 fn parameters(&self) -> &[String] {
119 let mut res = vec![]; 119 &self.signature.parameters
120 if let Some(param_list) = node.param_list() { 120 }
121 if let Some(self_param) = param_list.self_param() {
122 res.push(self_param.syntax().text().to_string())
123 }
124 121
125 // Maybe use param.pat here? See if we can just extract the name? 122 #[cfg(test)]
126 //res.extend(param_list.params().map(|p| p.syntax().text().to_string())); 123 fn doc(&self) -> Option<&hir::Documentation> {
127 res.extend( 124 self.signature.doc.as_ref()
128 param_list.params().filter_map(|p| p.pat()).map(|pat| pat.syntax().text().to_string()), 125 }
129 ); 126
127 #[cfg(test)]
128 fn label(&self) -> String {
129 self.signature.to_string()
130 } 130 }
131 res
132} 131}
133 132
134#[cfg(test)] 133#[cfg(test)]
@@ -151,7 +150,7 @@ mod tests {
151fn bar() { foo(<|>3, ); }"#, 150fn bar() { foo(<|>3, ); }"#,
152 ); 151 );
153 152
154 assert_eq!(info.parameters, vec!("x".to_string(), "y".to_string())); 153 assert_eq!(info.parameters(), ["x: u32", "y: u32"]);
155 assert_eq!(info.active_parameter, Some(0)); 154 assert_eq!(info.active_parameter, Some(0));
156 } 155 }
157 156
@@ -162,7 +161,7 @@ fn bar() { foo(<|>3, ); }"#,
162fn bar() { foo(3, <|>); }"#, 161fn bar() { foo(3, <|>); }"#,
163 ); 162 );
164 163
165 assert_eq!(info.parameters, vec!("x".to_string(), "y".to_string())); 164 assert_eq!(info.parameters(), ["x: u32", "y: u32"]);
166 assert_eq!(info.active_parameter, Some(1)); 165 assert_eq!(info.active_parameter, Some(1));
167 } 166 }
168 167
@@ -173,7 +172,27 @@ fn bar() { foo(3, <|>); }"#,
173fn bar() { foo(<|>); }"#, 172fn bar() { foo(<|>); }"#,
174 ); 173 );
175 174
176 assert_eq!(info.parameters, vec!("x".to_string(), "y".to_string())); 175 assert_eq!(info.parameters(), ["x: u32", "y: u32"]);
176 assert_eq!(info.active_parameter, Some(0));
177 }
178
179 #[test]
180 fn test_fn_signature_two_args_first_generics() {
181 let info = call_info(
182 r#"fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 where T: Copy + Display, U: Debug {x + y}
183fn bar() { foo(<|>3, ); }"#,
184 );
185
186 assert_eq!(info.parameters(), ["x: T", "y: U"]);
187 assert_eq!(
188 info.label(),
189 r#"
190fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
191where T: Copy + Display,
192 U: Debug
193 "#
194 .trim()
195 );
177 assert_eq!(info.active_parameter, Some(0)); 196 assert_eq!(info.active_parameter, Some(0));
178 } 197 }
179 198
@@ -184,7 +203,7 @@ fn bar() { foo(<|>); }"#,
184fn bar() {let _ : F = F::new(<|>);}"#, 203fn bar() {let _ : F = F::new(<|>);}"#,
185 ); 204 );
186 205
187 assert_eq!(info.parameters, Vec::<String>::new()); 206 assert!(info.parameters().is_empty());
188 assert_eq!(info.active_parameter, None); 207 assert_eq!(info.active_parameter, None);
189 } 208 }
190 209
@@ -206,7 +225,7 @@ fn bar() {
206}"#, 225}"#,
207 ); 226 );
208 227
209 assert_eq!(info.parameters, vec!["&self".to_string()]); 228 assert_eq!(info.parameters(), ["&self"]);
210 assert_eq!(info.active_parameter, None); 229 assert_eq!(info.active_parameter, None);
211 } 230 }
212 231
@@ -228,7 +247,7 @@ fn bar() {
228}"#, 247}"#,
229 ); 248 );
230 249
231 assert_eq!(info.parameters, vec!["&self".to_string(), "x".to_string()]); 250 assert_eq!(info.parameters(), ["&self", "x: i32"]);
232 assert_eq!(info.active_parameter, Some(1)); 251 assert_eq!(info.active_parameter, Some(1));
233 } 252 }
234 253
@@ -248,10 +267,10 @@ fn bar() {
248"#, 267"#,
249 ); 268 );
250 269
251 assert_eq!(info.parameters, vec!["j".to_string()]); 270 assert_eq!(info.parameters(), ["j: u32"]);
252 assert_eq!(info.active_parameter, Some(0)); 271 assert_eq!(info.active_parameter, Some(0));
253 assert_eq!(info.label, "fn foo(j: u32) -> u32".to_string()); 272 assert_eq!(info.label(), "fn foo(j: u32) -> u32");
254 assert_eq!(info.doc.map(|it| it.into()), Some("test".to_string())); 273 assert_eq!(info.doc().map(|it| it.into()), Some("test".to_string()));
255 } 274 }
256 275
257 #[test] 276 #[test]
@@ -276,11 +295,11 @@ pub fn do() {
276}"#, 295}"#,
277 ); 296 );
278 297
279 assert_eq!(info.parameters, vec!["x".to_string()]); 298 assert_eq!(info.parameters(), ["x: i32"]);
280 assert_eq!(info.active_parameter, Some(0)); 299 assert_eq!(info.active_parameter, Some(0));
281 assert_eq!(info.label, "pub fn add_one(x: i32) -> i32".to_string()); 300 assert_eq!(info.label(), "pub fn add_one(x: i32) -> i32");
282 assert_eq!( 301 assert_eq!(
283 info.doc.map(|it| it.into()), 302 info.doc().map(|it| it.into()),
284 Some( 303 Some(
285 r#"Adds one to the number given. 304 r#"Adds one to the number given.
286 305
@@ -322,11 +341,11 @@ pub fn do_it() {
322}"#, 341}"#,
323 ); 342 );
324 343
325 assert_eq!(info.parameters, vec!["x".to_string()]); 344 assert_eq!(info.parameters(), ["x: i32"]);
326 assert_eq!(info.active_parameter, Some(0)); 345 assert_eq!(info.active_parameter, Some(0));
327 assert_eq!(info.label, "pub fn add_one(x: i32) -> i32".to_string()); 346 assert_eq!(info.label(), "pub fn add_one(x: i32) -> i32");
328 assert_eq!( 347 assert_eq!(
329 info.doc.map(|it| it.into()), 348 info.doc().map(|it| it.into()),
330 Some( 349 Some(
331 r#"Adds one to the number given. 350 r#"Adds one to the number given.
332 351
@@ -375,10 +394,10 @@ pub fn foo() {
375"#, 394"#,
376 ); 395 );
377 396
378 assert_eq!(info.parameters, vec!["&mut self".to_string(), "ctx".to_string()]); 397 assert_eq!(info.parameters(), ["&mut self", "ctx: &mut Self::Context"]);
379 assert_eq!(info.active_parameter, Some(1)); 398 assert_eq!(info.active_parameter, Some(1));
380 assert_eq!( 399 assert_eq!(
381 info.doc.map(|it| it.into()), 400 info.doc().map(|it| it.into()),
382 Some( 401 Some(
383 r#"Method is called when writer finishes. 402 r#"Method is called when writer finishes.
384 403
diff --git a/crates/ra_ide_api/src/completion.rs b/crates/ra_ide_api/src/completion.rs
index a846a7a3c..d8e4410b2 100644
--- a/crates/ra_ide_api/src/completion.rs
+++ b/crates/ra_ide_api/src/completion.rs
@@ -13,11 +13,12 @@ mod complete_scope;
13mod complete_postfix; 13mod complete_postfix;
14 14
15use ra_db::SourceDatabase; 15use ra_db::SourceDatabase;
16use ra_syntax::{ast::{self, AstNode}, SyntaxKind::{ATTR, COMMENT}}; 16use ra_syntax::{ast::{self, AstNode, NameOwner, VisibilityOwner, TypeParamsOwner}, SyntaxKind::{ATTR, COMMENT}};
17 17
18use crate::{ 18use crate::{
19 db, 19 db,
20 FilePosition, 20 FilePosition,
21 FunctionSignature,
21 completion::{ 22 completion::{
22 completion_item::{Completions, CompletionKind}, 23 completion_item::{Completions, CompletionKind},
23 completion_context::CompletionContext, 24 completion_context::CompletionContext,
@@ -71,22 +72,52 @@ pub(crate) fn completions(db: &db::RootDatabase, position: FilePosition) -> Opti
71 Some(acc) 72 Some(acc)
72} 73}
73 74
74pub fn function_label(node: &ast::FnDef) -> Option<String> { 75pub fn generic_parameters<N: TypeParamsOwner>(node: &N) -> Vec<String> {
75 let label: String = if let Some(body) = node.body() { 76 let mut res = vec![];
76 let body_range = body.syntax().range(); 77 if let Some(type_params) = node.type_param_list() {
77 let label: String = node 78 res.extend(type_params.lifetime_params().map(|p| p.syntax().text().to_string()));
78 .syntax() 79 res.extend(type_params.type_params().map(|p| p.syntax().text().to_string()));
79 .children_with_tokens() 80 }
80 .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body 81 res
81 .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR)) // Filter out comments and attrs 82}
82 .map(|node| node.to_string()) 83
83 .collect(); 84pub fn where_predicates<N: TypeParamsOwner>(node: &N) -> Vec<String> {
84 label 85 let mut res = vec![];
85 } else { 86 if let Some(clause) = node.where_clause() {
86 node.syntax().text().to_string() 87 res.extend(clause.predicates().map(|p| p.syntax().text().to_string()));
88 }
89 res
90}
91
92pub fn function_signature(node: &ast::FnDef) -> Option<FunctionSignature> {
93 fn param_list(node: &ast::FnDef) -> Vec<String> {
94 let mut res = vec![];
95 if let Some(param_list) = node.param_list() {
96 if let Some(self_param) = param_list.self_param() {
97 res.push(self_param.syntax().text().to_string())
98 }
99
100 res.extend(param_list.params().map(|param| param.syntax().text().to_string()));
101 }
102 res
103 }
104
105 let sig = FunctionSignature {
106 visibility: node.visibility().map(|n| n.syntax().text().to_string()),
107 name: node.name().map(|n| n.text().to_string()),
108 ret_type: node.ret_type().and_then(|r| r.type_ref()).map(|n| n.syntax().text().to_string()),
109 parameters: param_list(node),
110 generic_parameters: generic_parameters(node),
111 where_predicates: where_predicates(node),
112 // docs are processed separately
113 doc: None,
87 }; 114 };
88 115
89 Some(label.trim().to_owned()) 116 Some(sig)
117}
118
119pub fn function_label(node: &ast::FnDef) -> Option<String> {
120 function_signature(node).map(|n| n.to_string())
90} 121}
91 122
92pub fn const_label(node: &ast::ConstDef) -> String { 123pub fn const_label(node: &ast::ConstDef) -> String {
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs
index 6146b7bb6..9d82f2270 100644
--- a/crates/ra_ide_api/src/completion/complete_scope.rs
+++ b/crates/ra_ide_api/src/completion/complete_scope.rs
@@ -145,7 +145,7 @@ mod tests {
145 check_reference_completion( 145 check_reference_completion(
146 "dont_show_both_completions_for_shadowing", 146 "dont_show_both_completions_for_shadowing",
147 r" 147 r"
148 fn foo() -> { 148 fn foo() {
149 let bar = 92; 149 let bar = 92;
150 { 150 {
151 let bar = 62; 151 let bar = 62;
diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs
new file mode 100644
index 000000000..60fa72f1b
--- /dev/null
+++ b/crates/ra_ide_api/src/display.rs
@@ -0,0 +1,51 @@
1use super::*;
2use std::fmt::{self, Display};
3
4impl Display for FunctionSignature {
5 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6 if let Some(t) = &self.visibility {
7 write!(f, "{} ", t)?;
8 }
9
10 if let Some(name) = &self.name {
11 write!(f, "fn {}", name)?;
12 }
13
14 if !self.generic_parameters.is_empty() {
15 write!(f, "<")?;
16 write_joined(f, &self.generic_parameters, ", ")?;
17 write!(f, ">")?;
18 }
19
20 write!(f, "(")?;
21 write_joined(f, &self.parameters, ", ")?;
22 write!(f, ")")?;
23
24 if let Some(t) = &self.ret_type {
25 write!(f, " -> {}", t)?;
26 }
27
28 if !self.where_predicates.is_empty() {
29 write!(f, "\nwhere ")?;
30 write_joined(f, &self.where_predicates, ",\n ")?;
31 }
32
33 Ok(())
34 }
35}
36
37fn write_joined<T: Display>(
38 f: &mut fmt::Formatter,
39 items: impl IntoIterator<Item = T>,
40 sep: &str,
41) -> fmt::Result {
42 let mut first = true;
43 for e in items {
44 if !first {
45 write!(f, "{}", sep)?;
46 }
47 first = false;
48 write!(f, "{}", e)?;
49 }
50 Ok(())
51}
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index 9063f78a9..7f8f454bc 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -37,6 +37,7 @@ mod join_lines;
37mod structure; 37mod structure;
38mod typing; 38mod typing;
39mod matching_brace; 39mod matching_brace;
40mod display;
40 41
41#[cfg(test)] 42#[cfg(test)]
42mod marks; 43mod marks;
@@ -243,10 +244,34 @@ impl<T> RangeInfo<T> {
243 244
244#[derive(Debug)] 245#[derive(Debug)]
245pub struct CallInfo { 246pub struct CallInfo {
246 pub label: String, 247 pub signature: FunctionSignature,
248 pub active_parameter: Option<usize>,
249}
250
251/// Contains information about a function signature
252#[derive(Debug)]
253pub struct FunctionSignature {
254 /// Optional visibility
255 pub visibility: Option<String>,
256 /// Name of the function
257 pub name: Option<String>,
258 /// Documentation for the function
247 pub doc: Option<Documentation>, 259 pub doc: Option<Documentation>,
260 /// Generic parameters
261 pub generic_parameters: Vec<String>,
262 /// Parameters of the function
248 pub parameters: Vec<String>, 263 pub parameters: Vec<String>,
249 pub active_parameter: Option<usize>, 264 /// Optional return type
265 pub ret_type: Option<String>,
266 /// Where predicates
267 pub where_predicates: Vec<String>,
268}
269
270impl FunctionSignature {
271 pub(crate) fn with_doc_opt(mut self, doc: Option<Documentation>) -> Self {
272 self.doc = doc;
273 self
274 }
250} 275}
251 276
252/// `AnalysisHost` stores the current state of the world. 277/// `AnalysisHost` stores the current state of the world.