diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-07-16 17:50:37 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-07-16 17:50:37 +0100 |
commit | 081596dd584ac39fbfa6a7e47dfe9dd4a58c362a (patch) | |
tree | b6d564a63068530ef3aabb8855699bf20c45a608 /crates/ra_ide/src/call_info.rs | |
parent | 9210fcc076808e53e9bde84be26307fc0dc7d688 (diff) | |
parent | e1e79cf0648624e7a3787d0013c0c7e86210772f (diff) |
Merge #5413
5413: Semantical call info r=matklad a=matklad
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_ide/src/call_info.rs')
-rw-r--r-- | crates/ra_ide/src/call_info.rs | 361 |
1 files changed, 193 insertions, 168 deletions
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 |
2 | use hir::Semantics; | 2 | use either::Either; |
3 | use hir::{Docs, HirDisplay, Semantics, Type}; | ||
3 | use ra_ide_db::RootDatabase; | 4 | use ra_ide_db::RootDatabase; |
4 | use ra_syntax::{ | 5 | use 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 | }; |
9 | use stdx::format_to; | ||
8 | use test_utils::mark; | 10 | use test_utils::mark; |
9 | 11 | ||
10 | use crate::{FilePosition, FunctionSignature}; | 12 | use 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)] |
15 | pub struct CallInfo { | 17 | pub 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 | |||
24 | impl 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)?; |
31 | pub(crate) struct ActiveParameter { | ||
32 | /// FIXME: should be `Type` and `Name | ||
33 | pub(crate) ty: String, | ||
34 | pub(crate) name: String, | ||
35 | } | ||
36 | 51 | ||
37 | impl 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 | ||
47 | fn call_info_for_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<CallInfo> { | 107 | fn 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(¯o_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(); | 143 | pub(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( | 148 | impl 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)] |
122 | pub(crate) enum FnCallNode { | 170 | pub(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 | ||
128 | impl FnCallNode { | 175 | impl 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 | ||
183 | impl 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)] |
194 | mod tests { | 226 | mod 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 | |||
296 | fn bar() { foo(<|>3, ); } | 326 | fn 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 {} | |||
312 | fn bar() { foo(<|>); } | 340 | fn 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#" |
326 | struct F; impl F { pub fn new() { F{}} } | 353 | struct F; |
327 | fn bar() {let _ : F = F::new(<|>);} | 354 | impl F { pub fn new() { } } |
355 | fn 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#" |
359 | struct S; | 389 | struct S; |
360 | impl S { pub fn do_it(&self, x: i32) {} } | 390 | impl S { |
391 | fn foo(&self, x: i32) {} | ||
392 | } | ||
361 | 393 | ||
362 | fn bar() { | 394 | fn 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#" | ||
407 | struct S; | ||
408 | impl S { | ||
409 | fn foo(&self, x: i32) {} | ||
365 | } | 410 | } |
411 | |||
412 | fn 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 |
552 | struct TS(u32, i32); | 599 | struct S(u32, i32); |
553 | fn main() { | 600 | fn 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#" |
570 | struct TS<T>(T); | 617 | struct S<T>(T); |
571 | fn main() { | 618 | fn 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#" | ||
586 | struct TS { x: u32, y: i32 } | ||
587 | fn 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#" |
625 | enum E { | 659 | struct 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 | |||
634 | fn main() { | 660 | fn 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 | 672 | enum E { |
647 | macro_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 | ||
651 | fn f() { | 681 | fn 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 | ||