diff options
Diffstat (limited to 'crates/ide_completion/src/completions')
14 files changed, 356 insertions, 313 deletions
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs index c48bb9e66..6df569c2a 100644 --- a/crates/ide_completion/src/completions/attribute.rs +++ b/crates/ide_completion/src/completions/attribute.rs | |||
@@ -3,20 +3,20 @@ | |||
3 | //! This module uses a bit of static metadata to provide completions | 3 | //! This module uses a bit of static metadata to provide completions |
4 | //! for built-in attributes. | 4 | //! for built-in attributes. |
5 | 5 | ||
6 | use hir::HasAttrs; | ||
7 | use ide_db::helpers::generated_lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES}; | ||
6 | use once_cell::sync::Lazy; | 8 | use once_cell::sync::Lazy; |
7 | use rustc_hash::{FxHashMap, FxHashSet}; | 9 | use rustc_hash::{FxHashMap, FxHashSet}; |
8 | use syntax::{algo::non_trivia_sibling, ast, AstNode, Direction, NodeOrToken, SyntaxKind, T}; | 10 | use syntax::{algo::non_trivia_sibling, ast, AstNode, Direction, NodeOrToken, SyntaxKind, T}; |
9 | 11 | ||
10 | use crate::{ | 12 | use crate::{ |
11 | context::CompletionContext, | 13 | context::CompletionContext, |
12 | generated_lint_completions::{CLIPPY_LINTS, FEATURES}, | ||
13 | item::{CompletionItem, CompletionItemKind, CompletionKind}, | 14 | item::{CompletionItem, CompletionItemKind, CompletionKind}, |
14 | Completions, | 15 | Completions, |
15 | }; | 16 | }; |
16 | 17 | ||
17 | mod derive; | 18 | mod derive; |
18 | mod lint; | 19 | mod lint; |
19 | pub(crate) use self::lint::LintCompletion; | ||
20 | 20 | ||
21 | pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | 21 | pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { |
22 | let attribute = ctx.attribute_under_caret.as_ref()?; | 22 | let attribute = ctx.attribute_under_caret.as_ref()?; |
@@ -25,7 +25,7 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) | |||
25 | "derive" => derive::complete_derive(acc, ctx, token_tree), | 25 | "derive" => derive::complete_derive(acc, ctx, token_tree), |
26 | "feature" => lint::complete_lint(acc, ctx, token_tree, FEATURES), | 26 | "feature" => lint::complete_lint(acc, ctx, token_tree, FEATURES), |
27 | "allow" | "warn" | "deny" | "forbid" => { | 27 | "allow" | "warn" | "deny" | "forbid" => { |
28 | lint::complete_lint(acc, ctx, token_tree.clone(), lint::DEFAULT_LINT_COMPLETIONS); | 28 | lint::complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINTS); |
29 | lint::complete_lint(acc, ctx, token_tree, CLIPPY_LINTS); | 29 | lint::complete_lint(acc, ctx, token_tree, CLIPPY_LINTS); |
30 | } | 30 | } |
31 | _ => (), | 31 | _ => (), |
@@ -69,7 +69,7 @@ fn complete_new_attribute(acc: &mut Completions, ctx: &CompletionContext, attrib | |||
69 | } | 69 | } |
70 | 70 | ||
71 | if is_inner || !attr_completion.prefer_inner { | 71 | if is_inner || !attr_completion.prefer_inner { |
72 | acc.add(item.build()); | 72 | item.add_to(acc); |
73 | } | 73 | } |
74 | }; | 74 | }; |
75 | 75 | ||
@@ -82,6 +82,24 @@ fn complete_new_attribute(acc: &mut Completions, ctx: &CompletionContext, attrib | |||
82 | None if is_inner => ATTRIBUTES.iter().for_each(add_completion), | 82 | None if is_inner => ATTRIBUTES.iter().for_each(add_completion), |
83 | None => ATTRIBUTES.iter().filter(|compl| !compl.prefer_inner).for_each(add_completion), | 83 | None => ATTRIBUTES.iter().filter(|compl| !compl.prefer_inner).for_each(add_completion), |
84 | } | 84 | } |
85 | |||
86 | // FIXME: write a test for this when we can | ||
87 | ctx.scope.process_all_names(&mut |name, scope_def| { | ||
88 | if let hir::ScopeDef::MacroDef(mac) = scope_def { | ||
89 | if mac.kind() == hir::MacroKind::Attr { | ||
90 | let mut item = CompletionItem::new( | ||
91 | CompletionKind::Attribute, | ||
92 | ctx.source_range(), | ||
93 | name.to_string(), | ||
94 | ); | ||
95 | item.kind(CompletionItemKind::Attribute); | ||
96 | if let Some(docs) = mac.docs(ctx.sema.db) { | ||
97 | item.documentation(docs); | ||
98 | } | ||
99 | item.add_to(acc); | ||
100 | } | ||
101 | } | ||
102 | }); | ||
85 | } | 103 | } |
86 | 104 | ||
87 | struct AttrCompletion { | 105 | struct AttrCompletion { |
@@ -201,7 +219,7 @@ static KIND_TO_ATTRIBUTES: Lazy<FxHashMap<SyntaxKind, &[&str]>> = Lazy::new(|| { | |||
201 | }); | 219 | }); |
202 | const EXPR_ATTRIBUTES: &[&str] = attrs!(); | 220 | const EXPR_ATTRIBUTES: &[&str] = attrs!(); |
203 | 221 | ||
204 | /// https://doc.rust-lang.org/reference/attributes.html#built-in-attributes-index | 222 | /// <https://doc.rust-lang.org/reference/attributes.html#built-in-attributes-index> |
205 | // Keep these sorted for the binary search! | 223 | // Keep these sorted for the binary search! |
206 | const ATTRIBUTES: &[AttrCompletion] = &[ | 224 | const ATTRIBUTES: &[AttrCompletion] = &[ |
207 | attr("allow(…)", Some("allow"), Some("allow(${0:lint})")), | 225 | attr("allow(…)", Some("allow"), Some("allow(${0:lint})")), |
diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs index 0bc3eab98..d526824fb 100644 --- a/crates/ide_completion/src/completions/attribute/derive.rs +++ b/crates/ide_completion/src/completions/attribute/derive.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | //! Completion for derives | 1 | //! Completion for derives |
2 | use hir::HasAttrs; | ||
2 | use itertools::Itertools; | 3 | use itertools::Itertools; |
3 | use rustc_hash::FxHashSet; | 4 | use rustc_hash::FxHashMap; |
4 | use syntax::ast; | 5 | use syntax::ast; |
5 | 6 | ||
6 | use crate::{ | 7 | use crate::{ |
@@ -15,66 +16,64 @@ pub(super) fn complete_derive( | |||
15 | derive_input: ast::TokenTree, | 16 | derive_input: ast::TokenTree, |
16 | ) { | 17 | ) { |
17 | if let Some(existing_derives) = super::parse_comma_sep_input(derive_input) { | 18 | if let Some(existing_derives) = super::parse_comma_sep_input(derive_input) { |
18 | for derive_completion in DEFAULT_DERIVE_COMPLETIONS | 19 | for (derive, docs) in get_derive_names_in_scope(ctx) { |
19 | .iter() | 20 | let (label, lookup) = if let Some(derive_completion) = DEFAULT_DERIVE_COMPLETIONS |
20 | .filter(|completion| !existing_derives.contains(completion.label)) | 21 | .iter() |
21 | { | 22 | .find(|derive_completion| derive_completion.label == derive) |
22 | let mut components = vec![derive_completion.label]; | 23 | { |
23 | components.extend( | 24 | let mut components = vec![derive_completion.label]; |
24 | derive_completion | 25 | components.extend( |
25 | .dependencies | 26 | derive_completion |
26 | .iter() | 27 | .dependencies |
27 | .filter(|&&dependency| !existing_derives.contains(dependency)), | 28 | .iter() |
28 | ); | 29 | .filter(|&&dependency| !existing_derives.contains(dependency)), |
29 | let lookup = components.join(", "); | 30 | ); |
30 | let label = components.iter().rev().join(", "); | 31 | let lookup = components.join(", "); |
32 | let label = components.iter().rev().join(", "); | ||
33 | (label, Some(lookup)) | ||
34 | } else { | ||
35 | (derive, None) | ||
36 | }; | ||
31 | let mut item = | 37 | let mut item = |
32 | CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label); | 38 | CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label); |
33 | item.lookup_by(lookup).kind(CompletionItemKind::Attribute); | ||
34 | item.add_to(acc); | ||
35 | } | ||
36 | |||
37 | for custom_derive_name in get_derive_names_in_scope(ctx).difference(&existing_derives) { | ||
38 | let mut item = CompletionItem::new( | ||
39 | CompletionKind::Attribute, | ||
40 | ctx.source_range(), | ||
41 | custom_derive_name, | ||
42 | ); | ||
43 | item.kind(CompletionItemKind::Attribute); | 39 | item.kind(CompletionItemKind::Attribute); |
40 | if let Some(docs) = docs { | ||
41 | item.documentation(docs); | ||
42 | } | ||
43 | if let Some(lookup) = lookup { | ||
44 | item.lookup_by(lookup); | ||
45 | } | ||
44 | item.add_to(acc); | 46 | item.add_to(acc); |
45 | } | 47 | } |
46 | } | 48 | } |
47 | } | 49 | } |
48 | 50 | ||
49 | fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> { | 51 | fn get_derive_names_in_scope( |
50 | let mut result = FxHashSet::default(); | 52 | ctx: &CompletionContext, |
53 | ) -> FxHashMap<String, Option<hir::Documentation>> { | ||
54 | let mut result = FxHashMap::default(); | ||
51 | ctx.scope.process_all_names(&mut |name, scope_def| { | 55 | ctx.scope.process_all_names(&mut |name, scope_def| { |
52 | if let hir::ScopeDef::MacroDef(mac) = scope_def { | 56 | if let hir::ScopeDef::MacroDef(mac) = scope_def { |
53 | if mac.kind() == hir::MacroKind::Derive { | 57 | if mac.kind() == hir::MacroKind::Derive { |
54 | result.insert(name.to_string()); | 58 | result.insert(name.to_string(), mac.docs(ctx.db)); |
55 | } | 59 | } |
56 | } | 60 | } |
57 | }); | 61 | }); |
58 | result | 62 | result |
59 | } | 63 | } |
60 | 64 | ||
61 | struct DeriveCompletion { | 65 | struct DeriveDependencies { |
62 | label: &'static str, | 66 | label: &'static str, |
63 | dependencies: &'static [&'static str], | 67 | dependencies: &'static [&'static str], |
64 | } | 68 | } |
65 | 69 | ||
66 | /// Standard Rust derives and the information about their dependencies | 70 | /// Standard Rust derives that have dependencies |
67 | /// (the dependencies are needed so that the main derive don't break the compilation when added) | 71 | /// (the dependencies are needed so that the main derive don't break the compilation when added) |
68 | const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[ | 72 | const DEFAULT_DERIVE_COMPLETIONS: &[DeriveDependencies] = &[ |
69 | DeriveCompletion { label: "Clone", dependencies: &[] }, | 73 | DeriveDependencies { label: "Copy", dependencies: &["Clone"] }, |
70 | DeriveCompletion { label: "Copy", dependencies: &["Clone"] }, | 74 | DeriveDependencies { label: "Eq", dependencies: &["PartialEq"] }, |
71 | DeriveCompletion { label: "Debug", dependencies: &[] }, | 75 | DeriveDependencies { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] }, |
72 | DeriveCompletion { label: "Default", dependencies: &[] }, | 76 | DeriveDependencies { label: "PartialOrd", dependencies: &["PartialEq"] }, |
73 | DeriveCompletion { label: "Hash", dependencies: &[] }, | ||
74 | DeriveCompletion { label: "PartialEq", dependencies: &[] }, | ||
75 | DeriveCompletion { label: "Eq", dependencies: &["PartialEq"] }, | ||
76 | DeriveCompletion { label: "PartialOrd", dependencies: &["PartialEq"] }, | ||
77 | DeriveCompletion { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] }, | ||
78 | ]; | 77 | ]; |
79 | 78 | ||
80 | #[cfg(test)] | 79 | #[cfg(test)] |
@@ -94,6 +93,7 @@ mod tests { | |||
94 | } | 93 | } |
95 | 94 | ||
96 | #[test] | 95 | #[test] |
96 | #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures | ||
97 | fn empty_derive() { | 97 | fn empty_derive() { |
98 | check( | 98 | check( |
99 | r#"#[derive($0)] struct Test;"#, | 99 | r#"#[derive($0)] struct Test;"#, |
@@ -112,6 +112,7 @@ mod tests { | |||
112 | } | 112 | } |
113 | 113 | ||
114 | #[test] | 114 | #[test] |
115 | #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures | ||
115 | fn derive_with_input() { | 116 | fn derive_with_input() { |
116 | check( | 117 | check( |
117 | r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#, | 118 | r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#, |
@@ -129,6 +130,7 @@ mod tests { | |||
129 | } | 130 | } |
130 | 131 | ||
131 | #[test] | 132 | #[test] |
133 | #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures | ||
132 | fn derive_with_input2() { | 134 | fn derive_with_input2() { |
133 | check( | 135 | check( |
134 | r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#, | 136 | r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#, |
diff --git a/crates/ide_completion/src/completions/attribute/lint.rs b/crates/ide_completion/src/completions/attribute/lint.rs index 403630dce..ca99e9759 100644 --- a/crates/ide_completion/src/completions/attribute/lint.rs +++ b/crates/ide_completion/src/completions/attribute/lint.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | //! Completion for lints | 1 | //! Completion for lints |
2 | use ide_db::helpers::generated_lints::Lint; | ||
2 | use syntax::ast; | 3 | use syntax::ast; |
3 | 4 | ||
4 | use crate::{ | 5 | use crate::{ |
@@ -11,7 +12,7 @@ pub(super) fn complete_lint( | |||
11 | acc: &mut Completions, | 12 | acc: &mut Completions, |
12 | ctx: &CompletionContext, | 13 | ctx: &CompletionContext, |
13 | derive_input: ast::TokenTree, | 14 | derive_input: ast::TokenTree, |
14 | lints_completions: &[LintCompletion], | 15 | lints_completions: &[Lint], |
15 | ) { | 16 | ) { |
16 | if let Some(existing_lints) = super::parse_comma_sep_input(derive_input) { | 17 | if let Some(existing_lints) = super::parse_comma_sep_input(derive_input) { |
17 | for lint_completion in lints_completions | 18 | for lint_completion in lints_completions |
@@ -23,136 +24,13 @@ pub(super) fn complete_lint( | |||
23 | ctx.source_range(), | 24 | ctx.source_range(), |
24 | lint_completion.label, | 25 | lint_completion.label, |
25 | ); | 26 | ); |
26 | item.kind(CompletionItemKind::Attribute).detail(lint_completion.description); | 27 | item.kind(CompletionItemKind::Attribute) |
28 | .documentation(hir::Documentation::new(lint_completion.description.to_owned())); | ||
27 | item.add_to(acc) | 29 | item.add_to(acc) |
28 | } | 30 | } |
29 | } | 31 | } |
30 | } | 32 | } |
31 | 33 | ||
32 | pub(crate) struct LintCompletion { | ||
33 | pub(crate) label: &'static str, | ||
34 | pub(crate) description: &'static str, | ||
35 | } | ||
36 | |||
37 | #[rustfmt::skip] | ||
38 | pub(super) const DEFAULT_LINT_COMPLETIONS: &[LintCompletion] = &[ | ||
39 | 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"# }, | ||
40 | LintCompletion { label: "anonymous_parameters", description: r#"detects anonymous parameters"# }, | ||
41 | LintCompletion { label: "box_pointers", description: r#"use of owned (Box type) heap memory"# }, | ||
42 | LintCompletion { label: "deprecated_in_future", description: r#"detects use of items that will be deprecated in a future version"# }, | ||
43 | LintCompletion { label: "elided_lifetimes_in_paths", description: r#"hidden lifetime parameters in types are deprecated"# }, | ||
44 | LintCompletion { label: "explicit_outlives_requirements", description: r#"outlives requirements can be inferred"# }, | ||
45 | LintCompletion { label: "indirect_structural_match", description: r#"pattern with const indirectly referencing non-structural-match type"# }, | ||
46 | LintCompletion { label: "keyword_idents", description: r#"detects edition keywords being used as an identifier"# }, | ||
47 | LintCompletion { label: "macro_use_extern_crate", description: r#"the `#[macro_use]` attribute is now deprecated in favor of using macros via the module system"# }, | ||
48 | LintCompletion { label: "meta_variable_misuse", description: r#"possible meta-variable misuse at macro definition"# }, | ||
49 | LintCompletion { label: "missing_copy_implementations", description: r#"detects potentially-forgotten implementations of `Copy`"# }, | ||
50 | LintCompletion { label: "missing_crate_level_docs", description: r#"detects crates with no crate-level documentation"# }, | ||
51 | LintCompletion { label: "missing_debug_implementations", description: r#"detects missing implementations of Debug"# }, | ||
52 | LintCompletion { label: "missing_docs", description: r#"detects missing documentation for public members"# }, | ||
53 | LintCompletion { label: "missing_doc_code_examples", description: r#"detects publicly-exported items without code samples in their documentation"# }, | ||
54 | LintCompletion { label: "non_ascii_idents", description: r#"detects non-ASCII identifiers"# }, | ||
55 | LintCompletion { label: "private_doc_tests", description: r#"detects code samples in docs of private items not documented by rustdoc"# }, | ||
56 | LintCompletion { label: "single_use_lifetimes", description: r#"detects lifetime parameters that are only used once"# }, | ||
57 | LintCompletion { label: "trivial_casts", description: r#"detects trivial casts which could be removed"# }, | ||
58 | LintCompletion { label: "trivial_numeric_casts", description: r#"detects trivial casts of numeric types which could be removed"# }, | ||
59 | LintCompletion { label: "unaligned_references", description: r#"detects unaligned references to fields of packed structs"# }, | ||
60 | LintCompletion { label: "unreachable_pub", description: r#"`pub` items not reachable from crate root"# }, | ||
61 | LintCompletion { label: "unsafe_code", description: r#"usage of `unsafe` code"# }, | ||
62 | LintCompletion { label: "unsafe_op_in_unsafe_fn", description: r#"unsafe operations in unsafe functions without an explicit unsafe block are deprecated"# }, | ||
63 | LintCompletion { label: "unstable_features", description: r#"enabling unstable features (deprecated. do not use)"# }, | ||
64 | LintCompletion { label: "unused_crate_dependencies", description: r#"crate dependencies that are never used"# }, | ||
65 | LintCompletion { label: "unused_extern_crates", description: r#"extern crates that are never used"# }, | ||
66 | LintCompletion { label: "unused_import_braces", description: r#"unnecessary braces around an imported item"# }, | ||
67 | LintCompletion { label: "unused_lifetimes", description: r#"detects lifetime parameters that are never used"# }, | ||
68 | LintCompletion { label: "unused_qualifications", description: r#"detects unnecessarily qualified names"# }, | ||
69 | LintCompletion { label: "unused_results", description: r#"unused result of an expression in a statement"# }, | ||
70 | LintCompletion { label: "variant_size_differences", description: r#"detects enums with widely varying variant sizes"# }, | ||
71 | LintCompletion { label: "array_into_iter", description: r#"detects calling `into_iter` on arrays"# }, | ||
72 | LintCompletion { label: "asm_sub_register", description: r#"using only a subset of a register for inline asm inputs"# }, | ||
73 | LintCompletion { label: "bare_trait_objects", description: r#"suggest using `dyn Trait` for trait objects"# }, | ||
74 | LintCompletion { label: "bindings_with_variant_name", description: r#"detects pattern bindings with the same name as one of the matched variants"# }, | ||
75 | LintCompletion { label: "cenum_impl_drop_cast", description: r#"a C-like enum implementing Drop is cast"# }, | ||
76 | LintCompletion { label: "clashing_extern_declarations", description: r#"detects when an extern fn has been declared with the same name but different types"# }, | ||
77 | LintCompletion { label: "coherence_leak_check", description: r#"distinct impls distinguished only by the leak-check code"# }, | ||
78 | LintCompletion { label: "confusable_idents", description: r#"detects visually confusable pairs between identifiers"# }, | ||
79 | LintCompletion { label: "dead_code", description: r#"detect unused, unexported items"# }, | ||
80 | LintCompletion { label: "deprecated", description: r#"detects use of deprecated items"# }, | ||
81 | LintCompletion { label: "ellipsis_inclusive_range_patterns", description: r#"`...` range patterns are deprecated"# }, | ||
82 | LintCompletion { label: "exported_private_dependencies", description: r#"public interface leaks type from a private dependency"# }, | ||
83 | LintCompletion { label: "illegal_floating_point_literal_pattern", description: r#"floating-point literals cannot be used in patterns"# }, | ||
84 | LintCompletion { label: "improper_ctypes", description: r#"proper use of libc types in foreign modules"# }, | ||
85 | LintCompletion { label: "improper_ctypes_definitions", description: r#"proper use of libc types in foreign item definitions"# }, | ||
86 | LintCompletion { label: "incomplete_features", description: r#"incomplete features that may function improperly in some or all cases"# }, | ||
87 | LintCompletion { label: "inline_no_sanitize", description: r#"detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`"# }, | ||
88 | LintCompletion { label: "intra_doc_link_resolution_failure", description: r#"failures in resolving intra-doc link targets"# }, | ||
89 | LintCompletion { label: "invalid_codeblock_attributes", description: r#"codeblock attribute looks a lot like a known one"# }, | ||
90 | LintCompletion { label: "invalid_value", description: r#"an invalid value is being created (such as a NULL reference)"# }, | ||
91 | LintCompletion { label: "irrefutable_let_patterns", description: r#"detects irrefutable patterns in if-let and while-let statements"# }, | ||
92 | LintCompletion { label: "late_bound_lifetime_arguments", description: r#"detects generic lifetime arguments in path segments with late bound lifetime parameters"# }, | ||
93 | LintCompletion { label: "mixed_script_confusables", description: r#"detects Unicode scripts whose mixed script confusables codepoints are solely used"# }, | ||
94 | LintCompletion { label: "mutable_borrow_reservation_conflict", description: r#"reservation of a two-phased borrow conflicts with other shared borrows"# }, | ||
95 | LintCompletion { label: "non_camel_case_types", description: r#"types, variants, traits and type parameters should have camel case names"# }, | ||
96 | LintCompletion { label: "non_shorthand_field_patterns", description: r#"using `Struct { x: x }` instead of `Struct { x }` in a pattern"# }, | ||
97 | LintCompletion { label: "non_snake_case", description: r#"variables, methods, functions, lifetime parameters and modules should have snake case names"# }, | ||
98 | LintCompletion { label: "non_upper_case_globals", description: r#"static constants should have uppercase identifiers"# }, | ||
99 | LintCompletion { label: "no_mangle_generic_items", description: r#"generic items must be mangled"# }, | ||
100 | LintCompletion { label: "overlapping_patterns", description: r#"detects overlapping patterns"# }, | ||
101 | LintCompletion { label: "path_statements", description: r#"path statements with no effect"# }, | ||
102 | LintCompletion { label: "private_in_public", description: r#"detect private items in public interfaces not caught by the old implementation"# }, | ||
103 | LintCompletion { label: "proc_macro_derive_resolution_fallback", description: r#"detects proc macro derives using inaccessible names from parent modules"# }, | ||
104 | LintCompletion { label: "redundant_semicolons", description: r#"detects unnecessary trailing semicolons"# }, | ||
105 | LintCompletion { label: "renamed_and_removed_lints", description: r#"lints that have been renamed or removed"# }, | ||
106 | LintCompletion { label: "safe_packed_borrows", description: r#"safe borrows of fields of packed structs were erroneously allowed"# }, | ||
107 | LintCompletion { label: "stable_features", description: r#"stable features found in `#[feature]` directive"# }, | ||
108 | LintCompletion { label: "trivial_bounds", description: r#"these bounds don't depend on an type parameters"# }, | ||
109 | LintCompletion { label: "type_alias_bounds", description: r#"bounds in type aliases are not enforced"# }, | ||
110 | LintCompletion { label: "tyvar_behind_raw_pointer", description: r#"raw pointer to an inference variable"# }, | ||
111 | LintCompletion { label: "uncommon_codepoints", description: r#"detects uncommon Unicode codepoints in identifiers"# }, | ||
112 | LintCompletion { label: "unconditional_recursion", description: r#"functions that cannot return without calling themselves"# }, | ||
113 | LintCompletion { label: "unknown_lints", description: r#"unrecognized lint attribute"# }, | ||
114 | LintCompletion { label: "unnameable_test_items", description: r#"detects an item that cannot be named being marked as `#[test_case]`"# }, | ||
115 | LintCompletion { label: "unreachable_code", description: r#"detects unreachable code paths"# }, | ||
116 | LintCompletion { label: "unreachable_patterns", description: r#"detects unreachable patterns"# }, | ||
117 | LintCompletion { label: "unstable_name_collisions", description: r#"detects name collision with an existing but unstable method"# }, | ||
118 | LintCompletion { label: "unused_allocation", description: r#"detects unnecessary allocations that can be eliminated"# }, | ||
119 | LintCompletion { label: "unused_assignments", description: r#"detect assignments that will never be read"# }, | ||
120 | LintCompletion { label: "unused_attributes", description: r#"detects attributes that were not used by the compiler"# }, | ||
121 | LintCompletion { label: "unused_braces", description: r#"unnecessary braces around an expression"# }, | ||
122 | LintCompletion { label: "unused_comparisons", description: r#"comparisons made useless by limits of the types involved"# }, | ||
123 | LintCompletion { label: "unused_doc_comments", description: r#"detects doc comments that aren't used by rustdoc"# }, | ||
124 | LintCompletion { label: "unused_features", description: r#"unused features found in crate-level `#[feature]` directives"# }, | ||
125 | LintCompletion { label: "unused_imports", description: r#"imports that are never used"# }, | ||
126 | LintCompletion { label: "unused_labels", description: r#"detects labels that are never used"# }, | ||
127 | LintCompletion { label: "unused_macros", description: r#"detects macros that were not used"# }, | ||
128 | LintCompletion { label: "unused_must_use", description: r#"unused result of a type flagged as `#[must_use]`"# }, | ||
129 | LintCompletion { label: "unused_mut", description: r#"detect mut variables which don't need to be mutable"# }, | ||
130 | LintCompletion { label: "unused_parens", description: r#"`if`, `match`, `while` and `return` do not need parentheses"# }, | ||
131 | LintCompletion { label: "unused_unsafe", description: r#"unnecessary use of an `unsafe` block"# }, | ||
132 | LintCompletion { label: "unused_variables", description: r#"detect variables which are not used in any way"# }, | ||
133 | LintCompletion { label: "warnings", description: r#"mass-change the level for lints which produce warnings"# }, | ||
134 | LintCompletion { label: "where_clauses_object_safety", description: r#"checks the object safety of where clauses"# }, | ||
135 | LintCompletion { label: "while_true", description: r#"suggest using `loop { }` instead of `while true { }`"# }, | ||
136 | LintCompletion { label: "ambiguous_associated_items", description: r#"ambiguous associated items"# }, | ||
137 | LintCompletion { label: "arithmetic_overflow", description: r#"arithmetic operation overflows"# }, | ||
138 | LintCompletion { label: "conflicting_repr_hints", description: r#"conflicts between `#[repr(..)]` hints that were previously accepted and used in practice"# }, | ||
139 | LintCompletion { label: "const_err", description: r#"constant evaluation detected erroneous expression"# }, | ||
140 | LintCompletion { label: "ill_formed_attribute_input", description: r#"ill-formed attribute inputs that were previously accepted and used in practice"# }, | ||
141 | LintCompletion { label: "incomplete_include", description: r#"trailing content in included file"# }, | ||
142 | LintCompletion { label: "invalid_type_param_default", description: r#"type parameter default erroneously allowed in invalid location"# }, | ||
143 | 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"# }, | ||
144 | LintCompletion { label: "missing_fragment_specifier", description: r#"detects missing fragment specifiers in unused `macro_rules!` patterns"# }, | ||
145 | LintCompletion { label: "mutable_transmutes", description: r#"mutating transmuted &mut T from &T may cause undefined behavior"# }, | ||
146 | LintCompletion { label: "no_mangle_const_items", description: r#"const items will not have their symbols exported"# }, | ||
147 | LintCompletion { label: "order_dependent_trait_objects", description: r#"trait-object types were treated as different depending on marker-trait order"# }, | ||
148 | LintCompletion { label: "overflowing_literals", description: r#"literal out of range for its type"# }, | ||
149 | LintCompletion { label: "patterns_in_fns_without_body", description: r#"patterns in functions without body were erroneously allowed"# }, | ||
150 | LintCompletion { label: "pub_use_of_private_extern_crate", description: r#"detect public re-exports of private extern crates"# }, | ||
151 | LintCompletion { label: "soft_unstable", description: r#"a feature gate that doesn't break dependent crates"# }, | ||
152 | LintCompletion { label: "unconditional_panic", description: r#"operation will cause a panic at runtime"# }, | ||
153 | LintCompletion { label: "unknown_crate_types", description: r#"unknown crate type found in `#[crate_type]` directive"# }, | ||
154 | ]; | ||
155 | |||
156 | #[cfg(test)] | 34 | #[cfg(test)] |
157 | mod tests { | 35 | mod tests { |
158 | 36 | ||
@@ -184,4 +62,13 @@ mod tests { | |||
184 | r#"#[allow(keyword_idents, deprecated)] struct Test;"#, | 62 | r#"#[allow(keyword_idents, deprecated)] struct Test;"#, |
185 | ) | 63 | ) |
186 | } | 64 | } |
65 | |||
66 | #[test] | ||
67 | fn check_feature() { | ||
68 | check_edit( | ||
69 | "box_syntax", | ||
70 | r#"#[feature(box_$0)] struct Test;"#, | ||
71 | r#"#[feature(box_syntax)] struct Test;"#, | ||
72 | ) | ||
73 | } | ||
187 | } | 74 | } |
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs index e0a7021fd..9552875c1 100644 --- a/crates/ide_completion/src/completions/dot.rs +++ b/crates/ide_completion/src/completions/dot.rs | |||
@@ -4,7 +4,7 @@ use either::Either; | |||
4 | use hir::{HasVisibility, ScopeDef}; | 4 | use hir::{HasVisibility, ScopeDef}; |
5 | use rustc_hash::FxHashSet; | 5 | use rustc_hash::FxHashSet; |
6 | 6 | ||
7 | use crate::{context::CompletionContext, Completions}; | 7 | use crate::{context::CompletionContext, patterns::ImmediateLocation, Completions}; |
8 | 8 | ||
9 | /// Complete dot accesses, i.e. fields or methods. | 9 | /// Complete dot accesses, i.e. fields or methods. |
10 | pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | 10 | pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { |
@@ -13,12 +13,12 @@ pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | |||
13 | _ => return complete_undotted_self(acc, ctx), | 13 | _ => return complete_undotted_self(acc, ctx), |
14 | }; | 14 | }; |
15 | 15 | ||
16 | let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) { | 16 | let receiver_ty = match ctx.sema.type_of_expr(dot_receiver) { |
17 | Some(ty) => ty, | 17 | Some(ty) => ty, |
18 | _ => return, | 18 | _ => return, |
19 | }; | 19 | }; |
20 | 20 | ||
21 | if ctx.is_call { | 21 | if matches!(ctx.completion_location, Some(ImmediateLocation::MethodCall { .. })) { |
22 | cov_mark::hit!(test_no_struct_field_completion_for_method_call); | 22 | cov_mark::hit!(test_no_struct_field_completion_for_method_call); |
23 | } else { | 23 | } else { |
24 | complete_fields(ctx, &receiver_ty, |field, ty| match field { | 24 | complete_fields(ctx, &receiver_ty, |field, ty| match field { |
@@ -33,7 +33,7 @@ fn complete_undotted_self(acc: &mut Completions, ctx: &CompletionContext) { | |||
33 | if !ctx.config.enable_self_on_the_fly { | 33 | if !ctx.config.enable_self_on_the_fly { |
34 | return; | 34 | return; |
35 | } | 35 | } |
36 | if !ctx.is_trivial_path || ctx.is_path_disallowed() { | 36 | if !ctx.is_trivial_path() || ctx.is_path_disallowed() { |
37 | return; | 37 | return; |
38 | } | 38 | } |
39 | ctx.scope.process_all_names(&mut |name, def| { | 39 | ctx.scope.process_all_names(&mut |name, def| { |
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs index d72bf13d3..30b8d44bd 100644 --- a/crates/ide_completion/src/completions/flyimport.rs +++ b/crates/ide_completion/src/completions/flyimport.rs | |||
@@ -1,10 +1,10 @@ | |||
1 | //! Feature: completion with imports-on-the-fly | 1 | //! Feature: completion with imports-on-the-fly |
2 | //! | 2 | //! |
3 | //! When completing names in the current scope, proposes additional imports from other modules or crates, | 3 | //! When completing names in the current scope, proposes additional imports from other modules or crates, |
4 | //! if they can be qualified in the scope and their name contains all symbols from the completion input. | 4 | //! if they can be qualified in the scope, and their name contains all symbols from the completion input. |
5 | //! | 5 | //! |
6 | //! To be considered applicable, the name must contain all input symbols in the given order, not necessarily adjacent. | 6 | //! To be considered applicable, the name must contain all input symbols in the given order, not necessarily adjacent. |
7 | //! If any input symbol is not lowercased, the name must contain all symbols in exact case; otherwise the contaning is checked case-insensitively. | 7 | //! If any input symbol is not lowercased, the name must contain all symbols in exact case; otherwise the containing is checked case-insensitively. |
8 | //! | 8 | //! |
9 | //! ``` | 9 | //! ``` |
10 | //! fn main() { | 10 | //! fn main() { |
@@ -23,8 +23,8 @@ | |||
23 | //! ``` | 23 | //! ``` |
24 | //! | 24 | //! |
25 | //! Also completes associated items, that require trait imports. | 25 | //! Also completes associated items, that require trait imports. |
26 | //! If any unresolved and/or partially-qualified path predeces the input, it will be taken into account. | 26 | //! If any unresolved and/or partially-qualified path precedes the input, it will be taken into account. |
27 | //! Currently, only the imports with their import path ending with the whole qialifier will be proposed | 27 | //! Currently, only the imports with their import path ending with the whole qualifier will be proposed |
28 | //! (no fuzzy matching for qualifier). | 28 | //! (no fuzzy matching for qualifier). |
29 | //! | 29 | //! |
30 | //! ``` | 30 | //! ``` |
@@ -61,14 +61,14 @@ | |||
61 | //! } | 61 | //! } |
62 | //! ``` | 62 | //! ``` |
63 | //! | 63 | //! |
64 | //! NOTE: currently, if an assoc item comes from a trait that's not currently imported and it also has an unresolved and/or partially-qualified path, | 64 | //! NOTE: currently, if an assoc item comes from a trait that's not currently imported, and it also has an unresolved and/or partially-qualified path, |
65 | //! no imports will be proposed. | 65 | //! no imports will be proposed. |
66 | //! | 66 | //! |
67 | //! .Fuzzy search details | 67 | //! .Fuzzy search details |
68 | //! | 68 | //! |
69 | //! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only | 69 | //! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only |
70 | //! (i.e. in `HashMap` in the `std::collections::HashMap` path). | 70 | //! (i.e. in `HashMap` in the `std::collections::HashMap` path). |
71 | //! For the same reasons, avoids searching for any path imports for inputs with their length less that 2 symbols | 71 | //! For the same reasons, avoids searching for any path imports for inputs with their length less than 2 symbols |
72 | //! (but shows all associated items for any input length). | 72 | //! (but shows all associated items for any input length). |
73 | //! | 73 | //! |
74 | //! .Import configuration | 74 | //! .Import configuration |
@@ -79,18 +79,17 @@ | |||
79 | //! .LSP and performance implications | 79 | //! .LSP and performance implications |
80 | //! | 80 | //! |
81 | //! The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits` | 81 | //! The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits` |
82 | //! (case sensitive) resolve client capability in its client capabilities. | 82 | //! (case-sensitive) resolve client capability in its client capabilities. |
83 | //! This way the server is able to defer the costly computations, doing them for a selected completion item only. | 83 | //! This way the server is able to defer the costly computations, doing them for a selected completion item only. |
84 | //! For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones, | 84 | //! For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones, |
85 | //! which might be slow ergo the feature is automatically disabled. | 85 | //! which might be slow ergo the feature is automatically disabled. |
86 | //! | 86 | //! |
87 | //! .Feature toggle | 87 | //! .Feature toggle |
88 | //! | 88 | //! |
89 | //! The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.enableAutoimportCompletions` flag. | 89 | //! The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.autoimport.enable` flag. |
90 | //! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding | 90 | //! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corresponding |
91 | //! capability enabled. | 91 | //! capability enabled. |
92 | 92 | ||
93 | use hir::ModPath; | ||
94 | use ide_db::helpers::{ | 93 | use ide_db::helpers::{ |
95 | import_assets::{ImportAssets, ImportCandidate}, | 94 | import_assets::{ImportAssets, ImportCandidate}, |
96 | insert_use::ImportScope, | 95 | insert_use::ImportScope, |
@@ -161,13 +160,13 @@ pub(crate) fn position_for_import<'a>( | |||
161 | ) -> Option<&'a SyntaxNode> { | 160 | ) -> Option<&'a SyntaxNode> { |
162 | Some(match import_candidate { | 161 | Some(match import_candidate { |
163 | Some(ImportCandidate::Path(_)) => ctx.name_ref_syntax.as_ref()?.syntax(), | 162 | Some(ImportCandidate::Path(_)) => ctx.name_ref_syntax.as_ref()?.syntax(), |
164 | Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual.as_ref()?.syntax(), | 163 | Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual()?.syntax(), |
165 | Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver()?.syntax(), | 164 | Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver()?.syntax(), |
166 | None => ctx | 165 | None => ctx |
167 | .name_ref_syntax | 166 | .name_ref_syntax |
168 | .as_ref() | 167 | .as_ref() |
169 | .map(|name_ref| name_ref.syntax()) | 168 | .map(|name_ref| name_ref.syntax()) |
170 | .or_else(|| ctx.path_qual.as_ref().map(|path| path.syntax())) | 169 | .or_else(|| ctx.path_qual().map(|path| path.syntax())) |
171 | .or_else(|| ctx.dot_receiver().map(|expr| expr.syntax()))?, | 170 | .or_else(|| ctx.dot_receiver().map(|expr| expr.syntax()))?, |
172 | }) | 171 | }) |
173 | } | 172 | } |
@@ -190,7 +189,7 @@ fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAs | |||
190 | }; | 189 | }; |
191 | let assets_for_path = ImportAssets::for_fuzzy_path( | 190 | let assets_for_path = ImportAssets::for_fuzzy_path( |
192 | current_module, | 191 | current_module, |
193 | ctx.path_qual.clone(), | 192 | ctx.path_qual().cloned(), |
194 | fuzzy_name, | 193 | fuzzy_name, |
195 | &ctx.sema, | 194 | &ctx.sema, |
196 | approximate_node, | 195 | approximate_node, |
@@ -208,7 +207,7 @@ fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAs | |||
208 | } | 207 | } |
209 | 208 | ||
210 | fn compute_fuzzy_completion_order_key( | 209 | fn compute_fuzzy_completion_order_key( |
211 | proposed_mod_path: &ModPath, | 210 | proposed_mod_path: &hir::ModPath, |
212 | user_input_lowercased: &str, | 211 | user_input_lowercased: &str, |
213 | ) -> usize { | 212 | ) -> usize { |
214 | cov_mark::hit!(certain_fuzzy_order_test); | 213 | cov_mark::hit!(certain_fuzzy_order_test); |
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index 1a7a484a4..ba13d3707 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs | |||
@@ -5,8 +5,8 @@ use std::iter; | |||
5 | use syntax::{SyntaxKind, T}; | 5 | use syntax::{SyntaxKind, T}; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | patterns::ImmediateLocation, CompletionContext, CompletionItem, CompletionItemKind, | 8 | context::PathCompletionContext, patterns::ImmediateLocation, CompletionContext, CompletionItem, |
9 | CompletionKind, Completions, | 9 | CompletionItemKind, CompletionKind, Completions, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) { | 12 | pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) { |
@@ -19,11 +19,12 @@ pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC | |||
19 | }; | 19 | }; |
20 | 20 | ||
21 | if ctx.use_item_syntax.is_some() { | 21 | if ctx.use_item_syntax.is_some() { |
22 | if ctx.path_qual.is_none() { | 22 | let qual = ctx.path_qual(); |
23 | if qual.is_none() { | ||
23 | kw_completion("crate::").add_to(acc); | 24 | kw_completion("crate::").add_to(acc); |
24 | } | 25 | } |
25 | kw_completion("self").add_to(acc); | 26 | kw_completion("self").add_to(acc); |
26 | if iter::successors(ctx.path_qual.clone(), |p| p.qualifier()) | 27 | if iter::successors(qual.cloned(), |p| p.qualifier()) |
27 | .all(|p| p.segment().and_then(|s| s.super_token()).is_some()) | 28 | .all(|p| p.segment().and_then(|s| s.super_token()).is_some()) |
28 | { | 29 | { |
29 | kw_completion("super::").add_to(acc); | 30 | kw_completion("super::").add_to(acc); |
@@ -127,8 +128,15 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
127 | add_keyword("mut", "mut "); | 128 | add_keyword("mut", "mut "); |
128 | } | 129 | } |
129 | 130 | ||
130 | if ctx.in_loop_body { | 131 | let (can_be_stmt, in_loop_body) = match ctx.path_context { |
131 | if ctx.can_be_stmt { | 132 | Some(PathCompletionContext { |
133 | is_trivial_path: true, can_be_stmt, in_loop_body, .. | ||
134 | }) => (can_be_stmt, in_loop_body), | ||
135 | _ => return, | ||
136 | }; | ||
137 | |||
138 | if in_loop_body { | ||
139 | if can_be_stmt { | ||
132 | add_keyword("continue", "continue;"); | 140 | add_keyword("continue", "continue;"); |
133 | add_keyword("break", "break;"); | 141 | add_keyword("break", "break;"); |
134 | } else { | 142 | } else { |
@@ -137,9 +145,6 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
137 | } | 145 | } |
138 | } | 146 | } |
139 | 147 | ||
140 | if !ctx.is_trivial_path { | ||
141 | return; | ||
142 | } | ||
143 | let fn_def = match &ctx.function_def { | 148 | let fn_def = match &ctx.function_def { |
144 | Some(it) => it, | 149 | Some(it) => it, |
145 | None => return, | 150 | None => return, |
@@ -147,7 +152,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
147 | 152 | ||
148 | add_keyword( | 153 | add_keyword( |
149 | "return", | 154 | "return", |
150 | match (ctx.can_be_stmt, fn_def.ret_type().is_some()) { | 155 | match (can_be_stmt, fn_def.ret_type().is_some()) { |
151 | (true, true) => "return $0;", | 156 | (true, true) => "return $0;", |
152 | (true, false) => "return;", | 157 | (true, false) => "return;", |
153 | (false, true) => "return $0", | 158 | (false, true) => "return $0", |
diff --git a/crates/ide_completion/src/completions/macro_in_item_position.rs b/crates/ide_completion/src/completions/macro_in_item_position.rs deleted file mode 100644 index 781b96ff1..000000000 --- a/crates/ide_completion/src/completions/macro_in_item_position.rs +++ /dev/null | |||
@@ -1,48 +0,0 @@ | |||
1 | //! Completes macro invocations used in item position. | ||
2 | |||
3 | use crate::{CompletionContext, Completions}; | ||
4 | |||
5 | // Ideally this should be removed and moved into `(un)qualified_path` respectively | ||
6 | pub(crate) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) { | ||
7 | // Show only macros in top level. | ||
8 | if !ctx.expects_item() { | ||
9 | return; | ||
10 | } | ||
11 | |||
12 | ctx.scope.process_all_names(&mut |name, res| { | ||
13 | if let hir::ScopeDef::MacroDef(mac) = res { | ||
14 | acc.add_macro(ctx, Some(name.clone()), mac); | ||
15 | } | ||
16 | // FIXME: This should be done in qualified_path/unqualified_path instead? | ||
17 | if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { | ||
18 | acc.add_resolution(ctx, name, &res); | ||
19 | } | ||
20 | }) | ||
21 | } | ||
22 | |||
23 | #[cfg(test)] | ||
24 | mod tests { | ||
25 | use expect_test::{expect, Expect}; | ||
26 | |||
27 | use crate::{test_utils::completion_list, CompletionKind}; | ||
28 | |||
29 | fn check(ra_fixture: &str, expect: Expect) { | ||
30 | let actual = completion_list(ra_fixture, CompletionKind::Reference); | ||
31 | expect.assert_eq(&actual) | ||
32 | } | ||
33 | |||
34 | #[test] | ||
35 | fn completes_macros_as_item() { | ||
36 | check( | ||
37 | r#" | ||
38 | macro_rules! foo { () => {} } | ||
39 | fn foo() {} | ||
40 | |||
41 | $0 | ||
42 | "#, | ||
43 | expect![[r#" | ||
44 | ma foo!(…) macro_rules! foo | ||
45 | "#]], | ||
46 | ) | ||
47 | } | ||
48 | } | ||
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs index 8a728c67e..1daa8595a 100644 --- a/crates/ide_completion/src/completions/pattern.rs +++ b/crates/ide_completion/src/completions/pattern.rs | |||
@@ -39,7 +39,7 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
39 | | hir::ModuleDef::Module(..) => refutable, | 39 | | hir::ModuleDef::Module(..) => refutable, |
40 | _ => false, | 40 | _ => false, |
41 | }, | 41 | }, |
42 | hir::ScopeDef::MacroDef(_) => true, | 42 | hir::ScopeDef::MacroDef(mac) => mac.is_fn_like(), |
43 | hir::ScopeDef::ImplSelfType(impl_) => match impl_.self_ty(ctx.db).as_adt() { | 43 | hir::ScopeDef::ImplSelfType(impl_) => match impl_.self_ty(ctx.db).as_adt() { |
44 | Some(hir::Adt::Struct(strukt)) => { | 44 | Some(hir::Adt::Struct(strukt)) => { |
45 | acc.add_struct_pat(ctx, strukt, Some(name.clone())); | 45 | acc.add_struct_pat(ctx, strukt, Some(name.clone())); |
@@ -102,6 +102,28 @@ fn foo() { | |||
102 | } | 102 | } |
103 | 103 | ||
104 | #[test] | 104 | #[test] |
105 | fn does_not_complete_non_fn_macros() { | ||
106 | check( | ||
107 | r#" | ||
108 | macro_rules! m { ($e:expr) => { $e } } | ||
109 | enum E { X } | ||
110 | |||
111 | #[rustc_builtin_macro] | ||
112 | macro Clone {} | ||
113 | |||
114 | fn foo() { | ||
115 | match E::X { $0 } | ||
116 | } | ||
117 | "#, | ||
118 | expect![[r#" | ||
119 | ev E::X () | ||
120 | en E | ||
121 | ma m!(…) macro_rules! m | ||
122 | "#]], | ||
123 | ); | ||
124 | } | ||
125 | |||
126 | #[test] | ||
105 | fn completes_in_simple_macro_call() { | 127 | fn completes_in_simple_macro_call() { |
106 | check( | 128 | check( |
107 | r#" | 129 | r#" |
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs index 86bbb58e2..9f98b21be 100644 --- a/crates/ide_completion/src/completions/postfix.rs +++ b/crates/ide_completion/src/completions/postfix.rs | |||
@@ -24,7 +24,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
24 | } | 24 | } |
25 | 25 | ||
26 | let (dot_receiver, receiver_is_ambiguous_float_literal) = match &ctx.completion_location { | 26 | let (dot_receiver, receiver_is_ambiguous_float_literal) = match &ctx.completion_location { |
27 | Some(ImmediateLocation::MethodCall { receiver: Some(it) }) => (it, false), | 27 | Some(ImmediateLocation::MethodCall { receiver: Some(it), .. }) => (it, false), |
28 | Some(ImmediateLocation::FieldAccess { | 28 | Some(ImmediateLocation::FieldAccess { |
29 | receiver: Some(it), | 29 | receiver: Some(it), |
30 | receiver_is_ambiguous_float_literal, | 30 | receiver_is_ambiguous_float_literal, |
@@ -34,7 +34,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
34 | 34 | ||
35 | let receiver_text = get_receiver_text(dot_receiver, receiver_is_ambiguous_float_literal); | 35 | let receiver_text = get_receiver_text(dot_receiver, receiver_is_ambiguous_float_literal); |
36 | 36 | ||
37 | let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) { | 37 | let receiver_ty = match ctx.sema.type_of_expr(dot_receiver) { |
38 | Some(it) => it, | 38 | Some(it) => it, |
39 | None => return, | 39 | None => return, |
40 | }; | 40 | }; |
@@ -50,7 +50,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
50 | postfix_snippet( | 50 | postfix_snippet( |
51 | ctx, | 51 | ctx, |
52 | cap, | 52 | cap, |
53 | &dot_receiver, | 53 | dot_receiver, |
54 | "ifl", | 54 | "ifl", |
55 | "if let Ok {}", | 55 | "if let Ok {}", |
56 | &format!("if let Ok($1) = {} {{\n $0\n}}", receiver_text), | 56 | &format!("if let Ok($1) = {} {{\n $0\n}}", receiver_text), |
@@ -60,7 +60,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
60 | postfix_snippet( | 60 | postfix_snippet( |
61 | ctx, | 61 | ctx, |
62 | cap, | 62 | cap, |
63 | &dot_receiver, | 63 | dot_receiver, |
64 | "while", | 64 | "while", |
65 | "while let Ok {}", | 65 | "while let Ok {}", |
66 | &format!("while let Ok($1) = {} {{\n $0\n}}", receiver_text), | 66 | &format!("while let Ok($1) = {} {{\n $0\n}}", receiver_text), |
@@ -71,7 +71,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
71 | postfix_snippet( | 71 | postfix_snippet( |
72 | ctx, | 72 | ctx, |
73 | cap, | 73 | cap, |
74 | &dot_receiver, | 74 | dot_receiver, |
75 | "ifl", | 75 | "ifl", |
76 | "if let Some {}", | 76 | "if let Some {}", |
77 | &format!("if let Some($1) = {} {{\n $0\n}}", receiver_text), | 77 | &format!("if let Some($1) = {} {{\n $0\n}}", receiver_text), |
@@ -81,7 +81,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
81 | postfix_snippet( | 81 | postfix_snippet( |
82 | ctx, | 82 | ctx, |
83 | cap, | 83 | cap, |
84 | &dot_receiver, | 84 | dot_receiver, |
85 | "while", | 85 | "while", |
86 | "while let Some {}", | 86 | "while let Some {}", |
87 | &format!("while let Some($1) = {} {{\n $0\n}}", receiver_text), | 87 | &format!("while let Some($1) = {} {{\n $0\n}}", receiver_text), |
@@ -93,7 +93,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
93 | postfix_snippet( | 93 | postfix_snippet( |
94 | ctx, | 94 | ctx, |
95 | cap, | 95 | cap, |
96 | &dot_receiver, | 96 | dot_receiver, |
97 | "if", | 97 | "if", |
98 | "if expr {}", | 98 | "if expr {}", |
99 | &format!("if {} {{\n $0\n}}", receiver_text), | 99 | &format!("if {} {{\n $0\n}}", receiver_text), |
@@ -102,22 +102,22 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
102 | postfix_snippet( | 102 | postfix_snippet( |
103 | ctx, | 103 | ctx, |
104 | cap, | 104 | cap, |
105 | &dot_receiver, | 105 | dot_receiver, |
106 | "while", | 106 | "while", |
107 | "while expr {}", | 107 | "while expr {}", |
108 | &format!("while {} {{\n $0\n}}", receiver_text), | 108 | &format!("while {} {{\n $0\n}}", receiver_text), |
109 | ) | 109 | ) |
110 | .add_to(acc); | 110 | .add_to(acc); |
111 | postfix_snippet(ctx, cap, &dot_receiver, "not", "!expr", &format!("!{}", receiver_text)) | 111 | postfix_snippet(ctx, cap, dot_receiver, "not", "!expr", &format!("!{}", receiver_text)) |
112 | .add_to(acc); | 112 | .add_to(acc); |
113 | } | 113 | } |
114 | 114 | ||
115 | postfix_snippet(ctx, cap, &dot_receiver, "ref", "&expr", &format!("&{}", receiver_text)) | 115 | postfix_snippet(ctx, cap, dot_receiver, "ref", "&expr", &format!("&{}", receiver_text)) |
116 | .add_to(acc); | 116 | .add_to(acc); |
117 | postfix_snippet( | 117 | postfix_snippet( |
118 | ctx, | 118 | ctx, |
119 | cap, | 119 | cap, |
120 | &dot_receiver, | 120 | dot_receiver, |
121 | "refm", | 121 | "refm", |
122 | "&mut expr", | 122 | "&mut expr", |
123 | &format!("&mut {}", receiver_text), | 123 | &format!("&mut {}", receiver_text), |
diff --git a/crates/ide_completion/src/completions/postfix/format_like.rs b/crates/ide_completion/src/completions/postfix/format_like.rs index 0dcb3e898..2dc13c293 100644 --- a/crates/ide_completion/src/completions/postfix/format_like.rs +++ b/crates/ide_completion/src/completions/postfix/format_like.rs | |||
@@ -4,15 +4,15 @@ | |||
4 | // | 4 | // |
5 | // The following postfix snippets are available: | 5 | // The following postfix snippets are available: |
6 | // | 6 | // |
7 | // - `format` -> `format!(...)` | 7 | // * `format` -> `format!(...)` |
8 | // - `panic` -> `panic!(...)` | 8 | // * `panic` -> `panic!(...)` |
9 | // - `println` -> `println!(...)` | 9 | // * `println` -> `println!(...)` |
10 | // - `log`: | 10 | // * `log`: |
11 | // + `logd` -> `log::debug!(...)` | 11 | // ** `logd` -> `log::debug!(...)` |
12 | // + `logt` -> `log::trace!(...)` | 12 | // ** `logt` -> `log::trace!(...)` |
13 | // + `logi` -> `log::info!(...)` | 13 | // ** `logi` -> `log::info!(...)` |
14 | // + `logw` -> `log::warn!(...)` | 14 | // ** `logw` -> `log::warn!(...)` |
15 | // + `loge` -> `log::error!(...)` | 15 | // ** `loge` -> `log::error!(...)` |
16 | // | 16 | // |
17 | // image::https://user-images.githubusercontent.com/48062697/113020656-b560f500-917a-11eb-87de-02991f61beb8.gif[] | 17 | // image::https://user-images.githubusercontent.com/48062697/113020656-b560f500-917a-11eb-87de-02991f61beb8.gif[] |
18 | 18 | ||
@@ -53,7 +53,7 @@ pub(crate) fn add_format_like_completions( | |||
53 | for (label, macro_name) in KINDS { | 53 | for (label, macro_name) in KINDS { |
54 | let snippet = parser.into_suggestion(macro_name); | 54 | let snippet = parser.into_suggestion(macro_name); |
55 | 55 | ||
56 | postfix_snippet(ctx, cap, &dot_receiver, label, macro_name, &snippet).add_to(acc); | 56 | postfix_snippet(ctx, cap, dot_receiver, label, macro_name, &snippet).add_to(acc); |
57 | } | 57 | } |
58 | } | 58 | } |
59 | } | 59 | } |
@@ -91,7 +91,7 @@ enum State { | |||
91 | impl FormatStrParser { | 91 | impl FormatStrParser { |
92 | pub(crate) fn new(input: String) -> Self { | 92 | pub(crate) fn new(input: String) -> Self { |
93 | Self { | 93 | Self { |
94 | input: input, | 94 | input, |
95 | output: String::new(), | 95 | output: String::new(), |
96 | extracted_expressions: Vec::new(), | 96 | extracted_expressions: Vec::new(), |
97 | state: State::NotExpr, | 97 | state: State::NotExpr, |
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index de58ce1cd..6083537b7 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs | |||
@@ -7,25 +7,28 @@ use syntax::AstNode; | |||
7 | use crate::{CompletionContext, Completions}; | 7 | use crate::{CompletionContext, Completions}; |
8 | 8 | ||
9 | pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 9 | pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) { |
10 | if ctx.is_path_disallowed() || ctx.expects_item() { | 10 | if ctx.is_path_disallowed() { |
11 | return; | 11 | return; |
12 | } | 12 | } |
13 | let path = match &ctx.path_qual { | 13 | let path = match ctx.path_qual() { |
14 | Some(path) => path.clone(), | 14 | Some(path) => path, |
15 | None => return, | 15 | None => return, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | let resolution = match ctx.sema.resolve_path(&path) { | 18 | let resolution = match ctx.sema.resolve_path(path) { |
19 | Some(res) => res, | 19 | Some(res) => res, |
20 | None => return, | 20 | None => return, |
21 | }; | 21 | }; |
22 | let context_module = ctx.scope.module(); | 22 | let context_module = ctx.scope.module(); |
23 | if ctx.expects_assoc_item() { | 23 | |
24 | if ctx.expects_item() || ctx.expects_assoc_item() { | ||
24 | if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution { | 25 | if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution { |
25 | let module_scope = module.scope(ctx.db, context_module); | 26 | let module_scope = module.scope(ctx.db, context_module); |
26 | for (name, def) in module_scope { | 27 | for (name, def) in module_scope { |
27 | if let hir::ScopeDef::MacroDef(macro_def) = def { | 28 | if let hir::ScopeDef::MacroDef(macro_def) = def { |
28 | acc.add_macro(ctx, Some(name.clone()), macro_def); | 29 | if macro_def.is_fn_like() { |
30 | acc.add_macro(ctx, Some(name.clone()), macro_def); | ||
31 | } | ||
29 | } | 32 | } |
30 | if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def { | 33 | if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def { |
31 | acc.add_resolution(ctx, name, &def); | 34 | acc.add_resolution(ctx, name, &def); |
@@ -57,6 +60,13 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
57 | } | 60 | } |
58 | } | 61 | } |
59 | 62 | ||
63 | if let hir::ScopeDef::MacroDef(macro_def) = def { | ||
64 | if !macro_def.is_fn_like() { | ||
65 | // Don't suggest attribute macros and derives. | ||
66 | continue; | ||
67 | } | ||
68 | } | ||
69 | |||
60 | acc.add_resolution(ctx, name, &def); | 70 | acc.add_resolution(ctx, name, &def); |
61 | } | 71 | } |
62 | } | 72 | } |
@@ -198,6 +208,36 @@ mod tests { | |||
198 | } | 208 | } |
199 | 209 | ||
200 | #[test] | 210 | #[test] |
211 | fn dont_complete_values_in_type_pos() { | ||
212 | check( | ||
213 | r#" | ||
214 | const FOO: () = (); | ||
215 | static BAR: () = (); | ||
216 | struct Baz; | ||
217 | fn foo() { | ||
218 | let _: self::$0; | ||
219 | } | ||
220 | "#, | ||
221 | expect![[r#" | ||
222 | st Baz | ||
223 | "#]], | ||
224 | ); | ||
225 | } | ||
226 | |||
227 | #[test] | ||
228 | fn dont_complete_enum_variants_in_type_pos() { | ||
229 | check( | ||
230 | r#" | ||
231 | enum Foo { Bar } | ||
232 | fn foo() { | ||
233 | let _: Foo::$0; | ||
234 | } | ||
235 | "#, | ||
236 | expect![[r#""#]], | ||
237 | ); | ||
238 | } | ||
239 | |||
240 | #[test] | ||
201 | fn dont_complete_current_use_in_braces_with_glob() { | 241 | fn dont_complete_current_use_in_braces_with_glob() { |
202 | check( | 242 | check( |
203 | r#" | 243 | r#" |
@@ -617,6 +657,32 @@ fn main() { let _ = crate::$0 } | |||
617 | } | 657 | } |
618 | 658 | ||
619 | #[test] | 659 | #[test] |
660 | fn does_not_complete_non_fn_macros() { | ||
661 | check( | ||
662 | r#" | ||
663 | mod m { | ||
664 | #[rustc_builtin_macro] | ||
665 | pub macro Clone {} | ||
666 | } | ||
667 | |||
668 | fn f() {m::$0} | ||
669 | "#, | ||
670 | expect![[r#""#]], | ||
671 | ); | ||
672 | check( | ||
673 | r#" | ||
674 | mod m { | ||
675 | #[rustc_builtin_macro] | ||
676 | pub macro bench {} | ||
677 | } | ||
678 | |||
679 | fn f() {m::$0} | ||
680 | "#, | ||
681 | expect![[r#""#]], | ||
682 | ); | ||
683 | } | ||
684 | |||
685 | #[test] | ||
620 | fn completes_in_assoc_item_list() { | 686 | fn completes_in_assoc_item_list() { |
621 | check( | 687 | check( |
622 | r#" | 688 | r#" |
@@ -631,17 +697,17 @@ impl MyStruct { | |||
631 | "#, | 697 | "#, |
632 | expect![[r##" | 698 | expect![[r##" |
633 | md bar | 699 | md bar |
634 | ma foo! #[macro_export] macro_rules! foo | 700 | ma foo!(…) #[macro_export] macro_rules! foo |
635 | "##]], | 701 | "##]], |
636 | ); | 702 | ); |
637 | } | 703 | } |
638 | 704 | ||
639 | #[test] | 705 | #[test] |
640 | #[ignore] // FIXME doesn't complete anything atm | ||
641 | fn completes_in_item_list() { | 706 | fn completes_in_item_list() { |
642 | check( | 707 | check( |
643 | r#" | 708 | r#" |
644 | struct MyStruct {} | 709 | struct MyStruct {} |
710 | #[macro_export] | ||
645 | macro_rules! foo {} | 711 | macro_rules! foo {} |
646 | mod bar {} | 712 | mod bar {} |
647 | 713 | ||
@@ -649,7 +715,7 @@ crate::$0 | |||
649 | "#, | 715 | "#, |
650 | expect![[r#" | 716 | expect![[r#" |
651 | md bar | 717 | md bar |
652 | ma foo! macro_rules! foo | 718 | ma foo!(…) #[macro_export] macro_rules! foo |
653 | "#]], | 719 | "#]], |
654 | ) | 720 | ) |
655 | } | 721 | } |
diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs index 6e6a6eb92..b9862de67 100644 --- a/crates/ide_completion/src/completions/snippet.rs +++ b/crates/ide_completion/src/completions/snippet.rs | |||
@@ -3,8 +3,8 @@ | |||
3 | use ide_db::helpers::SnippetCap; | 3 | use ide_db::helpers::SnippetCap; |
4 | 4 | ||
5 | use crate::{ | 5 | use crate::{ |
6 | item::Builder, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, | 6 | context::PathCompletionContext, item::Builder, CompletionContext, CompletionItem, |
7 | Completions, | 7 | CompletionItemKind, CompletionKind, Completions, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder { | 10 | fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder { |
@@ -14,15 +14,21 @@ fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) | |||
14 | } | 14 | } |
15 | 15 | ||
16 | pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionContext) { | 16 | pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionContext) { |
17 | if !(ctx.is_trivial_path && ctx.function_def.is_some()) { | 17 | if ctx.function_def.is_none() { |
18 | return; | 18 | return; |
19 | } | 19 | } |
20 | |||
21 | let can_be_stmt = match ctx.path_context { | ||
22 | Some(PathCompletionContext { is_trivial_path: true, can_be_stmt, .. }) => can_be_stmt, | ||
23 | _ => return, | ||
24 | }; | ||
25 | |||
20 | let cap = match ctx.config.snippet_cap { | 26 | let cap = match ctx.config.snippet_cap { |
21 | Some(it) => it, | 27 | Some(it) => it, |
22 | None => return, | 28 | None => return, |
23 | }; | 29 | }; |
24 | 30 | ||
25 | if ctx.can_be_stmt { | 31 | if can_be_stmt { |
26 | snippet(ctx, cap, "pd", "eprintln!(\"$0 = {:?}\", $0);").add_to(acc); | 32 | snippet(ctx, cap, "pd", "eprintln!(\"$0 = {:?}\", $0);").add_to(acc); |
27 | snippet(ctx, cap, "ppd", "eprintln!(\"$0 = {:#?}\", $0);").add_to(acc); | 33 | snippet(ctx, cap, "ppd", "eprintln!(\"$0 = {:#?}\", $0);").add_to(acc); |
28 | } | 34 | } |
diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs index 968c0254d..a60e5f43c 100644 --- a/crates/ide_completion/src/completions/trait_impl.rs +++ b/crates/ide_completion/src/completions/trait_impl.rs | |||
@@ -34,20 +34,13 @@ | |||
34 | use hir::{self, HasAttrs, HasSource}; | 34 | use hir::{self, HasAttrs, HasSource}; |
35 | use ide_db::{traits::get_missing_assoc_items, SymbolKind}; | 35 | use ide_db::{traits::get_missing_assoc_items, SymbolKind}; |
36 | use syntax::{ | 36 | use syntax::{ |
37 | ast::{self, edit, Impl}, | 37 | ast::{self, edit}, |
38 | display::function_declaration, | 38 | display::function_declaration, |
39 | AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, T, | 39 | AstNode, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, T, |
40 | }; | 40 | }; |
41 | use text_edit::TextEdit; | 41 | use text_edit::TextEdit; |
42 | 42 | ||
43 | use crate::{ | 43 | use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}; |
44 | CompletionContext, | ||
45 | CompletionItem, | ||
46 | CompletionItemKind, | ||
47 | CompletionKind, | ||
48 | Completions, | ||
49 | // display::function_declaration, | ||
50 | }; | ||
51 | 44 | ||
52 | #[derive(Debug, PartialEq, Eq)] | 45 | #[derive(Debug, PartialEq, Eq)] |
53 | enum ImplCompletionKind { | 46 | enum ImplCompletionKind { |
@@ -58,7 +51,7 @@ enum ImplCompletionKind { | |||
58 | } | 51 | } |
59 | 52 | ||
60 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { | 53 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { |
61 | if let Some((kind, trigger, impl_def)) = completion_match(ctx) { | 54 | if let Some((kind, trigger, impl_def)) = completion_match(ctx.token.clone()) { |
62 | get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| match item { | 55 | get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| match item { |
63 | hir::AssocItem::Function(fn_item) | 56 | hir::AssocItem::Function(fn_item) |
64 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Fn => | 57 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Fn => |
@@ -80,8 +73,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext | |||
80 | } | 73 | } |
81 | } | 74 | } |
82 | 75 | ||
83 | fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, SyntaxNode, Impl)> { | 76 | fn completion_match(mut token: SyntaxToken) -> Option<(ImplCompletionKind, SyntaxNode, ast::Impl)> { |
84 | let mut token = ctx.token.clone(); | ||
85 | // For keyword without name like `impl .. { fn $0 }`, the current position is inside | 77 | // For keyword without name like `impl .. { fn $0 }`, the current position is inside |
86 | // the whitespace token, which is outside `FN` syntax node. | 78 | // the whitespace token, which is outside `FN` syntax node. |
87 | // We need to follow the previous token in this case. | 79 | // We need to follow the previous token in this case. |
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index bd955aa85..952f052a1 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs | |||
@@ -1,30 +1,32 @@ | |||
1 | //! Completion of names from the current scope, e.g. locals and imported items. | 1 | //! Completion of names from the current scope, e.g. locals and imported items. |
2 | 2 | ||
3 | use hir::ScopeDef; | 3 | use hir::ScopeDef; |
4 | use syntax::{ast, AstNode}; | ||
4 | 5 | ||
5 | use crate::{CompletionContext, Completions}; | 6 | use crate::{patterns::ImmediateLocation, CompletionContext, Completions}; |
6 | 7 | ||
7 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 8 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { |
8 | if !ctx.is_trivial_path { | 9 | if ctx.is_path_disallowed() || !ctx.is_trivial_path() { |
9 | return; | ||
10 | } | ||
11 | if ctx.is_path_disallowed() || ctx.expects_item() { | ||
12 | return; | 10 | return; |
13 | } | 11 | } |
14 | 12 | ||
15 | if ctx.expects_assoc_item() { | 13 | if ctx.expects_item() || ctx.expects_assoc_item() { |
16 | ctx.scope.process_all_names(&mut |name, def| { | 14 | // only show macros in {Assoc}ItemList |
17 | if let ScopeDef::MacroDef(macro_def) = def { | 15 | ctx.scope.process_all_names(&mut |name, res| { |
18 | acc.add_macro(ctx, Some(name.clone()), macro_def); | 16 | if let hir::ScopeDef::MacroDef(mac) = res { |
17 | if mac.is_fn_like() { | ||
18 | acc.add_macro(ctx, Some(name.clone()), mac); | ||
19 | } | ||
19 | } | 20 | } |
20 | if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def { | 21 | if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { |
21 | acc.add_resolution(ctx, name, &def); | 22 | acc.add_resolution(ctx, name, &res); |
22 | } | 23 | } |
23 | }); | 24 | }); |
24 | return; | 25 | return; |
25 | } | 26 | } |
26 | 27 | ||
27 | if ctx.expects_use_tree() { | 28 | if ctx.expects_use_tree() { |
29 | // only show modules in a fresh UseTree | ||
28 | cov_mark::hit!(only_completes_modules_in_import); | 30 | cov_mark::hit!(only_completes_modules_in_import); |
29 | ctx.scope.process_all_names(&mut |name, res| { | 31 | ctx.scope.process_all_names(&mut |name, res| { |
30 | if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { | 32 | if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { |
@@ -42,12 +44,32 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
42 | }); | 44 | }); |
43 | } | 45 | } |
44 | 46 | ||
47 | if let Some(ImmediateLocation::GenericArgList(arg_list)) = &ctx.completion_location { | ||
48 | if let Some(path_seg) = arg_list.syntax().parent().and_then(ast::PathSegment::cast) { | ||
49 | if let Some(hir::PathResolution::Def(hir::ModuleDef::Trait(trait_))) = | ||
50 | ctx.sema.resolve_path(&path_seg.parent_path()) | ||
51 | { | ||
52 | trait_.items(ctx.sema.db).into_iter().for_each(|it| { | ||
53 | if let hir::AssocItem::TypeAlias(alias) = it { | ||
54 | acc.add_type_alias_with_eq(ctx, alias) | ||
55 | } | ||
56 | }); | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | |||
45 | ctx.scope.process_all_names(&mut |name, res| { | 61 | ctx.scope.process_all_names(&mut |name, res| { |
46 | if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { | 62 | if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { |
47 | cov_mark::hit!(skip_lifetime_completion); | 63 | cov_mark::hit!(skip_lifetime_completion); |
48 | return; | 64 | return; |
49 | } | 65 | } |
50 | acc.add_resolution(ctx, name, &res); | 66 | let add_resolution = match res { |
67 | ScopeDef::MacroDef(mac) => mac.is_fn_like(), | ||
68 | _ => true, | ||
69 | }; | ||
70 | if add_resolution { | ||
71 | acc.add_resolution(ctx, name, &res); | ||
72 | } | ||
51 | }); | 73 | }); |
52 | } | 74 | } |
53 | 75 | ||
@@ -70,6 +92,28 @@ mod tests { | |||
70 | } | 92 | } |
71 | 93 | ||
72 | #[test] | 94 | #[test] |
95 | fn dont_complete_values_in_type_pos() { | ||
96 | check( | ||
97 | r#" | ||
98 | const FOO: () = (); | ||
99 | static BAR: () = (); | ||
100 | enum Foo { | ||
101 | Bar | ||
102 | } | ||
103 | struct Baz; | ||
104 | fn foo() { | ||
105 | let local = (); | ||
106 | let _: $0; | ||
107 | } | ||
108 | "#, | ||
109 | expect![[r#" | ||
110 | en Foo | ||
111 | st Baz | ||
112 | "#]], | ||
113 | ); | ||
114 | } | ||
115 | |||
116 | #[test] | ||
73 | fn only_completes_modules_in_import() { | 117 | fn only_completes_modules_in_import() { |
74 | cov_mark::check!(only_completes_modules_in_import); | 118 | cov_mark::check!(only_completes_modules_in_import); |
75 | check( | 119 | check( |
@@ -340,7 +384,6 @@ fn x() -> $0 | |||
340 | "#, | 384 | "#, |
341 | expect![[r#" | 385 | expect![[r#" |
342 | st Foo | 386 | st Foo |
343 | fn x() fn() | ||
344 | "#]], | 387 | "#]], |
345 | ); | 388 | ); |
346 | } | 389 | } |
@@ -392,7 +435,6 @@ pub mod prelude { | |||
392 | } | 435 | } |
393 | "#, | 436 | "#, |
394 | expect![[r#" | 437 | expect![[r#" |
395 | fn foo() fn() | ||
396 | md std | 438 | md std |
397 | st Option | 439 | st Option |
398 | "#]], | 440 | "#]], |
@@ -428,6 +470,44 @@ mod macros { | |||
428 | } | 470 | } |
429 | 471 | ||
430 | #[test] | 472 | #[test] |
473 | fn does_not_complete_non_fn_macros() { | ||
474 | check( | ||
475 | r#" | ||
476 | #[rustc_builtin_macro] | ||
477 | pub macro Clone {} | ||
478 | |||
479 | fn f() {$0} | ||
480 | "#, | ||
481 | expect![[r#" | ||
482 | fn f() fn() | ||
483 | "#]], | ||
484 | ); | ||
485 | check( | ||
486 | r#" | ||
487 | #[rustc_builtin_macro] | ||
488 | pub macro Clone {} | ||
489 | |||
490 | struct S; | ||
491 | impl S { | ||
492 | $0 | ||
493 | } | ||
494 | "#, | ||
495 | expect![[r#""#]], | ||
496 | ); | ||
497 | check( | ||
498 | r#" | ||
499 | #[rustc_builtin_macro] | ||
500 | pub macro bench {} | ||
501 | |||
502 | fn f() {$0} | ||
503 | "#, | ||
504 | expect![[r#" | ||
505 | fn f() fn() | ||
506 | "#]], | ||
507 | ); | ||
508 | } | ||
509 | |||
510 | #[test] | ||
431 | fn completes_std_prelude_if_core_is_defined() { | 511 | fn completes_std_prelude_if_core_is_defined() { |
432 | check( | 512 | check( |
433 | r#" | 513 | r#" |
@@ -449,7 +529,6 @@ pub mod prelude { | |||
449 | } | 529 | } |
450 | "#, | 530 | "#, |
451 | expect![[r#" | 531 | expect![[r#" |
452 | fn foo() fn() | ||
453 | md std | 532 | md std |
454 | md core | 533 | md core |
455 | st String | 534 | st String |
@@ -510,7 +589,6 @@ macro_rules! foo { () => {} } | |||
510 | fn main() { let x: $0 } | 589 | fn main() { let x: $0 } |
511 | "#, | 590 | "#, |
512 | expect![[r#" | 591 | expect![[r#" |
513 | fn main() fn() | ||
514 | ma foo!(…) macro_rules! foo | 592 | ma foo!(…) macro_rules! foo |
515 | "#]], | 593 | "#]], |
516 | ); | 594 | ); |
@@ -693,12 +771,11 @@ impl MyStruct { | |||
693 | "#, | 771 | "#, |
694 | expect![[r#" | 772 | expect![[r#" |
695 | md bar | 773 | md bar |
696 | ma foo! macro_rules! foo | 774 | ma foo!(…) macro_rules! foo |
697 | "#]], | 775 | "#]], |
698 | ) | 776 | ) |
699 | } | 777 | } |
700 | 778 | ||
701 | // FIXME: The completions here currently come from `macro_in_item_position`, but they shouldn't | ||
702 | #[test] | 779 | #[test] |
703 | fn completes_in_item_list() { | 780 | fn completes_in_item_list() { |
704 | check( | 781 | check( |
@@ -715,4 +792,21 @@ $0 | |||
715 | "#]], | 792 | "#]], |
716 | ) | 793 | ) |
717 | } | 794 | } |
795 | |||
796 | #[test] | ||
797 | fn completes_assoc_types_in_dynimpl_trait() { | ||
798 | check( | ||
799 | r#" | ||
800 | trait Foo { | ||
801 | type Bar; | ||
802 | } | ||
803 | |||
804 | fn foo(_: impl Foo<B$0>) {} | ||
805 | "#, | ||
806 | expect![[r#" | ||
807 | ta Bar = type Bar; | ||
808 | tt Foo | ||
809 | "#]], | ||
810 | ); | ||
811 | } | ||
718 | } | 812 | } |