aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-07-16 17:50:37 +0100
committerGitHub <[email protected]>2020-07-16 17:50:37 +0100
commit081596dd584ac39fbfa6a7e47dfe9dd4a58c362a (patch)
treeb6d564a63068530ef3aabb8855699bf20c45a608 /crates/ra_ide
parent9210fcc076808e53e9bde84be26307fc0dc7d688 (diff)
parente1e79cf0648624e7a3787d0013c0c7e86210772f (diff)
Merge #5413
5413: Semantical call info r=matklad a=matklad Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_ide')
-rw-r--r--crates/ra_ide/src/call_hierarchy.rs10
-rw-r--r--crates/ra_ide/src/call_info.rs361
-rw-r--r--crates/ra_ide/src/completion/complete_trait_impl.rs2
-rw-r--r--crates/ra_ide/src/completion/presentation.rs9
-rw-r--r--crates/ra_ide/src/display.rs11
-rw-r--r--crates/ra_ide/src/display/function_signature.rs61
-rw-r--r--crates/ra_ide/src/file_structure.rs (renamed from crates/ra_ide/src/display/structure.rs)0
-rw-r--r--crates/ra_ide/src/inlay_hints.rs14
-rw-r--r--crates/ra_ide/src/lib.rs37
9 files changed, 249 insertions, 256 deletions
diff --git a/crates/ra_ide/src/call_hierarchy.rs b/crates/ra_ide/src/call_hierarchy.rs
index cb7e62cd6..6af251d23 100644
--- a/crates/ra_ide/src/call_hierarchy.rs
+++ b/crates/ra_ide/src/call_hierarchy.rs
@@ -95,9 +95,9 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
95 if let Some(func_target) = match &call_node { 95 if let Some(func_target) = match &call_node {
96 FnCallNode::CallExpr(expr) => { 96 FnCallNode::CallExpr(expr) => {
97 //FIXME: Type::as_callable is broken 97 //FIXME: Type::as_callable is broken
98 let callable_def = sema.type_of_expr(&expr.expr()?)?.as_callable()?; 98 let callable = sema.type_of_expr(&expr.expr()?)?.as_callable(db)?;
99 match callable_def { 99 match callable.kind() {
100 hir::CallableDefId::FunctionId(it) => { 100 hir::CallableKind::Function(it) => {
101 let fn_def: hir::Function = it.into(); 101 let fn_def: hir::Function = it.into();
102 let nav = fn_def.to_nav(db); 102 let nav = fn_def.to_nav(db);
103 Some(nav) 103 Some(nav)
@@ -109,10 +109,6 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
109 let function = sema.resolve_method_call(&expr)?; 109 let function = sema.resolve_method_call(&expr)?;
110 Some(function.to_nav(db)) 110 Some(function.to_nav(db))
111 } 111 }
112 FnCallNode::MacroCallExpr(macro_call) => {
113 let macro_def = sema.resolve_macro_call(&macro_call)?;
114 Some(macro_def.to_nav(db))
115 }
116 } { 112 } {
117 Some((func_target, name_ref.syntax().text_range())) 113 Some((func_target, name_ref.syntax().text_range()))
118 } else { 114 } else {
diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs
index 1fe1c21de..35a8a0dc5 100644
--- a/crates/ra_ide/src/call_info.rs
+++ b/crates/ra_ide/src/call_info.rs
@@ -1,20 +1,42 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2use hir::Semantics; 2use either::Either;
3use hir::{Docs, HirDisplay, Semantics, Type};
3use ra_ide_db::RootDatabase; 4use ra_ide_db::RootDatabase;
4use ra_syntax::{ 5use ra_syntax::{
5 ast::{self, ArgListOwner}, 6 ast::{self, ArgListOwner},
6 match_ast, AstNode, SyntaxNode, SyntaxToken, 7 match_ast, AstNode, SyntaxNode, SyntaxToken, TextRange, TextSize,
7}; 8};
9use stdx::format_to;
8use test_utils::mark; 10use test_utils::mark;
9 11
10use crate::{FilePosition, FunctionSignature}; 12use crate::FilePosition;
11 13
12/// Contains information about a call site. Specifically the 14/// Contains information about a call site. Specifically the
13/// `FunctionSignature`and current parameter. 15/// `FunctionSignature`and current parameter.
14#[derive(Debug)] 16#[derive(Debug)]
15pub struct CallInfo { 17pub struct CallInfo {
16 pub signature: FunctionSignature, 18 pub doc: Option<String>,
19 pub signature: String,
17 pub active_parameter: Option<usize>, 20 pub active_parameter: Option<usize>,
21 parameters: Vec<TextRange>,
22}
23
24impl CallInfo {
25 pub fn parameter_labels(&self) -> impl Iterator<Item = &str> + '_ {
26 self.parameters.iter().map(move |&it| &self.signature[it])
27 }
28 pub fn parameter_ranges(&self) -> &[TextRange] {
29 &self.parameters
30 }
31 fn push_param(&mut self, param: &str) {
32 if !self.signature.ends_with('(') {
33 self.signature.push_str(", ");
34 }
35 let start = TextSize::of(&self.signature);
36 self.signature.push_str(param);
37 let end = TextSize::of(&self.signature);
38 self.parameters.push(TextRange::new(start, end))
39 }
18} 40}
19 41
20/// Computes parameter information for the given call expression. 42/// Computes parameter information for the given call expression.
@@ -24,105 +46,130 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
24 let file = file.syntax(); 46 let file = file.syntax();
25 let token = file.token_at_offset(position.offset).next()?; 47 let token = file.token_at_offset(position.offset).next()?;
26 let token = sema.descend_into_macros(token); 48 let token = sema.descend_into_macros(token);
27 call_info_for_token(&sema, token)
28}
29 49
30#[derive(Debug)] 50 let (callable, active_parameter) = call_info_impl(&sema, token)?;
31pub(crate) struct ActiveParameter {
32 /// FIXME: should be `Type` and `Name
33 pub(crate) ty: String,
34 pub(crate) name: String,
35}
36 51
37impl ActiveParameter { 52 let mut res =
38 pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> { 53 CallInfo { doc: None, signature: String::new(), parameters: vec![], active_parameter };
39 call_info(db, position)?.into_active_parameter() 54
55 match callable.kind() {
56 hir::CallableKind::Function(func) => {
57 res.doc = func.docs(db).map(|it| it.as_str().to_string());
58 format_to!(res.signature, "fn {}", func.name(db));
59 }
60 hir::CallableKind::TupleStruct(strukt) => {
61 res.doc = strukt.docs(db).map(|it| it.as_str().to_string());
62 format_to!(res.signature, "struct {}", strukt.name(db));
63 }
64 hir::CallableKind::TupleEnumVariant(variant) => {
65 res.doc = variant.docs(db).map(|it| it.as_str().to_string());
66 format_to!(
67 res.signature,
68 "enum {}::{}",
69 variant.parent_enum(db).name(db),
70 variant.name(db)
71 );
72 }
40 } 73 }
41 74
42 pub(crate) fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> { 75 res.signature.push('(');
43 call_info_for_token(sema, token)?.into_active_parameter() 76 {
77 if let Some(self_param) = callable.receiver_param(db) {
78 format_to!(res.signature, "{}", self_param)
79 }
80 let mut buf = String::new();
81 for (pat, ty) in callable.params(db) {
82 buf.clear();
83 if let Some(pat) = pat {
84 match pat {
85 Either::Left(_self) => format_to!(buf, "self: "),
86 Either::Right(pat) => format_to!(buf, "{}: ", pat),
87 }
88 }
89 format_to!(buf, "{}", ty.display(db));
90 res.push_param(&buf);
91 }
44 } 92 }
93 res.signature.push(')');
94
95 match callable.kind() {
96 hir::CallableKind::Function(_) => {
97 let ret_type = callable.return_type();
98 if !ret_type.is_unit() {
99 format_to!(res.signature, " -> {}", ret_type.display(db));
100 }
101 }
102 hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}
103 }
104 Some(res)
45} 105}
46 106
47fn call_info_for_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<CallInfo> { 107fn call_info_impl(
108 sema: &Semantics<RootDatabase>,
109 token: SyntaxToken,
110) -> Option<(hir::Callable, Option<usize>)> {
48 // Find the calling expression and it's NameRef 111 // Find the calling expression and it's NameRef
49 let calling_node = FnCallNode::with_node(&token.parent())?; 112 let calling_node = FnCallNode::with_node(&token.parent())?;
50 113
51 let signature = match &calling_node { 114 let callable = match &calling_node {
52 FnCallNode::CallExpr(call) => { 115 FnCallNode::CallExpr(call) => sema.type_of_expr(&call.expr()?)?.as_callable(sema.db)?,
53 //FIXME: Type::as_callable is broken 116 FnCallNode::MethodCallExpr(call) => sema.resolve_method_call_as_callable(call)?,
54 let callable_def = sema.type_of_expr(&call.expr()?)?.as_callable()?; 117 };
55 match callable_def { 118 let active_param = if let Some(arg_list) = calling_node.arg_list() {
56 hir::CallableDefId::FunctionId(it) => { 119 // Number of arguments specified at the call site
57 let fn_def = it.into(); 120 let num_args_at_callsite = arg_list.args().count();
58 FunctionSignature::from_hir(sema.db, fn_def) 121
59 } 122 let arg_list_range = arg_list.syntax().text_range();
60 hir::CallableDefId::StructId(it) => { 123 if !arg_list_range.contains_inclusive(token.text_range().start()) {
61 FunctionSignature::from_struct(sema.db, it.into())? 124 mark::hit!(call_info_bad_offset);
62 } 125 return None;
63 hir::CallableDefId::EnumVariantId(it) => {
64 FunctionSignature::from_enum_variant(sema.db, it.into())?
65 }
66 }
67 }
68 FnCallNode::MethodCallExpr(method_call) => {
69 let function = sema.resolve_method_call(&method_call)?;
70 FunctionSignature::from_hir(sema.db, function)
71 }
72 FnCallNode::MacroCallExpr(macro_call) => {
73 let macro_def = sema.resolve_macro_call(&macro_call)?;
74 FunctionSignature::from_macro(sema.db, macro_def)?
75 } 126 }
127 let param = std::cmp::min(
128 num_args_at_callsite,
129 arg_list
130 .args()
131 .take_while(|arg| arg.syntax().text_range().end() <= token.text_range().start())
132 .count(),
133 );
134
135 Some(param)
136 } else {
137 None
76 }; 138 };
139 Some((callable, active_param))
140}
77 141
78 // If we have a calling expression let's find which argument we are on 142#[derive(Debug)]
79 let num_params = signature.parameters.len(); 143pub(crate) struct ActiveParameter {
80 144 pub(crate) ty: Type,
81 let active_parameter = match num_params { 145 pub(crate) name: String,
82 0 => None, 146}
83 1 if signature.has_self_param => None,
84 1 => Some(0),
85 _ => {
86 if let Some(arg_list) = calling_node.arg_list() {
87 // Number of arguments specified at the call site
88 let num_args_at_callsite = arg_list.args().count();
89
90 let arg_list_range = arg_list.syntax().text_range();
91 if !arg_list_range.contains_inclusive(token.text_range().start()) {
92 mark::hit!(call_info_bad_offset);
93 return None;
94 }
95 147
96 let mut param = std::cmp::min( 148impl ActiveParameter {
97 num_args_at_callsite, 149 pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> {
98 arg_list 150 let sema = Semantics::new(db);
99 .args() 151 let file = sema.parse(position.file_id);
100 .take_while(|arg| { 152 let file = file.syntax();
101 arg.syntax().text_range().end() <= token.text_range().start() 153 let token = file.token_at_offset(position.offset).next()?;
102 }) 154 let token = sema.descend_into_macros(token);
103 .count(), 155 Self::at_token(&sema, token)
104 ); 156 }
105
106 // If we are in a method account for `self`
107 if signature.has_self_param {
108 param += 1;
109 }
110 157
111 Some(param) 158 pub(crate) fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> {
112 } else { 159 let (signature, active_parameter) = call_info_impl(&sema, token)?;
113 None
114 }
115 }
116 };
117 160
118 Some(CallInfo { signature, active_parameter }) 161 let idx = active_parameter?;
162 let mut params = signature.params(sema.db);
163 let (pat, ty) = params.swap_remove(idx);
164 let name = pat?.to_string();
165 Some(ActiveParameter { ty, name })
166 }
119} 167}
120 168
121#[derive(Debug)] 169#[derive(Debug)]
122pub(crate) enum FnCallNode { 170pub(crate) enum FnCallNode {
123 CallExpr(ast::CallExpr), 171 CallExpr(ast::CallExpr),
124 MethodCallExpr(ast::MethodCallExpr), 172 MethodCallExpr(ast::MethodCallExpr),
125 MacroCallExpr(ast::MacroCall),
126} 173}
127 174
128impl FnCallNode { 175impl FnCallNode {
@@ -138,7 +185,6 @@ impl FnCallNode {
138 } 185 }
139 Some(FnCallNode::MethodCallExpr(it)) 186 Some(FnCallNode::MethodCallExpr(it))
140 }, 187 },
141 ast::MacroCall(it) => Some(FnCallNode::MacroCallExpr(it)),
142 _ => None, 188 _ => None,
143 } 189 }
144 } 190 }
@@ -150,7 +196,6 @@ impl FnCallNode {
150 match node { 196 match node {
151 ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)), 197 ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)),
152 ast::MethodCallExpr(it) => Some(FnCallNode::MethodCallExpr(it)), 198 ast::MethodCallExpr(it) => Some(FnCallNode::MethodCallExpr(it)),
153 ast::MacroCall(it) => Some(FnCallNode::MacroCallExpr(it)),
154 _ => None, 199 _ => None,
155 } 200 }
156 } 201 }
@@ -166,8 +211,6 @@ impl FnCallNode {
166 FnCallNode::MethodCallExpr(call_expr) => { 211 FnCallNode::MethodCallExpr(call_expr) => {
167 call_expr.syntax().children().filter_map(ast::NameRef::cast).next() 212 call_expr.syntax().children().filter_map(ast::NameRef::cast).next()
168 } 213 }
169
170 FnCallNode::MacroCallExpr(call_expr) => call_expr.path()?.segment()?.name_ref(),
171 } 214 }
172 } 215 }
173 216
@@ -175,21 +218,10 @@ impl FnCallNode {
175 match self { 218 match self {
176 FnCallNode::CallExpr(expr) => expr.arg_list(), 219 FnCallNode::CallExpr(expr) => expr.arg_list(),
177 FnCallNode::MethodCallExpr(expr) => expr.arg_list(), 220 FnCallNode::MethodCallExpr(expr) => expr.arg_list(),
178 FnCallNode::MacroCallExpr(_) => None,
179 } 221 }
180 } 222 }
181} 223}
182 224
183impl CallInfo {
184 fn into_active_parameter(self) -> Option<ActiveParameter> {
185 let idx = self.active_parameter?;
186 let ty = self.signature.parameter_types.get(idx)?.clone();
187 let name = self.signature.parameter_names.get(idx)?.clone();
188 let res = ActiveParameter { ty, name };
189 Some(res)
190 }
191}
192
193#[cfg(test)] 225#[cfg(test)]
194mod tests { 226mod tests {
195 use expect::{expect, Expect}; 227 use expect::{expect, Expect};
@@ -202,20 +234,18 @@ mod tests {
202 let call_info = analysis.call_info(position).unwrap(); 234 let call_info = analysis.call_info(position).unwrap();
203 let actual = match call_info { 235 let actual = match call_info {
204 Some(call_info) => { 236 Some(call_info) => {
205 let docs = match &call_info.signature.doc { 237 let docs = match &call_info.doc {
206 None => "".to_string(), 238 None => "".to_string(),
207 Some(docs) => format!("{}\n------\n", docs.as_str()), 239 Some(docs) => format!("{}\n------\n", docs.as_str()),
208 }; 240 };
209 let params = call_info 241 let params = call_info
210 .signature 242 .parameter_labels()
211 .parameters
212 .iter()
213 .enumerate() 243 .enumerate()
214 .map(|(i, param)| { 244 .map(|(i, param)| {
215 if Some(i) == call_info.active_parameter { 245 if Some(i) == call_info.active_parameter {
216 format!("<{}>", param) 246 format!("<{}>", param)
217 } else { 247 } else {
218 param.clone() 248 param.to_string()
219 } 249 }
220 }) 250 })
221 .collect::<Vec<_>>() 251 .collect::<Vec<_>>()
@@ -296,10 +326,8 @@ fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
296fn bar() { foo(<|>3, ); } 326fn bar() { foo(<|>3, ); }
297"#, 327"#,
298 expect![[r#" 328 expect![[r#"
299 fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 329 fn foo(x: i32, y: {unknown}) -> u32
300 where T: Copy + Display, 330 (<x: i32>, y: {unknown})
301 U: Debug
302 (<x: T>, y: U)
303 "#]], 331 "#]],
304 ); 332 );
305 } 333 }
@@ -312,8 +340,7 @@ fn foo<T>() -> T where T: Copy + Display {}
312fn bar() { foo(<|>); } 340fn bar() { foo(<|>); }
313"#, 341"#,
314 expect![[r#" 342 expect![[r#"
315 fn foo<T>() -> T 343 fn foo() -> {unknown}
316 where T: Copy + Display
317 () 344 ()
318 "#]], 345 "#]],
319 ); 346 );
@@ -323,11 +350,14 @@ fn bar() { foo(<|>); }
323 fn test_fn_signature_for_impl() { 350 fn test_fn_signature_for_impl() {
324 check( 351 check(
325 r#" 352 r#"
326struct F; impl F { pub fn new() { F{}} } 353struct F;
327fn bar() {let _ : F = F::new(<|>);} 354impl F { pub fn new() { } }
355fn bar() {
356 let _ : F = F::new(<|>);
357}
328"#, 358"#,
329 expect![[r#" 359 expect![[r#"
330 pub fn new() 360 fn new()
331 () 361 ()
332 "#]], 362 "#]],
333 ); 363 );
@@ -346,8 +376,8 @@ fn bar() {
346} 376}
347"#, 377"#,
348 expect![[r#" 378 expect![[r#"
349 pub fn do_it(&self) 379 fn do_it(&self)
350 (&self) 380 ()
351 "#]], 381 "#]],
352 ); 382 );
353 } 383 }
@@ -357,16 +387,33 @@ fn bar() {
357 check( 387 check(
358 r#" 388 r#"
359struct S; 389struct S;
360impl S { pub fn do_it(&self, x: i32) {} } 390impl S {
391 fn foo(&self, x: i32) {}
392}
361 393
362fn bar() { 394fn main() { S.foo(<|>); }
363 let s: S = S; 395"#,
364 s.do_it(<|>); 396 expect![[r#"
397 fn foo(&self, x: i32)
398 (<x: i32>)
399 "#]],
400 );
401 }
402
403 #[test]
404 fn test_fn_signature_for_method_with_arg_as_assoc_fn() {
405 check(
406 r#"
407struct S;
408impl S {
409 fn foo(&self, x: i32) {}
365} 410}
411
412fn main() { S::foo(<|>); }
366"#, 413"#,
367 expect![[r#" 414 expect![[r#"
368 pub fn do_it(&self, x: i32) 415 fn foo(self: &S, x: i32)
369 (&self, <x: i32>) 416 (<self: &S>, x: i32)
370 "#]], 417 "#]],
371 ); 418 );
372 } 419 }
@@ -425,7 +472,7 @@ pub fn do() {
425 assert_eq!(6, my_crate::add_one(5)); 472 assert_eq!(6, my_crate::add_one(5));
426 ``` 473 ```
427 ------ 474 ------
428 pub fn add_one(x: i32) -> i32 475 fn add_one(x: i32) -> i32
429 (<x: i32>) 476 (<x: i32>)
430 "##]], 477 "##]],
431 ); 478 );
@@ -467,7 +514,7 @@ pub fn do_it() {
467 assert_eq!(6, my_crate::add_one(5)); 514 assert_eq!(6, my_crate::add_one(5));
468 ``` 515 ```
469 ------ 516 ------
470 pub fn add_one(x: i32) -> i32 517 fn add_one(x: i32) -> i32
471 (<x: i32>) 518 (<x: i32>)
472 "##]], 519 "##]],
473 ); 520 );
@@ -505,8 +552,8 @@ pub fn foo(mut r: WriteHandler<()>) {
505 552
506 By default this method stops actor's `Context`. 553 By default this method stops actor's `Context`.
507 ------ 554 ------
508 fn finished(&mut self, ctx: &mut Self::Context) 555 fn finished(&mut self, ctx: &mut {unknown})
509 (&mut self, <ctx: &mut Self::Context>) 556 (<ctx: &mut {unknown}>)
510 "#]], 557 "#]],
511 ); 558 );
512 } 559 }
@@ -539,7 +586,7 @@ fn main() {
539"#, 586"#,
540 expect![[r#" 587 expect![[r#"
541 fn bar(&self, _: u32) 588 fn bar(&self, _: u32)
542 (&self, <_: u32>) 589 (<_: u32>)
543 "#]], 590 "#]],
544 ); 591 );
545 } 592 }
@@ -549,15 +596,15 @@ fn main() {
549 check( 596 check(
550 r#" 597 r#"
551/// A cool tuple struct 598/// A cool tuple struct
552struct TS(u32, i32); 599struct S(u32, i32);
553fn main() { 600fn main() {
554 let s = TS(0, <|>); 601 let s = S(0, <|>);
555} 602}
556"#, 603"#,
557 expect![[r#" 604 expect![[r#"
558 A cool tuple struct 605 A cool tuple struct
559 ------ 606 ------
560 struct TS(u32, i32) -> TS 607 struct S(u32, i32)
561 (u32, <i32>) 608 (u32, <i32>)
562 "#]], 609 "#]],
563 ); 610 );
@@ -567,32 +614,19 @@ fn main() {
567 fn generic_struct() { 614 fn generic_struct() {
568 check( 615 check(
569 r#" 616 r#"
570struct TS<T>(T); 617struct S<T>(T);
571fn main() { 618fn main() {
572 let s = TS(<|>); 619 let s = S(<|>);
573} 620}
574"#, 621"#,
575 expect![[r#" 622 expect![[r#"
576 struct TS<T>(T) -> TS 623 struct S({unknown})
577 (<T>) 624 (<{unknown}>)
578 "#]], 625 "#]],
579 ); 626 );
580 } 627 }
581 628
582 #[test] 629 #[test]
583 fn cant_call_named_structs() {
584 check(
585 r#"
586struct TS { x: u32, y: i32 }
587fn main() {
588 let s = TS(<|>);
589}
590"#,
591 expect![[""]],
592 );
593 }
594
595 #[test]
596 fn works_for_enum_variants() { 630 fn works_for_enum_variants() {
597 check( 631 check(
598 r#" 632 r#"
@@ -612,27 +646,19 @@ fn main() {
612 expect![[r#" 646 expect![[r#"
613 A Variant 647 A Variant
614 ------ 648 ------
615 E::A(0: i32) 649 enum E::A(i32)
616 (<0: i32>) 650 (<i32>)
617 "#]], 651 "#]],
618 ); 652 );
619 } 653 }
620 654
621 #[test] 655 #[test]
622 fn cant_call_enum_records() { 656 fn cant_call_struct_record() {
623 check( 657 check(
624 r#" 658 r#"
625enum E { 659struct S { x: u32, y: i32 }
626 /// A Variant
627 A(i32),
628 /// Another
629 B,
630 /// And C
631 C { a: i32, b: i32 }
632}
633
634fn main() { 660fn main() {
635 let a = E::C(<|>); 661 let s = S(<|>);
636} 662}
637"#, 663"#,
638 expect![[""]], 664 expect![[""]],
@@ -640,24 +666,23 @@ fn main() {
640 } 666 }
641 667
642 #[test] 668 #[test]
643 fn fn_signature_for_macro() { 669 fn cant_call_enum_record() {
644 check( 670 check(
645 r#" 671 r#"
646/// empty macro 672enum E {
647macro_rules! foo { 673 /// A Variant
648 () => {} 674 A(i32),
675 /// Another
676 B,
677 /// And C
678 C { a: i32, b: i32 }
649} 679}
650 680
651fn f() { 681fn main() {
652 foo!(<|>); 682 let a = E::C(<|>);
653} 683}
654"#, 684"#,
655 expect![[r#" 685 expect![[""]],
656 empty macro
657 ------
658 foo!()
659 ()
660 "#]],
661 ); 686 );
662 } 687 }
663 688
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs
index a610fd6d1..90f5b1c25 100644
--- a/crates/ra_ide/src/completion/complete_trait_impl.rs
+++ b/crates/ra_ide/src/completion/complete_trait_impl.rs
@@ -43,7 +43,7 @@ use crate::{
43 completion::{ 43 completion::{
44 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, 44 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
45 }, 45 },
46 display::FunctionSignature, 46 display::function_signature::FunctionSignature,
47}; 47};
48 48
49pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { 49pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs
index 64349dcb8..e29b82017 100644
--- a/crates/ra_ide/src/completion/presentation.rs
+++ b/crates/ra_ide/src/completion/presentation.rs
@@ -11,7 +11,7 @@ use crate::{
11 completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind, 11 completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind,
12 CompletionKind, Completions, 12 CompletionKind, Completions,
13 }, 13 },
14 display::{const_label, macro_label, type_label, FunctionSignature}, 14 display::{const_label, function_signature::FunctionSignature, macro_label, type_label},
15 CompletionScore, RootDatabase, 15 CompletionScore, RootDatabase,
16}; 16};
17 17
@@ -329,15 +329,10 @@ pub(crate) fn compute_score(
329 ty: &Type, 329 ty: &Type,
330 name: &str, 330 name: &str,
331) -> Option<CompletionScore> { 331) -> Option<CompletionScore> {
332 // FIXME: this should not fall back to string equality.
333 let ty = &ty.display(ctx.db).to_string();
334 let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { 332 let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax {
335 mark::hit!(record_field_type_match); 333 mark::hit!(record_field_type_match);
336 let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?; 334 let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?;
337 ( 335 (struct_field.name(ctx.db).to_string(), struct_field.signature_ty(ctx.db))
338 struct_field.name(ctx.db).to_string(),
339 struct_field.signature_ty(ctx.db).display(ctx.db).to_string(),
340 )
341 } else if let Some(active_parameter) = &ctx.active_parameter { 336 } else if let Some(active_parameter) = &ctx.active_parameter {
342 mark::hit!(active_param_type_match); 337 mark::hit!(active_param_type_match);
343 (active_parameter.name.clone(), active_parameter.ty.clone()) 338 (active_parameter.name.clone(), active_parameter.ty.clone())
diff --git a/crates/ra_ide/src/display.rs b/crates/ra_ide/src/display.rs
index 70d2a2dd1..1ec946369 100644
--- a/crates/ra_ide/src/display.rs
+++ b/crates/ra_ide/src/display.rs
@@ -1,9 +1,8 @@
1//! This module contains utilities for turning SyntaxNodes and HIR types 1//! This module contains utilities for turning SyntaxNodes and HIR types
2//! into types that may be used to render in a UI. 2//! into types that may be used to render in a UI.
3 3
4mod function_signature; 4pub(crate) mod function_signature;
5mod navigation_target; 5mod navigation_target;
6mod structure;
7mod short_label; 6mod short_label;
8 7
9use ra_syntax::{ 8use ra_syntax::{
@@ -11,15 +10,13 @@ use ra_syntax::{
11 SyntaxKind::{ATTR, COMMENT}, 10 SyntaxKind::{ATTR, COMMENT},
12}; 11};
13 12
14pub use function_signature::FunctionSignature;
15pub use navigation_target::NavigationTarget;
16pub use structure::{file_structure, StructureNode};
17
18pub(crate) use navigation_target::{ToNav, TryToNav}; 13pub(crate) use navigation_target::{ToNav, TryToNav};
19pub(crate) use short_label::ShortLabel; 14pub(crate) use short_label::ShortLabel;
20 15
16pub use navigation_target::NavigationTarget;
17
21pub(crate) fn function_label(node: &ast::FnDef) -> String { 18pub(crate) fn function_label(node: &ast::FnDef) -> String {
22 FunctionSignature::from(node).to_string() 19 function_signature::FunctionSignature::from(node).to_string()
23} 20}
24 21
25pub(crate) fn const_label(node: &ast::ConstDef) -> String { 22pub(crate) fn const_label(node: &ast::ConstDef) -> String {
diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs
index 1d39544d3..9b7220d1f 100644
--- a/crates/ra_ide/src/display/function_signature.rs
+++ b/crates/ra_ide/src/display/function_signature.rs
@@ -15,49 +15,48 @@ use stdx::{split_delim, SepBy};
15use crate::display::{generic_parameters, where_predicates}; 15use crate::display::{generic_parameters, where_predicates};
16 16
17#[derive(Debug)] 17#[derive(Debug)]
18pub enum CallableKind { 18pub(crate) enum CallableKind {
19 Function, 19 Function,
20 StructConstructor, 20 StructConstructor,
21 VariantConstructor, 21 VariantConstructor,
22 Macro,
23} 22}
24 23
25/// Contains information about a function signature 24/// Contains information about a function signature
26#[derive(Debug)] 25#[derive(Debug)]
27pub struct FunctionSignature { 26pub(crate) struct FunctionSignature {
28 pub kind: CallableKind, 27 pub(crate) kind: CallableKind,
29 /// Optional visibility 28 /// Optional visibility
30 pub visibility: Option<String>, 29 pub(crate) visibility: Option<String>,
31 /// Qualifiers like `async`, `unsafe`, ... 30 /// Qualifiers like `async`, `unsafe`, ...
32 pub qualifier: FunctionQualifier, 31 pub(crate) qualifier: FunctionQualifier,
33 /// Name of the function 32 /// Name of the function
34 pub name: Option<String>, 33 pub(crate) name: Option<String>,
35 /// Documentation for the function 34 /// Documentation for the function
36 pub doc: Option<Documentation>, 35 pub(crate) doc: Option<Documentation>,
37 /// Generic parameters 36 /// Generic parameters
38 pub generic_parameters: Vec<String>, 37 pub(crate) generic_parameters: Vec<String>,
39 /// Parameters of the function 38 /// Parameters of the function
40 pub parameters: Vec<String>, 39 pub(crate) parameters: Vec<String>,
41 /// Parameter names of the function 40 /// Parameter names of the function
42 pub parameter_names: Vec<String>, 41 pub(crate) parameter_names: Vec<String>,
43 /// Parameter types of the function 42 /// Parameter types of the function
44 pub parameter_types: Vec<String>, 43 pub(crate) parameter_types: Vec<String>,
45 /// Optional return type 44 /// Optional return type
46 pub ret_type: Option<String>, 45 pub(crate) ret_type: Option<String>,
47 /// Where predicates 46 /// Where predicates
48 pub where_predicates: Vec<String>, 47 pub(crate) where_predicates: Vec<String>,
49 /// Self param presence 48 /// Self param presence
50 pub has_self_param: bool, 49 pub(crate) has_self_param: bool,
51} 50}
52 51
53#[derive(Debug, Default)] 52#[derive(Debug, Default)]
54pub struct FunctionQualifier { 53pub(crate) struct FunctionQualifier {
55 // `async` and `const` are mutually exclusive. Do we need to enforcing it here? 54 // `async` and `const` are mutually exclusive. Do we need to enforcing it here?
56 pub is_async: bool, 55 pub(crate) is_async: bool,
57 pub is_const: bool, 56 pub(crate) is_const: bool,
58 pub is_unsafe: bool, 57 pub(crate) is_unsafe: bool,
59 /// The string `extern ".."` 58 /// The string `extern ".."`
60 pub extern_abi: Option<String>, 59 pub(crate) extern_abi: Option<String>,
61} 60}
62 61
63impl FunctionSignature { 62impl FunctionSignature {
@@ -149,27 +148,6 @@ impl FunctionSignature {
149 has_self_param: false, 148 has_self_param: false,
150 }) 149 })
151 } 150 }
152
153 pub(crate) fn from_macro(db: &RootDatabase, macro_def: hir::MacroDef) -> Option<Self> {
154 let node: ast::MacroCall = macro_def.source(db).value;
155
156 let params = vec![];
157
158 Some(FunctionSignature {
159 kind: CallableKind::Macro,
160 visibility: None,
161 qualifier: Default::default(),
162 name: node.name().map(|n| n.text().to_string()),
163 ret_type: None,
164 parameters: params,
165 parameter_names: vec![],
166 parameter_types: vec![],
167 generic_parameters: vec![],
168 where_predicates: vec![],
169 doc: macro_def.docs(db),
170 has_self_param: false,
171 })
172 }
173} 151}
174 152
175impl From<&'_ ast::FnDef> for FunctionSignature { 153impl From<&'_ ast::FnDef> for FunctionSignature {
@@ -298,7 +276,6 @@ impl Display for FunctionSignature {
298 CallableKind::Function => write!(f, "fn {}", name)?, 276 CallableKind::Function => write!(f, "fn {}", name)?,
299 CallableKind::StructConstructor => write!(f, "struct {}", name)?, 277 CallableKind::StructConstructor => write!(f, "struct {}", name)?,
300 CallableKind::VariantConstructor => write!(f, "{}", name)?, 278 CallableKind::VariantConstructor => write!(f, "{}", name)?,
301 CallableKind::Macro => write!(f, "{}!", name)?,
302 } 279 }
303 } 280 }
304 281
diff --git a/crates/ra_ide/src/display/structure.rs b/crates/ra_ide/src/file_structure.rs
index 1f6a3febf..1f6a3febf 100644
--- a/crates/ra_ide/src/display/structure.rs
+++ b/crates/ra_ide/src/file_structure.rs
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index 3cbae8a45..ae5695f61 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -5,10 +5,10 @@ use ra_syntax::{
5 ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner}, 5 ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner},
6 match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange, T, 6 match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange, T,
7}; 7};
8
9use crate::{FileId, FunctionSignature};
10use stdx::to_lower_snake_case; 8use stdx::to_lower_snake_case;
11 9
10use crate::{display::function_signature::FunctionSignature, FileId};
11
12#[derive(Clone, Debug, PartialEq, Eq)] 12#[derive(Clone, Debug, PartialEq, Eq)]
13pub struct InlayHintsConfig { 13pub struct InlayHintsConfig {
14 pub type_hints: bool, 14 pub type_hints: bool,
@@ -322,15 +322,15 @@ fn get_fn_signature(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<
322 match expr { 322 match expr {
323 ast::Expr::CallExpr(expr) => { 323 ast::Expr::CallExpr(expr) => {
324 // FIXME: Type::as_callable is broken for closures 324 // FIXME: Type::as_callable is broken for closures
325 let callable_def = sema.type_of_expr(&expr.expr()?)?.as_callable()?; 325 let callable = sema.type_of_expr(&expr.expr()?)?.as_callable(sema.db)?;
326 match callable_def { 326 match callable.kind() {
327 hir::CallableDefId::FunctionId(it) => { 327 hir::CallableKind::Function(it) => {
328 Some(FunctionSignature::from_hir(sema.db, it.into())) 328 Some(FunctionSignature::from_hir(sema.db, it.into()))
329 } 329 }
330 hir::CallableDefId::StructId(it) => { 330 hir::CallableKind::TupleStruct(it) => {
331 FunctionSignature::from_struct(sema.db, it.into()) 331 FunctionSignature::from_struct(sema.db, it.into())
332 } 332 }
333 hir::CallableDefId::EnumVariantId(it) => { 333 hir::CallableKind::TupleEnumVariant(it) => {
334 FunctionSignature::from_enum_variant(sema.db, it.into()) 334 FunctionSignature::from_enum_variant(sema.db, it.into())
335 } 335 }
336 } 336 }
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index 5d1f64e19..d3b20f371 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -19,29 +19,31 @@ pub mod mock_analysis;
19 19
20mod markup; 20mod markup;
21mod prime_caches; 21mod prime_caches;
22mod status; 22mod display;
23
24mod call_hierarchy;
25mod call_info;
23mod completion; 26mod completion;
24mod runnables; 27mod diagnostics;
28mod expand_macro;
29mod extend_selection;
30mod file_structure;
31mod folding_ranges;
25mod goto_definition; 32mod goto_definition;
26mod goto_type_definition;
27mod goto_implementation; 33mod goto_implementation;
28mod extend_selection; 34mod goto_type_definition;
29mod hover; 35mod hover;
30mod call_hierarchy; 36mod inlay_hints;
31mod call_info; 37mod join_lines;
32mod syntax_highlighting; 38mod matching_brace;
33mod parent_module; 39mod parent_module;
34mod references; 40mod references;
35mod diagnostics; 41mod runnables;
42mod ssr;
43mod status;
44mod syntax_highlighting;
36mod syntax_tree; 45mod syntax_tree;
37mod folding_ranges;
38mod join_lines;
39mod typing; 46mod typing;
40mod matching_brace;
41mod display;
42mod inlay_hints;
43mod expand_macro;
44mod ssr;
45 47
46use std::sync::Arc; 48use std::sync::Arc;
47 49
@@ -65,8 +67,9 @@ pub use crate::{
65 CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat, 67 CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat,
66 }, 68 },
67 diagnostics::Severity, 69 diagnostics::Severity,
68 display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, 70 display::NavigationTarget,
69 expand_macro::ExpandedMacro, 71 expand_macro::ExpandedMacro,
72 file_structure::StructureNode,
70 folding_ranges::{Fold, FoldKind}, 73 folding_ranges::{Fold, FoldKind},
71 hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult}, 74 hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult},
72 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, 75 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind},
@@ -323,7 +326,7 @@ impl Analysis {
323 /// Returns a tree representation of symbols in the file. Useful to draw a 326 /// Returns a tree representation of symbols in the file. Useful to draw a
324 /// file outline. 327 /// file outline.
325 pub fn file_structure(&self, file_id: FileId) -> Cancelable<Vec<StructureNode>> { 328 pub fn file_structure(&self, file_id: FileId) -> Cancelable<Vec<StructureNode>> {
326 self.with_db(|db| file_structure(&db.parse(file_id).tree())) 329 self.with_db(|db| file_structure::file_structure(&db.parse(file_id).tree()))
327 } 330 }
328 331
329 /// Returns a list of the places in the file where type hints can be displayed. 332 /// Returns a list of the places in the file where type hints can be displayed.