aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/completion
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/completion')
-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
17 files changed, 3393 insertions, 6604 deletions
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!(