diff options
Diffstat (limited to 'crates/ra_analysis/src/completion')
7 files changed, 195 insertions, 65 deletions
diff --git a/crates/ra_analysis/src/completion/complete_dot.rs b/crates/ra_analysis/src/completion/complete_dot.rs index 93d657576..f24835d17 100644 --- a/crates/ra_analysis/src/completion/complete_dot.rs +++ b/crates/ra_analysis/src/completion/complete_dot.rs | |||
@@ -6,20 +6,9 @@ use crate::completion::{CompletionContext, Completions, CompletionKind, Completi | |||
6 | 6 | ||
7 | /// Complete dot accesses, i.e. fields or methods (currently only fields). | 7 | /// Complete dot accesses, i.e. fields or methods (currently only fields). |
8 | pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) -> Cancelable<()> { | 8 | pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) -> Cancelable<()> { |
9 | let module = if let Some(module) = &ctx.module { | 9 | let (function, receiver) = match (&ctx.function, ctx.dot_receiver) { |
10 | module | 10 | (Some(function), Some(receiver)) => (function, receiver), |
11 | } else { | 11 | _ => return Ok(()), |
12 | return Ok(()); | ||
13 | }; | ||
14 | let function = if let Some(fn_def) = ctx.enclosing_fn { | ||
15 | hir::source_binder::function_from_module(ctx.db, module, fn_def) | ||
16 | } else { | ||
17 | return Ok(()); | ||
18 | }; | ||
19 | let receiver = if let Some(receiver) = ctx.dot_receiver { | ||
20 | receiver | ||
21 | } else { | ||
22 | return Ok(()); | ||
23 | }; | 12 | }; |
24 | let infer_result = function.infer(ctx.db)?; | 13 | let infer_result = function.infer(ctx.db)?; |
25 | let receiver_ty = if let Some(ty) = infer_result.type_of_node(receiver.syntax()) { | 14 | let receiver_ty = if let Some(ty) = infer_result.type_of_node(receiver.syntax()) { |
diff --git a/crates/ra_analysis/src/completion/complete_keyword.rs b/crates/ra_analysis/src/completion/complete_keyword.rs index 5427fcb11..b2486104a 100644 --- a/crates/ra_analysis/src/completion/complete_keyword.rs +++ b/crates/ra_analysis/src/completion/complete_keyword.rs | |||
@@ -18,7 +18,7 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
18 | if !ctx.is_trivial_path { | 18 | if !ctx.is_trivial_path { |
19 | return; | 19 | return; |
20 | } | 20 | } |
21 | let fn_def = match ctx.enclosing_fn { | 21 | let fn_def = match ctx.function_syntax { |
22 | Some(it) => it, | 22 | Some(it) => it, |
23 | None => return, | 23 | None => return, |
24 | }; | 24 | }; |
@@ -32,10 +32,15 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
32 | acc.add(keyword("else if", "else if $0 {}")); | 32 | acc.add(keyword("else if", "else if $0 {}")); |
33 | } | 33 | } |
34 | if is_in_loop_body(ctx.leaf) { | 34 | if is_in_loop_body(ctx.leaf) { |
35 | acc.add(keyword("continue", "continue")); | 35 | if ctx.can_be_stmt { |
36 | acc.add(keyword("break", "break")); | 36 | acc.add(keyword("continue", "continue;")); |
37 | acc.add(keyword("break", "break;")); | ||
38 | } else { | ||
39 | acc.add(keyword("continue", "continue")); | ||
40 | acc.add(keyword("break", "break")); | ||
41 | } | ||
37 | } | 42 | } |
38 | acc.add_all(complete_return(fn_def, ctx.is_stmt)); | 43 | acc.add_all(complete_return(fn_def, ctx.can_be_stmt)); |
39 | } | 44 | } |
40 | 45 | ||
41 | fn is_in_loop_body(leaf: SyntaxNodeRef) -> bool { | 46 | fn is_in_loop_body(leaf: SyntaxNodeRef) -> bool { |
@@ -57,8 +62,8 @@ fn is_in_loop_body(leaf: SyntaxNodeRef) -> bool { | |||
57 | false | 62 | false |
58 | } | 63 | } |
59 | 64 | ||
60 | fn complete_return(fn_def: ast::FnDef, is_stmt: bool) -> Option<CompletionItem> { | 65 | fn complete_return(fn_def: ast::FnDef, can_be_stmt: bool) -> Option<CompletionItem> { |
61 | let snip = match (is_stmt, fn_def.ret_type().is_some()) { | 66 | let snip = match (can_be_stmt, fn_def.ret_type().is_some()) { |
62 | (true, true) => "return $0;", | 67 | (true, true) => "return $0;", |
63 | (true, false) => "return;", | 68 | (true, false) => "return;", |
64 | (false, true) => "return $0", | 69 | (false, true) => "return $0", |
@@ -75,7 +80,7 @@ mod tests { | |||
75 | } | 80 | } |
76 | 81 | ||
77 | #[test] | 82 | #[test] |
78 | fn test_completion_kewords() { | 83 | fn completes_various_keywords_in_function() { |
79 | check_keyword_completion( | 84 | check_keyword_completion( |
80 | r" | 85 | r" |
81 | fn quux() { | 86 | fn quux() { |
@@ -87,13 +92,13 @@ mod tests { | |||
87 | match "match $0 {}" | 92 | match "match $0 {}" |
88 | while "while $0 {}" | 93 | while "while $0 {}" |
89 | loop "loop {$0}" | 94 | loop "loop {$0}" |
90 | return "return" | 95 | return "return;" |
91 | "#, | 96 | "#, |
92 | ); | 97 | ); |
93 | } | 98 | } |
94 | 99 | ||
95 | #[test] | 100 | #[test] |
96 | fn test_completion_else() { | 101 | fn completes_else_after_if() { |
97 | check_keyword_completion( | 102 | check_keyword_completion( |
98 | r" | 103 | r" |
99 | fn quux() { | 104 | fn quux() { |
@@ -109,7 +114,7 @@ mod tests { | |||
109 | loop "loop {$0}" | 114 | loop "loop {$0}" |
110 | else "else {$0}" | 115 | else "else {$0}" |
111 | else if "else if $0 {}" | 116 | else if "else if $0 {}" |
112 | return "return" | 117 | return "return;" |
113 | "#, | 118 | "#, |
114 | ); | 119 | ); |
115 | } | 120 | } |
@@ -149,7 +154,7 @@ mod tests { | |||
149 | } | 154 | } |
150 | 155 | ||
151 | #[test] | 156 | #[test] |
152 | fn test_completion_return_no_stmt() { | 157 | fn dont_add_semi_after_return_if_not_a_statement() { |
153 | check_keyword_completion( | 158 | check_keyword_completion( |
154 | r" | 159 | r" |
155 | fn quux() -> i32 { | 160 | fn quux() -> i32 { |
@@ -169,7 +174,27 @@ mod tests { | |||
169 | } | 174 | } |
170 | 175 | ||
171 | #[test] | 176 | #[test] |
172 | fn test_continue_break_completion() { | 177 | fn last_return_in_block_has_semi() { |
178 | check_keyword_completion( | ||
179 | r" | ||
180 | fn quux() -> i32 { | ||
181 | if condition { | ||
182 | <|> | ||
183 | } | ||
184 | } | ||
185 | ", | ||
186 | r#" | ||
187 | if "if $0 {}" | ||
188 | match "match $0 {}" | ||
189 | while "while $0 {}" | ||
190 | loop "loop {$0}" | ||
191 | return "return $0;" | ||
192 | "#, | ||
193 | ); | ||
194 | } | ||
195 | |||
196 | #[test] | ||
197 | fn completes_break_and_continue_in_loops() { | ||
173 | check_keyword_completion( | 198 | check_keyword_completion( |
174 | r" | 199 | r" |
175 | fn quux() -> i32 { | 200 | fn quux() -> i32 { |
@@ -181,11 +206,12 @@ mod tests { | |||
181 | match "match $0 {}" | 206 | match "match $0 {}" |
182 | while "while $0 {}" | 207 | while "while $0 {}" |
183 | loop "loop {$0}" | 208 | loop "loop {$0}" |
184 | continue "continue" | 209 | continue "continue;" |
185 | break "break" | 210 | break "break;" |
186 | return "return $0" | 211 | return "return $0;" |
187 | "#, | 212 | "#, |
188 | ); | 213 | ); |
214 | // No completion: lambda isolates control flow | ||
189 | check_keyword_completion( | 215 | check_keyword_completion( |
190 | r" | 216 | r" |
191 | fn quux() -> i32 { | 217 | fn quux() -> i32 { |
@@ -197,8 +223,32 @@ mod tests { | |||
197 | match "match $0 {}" | 223 | match "match $0 {}" |
198 | while "while $0 {}" | 224 | while "while $0 {}" |
199 | loop "loop {$0}" | 225 | loop "loop {$0}" |
200 | return "return $0" | 226 | return "return $0;" |
201 | "#, | 227 | "#, |
202 | ); | 228 | ); |
203 | } | 229 | } |
230 | |||
231 | #[test] | ||
232 | fn no_semi_after_break_continue_in_expr() { | ||
233 | check_keyword_completion( | ||
234 | r" | ||
235 | fn f() { | ||
236 | loop { | ||
237 | match () { | ||
238 | () => br<|> | ||
239 | } | ||
240 | } | ||
241 | } | ||
242 | ", | ||
243 | r#" | ||
244 | if "if $0 {}" | ||
245 | match "match $0 {}" | ||
246 | while "while $0 {}" | ||
247 | loop "loop {$0}" | ||
248 | continue "continue" | ||
249 | break "break" | ||
250 | return "return" | ||
251 | "#, | ||
252 | ) | ||
253 | } | ||
204 | } | 254 | } |
diff --git a/crates/ra_analysis/src/completion/complete_path.rs b/crates/ra_analysis/src/completion/complete_path.rs index aaa2c7cee..4723a65a6 100644 --- a/crates/ra_analysis/src/completion/complete_path.rs +++ b/crates/ra_analysis/src/completion/complete_path.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use crate::{ | 1 | use crate::{ |
2 | Cancelable, | 2 | Cancelable, |
3 | completion::{CompletionItem, Completions, CompletionKind, CompletionContext}, | 3 | completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext}, |
4 | }; | 4 | }; |
5 | 5 | ||
6 | pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) -> Cancelable<()> { | 6 | pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) -> Cancelable<()> { |
@@ -12,16 +12,25 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) -> C | |||
12 | Some(it) => it, | 12 | Some(it) => it, |
13 | None => return Ok(()), | 13 | None => return Ok(()), |
14 | }; | 14 | }; |
15 | let target_module = match def_id.resolve(ctx.db)? { | 15 | match def_id.resolve(ctx.db)? { |
16 | hir::Def::Module(it) => it, | 16 | hir::Def::Module(module) => { |
17 | let module_scope = module.scope(ctx.db)?; | ||
18 | module_scope.entries().for_each(|(name, res)| { | ||
19 | CompletionItem::new(CompletionKind::Reference, name.to_string()) | ||
20 | .from_resolution(ctx, res) | ||
21 | .add_to(acc) | ||
22 | }); | ||
23 | } | ||
24 | hir::Def::Enum(e) => e | ||
25 | .variants(ctx.db)? | ||
26 | .into_iter() | ||
27 | .for_each(|(name, _variant)| { | ||
28 | CompletionItem::new(CompletionKind::Reference, name.to_string()) | ||
29 | .kind(CompletionItemKind::EnumVariant) | ||
30 | .add_to(acc) | ||
31 | }), | ||
17 | _ => return Ok(()), | 32 | _ => return Ok(()), |
18 | }; | 33 | }; |
19 | let module_scope = target_module.scope(ctx.db)?; | ||
20 | module_scope.entries().for_each(|(name, res)| { | ||
21 | CompletionItem::new(CompletionKind::Reference, name.to_string()) | ||
22 | .from_resolution(ctx.db, res) | ||
23 | .add_to(acc) | ||
24 | }); | ||
25 | Ok(()) | 34 | Ok(()) |
26 | } | 35 | } |
27 | 36 | ||
@@ -92,4 +101,28 @@ mod tests { | |||
92 | "Spam", | 101 | "Spam", |
93 | ); | 102 | ); |
94 | } | 103 | } |
104 | |||
105 | #[test] | ||
106 | fn completes_enum_variant() { | ||
107 | check_reference_completion( | ||
108 | " | ||
109 | //- /lib.rs | ||
110 | enum E { Foo, Bar(i32) } | ||
111 | fn foo() { let _ = E::<|> } | ||
112 | ", | ||
113 | "Foo;Bar", | ||
114 | ); | ||
115 | } | ||
116 | |||
117 | #[test] | ||
118 | fn dont_render_function_parens_in_use_item() { | ||
119 | check_reference_completion( | ||
120 | " | ||
121 | //- /lib.rs | ||
122 | mod m { pub fn foo() {} } | ||
123 | use crate::m::f<|>; | ||
124 | ", | ||
125 | "foo", | ||
126 | ) | ||
127 | } | ||
95 | } | 128 | } |
diff --git a/crates/ra_analysis/src/completion/complete_scope.rs b/crates/ra_analysis/src/completion/complete_scope.rs index a57670e3b..daf666505 100644 --- a/crates/ra_analysis/src/completion/complete_scope.rs +++ b/crates/ra_analysis/src/completion/complete_scope.rs | |||
@@ -14,8 +14,7 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) -> | |||
14 | Some(it) => it, | 14 | Some(it) => it, |
15 | None => return Ok(()), | 15 | None => return Ok(()), |
16 | }; | 16 | }; |
17 | if let Some(fn_def) = ctx.enclosing_fn { | 17 | if let Some(function) = &ctx.function { |
18 | let function = hir::source_binder::function_from_module(ctx.db, module, fn_def); | ||
19 | let scopes = function.scopes(ctx.db); | 18 | let scopes = function.scopes(ctx.db); |
20 | complete_fn(acc, &scopes, ctx.offset); | 19 | complete_fn(acc, &scopes, ctx.offset); |
21 | } | 20 | } |
@@ -35,7 +34,7 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) -> | |||
35 | }) | 34 | }) |
36 | .for_each(|(name, res)| { | 35 | .for_each(|(name, res)| { |
37 | CompletionItem::new(CompletionKind::Reference, name.to_string()) | 36 | CompletionItem::new(CompletionKind::Reference, name.to_string()) |
38 | .from_resolution(ctx.db, res) | 37 | .from_resolution(ctx, res) |
39 | .add_to(acc) | 38 | .add_to(acc) |
40 | }); | 39 | }); |
41 | Ok(()) | 40 | Ok(()) |
@@ -75,7 +74,7 @@ mod tests { | |||
75 | let z = (); | 74 | let z = (); |
76 | } | 75 | } |
77 | ", | 76 | ", |
78 | "y;x;quux", | 77 | r#"y;x;quux "quux($0)""#, |
79 | ); | 78 | ); |
80 | } | 79 | } |
81 | 80 | ||
@@ -93,7 +92,7 @@ mod tests { | |||
93 | } | 92 | } |
94 | } | 93 | } |
95 | ", | 94 | ", |
96 | "b;a;quux", | 95 | r#"b;a;quux "quux()$0""#, |
97 | ); | 96 | ); |
98 | } | 97 | } |
99 | 98 | ||
@@ -107,7 +106,7 @@ mod tests { | |||
107 | } | 106 | } |
108 | } | 107 | } |
109 | ", | 108 | ", |
110 | "x;quux", | 109 | r#"x;quux "quux()$0""#, |
111 | ); | 110 | ); |
112 | } | 111 | } |
113 | 112 | ||
@@ -121,7 +120,7 @@ mod tests { | |||
121 | <|> | 120 | <|> |
122 | } | 121 | } |
123 | ", | 122 | ", |
124 | "quux;Foo;Baz", | 123 | r#"quux "quux()$0";Foo;Baz"#, |
125 | ); | 124 | ); |
126 | } | 125 | } |
127 | 126 | ||
@@ -135,7 +134,7 @@ mod tests { | |||
135 | fn quux() { <|> } | 134 | fn quux() { <|> } |
136 | } | 135 | } |
137 | ", | 136 | ", |
138 | "quux;Bar", | 137 | r#"quux "quux()$0";Bar"#, |
139 | ); | 138 | ); |
140 | } | 139 | } |
141 | 140 | ||
@@ -146,12 +145,12 @@ mod tests { | |||
146 | struct Foo; | 145 | struct Foo; |
147 | fn x() -> <|> | 146 | fn x() -> <|> |
148 | ", | 147 | ", |
149 | "Foo;x", | 148 | r#"Foo;x "x()$0""#, |
150 | ) | 149 | ) |
151 | } | 150 | } |
152 | 151 | ||
153 | #[test] | 152 | #[test] |
154 | fn dont_show_to_completions_for_shadowing() { | 153 | fn dont_show_both_completions_for_shadowing() { |
155 | check_reference_completion( | 154 | check_reference_completion( |
156 | r" | 155 | r" |
157 | fn foo() -> { | 156 | fn foo() -> { |
@@ -162,7 +161,7 @@ mod tests { | |||
162 | } | 161 | } |
163 | } | 162 | } |
164 | ", | 163 | ", |
165 | "bar;foo", | 164 | r#"bar;foo "foo()$0""#, |
166 | ) | 165 | ) |
167 | } | 166 | } |
168 | 167 | ||
@@ -170,4 +169,24 @@ mod tests { | |||
170 | fn completes_self_in_methods() { | 169 | fn completes_self_in_methods() { |
171 | check_reference_completion(r"impl S { fn foo(&self) { <|> } }", "self") | 170 | check_reference_completion(r"impl S { fn foo(&self) { <|> } }", "self") |
172 | } | 171 | } |
172 | |||
173 | #[test] | ||
174 | fn inserts_parens_for_function_calls() { | ||
175 | check_reference_completion( | ||
176 | r" | ||
177 | fn no_args() {} | ||
178 | fn main() { no_<|> } | ||
179 | ", | ||
180 | r#"no_args "no_args()$0" | ||
181 | main "main()$0""#, | ||
182 | ); | ||
183 | check_reference_completion( | ||
184 | r" | ||
185 | fn with_args(x: i32, y: String) {} | ||
186 | fn main() { with_<|> } | ||
187 | ", | ||
188 | r#"main "main()$0" | ||
189 | with_args "with_args($0)""#, | ||
190 | ); | ||
191 | } | ||
173 | } | 192 | } |
diff --git a/crates/ra_analysis/src/completion/complete_snippet.rs b/crates/ra_analysis/src/completion/complete_snippet.rs index fb9da0a4f..a495751dd 100644 --- a/crates/ra_analysis/src/completion/complete_snippet.rs +++ b/crates/ra_analysis/src/completion/complete_snippet.rs | |||
@@ -7,7 +7,7 @@ fn snippet(label: &str, snippet: &str) -> Builder { | |||
7 | } | 7 | } |
8 | 8 | ||
9 | pub(super) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionContext) { | 9 | pub(super) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionContext) { |
10 | if !(ctx.is_trivial_path && ctx.enclosing_fn.is_some()) { | 10 | if !(ctx.is_trivial_path && ctx.function_syntax.is_some()) { |
11 | return; | 11 | return; |
12 | } | 12 | } |
13 | snippet("pd", "eprintln!(\"$0 = {:?}\", $0);").add_to(acc); | 13 | snippet("pd", "eprintln!(\"$0 = {:?}\", $0);").add_to(acc); |
diff --git a/crates/ra_analysis/src/completion/completion_context.rs b/crates/ra_analysis/src/completion/completion_context.rs index 978772fd4..4685c9328 100644 --- a/crates/ra_analysis/src/completion/completion_context.rs +++ b/crates/ra_analysis/src/completion/completion_context.rs | |||
@@ -22,14 +22,17 @@ pub(super) struct CompletionContext<'a> { | |||
22 | pub(super) offset: TextUnit, | 22 | pub(super) offset: TextUnit, |
23 | pub(super) leaf: SyntaxNodeRef<'a>, | 23 | pub(super) leaf: SyntaxNodeRef<'a>, |
24 | pub(super) module: Option<hir::Module>, | 24 | pub(super) module: Option<hir::Module>, |
25 | pub(super) enclosing_fn: Option<ast::FnDef<'a>>, | 25 | pub(super) function: Option<hir::Function>, |
26 | pub(super) function_syntax: Option<ast::FnDef<'a>>, | ||
27 | pub(super) use_item_syntax: Option<ast::UseItem<'a>>, | ||
26 | pub(super) is_param: bool, | 28 | pub(super) is_param: bool, |
27 | /// A single-indent path, like `foo`. | 29 | /// A single-indent path, like `foo`. |
28 | pub(super) is_trivial_path: bool, | 30 | pub(super) is_trivial_path: bool, |
29 | /// If not a trivial, path, the prefix (qualifier). | 31 | /// If not a trivial, path, the prefix (qualifier). |
30 | pub(super) path_prefix: Option<hir::Path>, | 32 | pub(super) path_prefix: Option<hir::Path>, |
31 | pub(super) after_if: bool, | 33 | pub(super) after_if: bool, |
32 | pub(super) is_stmt: bool, | 34 | /// `true` if we are a statement or a last expr in the block. |
35 | pub(super) can_be_stmt: bool, | ||
33 | /// Something is typed at the "top" level, in module or impl/trait. | 36 | /// Something is typed at the "top" level, in module or impl/trait. |
34 | pub(super) is_new_item: bool, | 37 | pub(super) is_new_item: bool, |
35 | /// The receiver if this is a field or method access, i.e. writing something.<|> | 38 | /// The receiver if this is a field or method access, i.e. writing something.<|> |
@@ -52,12 +55,14 @@ impl<'a> CompletionContext<'a> { | |||
52 | leaf, | 55 | leaf, |
53 | offset: position.offset, | 56 | offset: position.offset, |
54 | module, | 57 | module, |
55 | enclosing_fn: None, | 58 | function: None, |
59 | function_syntax: None, | ||
60 | use_item_syntax: None, | ||
56 | is_param: false, | 61 | is_param: false, |
57 | is_trivial_path: false, | 62 | is_trivial_path: false, |
58 | path_prefix: None, | 63 | path_prefix: None, |
59 | after_if: false, | 64 | after_if: false, |
60 | is_stmt: false, | 65 | can_be_stmt: false, |
61 | is_new_item: false, | 66 | is_new_item: false, |
62 | dot_receiver: None, | 67 | dot_receiver: None, |
63 | is_method_call: false, | 68 | is_method_call: false, |
@@ -112,11 +117,20 @@ impl<'a> CompletionContext<'a> { | |||
112 | _ => (), | 117 | _ => (), |
113 | } | 118 | } |
114 | 119 | ||
115 | self.enclosing_fn = self | 120 | self.use_item_syntax = self.leaf.ancestors().find_map(ast::UseItem::cast); |
121 | |||
122 | self.function_syntax = self | ||
116 | .leaf | 123 | .leaf |
117 | .ancestors() | 124 | .ancestors() |
118 | .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) | 125 | .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) |
119 | .find_map(ast::FnDef::cast); | 126 | .find_map(ast::FnDef::cast); |
127 | match (&self.module, self.function_syntax) { | ||
128 | (Some(module), Some(fn_def)) => { | ||
129 | let function = source_binder::function_from_module(self.db, module, fn_def); | ||
130 | self.function = Some(function); | ||
131 | } | ||
132 | _ => (), | ||
133 | } | ||
120 | 134 | ||
121 | let parent = match name_ref.syntax().parent() { | 135 | let parent = match name_ref.syntax().parent() { |
122 | Some(it) => it, | 136 | Some(it) => it, |
@@ -134,13 +148,22 @@ impl<'a> CompletionContext<'a> { | |||
134 | if path.qualifier().is_none() { | 148 | if path.qualifier().is_none() { |
135 | self.is_trivial_path = true; | 149 | self.is_trivial_path = true; |
136 | 150 | ||
137 | self.is_stmt = match name_ref | 151 | self.can_be_stmt = match name_ref |
138 | .syntax() | 152 | .syntax() |
139 | .ancestors() | 153 | .ancestors() |
140 | .filter_map(ast::ExprStmt::cast) | 154 | .filter_map(ast::ExprStmt::cast) |
141 | .next() | 155 | .next() |
142 | { | 156 | { |
143 | None => false, | 157 | None => { |
158 | name_ref | ||
159 | .syntax() | ||
160 | .ancestors() | ||
161 | .filter_map(ast::Block::cast) | ||
162 | .next() | ||
163 | .and_then(|block| block.expr()) | ||
164 | .map(|e| e.syntax().range()) | ||
165 | == Some(name_ref.syntax().range()) | ||
166 | } | ||
144 | Some(expr_stmt) => expr_stmt.syntax().range() == name_ref.syntax().range(), | 167 | Some(expr_stmt) => expr_stmt.syntax().range() == name_ref.syntax().range(), |
145 | }; | 168 | }; |
146 | 169 | ||
diff --git a/crates/ra_analysis/src/completion/completion_item.rs b/crates/ra_analysis/src/completion/completion_item.rs index c9f9f495d..cd4d529f9 100644 --- a/crates/ra_analysis/src/completion/completion_item.rs +++ b/crates/ra_analysis/src/completion/completion_item.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use crate::db; | ||
2 | |||
3 | use hir::PerNs; | 1 | use hir::PerNs; |
4 | 2 | ||
3 | use crate::completion::CompletionContext; | ||
4 | |||
5 | /// `CompletionItem` describes a single completion variant in the editor pop-up. | 5 | /// `CompletionItem` describes a single completion variant in the editor pop-up. |
6 | /// It is basically a POD with various properties. To construct a | 6 | /// It is basically a POD with various properties. To construct a |
7 | /// `CompletionItem`, use `new` method and the `Builder` struct. | 7 | /// `CompletionItem`, use `new` method and the `Builder` struct. |
@@ -29,6 +29,7 @@ pub enum CompletionItemKind { | |||
29 | Function, | 29 | Function, |
30 | Struct, | 30 | Struct, |
31 | Enum, | 31 | Enum, |
32 | EnumVariant, | ||
32 | Binding, | 33 | Binding, |
33 | Field, | 34 | Field, |
34 | } | 35 | } |
@@ -117,12 +118,12 @@ impl Builder { | |||
117 | self.kind = Some(kind); | 118 | self.kind = Some(kind); |
118 | self | 119 | self |
119 | } | 120 | } |
120 | pub(crate) fn from_resolution( | 121 | pub(super) fn from_resolution( |
121 | mut self, | 122 | mut self, |
122 | db: &db::RootDatabase, | 123 | ctx: &CompletionContext, |
123 | resolution: &hir::Resolution, | 124 | resolution: &hir::Resolution, |
124 | ) -> Builder { | 125 | ) -> Builder { |
125 | let resolved = resolution.def_id.and_then(|d| d.resolve(db).ok()); | 126 | let resolved = resolution.def_id.and_then(|d| d.resolve(ctx.db).ok()); |
126 | let kind = match resolved { | 127 | let kind = match resolved { |
127 | PerNs { | 128 | PerNs { |
128 | types: Some(hir::Def::Module(..)), | 129 | types: Some(hir::Def::Module(..)), |
@@ -137,14 +138,29 @@ impl Builder { | |||
137 | .. | 138 | .. |
138 | } => CompletionItemKind::Enum, | 139 | } => CompletionItemKind::Enum, |
139 | PerNs { | 140 | PerNs { |
140 | values: Some(hir::Def::Function(..)), | 141 | values: Some(hir::Def::Function(function)), |
141 | .. | 142 | .. |
142 | } => CompletionItemKind::Function, | 143 | } => return self.from_function(ctx, function), |
143 | _ => return self, | 144 | _ => return self, |
144 | }; | 145 | }; |
145 | self.kind = Some(kind); | 146 | self.kind = Some(kind); |
146 | self | 147 | self |
147 | } | 148 | } |
149 | |||
150 | fn from_function(mut self, ctx: &CompletionContext, function: hir::Function) -> Builder { | ||
151 | // If not an import, add parenthesis automatically. | ||
152 | if ctx.use_item_syntax.is_none() { | ||
153 | if let Some(sig_info) = function.signature_info(ctx.db) { | ||
154 | if sig_info.params.is_empty() { | ||
155 | self.snippet = Some(format!("{}()$0", self.label)); | ||
156 | } else { | ||
157 | self.snippet = Some(format!("{}($0)", self.label)); | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | self.kind = Some(CompletionItemKind::Function); | ||
162 | self | ||
163 | } | ||
148 | } | 164 | } |
149 | 165 | ||
150 | impl Into<CompletionItem> for Builder { | 166 | impl Into<CompletionItem> for Builder { |