aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r--crates/ra_ide/src/call_hierarchy.rs97
-rw-r--r--crates/ra_ide/src/call_info.rs789
-rw-r--r--crates/ra_ide/src/completion.rs18
-rw-r--r--crates/ra_ide/src/completion/complete_attribute.rs1263
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs994
-rw-r--r--crates/ra_ide/src/completion/complete_fn_param.rs161
-rw-r--r--crates/ra_ide/src/completion/complete_keyword.rs562
-rw-r--r--crates/ra_ide/src/completion/complete_macro_in_item_position.rs137
-rw-r--r--crates/ra_ide/src/completion/complete_pattern.rs126
-rw-r--r--crates/ra_ide/src/completion/complete_postfix.rs635
-rw-r--r--crates/ra_ide/src/completion/complete_qualified_path.rs1506
-rw-r--r--crates/ra_ide/src/completion/complete_record.rs546
-rw-r--r--crates/ra_ide/src/completion/complete_snippet.rs106
-rw-r--r--crates/ra_ide/src/completion/complete_trait_impl.rs498
-rw-r--r--crates/ra_ide/src/completion/complete_unqualified_path.rs1615
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs59
-rw-r--r--crates/ra_ide/src/completion/completion_item.rs26
-rw-r--r--crates/ra_ide/src/completion/patterns.rs16
-rw-r--r--crates/ra_ide/src/completion/presentation.rs1675
-rw-r--r--crates/ra_ide/src/completion/test_utils.rs72
-rw-r--r--crates/ra_ide/src/diagnostics.rs913
-rw-r--r--crates/ra_ide/src/display.rs96
-rw-r--r--crates/ra_ide/src/display/function_signature.rs334
-rw-r--r--crates/ra_ide/src/display/navigation_target.rs207
-rw-r--r--crates/ra_ide/src/display/short_label.rs36
-rw-r--r--crates/ra_ide/src/display/structure.rs438
-rw-r--r--crates/ra_ide/src/expand_macro.rs241
-rw-r--r--crates/ra_ide/src/extend_selection.rs8
-rw-r--r--crates/ra_ide/src/file_structure.rs431
-rw-r--r--crates/ra_ide/src/folding_ranges.rs194
-rw-r--r--crates/ra_ide/src/goto_definition.rs1168
-rw-r--r--crates/ra_ide/src/goto_implementation.rs211
-rw-r--r--crates/ra_ide/src/goto_type_definition.rs132
-rw-r--r--crates/ra_ide/src/hover.rs3454
-rw-r--r--crates/ra_ide/src/inlay_hints.rs1062
-rw-r--r--crates/ra_ide/src/lib.rs142
-rw-r--r--crates/ra_ide/src/markup.rs38
-rw-r--r--crates/ra_ide/src/mock_analysis.rs40
-rw-r--r--crates/ra_ide/src/references.rs47
-rw-r--r--crates/ra_ide/src/references/rename.rs1101
-rw-r--r--crates/ra_ide/src/runnables.rs1137
-rw-r--r--crates/ra_ide/src/snapshots/highlight_doctest.html101
-rw-r--r--crates/ra_ide/src/snapshots/highlight_injection.html47
-rw-r--r--crates/ra_ide/src/snapshots/highlight_strings.html95
-rw-r--r--crates/ra_ide/src/snapshots/highlight_unsafe.html53
-rw-r--r--crates/ra_ide/src/snapshots/highlighting.html117
-rw-r--r--crates/ra_ide/src/snapshots/rainbow_highlighting.html48
-rw-r--r--crates/ra_ide/src/ssr.rs53
-rw-r--r--crates/ra_ide/src/status.rs15
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs114
-rw-r--r--crates/ra_ide/src/syntax_highlighting/html.rs15
-rw-r--r--crates/ra_ide/src/syntax_highlighting/injection.rs2
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tags.rs4
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tests.rs32
-rw-r--r--crates/ra_ide/src/syntax_tree.rs14
-rw-r--r--crates/ra_ide/src/typing.rs1
-rw-r--r--crates/ra_ide/src/typing/on_enter.rs67
57 files changed, 9393 insertions, 13716 deletions
diff --git a/crates/ra_ide/src/call_hierarchy.rs b/crates/ra_ide/src/call_hierarchy.rs
index 1e3a31602..1fcaf4a32 100644
--- a/crates/ra_ide/src/call_hierarchy.rs
+++ b/crates/ra_ide/src/call_hierarchy.rs
@@ -39,10 +39,11 @@ pub(crate) fn call_hierarchy(
39 39
40pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Option<Vec<CallItem>> { 40pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Option<Vec<CallItem>> {
41 let sema = Semantics::new(db); 41 let sema = Semantics::new(db);
42
42 // 1. Find all refs 43 // 1. Find all refs
43 // 2. Loop through refs and determine unique fndef. This will become our `from: CallHierarchyItem,` in the reply. 44 // 2. Loop through refs and determine unique fndef. This will become our `from: CallHierarchyItem,` in the reply.
44 // 3. Add ranges relative to the start of the fndef. 45 // 3. Add ranges relative to the start of the fndef.
45 let refs = references::find_all_refs(db, position, None)?; 46 let refs = references::find_all_refs(&sema, position, None)?;
46 47
47 let mut calls = CallLocations::default(); 48 let mut calls = CallLocations::default();
48 49
@@ -58,7 +59,7 @@ pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Optio
58 if let Some(nav) = syntax.ancestors().find_map(|node| { 59 if let Some(nav) = syntax.ancestors().find_map(|node| {
59 match_ast! { 60 match_ast! {
60 match node { 61 match node {
61 ast::FnDef(it) => { 62 ast::Fn(it) => {
62 let def = sema.to_def(&it)?; 63 let def = sema.to_def(&it)?;
63 Some(def.to_nav(sema.db)) 64 Some(def.to_nav(sema.db))
64 }, 65 },
@@ -94,9 +95,9 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
94 if let Some(func_target) = match &call_node { 95 if let Some(func_target) = match &call_node {
95 FnCallNode::CallExpr(expr) => { 96 FnCallNode::CallExpr(expr) => {
96 //FIXME: Type::as_callable is broken 97 //FIXME: Type::as_callable is broken
97 let callable_def = sema.type_of_expr(&expr.expr()?)?.as_callable()?; 98 let callable = sema.type_of_expr(&expr.expr()?)?.as_callable(db)?;
98 match callable_def { 99 match callable.kind() {
99 hir::CallableDef::FunctionId(it) => { 100 hir::CallableKind::Function(it) => {
100 let fn_def: hir::Function = it.into(); 101 let fn_def: hir::Function = it.into();
101 let nav = fn_def.to_nav(db); 102 let nav = fn_def.to_nav(db);
102 Some(nav) 103 Some(nav)
@@ -108,10 +109,6 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
108 let function = sema.resolve_method_call(&expr)?; 109 let function = sema.resolve_method_call(&expr)?;
109 Some(function.to_nav(db)) 110 Some(function.to_nav(db))
110 } 111 }
111 FnCallNode::MacroCallExpr(macro_call) => {
112 let macro_def = sema.resolve_macro_call(&macro_call)?;
113 Some(macro_def.to_nav(db))
114 }
115 } { 112 } {
116 Some((func_target, name_ref.syntax().text_range())) 113 Some((func_target, name_ref.syntax().text_range()))
117 } else { 114 } else {
@@ -157,7 +154,8 @@ mod tests {
157 let nav = navs.pop().unwrap(); 154 let nav = navs.pop().unwrap();
158 nav.assert_match(expected); 155 nav.assert_match(expected);
159 156
160 let item_pos = FilePosition { file_id: nav.file_id(), offset: nav.range().start() }; 157 let item_pos =
158 FilePosition { file_id: nav.file_id, offset: nav.focus_or_full_range().start() };
161 let incoming_calls = analysis.incoming_calls(item_pos).unwrap().unwrap(); 159 let incoming_calls = analysis.incoming_calls(item_pos).unwrap().unwrap();
162 assert_eq!(incoming_calls.len(), expected_incoming.len()); 160 assert_eq!(incoming_calls.len(), expected_incoming.len());
163 161
@@ -183,8 +181,8 @@ fn caller() {
183 call<|>ee(); 181 call<|>ee();
184} 182}
185"#, 183"#,
186 "callee FN_DEF FileId(1) 0..14 3..9", 184 "callee FN FileId(1) 0..14 3..9",
187 &["caller FN_DEF FileId(1) 15..44 18..24 : [33..39]"], 185 &["caller FN FileId(1) 15..44 18..24 : [33..39]"],
188 &[], 186 &[],
189 ); 187 );
190 } 188 }
@@ -199,8 +197,8 @@ fn caller() {
199 callee(); 197 callee();
200} 198}
201"#, 199"#,
202 "callee FN_DEF FileId(1) 0..14 3..9", 200 "callee FN FileId(1) 0..14 3..9",
203 &["caller FN_DEF FileId(1) 15..44 18..24 : [33..39]"], 201 &["caller FN FileId(1) 15..44 18..24 : [33..39]"],
204 &[], 202 &[],
205 ); 203 );
206 } 204 }
@@ -216,8 +214,8 @@ fn caller() {
216 callee(); 214 callee();
217} 215}
218"#, 216"#,
219 "callee FN_DEF FileId(1) 0..14 3..9", 217 "callee FN FileId(1) 0..14 3..9",
220 &["caller FN_DEF FileId(1) 15..58 18..24 : [33..39, 47..53]"], 218 &["caller FN FileId(1) 15..58 18..24 : [33..39, 47..53]"],
221 &[], 219 &[],
222 ); 220 );
223 } 221 }
@@ -236,10 +234,10 @@ fn caller2() {
236 callee(); 234 callee();
237} 235}
238"#, 236"#,
239 "callee FN_DEF FileId(1) 0..14 3..9", 237 "callee FN FileId(1) 0..14 3..9",
240 &[ 238 &[
241 "caller1 FN_DEF FileId(1) 15..45 18..25 : [34..40]", 239 "caller1 FN FileId(1) 15..45 18..25 : [34..40]",
242 "caller2 FN_DEF FileId(1) 47..77 50..57 : [66..72]", 240 "caller2 FN FileId(1) 47..77 50..57 : [66..72]",
243 ], 241 ],
244 &[], 242 &[],
245 ); 243 );
@@ -265,10 +263,10 @@ mod tests {
265 } 263 }
266} 264}
267"#, 265"#,
268 "callee FN_DEF FileId(1) 0..14 3..9", 266 "callee FN FileId(1) 0..14 3..9",
269 &[ 267 &[
270 "caller1 FN_DEF FileId(1) 15..45 18..25 : [34..40]", 268 "caller1 FN FileId(1) 15..45 18..25 : [34..40]",
271 "test_caller FN_DEF FileId(1) 95..149 110..121 : [134..140]", 269 "test_caller FN FileId(1) 95..149 110..121 : [134..140]",
272 ], 270 ],
273 &[], 271 &[],
274 ); 272 );
@@ -289,8 +287,8 @@ fn caller() {
289//- /foo/mod.rs 287//- /foo/mod.rs
290pub fn callee() {} 288pub fn callee() {}
291"#, 289"#,
292 "callee FN_DEF FileId(2) 0..18 7..13", 290 "callee FN FileId(2) 0..18 7..13",
293 &["caller FN_DEF FileId(1) 27..56 30..36 : [45..51]"], 291 &["caller FN FileId(1) 27..56 30..36 : [45..51]"],
294 &[], 292 &[],
295 ); 293 );
296 } 294 }
@@ -306,9 +304,9 @@ fn call<|>er() {
306 callee(); 304 callee();
307} 305}
308"#, 306"#,
309 "caller FN_DEF FileId(1) 15..58 18..24", 307 "caller FN FileId(1) 15..58 18..24",
310 &[], 308 &[],
311 &["callee FN_DEF FileId(1) 0..14 3..9 : [33..39, 47..53]"], 309 &["callee FN FileId(1) 0..14 3..9 : [33..39, 47..53]"],
312 ); 310 );
313 } 311 }
314 312
@@ -327,9 +325,9 @@ fn call<|>er() {
327//- /foo/mod.rs 325//- /foo/mod.rs
328pub fn callee() {} 326pub fn callee() {}
329"#, 327"#,
330 "caller FN_DEF FileId(1) 27..56 30..36", 328 "caller FN FileId(1) 27..56 30..36",
331 &[], 329 &[],
332 &["callee FN_DEF FileId(2) 0..18 7..13 : [45..51]"], 330 &["callee FN FileId(2) 0..18 7..13 : [45..51]"],
333 ); 331 );
334 } 332 }
335 333
@@ -350,9 +348,46 @@ fn caller3() {
350 348
351} 349}
352"#, 350"#,
353 "caller2 FN_DEF FileId(1) 33..64 36..43", 351 "caller2 FN FileId(1) 33..64 36..43",
354 &["caller1 FN_DEF FileId(1) 0..31 3..10 : [19..26]"], 352 &["caller1 FN FileId(1) 0..31 3..10 : [19..26]"],
355 &["caller3 FN_DEF FileId(1) 66..83 69..76 : [52..59]"], 353 &["caller3 FN FileId(1) 66..83 69..76 : [52..59]"],
354 );
355 }
356
357 #[test]
358 fn test_call_hierarchy_issue_5103() {
359 check_hierarchy(
360 r#"
361fn a() {
362 b()
363}
364
365fn b() {}
366
367fn main() {
368 a<|>()
369}
370"#,
371 "a FN FileId(1) 0..18 3..4",
372 &["main FN FileId(1) 31..52 34..38 : [47..48]"],
373 &["b FN FileId(1) 20..29 23..24 : [13..14]"],
374 );
375
376 check_hierarchy(
377 r#"
378fn a() {
379 b<|>()
380}
381
382fn b() {}
383
384fn main() {
385 a()
386}
387"#,
388 "b FN FileId(1) 20..29 23..24",
389 &["a FN FileId(1) 0..18 3..4 : [13..14]"],
390 &[],
356 ); 391 );
357 } 392 }
358} 393}
diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs
index a6bdf1c9d..ff602202f 100644
--- a/crates/ra_ide/src/call_info.rs
+++ b/crates/ra_ide/src/call_info.rs
@@ -1,13 +1,43 @@
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::{CallInfo, FilePosition, FunctionSignature}; 12use crate::FilePosition;
13
14/// Contains information about a call site. Specifically the
15/// `FunctionSignature`and current parameter.
16#[derive(Debug)]
17pub struct CallInfo {
18 pub doc: Option<String>,
19 pub signature: String,
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 }
40}
11 41
12/// Computes parameter information for the given call expression. 42/// Computes parameter information for the given call expression.
13pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> { 43pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> {
@@ -16,106 +46,135 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
16 let file = file.syntax(); 46 let file = file.syntax();
17 let token = file.token_at_offset(position.offset).next()?; 47 let token = file.token_at_offset(position.offset).next()?;
18 let token = sema.descend_into_macros(token); 48 let token = sema.descend_into_macros(token);
19 call_info_for_token(&sema, token)
20}
21 49
22#[derive(Debug)] 50 let (callable, active_parameter) = call_info_impl(&sema, token)?;
23pub(crate) struct ActiveParameter {
24 /// FIXME: should be `Type` and `Name
25 pub(crate) ty: String,
26 pub(crate) name: String,
27}
28 51
29impl ActiveParameter { 52 let mut res =
30 pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> { 53 CallInfo { doc: None, signature: String::new(), parameters: vec![], active_parameter };
31 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 }
73 hir::CallableKind::Closure => (),
32 } 74 }
33 75
34 pub(crate) fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> { 76 res.signature.push('(');
35 call_info_for_token(sema, token)?.into_active_parameter() 77 {
78 if let Some(self_param) = callable.receiver_param(db) {
79 format_to!(res.signature, "{}", self_param)
80 }
81 let mut buf = String::new();
82 for (pat, ty) in callable.params(db) {
83 buf.clear();
84 if let Some(pat) = pat {
85 match pat {
86 Either::Left(_self) => format_to!(buf, "self: "),
87 Either::Right(pat) => format_to!(buf, "{}: ", pat),
88 }
89 }
90 format_to!(buf, "{}", ty.display(db));
91 res.push_param(&buf);
92 }
36 } 93 }
94 res.signature.push(')');
95
96 match callable.kind() {
97 hir::CallableKind::Function(_) | hir::CallableKind::Closure => {
98 let ret_type = callable.return_type();
99 if !ret_type.is_unit() {
100 format_to!(res.signature, " -> {}", ret_type.display(db));
101 }
102 }
103 hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}
104 }
105 Some(res)
37} 106}
38 107
39fn call_info_for_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<CallInfo> { 108fn call_info_impl(
109 sema: &Semantics<RootDatabase>,
110 token: SyntaxToken,
111) -> Option<(hir::Callable, Option<usize>)> {
40 // Find the calling expression and it's NameRef 112 // Find the calling expression and it's NameRef
41 let calling_node = FnCallNode::with_node(&token.parent())?; 113 let calling_node = FnCallNode::with_node(&token.parent())?;
42 114
43 let (mut call_info, has_self) = match &calling_node { 115 let callable = match &calling_node {
44 FnCallNode::CallExpr(call) => { 116 FnCallNode::CallExpr(call) => sema.type_of_expr(&call.expr()?)?.as_callable(sema.db)?,
45 //FIXME: Type::as_callable is broken 117 FnCallNode::MethodCallExpr(call) => sema.resolve_method_call_as_callable(call)?,
46 let callable_def = sema.type_of_expr(&call.expr()?)?.as_callable()?; 118 };
47 match callable_def { 119 let active_param = if let Some(arg_list) = calling_node.arg_list() {
48 hir::CallableDef::FunctionId(it) => { 120 // Number of arguments specified at the call site
49 let fn_def = it.into(); 121 let num_args_at_callsite = arg_list.args().count();
50 (CallInfo::with_fn(sema.db, fn_def), fn_def.has_self_param(sema.db)) 122
51 } 123 let arg_list_range = arg_list.syntax().text_range();
52 hir::CallableDef::StructId(it) => { 124 if !arg_list_range.contains_inclusive(token.text_range().start()) {
53 (CallInfo::with_struct(sema.db, it.into())?, false) 125 mark::hit!(call_info_bad_offset);
54 } 126 return None;
55 hir::CallableDef::EnumVariantId(it) => {
56 (CallInfo::with_enum_variant(sema.db, it.into())?, false)
57 }
58 }
59 }
60 FnCallNode::MethodCallExpr(method_call) => {
61 let function = sema.resolve_method_call(&method_call)?;
62 (CallInfo::with_fn(sema.db, function), function.has_self_param(sema.db))
63 }
64 FnCallNode::MacroCallExpr(macro_call) => {
65 let macro_def = sema.resolve_macro_call(&macro_call)?;
66 (CallInfo::with_macro(sema.db, macro_def)?, false)
67 } 127 }
128 let param = std::cmp::min(
129 num_args_at_callsite,
130 arg_list
131 .args()
132 .take_while(|arg| arg.syntax().text_range().end() <= token.text_range().start())
133 .count(),
134 );
135
136 Some(param)
137 } else {
138 None
68 }; 139 };
140 Some((callable, active_param))
141}
69 142
70 // If we have a calling expression let's find which argument we are on 143#[derive(Debug)]
71 let num_params = call_info.parameters().len(); 144pub(crate) struct ActiveParameter {
145 pub(crate) ty: Type,
146 pub(crate) name: String,
147}
72 148
73 match num_params { 149impl ActiveParameter {
74 0 => (), 150 pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> {
75 1 => { 151 let sema = Semantics::new(db);
76 if !has_self { 152 let file = sema.parse(position.file_id);
77 call_info.active_parameter = Some(0); 153 let file = file.syntax();
78 } 154 let token = file.token_at_offset(position.offset).next()?;
79 } 155 let token = sema.descend_into_macros(token);
80 _ => { 156 Self::at_token(&sema, token)
81 if let Some(arg_list) = calling_node.arg_list() { 157 }
82 // Number of arguments specified at the call site
83 let num_args_at_callsite = arg_list.args().count();
84
85 let arg_list_range = arg_list.syntax().text_range();
86 if !arg_list_range.contains_inclusive(token.text_range().start()) {
87 mark::hit!(call_info_bad_offset);
88 return None;
89 }
90 158
91 let mut param = std::cmp::min( 159 pub(crate) fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> {
92 num_args_at_callsite, 160 let (signature, active_parameter) = call_info_impl(&sema, token)?;
93 arg_list
94 .args()
95 .take_while(|arg| {
96 arg.syntax().text_range().end() < token.text_range().start()
97 })
98 .count(),
99 );
100
101 // If we are in a method account for `self`
102 if has_self {
103 param += 1;
104 }
105 161
106 call_info.active_parameter = Some(param); 162 let idx = active_parameter?;
107 } 163 let mut params = signature.params(sema.db);
164 if !(idx < params.len()) {
165 mark::hit!(too_many_arguments);
166 return None;
108 } 167 }
168 let (pat, ty) = params.swap_remove(idx);
169 let name = pat?.to_string();
170 Some(ActiveParameter { ty, name })
109 } 171 }
110
111 Some(call_info)
112} 172}
113 173
114#[derive(Debug)] 174#[derive(Debug)]
115pub(crate) enum FnCallNode { 175pub(crate) enum FnCallNode {
116 CallExpr(ast::CallExpr), 176 CallExpr(ast::CallExpr),
117 MethodCallExpr(ast::MethodCallExpr), 177 MethodCallExpr(ast::MethodCallExpr),
118 MacroCallExpr(ast::MacroCall),
119} 178}
120 179
121impl FnCallNode { 180impl FnCallNode {
@@ -131,7 +190,6 @@ impl FnCallNode {
131 } 190 }
132 Some(FnCallNode::MethodCallExpr(it)) 191 Some(FnCallNode::MethodCallExpr(it))
133 }, 192 },
134 ast::MacroCall(it) => Some(FnCallNode::MacroCallExpr(it)),
135 _ => None, 193 _ => None,
136 } 194 }
137 } 195 }
@@ -143,7 +201,6 @@ impl FnCallNode {
143 match node { 201 match node {
144 ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)), 202 ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)),
145 ast::MethodCallExpr(it) => Some(FnCallNode::MethodCallExpr(it)), 203 ast::MethodCallExpr(it) => Some(FnCallNode::MethodCallExpr(it)),
146 ast::MacroCall(it) => Some(FnCallNode::MacroCallExpr(it)),
147 _ => None, 204 _ => None,
148 } 205 }
149 } 206 }
@@ -159,8 +216,6 @@ impl FnCallNode {
159 FnCallNode::MethodCallExpr(call_expr) => { 216 FnCallNode::MethodCallExpr(call_expr) => {
160 call_expr.syntax().children().filter_map(ast::NameRef::cast).next() 217 call_expr.syntax().children().filter_map(ast::NameRef::cast).next()
161 } 218 }
162
163 FnCallNode::MacroCallExpr(call_expr) => call_expr.path()?.segment()?.name_ref(),
164 } 219 }
165 } 220 }
166 221
@@ -168,214 +223,209 @@ impl FnCallNode {
168 match self { 223 match self {
169 FnCallNode::CallExpr(expr) => expr.arg_list(), 224 FnCallNode::CallExpr(expr) => expr.arg_list(),
170 FnCallNode::MethodCallExpr(expr) => expr.arg_list(), 225 FnCallNode::MethodCallExpr(expr) => expr.arg_list(),
171 FnCallNode::MacroCallExpr(_) => None,
172 } 226 }
173 } 227 }
174} 228}
175 229
176impl CallInfo {
177 fn into_active_parameter(self) -> Option<ActiveParameter> {
178 let idx = self.active_parameter?;
179 let ty = self.signature.parameter_types.get(idx)?.clone();
180 let name = self.signature.parameter_names.get(idx)?.clone();
181 let res = ActiveParameter { ty, name };
182 Some(res)
183 }
184
185 fn with_fn(db: &RootDatabase, function: hir::Function) -> Self {
186 let signature = FunctionSignature::from_hir(db, function);
187
188 CallInfo { signature, active_parameter: None }
189 }
190
191 fn with_struct(db: &RootDatabase, st: hir::Struct) -> Option<Self> {
192 let signature = FunctionSignature::from_struct(db, st)?;
193
194 Some(CallInfo { signature, active_parameter: None })
195 }
196
197 fn with_enum_variant(db: &RootDatabase, variant: hir::EnumVariant) -> Option<Self> {
198 let signature = FunctionSignature::from_enum_variant(db, variant)?;
199
200 Some(CallInfo { signature, active_parameter: None })
201 }
202
203 fn with_macro(db: &RootDatabase, macro_def: hir::MacroDef) -> Option<Self> {
204 let signature = FunctionSignature::from_macro(db, macro_def)?;
205
206 Some(CallInfo { signature, active_parameter: None })
207 }
208
209 fn parameters(&self) -> &[String] {
210 &self.signature.parameters
211 }
212}
213
214#[cfg(test)] 230#[cfg(test)]
215mod tests { 231mod tests {
232 use expect::{expect, Expect};
216 use test_utils::mark; 233 use test_utils::mark;
217 234
218 use crate::mock_analysis::analysis_and_position; 235 use crate::mock_analysis::analysis_and_position;
219 236
220 use super::*; 237 fn check(ra_fixture: &str, expect: Expect) {
221 238 let (analysis, position) = analysis_and_position(ra_fixture);
222 // These are only used when testing 239 let call_info = analysis.call_info(position).unwrap();
223 impl CallInfo { 240 let actual = match call_info {
224 fn doc(&self) -> Option<hir::Documentation> { 241 Some(call_info) => {
225 self.signature.doc.clone() 242 let docs = match &call_info.doc {
226 } 243 None => "".to_string(),
227 244 Some(docs) => format!("{}\n------\n", docs.as_str()),
228 fn label(&self) -> String { 245 };
229 self.signature.to_string() 246 let params = call_info
230 } 247 .parameter_labels()
231 } 248 .enumerate()
232 249 .map(|(i, param)| {
233 fn call_info_helper(text: &str) -> Option<CallInfo> { 250 if Some(i) == call_info.active_parameter {
234 let (analysis, position) = analysis_and_position(text); 251 format!("<{}>", param)
235 analysis.call_info(position).unwrap() 252 } else {
236 } 253 param.to_string()
237 254 }
238 fn call_info(text: &str) -> CallInfo { 255 })
239 let info = call_info_helper(text); 256 .collect::<Vec<_>>()
240 assert!(info.is_some()); 257 .join(", ");
241 info.unwrap() 258 format!("{}{}\n({})\n", docs, call_info.signature, params)
242 } 259 }
243 260 None => String::new(),
244 fn no_call_info(text: &str) { 261 };
245 let info = call_info_helper(text); 262 expect.assert_eq(&actual);
246 assert!(info.is_none());
247 } 263 }
248 264
249 #[test] 265 #[test]
250 fn test_fn_signature_two_args_firstx() { 266 fn test_fn_signature_two_args() {
251 let info = call_info( 267 check(
252 r#"fn foo(x: u32, y: u32) -> u32 {x + y} 268 r#"
253fn bar() { foo(<|>3, ); }"#, 269fn foo(x: u32, y: u32) -> u32 {x + y}
270fn bar() { foo(<|>3, ); }
271"#,
272 expect![[r#"
273 fn foo(x: u32, y: u32) -> u32
274 (<x: u32>, y: u32)
275 "#]],
254 ); 276 );
255 277 check(
256 assert_eq!(info.parameters(), ["x: u32", "y: u32"]); 278 r#"
257 assert_eq!(info.active_parameter, Some(0)); 279fn foo(x: u32, y: u32) -> u32 {x + y}
258 } 280fn bar() { foo(3<|>, ); }
259 281"#,
260 #[test] 282 expect![[r#"
261 fn test_fn_signature_two_args_second() { 283 fn foo(x: u32, y: u32) -> u32
262 let info = call_info( 284 (<x: u32>, y: u32)
263 r#"fn foo(x: u32, y: u32) -> u32 {x + y} 285 "#]],
264fn bar() { foo(3, <|>); }"#, 286 );
287 check(
288 r#"
289fn foo(x: u32, y: u32) -> u32 {x + y}
290fn bar() { foo(3,<|> ); }
291"#,
292 expect![[r#"
293 fn foo(x: u32, y: u32) -> u32
294 (x: u32, <y: u32>)
295 "#]],
296 );
297 check(
298 r#"
299fn foo(x: u32, y: u32) -> u32 {x + y}
300fn bar() { foo(3, <|>); }
301"#,
302 expect![[r#"
303 fn foo(x: u32, y: u32) -> u32
304 (x: u32, <y: u32>)
305 "#]],
265 ); 306 );
266
267 assert_eq!(info.parameters(), ["x: u32", "y: u32"]);
268 assert_eq!(info.active_parameter, Some(1));
269 } 307 }
270 308
271 #[test] 309 #[test]
272 fn test_fn_signature_two_args_empty() { 310 fn test_fn_signature_two_args_empty() {
273 let info = call_info( 311 check(
274 r#"fn foo(x: u32, y: u32) -> u32 {x + y} 312 r#"
275fn bar() { foo(<|>); }"#, 313fn foo(x: u32, y: u32) -> u32 {x + y}
314fn bar() { foo(<|>); }
315"#,
316 expect![[r#"
317 fn foo(x: u32, y: u32) -> u32
318 (<x: u32>, y: u32)
319 "#]],
276 ); 320 );
277
278 assert_eq!(info.parameters(), ["x: u32", "y: u32"]);
279 assert_eq!(info.active_parameter, Some(0));
280 } 321 }
281 322
282 #[test] 323 #[test]
283 fn test_fn_signature_two_args_first_generics() { 324 fn test_fn_signature_two_args_first_generics() {
284 let info = call_info( 325 check(
285 r#"fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 where T: Copy + Display, U: Debug {x + y}
286fn bar() { foo(<|>3, ); }"#,
287 );
288
289 assert_eq!(info.parameters(), ["x: T", "y: U"]);
290 assert_eq!(
291 info.label(),
292 r#" 326 r#"
293fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 327fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
294where T: Copy + Display, 328 where T: Copy + Display, U: Debug
295 U: Debug 329{ x + y }
296 "# 330
297 .trim() 331fn bar() { foo(<|>3, ); }
332"#,
333 expect![[r#"
334 fn foo(x: i32, y: {unknown}) -> u32
335 (<x: i32>, y: {unknown})
336 "#]],
298 ); 337 );
299 assert_eq!(info.active_parameter, Some(0));
300 } 338 }
301 339
302 #[test] 340 #[test]
303 fn test_fn_signature_no_params() { 341 fn test_fn_signature_no_params() {
304 let info = call_info( 342 check(
305 r#"fn foo<T>() -> T where T: Copy + Display {}
306fn bar() { foo(<|>); }"#,
307 );
308
309 assert!(info.parameters().is_empty());
310 assert_eq!(
311 info.label(),
312 r#" 343 r#"
313fn foo<T>() -> T 344fn foo<T>() -> T where T: Copy + Display {}
314where T: Copy + Display 345fn bar() { foo(<|>); }
315 "# 346"#,
316 .trim() 347 expect![[r#"
348 fn foo() -> {unknown}
349 ()
350 "#]],
317 ); 351 );
318 assert!(info.active_parameter.is_none());
319 } 352 }
320 353
321 #[test] 354 #[test]
322 fn test_fn_signature_for_impl() { 355 fn test_fn_signature_for_impl() {
323 let info = call_info( 356 check(
324 r#"struct F; impl F { pub fn new() { F{}} } 357 r#"
325fn bar() {let _ : F = F::new(<|>);}"#, 358struct F;
359impl F { pub fn new() { } }
360fn bar() {
361 let _ : F = F::new(<|>);
362}
363"#,
364 expect![[r#"
365 fn new()
366 ()
367 "#]],
326 ); 368 );
327
328 assert!(info.parameters().is_empty());
329 assert_eq!(info.active_parameter, None);
330 } 369 }
331 370
332 #[test] 371 #[test]
333 fn test_fn_signature_for_method_self() { 372 fn test_fn_signature_for_method_self() {
334 let info = call_info( 373 check(
335 r#"struct F; 374 r#"
336impl F { 375struct S;
337 pub fn new() -> F{ 376impl S { pub fn do_it(&self) {} }
338 F{}
339 }
340
341 pub fn do_it(&self) {}
342}
343 377
344fn bar() { 378fn bar() {
345 let f : F = F::new(); 379 let s: S = S;
346 f.do_it(<|>); 380 s.do_it(<|>);
347}"#, 381}
382"#,
383 expect![[r#"
384 fn do_it(&self)
385 ()
386 "#]],
348 ); 387 );
349
350 assert_eq!(info.parameters(), ["&self"]);
351 assert_eq!(info.active_parameter, None);
352 } 388 }
353 389
354 #[test] 390 #[test]
355 fn test_fn_signature_for_method_with_arg() { 391 fn test_fn_signature_for_method_with_arg() {
356 let info = call_info( 392 check(
357 r#"struct F; 393 r#"
358impl F { 394struct S;
359 pub fn new() -> F{ 395impl S {
360 F{} 396 fn foo(&self, x: i32) {}
397}
398
399fn main() { S.foo(<|>); }
400"#,
401 expect![[r#"
402 fn foo(&self, x: i32)
403 (<x: i32>)
404 "#]],
405 );
361 } 406 }
362 407
363 pub fn do_it(&self, x: i32) {} 408 #[test]
409 fn test_fn_signature_for_method_with_arg_as_assoc_fn() {
410 check(
411 r#"
412struct S;
413impl S {
414 fn foo(&self, x: i32) {}
364} 415}
365 416
366fn bar() { 417fn main() { S::foo(<|>); }
367 let f : F = F::new(); 418"#,
368 f.do_it(<|>); 419 expect![[r#"
369}"#, 420 fn foo(self: &S, x: i32)
421 (<self: &S>, x: i32)
422 "#]],
370 ); 423 );
371
372 assert_eq!(info.parameters(), ["&self", "x: i32"]);
373 assert_eq!(info.active_parameter, Some(1));
374 } 424 }
375 425
376 #[test] 426 #[test]
377 fn test_fn_signature_with_docs_simple() { 427 fn test_fn_signature_with_docs_simple() {
378 let info = call_info( 428 check(
379 r#" 429 r#"
380/// test 430/// test
381// non-doc-comment 431// non-doc-comment
@@ -387,17 +437,18 @@ fn bar() {
387 let _ = foo(<|>); 437 let _ = foo(<|>);
388} 438}
389"#, 439"#,
440 expect![[r#"
441 test
442 ------
443 fn foo(j: u32) -> u32
444 (<j: u32>)
445 "#]],
390 ); 446 );
391
392 assert_eq!(info.parameters(), ["j: u32"]);
393 assert_eq!(info.active_parameter, Some(0));
394 assert_eq!(info.label(), "fn foo(j: u32) -> u32");
395 assert_eq!(info.doc().map(|it| it.into()), Some("test".to_string()));
396 } 447 }
397 448
398 #[test] 449 #[test]
399 fn test_fn_signature_with_docs() { 450 fn test_fn_signature_with_docs() {
400 let info = call_info( 451 check(
401 r#" 452 r#"
402/// Adds one to the number given. 453/// Adds one to the number given.
403/// 454///
@@ -415,31 +466,26 @@ pub fn add_one(x: i32) -> i32 {
415pub fn do() { 466pub fn do() {
416 add_one(<|> 467 add_one(<|>
417}"#, 468}"#,
418 ); 469 expect![[r##"
419 470 Adds one to the number given.
420 assert_eq!(info.parameters(), ["x: i32"]);
421 assert_eq!(info.active_parameter, Some(0));
422 assert_eq!(info.label(), "pub fn add_one(x: i32) -> i32");
423 assert_eq!(
424 info.doc().map(|it| it.into()),
425 Some(
426 r#"Adds one to the number given.
427 471
428# Examples 472 # Examples
429 473
430``` 474 ```
431let five = 5; 475 let five = 5;
432 476
433assert_eq!(6, my_crate::add_one(5)); 477 assert_eq!(6, my_crate::add_one(5));
434```"# 478 ```
435 .to_string() 479 ------
436 ) 480 fn add_one(x: i32) -> i32
481 (<x: i32>)
482 "##]],
437 ); 483 );
438 } 484 }
439 485
440 #[test] 486 #[test]
441 fn test_fn_signature_with_docs_impl() { 487 fn test_fn_signature_with_docs_impl() {
442 let info = call_info( 488 check(
443 r#" 489 r#"
444struct addr; 490struct addr;
445impl addr { 491impl addr {
@@ -460,32 +506,28 @@ impl addr {
460pub fn do_it() { 506pub fn do_it() {
461 addr {}; 507 addr {};
462 addr::add_one(<|>); 508 addr::add_one(<|>);
463}"#, 509}
464 ); 510"#,
465 511 expect![[r##"
466 assert_eq!(info.parameters(), ["x: i32"]); 512 Adds one to the number given.
467 assert_eq!(info.active_parameter, Some(0));
468 assert_eq!(info.label(), "pub fn add_one(x: i32) -> i32");
469 assert_eq!(
470 info.doc().map(|it| it.into()),
471 Some(
472 r#"Adds one to the number given.
473 513
474# Examples 514 # Examples
475 515
476``` 516 ```
477let five = 5; 517 let five = 5;
478 518
479assert_eq!(6, my_crate::add_one(5)); 519 assert_eq!(6, my_crate::add_one(5));
480```"# 520 ```
481 .to_string() 521 ------
482 ) 522 fn add_one(x: i32) -> i32
523 (<x: i32>)
524 "##]],
483 ); 525 );
484 } 526 }
485 527
486 #[test] 528 #[test]
487 fn test_fn_signature_with_docs_from_actix() { 529 fn test_fn_signature_with_docs_from_actix() {
488 let info = call_info( 530 check(
489 r#" 531 r#"
490struct WriteHandler<E>; 532struct WriteHandler<E>;
491 533
@@ -509,101 +551,89 @@ impl<E> WriteHandler<E> {
509pub fn foo(mut r: WriteHandler<()>) { 551pub fn foo(mut r: WriteHandler<()>) {
510 r.finished(<|>); 552 r.finished(<|>);
511} 553}
512
513"#, 554"#,
514 ); 555 expect![[r#"
515 556 Method is called when writer finishes.
516 assert_eq!(info.label(), "fn finished(&mut self, ctx: &mut Self::Context)".to_string()); 557
517 assert_eq!(info.parameters(), ["&mut self", "ctx: &mut Self::Context"]); 558 By default this method stops actor's `Context`.
518 assert_eq!(info.active_parameter, Some(1)); 559 ------
519 assert_eq!( 560 fn finished(&mut self, ctx: &mut {unknown})
520 info.doc().map(|it| it.into()), 561 (<ctx: &mut {unknown}>)
521 Some( 562 "#]],
522 r#"Method is called when writer finishes.
523
524By default this method stops actor's `Context`."#
525 .to_string()
526 )
527 ); 563 );
528 } 564 }
529 565
530 #[test] 566 #[test]
531 fn call_info_bad_offset() { 567 fn call_info_bad_offset() {
532 mark::check!(call_info_bad_offset); 568 mark::check!(call_info_bad_offset);
533 let (analysis, position) = analysis_and_position( 569 check(
534 r#"fn foo(x: u32, y: u32) -> u32 {x + y} 570 r#"
535 fn bar() { foo <|> (3, ); }"#, 571fn foo(x: u32, y: u32) -> u32 {x + y}
572fn bar() { foo <|> (3, ); }
573"#,
574 expect![[""]],
536 ); 575 );
537 let call_info = analysis.call_info(position).unwrap();
538 assert!(call_info.is_none());
539 } 576 }
540 577
541 #[test] 578 #[test]
542 fn test_nested_method_in_lamba() { 579 fn test_nested_method_in_lambda() {
543 let info = call_info( 580 check(
544 r#"struct Foo; 581 r#"
545 582struct Foo;
546impl Foo { 583impl Foo { fn bar(&self, _: u32) { } }
547 fn bar(&self, _: u32) { }
548}
549 584
550fn bar(_: u32) { } 585fn bar(_: u32) { }
551 586
552fn main() { 587fn main() {
553 let foo = Foo; 588 let foo = Foo;
554 std::thread::spawn(move || foo.bar(<|>)); 589 std::thread::spawn(move || foo.bar(<|>));
555}"#, 590}
591"#,
592 expect![[r#"
593 fn bar(&self, _: u32)
594 (<_: u32>)
595 "#]],
556 ); 596 );
557
558 assert_eq!(info.parameters(), ["&self", "_: u32"]);
559 assert_eq!(info.active_parameter, Some(1));
560 assert_eq!(info.label(), "fn bar(&self, _: u32)");
561 } 597 }
562 598
563 #[test] 599 #[test]
564 fn works_for_tuple_structs() { 600 fn works_for_tuple_structs() {
565 let info = call_info( 601 check(
566 r#" 602 r#"
567/// A cool tuple struct 603/// A cool tuple struct
568struct TS(u32, i32); 604struct S(u32, i32);
569fn main() { 605fn main() {
570 let s = TS(0, <|>); 606 let s = S(0, <|>);
571}"#, 607}
608"#,
609 expect![[r#"
610 A cool tuple struct
611 ------
612 struct S(u32, i32)
613 (u32, <i32>)
614 "#]],
572 ); 615 );
573
574 assert_eq!(info.label(), "struct TS(u32, i32) -> TS");
575 assert_eq!(info.doc().map(|it| it.into()), Some("A cool tuple struct".to_string()));
576 assert_eq!(info.active_parameter, Some(1));
577 } 616 }
578 617
579 #[test] 618 #[test]
580 fn generic_struct() { 619 fn generic_struct() {
581 let info = call_info( 620 check(
582 r#" 621 r#"
583struct TS<T>(T); 622struct S<T>(T);
584fn main() { 623fn main() {
585 let s = TS(<|>); 624 let s = S(<|>);
586}"#, 625}
587 ); 626"#,
588 627 expect![[r#"
589 assert_eq!(info.label(), "struct TS<T>(T) -> TS"); 628 struct S({unknown})
590 assert_eq!(info.active_parameter, Some(0)); 629 (<{unknown}>)
591 } 630 "#]],
592
593 #[test]
594 fn cant_call_named_structs() {
595 no_call_info(
596 r#"
597struct TS { x: u32, y: i32 }
598fn main() {
599 let s = TS(<|>);
600}"#,
601 ); 631 );
602 } 632 }
603 633
604 #[test] 634 #[test]
605 fn works_for_enum_variants() { 635 fn works_for_enum_variants() {
606 let info = call_info( 636 check(
607 r#" 637 r#"
608enum E { 638enum E {
609 /// A Variant 639 /// A Variant
@@ -617,17 +647,32 @@ enum E {
617fn main() { 647fn main() {
618 let a = E::A(<|>); 648 let a = E::A(<|>);
619} 649}
620 "#, 650"#,
651 expect![[r#"
652 A Variant
653 ------
654 enum E::A(i32)
655 (<i32>)
656 "#]],
621 ); 657 );
658 }
622 659
623 assert_eq!(info.label(), "E::A(0: i32)"); 660 #[test]
624 assert_eq!(info.doc().map(|it| it.into()), Some("A Variant".to_string())); 661 fn cant_call_struct_record() {
625 assert_eq!(info.active_parameter, Some(0)); 662 check(
663 r#"
664struct S { x: u32, y: i32 }
665fn main() {
666 let s = S(<|>);
667}
668"#,
669 expect![[""]],
670 );
626 } 671 }
627 672
628 #[test] 673 #[test]
629 fn cant_call_enum_records() { 674 fn cant_call_enum_record() {
630 no_call_info( 675 check(
631 r#" 676 r#"
632enum E { 677enum E {
633 /// A Variant 678 /// A Variant
@@ -641,47 +686,57 @@ enum E {
641fn main() { 686fn main() {
642 let a = E::C(<|>); 687 let a = E::C(<|>);
643} 688}
644 "#, 689"#,
690 expect![[""]],
645 ); 691 );
646 } 692 }
647 693
648 #[test] 694 #[test]
649 fn fn_signature_for_macro() { 695 fn fn_signature_for_call_in_macro() {
650 let info = call_info( 696 check(
651 r#" 697 r#"
652/// empty macro 698macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
653macro_rules! foo { 699fn foo() { }
654 () => {} 700id! {
701 fn bar() { foo(<|>); }
655} 702}
703"#,
704 expect![[r#"
705 fn foo()
706 ()
707 "#]],
708 );
709 }
656 710
657fn f() { 711 #[test]
658 foo!(<|>); 712 fn call_info_for_lambdas() {
713 check(
714 r#"
715struct S;
716fn foo(s: S) -> i32 { 92 }
717fn main() {
718 (|s| foo(s))(<|>)
659} 719}
660 "#, 720 "#,
661 ); 721 expect![[r#"
662 722 (S) -> i32
663 assert_eq!(info.label(), "foo!()"); 723 (<S>)
664 assert_eq!(info.doc().map(|it| it.into()), Some("empty macro".to_string())); 724 "#]],
725 )
665 } 726 }
666 727
667 #[test] 728 #[test]
668 fn fn_signature_for_call_in_macro() { 729 fn call_info_for_fn_ptr() {
669 let info = call_info( 730 check(
670 r#" 731 r#"
671 macro_rules! id { 732fn main(f: fn(i32, f64) -> char) {
672 ($($tt:tt)*) => { $($tt)* } 733 f(0, <|>)
673 } 734}
674 fn foo() { 735 "#,
675 736 expect![[r#"
676 } 737 (i32, f64) -> char
677 id! { 738 (i32, <f64>)
678 fn bar() { 739 "#]],
679 foo(<|>); 740 )
680 }
681 }
682 "#,
683 );
684
685 assert_eq!(info.label(), "fn foo()");
686 } 741 }
687} 742}
diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs
index e1fcf379d..68ac05e4c 100644
--- a/crates/ra_ide/src/completion.rs
+++ b/crates/ra_ide/src/completion.rs
@@ -2,6 +2,9 @@ mod completion_config;
2mod completion_item; 2mod completion_item;
3mod completion_context; 3mod completion_context;
4mod presentation; 4mod presentation;
5mod patterns;
6#[cfg(test)]
7mod test_utils;
5 8
6mod complete_attribute; 9mod complete_attribute;
7mod complete_dot; 10mod complete_dot;
@@ -15,9 +18,6 @@ mod complete_unqualified_path;
15mod complete_postfix; 18mod complete_postfix;
16mod complete_macro_in_item_position; 19mod complete_macro_in_item_position;
17mod complete_trait_impl; 20mod complete_trait_impl;
18mod patterns;
19#[cfg(test)]
20mod test_utils;
21 21
22use ra_ide_db::RootDatabase; 22use ra_ide_db::RootDatabase;
23 23
@@ -63,11 +63,11 @@ pub use crate::completion::{
63// There also snippet completions: 63// There also snippet completions:
64// 64//
65// .Expressions 65// .Expressions
66// - `pd` -> `println!("{:?}")` 66// - `pd` -> `eprintln!(" = {:?}", );`
67// - `ppd` -> `println!("{:#?}")` 67// - `ppd` -> `eprintln!(" = {:#?}", );`
68// 68//
69// .Items 69// .Items
70// - `tfn` -> `#[test] fn f(){}` 70// - `tfn` -> `#[test] fn feature(){}`
71// - `tmod` -> 71// - `tmod` ->
72// ```rust 72// ```rust
73// #[cfg(test)] 73// #[cfg(test)]
@@ -75,7 +75,7 @@ pub use crate::completion::{
75// use super::*; 75// use super::*;
76// 76//
77// #[test] 77// #[test]
78// fn test_fn() {} 78// fn test_name() {}
79// } 79// }
80// ``` 80// ```
81 81
@@ -137,8 +137,8 @@ mod tests {
137 documentation: &'a str, 137 documentation: &'a str,
138 } 138 }
139 139
140 fn check_detail_and_documentation(fixture: &str, expected: DetailAndDocumentation) { 140 fn check_detail_and_documentation(ra_fixture: &str, expected: DetailAndDocumentation) {
141 let (analysis, position) = analysis_and_position(fixture); 141 let (analysis, position) = analysis_and_position(ra_fixture);
142 let config = CompletionConfig::default(); 142 let config = CompletionConfig::default();
143 let completions = analysis.completions(&config, position).unwrap().unwrap(); 143 let completions = analysis.completions(&config, position).unwrap().unwrap();
144 for item in completions { 144 for item in completions {
diff --git a/crates/ra_ide/src/completion/complete_attribute.rs b/crates/ra_ide/src/completion/complete_attribute.rs
index 6beeca457..2faaae974 100644
--- a/crates/ra_ide/src/completion/complete_attribute.rs
+++ b/crates/ra_ide/src/completion/complete_attribute.rs
@@ -13,14 +13,18 @@ use crate::completion::{
13 13
14pub(super) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { 14pub(super) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
15 let attribute = ctx.attribute_under_caret.as_ref()?; 15 let attribute = ctx.attribute_under_caret.as_ref()?;
16 16 match (attribute.path(), attribute.token_tree()) {
17 match (attribute.path(), attribute.input()) { 17 (Some(path), Some(token_tree)) if path.to_string() == "derive" => {
18 (Some(path), Some(ast::AttrInput::TokenTree(token_tree)))
19 if path.to_string() == "derive" =>
20 {
21 complete_derive(acc, ctx, token_tree) 18 complete_derive(acc, ctx, token_tree)
22 } 19 }
23 (_, Some(ast::AttrInput::TokenTree(_token_tree))) => {} 20 (Some(path), Some(token_tree))
21 if ["allow", "warn", "deny", "forbid"]
22 .iter()
23 .any(|lint_level| lint_level == &path.to_string()) =>
24 {
25 complete_lint(acc, ctx, token_tree)
26 }
27 (_, Some(_token_tree)) => {}
24 _ => complete_attribute_start(acc, ctx, attribute), 28 _ => complete_attribute_start(acc, ctx, attribute),
25 } 29 }
26 Some(()) 30 Some(())
@@ -46,7 +50,7 @@ fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attr
46 _ => {} 50 _ => {}
47 } 51 }
48 52
49 if attribute.kind() == ast::AttrKind::Inner || !attr_completion.should_be_inner { 53 if attribute.kind() == ast::AttrKind::Inner || !attr_completion.prefer_inner {
50 acc.add(item); 54 acc.add(item);
51 } 55 }
52 } 56 }
@@ -56,163 +60,76 @@ struct AttrCompletion {
56 label: &'static str, 60 label: &'static str,
57 lookup: Option<&'static str>, 61 lookup: Option<&'static str>,
58 snippet: Option<&'static str>, 62 snippet: Option<&'static str>,
59 should_be_inner: bool, 63 prefer_inner: bool,
64}
65
66impl AttrCompletion {
67 const fn prefer_inner(self) -> AttrCompletion {
68 AttrCompletion { prefer_inner: true, ..self }
69 }
70}
71
72const fn attr(
73 label: &'static str,
74 lookup: Option<&'static str>,
75 snippet: Option<&'static str>,
76) -> AttrCompletion {
77 AttrCompletion { label, lookup, snippet, prefer_inner: false }
60} 78}
61 79
62const ATTRIBUTES: &[AttrCompletion] = &[ 80const ATTRIBUTES: &[AttrCompletion] = &[
63 AttrCompletion { 81 attr("allow(…)", Some("allow"), Some("allow(${0:lint})")),
64 label: "allow(…)", 82 attr("cfg_attr(…)", Some("cfg_attr"), Some("cfg_attr(${1:predicate}, ${0:attr})")),
65 snippet: Some("allow(${0:lint})"), 83 attr("cfg(…)", Some("cfg"), Some("cfg(${0:predicate})")),
66 should_be_inner: false, 84 attr("deny(…)", Some("deny"), Some("deny(${0:lint})")),
67 lookup: Some("allow"), 85 attr(r#"deprecated = "…""#, Some("deprecated"), Some(r#"deprecated = "${0:reason}""#)),
68 }, 86 attr("derive(…)", Some("derive"), Some(r#"derive(${0:Debug})"#)),
69 AttrCompletion { 87 attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)),
70 label: "cfg_attr(…)", 88 attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(),
71 snippet: Some("cfg_attr(${1:predicate}, ${0:attr})"), 89 attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")),
72 should_be_inner: false,
73 lookup: Some("cfg_attr"),
74 },
75 AttrCompletion {
76 label: "cfg(…)",
77 snippet: Some("cfg(${0:predicate})"),
78 should_be_inner: false,
79 lookup: Some("cfg"),
80 },
81 AttrCompletion {
82 label: "deny(…)",
83 snippet: Some("deny(${0:lint})"),
84 should_be_inner: false,
85 lookup: Some("deny"),
86 },
87 AttrCompletion {
88 label: r#"deprecated = "…""#,
89 snippet: Some(r#"deprecated = "${0:reason}""#),
90 should_be_inner: false,
91 lookup: Some("deprecated"),
92 },
93 AttrCompletion {
94 label: "derive(…)",
95 snippet: Some(r#"derive(${0:Debug})"#),
96 should_be_inner: false,
97 lookup: Some("derive"),
98 },
99 AttrCompletion {
100 label: r#"doc = "…""#,
101 snippet: Some(r#"doc = "${0:docs}""#),
102 should_be_inner: false,
103 lookup: Some("doc"),
104 },
105 AttrCompletion {
106 label: "feature(…)",
107 snippet: Some("feature(${0:flag})"),
108 should_be_inner: true,
109 lookup: Some("feature"),
110 },
111 AttrCompletion {
112 label: "forbid(…)",
113 snippet: Some("forbid(${0:lint})"),
114 should_be_inner: false,
115 lookup: Some("forbid"),
116 },
117 // FIXME: resolve through macro resolution? 90 // FIXME: resolve through macro resolution?
118 AttrCompletion { 91 attr("global_allocator", None, None).prefer_inner(),
119 label: "global_allocator", 92 attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)),
120 snippet: None, 93 attr("inline(…)", Some("inline"), Some("inline(${0:lint})")),
121 should_be_inner: true, 94 attr(r#"link_name = "…""#, Some("link_name"), Some(r#"link_name = "${0:symbol_name}""#)),
122 lookup: None, 95 attr("link", None, None),
123 }, 96 attr("macro_export", None, None),
124 AttrCompletion { 97 attr("macro_use", None, None),
125 label: "ignore(…)", 98 attr(r#"must_use = "…""#, Some("must_use"), Some(r#"must_use = "${0:reason}""#)),
126 snippet: Some("ignore(${0:lint})"), 99 attr("no_mangle", None, None),
127 should_be_inner: false, 100 attr("no_std", None, None).prefer_inner(),
128 lookup: Some("ignore"), 101 attr("non_exhaustive", None, None),
129 }, 102 attr("panic_handler", None, None).prefer_inner(),
130 AttrCompletion { 103 attr("path = \"…\"", Some("path"), Some("path =\"${0:path}\"")),
131 label: "inline(…)", 104 attr("proc_macro", None, None),
132 snippet: Some("inline(${0:lint})"), 105 attr("proc_macro_attribute", None, None),
133 should_be_inner: false, 106 attr("proc_macro_derive(…)", Some("proc_macro_derive"), Some("proc_macro_derive(${0:Trait})")),
134 lookup: Some("inline"), 107 attr("recursion_limit = …", Some("recursion_limit"), Some("recursion_limit = ${0:128}"))
135 }, 108 .prefer_inner(),
136 AttrCompletion { 109 attr("repr(…)", Some("repr"), Some("repr(${0:C})")),
137 label: r#"link_name = "…""#, 110 attr(
138 snippet: Some(r#"link_name = "${0:symbol_name}""#), 111 "should_panic(…)",
139 should_be_inner: false, 112 Some("should_panic"),
140 lookup: Some("link_name"), 113 Some(r#"should_panic(expected = "${0:reason}")"#),
141 }, 114 ),
142 AttrCompletion { label: "link", snippet: None, should_be_inner: false, lookup: None }, 115 attr(
143 AttrCompletion { label: "macro_export", snippet: None, should_be_inner: false, lookup: None }, 116 r#"target_feature = "…""#,
144 AttrCompletion { label: "macro_use", snippet: None, should_be_inner: false, lookup: None }, 117 Some("target_feature"),
145 AttrCompletion { 118 Some("target_feature = \"${0:feature}\""),
146 label: r#"must_use = "…""#, 119 ),
147 snippet: Some(r#"must_use = "${0:reason}""#), 120 attr("test", None, None),
148 should_be_inner: false, 121 attr("used", None, None),
149 lookup: Some("must_use"), 122 attr("warn(…)", Some("warn"), Some("warn(${0:lint})")),
150 }, 123 attr(
151 AttrCompletion { label: "no_mangle", snippet: None, should_be_inner: false, lookup: None }, 124 r#"windows_subsystem = "…""#,
152 AttrCompletion { label: "no_std", snippet: None, should_be_inner: true, lookup: None }, 125 Some("windows_subsystem"),
153 AttrCompletion { label: "non_exhaustive", snippet: None, should_be_inner: false, lookup: None }, 126 Some(r#"windows_subsystem = "${0:subsystem}""#),
154 AttrCompletion { label: "panic_handler", snippet: None, should_be_inner: true, lookup: None }, 127 )
155 AttrCompletion { 128 .prefer_inner(),
156 label: "path = \"…\"",
157 snippet: Some("path =\"${0:path}\""),
158 should_be_inner: false,
159 lookup: Some("path"),
160 },
161 AttrCompletion { label: "proc_macro", snippet: None, should_be_inner: false, lookup: None },
162 AttrCompletion {
163 label: "proc_macro_attribute",
164 snippet: None,
165 should_be_inner: false,
166 lookup: None,
167 },
168 AttrCompletion {
169 label: "proc_macro_derive(…)",
170 snippet: Some("proc_macro_derive(${0:Trait})"),
171 should_be_inner: false,
172 lookup: Some("proc_macro_derive"),
173 },
174 AttrCompletion {
175 label: "recursion_limit = …",
176 snippet: Some("recursion_limit = ${0:128}"),
177 should_be_inner: true,
178 lookup: Some("recursion_limit"),
179 },
180 AttrCompletion {
181 label: "repr(…)",
182 snippet: Some("repr(${0:C})"),
183 should_be_inner: false,
184 lookup: Some("repr"),
185 },
186 AttrCompletion {
187 label: "should_panic(…)",
188 snippet: Some(r#"should_panic(expected = "${0:reason}")"#),
189 should_be_inner: false,
190 lookup: Some("should_panic"),
191 },
192 AttrCompletion {
193 label: r#"target_feature = "…""#,
194 snippet: Some("target_feature = \"${0:feature}\""),
195 should_be_inner: false,
196 lookup: Some("target_feature"),
197 },
198 AttrCompletion { label: "test", snippet: None, should_be_inner: false, lookup: None },
199 AttrCompletion { label: "used", snippet: None, should_be_inner: false, lookup: None },
200 AttrCompletion {
201 label: "warn(…)",
202 snippet: Some("warn(${0:lint})"),
203 should_be_inner: false,
204 lookup: Some("warn"),
205 },
206 AttrCompletion {
207 label: r#"windows_subsystem = "…""#,
208 snippet: Some(r#"windows_subsystem = "${0:subsystem}""#),
209 should_be_inner: true,
210 lookup: Some("windows_subsystem"),
211 },
212]; 129];
213 130
214fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input: ast::TokenTree) { 131fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input: ast::TokenTree) {
215 if let Ok(existing_derives) = parse_derive_input(derive_input) { 132 if let Ok(existing_derives) = parse_comma_sep_input(derive_input) {
216 for derive_completion in DEFAULT_DERIVE_COMPLETIONS 133 for derive_completion in DEFAULT_DERIVE_COMPLETIONS
217 .into_iter() 134 .into_iter()
218 .filter(|completion| !existing_derives.contains(completion.label)) 135 .filter(|completion| !existing_derives.contains(completion.label))
@@ -245,7 +162,26 @@ fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input:
245 } 162 }
246} 163}
247 164
248fn parse_derive_input(derive_input: ast::TokenTree) -> Result<FxHashSet<String>, ()> { 165fn complete_lint(acc: &mut Completions, ctx: &CompletionContext, derive_input: ast::TokenTree) {
166 if let Ok(existing_lints) = parse_comma_sep_input(derive_input) {
167 for lint_completion in DEFAULT_LINT_COMPLETIONS
168 .into_iter()
169 .filter(|completion| !existing_lints.contains(completion.label))
170 {
171 acc.add(
172 CompletionItem::new(
173 CompletionKind::Attribute,
174 ctx.source_range(),
175 lint_completion.label,
176 )
177 .kind(CompletionItemKind::Attribute)
178 .detail(lint_completion.description),
179 );
180 }
181 }
182}
183
184fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Result<FxHashSet<String>, ()> {
249 match (derive_input.left_delimiter_token(), derive_input.right_delimiter_token()) { 185 match (derive_input.left_delimiter_token(), derive_input.right_delimiter_token()) {
250 (Some(left_paren), Some(right_paren)) 186 (Some(left_paren), Some(right_paren))
251 if left_paren.kind() == SyntaxKind::L_PAREN 187 if left_paren.kind() == SyntaxKind::L_PAREN
@@ -282,7 +218,7 @@ fn parse_derive_input(derive_input: ast::TokenTree) -> Result<FxHashSet<String>,
282 218
283fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> { 219fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> {
284 let mut result = FxHashSet::default(); 220 let mut result = FxHashSet::default();
285 ctx.scope().process_all_names(&mut |name, scope_def| { 221 ctx.scope.process_all_names(&mut |name, scope_def| {
286 if let hir::ScopeDef::MacroDef(mac) = scope_def { 222 if let hir::ScopeDef::MacroDef(mac) = scope_def {
287 if mac.is_derive_macro() { 223 if mac.is_derive_macro() {
288 result.insert(name.to_string()); 224 result.insert(name.to_string());
@@ -299,6 +235,7 @@ struct DeriveCompletion {
299 235
300/// Standard Rust derives and the information about their dependencies 236/// Standard Rust derives and the information about their dependencies
301/// (the dependencies are needed so that the main derive don't break the compilation when added) 237/// (the dependencies are needed so that the main derive don't break the compilation when added)
238#[rustfmt::skip]
302const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[ 239const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[
303 DeriveCompletion { label: "Clone", dependencies: &[] }, 240 DeriveCompletion { label: "Clone", dependencies: &[] },
304 DeriveCompletion { label: "Copy", dependencies: &["Clone"] }, 241 DeriveCompletion { label: "Copy", dependencies: &["Clone"] },
@@ -311,679 +248,397 @@ const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[
311 DeriveCompletion { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] }, 248 DeriveCompletion { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] },
312]; 249];
313 250
251struct LintCompletion {
252 label: &'static str,
253 description: &'static str,
254}
255
256#[rustfmt::skip]
257const DEFAULT_LINT_COMPLETIONS: &[LintCompletion] = &[
258 LintCompletion { label: "absolute_paths_not_starting_with_crate", description: r#"fully qualified paths that start with a module name instead of `crate`, `self`, or an extern crate name"# },
259 LintCompletion { label: "anonymous_parameters", description: r#"detects anonymous parameters"# },
260 LintCompletion { label: "box_pointers", description: r#"use of owned (Box type) heap memory"# },
261 LintCompletion { label: "deprecated_in_future", description: r#"detects use of items that will be deprecated in a future version"# },
262 LintCompletion { label: "elided_lifetimes_in_paths", description: r#"hidden lifetime parameters in types are deprecated"# },
263 LintCompletion { label: "explicit_outlives_requirements", description: r#"outlives requirements can be inferred"# },
264 LintCompletion { label: "indirect_structural_match", description: r#"pattern with const indirectly referencing non-structural-match type"# },
265 LintCompletion { label: "keyword_idents", description: r#"detects edition keywords being used as an identifier"# },
266 LintCompletion { label: "macro_use_extern_crate", description: r#"the `#[macro_use]` attribute is now deprecated in favor of using macros via the module system"# },
267 LintCompletion { label: "meta_variable_misuse", description: r#"possible meta-variable misuse at macro definition"# },
268 LintCompletion { label: "missing_copy_implementations", description: r#"detects potentially-forgotten implementations of `Copy`"# },
269 LintCompletion { label: "missing_crate_level_docs", description: r#"detects crates with no crate-level documentation"# },
270 LintCompletion { label: "missing_debug_implementations", description: r#"detects missing implementations of Debug"# },
271 LintCompletion { label: "missing_docs", description: r#"detects missing documentation for public members"# },
272 LintCompletion { label: "missing_doc_code_examples", description: r#"detects publicly-exported items without code samples in their documentation"# },
273 LintCompletion { label: "non_ascii_idents", description: r#"detects non-ASCII identifiers"# },
274 LintCompletion { label: "private_doc_tests", description: r#"detects code samples in docs of private items not documented by rustdoc"# },
275 LintCompletion { label: "single_use_lifetimes", description: r#"detects lifetime parameters that are only used once"# },
276 LintCompletion { label: "trivial_casts", description: r#"detects trivial casts which could be removed"# },
277 LintCompletion { label: "trivial_numeric_casts", description: r#"detects trivial casts of numeric types which could be removed"# },
278 LintCompletion { label: "unaligned_references", description: r#"detects unaligned references to fields of packed structs"# },
279 LintCompletion { label: "unreachable_pub", description: r#"`pub` items not reachable from crate root"# },
280 LintCompletion { label: "unsafe_code", description: r#"usage of `unsafe` code"# },
281 LintCompletion { label: "unsafe_op_in_unsafe_fn", description: r#"unsafe operations in unsafe functions without an explicit unsafe block are deprecated"# },
282 LintCompletion { label: "unstable_features", description: r#"enabling unstable features (deprecated. do not use)"# },
283 LintCompletion { label: "unused_crate_dependencies", description: r#"crate dependencies that are never used"# },
284 LintCompletion { label: "unused_extern_crates", description: r#"extern crates that are never used"# },
285 LintCompletion { label: "unused_import_braces", description: r#"unnecessary braces around an imported item"# },
286 LintCompletion { label: "unused_lifetimes", description: r#"detects lifetime parameters that are never used"# },
287 LintCompletion { label: "unused_qualifications", description: r#"detects unnecessarily qualified names"# },
288 LintCompletion { label: "unused_results", description: r#"unused result of an expression in a statement"# },
289 LintCompletion { label: "variant_size_differences", description: r#"detects enums with widely varying variant sizes"# },
290 LintCompletion { label: "array_into_iter", description: r#"detects calling `into_iter` on arrays"# },
291 LintCompletion { label: "asm_sub_register", description: r#"using only a subset of a register for inline asm inputs"# },
292 LintCompletion { label: "bare_trait_objects", description: r#"suggest using `dyn Trait` for trait objects"# },
293 LintCompletion { label: "bindings_with_variant_name", description: r#"detects pattern bindings with the same name as one of the matched variants"# },
294 LintCompletion { label: "cenum_impl_drop_cast", description: r#"a C-like enum implementing Drop is cast"# },
295 LintCompletion { label: "clashing_extern_declarations", description: r#"detects when an extern fn has been declared with the same name but different types"# },
296 LintCompletion { label: "coherence_leak_check", description: r#"distinct impls distinguished only by the leak-check code"# },
297 LintCompletion { label: "confusable_idents", description: r#"detects visually confusable pairs between identifiers"# },
298 LintCompletion { label: "dead_code", description: r#"detect unused, unexported items"# },
299 LintCompletion { label: "deprecated", description: r#"detects use of deprecated items"# },
300 LintCompletion { label: "ellipsis_inclusive_range_patterns", description: r#"`...` range patterns are deprecated"# },
301 LintCompletion { label: "exported_private_dependencies", description: r#"public interface leaks type from a private dependency"# },
302 LintCompletion { label: "illegal_floating_point_literal_pattern", description: r#"floating-point literals cannot be used in patterns"# },
303 LintCompletion { label: "improper_ctypes", description: r#"proper use of libc types in foreign modules"# },
304 LintCompletion { label: "improper_ctypes_definitions", description: r#"proper use of libc types in foreign item definitions"# },
305 LintCompletion { label: "incomplete_features", description: r#"incomplete features that may function improperly in some or all cases"# },
306 LintCompletion { label: "inline_no_sanitize", description: r#"detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`"# },
307 LintCompletion { label: "intra_doc_link_resolution_failure", description: r#"failures in resolving intra-doc link targets"# },
308 LintCompletion { label: "invalid_codeblock_attributes", description: r#"codeblock attribute looks a lot like a known one"# },
309 LintCompletion { label: "invalid_value", description: r#"an invalid value is being created (such as a NULL reference)"# },
310 LintCompletion { label: "irrefutable_let_patterns", description: r#"detects irrefutable patterns in if-let and while-let statements"# },
311 LintCompletion { label: "late_bound_lifetime_arguments", description: r#"detects generic lifetime arguments in path segments with late bound lifetime parameters"# },
312 LintCompletion { label: "mixed_script_confusables", description: r#"detects Unicode scripts whose mixed script confusables codepoints are solely used"# },
313 LintCompletion { label: "mutable_borrow_reservation_conflict", description: r#"reservation of a two-phased borrow conflicts with other shared borrows"# },
314 LintCompletion { label: "non_camel_case_types", description: r#"types, variants, traits and type parameters should have camel case names"# },
315 LintCompletion { label: "non_shorthand_field_patterns", description: r#"using `Struct { x: x }` instead of `Struct { x }` in a pattern"# },
316 LintCompletion { label: "non_snake_case", description: r#"variables, methods, functions, lifetime parameters and modules should have snake case names"# },
317 LintCompletion { label: "non_upper_case_globals", description: r#"static constants should have uppercase identifiers"# },
318 LintCompletion { label: "no_mangle_generic_items", description: r#"generic items must be mangled"# },
319 LintCompletion { label: "overlapping_patterns", description: r#"detects overlapping patterns"# },
320 LintCompletion { label: "path_statements", description: r#"path statements with no effect"# },
321 LintCompletion { label: "private_in_public", description: r#"detect private items in public interfaces not caught by the old implementation"# },
322 LintCompletion { label: "proc_macro_derive_resolution_fallback", description: r#"detects proc macro derives using inaccessible names from parent modules"# },
323 LintCompletion { label: "redundant_semicolons", description: r#"detects unnecessary trailing semicolons"# },
324 LintCompletion { label: "renamed_and_removed_lints", description: r#"lints that have been renamed or removed"# },
325 LintCompletion { label: "safe_packed_borrows", description: r#"safe borrows of fields of packed structs were erroneously allowed"# },
326 LintCompletion { label: "stable_features", description: r#"stable features found in `#[feature]` directive"# },
327 LintCompletion { label: "trivial_bounds", description: r#"these bounds don't depend on an type parameters"# },
328 LintCompletion { label: "type_alias_bounds", description: r#"bounds in type aliases are not enforced"# },
329 LintCompletion { label: "tyvar_behind_raw_pointer", description: r#"raw pointer to an inference variable"# },
330 LintCompletion { label: "uncommon_codepoints", description: r#"detects uncommon Unicode codepoints in identifiers"# },
331 LintCompletion { label: "unconditional_recursion", description: r#"functions that cannot return without calling themselves"# },
332 LintCompletion { label: "unknown_lints", description: r#"unrecognized lint attribute"# },
333 LintCompletion { label: "unnameable_test_items", description: r#"detects an item that cannot be named being marked as `#[test_case]`"# },
334 LintCompletion { label: "unreachable_code", description: r#"detects unreachable code paths"# },
335 LintCompletion { label: "unreachable_patterns", description: r#"detects unreachable patterns"# },
336 LintCompletion { label: "unstable_name_collisions", description: r#"detects name collision with an existing but unstable method"# },
337 LintCompletion { label: "unused_allocation", description: r#"detects unnecessary allocations that can be eliminated"# },
338 LintCompletion { label: "unused_assignments", description: r#"detect assignments that will never be read"# },
339 LintCompletion { label: "unused_attributes", description: r#"detects attributes that were not used by the compiler"# },
340 LintCompletion { label: "unused_braces", description: r#"unnecessary braces around an expression"# },
341 LintCompletion { label: "unused_comparisons", description: r#"comparisons made useless by limits of the types involved"# },
342 LintCompletion { label: "unused_doc_comments", description: r#"detects doc comments that aren't used by rustdoc"# },
343 LintCompletion { label: "unused_features", description: r#"unused features found in crate-level `#[feature]` directives"# },
344 LintCompletion { label: "unused_imports", description: r#"imports that are never used"# },
345 LintCompletion { label: "unused_labels", description: r#"detects labels that are never used"# },
346 LintCompletion { label: "unused_macros", description: r#"detects macros that were not used"# },
347 LintCompletion { label: "unused_must_use", description: r#"unused result of a type flagged as `#[must_use]`"# },
348 LintCompletion { label: "unused_mut", description: r#"detect mut variables which don't need to be mutable"# },
349 LintCompletion { label: "unused_parens", description: r#"`if`, `match`, `while` and `return` do not need parentheses"# },
350 LintCompletion { label: "unused_unsafe", description: r#"unnecessary use of an `unsafe` block"# },
351 LintCompletion { label: "unused_variables", description: r#"detect variables which are not used in any way"# },
352 LintCompletion { label: "warnings", description: r#"mass-change the level for lints which produce warnings"# },
353 LintCompletion { label: "where_clauses_object_safety", description: r#"checks the object safety of where clauses"# },
354 LintCompletion { label: "while_true", description: r#"suggest using `loop { }` instead of `while true { }`"# },
355 LintCompletion { label: "ambiguous_associated_items", description: r#"ambiguous associated items"# },
356 LintCompletion { label: "arithmetic_overflow", description: r#"arithmetic operation overflows"# },
357 LintCompletion { label: "conflicting_repr_hints", description: r#"conflicts between `#[repr(..)]` hints that were previously accepted and used in practice"# },
358 LintCompletion { label: "const_err", description: r#"constant evaluation detected erroneous expression"# },
359 LintCompletion { label: "ill_formed_attribute_input", description: r#"ill-formed attribute inputs that were previously accepted and used in practice"# },
360 LintCompletion { label: "incomplete_include", description: r#"trailing content in included file"# },
361 LintCompletion { label: "invalid_type_param_default", description: r#"type parameter default erroneously allowed in invalid location"# },
362 LintCompletion { label: "macro_expanded_macro_exports_accessed_by_absolute_paths", description: r#"macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths"# },
363 LintCompletion { label: "missing_fragment_specifier", description: r#"detects missing fragment specifiers in unused `macro_rules!` patterns"# },
364 LintCompletion { label: "mutable_transmutes", description: r#"mutating transmuted &mut T from &T may cause undefined behavior"# },
365 LintCompletion { label: "no_mangle_const_items", description: r#"const items will not have their symbols exported"# },
366 LintCompletion { label: "order_dependent_trait_objects", description: r#"trait-object types were treated as different depending on marker-trait order"# },
367 LintCompletion { label: "overflowing_literals", description: r#"literal out of range for its type"# },
368 LintCompletion { label: "patterns_in_fns_without_body", description: r#"patterns in functions without body were erroneously allowed"# },
369 LintCompletion { label: "pub_use_of_private_extern_crate", description: r#"detect public re-exports of private extern crates"# },
370 LintCompletion { label: "soft_unstable", description: r#"a feature gate that doesn't break dependent crates"# },
371 LintCompletion { label: "unconditional_panic", description: r#"operation will cause a panic at runtime"# },
372 LintCompletion { label: "unknown_crate_types", description: r#"unknown crate type found in `#[crate_type]` directive"# },
373];
374
314#[cfg(test)] 375#[cfg(test)]
315mod tests { 376mod tests {
316 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 377 use expect::{expect, Expect};
317 use insta::assert_debug_snapshot;
318 378
319 fn do_attr_completion(code: &str) -> Vec<CompletionItem> { 379 use crate::completion::{test_utils::completion_list, CompletionKind};
320 do_completion(code, CompletionKind::Attribute) 380
381 fn check(ra_fixture: &str, expect: Expect) {
382 let actual = completion_list(ra_fixture, CompletionKind::Attribute);
383 expect.assert_eq(&actual);
321 } 384 }
322 385
323 #[test] 386 #[test]
324 fn empty_derive_completion() { 387 fn empty_derive_completion() {
325 assert_debug_snapshot!( 388 check(
326 do_attr_completion( 389 r#"
327 r" 390#[derive(<|>)]
328 #[derive(<|>)] 391struct Test {}
329 struct Test {} 392 "#,
330 ", 393 expect![[r#"
331 ), 394 at Clone
332 @r###" 395 at Copy, Clone
333 [ 396 at Debug
334 CompletionItem { 397 at Default
335 label: "Clone", 398 at Eq, PartialEq
336 source_range: 9..9, 399 at Hash
337 delete: 9..9, 400 at Ord, PartialOrd, Eq, PartialEq
338 insert: "Clone", 401 at PartialEq
339 kind: Attribute, 402 at PartialOrd, PartialEq
340 }, 403 "#]],
341 CompletionItem {
342 label: "Copy, Clone",
343 source_range: 9..9,
344 delete: 9..9,
345 insert: "Copy, Clone",
346 kind: Attribute,
347 },
348 CompletionItem {
349 label: "Debug",
350 source_range: 9..9,
351 delete: 9..9,
352 insert: "Debug",
353 kind: Attribute,
354 },
355 CompletionItem {
356 label: "Default",
357 source_range: 9..9,
358 delete: 9..9,
359 insert: "Default",
360 kind: Attribute,
361 },
362 CompletionItem {
363 label: "Eq, PartialEq",
364 source_range: 9..9,
365 delete: 9..9,
366 insert: "Eq, PartialEq",
367 kind: Attribute,
368 },
369 CompletionItem {
370 label: "Hash",
371 source_range: 9..9,
372 delete: 9..9,
373 insert: "Hash",
374 kind: Attribute,
375 },
376 CompletionItem {
377 label: "Ord, PartialOrd, Eq, PartialEq",
378 source_range: 9..9,
379 delete: 9..9,
380 insert: "Ord, PartialOrd, Eq, PartialEq",
381 kind: Attribute,
382 },
383 CompletionItem {
384 label: "PartialEq",
385 source_range: 9..9,
386 delete: 9..9,
387 insert: "PartialEq",
388 kind: Attribute,
389 },
390 CompletionItem {
391 label: "PartialOrd, PartialEq",
392 source_range: 9..9,
393 delete: 9..9,
394 insert: "PartialOrd, PartialEq",
395 kind: Attribute,
396 },
397 ]
398 "###
399 ); 404 );
400 } 405 }
401 406
402 #[test] 407 #[test]
408 fn empty_lint_completion() {
409 check(
410 r#"#[allow(<|>)]"#,
411 expect![[r#"
412 at absolute_paths_not_starting_with_crate fully qualified paths that start with a module name instead of `crate`, `self`, or an extern crate name
413 at ambiguous_associated_items ambiguous associated items
414 at anonymous_parameters detects anonymous parameters
415 at arithmetic_overflow arithmetic operation overflows
416 at array_into_iter detects calling `into_iter` on arrays
417 at asm_sub_register using only a subset of a register for inline asm inputs
418 at bare_trait_objects suggest using `dyn Trait` for trait objects
419 at bindings_with_variant_name detects pattern bindings with the same name as one of the matched variants
420 at box_pointers use of owned (Box type) heap memory
421 at cenum_impl_drop_cast a C-like enum implementing Drop is cast
422 at clashing_extern_declarations detects when an extern fn has been declared with the same name but different types
423 at coherence_leak_check distinct impls distinguished only by the leak-check code
424 at conflicting_repr_hints conflicts between `#[repr(..)]` hints that were previously accepted and used in practice
425 at confusable_idents detects visually confusable pairs between identifiers
426 at const_err constant evaluation detected erroneous expression
427 at dead_code detect unused, unexported items
428 at deprecated detects use of deprecated items
429 at deprecated_in_future detects use of items that will be deprecated in a future version
430 at elided_lifetimes_in_paths hidden lifetime parameters in types are deprecated
431 at ellipsis_inclusive_range_patterns `...` range patterns are deprecated
432 at explicit_outlives_requirements outlives requirements can be inferred
433 at exported_private_dependencies public interface leaks type from a private dependency
434 at ill_formed_attribute_input ill-formed attribute inputs that were previously accepted and used in practice
435 at illegal_floating_point_literal_pattern floating-point literals cannot be used in patterns
436 at improper_ctypes proper use of libc types in foreign modules
437 at improper_ctypes_definitions proper use of libc types in foreign item definitions
438 at incomplete_features incomplete features that may function improperly in some or all cases
439 at incomplete_include trailing content in included file
440 at indirect_structural_match pattern with const indirectly referencing non-structural-match type
441 at inline_no_sanitize detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`
442 at intra_doc_link_resolution_failure failures in resolving intra-doc link targets
443 at invalid_codeblock_attributes codeblock attribute looks a lot like a known one
444 at invalid_type_param_default type parameter default erroneously allowed in invalid location
445 at invalid_value an invalid value is being created (such as a NULL reference)
446 at irrefutable_let_patterns detects irrefutable patterns in if-let and while-let statements
447 at keyword_idents detects edition keywords being used as an identifier
448 at late_bound_lifetime_arguments detects generic lifetime arguments in path segments with late bound lifetime parameters
449 at macro_expanded_macro_exports_accessed_by_absolute_paths macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
450 at macro_use_extern_crate the `#[macro_use]` attribute is now deprecated in favor of using macros via the module system
451 at meta_variable_misuse possible meta-variable misuse at macro definition
452 at missing_copy_implementations detects potentially-forgotten implementations of `Copy`
453 at missing_crate_level_docs detects crates with no crate-level documentation
454 at missing_debug_implementations detects missing implementations of Debug
455 at missing_doc_code_examples detects publicly-exported items without code samples in their documentation
456 at missing_docs detects missing documentation for public members
457 at missing_fragment_specifier detects missing fragment specifiers in unused `macro_rules!` patterns
458 at mixed_script_confusables detects Unicode scripts whose mixed script confusables codepoints are solely used
459 at mutable_borrow_reservation_conflict reservation of a two-phased borrow conflicts with other shared borrows
460 at mutable_transmutes mutating transmuted &mut T from &T may cause undefined behavior
461 at no_mangle_const_items const items will not have their symbols exported
462 at no_mangle_generic_items generic items must be mangled
463 at non_ascii_idents detects non-ASCII identifiers
464 at non_camel_case_types types, variants, traits and type parameters should have camel case names
465 at non_shorthand_field_patterns using `Struct { x: x }` instead of `Struct { x }` in a pattern
466 at non_snake_case variables, methods, functions, lifetime parameters and modules should have snake case names
467 at non_upper_case_globals static constants should have uppercase identifiers
468 at order_dependent_trait_objects trait-object types were treated as different depending on marker-trait order
469 at overflowing_literals literal out of range for its type
470 at overlapping_patterns detects overlapping patterns
471 at path_statements path statements with no effect
472 at patterns_in_fns_without_body patterns in functions without body were erroneously allowed
473 at private_doc_tests detects code samples in docs of private items not documented by rustdoc
474 at private_in_public detect private items in public interfaces not caught by the old implementation
475 at proc_macro_derive_resolution_fallback detects proc macro derives using inaccessible names from parent modules
476 at pub_use_of_private_extern_crate detect public re-exports of private extern crates
477 at redundant_semicolons detects unnecessary trailing semicolons
478 at renamed_and_removed_lints lints that have been renamed or removed
479 at safe_packed_borrows safe borrows of fields of packed structs were erroneously allowed
480 at single_use_lifetimes detects lifetime parameters that are only used once
481 at soft_unstable a feature gate that doesn't break dependent crates
482 at stable_features stable features found in `#[feature]` directive
483 at trivial_bounds these bounds don't depend on an type parameters
484 at trivial_casts detects trivial casts which could be removed
485 at trivial_numeric_casts detects trivial casts of numeric types which could be removed
486 at type_alias_bounds bounds in type aliases are not enforced
487 at tyvar_behind_raw_pointer raw pointer to an inference variable
488 at unaligned_references detects unaligned references to fields of packed structs
489 at uncommon_codepoints detects uncommon Unicode codepoints in identifiers
490 at unconditional_panic operation will cause a panic at runtime
491 at unconditional_recursion functions that cannot return without calling themselves
492 at unknown_crate_types unknown crate type found in `#[crate_type]` directive
493 at unknown_lints unrecognized lint attribute
494 at unnameable_test_items detects an item that cannot be named being marked as `#[test_case]`
495 at unreachable_code detects unreachable code paths
496 at unreachable_patterns detects unreachable patterns
497 at unreachable_pub `pub` items not reachable from crate root
498 at unsafe_code usage of `unsafe` code
499 at unsafe_op_in_unsafe_fn unsafe operations in unsafe functions without an explicit unsafe block are deprecated
500 at unstable_features enabling unstable features (deprecated. do not use)
501 at unstable_name_collisions detects name collision with an existing but unstable method
502 at unused_allocation detects unnecessary allocations that can be eliminated
503 at unused_assignments detect assignments that will never be read
504 at unused_attributes detects attributes that were not used by the compiler
505 at unused_braces unnecessary braces around an expression
506 at unused_comparisons comparisons made useless by limits of the types involved
507 at unused_crate_dependencies crate dependencies that are never used
508 at unused_doc_comments detects doc comments that aren't used by rustdoc
509 at unused_extern_crates extern crates that are never used
510 at unused_features unused features found in crate-level `#[feature]` directives
511 at unused_import_braces unnecessary braces around an imported item
512 at unused_imports imports that are never used
513 at unused_labels detects labels that are never used
514 at unused_lifetimes detects lifetime parameters that are never used
515 at unused_macros detects macros that were not used
516 at unused_must_use unused result of a type flagged as `#[must_use]`
517 at unused_mut detect mut variables which don't need to be mutable
518 at unused_parens `if`, `match`, `while` and `return` do not need parentheses
519 at unused_qualifications detects unnecessarily qualified names
520 at unused_results unused result of an expression in a statement
521 at unused_unsafe unnecessary use of an `unsafe` block
522 at unused_variables detect variables which are not used in any way
523 at variant_size_differences detects enums with widely varying variant sizes
524 at warnings mass-change the level for lints which produce warnings
525 at where_clauses_object_safety checks the object safety of where clauses
526 at while_true suggest using `loop { }` instead of `while true { }`
527 "#]],
528 )
529 }
530
531 #[test]
403 fn no_completion_for_incorrect_derive() { 532 fn no_completion_for_incorrect_derive() {
404 assert_debug_snapshot!( 533 check(
405 do_attr_completion( 534 r#"
406 r" 535#[derive{<|>)]
407 #[derive{<|>)] 536struct Test {}
408 struct Test {} 537"#,
409 ", 538 expect![[r#""#]],
410 ), 539 )
411 @"[]"
412 );
413 } 540 }
414 541
415 #[test] 542 #[test]
416 fn derive_with_input_completion() { 543 fn derive_with_input_completion() {
417 assert_debug_snapshot!( 544 check(
418 do_attr_completion( 545 r#"
419 r" 546#[derive(serde::Serialize, PartialEq, <|>)]
420 #[derive(serde::Serialize, PartialEq, <|>)] 547struct Test {}
421 struct Test {} 548"#,
422 ", 549 expect![[r#"
423 ), 550 at Clone
424 @r###" 551 at Copy, Clone
425 [ 552 at Debug
426 CompletionItem { 553 at Default
427 label: "Clone", 554 at Eq
428 source_range: 38..38, 555 at Hash
429 delete: 38..38, 556 at Ord, PartialOrd, Eq
430 insert: "Clone", 557 at PartialOrd
431 kind: Attribute, 558 "#]],
432 }, 559 )
433 CompletionItem {
434 label: "Copy, Clone",
435 source_range: 38..38,
436 delete: 38..38,
437 insert: "Copy, Clone",
438 kind: Attribute,
439 },
440 CompletionItem {
441 label: "Debug",
442 source_range: 38..38,
443 delete: 38..38,
444 insert: "Debug",
445 kind: Attribute,
446 },
447 CompletionItem {
448 label: "Default",
449 source_range: 38..38,
450 delete: 38..38,
451 insert: "Default",
452 kind: Attribute,
453 },
454 CompletionItem {
455 label: "Eq",
456 source_range: 38..38,
457 delete: 38..38,
458 insert: "Eq",
459 kind: Attribute,
460 },
461 CompletionItem {
462 label: "Hash",
463 source_range: 38..38,
464 delete: 38..38,
465 insert: "Hash",
466 kind: Attribute,
467 },
468 CompletionItem {
469 label: "Ord, PartialOrd, Eq",
470 source_range: 38..38,
471 delete: 38..38,
472 insert: "Ord, PartialOrd, Eq",
473 kind: Attribute,
474 },
475 CompletionItem {
476 label: "PartialOrd",
477 source_range: 38..38,
478 delete: 38..38,
479 insert: "PartialOrd",
480 kind: Attribute,
481 },
482 ]
483 "###
484 );
485 } 560 }
486 561
487 #[test] 562 #[test]
488 fn test_attribute_completion() { 563 fn test_attribute_completion() {
489 assert_debug_snapshot!( 564 check(
490 do_attr_completion( 565 r#"#[<|>]"#,
491 r" 566 expect![[r#"
492 #[<|>] 567 at allow(…)
493 ", 568 at cfg(…)
494 ), 569 at cfg_attr(…)
495 @r###" 570 at deny(…)
496 [ 571 at deprecated = "…"
497 CompletionItem { 572 at derive(…)
498 label: "allow(…)", 573 at doc = "…"
499 source_range: 2..2, 574 at forbid(…)
500 delete: 2..2, 575 at ignore = "…"
501 insert: "allow(${0:lint})", 576 at inline(…)
502 kind: Attribute, 577 at link
503 lookup: "allow", 578 at link_name = "…"
504 }, 579 at macro_export
505 CompletionItem { 580 at macro_use
506 label: "cfg(…)", 581 at must_use = "…"
507 source_range: 2..2, 582 at no_mangle
508 delete: 2..2, 583 at non_exhaustive
509 insert: "cfg(${0:predicate})", 584 at path = "…"
510 kind: Attribute, 585 at proc_macro
511 lookup: "cfg", 586 at proc_macro_attribute
512 }, 587 at proc_macro_derive(…)
513 CompletionItem { 588 at repr(…)
514 label: "cfg_attr(…)", 589 at should_panic(…)
515 source_range: 2..2, 590 at target_feature = "…"
516 delete: 2..2, 591 at test
517 insert: "cfg_attr(${1:predicate}, ${0:attr})", 592 at used
518 kind: Attribute, 593 at warn(…)
519 lookup: "cfg_attr", 594 "#]],
520 }, 595 )
521 CompletionItem {
522 label: "deny(…)",
523 source_range: 2..2,
524 delete: 2..2,
525 insert: "deny(${0:lint})",
526 kind: Attribute,
527 lookup: "deny",
528 },
529 CompletionItem {
530 label: "deprecated = \"…\"",
531 source_range: 2..2,
532 delete: 2..2,
533 insert: "deprecated = \"${0:reason}\"",
534 kind: Attribute,
535 lookup: "deprecated",
536 },
537 CompletionItem {
538 label: "derive(…)",
539 source_range: 2..2,
540 delete: 2..2,
541 insert: "derive(${0:Debug})",
542 kind: Attribute,
543 lookup: "derive",
544 },
545 CompletionItem {
546 label: "doc = \"…\"",
547 source_range: 2..2,
548 delete: 2..2,
549 insert: "doc = \"${0:docs}\"",
550 kind: Attribute,
551 lookup: "doc",
552 },
553 CompletionItem {
554 label: "forbid(…)",
555 source_range: 2..2,
556 delete: 2..2,
557 insert: "forbid(${0:lint})",
558 kind: Attribute,
559 lookup: "forbid",
560 },
561 CompletionItem {
562 label: "ignore(…)",
563 source_range: 2..2,
564 delete: 2..2,
565 insert: "ignore(${0:lint})",
566 kind: Attribute,
567 lookup: "ignore",
568 },
569 CompletionItem {
570 label: "inline(…)",
571 source_range: 2..2,
572 delete: 2..2,
573 insert: "inline(${0:lint})",
574 kind: Attribute,
575 lookup: "inline",
576 },
577 CompletionItem {
578 label: "link",
579 source_range: 2..2,
580 delete: 2..2,
581 insert: "link",
582 kind: Attribute,
583 },
584 CompletionItem {
585 label: "link_name = \"…\"",
586 source_range: 2..2,
587 delete: 2..2,
588 insert: "link_name = \"${0:symbol_name}\"",
589 kind: Attribute,
590 lookup: "link_name",
591 },
592 CompletionItem {
593 label: "macro_export",
594 source_range: 2..2,
595 delete: 2..2,
596 insert: "macro_export",
597 kind: Attribute,
598 },
599 CompletionItem {
600 label: "macro_use",
601 source_range: 2..2,
602 delete: 2..2,
603 insert: "macro_use",
604 kind: Attribute,
605 },
606 CompletionItem {
607 label: "must_use = \"…\"",
608 source_range: 2..2,
609 delete: 2..2,
610 insert: "must_use = \"${0:reason}\"",
611 kind: Attribute,
612 lookup: "must_use",
613 },
614 CompletionItem {
615 label: "no_mangle",
616 source_range: 2..2,
617 delete: 2..2,
618 insert: "no_mangle",
619 kind: Attribute,
620 },
621 CompletionItem {
622 label: "non_exhaustive",
623 source_range: 2..2,
624 delete: 2..2,
625 insert: "non_exhaustive",
626 kind: Attribute,
627 },
628 CompletionItem {
629 label: "path = \"…\"",
630 source_range: 2..2,
631 delete: 2..2,
632 insert: "path =\"${0:path}\"",
633 kind: Attribute,
634 lookup: "path",
635 },
636 CompletionItem {
637 label: "proc_macro",
638 source_range: 2..2,
639 delete: 2..2,
640 insert: "proc_macro",
641 kind: Attribute,
642 },
643 CompletionItem {
644 label: "proc_macro_attribute",
645 source_range: 2..2,
646 delete: 2..2,
647 insert: "proc_macro_attribute",
648 kind: Attribute,
649 },
650 CompletionItem {
651 label: "proc_macro_derive(…)",
652 source_range: 2..2,
653 delete: 2..2,
654 insert: "proc_macro_derive(${0:Trait})",
655 kind: Attribute,
656 lookup: "proc_macro_derive",
657 },
658 CompletionItem {
659 label: "repr(…)",
660 source_range: 2..2,
661 delete: 2..2,
662 insert: "repr(${0:C})",
663 kind: Attribute,
664 lookup: "repr",
665 },
666 CompletionItem {
667 label: "should_panic(…)",
668 source_range: 2..2,
669 delete: 2..2,
670 insert: "should_panic(expected = \"${0:reason}\")",
671 kind: Attribute,
672 lookup: "should_panic",
673 },
674 CompletionItem {
675 label: "target_feature = \"…\"",
676 source_range: 2..2,
677 delete: 2..2,
678 insert: "target_feature = \"${0:feature}\"",
679 kind: Attribute,
680 lookup: "target_feature",
681 },
682 CompletionItem {
683 label: "test",
684 source_range: 2..2,
685 delete: 2..2,
686 insert: "test",
687 kind: Attribute,
688 },
689 CompletionItem {
690 label: "used",
691 source_range: 2..2,
692 delete: 2..2,
693 insert: "used",
694 kind: Attribute,
695 },
696 CompletionItem {
697 label: "warn(…)",
698 source_range: 2..2,
699 delete: 2..2,
700 insert: "warn(${0:lint})",
701 kind: Attribute,
702 lookup: "warn",
703 },
704 ]
705 "###
706 );
707 } 596 }
708 597
709 #[test] 598 #[test]
710 fn test_attribute_completion_inside_nested_attr() { 599 fn test_attribute_completion_inside_nested_attr() {
711 assert_debug_snapshot!( 600 check(r#"#[cfg(<|>)]"#, expect![[]])
712 do_attr_completion(
713 r"
714 #[allow(<|>)]
715 ",
716 ),
717 @r###"
718 []
719 "###
720 );
721 } 601 }
722 602
723 #[test] 603 #[test]
724 fn test_inner_attribute_completion() { 604 fn test_inner_attribute_completion() {
725 assert_debug_snapshot!( 605 check(
726 do_attr_completion( 606 r"#![<|>]",
727 r" 607 expect![[r#"
728 #![<|>] 608 at allow(…)
729 ", 609 at cfg(…)
730 ), 610 at cfg_attr(…)
731 @r###" 611 at deny(…)
732 [ 612 at deprecated = "…"
733 CompletionItem { 613 at derive(…)
734 label: "allow(…)", 614 at doc = "…"
735 source_range: 3..3, 615 at feature(…)
736 delete: 3..3, 616 at forbid(…)
737 insert: "allow(${0:lint})", 617 at global_allocator
738 kind: Attribute, 618 at ignore = "…"
739 lookup: "allow", 619 at inline(…)
740 }, 620 at link
741 CompletionItem { 621 at link_name = "…"
742 label: "cfg(…)", 622 at macro_export
743 source_range: 3..3, 623 at macro_use
744 delete: 3..3, 624 at must_use = "…"
745 insert: "cfg(${0:predicate})", 625 at no_mangle
746 kind: Attribute, 626 at no_std
747 lookup: "cfg", 627 at non_exhaustive
748 }, 628 at panic_handler
749 CompletionItem { 629 at path = "…"
750 label: "cfg_attr(…)", 630 at proc_macro
751 source_range: 3..3, 631 at proc_macro_attribute
752 delete: 3..3, 632 at proc_macro_derive(…)
753 insert: "cfg_attr(${1:predicate}, ${0:attr})", 633 at recursion_limit = …
754 kind: Attribute, 634 at repr(…)
755 lookup: "cfg_attr", 635 at should_panic(…)
756 }, 636 at target_feature = "…"
757 CompletionItem { 637 at test
758 label: "deny(…)", 638 at used
759 source_range: 3..3, 639 at warn(…)
760 delete: 3..3, 640 at windows_subsystem = "…"
761 insert: "deny(${0:lint})", 641 "#]],
762 kind: Attribute,
763 lookup: "deny",
764 },
765 CompletionItem {
766 label: "deprecated = \"…\"",
767 source_range: 3..3,
768 delete: 3..3,
769 insert: "deprecated = \"${0:reason}\"",
770 kind: Attribute,
771 lookup: "deprecated",
772 },
773 CompletionItem {
774 label: "derive(…)",
775 source_range: 3..3,
776 delete: 3..3,
777 insert: "derive(${0:Debug})",
778 kind: Attribute,
779 lookup: "derive",
780 },
781 CompletionItem {
782 label: "doc = \"…\"",
783 source_range: 3..3,
784 delete: 3..3,
785 insert: "doc = \"${0:docs}\"",
786 kind: Attribute,
787 lookup: "doc",
788 },
789 CompletionItem {
790 label: "feature(…)",
791 source_range: 3..3,
792 delete: 3..3,
793 insert: "feature(${0:flag})",
794 kind: Attribute,
795 lookup: "feature",
796 },
797 CompletionItem {
798 label: "forbid(…)",
799 source_range: 3..3,
800 delete: 3..3,
801 insert: "forbid(${0:lint})",
802 kind: Attribute,
803 lookup: "forbid",
804 },
805 CompletionItem {
806 label: "global_allocator",
807 source_range: 3..3,
808 delete: 3..3,
809 insert: "global_allocator",
810 kind: Attribute,
811 },
812 CompletionItem {
813 label: "ignore(…)",
814 source_range: 3..3,
815 delete: 3..3,
816 insert: "ignore(${0:lint})",
817 kind: Attribute,
818 lookup: "ignore",
819 },
820 CompletionItem {
821 label: "inline(…)",
822 source_range: 3..3,
823 delete: 3..3,
824 insert: "inline(${0:lint})",
825 kind: Attribute,
826 lookup: "inline",
827 },
828 CompletionItem {
829 label: "link",
830 source_range: 3..3,
831 delete: 3..3,
832 insert: "link",
833 kind: Attribute,
834 },
835 CompletionItem {
836 label: "link_name = \"…\"",
837 source_range: 3..3,
838 delete: 3..3,
839 insert: "link_name = \"${0:symbol_name}\"",
840 kind: Attribute,
841 lookup: "link_name",
842 },
843 CompletionItem {
844 label: "macro_export",
845 source_range: 3..3,
846 delete: 3..3,
847 insert: "macro_export",
848 kind: Attribute,
849 },
850 CompletionItem {
851 label: "macro_use",
852 source_range: 3..3,
853 delete: 3..3,
854 insert: "macro_use",
855 kind: Attribute,
856 },
857 CompletionItem {
858 label: "must_use = \"…\"",
859 source_range: 3..3,
860 delete: 3..3,
861 insert: "must_use = \"${0:reason}\"",
862 kind: Attribute,
863 lookup: "must_use",
864 },
865 CompletionItem {
866 label: "no_mangle",
867 source_range: 3..3,
868 delete: 3..3,
869 insert: "no_mangle",
870 kind: Attribute,
871 },
872 CompletionItem {
873 label: "no_std",
874 source_range: 3..3,
875 delete: 3..3,
876 insert: "no_std",
877 kind: Attribute,
878 },
879 CompletionItem {
880 label: "non_exhaustive",
881 source_range: 3..3,
882 delete: 3..3,
883 insert: "non_exhaustive",
884 kind: Attribute,
885 },
886 CompletionItem {
887 label: "panic_handler",
888 source_range: 3..3,
889 delete: 3..3,
890 insert: "panic_handler",
891 kind: Attribute,
892 },
893 CompletionItem {
894 label: "path = \"…\"",
895 source_range: 3..3,
896 delete: 3..3,
897 insert: "path =\"${0:path}\"",
898 kind: Attribute,
899 lookup: "path",
900 },
901 CompletionItem {
902 label: "proc_macro",
903 source_range: 3..3,
904 delete: 3..3,
905 insert: "proc_macro",
906 kind: Attribute,
907 },
908 CompletionItem {
909 label: "proc_macro_attribute",
910 source_range: 3..3,
911 delete: 3..3,
912 insert: "proc_macro_attribute",
913 kind: Attribute,
914 },
915 CompletionItem {
916 label: "proc_macro_derive(…)",
917 source_range: 3..3,
918 delete: 3..3,
919 insert: "proc_macro_derive(${0:Trait})",
920 kind: Attribute,
921 lookup: "proc_macro_derive",
922 },
923 CompletionItem {
924 label: "recursion_limit = …",
925 source_range: 3..3,
926 delete: 3..3,
927 insert: "recursion_limit = ${0:128}",
928 kind: Attribute,
929 lookup: "recursion_limit",
930 },
931 CompletionItem {
932 label: "repr(…)",
933 source_range: 3..3,
934 delete: 3..3,
935 insert: "repr(${0:C})",
936 kind: Attribute,
937 lookup: "repr",
938 },
939 CompletionItem {
940 label: "should_panic(…)",
941 source_range: 3..3,
942 delete: 3..3,
943 insert: "should_panic(expected = \"${0:reason}\")",
944 kind: Attribute,
945 lookup: "should_panic",
946 },
947 CompletionItem {
948 label: "target_feature = \"…\"",
949 source_range: 3..3,
950 delete: 3..3,
951 insert: "target_feature = \"${0:feature}\"",
952 kind: Attribute,
953 lookup: "target_feature",
954 },
955 CompletionItem {
956 label: "test",
957 source_range: 3..3,
958 delete: 3..3,
959 insert: "test",
960 kind: Attribute,
961 },
962 CompletionItem {
963 label: "used",
964 source_range: 3..3,
965 delete: 3..3,
966 insert: "used",
967 kind: Attribute,
968 },
969 CompletionItem {
970 label: "warn(…)",
971 source_range: 3..3,
972 delete: 3..3,
973 insert: "warn(${0:lint})",
974 kind: Attribute,
975 lookup: "warn",
976 },
977 CompletionItem {
978 label: "windows_subsystem = \"…\"",
979 source_range: 3..3,
980 delete: 3..3,
981 insert: "windows_subsystem = \"${0:subsystem}\"",
982 kind: Attribute,
983 lookup: "windows_subsystem",
984 },
985 ]
986 "###
987 ); 642 );
988 } 643 }
989} 644}
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs
index ee4e24fca..532665285 100644
--- a/crates/ra_ide/src/completion/complete_dot.rs
+++ b/crates/ra_ide/src/completion/complete_dot.rs
@@ -1,17 +1,12 @@
1//! FIXME: write short doc here 1//! Completes references after dot (fields and method calls).
2 2
3use hir::{HasVisibility, Type}; 3use hir::{HasVisibility, Type};
4
5use crate::{
6 completion::{
7 completion_context::CompletionContext,
8 completion_item::{CompletionKind, Completions},
9 },
10 CompletionItem,
11};
12use rustc_hash::FxHashSet; 4use rustc_hash::FxHashSet;
5use test_utils::mark;
13 6
14/// Complete dot accesses, i.e. fields or methods (and .await syntax). 7use crate::completion::{completion_context::CompletionContext, completion_item::Completions};
8
9/// Complete dot accesses, i.e. fields or methods.
15pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { 10pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
16 let dot_receiver = match &ctx.dot_receiver { 11 let dot_receiver = match &ctx.dot_receiver {
17 Some(expr) => expr, 12 Some(expr) => expr,
@@ -23,24 +18,18 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
23 _ => return, 18 _ => return,
24 }; 19 };
25 20
26 if !ctx.is_call { 21 if ctx.is_call {
22 mark::hit!(test_no_struct_field_completion_for_method_call);
23 } else {
27 complete_fields(acc, ctx, &receiver_ty); 24 complete_fields(acc, ctx, &receiver_ty);
28 } 25 }
29 complete_methods(acc, ctx, &receiver_ty); 26 complete_methods(acc, ctx, &receiver_ty);
30
31 // Suggest .await syntax for types that implement Future trait
32 if receiver_ty.impls_future(ctx.db) {
33 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await")
34 .detail("expr.await")
35 .insert_text("await")
36 .add_to(acc);
37 }
38} 27}
39 28
40fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { 29fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
41 for receiver in receiver.autoderef(ctx.db) { 30 for receiver in receiver.autoderef(ctx.db) {
42 for (field, ty) in receiver.fields(ctx.db) { 31 for (field, ty) in receiver.fields(ctx.db) {
43 if ctx.scope().module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) { 32 if ctx.scope.module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) {
44 // Skip private field. FIXME: If the definition location of the 33 // Skip private field. FIXME: If the definition location of the
45 // field is editable, we should show the completion 34 // field is editable, we should show the completion
46 continue; 35 continue;
@@ -57,10 +46,10 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Ty
57fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { 46fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
58 if let Some(krate) = ctx.krate { 47 if let Some(krate) = ctx.krate {
59 let mut seen_methods = FxHashSet::default(); 48 let mut seen_methods = FxHashSet::default();
60 let traits_in_scope = ctx.scope().traits_in_scope(); 49 let traits_in_scope = ctx.scope.traits_in_scope();
61 receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| { 50 receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| {
62 if func.has_self_param(ctx.db) 51 if func.has_self_param(ctx.db)
63 && ctx.scope().module().map_or(true, |m| func.is_visible_from(ctx.db, m)) 52 && ctx.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m))
64 && seen_methods.insert(func.name(ctx.db)) 53 && seen_methods.insert(func.name(ctx.db))
65 { 54 {
66 acc.add_function(ctx, func, None); 55 acc.add_function(ctx, func, None);
@@ -72,801 +61,356 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &T
72 61
73#[cfg(test)] 62#[cfg(test)]
74mod tests { 63mod tests {
75 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 64 use expect::{expect, Expect};
76 use insta::assert_debug_snapshot; 65 use test_utils::mark;
66
67 use crate::completion::{test_utils::completion_list, CompletionKind};
77 68
78 fn do_ref_completion(code: &str) -> Vec<CompletionItem> { 69 fn check(ra_fixture: &str, expect: Expect) {
79 do_completion(code, CompletionKind::Reference) 70 let actual = completion_list(ra_fixture, CompletionKind::Reference);
71 expect.assert_eq(&actual);
80 } 72 }
81 73
82 #[test] 74 #[test]
83 fn test_struct_field_completion() { 75 fn test_struct_field_and_method_completion() {
84 assert_debug_snapshot!( 76 check(
85 do_ref_completion( 77 r#"
86 r" 78struct S { foo: u32 }
87 struct A { the_field: u32 } 79impl S {
88 fn foo(a: A) { 80 fn bar(&self) {}
89 a.<|> 81}
90 } 82fn foo(s: S) { s.<|> }
91 ", 83"#,
92 ), 84 expect![[r#"
93 @r###" 85 me bar() fn bar(&self)
94 [ 86 fd foo u32
95 CompletionItem { 87 "#]],
96 label: "the_field",
97 source_range: 45..45,
98 delete: 45..45,
99 insert: "the_field",
100 kind: Field,
101 detail: "u32",
102 },
103 ]
104 "###
105 ); 88 );
106 } 89 }
107 90
108 #[test] 91 #[test]
109 fn test_struct_field_completion_self() { 92 fn test_struct_field_completion_self() {
110 assert_debug_snapshot!( 93 check(
111 do_ref_completion( 94 r#"
112 r" 95struct S { the_field: (u32,) }
113 struct A { 96impl S {
114 /// This is the_field 97 fn foo(self) { self.<|> }
115 the_field: (u32,) 98}
116 } 99"#,
117 impl A { 100 expect![[r#"
118 fn foo(self) { 101 me foo() fn foo(self)
119 self.<|> 102 fd the_field (u32,)
120 } 103 "#]],
121 } 104 )
122 ",
123 ),
124 @r###"
125 [
126 CompletionItem {
127 label: "foo()",
128 source_range: 102..102,
129 delete: 102..102,
130 insert: "foo()$0",
131 kind: Method,
132 lookup: "foo",
133 detail: "fn foo(self)",
134 },
135 CompletionItem {
136 label: "the_field",
137 source_range: 102..102,
138 delete: 102..102,
139 insert: "the_field",
140 kind: Field,
141 detail: "(u32,)",
142 documentation: Documentation(
143 "This is the_field",
144 ),
145 },
146 ]
147 "###
148 );
149 } 105 }
150 106
151 #[test] 107 #[test]
152 fn test_struct_field_completion_autoderef() { 108 fn test_struct_field_completion_autoderef() {
153 assert_debug_snapshot!( 109 check(
154 do_ref_completion( 110 r#"
155 r" 111struct A { the_field: (u32, i32) }
156 struct A { the_field: (u32, i32) } 112impl A {
157 impl A { 113 fn foo(&self) { self.<|> }
158 fn foo(&self) { 114}
159 self.<|> 115"#,
160 } 116 expect![[r#"
161 } 117 me foo() fn foo(&self)
162 ", 118 fd the_field (u32, i32)
163 ), 119 "#]],
164 @r###" 120 )
165 [
166 CompletionItem {
167 label: "foo()",
168 source_range: 77..77,
169 delete: 77..77,
170 insert: "foo()$0",
171 kind: Method,
172 lookup: "foo",
173 detail: "fn foo(&self)",
174 },
175 CompletionItem {
176 label: "the_field",
177 source_range: 77..77,
178 delete: 77..77,
179 insert: "the_field",
180 kind: Field,
181 detail: "(u32, i32)",
182 },
183 ]
184 "###
185 );
186 } 121 }
187 122
188 #[test] 123 #[test]
189 fn test_no_struct_field_completion_for_method_call() { 124 fn test_no_struct_field_completion_for_method_call() {
190 assert_debug_snapshot!( 125 mark::check!(test_no_struct_field_completion_for_method_call);
191 do_ref_completion( 126 check(
192 r" 127 r#"
193 struct A { the_field: u32 } 128struct A { the_field: u32 }
194 fn foo(a: A) { 129fn foo(a: A) { a.<|>() }
195 a.<|>() 130"#,
196 } 131 expect![[""]],
197 ",
198 ),
199 @"[]"
200 ); 132 );
201 } 133 }
202 134
203 #[test] 135 #[test]
204 fn test_struct_field_visibility_private() { 136 fn test_visibility_filtering() {
205 assert_debug_snapshot!( 137 check(
206 do_ref_completion( 138 r#"
207 r" 139mod inner {
208 mod inner { 140 pub struct A {
209 struct A { 141 private_field: u32,
210 private_field: u32, 142 pub pub_field: u32,
211 pub pub_field: u32, 143 pub(crate) crate_field: u32,
212 pub(crate) crate_field: u32, 144 pub(super) super_field: u32,
213 pub(super) super_field: u32,
214 }
215 }
216 fn foo(a: inner::A) {
217 a.<|>
218 }
219 ",
220 ),
221 @r###"
222 [
223 CompletionItem {
224 label: "crate_field",
225 source_range: 192..192,
226 delete: 192..192,
227 insert: "crate_field",
228 kind: Field,
229 detail: "u32",
230 },
231 CompletionItem {
232 label: "pub_field",
233 source_range: 192..192,
234 delete: 192..192,
235 insert: "pub_field",
236 kind: Field,
237 detail: "u32",
238 },
239 CompletionItem {
240 label: "super_field",
241 source_range: 192..192,
242 delete: 192..192,
243 insert: "super_field",
244 kind: Field,
245 detail: "u32",
246 },
247 ]
248 "###
249 );
250 } 145 }
251 146}
252 #[test] 147fn foo(a: inner::A) { a.<|> }
253 fn test_union_field_completion() { 148"#,
254 assert_debug_snapshot!( 149 expect![[r#"
255 do_ref_completion( 150 fd crate_field u32
256 r" 151 fd pub_field u32
257 union Un { 152 fd super_field u32
258 field: u8, 153 "#]],
259 other: u16,
260 }
261
262 fn foo(u: Un) {
263 u.<|>
264 }
265 ",
266 ),
267 @r###"
268 [
269 CompletionItem {
270 label: "field",
271 source_range: 67..67,
272 delete: 67..67,
273 insert: "field",
274 kind: Field,
275 detail: "u8",
276 },
277 CompletionItem {
278 label: "other",
279 source_range: 67..67,
280 delete: 67..67,
281 insert: "other",
282 kind: Field,
283 detail: "u16",
284 },
285 ]
286 "###
287 ); 154 );
288 }
289 155
290 #[test] 156 check(
291 fn test_method_completion() { 157 r#"
292 assert_debug_snapshot!( 158struct A {}
293 do_ref_completion( 159mod m {
294 r" 160 impl super::A {
295 struct A {} 161 fn private_method(&self) {}
296 impl A { 162 pub(super) fn the_method(&self) {}
297 fn the_method(&self) {} 163 }
298 } 164}
299 fn foo(a: A) { 165fn foo(a: A) { a.<|> }
300 a.<|> 166"#,
301 } 167 expect![[r#"
302 ", 168 me the_method() pub(super) fn the_method(&self)
303 ), 169 "#]],
304 @r###"
305 [
306 CompletionItem {
307 label: "the_method()",
308 source_range: 71..71,
309 delete: 71..71,
310 insert: "the_method()$0",
311 kind: Method,
312 lookup: "the_method",
313 detail: "fn the_method(&self)",
314 },
315 ]
316 "###
317 ); 170 );
318 } 171 }
319 172
320 #[test] 173 #[test]
321 fn test_method_completion_only_fitting_impls() { 174 fn test_union_field_completion() {
322 assert_debug_snapshot!( 175 check(
323 do_ref_completion( 176 r#"
324 r" 177union U { field: u8, other: u16 }
325 struct A<T> {} 178fn foo(u: U) { u.<|> }
326 impl A<u32> { 179"#,
327 fn the_method(&self) {} 180 expect![[r#"
328 } 181 fd field u8
329 impl A<i32> { 182 fd other u16
330 fn the_other_method(&self) {} 183 "#]],
331 }
332 fn foo(a: A<u32>) {
333 a.<|>
334 }
335 ",
336 ),
337 @r###"
338 [
339 CompletionItem {
340 label: "the_method()",
341 source_range: 134..134,
342 delete: 134..134,
343 insert: "the_method()$0",
344 kind: Method,
345 lookup: "the_method",
346 detail: "fn the_method(&self)",
347 },
348 ]
349 "###
350 ); 184 );
351 } 185 }
352 186
353 #[test] 187 #[test]
354 fn test_method_completion_private() { 188 fn test_method_completion_only_fitting_impls() {
355 assert_debug_snapshot!( 189 check(
356 do_ref_completion( 190 r#"
357 r" 191struct A<T> {}
358 struct A {} 192impl A<u32> {
359 mod m { 193 fn the_method(&self) {}
360 impl super::A { 194}
361 fn private_method(&self) {} 195impl A<i32> {
362 pub(super) fn the_method(&self) {} 196 fn the_other_method(&self) {}
363 } 197}
364 } 198fn foo(a: A<u32>) { a.<|> }
365 fn foo(a: A) { 199"#,
366 a.<|> 200 expect![[r#"
367 } 201 me the_method() fn the_method(&self)
368 ", 202 "#]],
369 ), 203 )
370 @r###"
371 [
372 CompletionItem {
373 label: "the_method()",
374 source_range: 147..147,
375 delete: 147..147,
376 insert: "the_method()$0",
377 kind: Method,
378 lookup: "the_method",
379 detail: "pub(super) fn the_method(&self)",
380 },
381 ]
382 "###
383 );
384 } 204 }
385 205
386 #[test] 206 #[test]
387 fn test_trait_method_completion() { 207 fn test_trait_method_completion() {
388 assert_debug_snapshot!( 208 check(
389 do_ref_completion( 209 r#"
390 r" 210struct A {}
391 struct A {} 211trait Trait { fn the_method(&self); }
392 trait Trait { fn the_method(&self); } 212impl Trait for A {}
393 impl Trait for A {} 213fn foo(a: A) { a.<|> }
394 fn foo(a: A) { 214"#,
395 a.<|> 215 expect![[r#"
396 } 216 me the_method() fn the_method(&self)
397 ", 217 "#]],
398 ),
399 @r###"
400 [
401 CompletionItem {
402 label: "the_method()",
403 source_range: 90..90,
404 delete: 90..90,
405 insert: "the_method()$0",
406 kind: Method,
407 lookup: "the_method",
408 detail: "fn the_method(&self)",
409 },
410 ]
411 "###
412 ); 218 );
413 } 219 }
414 220
415 #[test] 221 #[test]
416 fn test_trait_method_completion_deduplicated() { 222 fn test_trait_method_completion_deduplicated() {
417 assert_debug_snapshot!( 223 check(
418 do_ref_completion( 224 r"
419 r" 225struct A {}
420 struct A {} 226trait Trait { fn the_method(&self); }
421 trait Trait { fn the_method(&self); } 227impl<T> Trait for T {}
422 impl<T> Trait for T {} 228fn foo(a: &A) { a.<|> }
423 fn foo(a: &A) { 229",
424 a.<|> 230 expect![[r#"
425 } 231 me the_method() fn the_method(&self)
426 ", 232 "#]],
427 ),
428 @r###"
429 [
430 CompletionItem {
431 label: "the_method()",
432 source_range: 94..94,
433 delete: 94..94,
434 insert: "the_method()$0",
435 kind: Method,
436 lookup: "the_method",
437 detail: "fn the_method(&self)",
438 },
439 ]
440 "###
441 ); 233 );
442 } 234 }
443 235
444 #[test] 236 #[test]
445 fn completes_trait_method_from_other_module() { 237 fn completes_trait_method_from_other_module() {
446 assert_debug_snapshot!( 238 check(
447 do_ref_completion(
448 r"
449 struct A {}
450 mod m {
451 pub trait Trait { fn the_method(&self); }
452 }
453 use m::Trait;
454 impl Trait for A {}
455 fn foo(a: A) {
456 a.<|>
457 }
458 ",
459 ),
460 @r###"
461 [
462 CompletionItem {
463 label: "the_method()",
464 source_range: 122..122,
465 delete: 122..122,
466 insert: "the_method()$0",
467 kind: Method,
468 lookup: "the_method",
469 detail: "fn the_method(&self)",
470 },
471 ]
472 "###
473 );
474 }
475
476 #[test]
477 fn test_no_non_self_method() {
478 assert_debug_snapshot!(
479 do_ref_completion(
480 r" 239 r"
481 struct A {} 240struct A {}
482 impl A { 241mod m {
483 fn the_method() {} 242 pub trait Trait { fn the_method(&self); }
484 } 243}
485 fn foo(a: A) { 244use m::Trait;
486 a.<|> 245impl Trait for A {}
487 } 246fn foo(a: A) { a.<|> }
488 ", 247",
489 ), 248 expect![[r#"
490 @"[]" 249 me the_method() fn the_method(&self)
250 "#]],
491 ); 251 );
492 } 252 }
493 253
494 #[test] 254 #[test]
495 fn test_method_attr_filtering() { 255 fn test_no_non_self_method() {
496 assert_debug_snapshot!( 256 check(
497 do_ref_completion( 257 r#"
498 r" 258struct A {}
499 struct A {} 259impl A {
500 impl A { 260 fn the_method() {}
501 #[inline] 261}
502 fn the_method(&self) { 262fn foo(a: A) {
503 let x = 1; 263 a.<|>
504 let y = 2; 264}
505 } 265"#,
506 } 266 expect![[""]],
507 fn foo(a: A) {
508 a.<|>
509 }
510 ",
511 ),
512 @r###"
513 [
514 CompletionItem {
515 label: "the_method()",
516 source_range: 128..128,
517 delete: 128..128,
518 insert: "the_method()$0",
519 kind: Method,
520 lookup: "the_method",
521 detail: "fn the_method(&self)",
522 },
523 ]
524 "###
525 ); 267 );
526 } 268 }
527 269
528 #[test] 270 #[test]
529 fn test_tuple_field_completion() { 271 fn test_tuple_field_completion() {
530 assert_debug_snapshot!( 272 check(
531 do_ref_completion( 273 r#"
532 r" 274fn foo() {
533 fn foo() { 275 let b = (0, 3.14);
534 let b = (0, 3.14); 276 b.<|>
535 b.<|> 277}
536 } 278"#,
537 ", 279 expect![[r#"
538 ), 280 fd 0 i32
539 @r###" 281 fd 1 f64
540 [ 282 "#]],
541 CompletionItem { 283 )
542 label: "0",
543 source_range: 38..38,
544 delete: 38..38,
545 insert: "0",
546 kind: Field,
547 detail: "i32",
548 },
549 CompletionItem {
550 label: "1",
551 source_range: 38..38,
552 delete: 38..38,
553 insert: "1",
554 kind: Field,
555 detail: "f64",
556 },
557 ]
558 "###
559 );
560 } 284 }
561 285
562 #[test] 286 #[test]
563 fn test_tuple_field_inference() { 287 fn test_tuple_field_inference() {
564 assert_debug_snapshot!( 288 check(
565 do_ref_completion( 289 r#"
566 r" 290pub struct S;
567 pub struct S; 291impl S { pub fn blah(&self) {} }
568 impl S {
569 pub fn blah(&self) {}
570 }
571 292
572 struct T(S); 293struct T(S);
573 294
574 impl T { 295impl T {
575 fn foo(&self) { 296 fn foo(&self) {
576 // FIXME: This doesn't work without the trailing `a` as `0.` is a float 297 // FIXME: This doesn't work without the trailing `a` as `0.` is a float
577 self.0.a<|> 298 self.0.a<|>
578 }
579 }
580 ",
581 ),
582 @r###"
583 [
584 CompletionItem {
585 label: "blah()",
586 source_range: 190..191,
587 delete: 190..191,
588 insert: "blah()$0",
589 kind: Method,
590 lookup: "blah",
591 detail: "pub fn blah(&self)",
592 },
593 ]
594 "###
595 );
596 } 299 }
597 300}
598 #[test] 301"#,
599 fn test_completion_works_in_consts() { 302 expect![[r#"
600 assert_debug_snapshot!( 303 me blah() pub fn blah(&self)
601 do_ref_completion( 304 "#]],
602 r"
603 struct A { the_field: u32 }
604 const X: u32 = {
605 A { the_field: 92 }.<|>
606 };
607 ",
608 ),
609 @r###"
610 [
611 CompletionItem {
612 label: "the_field",
613 source_range: 69..69,
614 delete: 69..69,
615 insert: "the_field",
616 kind: Field,
617 detail: "u32",
618 },
619 ]
620 "###
621 ); 305 );
622 } 306 }
623 307
624 #[test] 308 #[test]
625 fn test_completion_await_impls_future() { 309 fn test_completion_works_in_consts() {
626 assert_debug_snapshot!( 310 check(
627 do_completion( 311 r#"
628 r###" 312struct A { the_field: u32 }
629 //- /main.rs 313const X: u32 = {
630 use std::future::*; 314 A { the_field: 92 }.<|>
631 struct A {} 315};
632 impl Future for A {} 316"#,
633 fn foo(a: A) { 317 expect![[r#"
634 a.<|> 318 fd the_field u32
635 } 319 "#]],
636
637 //- /std/lib.rs
638 pub mod future {
639 #[lang = "future_trait"]
640 pub trait Future {}
641 }
642 "###, CompletionKind::Keyword),
643 @r###"
644 [
645 CompletionItem {
646 label: "await",
647 source_range: 74..74,
648 delete: 74..74,
649 insert: "await",
650 detail: "expr.await",
651 },
652 ]
653 "###
654 )
655 }
656
657 #[test]
658 fn test_super_super_completion() {
659 assert_debug_snapshot!(
660 do_ref_completion(
661 r"
662 mod a {
663 const A: usize = 0;
664
665 mod b {
666 const B: usize = 0;
667
668 mod c {
669 use super::super::<|>
670 }
671 }
672 }
673 ",
674 ),
675 @r###"
676 [
677 CompletionItem {
678 label: "A",
679 source_range: 120..120,
680 delete: 120..120,
681 insert: "A",
682 kind: Const,
683 },
684 CompletionItem {
685 label: "b",
686 source_range: 120..120,
687 delete: 120..120,
688 insert: "b",
689 kind: Module,
690 },
691 ]
692 "###
693 ); 320 );
694 } 321 }
695 322
696 #[test] 323 #[test]
697 fn works_in_simple_macro_1() { 324 fn works_in_simple_macro_1() {
698 assert_debug_snapshot!( 325 check(
699 do_ref_completion( 326 r#"
700 r" 327macro_rules! m { ($e:expr) => { $e } }
701 macro_rules! m { ($e:expr) => { $e } } 328struct A { the_field: u32 }
702 struct A { the_field: u32 } 329fn foo(a: A) {
703 fn foo(a: A) { 330 m!(a.x<|>)
704 m!(a.x<|>) 331}
705 } 332"#,
706 ", 333 expect![[r#"
707 ), 334 fd the_field u32
708 @r###" 335 "#]],
709 [
710 CompletionItem {
711 label: "the_field",
712 source_range: 91..92,
713 delete: 91..92,
714 insert: "the_field",
715 kind: Field,
716 detail: "u32",
717 },
718 ]
719 "###
720 );
721 }
722
723 #[test]
724 fn works_in_simple_macro_recursive() {
725 assert_debug_snapshot!(
726 do_ref_completion(
727 r"
728 macro_rules! m { ($e:expr) => { $e } }
729 struct A { the_field: u32 }
730 fn foo(a: A) {
731 m!(a.x<|>)
732 }
733 ",
734 ),
735 @r###"
736 [
737 CompletionItem {
738 label: "the_field",
739 source_range: 91..92,
740 delete: 91..92,
741 insert: "the_field",
742 kind: Field,
743 detail: "u32",
744 },
745 ]
746 "###
747 ); 336 );
748 } 337 }
749 338
750 #[test] 339 #[test]
751 fn works_in_simple_macro_2() { 340 fn works_in_simple_macro_2() {
752 // this doesn't work yet because the macro doesn't expand without the token -- maybe it can be fixed with better recovery 341 // this doesn't work yet because the macro doesn't expand without the token -- maybe it can be fixed with better recovery
753 assert_debug_snapshot!( 342 check(
754 do_ref_completion( 343 r#"
755 r" 344macro_rules! m { ($e:expr) => { $e } }
756 macro_rules! m { ($e:expr) => { $e } } 345struct A { the_field: u32 }
757 struct A { the_field: u32 } 346fn foo(a: A) {
758 fn foo(a: A) { 347 m!(a.<|>)
759 m!(a.<|>) 348}
760 } 349"#,
761 ", 350 expect![[r#"
762 ), 351 fd the_field u32
763 @r###" 352 "#]],
764 [
765 CompletionItem {
766 label: "the_field",
767 source_range: 91..91,
768 delete: 91..91,
769 insert: "the_field",
770 kind: Field,
771 detail: "u32",
772 },
773 ]
774 "###
775 ); 353 );
776 } 354 }
777 355
778 #[test] 356 #[test]
779 fn works_in_simple_macro_recursive_1() { 357 fn works_in_simple_macro_recursive_1() {
780 assert_debug_snapshot!( 358 check(
781 do_ref_completion( 359 r#"
782 r" 360macro_rules! m { ($e:expr) => { $e } }
783 macro_rules! m { ($e:expr) => { $e } } 361struct A { the_field: u32 }
784 struct A { the_field: u32 } 362fn foo(a: A) {
785 fn foo(a: A) { 363 m!(m!(m!(a.x<|>)))
786 m!(m!(m!(a.x<|>))) 364}
787 } 365"#,
788 ", 366 expect![[r#"
789 ), 367 fd the_field u32
790 @r###" 368 "#]],
791 [
792 CompletionItem {
793 label: "the_field",
794 source_range: 97..98,
795 delete: 97..98,
796 insert: "the_field",
797 kind: Field,
798 detail: "u32",
799 },
800 ]
801 "###
802 ); 369 );
803 } 370 }
804 371
805 #[test] 372 #[test]
806 fn macro_expansion_resilient() { 373 fn macro_expansion_resilient() {
807 assert_debug_snapshot!( 374 check(
808 do_ref_completion( 375 r#"
809 r" 376macro_rules! dbg {
810 macro_rules! dbg { 377 () => {};
811 () => {}; 378 ($val:expr) => {
812 ($val:expr) => { 379 match $val { tmp => { tmp } }
813 match $val { tmp => { tmp } } 380 };
814 }; 381 // Trailing comma with single argument is ignored
815 // Trailing comma with single argument is ignored 382 ($val:expr,) => { $crate::dbg!($val) };
816 ($val:expr,) => { $crate::dbg!($val) }; 383 ($($val:expr),+ $(,)?) => {
817 ($($val:expr),+ $(,)?) => { 384 ($($crate::dbg!($val)),+,)
818 ($($crate::dbg!($val)),+,) 385 };
819 }; 386}
820 } 387struct A { the_field: u32 }
821 struct A { the_field: u32 } 388fn foo(a: A) {
822 fn foo(a: A) { 389 dbg!(a.<|>)
823 dbg!(a.<|>) 390}
824 } 391"#,
825 ", 392 expect![[r#"
826 ), 393 fd the_field u32
827 @r###" 394 "#]],
828 [
829 CompletionItem {
830 label: "the_field",
831 source_range: 327..327,
832 delete: 327..327,
833 insert: "the_field",
834 kind: Field,
835 detail: "u32",
836 },
837 ]
838 "###
839 ); 395 );
840 } 396 }
841 397
842 #[test] 398 #[test]
843 fn test_method_completion_3547() { 399 fn test_method_completion_issue_3547() {
844 assert_debug_snapshot!( 400 check(
845 do_ref_completion( 401 r#"
846 r" 402struct HashSet<T> {}
847 struct HashSet<T> {} 403impl<T> HashSet<T> {
848 impl<T> HashSet<T> { 404 pub fn the_method(&self) {}
849 pub fn the_method(&self) {} 405}
850 } 406fn foo() {
851 fn foo() { 407 let s: HashSet<_>;
852 let s: HashSet<_>; 408 s.<|>
853 s.<|> 409}
854 } 410"#,
855 ", 411 expect![[r#"
856 ), 412 me the_method() pub fn the_method(&self)
857 @r###" 413 "#]],
858 [
859 CompletionItem {
860 label: "the_method()",
861 source_range: 116..116,
862 delete: 116..116,
863 insert: "the_method()$0",
864 kind: Method,
865 lookup: "the_method",
866 detail: "pub fn the_method(&self)",
867 },
868 ]
869 "###
870 ); 414 );
871 } 415 }
872} 416}
diff --git a/crates/ra_ide/src/completion/complete_fn_param.rs b/crates/ra_ide/src/completion/complete_fn_param.rs
index f5573ddf7..406334257 100644
--- a/crates/ra_ide/src/completion/complete_fn_param.rs
+++ b/crates/ra_ide/src/completion/complete_fn_param.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! See `complete_fn_param`.
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 ast::{self, ModuleItemOwner}, 4 ast::{self, ModuleItemOwner},
@@ -18,35 +18,47 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
18 } 18 }
19 19
20 let mut params = FxHashMap::default(); 20 let mut params = FxHashMap::default();
21
22 let me = ctx.token.ancestors().find_map(ast::Fn::cast);
23 let mut process_fn = |func: ast::Fn| {
24 if Some(&func) == me.as_ref() {
25 return;
26 }
27 func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| {
28 let text = param.syntax().text().to_string();
29 params.entry(text).or_insert(param);
30 })
31 };
32
21 for node in ctx.token.parent().ancestors() { 33 for node in ctx.token.parent().ancestors() {
22 let items = match_ast! { 34 match_ast! {
23 match node { 35 match node {
24 ast::SourceFile(it) => it.items(), 36 ast::SourceFile(it) => it.items().filter_map(|item| match item {
25 ast::ItemList(it) => it.items(), 37 ast::Item::Fn(it) => Some(it),
38 _ => None,
39 }).for_each(&mut process_fn),
40 ast::ItemList(it) => it.items().filter_map(|item| match item {
41 ast::Item::Fn(it) => Some(it),
42 _ => None,
43 }).for_each(&mut process_fn),
44 ast::AssocItemList(it) => it.assoc_items().filter_map(|item| match item {
45 ast::AssocItem::Fn(it) => Some(it),
46 _ => None,
47 }).for_each(&mut process_fn),
26 _ => continue, 48 _ => continue,
27 } 49 }
28 }; 50 };
29 for item in items {
30 if let ast::ModuleItem::FnDef(func) = item {
31 func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| {
32 let text = param.syntax().text().to_string();
33 params.entry(text).or_insert((0, param)).0 += 1;
34 })
35 }
36 }
37 } 51 }
52
38 params 53 params
39 .into_iter() 54 .into_iter()
40 .filter_map(|(label, (count, param))| { 55 .filter_map(|(label, param)| {
41 let lookup = param.pat()?.syntax().text().to_string(); 56 let lookup = param.pat()?.syntax().text().to_string();
42 if count < 2 { 57 Some((label, lookup))
43 None
44 } else {
45 Some((label, lookup))
46 }
47 }) 58 })
48 .for_each(|(label, lookup)| { 59 .for_each(|(label, lookup)| {
49 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label) 60 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label)
61 .kind(crate::CompletionItemKind::Binding)
50 .lookup_by(lookup) 62 .lookup_by(lookup)
51 .add_to(acc) 63 .add_to(acc)
52 }); 64 });
@@ -54,85 +66,70 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
54 66
55#[cfg(test)] 67#[cfg(test)]
56mod tests { 68mod tests {
57 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 69 use expect::{expect, Expect};
58 use insta::assert_debug_snapshot; 70
71 use crate::completion::{test_utils::completion_list, CompletionKind};
59 72
60 fn do_magic_completion(code: &str) -> Vec<CompletionItem> { 73 fn check(ra_fixture: &str, expect: Expect) {
61 do_completion(code, CompletionKind::Magic) 74 let actual = completion_list(ra_fixture, CompletionKind::Magic);
75 expect.assert_eq(&actual);
62 } 76 }
63 77
64 #[test] 78 #[test]
65 fn test_param_completion_last_param() { 79 fn test_param_completion_last_param() {
66 assert_debug_snapshot!( 80 check(
67 do_magic_completion( 81 r#"
68 r" 82fn foo(file_id: FileId) {}
69 fn foo(file_id: FileId) {} 83fn bar(file_id: FileId) {}
70 fn bar(file_id: FileId) {} 84fn baz(file<|>) {}
71 fn baz(file<|>) {} 85"#,
72 ", 86 expect![[r#"
73 ), 87 bn file_id: FileId
74 @r###" 88 "#]],
75 [
76 CompletionItem {
77 label: "file_id: FileId",
78 source_range: 61..65,
79 delete: 61..65,
80 insert: "file_id: FileId",
81 lookup: "file_id",
82 },
83 ]
84 "###
85 ); 89 );
86 } 90 }
87 91
88 #[test] 92 #[test]
89 fn test_param_completion_nth_param() { 93 fn test_param_completion_nth_param() {
90 assert_debug_snapshot!( 94 check(
91 do_magic_completion( 95 r#"
92 r" 96fn foo(file_id: FileId) {}
93 fn foo(file_id: FileId) {} 97fn baz(file<|>, x: i32) {}
94 fn bar(file_id: FileId) {} 98"#,
95 fn baz(file<|>, x: i32) {} 99 expect![[r#"
96 ", 100 bn file_id: FileId
97 ), 101 "#]],
98 @r###"
99 [
100 CompletionItem {
101 label: "file_id: FileId",
102 source_range: 61..65,
103 delete: 61..65,
104 insert: "file_id: FileId",
105 lookup: "file_id",
106 },
107 ]
108 "###
109 ); 102 );
110 } 103 }
111 104
112 #[test] 105 #[test]
113 fn test_param_completion_trait_param() { 106 fn test_param_completion_trait_param() {
114 assert_debug_snapshot!( 107 check(
115 do_magic_completion( 108 r#"
116 r" 109pub(crate) trait SourceRoot {
117 pub(crate) trait SourceRoot { 110 pub fn contains(&self, file_id: FileId) -> bool;
118 pub fn contains(&self, file_id: FileId) -> bool; 111 pub fn module_map(&self) -> &ModuleMap;
119 pub fn module_map(&self) -> &ModuleMap; 112 pub fn lines(&self, file_id: FileId) -> &LineIndex;
120 pub fn lines(&self, file_id: FileId) -> &LineIndex; 113 pub fn syntax(&self, file<|>)
121 pub fn syntax(&self, file<|>) 114}
122 } 115"#,
123 ", 116 expect![[r#"
124 ), 117 bn file_id: FileId
125 @r###" 118 "#]],
126 [
127 CompletionItem {
128 label: "file_id: FileId",
129 source_range: 208..212,
130 delete: 208..212,
131 insert: "file_id: FileId",
132 lookup: "file_id",
133 },
134 ]
135 "###
136 ); 119 );
137 } 120 }
121
122 #[test]
123 fn completes_param_in_inner_function() {
124 check(
125 r#"
126fn outer(text: String) {
127 fn inner(<|>)
128}
129"#,
130 expect![[r#"
131 bn text: String
132 "#]],
133 )
134 }
138} 135}
diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs
index 3b174f916..b62064797 100644
--- a/crates/ra_ide/src/completion/complete_keyword.rs
+++ b/crates/ra_ide/src/completion/complete_keyword.rs
@@ -1,6 +1,7 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_syntax::ast; 3use ra_syntax::{ast, SyntaxKind};
4use test_utils::mark;
4 5
5use crate::completion::{ 6use crate::completion::{
6 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, 7 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
@@ -34,9 +35,27 @@ pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC
34 } 35 }
35 _ => {} 36 _ => {}
36 } 37 }
38
39 // Suggest .await syntax for types that implement Future trait
40 if let Some(receiver) = &ctx.dot_receiver {
41 if let Some(ty) = ctx.sema.type_of_expr(receiver) {
42 if ty.impls_future(ctx.db) {
43 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await")
44 .kind(CompletionItemKind::Keyword)
45 .detail("expr.await")
46 .insert_text("await")
47 .add_to(acc);
48 }
49 };
50 }
37} 51}
38 52
39pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { 53pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
54 if ctx.token.kind() == SyntaxKind::COMMENT {
55 mark::hit!(no_keyword_completion_in_comments);
56 return;
57 }
58
40 let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent; 59 let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent;
41 if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling { 60 if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling {
42 add_keyword(ctx, acc, "where", "where "); 61 add_keyword(ctx, acc, "where", "where ");
@@ -47,73 +66,67 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
47 add_keyword(ctx, acc, "fn", "fn $0() {}") 66 add_keyword(ctx, acc, "fn", "fn $0() {}")
48 } 67 }
49 68
50 if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent) 69 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
51 || ctx.block_expr_parent
52 {
53 add_keyword(ctx, acc, "trait", "trait $0 {}"); 70 add_keyword(ctx, acc, "trait", "trait $0 {}");
54 add_keyword(ctx, acc, "impl", "impl $0 {}"); 71 add_keyword(ctx, acc, "impl", "impl $0 {}");
55 } 72 }
56 73
57 return; 74 return;
58 } 75 }
59 if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent { 76 if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent
77 {
60 add_keyword(ctx, acc, "fn", "fn $0() {}"); 78 add_keyword(ctx, acc, "fn", "fn $0() {}");
61 } 79 }
62 if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent) 80 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
63 || ctx.block_expr_parent
64 {
65 add_keyword(ctx, acc, "use", "use "); 81 add_keyword(ctx, acc, "use", "use ");
66 add_keyword(ctx, acc, "impl", "impl $0 {}"); 82 add_keyword(ctx, acc, "impl", "impl $0 {}");
67 add_keyword(ctx, acc, "trait", "trait $0 {}"); 83 add_keyword(ctx, acc, "trait", "trait $0 {}");
68 } 84 }
69 85
70 if ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent { 86 if ctx.has_item_list_or_source_file_parent {
71 add_keyword(ctx, acc, "enum", "enum $0 {}"); 87 add_keyword(ctx, acc, "enum", "enum $0 {}");
72 add_keyword(ctx, acc, "struct", "struct $0 {}"); 88 add_keyword(ctx, acc, "struct", "struct $0");
73 add_keyword(ctx, acc, "union", "union $0 {}"); 89 add_keyword(ctx, acc, "union", "union $0 {}");
74 } 90 }
75 91
76 if ctx.block_expr_parent || ctx.is_match_arm { 92 if ctx.is_expr {
77 add_keyword(ctx, acc, "match", "match $0 {}"); 93 add_keyword(ctx, acc, "match", "match $0 {}");
78 add_keyword(ctx, acc, "loop", "loop {$0}");
79 }
80 if ctx.block_expr_parent {
81 add_keyword(ctx, acc, "while", "while $0 {}"); 94 add_keyword(ctx, acc, "while", "while $0 {}");
95 add_keyword(ctx, acc, "loop", "loop {$0}");
96 add_keyword(ctx, acc, "if", "if ");
97 add_keyword(ctx, acc, "if let", "if let ");
82 } 98 }
99
83 if ctx.if_is_prev || ctx.block_expr_parent { 100 if ctx.if_is_prev || ctx.block_expr_parent {
84 add_keyword(ctx, acc, "let", "let "); 101 add_keyword(ctx, acc, "let", "let ");
85 } 102 }
86 if ctx.if_is_prev || ctx.block_expr_parent || ctx.is_match_arm { 103
87 add_keyword(ctx, acc, "if", "if ");
88 add_keyword(ctx, acc, "if let", "if let ");
89 }
90 if ctx.after_if { 104 if ctx.after_if {
91 add_keyword(ctx, acc, "else", "else {$0}"); 105 add_keyword(ctx, acc, "else", "else {$0}");
92 add_keyword(ctx, acc, "else if", "else if $0 {}"); 106 add_keyword(ctx, acc, "else if", "else if $0 {}");
93 } 107 }
94 if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent) 108 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
95 || ctx.block_expr_parent
96 {
97 add_keyword(ctx, acc, "mod", "mod $0 {}"); 109 add_keyword(ctx, acc, "mod", "mod $0 {}");
98 } 110 }
99 if ctx.bind_pat_parent || ctx.ref_pat_parent { 111 if ctx.bind_pat_parent || ctx.ref_pat_parent {
100 add_keyword(ctx, acc, "mut", "mut "); 112 add_keyword(ctx, acc, "mut", "mut ");
101 } 113 }
102 if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent { 114 if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent
115 {
103 add_keyword(ctx, acc, "const", "const "); 116 add_keyword(ctx, acc, "const", "const ");
104 add_keyword(ctx, acc, "type", "type "); 117 add_keyword(ctx, acc, "type", "type ");
105 } 118 }
106 if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent) 119 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
107 || ctx.block_expr_parent
108 {
109 add_keyword(ctx, acc, "static", "static "); 120 add_keyword(ctx, acc, "static", "static ");
110 }; 121 };
111 if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent) 122 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
112 || ctx.block_expr_parent
113 {
114 add_keyword(ctx, acc, "extern", "extern "); 123 add_keyword(ctx, acc, "extern", "extern ");
115 } 124 }
116 if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent || ctx.is_match_arm { 125 if ctx.has_item_list_or_source_file_parent
126 || has_trait_or_impl_parent
127 || ctx.block_expr_parent
128 || ctx.is_match_arm
129 {
117 add_keyword(ctx, acc, "unsafe", "unsafe "); 130 add_keyword(ctx, acc, "unsafe", "unsafe ");
118 } 131 }
119 if ctx.in_loop_body { 132 if ctx.in_loop_body {
@@ -125,7 +138,7 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
125 add_keyword(ctx, acc, "break", "break"); 138 add_keyword(ctx, acc, "break", "break");
126 } 139 }
127 } 140 }
128 if ctx.has_item_list_or_source_file_parent && !ctx.has_trait_parent { 141 if ctx.has_item_list_or_source_file_parent || ctx.has_impl_parent {
129 add_keyword(ctx, acc, "pub", "pub ") 142 add_keyword(ctx, acc, "pub", "pub ")
130 } 143 }
131 144
@@ -156,7 +169,7 @@ fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet
156 169
157fn complete_return( 170fn complete_return(
158 ctx: &CompletionContext, 171 ctx: &CompletionContext,
159 fn_def: &ast::FnDef, 172 fn_def: &ast::Fn,
160 can_be_stmt: bool, 173 can_be_stmt: bool,
161) -> Option<CompletionItem> { 174) -> Option<CompletionItem> {
162 let snip = match (can_be_stmt, fn_def.ret_type().is_some()) { 175 let snip = match (can_be_stmt, fn_def.ret_type().is_some()) {
@@ -170,289 +183,354 @@ fn complete_return(
170 183
171#[cfg(test)] 184#[cfg(test)]
172mod tests { 185mod tests {
173 use crate::completion::{test_utils::completion_list, CompletionKind}; 186 use expect::{expect, Expect};
174 use insta::assert_snapshot; 187
188 use crate::completion::{
189 test_utils::{check_edit, completion_list},
190 CompletionKind,
191 };
192 use test_utils::mark;
175 193
176 fn get_keyword_completions(code: &str) -> String { 194 fn check(ra_fixture: &str, expect: Expect) {
177 completion_list(code, CompletionKind::Keyword) 195 let actual = completion_list(ra_fixture, CompletionKind::Keyword);
196 expect.assert_eq(&actual)
178 } 197 }
179 198
180 #[test] 199 #[test]
181 fn test_keywords_in_use_stmt() { 200 fn test_keywords_in_use_stmt() {
182 assert_snapshot!( 201 check(
183 get_keyword_completions(r"use <|>"), 202 r"use <|>",
184 @r###" 203 expect![[r#"
185 kw crate:: 204 kw crate::
186 kw self 205 kw self
187 kw super:: 206 kw super::
188 "### 207 "#]],
189 ); 208 );
190 209
191 assert_snapshot!( 210 check(
192 get_keyword_completions(r"use a::<|>"), 211 r"use a::<|>",
193 @r###" 212 expect![[r#"
194 kw self 213 kw self
195 kw super:: 214 kw super::
196 "### 215 "#]],
197 ); 216 );
198 217
199 assert_snapshot!( 218 check(
200 get_keyword_completions(r"use a::{b, <|>}"), 219 r"use a::{b, <|>}",
201 @r###" 220 expect![[r#"
202 kw self 221 kw self
203 kw super:: 222 kw super::
204 "### 223 "#]],
205 ); 224 );
206 } 225 }
207 226
208 #[test] 227 #[test]
209 fn test_keywords_at_source_file_level() { 228 fn test_keywords_at_source_file_level() {
210 assert_snapshot!( 229 check(
211 get_keyword_completions(r"m<|>"), 230 r"m<|>",
212 @r###" 231 expect![[r#"
213 kw const 232 kw const
214 kw enum 233 kw enum
215 kw extern 234 kw extern
216 kw fn 235 kw fn
217 kw impl 236 kw impl
218 kw mod 237 kw mod
219 kw pub 238 kw pub
220 kw static 239 kw static
221 kw struct 240 kw struct
222 kw trait 241 kw trait
223 kw type 242 kw type
224 kw union 243 kw union
225 kw unsafe 244 kw unsafe
226 kw use 245 kw use
227 "### 246 "#]],
228 ); 247 );
229 } 248 }
230 249
231 #[test] 250 #[test]
232 fn test_keywords_in_function() { 251 fn test_keywords_in_function() {
233 assert_snapshot!( 252 check(
234 get_keyword_completions(r"fn quux() { <|> }"), 253 r"fn quux() { <|> }",
235 @r###" 254 expect![[r#"
236 kw const 255 kw const
237 kw extern 256 kw extern
238 kw fn 257 kw fn
239 kw if 258 kw if
240 kw if let 259 kw if let
241 kw impl 260 kw impl
242 kw let 261 kw let
243 kw loop 262 kw loop
244 kw match 263 kw match
245 kw mod 264 kw mod
246 kw return 265 kw return
247 kw static 266 kw static
248 kw trait 267 kw trait
249 kw type 268 kw type
250 kw unsafe 269 kw unsafe
251 kw use 270 kw use
252 kw while 271 kw while
253 "### 272 "#]],
254 ); 273 );
255 } 274 }
256 275
257 #[test] 276 #[test]
258 fn test_keywords_inside_block() { 277 fn test_keywords_inside_block() {
259 assert_snapshot!( 278 check(
260 get_keyword_completions(r"fn quux() { if true { <|> } }"), 279 r"fn quux() { if true { <|> } }",
261 @r###" 280 expect![[r#"
262 kw const 281 kw const
263 kw extern 282 kw extern
264 kw fn 283 kw fn
265 kw if 284 kw if
266 kw if let 285 kw if let
267 kw impl 286 kw impl
268 kw let 287 kw let
269 kw loop 288 kw loop
270 kw match 289 kw match
271 kw mod 290 kw mod
272 kw return 291 kw return
273 kw static 292 kw static
274 kw trait 293 kw trait
275 kw type 294 kw type
276 kw unsafe 295 kw unsafe
277 kw use 296 kw use
278 kw while 297 kw while
279 "### 298 "#]],
280 ); 299 );
281 } 300 }
282 301
283 #[test] 302 #[test]
284 fn test_keywords_after_if() { 303 fn test_keywords_after_if() {
285 assert_snapshot!( 304 check(
286 get_keyword_completions( 305 r#"fn quux() { if true { () } <|> }"#,
287 r" 306 expect![[r#"
288 fn quux() { 307 kw const
289 if true { 308 kw else
290 () 309 kw else if
291 } <|> 310 kw extern
292 } 311 kw fn
293 ", 312 kw if
294 ), 313 kw if let
295 @r###" 314 kw impl
296 kw const 315 kw let
297 kw else 316 kw loop
298 kw else if 317 kw match
299 kw extern 318 kw mod
300 kw fn 319 kw return
301 kw if 320 kw static
302 kw if let 321 kw trait
303 kw impl 322 kw type
304 kw let 323 kw unsafe
305 kw loop 324 kw use
306 kw match 325 kw while
307 kw mod 326 "#]],
308 kw return 327 );
309 kw static 328 check_edit(
310 kw trait 329 "else",
311 kw type 330 r#"fn quux() { if true { () } <|> }"#,
312 kw unsafe 331 r#"fn quux() { if true { () } else {$0} }"#,
313 kw use
314 kw while
315 "###
316 ); 332 );
317 } 333 }
318 334
319 #[test] 335 #[test]
320 fn test_keywords_in_match_arm() { 336 fn test_keywords_in_match_arm() {
321 assert_snapshot!( 337 check(
322 get_keyword_completions( 338 r#"
323 r" 339fn quux() -> i32 {
324 fn quux() -> i32 { 340 match () { () => <|> }
325 match () { 341}
326 () => <|> 342"#,
327 } 343 expect![[r#"
328 } 344 kw if
329 ", 345 kw if let
330 ), 346 kw loop
331 @r###" 347 kw match
332 kw if 348 kw return
333 kw if let 349 kw unsafe
334 kw loop 350 kw while
335 kw match 351 "#]],
336 kw return
337 kw unsafe
338 "###
339 ); 352 );
340 } 353 }
341 354
342 #[test] 355 #[test]
343 fn test_keywords_in_trait_def() { 356 fn test_keywords_in_trait_def() {
344 assert_snapshot!( 357 check(
345 get_keyword_completions(r"trait My { <|> }"), 358 r"trait My { <|> }",
346 @r###" 359 expect![[r#"
347 kw const 360 kw const
348 kw fn 361 kw fn
349 kw type 362 kw type
350 kw unsafe 363 kw unsafe
351 "### 364 "#]],
352 ); 365 );
353 } 366 }
354 367
355 #[test] 368 #[test]
356 fn test_keywords_in_impl_def() { 369 fn test_keywords_in_impl_def() {
357 assert_snapshot!( 370 check(
358 get_keyword_completions(r"impl My { <|> }"), 371 r"impl My { <|> }",
359 @r###" 372 expect![[r#"
360 kw const 373 kw const
361 kw fn 374 kw fn
362 kw pub 375 kw pub
363 kw type 376 kw type
364 kw unsafe 377 kw unsafe
365 "### 378 "#]],
366 ); 379 );
367 } 380 }
368 381
369 #[test] 382 #[test]
370 fn test_keywords_in_loop() { 383 fn test_keywords_in_loop() {
371 assert_snapshot!( 384 check(
372 get_keyword_completions(r"fn my() { loop { <|> } }"), 385 r"fn my() { loop { <|> } }",
373 @r###" 386 expect![[r#"
374 kw break 387 kw break
375 kw const 388 kw const
376 kw continue 389 kw continue
377 kw extern 390 kw extern
378 kw fn 391 kw fn
379 kw if 392 kw if
380 kw if let 393 kw if let
381 kw impl 394 kw impl
382 kw let 395 kw let
383 kw loop 396 kw loop
384 kw match 397 kw match
385 kw mod 398 kw mod
386 kw return 399 kw return
387 kw static 400 kw static
388 kw trait 401 kw trait
389 kw type 402 kw type
390 kw unsafe 403 kw unsafe
391 kw use 404 kw use
392 kw while 405 kw while
393 "### 406 "#]],
394 ); 407 );
395 } 408 }
396 409
397 #[test] 410 #[test]
398 fn test_keywords_after_unsafe_in_item_list() { 411 fn test_keywords_after_unsafe_in_item_list() {
399 assert_snapshot!( 412 check(
400 get_keyword_completions(r"unsafe <|>"), 413 r"unsafe <|>",
401 @r###" 414 expect![[r#"
402 kw fn 415 kw fn
403 kw impl 416 kw impl
404 kw trait 417 kw trait
405 "### 418 "#]],
406 ); 419 );
407 } 420 }
408 421
409 #[test] 422 #[test]
410 fn test_keywords_after_unsafe_in_block_expr() { 423 fn test_keywords_after_unsafe_in_block_expr() {
411 assert_snapshot!( 424 check(
412 get_keyword_completions(r"fn my_fn() { unsafe <|> }"), 425 r"fn my_fn() { unsafe <|> }",
413 @r###" 426 expect![[r#"
414 kw fn 427 kw fn
415 kw impl 428 kw impl
416 kw trait 429 kw trait
417 "### 430 "#]],
418 ); 431 );
419 } 432 }
420 433
421 #[test] 434 #[test]
422 fn test_mut_in_ref_and_in_fn_parameters_list() { 435 fn test_mut_in_ref_and_in_fn_parameters_list() {
423 assert_snapshot!( 436 check(
424 get_keyword_completions(r"fn my_fn(&<|>) {}"), 437 r"fn my_fn(&<|>) {}",
425 @r###" 438 expect![[r#"
426 kw mut 439 kw mut
427 "### 440 "#]],
428 ); 441 );
429 assert_snapshot!( 442 check(
430 get_keyword_completions(r"fn my_fn(<|>) {}"), 443 r"fn my_fn(<|>) {}",
431 @r###" 444 expect![[r#"
432 kw mut 445 kw mut
433 "### 446 "#]],
434 ); 447 );
435 assert_snapshot!( 448 check(
436 get_keyword_completions(r"fn my_fn() { let &<|> }"), 449 r"fn my_fn() { let &<|> }",
437 @r###" 450 expect![[r#"
438 kw mut 451 kw mut
439 "### 452 "#]],
440 ); 453 );
441 } 454 }
442 455
443 #[test] 456 #[test]
444 fn test_where_keyword() { 457 fn test_where_keyword() {
445 assert_snapshot!( 458 check(
446 get_keyword_completions(r"trait A <|>"), 459 r"trait A <|>",
447 @r###" 460 expect![[r#"
448 kw where 461 kw where
449 "### 462 "#]],
450 ); 463 );
451 assert_snapshot!( 464 check(
452 get_keyword_completions(r"impl A <|>"), 465 r"impl A <|>",
453 @r###" 466 expect![[r#"
454 kw where 467 kw where
455 "### 468 "#]],
456 ); 469 );
457 } 470 }
471
472 #[test]
473 fn no_keyword_completion_in_comments() {
474 mark::check!(no_keyword_completion_in_comments);
475 check(
476 r#"
477fn test() {
478 let x = 2; // A comment<|>
479}
480"#,
481 expect![[""]],
482 );
483 check(
484 r#"
485/*
486Some multi-line comment<|>
487*/
488"#,
489 expect![[""]],
490 );
491 check(
492 r#"
493/// Some doc comment
494/// let test<|> = 1
495"#,
496 expect![[""]],
497 );
498 }
499
500 #[test]
501 fn test_completion_await_impls_future() {
502 check(
503 r#"
504//- /main.rs
505use std::future::*;
506struct A {}
507impl Future for A {}
508fn foo(a: A) { a.<|> }
509
510//- /std/lib.rs
511pub mod future {
512 #[lang = "future_trait"]
513 pub trait Future {}
514}
515"#,
516 expect![[r#"
517 kw await expr.await
518 "#]],
519 )
520 }
521
522 #[test]
523 fn after_let() {
524 check(
525 r#"fn main() { let _ = <|> }"#,
526 expect![[r#"
527 kw if
528 kw if let
529 kw loop
530 kw match
531 kw return
532 kw while
533 "#]],
534 )
535 }
458} 536}
diff --git a/crates/ra_ide/src/completion/complete_macro_in_item_position.rs b/crates/ra_ide/src/completion/complete_macro_in_item_position.rs
index 4c33f41d4..0447f0511 100644
--- a/crates/ra_ide/src/completion/complete_macro_in_item_position.rs
+++ b/crates/ra_ide/src/completion/complete_macro_in_item_position.rs
@@ -5,7 +5,7 @@ use crate::completion::{CompletionContext, Completions};
5pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) { 5pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) {
6 // Show only macros in top level. 6 // Show only macros in top level.
7 if ctx.is_new_item { 7 if ctx.is_new_item {
8 ctx.scope().process_all_names(&mut |name, res| { 8 ctx.scope.process_all_names(&mut |name, res| {
9 if let hir::ScopeDef::MacroDef(mac) = res { 9 if let hir::ScopeDef::MacroDef(mac) = res {
10 acc.add_macro(ctx, Some(name.to_string()), mac); 10 acc.add_macro(ctx, Some(name.to_string()), mac);
11 } 11 }
@@ -15,130 +15,27 @@ pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &Compl
15 15
16#[cfg(test)] 16#[cfg(test)]
17mod tests { 17mod tests {
18 use insta::assert_debug_snapshot; 18 use expect::{expect, Expect};
19 19
20 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 20 use crate::completion::{test_utils::completion_list, CompletionKind};
21 21
22 fn do_reference_completion(code: &str) -> Vec<CompletionItem> { 22 fn check(ra_fixture: &str, expect: Expect) {
23 do_completion(code, CompletionKind::Reference) 23 let actual = completion_list(ra_fixture, CompletionKind::Reference);
24 expect.assert_eq(&actual)
24 } 25 }
25 26
26 #[test] 27 #[test]
27 fn completes_macros_as_item() { 28 fn completes_macros_as_item() {
28 assert_debug_snapshot!( 29 check(
29 do_reference_completion( 30 r#"
30 " 31macro_rules! foo { () => {} }
31 //- /main.rs 32fn foo() {}
32 macro_rules! foo { 33
33 () => {} 34<|>
34 } 35"#,
35 36 expect![[r#"
36 fn foo() {} 37 ma foo!(…) macro_rules! foo
37 38 "#]],
38 <|> 39 )
39 "
40 ),
41 @r###"
42 [
43 CompletionItem {
44 label: "foo!(…)",
45 source_range: 48..48,
46 delete: 48..48,
47 insert: "foo!($0)",
48 kind: Macro,
49 detail: "macro_rules! foo",
50 },
51 ]
52 "###
53 );
54 }
55
56 #[test]
57 fn completes_vec_macros_with_square_brackets() {
58 assert_debug_snapshot!(
59 do_reference_completion(
60 "
61 //- /main.rs
62 /// Creates a [`Vec`] containing the arguments.
63 ///
64 /// - Create a [`Vec`] containing a given list of elements:
65 ///
66 /// ```
67 /// let v = vec![1, 2, 3];
68 /// assert_eq!(v[0], 1);
69 /// assert_eq!(v[1], 2);
70 /// assert_eq!(v[2], 3);
71 /// ```
72 macro_rules! vec {
73 () => {}
74 }
75
76 fn foo() {}
77
78 <|>
79 "
80 ),
81 @r###"
82 [
83 CompletionItem {
84 label: "vec![…]",
85 source_range: 282..282,
86 delete: 282..282,
87 insert: "vec![$0]",
88 kind: Macro,
89 detail: "macro_rules! vec",
90 documentation: Documentation(
91 "Creates a [`Vec`] containing the arguments.\n\n- Create a [`Vec`] containing a given list of elements:\n\n```\nlet v = vec![1, 2, 3];\nassert_eq!(v[0], 1);\nassert_eq!(v[1], 2);\nassert_eq!(v[2], 3);\n```",
92 ),
93 },
94 ]
95 "###
96 );
97 }
98
99 #[test]
100 fn completes_macros_braces_guessing() {
101 assert_debug_snapshot!(
102 do_reference_completion(
103 "
104 //- /main.rs
105 /// Foo
106 ///
107 /// Not call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`.
108 /// Call as `let _=foo! { hello world };`
109 macro_rules! foo {
110 () => {}
111 }
112
113 fn main() {
114 <|>
115 }
116 "
117 ),
118 @r###"
119 [
120 CompletionItem {
121 label: "foo! {…}",
122 source_range: 164..164,
123 delete: 164..164,
124 insert: "foo! {$0}",
125 kind: Macro,
126 detail: "macro_rules! foo",
127 documentation: Documentation(
128 "Foo\n\nNot call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`.\nCall as `let _=foo! { hello world };`",
129 ),
130 },
131 CompletionItem {
132 label: "main()",
133 source_range: 164..164,
134 delete: 164..164,
135 insert: "main()$0",
136 kind: Function,
137 lookup: "main",
138 detail: "fn main()",
139 },
140 ]
141 "###
142 );
143 } 40 }
144} 41}
diff --git a/crates/ra_ide/src/completion/complete_pattern.rs b/crates/ra_ide/src/completion/complete_pattern.rs
index 367e2bbce..aceb77cb5 100644
--- a/crates/ra_ide/src/completion/complete_pattern.rs
+++ b/crates/ra_ide/src/completion/complete_pattern.rs
@@ -13,7 +13,7 @@ pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
13 13
14 // FIXME: ideally, we should look at the type we are matching against and 14 // FIXME: ideally, we should look at the type we are matching against and
15 // suggest variants + auto-imports 15 // suggest variants + auto-imports
16 ctx.scope().process_all_names(&mut |name, res| { 16 ctx.scope.process_all_names(&mut |name, res| {
17 match &res { 17 match &res {
18 hir::ScopeDef::ModuleDef(def) => match def { 18 hir::ScopeDef::ModuleDef(def) => match def {
19 hir::ModuleDef::Adt(hir::Adt::Enum(..)) 19 hir::ModuleDef::Adt(hir::Adt::Enum(..))
@@ -33,106 +33,56 @@ pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
33 33
34#[cfg(test)] 34#[cfg(test)]
35mod tests { 35mod tests {
36 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 36 use expect::{expect, Expect};
37 use insta::assert_debug_snapshot;
38 37
39 fn complete(code: &str) -> Vec<CompletionItem> { 38 use crate::completion::{test_utils::completion_list, CompletionKind};
40 do_completion(code, CompletionKind::Reference) 39
40 fn check(ra_fixture: &str, expect: Expect) {
41 let actual = completion_list(ra_fixture, CompletionKind::Reference);
42 expect.assert_eq(&actual)
41 } 43 }
42 44
43 #[test] 45 #[test]
44 fn completes_enum_variants_and_modules() { 46 fn completes_enum_variants_and_modules() {
45 let completions = complete( 47 check(
46 r" 48 r#"
47 enum E { X } 49enum E { X }
48 use self::E::X; 50use self::E::X;
49 const Z: E = E::X; 51const Z: E = E::X;
50 mod m {} 52mod m {}
51 53
52 static FOO: E = E::X; 54static FOO: E = E::X;
53 struct Bar { f: u32 } 55struct Bar { f: u32 }
54 56
55 fn foo() { 57fn foo() {
56 match E::X { 58 match E::X { <|> }
57 <|> 59}
58 } 60"#,
59 } 61 expect![[r#"
60 ", 62 st Bar
63 en E
64 ev X ()
65 ct Z
66 md m
67 "#]],
61 ); 68 );
62 assert_debug_snapshot!(completions, @r###"
63 [
64 CompletionItem {
65 label: "Bar",
66 source_range: 137..137,
67 delete: 137..137,
68 insert: "Bar",
69 kind: Struct,
70 },
71 CompletionItem {
72 label: "E",
73 source_range: 137..137,
74 delete: 137..137,
75 insert: "E",
76 kind: Enum,
77 },
78 CompletionItem {
79 label: "X",
80 source_range: 137..137,
81 delete: 137..137,
82 insert: "X",
83 kind: EnumVariant,
84 detail: "()",
85 },
86 CompletionItem {
87 label: "Z",
88 source_range: 137..137,
89 delete: 137..137,
90 insert: "Z",
91 kind: Const,
92 },
93 CompletionItem {
94 label: "m",
95 source_range: 137..137,
96 delete: 137..137,
97 insert: "m",
98 kind: Module,
99 },
100 ]
101 "###);
102 } 69 }
103 70
104 #[test] 71 #[test]
105 fn completes_in_simple_macro_call() { 72 fn completes_in_simple_macro_call() {
106 let completions = complete( 73 check(
107 r" 74 r#"
108 macro_rules! m { ($e:expr) => { $e } } 75macro_rules! m { ($e:expr) => { $e } }
109 enum E { X } 76enum E { X }
110 77
111 fn foo() { 78fn foo() {
112 m!(match E::X { 79 m!(match E::X { <|> })
113 <|> 80}
114 }) 81"#,
115 } 82 expect![[r#"
116 ", 83 en E
84 ma m!(…) macro_rules! m
85 "#]],
117 ); 86 );
118 assert_debug_snapshot!(completions, @r###"
119 [
120 CompletionItem {
121 label: "E",
122 source_range: 90..90,
123 delete: 90..90,
124 insert: "E",
125 kind: Enum,
126 },
127 CompletionItem {
128 label: "m!(…)",
129 source_range: 90..90,
130 delete: 90..90,
131 insert: "m!($0)",
132 kind: Macro,
133 detail: "macro_rules! m",
134 },
135 ]
136 "###);
137 } 87 }
138} 88}
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs
index 3bd64804f..8735b9010 100644
--- a/crates/ra_ide/src/completion/complete_postfix.rs
+++ b/crates/ra_ide/src/completion/complete_postfix.rs
@@ -8,14 +8,13 @@ use ra_text_edit::TextEdit;
8 8
9use crate::{ 9use crate::{
10 completion::{ 10 completion::{
11 completion_config::SnippetCap,
11 completion_context::CompletionContext, 12 completion_context::CompletionContext,
12 completion_item::{Builder, CompletionKind, Completions}, 13 completion_item::{Builder, CompletionKind, Completions},
13 }, 14 },
14 CompletionItem, 15 CompletionItem, CompletionItemKind,
15}; 16};
16 17
17use super::completion_config::SnippetCap;
18
19pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { 18pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
20 if !ctx.config.enable_postfix_completions { 19 if !ctx.config.enable_postfix_completions {
21 return; 20 return;
@@ -103,10 +102,9 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
103 &format!("while {} {{\n $0\n}}", receiver_text), 102 &format!("while {} {{\n $0\n}}", receiver_text),
104 ) 103 )
105 .add_to(acc); 104 .add_to(acc);
105 postfix_snippet(ctx, cap, &dot_receiver, "not", "!expr", &format!("!{}", receiver_text))
106 .add_to(acc);
106 } 107 }
107 // !&&&42 is a compiler error, ergo process it before considering the references
108 postfix_snippet(ctx, cap, &dot_receiver, "not", "!expr", &format!("!{}", receiver_text))
109 .add_to(acc);
110 108
111 postfix_snippet(ctx, cap, &dot_receiver, "ref", "&expr", &format!("&{}", receiver_text)) 109 postfix_snippet(ctx, cap, &dot_receiver, "ref", "&expr", &format!("&{}", receiver_text))
112 .add_to(acc); 110 .add_to(acc);
@@ -125,33 +123,35 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
125 let dot_receiver = include_references(dot_receiver); 123 let dot_receiver = include_references(dot_receiver);
126 let receiver_text = 124 let receiver_text =
127 get_receiver_text(&dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal); 125 get_receiver_text(&dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal);
126
128 match try_enum { 127 match try_enum {
129 Some(try_enum) => { 128 Some(try_enum) => match try_enum {
130 match try_enum { 129 TryEnum::Result => {
131 TryEnum::Result => { 130 postfix_snippet(
132 postfix_snippet(
133 ctx, 131 ctx,
134 cap, 132 cap,
135 &dot_receiver, 133 &dot_receiver,
136 "match", 134 "match",
137 "match expr {}", 135 "match expr {}",
138 &format!("match {} {{\n Ok(${{1:_}}) => {{$2\\}},\n Err(${{3:_}}) => {{$0\\}},\n}}", receiver_text), 136 &format!("match {} {{\n Ok(${{1:_}}) => {{$2}},\n Err(${{3:_}}) => {{$0}},\n}}", receiver_text),
139 ) 137 )
140 .add_to(acc); 138 .add_to(acc);
141 } 139 }
142 TryEnum::Option => { 140 TryEnum::Option => {
143 postfix_snippet( 141 postfix_snippet(
144 ctx, 142 ctx,
145 cap, 143 cap,
146 &dot_receiver, 144 &dot_receiver,
147 "match", 145 "match",
148 "match expr {}", 146 "match expr {}",
149 &format!("match {} {{\n Some(${{1:_}}) => {{$2\\}},\n None => {{$0\\}},\n}}", receiver_text), 147 &format!(
148 "match {} {{\n Some(${{1:_}}) => {{$2}},\n None => {{$0}},\n}}",
149 receiver_text
150 ),
150 ) 151 )
151 .add_to(acc); 152 .add_to(acc);
152 }
153 } 153 }
154 } 154 },
155 None => { 155 None => {
156 postfix_snippet( 156 postfix_snippet(
157 ctx, 157 ctx,
@@ -159,7 +159,7 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
159 &dot_receiver, 159 &dot_receiver,
160 "match", 160 "match",
161 "match expr {}", 161 "match expr {}",
162 &format!("match {} {{\n ${{1:_}} => {{$0\\}},\n}}", receiver_text), 162 &format!("match {} {{\n ${{1:_}} => {{$0}},\n}}", receiver_text),
163 ) 163 )
164 .add_to(acc); 164 .add_to(acc);
165 } 165 }
@@ -232,536 +232,147 @@ fn postfix_snippet(
232 }; 232 };
233 CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label) 233 CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label)
234 .detail(detail) 234 .detail(detail)
235 .kind(CompletionItemKind::Snippet)
235 .snippet_edit(cap, edit) 236 .snippet_edit(cap, edit)
236} 237}
237 238
238#[cfg(test)] 239#[cfg(test)]
239mod tests { 240mod tests {
240 use insta::assert_debug_snapshot; 241 use expect::{expect, Expect};
241 242
242 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 243 use crate::completion::{
244 test_utils::{check_edit, completion_list},
245 CompletionKind,
246 };
243 247
244 fn do_postfix_completion(code: &str) -> Vec<CompletionItem> { 248 fn check(ra_fixture: &str, expect: Expect) {
245 do_completion(code, CompletionKind::Postfix) 249 let actual = completion_list(ra_fixture, CompletionKind::Postfix);
250 expect.assert_eq(&actual)
246 } 251 }
247 252
248 #[test] 253 #[test]
249 fn postfix_completion_works_for_trivial_path_expression() { 254 fn postfix_completion_works_for_trivial_path_expression() {
250 assert_debug_snapshot!( 255 check(
251 do_postfix_completion( 256 r#"
252 r#" 257fn main() {
253 fn main() { 258 let bar = true;
254 let bar = true; 259 bar.<|>
255 bar.<|> 260}
256 } 261"#,
257 "#, 262 expect![[r#"
258 ), 263 sn box Box::new(expr)
259 @r###" 264 sn call function(expr)
260 [ 265 sn dbg dbg!(expr)
261 CompletionItem { 266 sn if if expr {}
262 label: "box", 267 sn match match expr {}
263 source_range: 40..40, 268 sn not !expr
264 delete: 36..40, 269 sn ref &expr
265 insert: "Box::new(bar)", 270 sn refm &mut expr
266 detail: "Box::new(expr)", 271 sn while while expr {}
267 }, 272 "#]],
268 CompletionItem {
269 label: "call",
270 source_range: 40..40,
271 delete: 36..40,
272 insert: "${1}(bar)",
273 detail: "function(expr)",
274 },
275 CompletionItem {
276 label: "dbg",
277 source_range: 40..40,
278 delete: 36..40,
279 insert: "dbg!(bar)",
280 detail: "dbg!(expr)",
281 },
282 CompletionItem {
283 label: "if",
284 source_range: 40..40,
285 delete: 36..40,
286 insert: "if bar {\n $0\n}",
287 detail: "if expr {}",
288 },
289 CompletionItem {
290 label: "match",
291 source_range: 40..40,
292 delete: 36..40,
293 insert: "match bar {\n ${1:_} => {$0\\},\n}",
294 detail: "match expr {}",
295 },
296 CompletionItem {
297 label: "not",
298 source_range: 40..40,
299 delete: 36..40,
300 insert: "!bar",
301 detail: "!expr",
302 },
303 CompletionItem {
304 label: "ref",
305 source_range: 40..40,
306 delete: 36..40,
307 insert: "&bar",
308 detail: "&expr",
309 },
310 CompletionItem {
311 label: "refm",
312 source_range: 40..40,
313 delete: 36..40,
314 insert: "&mut bar",
315 detail: "&mut expr",
316 },
317 CompletionItem {
318 label: "while",
319 source_range: 40..40,
320 delete: 36..40,
321 insert: "while bar {\n $0\n}",
322 detail: "while expr {}",
323 },
324 ]
325 "###
326 ); 273 );
327 } 274 }
328 275
329 #[test] 276 #[test]
330 fn postfix_completion_works_for_option() { 277 fn postfix_type_filtering() {
331 assert_debug_snapshot!( 278 check(
332 do_postfix_completion( 279 r#"
333 r#" 280fn main() {
334 enum Option<T> { 281 let bar: u8 = 12;
335 Some(T), 282 bar.<|>
336 None, 283}
337 } 284"#,
338 285 expect![[r#"
339 fn main() { 286 sn box Box::new(expr)
340 let bar = Option::Some(true); 287 sn call function(expr)
341 bar.<|> 288 sn dbg dbg!(expr)
342 } 289 sn match match expr {}
343 "#, 290 sn ref &expr
344 ), 291 sn refm &mut expr
345 @r###" 292 "#]],
346 [ 293 )
347 CompletionItem {
348 label: "box",
349 source_range: 97..97,
350 delete: 93..97,
351 insert: "Box::new(bar)",
352 detail: "Box::new(expr)",
353 },
354 CompletionItem {
355 label: "call",
356 source_range: 97..97,
357 delete: 93..97,
358 insert: "${1}(bar)",
359 detail: "function(expr)",
360 },
361 CompletionItem {
362 label: "dbg",
363 source_range: 97..97,
364 delete: 93..97,
365 insert: "dbg!(bar)",
366 detail: "dbg!(expr)",
367 },
368 CompletionItem {
369 label: "ifl",
370 source_range: 97..97,
371 delete: 93..97,
372 insert: "if let Some($1) = bar {\n $0\n}",
373 detail: "if let Some {}",
374 },
375 CompletionItem {
376 label: "match",
377 source_range: 97..97,
378 delete: 93..97,
379 insert: "match bar {\n Some(${1:_}) => {$2\\},\n None => {$0\\},\n}",
380 detail: "match expr {}",
381 },
382 CompletionItem {
383 label: "not",
384 source_range: 97..97,
385 delete: 93..97,
386 insert: "!bar",
387 detail: "!expr",
388 },
389 CompletionItem {
390 label: "ref",
391 source_range: 97..97,
392 delete: 93..97,
393 insert: "&bar",
394 detail: "&expr",
395 },
396 CompletionItem {
397 label: "refm",
398 source_range: 97..97,
399 delete: 93..97,
400 insert: "&mut bar",
401 detail: "&mut expr",
402 },
403 CompletionItem {
404 label: "while",
405 source_range: 97..97,
406 delete: 93..97,
407 insert: "while let Some($1) = bar {\n $0\n}",
408 detail: "while let Some {}",
409 },
410 ]
411 "###
412 );
413 } 294 }
414 295
415 #[test] 296 #[test]
416 fn postfix_completion_works_for_result() { 297 fn option_iflet() {
417 assert_debug_snapshot!( 298 check_edit(
418 do_postfix_completion( 299 "ifl",
419 r#" 300 r#"
420 enum Result<T, E> { 301enum Option<T> { Some(T), None }
421 Ok(T), 302
422 Err(E), 303fn main() {
423 } 304 let bar = Option::Some(true);
305 bar.<|>
306}
307"#,
308 r#"
309enum Option<T> { Some(T), None }
424 310
425 fn main() { 311fn main() {
426 let bar = Result::Ok(true); 312 let bar = Option::Some(true);
427 bar.<|> 313 if let Some($1) = bar {
428 } 314 $0
429 "#, 315}
430 ), 316}
431 @r###" 317"#,
432 [
433 CompletionItem {
434 label: "box",
435 source_range: 98..98,
436 delete: 94..98,
437 insert: "Box::new(bar)",
438 detail: "Box::new(expr)",
439 },
440 CompletionItem {
441 label: "call",
442 source_range: 98..98,
443 delete: 94..98,
444 insert: "${1}(bar)",
445 detail: "function(expr)",
446 },
447 CompletionItem {
448 label: "dbg",
449 source_range: 98..98,
450 delete: 94..98,
451 insert: "dbg!(bar)",
452 detail: "dbg!(expr)",
453 },
454 CompletionItem {
455 label: "ifl",
456 source_range: 98..98,
457 delete: 94..98,
458 insert: "if let Ok($1) = bar {\n $0\n}",
459 detail: "if let Ok {}",
460 },
461 CompletionItem {
462 label: "match",
463 source_range: 98..98,
464 delete: 94..98,
465 insert: "match bar {\n Ok(${1:_}) => {$2\\},\n Err(${3:_}) => {$0\\},\n}",
466 detail: "match expr {}",
467 },
468 CompletionItem {
469 label: "not",
470 source_range: 98..98,
471 delete: 94..98,
472 insert: "!bar",
473 detail: "!expr",
474 },
475 CompletionItem {
476 label: "ref",
477 source_range: 98..98,
478 delete: 94..98,
479 insert: "&bar",
480 detail: "&expr",
481 },
482 CompletionItem {
483 label: "refm",
484 source_range: 98..98,
485 delete: 94..98,
486 insert: "&mut bar",
487 detail: "&mut expr",
488 },
489 CompletionItem {
490 label: "while",
491 source_range: 98..98,
492 delete: 94..98,
493 insert: "while let Ok($1) = bar {\n $0\n}",
494 detail: "while let Ok {}",
495 },
496 ]
497 "###
498 ); 318 );
499 } 319 }
500 320
501 #[test] 321 #[test]
502 fn some_postfix_completions_ignored() { 322 fn result_match() {
503 assert_debug_snapshot!( 323 check_edit(
504 do_postfix_completion( 324 "match",
505 r#" 325 r#"
506 fn main() { 326enum Result<T, E> { Ok(T), Err(E) }
507 let bar: u8 = 12; 327
508 bar.<|> 328fn main() {
509 } 329 let bar = Result::Ok(true);
510 "#, 330 bar.<|>
511 ), 331}
512 @r###" 332"#,
513 [ 333 r#"
514 CompletionItem { 334enum Result<T, E> { Ok(T), Err(E) }
515 label: "box", 335
516 source_range: 42..42, 336fn main() {
517 delete: 38..42, 337 let bar = Result::Ok(true);
518 insert: "Box::new(bar)", 338 match bar {
519 detail: "Box::new(expr)", 339 Ok(${1:_}) => {$2},
520 }, 340 Err(${3:_}) => {$0},
521 CompletionItem { 341}
522 label: "call", 342}
523 source_range: 42..42, 343"#,
524 delete: 38..42,
525 insert: "${1}(bar)",
526 detail: "function(expr)",
527 },
528 CompletionItem {
529 label: "dbg",
530 source_range: 42..42,
531 delete: 38..42,
532 insert: "dbg!(bar)",
533 detail: "dbg!(expr)",
534 },
535 CompletionItem {
536 label: "match",
537 source_range: 42..42,
538 delete: 38..42,
539 insert: "match bar {\n ${1:_} => {$0\\},\n}",
540 detail: "match expr {}",
541 },
542 CompletionItem {
543 label: "not",
544 source_range: 42..42,
545 delete: 38..42,
546 insert: "!bar",
547 detail: "!expr",
548 },
549 CompletionItem {
550 label: "ref",
551 source_range: 42..42,
552 delete: 38..42,
553 insert: "&bar",
554 detail: "&expr",
555 },
556 CompletionItem {
557 label: "refm",
558 source_range: 42..42,
559 delete: 38..42,
560 insert: "&mut bar",
561 detail: "&mut expr",
562 },
563 ]
564 "###
565 ); 344 );
566 } 345 }
567 346
568 #[test] 347 #[test]
569 fn postfix_completion_works_for_ambiguous_float_literal() { 348 fn postfix_completion_works_for_ambiguous_float_literal() {
570 assert_debug_snapshot!( 349 check_edit("refm", r#"fn main() { 42.<|> }"#, r#"fn main() { &mut 42 }"#)
571 do_postfix_completion(
572 r#"
573 fn main() {
574 42.<|>
575 }
576 "#,
577 ),
578 @r###"
579 [
580 CompletionItem {
581 label: "box",
582 source_range: 19..19,
583 delete: 16..19,
584 insert: "Box::new(42)",
585 detail: "Box::new(expr)",
586 },
587 CompletionItem {
588 label: "call",
589 source_range: 19..19,
590 delete: 16..19,
591 insert: "${1}(42)",
592 detail: "function(expr)",
593 },
594 CompletionItem {
595 label: "dbg",
596 source_range: 19..19,
597 delete: 16..19,
598 insert: "dbg!(42)",
599 detail: "dbg!(expr)",
600 },
601 CompletionItem {
602 label: "match",
603 source_range: 19..19,
604 delete: 16..19,
605 insert: "match 42 {\n ${1:_} => {$0\\},\n}",
606 detail: "match expr {}",
607 },
608 CompletionItem {
609 label: "not",
610 source_range: 19..19,
611 delete: 16..19,
612 insert: "!42",
613 detail: "!expr",
614 },
615 CompletionItem {
616 label: "ref",
617 source_range: 19..19,
618 delete: 16..19,
619 insert: "&42",
620 detail: "&expr",
621 },
622 CompletionItem {
623 label: "refm",
624 source_range: 19..19,
625 delete: 16..19,
626 insert: "&mut 42",
627 detail: "&mut expr",
628 },
629 ]
630 "###
631 );
632 } 350 }
633 351
634 #[test] 352 #[test]
635 fn works_in_simple_macro() { 353 fn works_in_simple_macro() {
636 assert_debug_snapshot!( 354 check_edit(
637 do_postfix_completion( 355 "dbg",
638 r#" 356 r#"
639 macro_rules! m { ($e:expr) => { $e } } 357macro_rules! m { ($e:expr) => { $e } }
640 fn main() { 358fn main() {
641 let bar: u8 = 12; 359 let bar: u8 = 12;
642 m!(bar.b<|>) 360 m!(bar.d<|>)
643 } 361}
644 "#, 362"#,
645 ), 363 r#"
646 @r###" 364macro_rules! m { ($e:expr) => { $e } }
647 [ 365fn main() {
648 CompletionItem { 366 let bar: u8 = 12;
649 label: "box", 367 m!(dbg!(bar))
650 source_range: 84..85, 368}
651 delete: 80..85, 369"#,
652 insert: "Box::new(bar)",
653 detail: "Box::new(expr)",
654 },
655 CompletionItem {
656 label: "call",
657 source_range: 84..85,
658 delete: 80..85,
659 insert: "${1}(bar)",
660 detail: "function(expr)",
661 },
662 CompletionItem {
663 label: "dbg",
664 source_range: 84..85,
665 delete: 80..85,
666 insert: "dbg!(bar)",
667 detail: "dbg!(expr)",
668 },
669 CompletionItem {
670 label: "match",
671 source_range: 84..85,
672 delete: 80..85,
673 insert: "match bar {\n ${1:_} => {$0\\},\n}",
674 detail: "match expr {}",
675 },
676 CompletionItem {
677 label: "not",
678 source_range: 84..85,
679 delete: 80..85,
680 insert: "!bar",
681 detail: "!expr",
682 },
683 CompletionItem {
684 label: "ref",
685 source_range: 84..85,
686 delete: 80..85,
687 insert: "&bar",
688 detail: "&expr",
689 },
690 CompletionItem {
691 label: "refm",
692 source_range: 84..85,
693 delete: 80..85,
694 insert: "&mut bar",
695 detail: "&mut expr",
696 },
697 ]
698 "###
699 ); 370 );
700 } 371 }
701 372
702 #[test] 373 #[test]
703 fn postfix_completion_for_references() { 374 fn postfix_completion_for_references() {
704 assert_debug_snapshot!( 375 check_edit("dbg", r#"fn main() { &&42.<|> }"#, r#"fn main() { dbg!(&&42) }"#);
705 do_postfix_completion( 376 check_edit("refm", r#"fn main() { &&42.<|> }"#, r#"fn main() { &&&mut 42 }"#);
706 r#"
707 fn main() {
708 &&&&42.<|>
709 }
710 "#,
711 ),
712 @r###"
713 [
714 CompletionItem {
715 label: "box",
716 source_range: 23..23,
717 delete: 16..23,
718 insert: "Box::new(&&&&42)",
719 detail: "Box::new(expr)",
720 },
721 CompletionItem {
722 label: "call",
723 source_range: 23..23,
724 delete: 16..23,
725 insert: "${1}(&&&&42)",
726 detail: "function(expr)",
727 },
728 CompletionItem {
729 label: "dbg",
730 source_range: 23..23,
731 delete: 16..23,
732 insert: "dbg!(&&&&42)",
733 detail: "dbg!(expr)",
734 },
735 CompletionItem {
736 label: "match",
737 source_range: 23..23,
738 delete: 16..23,
739 insert: "match &&&&42 {\n ${1:_} => {$0\\},\n}",
740 detail: "match expr {}",
741 },
742 CompletionItem {
743 label: "not",
744 source_range: 23..23,
745 delete: 20..23,
746 insert: "!42",
747 detail: "!expr",
748 },
749 CompletionItem {
750 label: "ref",
751 source_range: 23..23,
752 delete: 20..23,
753 insert: "&42",
754 detail: "&expr",
755 },
756 CompletionItem {
757 label: "refm",
758 source_range: 23..23,
759 delete: 20..23,
760 insert: "&mut 42",
761 detail: "&mut expr",
762 },
763 ]
764 "###
765 );
766 } 377 }
767} 378}
diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs
index f133ce3ce..b08f5b9b4 100644
--- a/crates/ra_ide/src/completion/complete_qualified_path.rs
+++ b/crates/ra_ide/src/completion/complete_qualified_path.rs
@@ -17,21 +17,20 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
17 return; 17 return;
18 } 18 }
19 19
20 let scope = ctx.scope(); 20 let context_module = ctx.scope.module();
21 let context_module = scope.module();
22 21
23 let res = match scope.resolve_hir_path_qualifier(&path) { 22 let resolution = match ctx.scope.resolve_hir_path_qualifier(&path) {
24 Some(res) => res, 23 Some(res) => res,
25 None => return, 24 None => return,
26 }; 25 };
27 26
28 // Add associated types on type parameters and `Self`. 27 // Add associated types on type parameters and `Self`.
29 res.assoc_type_shorthand_candidates(ctx.db, |alias| { 28 resolution.assoc_type_shorthand_candidates(ctx.db, |alias| {
30 acc.add_type_alias(ctx, alias); 29 acc.add_type_alias(ctx, alias);
31 None::<()> 30 None::<()>
32 }); 31 });
33 32
34 match res { 33 match resolution {
35 PathResolution::Def(hir::ModuleDef::Module(module)) => { 34 PathResolution::Def(hir::ModuleDef::Module(module)) => {
36 let module_scope = module.scope(ctx.db, context_module); 35 let module_scope = module.scope(ctx.db, context_module);
37 for (name, def) in module_scope { 36 for (name, def) in module_scope {
@@ -68,7 +67,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
68 67
69 let krate = ctx.krate; 68 let krate = ctx.krate;
70 if let Some(krate) = krate { 69 if let Some(krate) = krate {
71 let traits_in_scope = ctx.scope().traits_in_scope(); 70 let traits_in_scope = ctx.scope.traits_in_scope();
72 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { 71 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| {
73 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { 72 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
74 return None; 73 return None;
@@ -113,13 +112,13 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
113 } 112 }
114 PathResolution::TypeParam(_) | PathResolution::SelfType(_) => { 113 PathResolution::TypeParam(_) | PathResolution::SelfType(_) => {
115 if let Some(krate) = ctx.krate { 114 if let Some(krate) = ctx.krate {
116 let ty = match res { 115 let ty = match resolution {
117 PathResolution::TypeParam(param) => param.ty(ctx.db), 116 PathResolution::TypeParam(param) => param.ty(ctx.db),
118 PathResolution::SelfType(impl_def) => impl_def.target_ty(ctx.db), 117 PathResolution::SelfType(impl_def) => impl_def.target_ty(ctx.db),
119 _ => return, 118 _ => return,
120 }; 119 };
121 120
122 let traits_in_scope = ctx.scope().traits_in_scope(); 121 let traits_in_scope = ctx.scope.traits_in_scope();
123 let mut seen = FxHashSet::default(); 122 let mut seen = FxHashSet::default();
124 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { 123 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| {
125 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { 124 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
@@ -147,1229 +146,588 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
147 146
148#[cfg(test)] 147#[cfg(test)]
149mod tests { 148mod tests {
149 use expect::{expect, Expect};
150 use test_utils::mark; 150 use test_utils::mark;
151 151
152 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 152 use crate::completion::{
153 use insta::assert_debug_snapshot; 153 test_utils::{check_edit, completion_list},
154 CompletionKind,
155 };
156
157 fn check(ra_fixture: &str, expect: Expect) {
158 let actual = completion_list(ra_fixture, CompletionKind::Reference);
159 expect.assert_eq(&actual);
160 }
154 161
155 fn do_reference_completion(code: &str) -> Vec<CompletionItem> { 162 fn check_builtin(ra_fixture: &str, expect: Expect) {
156 do_completion(code, CompletionKind::Reference) 163 let actual = completion_list(ra_fixture, CompletionKind::BuiltinType);
164 expect.assert_eq(&actual);
157 } 165 }
158 166
159 #[test] 167 #[test]
160 fn dont_complete_current_use() { 168 fn dont_complete_current_use() {
161 mark::check!(dont_complete_current_use); 169 mark::check!(dont_complete_current_use);
162 let completions = do_completion(r"use self::foo<|>;", CompletionKind::Reference); 170 check(r#"use self::foo<|>;"#, expect![[""]]);
163 assert!(completions.is_empty());
164 } 171 }
165 172
166 #[test] 173 #[test]
167 fn dont_complete_current_use_in_braces_with_glob() { 174 fn dont_complete_current_use_in_braces_with_glob() {
168 let completions = do_completion( 175 check(
169 r" 176 r#"
170 mod foo { pub struct S; } 177mod foo { pub struct S; }
171 use self::{foo::*, bar<|>}; 178use self::{foo::*, bar<|>};
172 ", 179"#,
173 CompletionKind::Reference, 180 expect![[r#"
181 st S
182 md foo
183 "#]],
174 ); 184 );
175 assert_eq!(completions.len(), 2);
176 } 185 }
177 186
178 #[test] 187 #[test]
179 fn dont_complete_primitive_in_use() { 188 fn dont_complete_primitive_in_use() {
180 let completions = do_completion(r"use self::<|>;", CompletionKind::BuiltinType); 189 check_builtin(r#"use self::<|>;"#, expect![[""]]);
181 assert!(completions.is_empty());
182 } 190 }
183 191
184 #[test] 192 #[test]
185 fn dont_complete_primitive_in_module_scope() { 193 fn dont_complete_primitive_in_module_scope() {
186 let completions = do_completion(r"fn foo() { self::<|> }", CompletionKind::BuiltinType); 194 check_builtin(r#"fn foo() { self::<|> }"#, expect![[""]]);
187 assert!(completions.is_empty());
188 } 195 }
189 196
190 #[test] 197 #[test]
191 fn completes_primitives() { 198 fn completes_primitives() {
192 let completions = 199 check_builtin(
193 do_completion(r"fn main() { let _: <|> = 92; }", CompletionKind::BuiltinType); 200 r#"fn main() { let _: <|> = 92; }"#,
194 assert_eq!(completions.len(), 17); 201 expect![[r#"
195 } 202 bt bool
196 203 bt char
197 #[test] 204 bt f32
198 fn completes_mod_with_docs() { 205 bt f64
199 assert_debug_snapshot!( 206 bt i128
200 do_reference_completion( 207 bt i16
201 r" 208 bt i32
202 use self::my<|>; 209 bt i64
203 210 bt i8
204 /// Some simple 211 bt isize
205 /// docs describing `mod my`. 212 bt str
206 mod my { 213 bt u128
207 struct Bar; 214 bt u16
208 } 215 bt u32
209 " 216 bt u64
210 ), 217 bt u8
211 @r###" 218 bt usize
212 [ 219 "#]],
213 CompletionItem {
214 label: "my",
215 source_range: 10..12,
216 delete: 10..12,
217 insert: "my",
218 kind: Module,
219 documentation: Documentation(
220 "Some simple\ndocs describing `mod my`.",
221 ),
222 },
223 ]
224 "###
225 ); 220 );
226 } 221 }
227 222
228 #[test] 223 #[test]
229 fn completes_mod_with_same_name_as_function() { 224 fn completes_mod_with_same_name_as_function() {
230 assert_debug_snapshot!( 225 check(
231 do_reference_completion( 226 r#"
232 r" 227use self::my::<|>;
233 use self::my::<|>; 228
234 229mod my { pub struct Bar; }
235 mod my { 230fn my() {}
236 pub struct Bar; 231"#,
237 } 232 expect![[r#"
238 233 st Bar
239 fn my() {} 234 "#]],
240 "
241 ),
242 @r###"
243 [
244 CompletionItem {
245 label: "Bar",
246 source_range: 14..14,
247 delete: 14..14,
248 insert: "Bar",
249 kind: Struct,
250 },
251 ]
252 "###
253 ); 235 );
254 } 236 }
255 237
256 #[test] 238 #[test]
257 fn path_visibility() { 239 fn filters_visibility() {
258 assert_debug_snapshot!( 240 check(
259 do_reference_completion( 241 r#"
260 r" 242use self::my::<|>;
261 use self::my::<|>; 243
262 244mod my {
263 mod my { 245 struct Bar;
264 struct Bar; 246 pub struct Foo;
265 pub struct Foo; 247 pub use Bar as PublicBar;
266 pub use Bar as PublicBar; 248}
267 } 249"#,
268 " 250 expect![[r#"
269 ), 251 st Foo
270 @r###" 252 st PublicBar
271 [ 253 "#]],
272 CompletionItem {
273 label: "Foo",
274 source_range: 14..14,
275 delete: 14..14,
276 insert: "Foo",
277 kind: Struct,
278 },
279 CompletionItem {
280 label: "PublicBar",
281 source_range: 14..14,
282 delete: 14..14,
283 insert: "PublicBar",
284 kind: Struct,
285 },
286 ]
287 "###
288 ); 254 );
289 } 255 }
290 256
291 #[test] 257 #[test]
292 fn completes_use_item_starting_with_self() { 258 fn completes_use_item_starting_with_self() {
293 assert_debug_snapshot!( 259 check(
294 do_reference_completion( 260 r#"
295 r" 261use self::m::<|>;
296 use self::m::<|>;
297 262
298 mod m { 263mod m { pub struct Bar; }
299 pub struct Bar; 264"#,
300 } 265 expect![[r#"
301 " 266 st Bar
302 ), 267 "#]],
303 @r###"
304 [
305 CompletionItem {
306 label: "Bar",
307 source_range: 13..13,
308 delete: 13..13,
309 insert: "Bar",
310 kind: Struct,
311 },
312 ]
313 "###
314 ); 268 );
315 } 269 }
316 270
317 #[test] 271 #[test]
318 fn completes_use_item_starting_with_crate() { 272 fn completes_use_item_starting_with_crate() {
319 assert_debug_snapshot!( 273 check(
320 do_reference_completion( 274 r#"
321 " 275//- /lib.rs
322 //- /lib.rs 276mod foo;
323 mod foo; 277struct Spam;
324 struct Spam; 278//- /foo.rs
325 //- /foo.rs 279use crate::Sp<|>
326 use crate::Sp<|> 280"#,
327 " 281 expect![[r#"
328 ), 282 st Spam
329 @r###" 283 md foo
330 [ 284 "#]],
331 CompletionItem {
332 label: "Spam",
333 source_range: 11..13,
334 delete: 11..13,
335 insert: "Spam",
336 kind: Struct,
337 },
338 CompletionItem {
339 label: "foo",
340 source_range: 11..13,
341 delete: 11..13,
342 insert: "foo",
343 kind: Module,
344 },
345 ]
346 "###
347 ); 285 );
348 } 286 }
349 287
350 #[test] 288 #[test]
351 fn completes_nested_use_tree() { 289 fn completes_nested_use_tree() {
352 assert_debug_snapshot!( 290 check(
353 do_reference_completion( 291 r#"
354 " 292//- /lib.rs
355 //- /lib.rs 293mod foo;
356 mod foo; 294struct Spam;
357 struct Spam; 295//- /foo.rs
358 //- /foo.rs 296use crate::{Sp<|>};
359 use crate::{Sp<|>}; 297"#,
360 " 298 expect![[r#"
361 ), 299 st Spam
362 @r###" 300 md foo
363 [ 301 "#]],
364 CompletionItem {
365 label: "Spam",
366 source_range: 12..14,
367 delete: 12..14,
368 insert: "Spam",
369 kind: Struct,
370 },
371 CompletionItem {
372 label: "foo",
373 source_range: 12..14,
374 delete: 12..14,
375 insert: "foo",
376 kind: Module,
377 },
378 ]
379 "###
380 ); 302 );
381 } 303 }
382 304
383 #[test] 305 #[test]
384 fn completes_deeply_nested_use_tree() { 306 fn completes_deeply_nested_use_tree() {
385 assert_debug_snapshot!( 307 check(
386 do_reference_completion( 308 r#"
387 " 309//- /lib.rs
388 //- /lib.rs 310mod foo;
389 mod foo; 311pub mod bar {
390 pub mod bar { 312 pub mod baz {
391 pub mod baz { 313 pub struct Spam;
392 pub struct Spam;
393 }
394 }
395 //- /foo.rs
396 use crate::{bar::{baz::Sp<|>}};
397 "
398 ),
399 @r###"
400 [
401 CompletionItem {
402 label: "Spam",
403 source_range: 23..25,
404 delete: 23..25,
405 insert: "Spam",
406 kind: Struct,
407 },
408 ]
409 "###
410 );
411 }
412
413 #[test]
414 fn completes_enum_variant() {
415 assert_debug_snapshot!(
416 do_reference_completion(
417 "
418 //- /lib.rs
419 /// An enum
420 enum E {
421 /// Foo Variant
422 Foo,
423 /// Bar Variant with i32
424 Bar(i32)
425 }
426 fn foo() { let _ = E::<|> }
427 "
428 ),
429 @r###"
430 [
431 CompletionItem {
432 label: "Bar(…)",
433 source_range: 116..116,
434 delete: 116..116,
435 insert: "Bar($0)",
436 kind: EnumVariant,
437 lookup: "Bar",
438 detail: "(i32)",
439 documentation: Documentation(
440 "Bar Variant with i32",
441 ),
442 trigger_call_info: true,
443 },
444 CompletionItem {
445 label: "Foo",
446 source_range: 116..116,
447 delete: 116..116,
448 insert: "Foo",
449 kind: EnumVariant,
450 detail: "()",
451 documentation: Documentation(
452 "Foo Variant",
453 ),
454 },
455 ]
456 "###
457 );
458 }
459
460 #[test]
461 fn completes_enum_variant_with_details() {
462 assert_debug_snapshot!(
463 do_reference_completion(
464 "
465 //- /lib.rs
466 struct S { field: u32 }
467 /// An enum
468 enum E {
469 /// Foo Variant (empty)
470 Foo,
471 /// Bar Variant with i32 and u32
472 Bar(i32, u32),
473 ///
474 S(S),
475 }
476 fn foo() { let _ = E::<|> }
477 "
478 ),
479 @r###"
480 [
481 CompletionItem {
482 label: "Bar(…)",
483 source_range: 180..180,
484 delete: 180..180,
485 insert: "Bar($0)",
486 kind: EnumVariant,
487 lookup: "Bar",
488 detail: "(i32, u32)",
489 documentation: Documentation(
490 "Bar Variant with i32 and u32",
491 ),
492 trigger_call_info: true,
493 },
494 CompletionItem {
495 label: "Foo",
496 source_range: 180..180,
497 delete: 180..180,
498 insert: "Foo",
499 kind: EnumVariant,
500 detail: "()",
501 documentation: Documentation(
502 "Foo Variant (empty)",
503 ),
504 },
505 CompletionItem {
506 label: "S(…)",
507 source_range: 180..180,
508 delete: 180..180,
509 insert: "S($0)",
510 kind: EnumVariant,
511 lookup: "S",
512 detail: "(S)",
513 documentation: Documentation(
514 "",
515 ),
516 trigger_call_info: true,
517 },
518 ]
519 "###
520 );
521 } 314 }
522 315}
523 #[test] 316//- /foo.rs
524 fn completes_struct_associated_method() { 317use crate::{bar::{baz::Sp<|>}};
525 assert_debug_snapshot!( 318"#,
526 do_reference_completion( 319 expect![[r#"
527 " 320 st Spam
528 //- /lib.rs 321 "#]],
529 /// A Struct
530 struct S;
531
532 impl S {
533 /// An associated method
534 fn m() { }
535 }
536
537 fn foo() { let _ = S::<|> }
538 "
539 ),
540 @r###"
541 [
542 CompletionItem {
543 label: "m()",
544 source_range: 102..102,
545 delete: 102..102,
546 insert: "m()$0",
547 kind: Function,
548 lookup: "m",
549 detail: "fn m()",
550 documentation: Documentation(
551 "An associated method",
552 ),
553 },
554 ]
555 "###
556 ); 322 );
557 } 323 }
558 324
559 #[test] 325 #[test]
560 fn completes_struct_associated_method_with_self() { 326 fn completes_enum_variant() {
561 assert_debug_snapshot!( 327 check(
562 do_reference_completion( 328 r#"
563 " 329enum E { Foo, Bar(i32) }
564 //- /lib.rs 330fn foo() { let _ = E::<|> }
565 /// A Struct 331"#,
566 struct S; 332 expect![[r#"
567 333 ev Bar(…) (i32)
568 impl S { 334 ev Foo ()
569 /// An associated method 335 "#]],
570 fn m(&self) { }
571 }
572
573 fn foo() { let _ = S::<|> }
574 "
575 ),
576 @r###"
577 [
578 CompletionItem {
579 label: "m()",
580 source_range: 107..107,
581 delete: 107..107,
582 insert: "m()$0",
583 kind: Method,
584 lookup: "m",
585 detail: "fn m(&self)",
586 documentation: Documentation(
587 "An associated method",
588 ),
589 },
590 ]
591 "###
592 ); 336 );
593 } 337 }
594 338
595 #[test] 339 #[test]
596 fn completes_struct_associated_const() { 340 fn completes_struct_associated_items() {
597 assert_debug_snapshot!( 341 check(
598 do_reference_completion( 342 r#"
599 " 343//- /lib.rs
600 //- /lib.rs 344struct S;
601 /// A Struct 345
602 struct S; 346impl S {
603 347 fn a() {}
604 impl S { 348 fn b(&self) {}
605 /// An associated const 349 const C: i32 = 42;
606 const C: i32 = 42; 350 type T = i32;
607 } 351}
608 352
609 fn foo() { let _ = S::<|> } 353fn foo() { let _ = S::<|> }
610 " 354"#,
611 ), 355 expect![[r#"
612 @r###" 356 ct C const C: i32 = 42;
613 [ 357 ta T type T = i32;
614 CompletionItem { 358 fn a() fn a()
615 label: "C", 359 me b() fn b(&self)
616 source_range: 109..109, 360 "#]],
617 delete: 109..109,
618 insert: "C",
619 kind: Const,
620 detail: "const C: i32 = 42;",
621 documentation: Documentation(
622 "An associated const",
623 ),
624 },
625 ]
626 "###
627 ); 361 );
628 } 362 }
629 363
630 #[test] 364 #[test]
631 fn completes_struct_associated_type() { 365 fn associated_item_visibility() {
632 assert_debug_snapshot!( 366 check(
633 do_reference_completion( 367 r#"
634 " 368struct S;
635 //- /lib.rs
636 /// A Struct
637 struct S;
638
639 impl S {
640 /// An associated type
641 type T = i32;
642 }
643 369
644 fn foo() { let _ = S::<|> } 370mod m {
645 " 371 impl super::S {
646 ), 372 pub(super) fn public_method() { }
647 @r###" 373 fn private_method() { }
648 [ 374 pub(super) type PublicType = u32;
649 CompletionItem { 375 type PrivateType = u32;
650 label: "T", 376 pub(super) const PUBLIC_CONST: u32 = 1;
651 source_range: 103..103, 377 const PRIVATE_CONST: u32 = 1;
652 delete: 103..103,
653 insert: "T",
654 kind: TypeAlias,
655 detail: "type T = i32;",
656 documentation: Documentation(
657 "An associated type",
658 ),
659 },
660 ]
661 "###
662 );
663 } 378 }
379}
664 380
665 #[test] 381fn foo() { let _ = S::<|> }
666 fn associated_item_visibility() { 382"#,
667 assert_debug_snapshot!( 383 expect![[r#"
668 do_reference_completion( 384 ct PUBLIC_CONST pub(super) const PUBLIC_CONST: u32 = 1;
669 " 385 ta PublicType pub(super) type PublicType = u32;
670 //- /lib.rs 386 fn public_method() pub(super) fn public_method()
671 struct S; 387 "#]],
672
673 mod m {
674 impl super::S {
675 pub(super) fn public_method() { }
676 fn private_method() { }
677 pub(super) type PublicType = u32;
678 type PrivateType = u32;
679 pub(super) const PUBLIC_CONST: u32 = 1;
680 const PRIVATE_CONST: u32 = 1;
681 }
682 }
683
684 fn foo() { let _ = S::<|> }
685 "
686 ),
687 @r###"
688 [
689 CompletionItem {
690 label: "PUBLIC_CONST",
691 source_range: 304..304,
692 delete: 304..304,
693 insert: "PUBLIC_CONST",
694 kind: Const,
695 detail: "pub(super) const PUBLIC_CONST: u32 = 1;",
696 },
697 CompletionItem {
698 label: "PublicType",
699 source_range: 304..304,
700 delete: 304..304,
701 insert: "PublicType",
702 kind: TypeAlias,
703 detail: "pub(super) type PublicType = u32;",
704 },
705 CompletionItem {
706 label: "public_method()",
707 source_range: 304..304,
708 delete: 304..304,
709 insert: "public_method()$0",
710 kind: Function,
711 lookup: "public_method",
712 detail: "pub(super) fn public_method()",
713 },
714 ]
715 "###
716 ); 388 );
717 } 389 }
718 390
719 #[test] 391 #[test]
720 fn completes_enum_associated_method() { 392 fn completes_enum_associated_method() {
721 assert_debug_snapshot!( 393 check(
722 do_reference_completion( 394 r#"
723 " 395enum E {};
724 //- /lib.rs 396impl E { fn m() { } }
725 /// An enum 397
726 enum S {}; 398fn foo() { let _ = E::<|> }
727 399 "#,
728 impl S { 400 expect![[r#"
729 /// An associated method 401 fn m() fn m()
730 fn m() { } 402 "#]],
731 }
732
733 fn foo() { let _ = S::<|> }
734 "
735 ),
736 @r###"
737 [
738 CompletionItem {
739 label: "m()",
740 source_range: 102..102,
741 delete: 102..102,
742 insert: "m()$0",
743 kind: Function,
744 lookup: "m",
745 detail: "fn m()",
746 documentation: Documentation(
747 "An associated method",
748 ),
749 },
750 ]
751 "###
752 ); 403 );
753 } 404 }
754 405
755 #[test] 406 #[test]
756 fn completes_union_associated_method() { 407 fn completes_union_associated_method() {
757 assert_debug_snapshot!( 408 check(
758 do_reference_completion( 409 r#"
759 " 410union U {};
760 //- /lib.rs 411impl U { fn m() { } }
761 /// A union 412
762 union U {}; 413fn foo() { let _ = U::<|> }
763 414"#,
764 impl U { 415 expect![[r#"
765 /// An associated method 416 fn m() fn m()
766 fn m() { } 417 "#]],
767 }
768
769 fn foo() { let _ = U::<|> }
770 "
771 ),
772 @r###"
773 [
774 CompletionItem {
775 label: "m()",
776 source_range: 103..103,
777 delete: 103..103,
778 insert: "m()$0",
779 kind: Function,
780 lookup: "m",
781 detail: "fn m()",
782 documentation: Documentation(
783 "An associated method",
784 ),
785 },
786 ]
787 "###
788 ); 418 );
789 } 419 }
790 420
791 #[test] 421 #[test]
792 fn completes_use_paths_across_crates() { 422 fn completes_use_paths_across_crates() {
793 assert_debug_snapshot!( 423 check(
794 do_reference_completion( 424 r#"
795 " 425//- /main.rs
796 //- /main.rs 426use foo::<|>;
797 use foo::<|>; 427
798 428//- /foo/lib.rs
799 //- /foo/lib.rs 429pub mod bar { pub struct S; }
800 pub mod bar { 430"#,
801 pub struct S; 431 expect![[r#"
802 } 432 md bar
803 " 433 "#]],
804 ),
805 @r###"
806 [
807 CompletionItem {
808 label: "bar",
809 source_range: 9..9,
810 delete: 9..9,
811 insert: "bar",
812 kind: Module,
813 },
814 ]
815 "###
816 ); 434 );
817 } 435 }
818 436
819 #[test] 437 #[test]
820 fn completes_trait_associated_method_1() { 438 fn completes_trait_associated_method_1() {
821 assert_debug_snapshot!( 439 check(
822 do_reference_completion( 440 r#"
823 " 441trait Trait { fn m(); }
824 //- /lib.rs
825 trait Trait {
826 /// A trait method
827 fn m();
828 }
829 442
830 fn foo() { let _ = Trait::<|> } 443fn foo() { let _ = Trait::<|> }
831 " 444"#,
832 ), 445 expect![[r#"
833 @r###" 446 fn m() fn m()
834 [ 447 "#]],
835 CompletionItem {
836 label: "m()",
837 source_range: 74..74,
838 delete: 74..74,
839 insert: "m()$0",
840 kind: Function,
841 lookup: "m",
842 detail: "fn m()",
843 documentation: Documentation(
844 "A trait method",
845 ),
846 },
847 ]
848 "###
849 ); 448 );
850 } 449 }
851 450
852 #[test] 451 #[test]
853 fn completes_trait_associated_method_2() { 452 fn completes_trait_associated_method_2() {
854 assert_debug_snapshot!( 453 check(
855 do_reference_completion( 454 r#"
856 " 455trait Trait { fn m(); }
857 //- /lib.rs 456
858 trait Trait { 457struct S;
859 /// A trait method 458impl Trait for S {}
860 fn m();
861 }
862 459
863 struct S; 460fn foo() { let _ = S::<|> }
864 impl Trait for S {} 461"#,
865 462 expect![[r#"
866 fn foo() { let _ = S::<|> } 463 fn m() fn m()
867 " 464 "#]],
868 ),
869 @r###"
870 [
871 CompletionItem {
872 label: "m()",
873 source_range: 101..101,
874 delete: 101..101,
875 insert: "m()$0",
876 kind: Function,
877 lookup: "m",
878 detail: "fn m()",
879 documentation: Documentation(
880 "A trait method",
881 ),
882 },
883 ]
884 "###
885 ); 465 );
886 } 466 }
887 467
888 #[test] 468 #[test]
889 fn completes_trait_associated_method_3() { 469 fn completes_trait_associated_method_3() {
890 assert_debug_snapshot!( 470 check(
891 do_reference_completion( 471 r#"
892 " 472trait Trait { fn m(); }
893 //- /lib.rs
894 trait Trait {
895 /// A trait method
896 fn m();
897 }
898 473
899 struct S; 474struct S;
900 impl Trait for S {} 475impl Trait for S {}
901 476
902 fn foo() { let _ = <S as Trait>::<|> } 477fn foo() { let _ = <S as Trait>::<|> }
903 " 478"#,
904 ), 479 expect![[r#"
905 @r###" 480 fn m() fn m()
906 [ 481 "#]],
907 CompletionItem {
908 label: "m()",
909 source_range: 112..112,
910 delete: 112..112,
911 insert: "m()$0",
912 kind: Function,
913 lookup: "m",
914 detail: "fn m()",
915 documentation: Documentation(
916 "A trait method",
917 ),
918 },
919 ]
920 "###
921 ); 482 );
922 } 483 }
923 484
924 #[test] 485 #[test]
925 fn completes_ty_param_assoc_ty() { 486 fn completes_ty_param_assoc_ty() {
926 assert_debug_snapshot!( 487 check(
927 do_reference_completion( 488 r#"
928 " 489trait Super {
929 //- /lib.rs 490 type Ty;
930 trait Super { 491 const CONST: u8;
931 type Ty; 492 fn func() {}
932 const CONST: u8; 493 fn method(&self) {}
933 fn func() {} 494}
934 fn method(&self) {}
935 }
936 495
937 trait Sub: Super { 496trait Sub: Super {
938 type SubTy; 497 type SubTy;
939 const C2: (); 498 const C2: ();
940 fn subfunc() {} 499 fn subfunc() {}
941 fn submethod(&self) {} 500 fn submethod(&self) {}
942 } 501}
943 502
944 fn foo<T: Sub>() { 503fn foo<T: Sub>() { T::<|> }
945 T::<|> 504"#,
946 } 505 expect![[r#"
947 " 506 ct C2 const C2: ();
948 ), 507 ct CONST const CONST: u8;
949 @r###" 508 ta SubTy type SubTy;
950 [ 509 ta Ty type Ty;
951 CompletionItem { 510 fn func() fn func()
952 label: "C2", 511 me method() fn method(&self)
953 source_range: 221..221, 512 fn subfunc() fn subfunc()
954 delete: 221..221, 513 me submethod() fn submethod(&self)
955 insert: "C2", 514 "#]],
956 kind: Const,
957 detail: "const C2: ();",
958 },
959 CompletionItem {
960 label: "CONST",
961 source_range: 221..221,
962 delete: 221..221,
963 insert: "CONST",
964 kind: Const,
965 detail: "const CONST: u8;",
966 },
967 CompletionItem {
968 label: "SubTy",
969 source_range: 221..221,
970 delete: 221..221,
971 insert: "SubTy",
972 kind: TypeAlias,
973 detail: "type SubTy;",
974 },
975 CompletionItem {
976 label: "Ty",
977 source_range: 221..221,
978 delete: 221..221,
979 insert: "Ty",
980 kind: TypeAlias,
981 detail: "type Ty;",
982 },
983 CompletionItem {
984 label: "func()",
985 source_range: 221..221,
986 delete: 221..221,
987 insert: "func()$0",
988 kind: Function,
989 lookup: "func",
990 detail: "fn func()",
991 },
992 CompletionItem {
993 label: "method()",
994 source_range: 221..221,
995 delete: 221..221,
996 insert: "method()$0",
997 kind: Method,
998 lookup: "method",
999 detail: "fn method(&self)",
1000 },
1001 CompletionItem {
1002 label: "subfunc()",
1003 source_range: 221..221,
1004 delete: 221..221,
1005 insert: "subfunc()$0",
1006 kind: Function,
1007 lookup: "subfunc",
1008 detail: "fn subfunc()",
1009 },
1010 CompletionItem {
1011 label: "submethod()",
1012 source_range: 221..221,
1013 delete: 221..221,
1014 insert: "submethod()$0",
1015 kind: Method,
1016 lookup: "submethod",
1017 detail: "fn submethod(&self)",
1018 },
1019 ]
1020 "###
1021 ); 515 );
1022 } 516 }
1023 517
1024 #[test] 518 #[test]
1025 fn completes_self_param_assoc_ty() { 519 fn completes_self_param_assoc_ty() {
1026 assert_debug_snapshot!( 520 check(
1027 do_reference_completion( 521 r#"
1028 " 522trait Super {
1029 //- /lib.rs 523 type Ty;
1030 trait Super { 524 const CONST: u8 = 0;
1031 type Ty; 525 fn func() {}
1032 const CONST: u8 = 0; 526 fn method(&self) {}
1033 fn func() {} 527}
1034 fn method(&self) {}
1035 }
1036 528
1037 trait Sub: Super { 529trait Sub: Super {
1038 type SubTy; 530 type SubTy;
1039 const C2: () = (); 531 const C2: () = ();
1040 fn subfunc() {} 532 fn subfunc() {}
1041 fn submethod(&self) {} 533 fn submethod(&self) {}
1042 } 534}
1043 535
1044 struct Wrap<T>(T); 536struct Wrap<T>(T);
1045 impl<T> Super for Wrap<T> {} 537impl<T> Super for Wrap<T> {}
1046 impl<T> Sub for Wrap<T> { 538impl<T> Sub for Wrap<T> {
1047 fn subfunc() { 539 fn subfunc() {
1048 // Should be able to assume `Self: Sub + Super` 540 // Should be able to assume `Self: Sub + Super`
1049 Self::<|> 541 Self::<|>
1050 } 542 }
1051 } 543}
1052 " 544"#,
1053 ), 545 expect![[r#"
1054 @r###" 546 ct C2 const C2: () = ();
1055 [ 547 ct CONST const CONST: u8 = 0;
1056 CompletionItem { 548 ta SubTy type SubTy;
1057 label: "C2", 549 ta Ty type Ty;
1058 source_range: 367..367, 550 fn func() fn func()
1059 delete: 367..367, 551 me method() fn method(&self)
1060 insert: "C2", 552 fn subfunc() fn subfunc()
1061 kind: Const, 553 me submethod() fn submethod(&self)
1062 detail: "const C2: () = ();", 554 "#]],
1063 },
1064 CompletionItem {
1065 label: "CONST",
1066 source_range: 367..367,
1067 delete: 367..367,
1068 insert: "CONST",
1069 kind: Const,
1070 detail: "const CONST: u8 = 0;",
1071 },
1072 CompletionItem {
1073 label: "SubTy",
1074 source_range: 367..367,
1075 delete: 367..367,
1076 insert: "SubTy",
1077 kind: TypeAlias,
1078 detail: "type SubTy;",
1079 },
1080 CompletionItem {
1081 label: "Ty",
1082 source_range: 367..367,
1083 delete: 367..367,
1084 insert: "Ty",
1085 kind: TypeAlias,
1086 detail: "type Ty;",
1087 },
1088 CompletionItem {
1089 label: "func()",
1090 source_range: 367..367,
1091 delete: 367..367,
1092 insert: "func()$0",
1093 kind: Function,
1094 lookup: "func",
1095 detail: "fn func()",
1096 },
1097 CompletionItem {
1098 label: "method()",
1099 source_range: 367..367,
1100 delete: 367..367,
1101 insert: "method()$0",
1102 kind: Method,
1103 lookup: "method",
1104 detail: "fn method(&self)",
1105 },
1106 CompletionItem {
1107 label: "subfunc()",
1108 source_range: 367..367,
1109 delete: 367..367,
1110 insert: "subfunc()$0",
1111 kind: Function,
1112 lookup: "subfunc",
1113 detail: "fn subfunc()",
1114 },
1115 CompletionItem {
1116 label: "submethod()",
1117 source_range: 367..367,
1118 delete: 367..367,
1119 insert: "submethod()$0",
1120 kind: Method,
1121 lookup: "submethod",
1122 detail: "fn submethod(&self)",
1123 },
1124 ]
1125 "###
1126 ); 555 );
1127 } 556 }
1128 557
1129 #[test] 558 #[test]
1130 fn completes_type_alias() { 559 fn completes_type_alias() {
1131 assert_debug_snapshot!( 560 check(
1132 do_reference_completion( 561 r#"
1133 " 562struct S;
1134 struct S; 563impl S { fn foo() {} }
1135 impl S { fn foo() {} } 564type T = S;
1136 type T = S; 565impl T { fn bar() {} }
1137 impl T { fn bar() {} } 566
1138 567fn main() { T::<|>; }
1139 fn main() { 568"#,
1140 T::<|>; 569 expect![[r#"
1141 } 570 fn bar() fn bar()
1142 " 571 fn foo() fn foo()
1143 ), 572 "#]],
1144 @r###"
1145 [
1146 CompletionItem {
1147 label: "bar()",
1148 source_range: 88..88,
1149 delete: 88..88,
1150 insert: "bar()$0",
1151 kind: Function,
1152 lookup: "bar",
1153 detail: "fn bar()",
1154 },
1155 CompletionItem {
1156 label: "foo()",
1157 source_range: 88..88,
1158 delete: 88..88,
1159 insert: "foo()$0",
1160 kind: Function,
1161 lookup: "foo",
1162 detail: "fn foo()",
1163 },
1164 ]
1165 "###
1166 ); 573 );
1167 } 574 }
1168 575
1169 #[test] 576 #[test]
1170 fn completes_qualified_macros() { 577 fn completes_qualified_macros() {
1171 assert_debug_snapshot!( 578 check(
1172 do_reference_completion( 579 r#"
1173 " 580#[macro_export]
1174 #[macro_export] 581macro_rules! foo { () => {} }
1175 macro_rules! foo { 582
1176 () => {} 583fn main() { let _ = crate::<|> }
1177 } 584 "#,
585 expect![[r##"
586 ma foo!(…) #[macro_export]
587 macro_rules! foo
588 fn main() fn main()
589 "##]],
590 );
591 }
1178 592
1179 fn main() { 593 #[test]
1180 let _ = crate::<|> 594 fn test_super_super_completion() {
1181 } 595 check(
1182 " 596 r#"
1183 ), 597mod a {
1184 @r###" 598 const A: usize = 0;
1185 [ 599 mod b {
1186 CompletionItem { 600 const B: usize = 0;
1187 label: "foo!(…)", 601 mod c { use super::super::<|> }
1188 source_range: 82..82, 602 }
1189 delete: 82..82, 603}
1190 insert: "foo!($0)", 604"#,
1191 kind: Macro, 605 expect![[r#"
1192 detail: "#[macro_export]\nmacro_rules! foo", 606 ct A
1193 }, 607 md b
1194 CompletionItem { 608 "#]],
1195 label: "main()",
1196 source_range: 82..82,
1197 delete: 82..82,
1198 insert: "main()$0",
1199 kind: Function,
1200 lookup: "main",
1201 detail: "fn main()",
1202 },
1203 ]
1204 "###
1205 ); 609 );
1206 } 610 }
1207 611
1208 #[test] 612 #[test]
1209 fn completes_reexported_items_under_correct_name() { 613 fn completes_reexported_items_under_correct_name() {
1210 assert_debug_snapshot!( 614 check(
1211 do_reference_completion( 615 r#"
1212 r" 616fn foo() { self::m::<|> }
1213 fn foo() {
1214 self::m::<|>
1215 }
1216 617
1217 mod m { 618mod m {
1218 pub use super::p::wrong_fn as right_fn; 619 pub use super::p::wrong_fn as right_fn;
1219 pub use super::p::WRONG_CONST as RIGHT_CONST; 620 pub use super::p::WRONG_CONST as RIGHT_CONST;
1220 pub use super::p::WrongType as RightType; 621 pub use super::p::WrongType as RightType;
1221 } 622}
1222 mod p { 623mod p {
1223 fn wrong_fn() {} 624 fn wrong_fn() {}
1224 const WRONG_CONST: u32 = 1; 625 const WRONG_CONST: u32 = 1;
1225 struct WrongType {}; 626 struct WrongType {};
1226 } 627}
1227 " 628"#,
1228 ), 629 expect![[r#"
1229 @r###" 630 ct RIGHT_CONST
1230 [ 631 st RightType
1231 CompletionItem { 632 fn right_fn() fn wrong_fn()
1232 label: "RIGHT_CONST", 633 "#]],
1233 source_range: 24..24, 634 );
1234 delete: 24..24, 635
1235 insert: "RIGHT_CONST", 636 check_edit(
1236 kind: Const, 637 "RightType",
1237 }, 638 r#"
1238 CompletionItem { 639fn foo() { self::m::<|> }
1239 label: "RightType", 640
1240 source_range: 24..24, 641mod m {
1241 delete: 24..24, 642 pub use super::p::wrong_fn as right_fn;
1242 insert: "RightType", 643 pub use super::p::WRONG_CONST as RIGHT_CONST;
1243 kind: Struct, 644 pub use super::p::WrongType as RightType;
1244 }, 645}
1245 CompletionItem { 646mod p {
1246 label: "right_fn()", 647 fn wrong_fn() {}
1247 source_range: 24..24, 648 const WRONG_CONST: u32 = 1;
1248 delete: 24..24, 649 struct WrongType {};
1249 insert: "right_fn()$0", 650}
1250 kind: Function, 651"#,
1251 lookup: "right_fn", 652 r#"
1252 detail: "fn wrong_fn()", 653fn foo() { self::m::RightType }
1253 }, 654
1254 ] 655mod m {
1255 "### 656 pub use super::p::wrong_fn as right_fn;
657 pub use super::p::WRONG_CONST as RIGHT_CONST;
658 pub use super::p::WrongType as RightType;
659}
660mod p {
661 fn wrong_fn() {}
662 const WRONG_CONST: u32 = 1;
663 struct WrongType {};
664}
665"#,
1256 ); 666 );
1257 } 667 }
1258 668
1259 #[test] 669 #[test]
1260 fn completes_in_simple_macro_call() { 670 fn completes_in_simple_macro_call() {
1261 let completions = do_reference_completion( 671 check(
1262 r#" 672 r#"
1263 macro_rules! m { ($e:expr) => { $e } } 673macro_rules! m { ($e:expr) => { $e } }
1264 fn main() { m!(self::f<|>); } 674fn main() { m!(self::f<|>); }
1265 fn foo() {} 675fn foo() {}
1266 "#, 676"#,
677 expect![[r#"
678 fn foo() fn foo()
679 fn main() fn main()
680 "#]],
1267 ); 681 );
1268 assert_debug_snapshot!(completions, @r###"
1269 [
1270 CompletionItem {
1271 label: "foo()",
1272 source_range: 60..61,
1273 delete: 60..61,
1274 insert: "foo()$0",
1275 kind: Function,
1276 lookup: "foo",
1277 detail: "fn foo()",
1278 },
1279 CompletionItem {
1280 label: "main()",
1281 source_range: 60..61,
1282 delete: 60..61,
1283 insert: "main()$0",
1284 kind: Function,
1285 lookup: "main",
1286 detail: "fn main()",
1287 },
1288 ]
1289 "###);
1290 } 682 }
1291 683
1292 #[test] 684 #[test]
1293 fn function_mod_share_name() { 685 fn function_mod_share_name() {
1294 assert_debug_snapshot!( 686 check(
1295 do_reference_completion( 687 r#"
1296 r" 688fn foo() { self::m::<|> }
1297 fn foo() {
1298 self::m::<|>
1299 }
1300 689
1301 mod m { 690mod m {
1302 pub mod z {} 691 pub mod z {}
1303 pub fn z() {} 692 pub fn z() {}
1304 } 693}
1305 ", 694"#,
1306 ), 695 expect![[r#"
1307 @r###" 696 md z
1308 [ 697 fn z() pub fn z()
1309 CompletionItem { 698 "#]],
1310 label: "z",
1311 source_range: 24..24,
1312 delete: 24..24,
1313 insert: "z",
1314 kind: Module,
1315 },
1316 CompletionItem {
1317 label: "z()",
1318 source_range: 24..24,
1319 delete: 24..24,
1320 insert: "z()$0",
1321 kind: Function,
1322 lookup: "z",
1323 detail: "pub fn z()",
1324 },
1325 ]
1326 "###
1327 ); 699 );
1328 } 700 }
1329 701
1330 #[test] 702 #[test]
1331 fn completes_hashmap_new() { 703 fn completes_hashmap_new() {
1332 assert_debug_snapshot!( 704 check(
1333 do_reference_completion( 705 r#"
1334 r" 706struct RandomState;
1335 struct RandomState; 707struct HashMap<K, V, S = RandomState> {}
1336 struct HashMap<K, V, S = RandomState> {} 708
1337 709impl<K, V> HashMap<K, V, RandomState> {
1338 impl<K, V> HashMap<K, V, RandomState> { 710 pub fn new() -> HashMap<K, V, RandomState> { }
1339 pub fn new() -> HashMap<K, V, RandomState> { } 711}
1340 } 712fn foo() {
1341 fn foo() { 713 HashMap::<|>
1342 HashMap::<|> 714}
1343 } 715"#,
1344 " 716 expect![[r#"
1345 ), 717 fn new() pub fn new() -> HashMap<K, V, RandomState>
1346 @r###" 718 "#]],
1347 [
1348 CompletionItem {
1349 label: "new()",
1350 source_range: 179..179,
1351 delete: 179..179,
1352 insert: "new()$0",
1353 kind: Function,
1354 lookup: "new",
1355 detail: "pub fn new() -> HashMap<K, V, RandomState>",
1356 },
1357 ]
1358 "###
1359 ); 719 );
1360 } 720 }
1361 721
1362 #[test] 722 #[test]
1363 fn dont_complete_attr() { 723 fn dont_complete_attr() {
1364 assert_debug_snapshot!( 724 check(
1365 do_reference_completion( 725 r#"
1366 r" 726mod foo { pub struct Foo; }
1367 mod foo { pub struct Foo; } 727#[foo::<|>]
1368 #[foo::<|>] 728fn f() {}
1369 fn f() {} 729"#,
1370 " 730 expect![[""]],
1371 ), 731 );
1372 @r###"[]"###
1373 )
1374 } 732 }
1375} 733}
diff --git a/crates/ra_ide/src/completion/complete_record.rs b/crates/ra_ide/src/completion/complete_record.rs
index 13eb2f79f..74b94594d 100644
--- a/crates/ra_ide/src/completion/complete_record.rs
+++ b/crates/ra_ide/src/completion/complete_record.rs
@@ -18,389 +18,209 @@ pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
18 18
19#[cfg(test)] 19#[cfg(test)]
20mod tests { 20mod tests {
21 mod record_pat_tests { 21 use expect::{expect, Expect};
22 use insta::assert_debug_snapshot;
23 22
24 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 23 use crate::completion::{test_utils::completion_list, CompletionKind};
25 24
26 fn complete(code: &str) -> Vec<CompletionItem> { 25 fn check(ra_fixture: &str, expect: Expect) {
27 do_completion(code, CompletionKind::Reference) 26 let actual = completion_list(ra_fixture, CompletionKind::Reference);
28 } 27 expect.assert_eq(&actual);
29 28 }
30 #[test]
31 fn test_record_pattern_field() {
32 let completions = complete(
33 r"
34 struct S { foo: u32 }
35
36 fn process(f: S) {
37 match f {
38 S { f<|>: 92 } => (),
39 }
40 }
41 ",
42 );
43 assert_debug_snapshot!(completions, @r###"
44 [
45 CompletionItem {
46 label: "foo",
47 source_range: 68..69,
48 delete: 68..69,
49 insert: "foo",
50 kind: Field,
51 detail: "u32",
52 },
53 ]
54 "###);
55 }
56
57 #[test]
58 fn test_record_pattern_enum_variant() {
59 let completions = complete(
60 r"
61 enum E {
62 S { foo: u32, bar: () }
63 }
64
65 fn process(e: E) {
66 match e {
67 E::S { <|> } => (),
68 }
69 }
70 ",
71 );
72 assert_debug_snapshot!(completions, @r###"
73 [
74 CompletionItem {
75 label: "bar",
76 source_range: 88..88,
77 delete: 88..88,
78 insert: "bar",
79 kind: Field,
80 detail: "()",
81 },
82 CompletionItem {
83 label: "foo",
84 source_range: 88..88,
85 delete: 88..88,
86 insert: "foo",
87 kind: Field,
88 detail: "u32",
89 },
90 ]
91 "###);
92 }
93 29
94 #[test] 30 #[test]
95 fn test_record_pattern_field_in_simple_macro() { 31 fn test_record_pattern_field() {
96 let completions = complete( 32 check(
97 r" 33 r#"
98 macro_rules! m { ($e:expr) => { $e } } 34struct S { foo: u32 }
99 struct S { foo: u32 }
100 35
101 fn process(f: S) { 36fn process(f: S) {
102 m!(match f { 37 match f {
103 S { f<|>: 92 } => (), 38 S { f<|>: 92 } => (),
104 }) 39 }
105 } 40}
106 ", 41"#,
107 ); 42 expect![[r#"
108 assert_debug_snapshot!(completions, @r###" 43 fd foo u32
109 [ 44 "#]],
110 CompletionItem { 45 );
111 label: "foo", 46 }
112 source_range: 110..111,
113 delete: 110..111,
114 insert: "foo",
115 kind: Field,
116 detail: "u32",
117 },
118 ]
119 "###);
120 }
121 47
122 #[test] 48 #[test]
123 fn only_missing_fields_are_completed_in_destruct_pats() { 49 fn test_record_pattern_enum_variant() {
124 let completions = complete( 50 check(
125 r" 51 r#"
126 struct S { 52enum E { S { foo: u32, bar: () } }
127 foo1: u32,
128 foo2: u32,
129 bar: u32,
130 baz: u32,
131 }
132 53
133 fn main() { 54fn process(e: E) {
134 let s = S { 55 match e {
135 foo1: 1, 56 E::S { <|> } => (),
136 foo2: 2, 57 }
137 bar: 3, 58}
138 baz: 4, 59"#,
139 }; 60 expect![[r#"
140 if let S { foo1, foo2: a, <|> } = s {} 61 fd bar ()
141 } 62 fd foo u32
142 ", 63 "#]],
143 ); 64 );
144 assert_debug_snapshot!(completions, @r###"
145 [
146 CompletionItem {
147 label: "bar",
148 source_range: 203..203,
149 delete: 203..203,
150 insert: "bar",
151 kind: Field,
152 detail: "u32",
153 },
154 CompletionItem {
155 label: "baz",
156 source_range: 203..203,
157 delete: 203..203,
158 insert: "baz",
159 kind: Field,
160 detail: "u32",
161 },
162 ]
163 "###);
164 }
165 } 65 }
166 66
167 mod record_lit_tests { 67 #[test]
168 use insta::assert_debug_snapshot; 68 fn test_record_pattern_field_in_simple_macro() {
169 69 check(
170 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 70 r"
71macro_rules! m { ($e:expr) => { $e } }
72struct S { foo: u32 }
73
74fn process(f: S) {
75 m!(match f {
76 S { f<|>: 92 } => (),
77 })
78}
79",
80 expect![[r#"
81 fd foo u32
82 "#]],
83 );
84 }
171 85
172 fn complete(code: &str) -> Vec<CompletionItem> { 86 #[test]
173 do_completion(code, CompletionKind::Reference) 87 fn only_missing_fields_are_completed_in_destruct_pats() {
174 } 88 check(
89 r#"
90struct S {
91 foo1: u32, foo2: u32,
92 bar: u32, baz: u32,
93}
175 94
176 #[test] 95fn main() {
177 fn test_record_literal_deprecated_field() { 96 let s = S {
178 let completions = complete( 97 foo1: 1, foo2: 2,
179 r" 98 bar: 3, baz: 4,
180 struct A { 99 };
181 #[deprecated] 100 if let S { foo1, foo2: a, <|> } = s {}
182 the_field: u32, 101}
183 } 102"#,
184 fn foo() { 103 expect![[r#"
185 A { the<|> } 104 fd bar u32
186 } 105 fd baz u32
187 ", 106 "#]],
188 ); 107 );
189 assert_debug_snapshot!(completions, @r###" 108 }
190 [
191 CompletionItem {
192 label: "the_field",
193 source_range: 69..72,
194 delete: 69..72,
195 insert: "the_field",
196 kind: Field,
197 detail: "u32",
198 deprecated: true,
199 },
200 ]
201 "###);
202 }
203 109
204 #[test] 110 #[test]
205 fn test_record_literal_field() { 111 fn test_record_literal_field() {
206 let completions = complete( 112 check(
207 r" 113 r#"
208 struct A { the_field: u32 } 114struct A { the_field: u32 }
209 fn foo() { 115fn foo() {
210 A { the<|> } 116 A { the<|> }
211 } 117}
212 ", 118"#,
213 ); 119 expect![[r#"
214 assert_debug_snapshot!(completions, @r###" 120 fd the_field u32
215 [ 121 "#]],
216 CompletionItem { 122 );
217 label: "the_field", 123 }
218 source_range: 46..49,
219 delete: 46..49,
220 insert: "the_field",
221 kind: Field,
222 detail: "u32",
223 },
224 ]
225 "###);
226 }
227 124
228 #[test] 125 #[test]
229 fn test_record_literal_enum_variant() { 126 fn test_record_literal_enum_variant() {
230 let completions = complete( 127 check(
231 r" 128 r#"
232 enum E { 129enum E { A { a: u32 } }
233 A { a: u32 } 130fn foo() {
234 } 131 let _ = E::A { <|> }
235 fn foo() { 132}
236 let _ = E::A { <|> } 133"#,
237 } 134 expect![[r#"
238 ", 135 fd a u32
239 ); 136 "#]],
240 assert_debug_snapshot!(completions, @r###" 137 );
241 [ 138 }
242 CompletionItem {
243 label: "a",
244 source_range: 58..58,
245 delete: 58..58,
246 insert: "a",
247 kind: Field,
248 detail: "u32",
249 },
250 ]
251 "###);
252 }
253 139
254 #[test] 140 #[test]
255 fn test_record_literal_two_structs() { 141 fn test_record_literal_two_structs() {
256 let completions = complete( 142 check(
257 r" 143 r#"
258 struct A { a: u32 } 144struct A { a: u32 }
259 struct B { b: u32 } 145struct B { b: u32 }
260 146
261 fn foo() { 147fn foo() {
262 let _: A = B { <|> } 148 let _: A = B { <|> }
263 } 149}
264 ", 150"#,
265 ); 151 expect![[r#"
266 assert_debug_snapshot!(completions, @r###" 152 fd b u32
267 [ 153 "#]],
268 CompletionItem { 154 );
269 label: "b", 155 }
270 source_range: 70..70,
271 delete: 70..70,
272 insert: "b",
273 kind: Field,
274 detail: "u32",
275 },
276 ]
277 "###);
278 }
279 156
280 #[test] 157 #[test]
281 fn test_record_literal_generic_struct() { 158 fn test_record_literal_generic_struct() {
282 let completions = complete( 159 check(
283 r" 160 r#"
284 struct A<T> { a: T } 161struct A<T> { a: T }
285 162
286 fn foo() { 163fn foo() {
287 let _: A<u32> = A { <|> } 164 let _: A<u32> = A { <|> }
288 } 165}
289 ", 166"#,
290 ); 167 expect![[r#"
291 assert_debug_snapshot!(completions, @r###" 168 fd a u32
292 [ 169 "#]],
293 CompletionItem { 170 );
294 label: "a", 171 }
295 source_range: 56..56,
296 delete: 56..56,
297 insert: "a",
298 kind: Field,
299 detail: "u32",
300 },
301 ]
302 "###);
303 }
304 172
305 #[test] 173 #[test]
306 fn test_record_literal_field_in_simple_macro() { 174 fn test_record_literal_field_in_simple_macro() {
307 let completions = complete( 175 check(
308 r" 176 r#"
309 macro_rules! m { ($e:expr) => { $e } } 177macro_rules! m { ($e:expr) => { $e } }
310 struct A { the_field: u32 } 178struct A { the_field: u32 }
311 fn foo() { 179fn foo() {
312 m!(A { the<|> }) 180 m!(A { the<|> })
313 } 181}
314 ", 182"#,
315 ); 183 expect![[r#"
316 assert_debug_snapshot!(completions, @r###" 184 fd the_field u32
317 [ 185 "#]],
318 CompletionItem { 186 );
319 label: "the_field", 187 }
320 source_range: 88..91,
321 delete: 88..91,
322 insert: "the_field",
323 kind: Field,
324 detail: "u32",
325 },
326 ]
327 "###);
328 }
329 188
330 #[test] 189 #[test]
331 fn only_missing_fields_are_completed() { 190 fn only_missing_fields_are_completed() {
332 let completions = complete( 191 check(
333 r" 192 r#"
334 struct S { 193struct S {
335 foo1: u32, 194 foo1: u32, foo2: u32,
336 foo2: u32, 195 bar: u32, baz: u32,
337 bar: u32, 196}
338 baz: u32,
339 }
340 197
341 fn main() { 198fn main() {
342 let foo1 = 1; 199 let foo1 = 1;
343 let s = S { 200 let s = S { foo1, foo2: 5, <|> }
344 foo1, 201}
345 foo2: 5, 202"#,
346 <|> 203 expect![[r#"
347 } 204 fd bar u32
348 } 205 fd baz u32
349 ", 206 "#]],
350 ); 207 );
351 assert_debug_snapshot!(completions, @r###" 208 }
352 [
353 CompletionItem {
354 label: "bar",
355 source_range: 157..157,
356 delete: 157..157,
357 insert: "bar",
358 kind: Field,
359 detail: "u32",
360 },
361 CompletionItem {
362 label: "baz",
363 source_range: 157..157,
364 delete: 157..157,
365 insert: "baz",
366 kind: Field,
367 detail: "u32",
368 },
369 ]
370 "###);
371 }
372 209
373 #[test] 210 #[test]
374 fn completes_functional_update() { 211 fn completes_functional_update() {
375 let completions = complete( 212 check(
376 r" 213 r#"
377 struct S { 214struct S { foo1: u32, foo2: u32 }
378 foo1: u32,
379 foo2: u32,
380 }
381 215
382 fn main() { 216fn main() {
383 let foo1 = 1; 217 let foo1 = 1;
384 let s = S { 218 let s = S { foo1, <|> .. loop {} }
385 foo1, 219}
386 <|> 220"#,
387 .. loop {} 221 expect![[r#"
388 } 222 fd foo2 u32
389 } 223 "#]],
390 ", 224 );
391 );
392 assert_debug_snapshot!(completions, @r###"
393 [
394 CompletionItem {
395 label: "foo2",
396 source_range: 112..112,
397 delete: 112..112,
398 insert: "foo2",
399 kind: Field,
400 detail: "u32",
401 },
402 ]
403 "###);
404 }
405 } 225 }
406} 226}
diff --git a/crates/ra_ide/src/completion/complete_snippet.rs b/crates/ra_ide/src/completion/complete_snippet.rs
index 52aaa70f0..28d8f7876 100644
--- a/crates/ra_ide/src/completion/complete_snippet.rs
+++ b/crates/ra_ide/src/completion/complete_snippet.rs
@@ -70,95 +70,47 @@ fn ${1:feature}() {
70 70
71#[cfg(test)] 71#[cfg(test)]
72mod tests { 72mod tests {
73 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 73 use expect::{expect, Expect};
74 use insta::assert_debug_snapshot;
75 74
76 fn do_snippet_completion(code: &str) -> Vec<CompletionItem> { 75 use crate::completion::{test_utils::completion_list, CompletionKind};
77 do_completion(code, CompletionKind::Snippet) 76
77 fn check(ra_fixture: &str, expect: Expect) {
78 let actual = completion_list(ra_fixture, CompletionKind::Snippet);
79 expect.assert_eq(&actual)
78 } 80 }
79 81
80 #[test] 82 #[test]
81 fn completes_snippets_in_expressions() { 83 fn completes_snippets_in_expressions() {
82 assert_debug_snapshot!( 84 check(
83 do_snippet_completion(r"fn foo(x: i32) { <|> }"), 85 r#"fn foo(x: i32) { <|> }"#,
84 @r###" 86 expect![[r#"
85 [ 87 sn pd
86 CompletionItem { 88 sn ppd
87 label: "pd", 89 "#]],
88 source_range: 17..17, 90 );
89 delete: 17..17,
90 insert: "eprintln!(\"$0 = {:?}\", $0);",
91 kind: Snippet,
92 },
93 CompletionItem {
94 label: "ppd",
95 source_range: 17..17,
96 delete: 17..17,
97 insert: "eprintln!(\"$0 = {:#?}\", $0);",
98 kind: Snippet,
99 },
100 ]
101 "###
102 );
103 } 91 }
104 92
105 #[test] 93 #[test]
106 fn should_not_complete_snippets_in_path() { 94 fn should_not_complete_snippets_in_path() {
107 assert_debug_snapshot!( 95 check(r#"fn foo(x: i32) { ::foo<|> }"#, expect![[""]]);
108 do_snippet_completion(r"fn foo(x: i32) { ::foo<|> }"), 96 check(r#"fn foo(x: i32) { ::<|> }"#, expect![[""]]);
109 @"[]"
110 );
111 assert_debug_snapshot!(
112 do_snippet_completion(r"fn foo(x: i32) { ::<|> }"),
113 @"[]"
114 );
115 } 97 }
116 98
117 #[test] 99 #[test]
118 fn completes_snippets_in_items() { 100 fn completes_snippets_in_items() {
119 assert_debug_snapshot!( 101 check(
120 do_snippet_completion( 102 r#"
121 r" 103#[cfg(test)]
122 #[cfg(test)] 104mod tests {
123 mod tests { 105 <|>
124 <|> 106}
125 } 107"#,
126 " 108 expect![[r#"
127 ), 109 sn Test function
128 @r###" 110 sn Test module
129 [ 111 sn macro_rules
130 CompletionItem { 112 sn pub(crate)
131 label: "Test function", 113 "#]],
132 source_range: 29..29, 114 )
133 delete: 29..29,
134 insert: "#[test]\nfn ${1:feature}() {\n $0\n}",
135 kind: Snippet,
136 lookup: "tfn",
137 },
138 CompletionItem {
139 label: "Test module",
140 source_range: 29..29,
141 delete: 29..29,
142 insert: "#[cfg(test)]\nmod tests {\n use super::*;\n\n #[test]\n fn ${1:test_name}() {\n $0\n }\n}",
143 kind: Snippet,
144 lookup: "tmod",
145 },
146 CompletionItem {
147 label: "macro_rules",
148 source_range: 29..29,
149 delete: 29..29,
150 insert: "macro_rules! $1 {\n\t($2) => {\n\t\t$0\n\t};\n}",
151 kind: Snippet,
152 },
153 CompletionItem {
154 label: "pub(crate)",
155 source_range: 29..29,
156 delete: 29..29,
157 insert: "pub(crate) $0",
158 kind: Snippet,
159 },
160 ]
161 "###
162 );
163 } 115 }
164} 116}
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs
index 23e42928d..d9a0ef167 100644
--- a/crates/ra_ide/src/completion/complete_trait_impl.rs
+++ b/crates/ra_ide/src/completion/complete_trait_impl.rs
@@ -2,8 +2,8 @@
2//! 2//!
3//! This module adds the completion items related to implementing associated 3//! This module adds the completion items related to implementing associated
4//! items within a `impl Trait for Struct` block. The current context node 4//! items within a `impl Trait for Struct` block. The current context node
5//! must be within either a `FN_DEF`, `TYPE_ALIAS_DEF`, or `CONST_DEF` node 5//! must be within either a `FN`, `TYPE_ALIAS`, or `CONST` node
6//! and an direct child of an `IMPL_DEF`. 6//! and an direct child of an `IMPL`.
7//! 7//!
8//! # Examples 8//! # Examples
9//! 9//!
@@ -34,7 +34,7 @@
34use hir::{self, Docs, HasSource}; 34use hir::{self, Docs, HasSource};
35use ra_assists::utils::get_missing_assoc_items; 35use ra_assists::utils::get_missing_assoc_items;
36use ra_syntax::{ 36use ra_syntax::{
37 ast::{self, edit, ImplDef}, 37 ast::{self, edit, Impl},
38 AstNode, SyntaxKind, SyntaxNode, TextRange, T, 38 AstNode, SyntaxKind, SyntaxNode, TextRange, T,
39}; 39};
40use ra_text_edit::TextEdit; 40use ra_text_edit::TextEdit;
@@ -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_declaration,
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) {
@@ -63,7 +63,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext
63 } 63 }
64 }), 64 }),
65 65
66 SyntaxKind::FN_DEF => { 66 SyntaxKind::FN => {
67 for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def) 67 for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
68 .into_iter() 68 .into_iter()
69 .filter_map(|item| match item { 69 .filter_map(|item| match item {
@@ -75,7 +75,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext
75 } 75 }
76 } 76 }
77 77
78 SyntaxKind::TYPE_ALIAS_DEF => { 78 SyntaxKind::TYPE_ALIAS => {
79 for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def) 79 for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
80 .into_iter() 80 .into_iter()
81 .filter_map(|item| match item { 81 .filter_map(|item| match item {
@@ -87,7 +87,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext
87 } 87 }
88 } 88 }
89 89
90 SyntaxKind::CONST_DEF => { 90 SyntaxKind::CONST => {
91 for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def) 91 for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
92 .into_iter() 92 .into_iter()
93 .filter_map(|item| match item { 93 .filter_map(|item| match item {
@@ -104,18 +104,17 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext
104 } 104 }
105} 105}
106 106
107fn completion_match(ctx: &CompletionContext) -> Option<(SyntaxNode, ImplDef)> { 107fn completion_match(ctx: &CompletionContext) -> Option<(SyntaxNode, Impl)> {
108 let (trigger, impl_def_offset) = ctx.token.ancestors().find_map(|p| match p.kind() { 108 let (trigger, impl_def_offset) = ctx.token.ancestors().find_map(|p| match p.kind() {
109 SyntaxKind::FN_DEF 109 SyntaxKind::FN | SyntaxKind::TYPE_ALIAS | SyntaxKind::CONST | SyntaxKind::BLOCK_EXPR => {
110 | SyntaxKind::TYPE_ALIAS_DEF 110 Some((p, 2))
111 | SyntaxKind::CONST_DEF 111 }
112 | SyntaxKind::BLOCK_EXPR => Some((p, 2)),
113 SyntaxKind::NAME_REF => Some((p, 5)), 112 SyntaxKind::NAME_REF => Some((p, 5)),
114 _ => None, 113 _ => None,
115 })?; 114 })?;
116 let impl_def = (0..impl_def_offset - 1) 115 let impl_def = (0..impl_def_offset - 1)
117 .try_fold(trigger.parent()?, |t, _| t.parent()) 116 .try_fold(trigger.parent()?, |t, _| t.parent())
118 .and_then(ast::ImplDef::cast)?; 117 .and_then(ast::Impl::cast)?;
119 Some((trigger, impl_def)) 118 Some((trigger, impl_def))
120} 119}
121 120
@@ -125,8 +124,6 @@ fn add_function_impl(
125 ctx: &CompletionContext, 124 ctx: &CompletionContext,
126 func: hir::Function, 125 func: hir::Function,
127) { 126) {
128 let signature = FunctionSignature::from_hir(ctx.db, func);
129
130 let fn_name = func.name(ctx.db).to_string(); 127 let fn_name = func.name(ctx.db).to_string();
131 128
132 let label = if !func.params(ctx.db).is_empty() { 129 let label = if !func.params(ctx.db).is_empty() {
@@ -146,13 +143,14 @@ fn add_function_impl(
146 }; 143 };
147 let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); 144 let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end());
148 145
146 let function_decl = function_declaration(&func.source(ctx.db).value);
149 match ctx.config.snippet_cap { 147 match ctx.config.snippet_cap {
150 Some(cap) => { 148 Some(cap) => {
151 let snippet = format!("{} {{\n $0\n}}", signature); 149 let snippet = format!("{} {{\n $0\n}}", function_decl);
152 builder.snippet_edit(cap, TextEdit::replace(range, snippet)) 150 builder.snippet_edit(cap, TextEdit::replace(range, snippet))
153 } 151 }
154 None => { 152 None => {
155 let header = format!("{} {{", signature); 153 let header = format!("{} {{", function_decl);
156 builder.text_edit(TextEdit::replace(range, header)) 154 builder.text_edit(TextEdit::replace(range, header))
157 } 155 }
158 } 156 }
@@ -202,7 +200,7 @@ fn add_const_impl(
202 } 200 }
203} 201}
204 202
205fn make_const_compl_syntax(const_: &ast::ConstDef) -> String { 203fn make_const_compl_syntax(const_: &ast::Const) -> String {
206 let const_ = edit::remove_attrs_and_docs(const_); 204 let const_ = edit::remove_attrs_and_docs(const_);
207 205
208 let const_start = const_.syntax().text_range().start(); 206 let const_start = const_.syntax().text_range().start();
@@ -227,330 +225,264 @@ fn make_const_compl_syntax(const_: &ast::ConstDef) -> String {
227 225
228#[cfg(test)] 226#[cfg(test)]
229mod tests { 227mod tests {
230 use insta::assert_debug_snapshot; 228 use expect::{expect, Expect};
231 229
232 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 230 use crate::completion::{
231 test_utils::{check_edit, completion_list},
232 CompletionKind,
233 };
233 234
234 fn complete(code: &str) -> Vec<CompletionItem> { 235 fn check(ra_fixture: &str, expect: Expect) {
235 do_completion(code, CompletionKind::Magic) 236 let actual = completion_list(ra_fixture, CompletionKind::Magic);
237 expect.assert_eq(&actual)
236 } 238 }
237 239
238 #[test] 240 #[test]
239 fn name_ref_function_type_const() { 241 fn name_ref_function_type_const() {
240 let completions = complete( 242 check(
241 r" 243 r#"
242 trait Test { 244trait Test {
243 type TestType; 245 type TestType;
244 const TEST_CONST: u16; 246 const TEST_CONST: u16;
245 fn test(); 247 fn test();
246 } 248}
247 249struct T;
248 struct T1;
249 250
250 impl Test for T1 { 251impl Test for T {
251 t<|> 252 t<|>
252 } 253}
253 ", 254"#,
255 expect![["
256ct const TEST_CONST: u16 = \n\
257fn fn test()
258ta type TestType = \n\
259 "]],
254 ); 260 );
255 assert_debug_snapshot!(completions, @r###"
256 [
257 CompletionItem {
258 label: "const TEST_CONST: u16 = ",
259 source_range: 112..113,
260 delete: 112..113,
261 insert: "const TEST_CONST: u16 = ",
262 kind: Const,
263 lookup: "TEST_CONST",
264 },
265 CompletionItem {
266 label: "fn test()",
267 source_range: 112..113,
268 delete: 112..113,
269 insert: "fn test() {\n $0\n}",
270 kind: Function,
271 lookup: "test",
272 },
273 CompletionItem {
274 label: "type TestType = ",
275 source_range: 112..113,
276 delete: 112..113,
277 insert: "type TestType = ",
278 kind: TypeAlias,
279 lookup: "TestType",
280 },
281 ]
282 "###);
283 } 261 }
284 262
285 #[test] 263 #[test]
286 fn no_nested_fn_completions() { 264 fn no_nested_fn_completions() {
287 let completions = complete( 265 check(
288 r" 266 r"
289 trait Test { 267trait Test {
290 fn test(); 268 fn test();
291 fn test2(); 269 fn test2();
292 } 270}
293 271struct T;
294 struct T1;
295 272
296 impl Test for T1 { 273impl Test for T {
297 fn test() { 274 fn test() {
298 t<|> 275 t<|>
299 } 276 }
300 } 277}
301 ", 278",
279 expect![[""]],
302 ); 280 );
303 assert_debug_snapshot!(completions, @r###"[]"###);
304 } 281 }
305 282
306 #[test] 283 #[test]
307 fn name_ref_single_function() { 284 fn name_ref_single_function() {
308 let completions = complete( 285 check_edit(
309 r" 286 "test",
310 trait Test { 287 r#"
311 fn test(); 288trait Test {
312 } 289 fn test();
290}
291struct T;
313 292
314 struct T1; 293impl Test for T {
294 t<|>
295}
296"#,
297 r#"
298trait Test {
299 fn test();
300}
301struct T;
315 302
316 impl Test for T1 { 303impl Test for T {
317 t<|> 304 fn test() {
318 } 305 $0
319 ", 306}
307}
308"#,
320 ); 309 );
321 assert_debug_snapshot!(completions, @r###"
322 [
323 CompletionItem {
324 label: "fn test()",
325 source_range: 66..67,
326 delete: 66..67,
327 insert: "fn test() {\n $0\n}",
328 kind: Function,
329 lookup: "test",
330 },
331 ]
332 "###);
333 } 310 }
334 311
335 #[test] 312 #[test]
336 fn single_function() { 313 fn single_function() {
337 let completions = complete( 314 check_edit(
338 r" 315 "test",
339 trait Test { 316 r#"
340 fn foo(); 317trait Test {
341 } 318 fn test();
319}
320struct T;
342 321
343 struct T1; 322impl Test for T {
323 fn t<|>
324}
325"#,
326 r#"
327trait Test {
328 fn test();
329}
330struct T;
344 331
345 impl Test for T1 { 332impl Test for T {
346 fn f<|> 333 fn test() {
347 } 334 $0
348 ", 335}
336}
337"#,
349 ); 338 );
350 assert_debug_snapshot!(completions, @r###"
351 [
352 CompletionItem {
353 label: "fn foo()",
354 source_range: 68..69,
355 delete: 65..69,
356 insert: "fn foo() {\n $0\n}",
357 kind: Function,
358 lookup: "foo",
359 },
360 ]
361 "###);
362 } 339 }
363 340
364 #[test] 341 #[test]
365 fn hide_implemented_fn() { 342 fn hide_implemented_fn() {
366 let completions = complete( 343 check(
367 r" 344 r#"
368 trait Test { 345trait Test {
369 fn foo(); 346 fn foo();
370 fn foo_bar(); 347 fn foo_bar();
371 } 348}
372 349struct T;
373 struct T1;
374
375 impl Test for T1 {
376 fn foo() {}
377
378 fn f<|>
379 }
380 ",
381 );
382 assert_debug_snapshot!(completions, @r###"
383 [
384 CompletionItem {
385 label: "fn foo_bar()",
386 source_range: 103..104,
387 delete: 100..104,
388 insert: "fn foo_bar() {\n $0\n}",
389 kind: Function,
390 lookup: "foo_bar",
391 },
392 ]
393 "###);
394 }
395
396 #[test]
397 fn completes_only_on_top_level() {
398 let completions = complete(
399 r"
400 trait Test {
401 fn foo();
402
403 fn foo_bar();
404 }
405
406 struct T1;
407 350
408 impl Test for T1 { 351impl Test for T {
409 fn foo() { 352 fn foo() {}
410 <|> 353 fn f<|>
411 } 354}
412 } 355"#,
413 ", 356 expect![[r#"
357 fn fn foo_bar()
358 "#]],
414 ); 359 );
415 assert_debug_snapshot!(completions, @r###"[]"###);
416 } 360 }
417 361
418 #[test] 362 #[test]
419 fn generic_fn() { 363 fn generic_fn() {
420 let completions = complete( 364 check_edit(
421 r" 365 "foo",
422 trait Test { 366 r#"
423 fn foo<T>(); 367trait Test {
424 } 368 fn foo<T>();
369}
370struct T;
425 371
426 struct T1; 372impl Test for T {
373 fn f<|>
374}
375"#,
376 r#"
377trait Test {
378 fn foo<T>();
379}
380struct T;
427 381
428 impl Test for T1 { 382impl Test for T {
429 fn f<|> 383 fn foo<T>() {
430 } 384 $0
431 ", 385}
386}
387"#,
432 ); 388 );
433 assert_debug_snapshot!(completions, @r###" 389 check_edit(
434 [ 390 "foo",
435 CompletionItem { 391 r#"
436 label: "fn foo()", 392trait Test {
437 source_range: 71..72, 393 fn foo<T>() where T: Into<String>;
438 delete: 68..72, 394}
439 insert: "fn foo<T>() {\n $0\n}", 395struct T;
440 kind: Function,
441 lookup: "foo",
442 },
443 ]
444 "###);
445 }
446
447 #[test]
448 fn generic_constrait_fn() {
449 let completions = complete(
450 r"
451 trait Test {
452 fn foo<T>() where T: Into<String>;
453 }
454 396
455 struct T1; 397impl Test for T {
398 fn f<|>
399}
400"#,
401 r#"
402trait Test {
403 fn foo<T>() where T: Into<String>;
404}
405struct T;
456 406
457 impl Test for T1 { 407impl Test for T {
458 fn f<|> 408 fn foo<T>()
459 } 409where T: Into<String> {
460 ", 410 $0
411}
412}
413"#,
461 ); 414 );
462 assert_debug_snapshot!(completions, @r###"
463 [
464 CompletionItem {
465 label: "fn foo()",
466 source_range: 93..94,
467 delete: 90..94,
468 insert: "fn foo<T>()\nwhere T: Into<String> {\n $0\n}",
469 kind: Function,
470 lookup: "foo",
471 },
472 ]
473 "###);
474 } 415 }
475 416
476 #[test] 417 #[test]
477 fn associated_type() { 418 fn associated_type() {
478 let completions = complete( 419 check_edit(
479 r" 420 "SomeType",
480 trait Test { 421 r#"
481 type SomeType; 422trait Test {
482 } 423 type SomeType;
424}
483 425
484 impl Test for () { 426impl Test for () {
485 type S<|> 427 type S<|>
486 } 428}
487 ", 429"#,
430 "
431trait Test {
432 type SomeType;
433}
434
435impl Test for () {
436 type SomeType = \n\
437}
438",
488 ); 439 );
489 assert_debug_snapshot!(completions, @r###"
490 [
491 CompletionItem {
492 label: "type SomeType = ",
493 source_range: 63..64,
494 delete: 58..64,
495 insert: "type SomeType = ",
496 kind: TypeAlias,
497 lookup: "SomeType",
498 },
499 ]
500 "###);
501 } 440 }
502 441
503 #[test] 442 #[test]
504 fn associated_const() { 443 fn associated_const() {
505 let completions = complete( 444 check_edit(
506 r" 445 "SOME_CONST",
507 trait Test { 446 r#"
508 const SOME_CONST: u16; 447trait Test {
509 } 448 const SOME_CONST: u16;
449}
510 450
511 impl Test for () { 451impl Test for () {
512 const S<|> 452 const S<|>
513 } 453}
514 ", 454"#,
455 "
456trait Test {
457 const SOME_CONST: u16;
458}
459
460impl Test for () {
461 const SOME_CONST: u16 = \n\
462}
463",
515 ); 464 );
516 assert_debug_snapshot!(completions, @r###"
517 [
518 CompletionItem {
519 label: "const SOME_CONST: u16 = ",
520 source_range: 72..73,
521 delete: 66..73,
522 insert: "const SOME_CONST: u16 = ",
523 kind: Const,
524 lookup: "SOME_CONST",
525 },
526 ]
527 "###);
528 }
529 465
530 #[test] 466 check_edit(
531 fn associated_const_with_default() { 467 "SOME_CONST",
532 let completions = complete( 468 r#"
533 r" 469trait Test {
534 trait Test { 470 const SOME_CONST: u16 = 92;
535 const SOME_CONST: u16 = 42; 471}
536 }
537 472
538 impl Test for () { 473impl Test for () {
539 const S<|> 474 const S<|>
540 } 475}
541 ", 476"#,
477 "
478trait Test {
479 const SOME_CONST: u16 = 92;
480}
481
482impl Test for () {
483 const SOME_CONST: u16 = \n\
484}
485",
542 ); 486 );
543 assert_debug_snapshot!(completions, @r###"
544 [
545 CompletionItem {
546 label: "const SOME_CONST: u16 = ",
547 source_range: 77..78,
548 delete: 71..78,
549 insert: "const SOME_CONST: u16 = ",
550 kind: Const,
551 lookup: "SOME_CONST",
552 },
553 ]
554 "###);
555 } 487 }
556} 488}
diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs
index a0a04bb58..bd9551f35 100644
--- a/crates/ra_ide/src/completion/complete_unqualified_path.rs
+++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs
@@ -1,11 +1,10 @@
1//! Completion of names from the current scope, e.g. locals and imported items. 1//! Completion of names from the current scope, e.g. locals and imported items.
2 2
3use hir::ScopeDef; 3use hir::{Adt, ModuleDef, ScopeDef, Type};
4use ra_syntax::AstNode;
4use test_utils::mark; 5use test_utils::mark;
5 6
6use crate::completion::{CompletionContext, Completions}; 7use crate::completion::{CompletionContext, Completions};
7use hir::{Adt, ModuleDef, Type};
8use ra_syntax::AstNode;
9 8
10pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 9pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
11 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { 10 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) {
@@ -26,7 +25,7 @@ pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
26 return; 25 return;
27 } 26 }
28 27
29 ctx.scope().process_all_names(&mut |name, res| { 28 ctx.scope.process_all_names(&mut |name, res| {
30 if ctx.use_item_syntax.is_some() { 29 if ctx.use_item_syntax.is_some() {
31 if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) { 30 if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) {
32 if name_ref.syntax().text() == name.to_string().as_str() { 31 if name_ref.syntax().text() == name.to_string().as_str() {
@@ -43,7 +42,7 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
43 if let Some(Adt::Enum(enum_data)) = ty.as_adt() { 42 if let Some(Adt::Enum(enum_data)) = ty.as_adt() {
44 let variants = enum_data.variants(ctx.db); 43 let variants = enum_data.variants(ctx.db);
45 44
46 let module = if let Some(module) = ctx.scope().module() { 45 let module = if let Some(module) = ctx.scope.module() {
47 // Compute path from the completion site if available. 46 // Compute path from the completion site if available.
48 module 47 module
49 } else { 48 } else {
@@ -65,1361 +64,595 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
65 64
66#[cfg(test)] 65#[cfg(test)]
67mod tests { 66mod tests {
68 use insta::assert_debug_snapshot; 67 use expect::{expect, Expect};
69 use test_utils::mark; 68 use test_utils::mark;
70 69
71 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 70 use crate::completion::{
71 test_utils::{check_edit, completion_list},
72 CompletionKind,
73 };
72 74
73 fn do_reference_completion(ra_fixture: &str) -> Vec<CompletionItem> { 75 fn check(ra_fixture: &str, expect: Expect) {
74 do_completion(ra_fixture, CompletionKind::Reference) 76 let actual = completion_list(ra_fixture, CompletionKind::Reference);
77 expect.assert_eq(&actual)
75 } 78 }
76 79
77 #[test] 80 #[test]
78 fn self_fulfilling_completion() { 81 fn self_fulfilling_completion() {
79 mark::check!(self_fulfilling_completion); 82 mark::check!(self_fulfilling_completion);
80 assert_debug_snapshot!( 83 check(
81 do_reference_completion( 84 r#"
82 r#" 85use foo<|>
83 use foo<|> 86use std::collections;
84 use std::collections; 87"#,
85 "#, 88 expect![[r#"
86 ), 89 ?? collections
87 @r###" 90 "#]],
88 [
89 CompletionItem {
90 label: "collections",
91 source_range: 4..7,
92 delete: 4..7,
93 insert: "collections",
94 },
95 ]
96 "###
97 ); 91 );
98 } 92 }
99 93
100 #[test] 94 #[test]
101 fn bind_pat_and_path_ignore_at() { 95 fn bind_pat_and_path_ignore_at() {
102 assert_debug_snapshot!( 96 check(
103 do_reference_completion( 97 r#"
104 r" 98enum Enum { A, B }
105 enum Enum { 99fn quux(x: Option<Enum>) {
106 A, 100 match x {
107 B, 101 None => (),
108 } 102 Some(en<|> @ Enum::A) => (),
109 fn quux(x: Option<Enum>) { 103 }
110 match x { 104}
111 None => (), 105"#,
112 Some(en<|> @ Enum::A) => (), 106 expect![[""]],
113 }
114 }
115 "
116 ),
117 @"[]"
118 ); 107 );
119 } 108 }
120 109
121 #[test] 110 #[test]
122 fn bind_pat_and_path_ignore_ref() { 111 fn bind_pat_and_path_ignore_ref() {
123 assert_debug_snapshot!( 112 check(
124 do_reference_completion( 113 r#"
125 r" 114enum Enum { A, B }
126 enum Enum { 115fn quux(x: Option<Enum>) {
127 A, 116 match x {
128 B, 117 None => (),
129 } 118 Some(ref en<|>) => (),
130 fn quux(x: Option<Enum>) { 119 }
131 match x { 120}
132 None => (), 121"#,
133 Some(ref en<|>) => (), 122 expect![[""]],
134 }
135 }
136 "
137 ),
138 @r###"[]"###
139 ); 123 );
140 } 124 }
141 125
142 #[test] 126 #[test]
143 fn bind_pat_and_path() { 127 fn bind_pat_and_path() {
144 assert_debug_snapshot!( 128 check(
145 do_reference_completion( 129 r#"
146 r" 130enum Enum { A, B }
147 enum Enum { 131fn quux(x: Option<Enum>) {
148 A, 132 match x {
149 B, 133 None => (),
150 } 134 Some(En<|>) => (),
151 fn quux(x: Option<Enum>) { 135 }
152 match x { 136}
153 None => (), 137"#,
154 Some(En<|>) => (), 138 expect![[r#"
155 } 139 en Enum
156 } 140 "#]],
157 "
158 ),
159 @r###"
160 [
161 CompletionItem {
162 label: "Enum",
163 source_range: 102..104,
164 delete: 102..104,
165 insert: "Enum",
166 kind: Enum,
167 },
168 ]
169 "###
170 ); 141 );
171 } 142 }
172 143
173 #[test] 144 #[test]
174 fn completes_bindings_from_let() { 145 fn completes_bindings_from_let() {
175 assert_debug_snapshot!( 146 check(
176 do_reference_completion( 147 r#"
177 r" 148fn quux(x: i32) {
178 fn quux(x: i32) { 149 let y = 92;
179 let y = 92; 150 1 + <|>;
180 1 + <|>; 151 let z = ();
181 let z = (); 152}
182 } 153"#,
183 " 154 expect![[r#"
184 ), 155 fn quux(…) fn quux(x: i32)
185 @r###" 156 bn x i32
186 [ 157 bn y i32
187 CompletionItem { 158 "#]],
188 label: "quux(…)",
189 source_range: 42..42,
190 delete: 42..42,
191 insert: "quux(${1:x})$0",
192 kind: Function,
193 lookup: "quux",
194 detail: "fn quux(x: i32)",
195 trigger_call_info: true,
196 },
197 CompletionItem {
198 label: "x",
199 source_range: 42..42,
200 delete: 42..42,
201 insert: "x",
202 kind: Binding,
203 detail: "i32",
204 },
205 CompletionItem {
206 label: "y",
207 source_range: 42..42,
208 delete: 42..42,
209 insert: "y",
210 kind: Binding,
211 detail: "i32",
212 },
213 ]
214 "###
215 ); 159 );
216 } 160 }
217 161
218 #[test] 162 #[test]
219 fn completes_bindings_from_if_let() { 163 fn completes_bindings_from_if_let() {
220 assert_debug_snapshot!( 164 check(
221 do_reference_completion( 165 r#"
222 r" 166fn quux() {
223 fn quux() { 167 if let Some(x) = foo() {
224 if let Some(x) = foo() { 168 let y = 92;
225 let y = 92; 169 };
226 }; 170 if let Some(a) = bar() {
227 if let Some(a) = bar() { 171 let b = 62;
228 let b = 62; 172 1 + <|>
229 1 + <|> 173 }
230 } 174}
231 } 175"#,
232 " 176 expect![[r#"
233 ), 177 bn a
234 @r###" 178 bn b i32
235 [ 179 fn quux() fn quux()
236 CompletionItem { 180 "#]],
237 label: "a",
238 source_range: 129..129,
239 delete: 129..129,
240 insert: "a",
241 kind: Binding,
242 },
243 CompletionItem {
244 label: "b",
245 source_range: 129..129,
246 delete: 129..129,
247 insert: "b",
248 kind: Binding,
249 detail: "i32",
250 },
251 CompletionItem {
252 label: "quux()",
253 source_range: 129..129,
254 delete: 129..129,
255 insert: "quux()$0",
256 kind: Function,
257 lookup: "quux",
258 detail: "fn quux()",
259 },
260 ]
261 "###
262 ); 181 );
263 } 182 }
264 183
265 #[test] 184 #[test]
266 fn completes_bindings_from_for() { 185 fn completes_bindings_from_for() {
267 assert_debug_snapshot!( 186 check(
268 do_reference_completion( 187 r#"
269 r" 188fn quux() {
270 fn quux() { 189 for x in &[1, 2, 3] { <|> }
271 for x in &[1, 2, 3] { 190}
272 <|> 191"#,
273 } 192 expect![[r#"
274 } 193 fn quux() fn quux()
275 " 194 bn x
276 ), 195 "#]],
277 @r###"
278 [
279 CompletionItem {
280 label: "quux()",
281 source_range: 46..46,
282 delete: 46..46,
283 insert: "quux()$0",
284 kind: Function,
285 lookup: "quux",
286 detail: "fn quux()",
287 },
288 CompletionItem {
289 label: "x",
290 source_range: 46..46,
291 delete: 46..46,
292 insert: "x",
293 kind: Binding,
294 },
295 ]
296 "###
297 ); 196 );
298 } 197 }
299 198
300 #[test] 199 #[test]
301 fn completes_bindings_from_for_with_in_prefix() { 200 fn completes_if_prefix_is_keyword() {
302 mark::check!(completes_bindings_from_for_with_in_prefix); 201 mark::check!(completes_if_prefix_is_keyword);
303 assert_debug_snapshot!( 202 check_edit(
304 do_reference_completion( 203 "wherewolf",
305 r" 204 r#"
306 fn test() { 205fn main() {
307 for index in &[1, 2, 3] { 206 let wherewolf = 92;
308 let t = in<|> 207 drop(where<|>)
309 } 208}
310 } 209"#,
311 " 210 r#"
312 ), 211fn main() {
313 @r###" 212 let wherewolf = 92;
314 [ 213 drop(wherewolf)
315 CompletionItem { 214}
316 label: "index", 215"#,
317 source_range: 58..58, 216 )
318 delete: 58..58,
319 insert: "index",
320 kind: Binding,
321 },
322 CompletionItem {
323 label: "test()",
324 source_range: 58..58,
325 delete: 58..58,
326 insert: "test()$0",
327 kind: Function,
328 lookup: "test",
329 detail: "fn test()",
330 },
331 ]
332 "###
333 );
334 } 217 }
335 218
336 #[test] 219 #[test]
337 fn completes_generic_params() { 220 fn completes_generic_params() {
338 assert_debug_snapshot!( 221 check(
339 do_reference_completion( 222 r#"fn quux<T>() { <|> }"#,
340 r" 223 expect![[r#"
341 fn quux<T>() { 224 tp T
342 <|> 225 fn quux() fn quux<T>()
343 } 226 "#]],
344 "
345 ),
346 @r###"
347 [
348 CompletionItem {
349 label: "T",
350 source_range: 19..19,
351 delete: 19..19,
352 insert: "T",
353 kind: TypeParam,
354 },
355 CompletionItem {
356 label: "quux()",
357 source_range: 19..19,
358 delete: 19..19,
359 insert: "quux()$0",
360 kind: Function,
361 lookup: "quux",
362 detail: "fn quux<T>()",
363 },
364 ]
365 "###
366 ); 227 );
367 } 228 }
368 229
369 #[test] 230 #[test]
370 fn completes_generic_params_in_struct() { 231 fn completes_generic_params_in_struct() {
371 assert_debug_snapshot!( 232 check(
372 do_reference_completion( 233 r#"struct S<T> { x: <|>}"#,
373 r" 234 expect![[r#"
374 struct X<T> { 235 st S<…>
375 x: <|> 236 tp Self
376 } 237 tp T
377 " 238 "#]],
378 ),
379 @r###"
380 [
381 CompletionItem {
382 label: "Self",
383 source_range: 21..21,
384 delete: 21..21,
385 insert: "Self",
386 kind: TypeParam,
387 },
388 CompletionItem {
389 label: "T",
390 source_range: 21..21,
391 delete: 21..21,
392 insert: "T",
393 kind: TypeParam,
394 },
395 CompletionItem {
396 label: "X<…>",
397 source_range: 21..21,
398 delete: 21..21,
399 insert: "X<$0>",
400 kind: Struct,
401 lookup: "X",
402 },
403 ]
404 "###
405 ); 239 );
406 } 240 }
407 241
408 #[test] 242 #[test]
409 fn completes_self_in_enum() { 243 fn completes_self_in_enum() {
410 assert_debug_snapshot!( 244 check(
411 do_reference_completion( 245 r#"enum X { Y(<|>) }"#,
412 r" 246 expect![[r#"
413 enum X { 247 tp Self
414 Y(<|>) 248 en X
415 } 249 "#]],
416 "
417 ),
418 @r###"
419 [
420 CompletionItem {
421 label: "Self",
422 source_range: 15..15,
423 delete: 15..15,
424 insert: "Self",
425 kind: TypeParam,
426 },
427 CompletionItem {
428 label: "X",
429 source_range: 15..15,
430 delete: 15..15,
431 insert: "X",
432 kind: Enum,
433 },
434 ]
435 "###
436 ); 250 );
437 } 251 }
438 252
439 #[test] 253 #[test]
440 fn completes_module_items() { 254 fn completes_module_items() {
441 assert_debug_snapshot!( 255 check(
442 do_reference_completion( 256 r#"
443 r" 257struct S;
444 struct Foo; 258enum E {}
445 enum Baz {} 259fn quux() { <|> }
446 fn quux() { 260"#,
447 <|> 261 expect![[r#"
448 } 262 en E
449 " 263 st S
450 ), 264 fn quux() fn quux()
451 @r###" 265 "#]],
452 [ 266 );
453 CompletionItem {
454 label: "Baz",
455 source_range: 40..40,
456 delete: 40..40,
457 insert: "Baz",
458 kind: Enum,
459 },
460 CompletionItem {
461 label: "Foo",
462 source_range: 40..40,
463 delete: 40..40,
464 insert: "Foo",
465 kind: Struct,
466 },
467 CompletionItem {
468 label: "quux()",
469 source_range: 40..40,
470 delete: 40..40,
471 insert: "quux()$0",
472 kind: Function,
473 lookup: "quux",
474 detail: "fn quux()",
475 },
476 ]
477 "###
478 );
479 } 267 }
480 268
481 #[test] 269 #[test]
482 fn completes_extern_prelude() { 270 fn completes_extern_prelude() {
483 assert_debug_snapshot!( 271 check(
484 do_reference_completion( 272 r#"
485 r" 273//- /lib.rs
486 //- /lib.rs 274use <|>;
487 use <|>; 275
488 276//- /other_crate/lib.rs
489 //- /other_crate/lib.rs 277// nothing here
490 // nothing here 278"#,
491 " 279 expect![[r#"
492 ), 280 md other_crate
493 @r###" 281 "#]],
494 [
495 CompletionItem {
496 label: "other_crate",
497 source_range: 4..4,
498 delete: 4..4,
499 insert: "other_crate",
500 kind: Module,
501 },
502 ]
503 "###
504 ); 282 );
505 } 283 }
506 284
507 #[test] 285 #[test]
508 fn completes_module_items_in_nested_modules() { 286 fn completes_module_items_in_nested_modules() {
509 assert_debug_snapshot!( 287 check(
510 do_reference_completion( 288 r#"
511 r" 289struct Foo;
512 struct Foo; 290mod m {
513 mod m { 291 struct Bar;
514 struct Bar; 292 fn quux() { <|> }
515 fn quux() { <|> } 293}
516 } 294"#,
517 " 295 expect![[r#"
518 ), 296 st Bar
519 @r###" 297 fn quux() fn quux()
520 [ 298 "#]],
521 CompletionItem {
522 label: "Bar",
523 source_range: 52..52,
524 delete: 52..52,
525 insert: "Bar",
526 kind: Struct,
527 },
528 CompletionItem {
529 label: "quux()",
530 source_range: 52..52,
531 delete: 52..52,
532 insert: "quux()$0",
533 kind: Function,
534 lookup: "quux",
535 detail: "fn quux()",
536 },
537 ]
538 "###
539 ); 299 );
540 } 300 }
541 301
542 #[test] 302 #[test]
543 fn completes_return_type() { 303 fn completes_return_type() {
544 assert_debug_snapshot!( 304 check(
545 do_reference_completion( 305 r#"
546 r" 306struct Foo;
547 struct Foo; 307fn x() -> <|>
548 fn x() -> <|> 308"#,
549 " 309 expect![[r#"
550 ), 310 st Foo
551 @r###" 311 fn x() fn x()
552 [ 312 "#]],
553 CompletionItem {
554 label: "Foo",
555 source_range: 22..22,
556 delete: 22..22,
557 insert: "Foo",
558 kind: Struct,
559 },
560 CompletionItem {
561 label: "x()",
562 source_range: 22..22,
563 delete: 22..22,
564 insert: "x()$0",
565 kind: Function,
566 lookup: "x",
567 detail: "fn x()",
568 },
569 ]
570 "###
571 ); 313 );
572 } 314 }
573 315
574 #[test] 316 #[test]
575 fn dont_show_both_completions_for_shadowing() { 317 fn dont_show_both_completions_for_shadowing() {
576 assert_debug_snapshot!( 318 check(
577 do_reference_completion( 319 r#"
578 r" 320fn foo() {
579 fn foo() { 321 let bar = 92;
580 let bar = 92; 322 {
581 { 323 let bar = 62;
582 let bar = 62; 324 drop(<|>)
583 <|> 325 }
584 } 326}
585 } 327"#,
586 " 328 // FIXME: should be only one bar here
587 ), 329 expect![[r#"
588 @r###" 330 bn bar i32
589 [ 331 bn bar i32
590 CompletionItem { 332 fn foo() fn foo()
591 label: "bar", 333 "#]],
592 source_range: 65..65,
593 delete: 65..65,
594 insert: "bar",
595 kind: Binding,
596 detail: "i32",
597 },
598 CompletionItem {
599 label: "foo()",
600 source_range: 65..65,
601 delete: 65..65,
602 insert: "foo()$0",
603 kind: Function,
604 lookup: "foo",
605 detail: "fn foo()",
606 },
607 ]
608 "###
609 ); 334 );
610 } 335 }
611 336
612 #[test] 337 #[test]
613 fn completes_self_in_methods() { 338 fn completes_self_in_methods() {
614 assert_debug_snapshot!( 339 check(
615 do_reference_completion(r"impl S { fn foo(&self) { <|> } }"), 340 r#"impl S { fn foo(&self) { <|> } }"#,
616 @r###" 341 expect![[r#"
617 [ 342 tp Self
618 CompletionItem { 343 bn self &{unknown}
619 label: "Self", 344 "#]],
620 source_range: 25..25,
621 delete: 25..25,
622 insert: "Self",
623 kind: TypeParam,
624 },
625 CompletionItem {
626 label: "self",
627 source_range: 25..25,
628 delete: 25..25,
629 insert: "self",
630 kind: Binding,
631 detail: "&{unknown}",
632 },
633 ]
634 "###
635 ); 345 );
636 } 346 }
637 347
638 #[test] 348 #[test]
639 fn completes_prelude() { 349 fn completes_prelude() {
640 assert_debug_snapshot!( 350 check(
641 do_reference_completion( 351 r#"
642 " 352//- /main.rs
643 //- /main.rs 353fn foo() { let x: <|> }
644 fn foo() { let x: <|> } 354
645 355//- /std/lib.rs
646 //- /std/lib.rs 356#[prelude_import]
647 #[prelude_import] 357use prelude::*;
648 use prelude::*; 358
649 359mod prelude { struct Option; }
650 mod prelude { 360"#,
651 struct Option; 361 expect![[r#"
652 } 362 st Option
653 " 363 fn foo() fn foo()
654 ), 364 md std
655 @r###" 365 "#]],
656 [
657 CompletionItem {
658 label: "Option",
659 source_range: 18..18,
660 delete: 18..18,
661 insert: "Option",
662 kind: Struct,
663 },
664 CompletionItem {
665 label: "foo()",
666 source_range: 18..18,
667 delete: 18..18,
668 insert: "foo()$0",
669 kind: Function,
670 lookup: "foo",
671 detail: "fn foo()",
672 },
673 CompletionItem {
674 label: "std",
675 source_range: 18..18,
676 delete: 18..18,
677 insert: "std",
678 kind: Module,
679 },
680 ]
681 "###
682 ); 366 );
683 } 367 }
684 368
685 #[test] 369 #[test]
686 fn completes_std_prelude_if_core_is_defined() { 370 fn completes_std_prelude_if_core_is_defined() {
687 assert_debug_snapshot!( 371 check(
688 do_reference_completion( 372 r#"
689 " 373//- /main.rs
690 //- /main.rs 374fn foo() { let x: <|> }
691 fn foo() { let x: <|> } 375
692 376//- /core/lib.rs
693 //- /core/lib.rs 377#[prelude_import]
694 #[prelude_import] 378use prelude::*;
695 use prelude::*; 379
696 380mod prelude { struct Option; }
697 mod prelude { 381
698 struct Option; 382//- /std/lib.rs
699 } 383#[prelude_import]
700 384use prelude::*;
701 //- /std/lib.rs 385
702 #[prelude_import] 386mod prelude { struct String; }
703 use prelude::*; 387"#,
704 388 expect![[r#"
705 mod prelude { 389 st String
706 struct String; 390 md core
707 } 391 fn foo() fn foo()
708 " 392 md std
709 ), 393 "#]],
710 @r###"
711 [
712 CompletionItem {
713 label: "String",
714 source_range: 18..18,
715 delete: 18..18,
716 insert: "String",
717 kind: Struct,
718 },
719 CompletionItem {
720 label: "core",
721 source_range: 18..18,
722 delete: 18..18,
723 insert: "core",
724 kind: Module,
725 },
726 CompletionItem {
727 label: "foo()",
728 source_range: 18..18,
729 delete: 18..18,
730 insert: "foo()$0",
731 kind: Function,
732 lookup: "foo",
733 detail: "fn foo()",
734 },
735 CompletionItem {
736 label: "std",
737 source_range: 18..18,
738 delete: 18..18,
739 insert: "std",
740 kind: Module,
741 },
742 ]
743 "###
744 ); 394 );
745 } 395 }
746 396
747 #[test] 397 #[test]
748 fn completes_macros_as_value() { 398 fn completes_macros_as_value() {
749 assert_debug_snapshot!( 399 check(
750 do_reference_completion( 400 r#"
751 " 401macro_rules! foo { () => {} }
752 //- /main.rs
753 macro_rules! foo {
754 () => {}
755 }
756 402
757 #[macro_use] 403#[macro_use]
758 mod m1 { 404mod m1 {
759 macro_rules! bar { 405 macro_rules! bar { () => {} }
760 () => {} 406}
761 }
762 }
763 407
764 mod m2 { 408mod m2 {
765 macro_rules! nope { 409 macro_rules! nope { () => {} }
766 () => {}
767 }
768 410
769 #[macro_export] 411 #[macro_export]
770 macro_rules! baz { 412 macro_rules! baz { () => {} }
771 () => {} 413}
772 }
773 }
774 414
775 fn main() { 415fn main() { let v = <|> }
776 let v = <|> 416"#,
777 } 417 expect![[r##"
778 " 418 ma bar!(…) macro_rules! bar
779 ), 419 ma baz!(…) #[macro_export]
780 @r###" 420 macro_rules! baz
781 [ 421 ma foo!(…) macro_rules! foo
782 CompletionItem { 422 md m1
783 label: "bar!(…)", 423 md m2
784 source_range: 256..256, 424 fn main() fn main()
785 delete: 256..256, 425 "##]],
786 insert: "bar!($0)",
787 kind: Macro,
788 detail: "macro_rules! bar",
789 },
790 CompletionItem {
791 label: "baz!(…)",
792 source_range: 256..256,
793 delete: 256..256,
794 insert: "baz!($0)",
795 kind: Macro,
796 detail: "#[macro_export]\nmacro_rules! baz",
797 },
798 CompletionItem {
799 label: "foo!(…)",
800 source_range: 256..256,
801 delete: 256..256,
802 insert: "foo!($0)",
803 kind: Macro,
804 detail: "macro_rules! foo",
805 },
806 CompletionItem {
807 label: "m1",
808 source_range: 256..256,
809 delete: 256..256,
810 insert: "m1",
811 kind: Module,
812 },
813 CompletionItem {
814 label: "m2",
815 source_range: 256..256,
816 delete: 256..256,
817 insert: "m2",
818 kind: Module,
819 },
820 CompletionItem {
821 label: "main()",
822 source_range: 256..256,
823 delete: 256..256,
824 insert: "main()$0",
825 kind: Function,
826 lookup: "main",
827 detail: "fn main()",
828 },
829 ]
830 "###
831 ); 426 );
832 } 427 }
833 428
834 #[test] 429 #[test]
835 fn completes_both_macro_and_value() { 430 fn completes_both_macro_and_value() {
836 assert_debug_snapshot!( 431 check(
837 do_reference_completion( 432 r#"
838 " 433macro_rules! foo { () => {} }
839 //- /main.rs 434fn foo() { <|> }
840 macro_rules! foo { 435"#,
841 () => {} 436 expect![[r#"
842 } 437 ma foo!(…) macro_rules! foo
843 438 fn foo() fn foo()
844 fn foo() { 439 "#]],
845 <|>
846 }
847 "
848 ),
849 @r###"
850 [
851 CompletionItem {
852 label: "foo!(…)",
853 source_range: 50..50,
854 delete: 50..50,
855 insert: "foo!($0)",
856 kind: Macro,
857 detail: "macro_rules! foo",
858 },
859 CompletionItem {
860 label: "foo()",
861 source_range: 50..50,
862 delete: 50..50,
863 insert: "foo()$0",
864 kind: Function,
865 lookup: "foo",
866 detail: "fn foo()",
867 },
868 ]
869 "###
870 ); 440 );
871 } 441 }
872 442
873 #[test] 443 #[test]
874 fn completes_macros_as_type() { 444 fn completes_macros_as_type() {
875 assert_debug_snapshot!( 445 check(
876 do_reference_completion( 446 r#"
877 " 447macro_rules! foo { () => {} }
878 //- /main.rs 448fn main() { let x: <|> }
879 macro_rules! foo { 449"#,
880 () => {} 450 expect![[r#"
881 } 451 ma foo!(…) macro_rules! foo
882 452 fn main() fn main()
883 fn main() { 453 "#]],
884 let x: <|>
885 }
886 "
887 ),
888 @r###"
889 [
890 CompletionItem {
891 label: "foo!(…)",
892 source_range: 58..58,
893 delete: 58..58,
894 insert: "foo!($0)",
895 kind: Macro,
896 detail: "macro_rules! foo",
897 },
898 CompletionItem {
899 label: "main()",
900 source_range: 58..58,
901 delete: 58..58,
902 insert: "main()$0",
903 kind: Function,
904 lookup: "main",
905 detail: "fn main()",
906 },
907 ]
908 "###
909 ); 454 );
910 } 455 }
911 456
912 #[test] 457 #[test]
913 fn completes_macros_as_stmt() { 458 fn completes_macros_as_stmt() {
914 assert_debug_snapshot!( 459 check(
915 do_reference_completion( 460 r#"
916 " 461macro_rules! foo { () => {} }
917 //- /main.rs 462fn main() { <|> }
918 macro_rules! foo { 463"#,
919 () => {} 464 expect![[r#"
920 } 465 ma foo!(…) macro_rules! foo
921 466 fn main() fn main()
922 fn main() { 467 "#]],
923 <|>
924 }
925 "
926 ),
927 @r###"
928 [
929 CompletionItem {
930 label: "foo!(…)",
931 source_range: 51..51,
932 delete: 51..51,
933 insert: "foo!($0)",
934 kind: Macro,
935 detail: "macro_rules! foo",
936 },
937 CompletionItem {
938 label: "main()",
939 source_range: 51..51,
940 delete: 51..51,
941 insert: "main()$0",
942 kind: Function,
943 lookup: "main",
944 detail: "fn main()",
945 },
946 ]
947 "###
948 ); 468 );
949 } 469 }
950 470
951 #[test] 471 #[test]
952 fn completes_local_item() { 472 fn completes_local_item() {
953 assert_debug_snapshot!( 473 check(
954 do_reference_completion( 474 r#"
955 " 475fn main() {
956 //- /main.rs 476 return f<|>;
957 fn main() { 477 fn frobnicate() {}
958 return f<|>; 478}
959 fn frobnicate() {} 479"#,
960 } 480 expect![[r#"
961 " 481 fn frobnicate() fn frobnicate()
962 ), 482 fn main() fn main()
963 @r###" 483 "#]],
964 [ 484 );
965 CompletionItem {
966 label: "frobnicate()",
967 source_range: 23..24,
968 delete: 23..24,
969 insert: "frobnicate()$0",
970 kind: Function,
971 lookup: "frobnicate",
972 detail: "fn frobnicate()",
973 },
974 CompletionItem {
975 label: "main()",
976 source_range: 23..24,
977 delete: 23..24,
978 insert: "main()$0",
979 kind: Function,
980 lookup: "main",
981 detail: "fn main()",
982 },
983 ]
984 "###
985 )
986 } 485 }
987 486
988 #[test] 487 #[test]
989 fn completes_in_simple_macro_1() { 488 fn completes_in_simple_macro_1() {
990 assert_debug_snapshot!( 489 check(
991 do_reference_completion( 490 r#"
992 r" 491macro_rules! m { ($e:expr) => { $e } }
993 macro_rules! m { ($e:expr) => { $e } } 492fn quux(x: i32) {
994 fn quux(x: i32) { 493 let y = 92;
995 let y = 92; 494 m!(<|>);
996 m!(<|>); 495}
997 } 496"#,
998 " 497 expect![[r#"
999 ), 498 ma m!(…) macro_rules! m
1000 @r###" 499 fn quux(…) fn quux(x: i32)
1001 [ 500 bn x i32
1002 CompletionItem { 501 bn y i32
1003 label: "m!(…)", 502 "#]],
1004 source_range: 80..80,
1005 delete: 80..80,
1006 insert: "m!($0)",
1007 kind: Macro,
1008 detail: "macro_rules! m",
1009 },
1010 CompletionItem {
1011 label: "quux(…)",
1012 source_range: 80..80,
1013 delete: 80..80,
1014 insert: "quux(${1:x})$0",
1015 kind: Function,
1016 lookup: "quux",
1017 detail: "fn quux(x: i32)",
1018 trigger_call_info: true,
1019 },
1020 CompletionItem {
1021 label: "x",
1022 source_range: 80..80,
1023 delete: 80..80,
1024 insert: "x",
1025 kind: Binding,
1026 detail: "i32",
1027 },
1028 CompletionItem {
1029 label: "y",
1030 source_range: 80..80,
1031 delete: 80..80,
1032 insert: "y",
1033 kind: Binding,
1034 detail: "i32",
1035 },
1036 ]
1037 "###
1038 ); 503 );
1039 } 504 }
1040 505
1041 #[test] 506 #[test]
1042 fn completes_in_simple_macro_2() { 507 fn completes_in_simple_macro_2() {
1043 assert_debug_snapshot!( 508 check(
1044 do_reference_completion( 509 r"
1045 r" 510macro_rules! m { ($e:expr) => { $e } }
1046 macro_rules! m { ($e:expr) => { $e } } 511fn quux(x: i32) {
1047 fn quux(x: i32) { 512 let y = 92;
1048 let y = 92; 513 m!(x<|>);
1049 m!(x<|>); 514}
1050 } 515",
1051 " 516 expect![[r#"
1052 ), 517 ma m!(…) macro_rules! m
1053 @r###" 518 fn quux(…) fn quux(x: i32)
1054 [ 519 bn x i32
1055 CompletionItem { 520 bn y i32
1056 label: "m!(…)", 521 "#]],
1057 source_range: 80..81,
1058 delete: 80..81,
1059 insert: "m!($0)",
1060 kind: Macro,
1061 detail: "macro_rules! m",
1062 },
1063 CompletionItem {
1064 label: "quux(…)",
1065 source_range: 80..81,
1066 delete: 80..81,
1067 insert: "quux(${1:x})$0",
1068 kind: Function,
1069 lookup: "quux",
1070 detail: "fn quux(x: i32)",
1071 trigger_call_info: true,
1072 },
1073 CompletionItem {
1074 label: "x",
1075 source_range: 80..81,
1076 delete: 80..81,
1077 insert: "x",
1078 kind: Binding,
1079 detail: "i32",
1080 },
1081 CompletionItem {
1082 label: "y",
1083 source_range: 80..81,
1084 delete: 80..81,
1085 insert: "y",
1086 kind: Binding,
1087 detail: "i32",
1088 },
1089 ]
1090 "###
1091 ); 522 );
1092 } 523 }
1093 5