diff options
-rw-r--r-- | crates/ide_completion/src/completions/flyimport.rs | 6 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/keyword.rs | 27 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/qualified_path.rs | 12 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/unqualified_path.rs | 27 | ||||
-rw-r--r-- | crates/ide_completion/src/context.rs | 21 | ||||
-rw-r--r-- | crates/ide_completion/src/patterns.rs | 12 |
6 files changed, 76 insertions, 29 deletions
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs index be9cfbded..df27e7a84 100644 --- a/crates/ide_completion/src/completions/flyimport.rs +++ b/crates/ide_completion/src/completions/flyimport.rs | |||
@@ -110,7 +110,11 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) | |||
110 | if !ctx.config.enable_imports_on_the_fly { | 110 | if !ctx.config.enable_imports_on_the_fly { |
111 | return None; | 111 | return None; |
112 | } | 112 | } |
113 | if ctx.use_item_syntax.is_some() || ctx.is_path_disallowed() { | 113 | if ctx.use_item_syntax.is_some() |
114 | || ctx.is_path_disallowed() | ||
115 | || ctx.expects_item() | ||
116 | || ctx.expects_assoc_item() | ||
117 | { | ||
114 | return None; | 118 | return None; |
115 | } | 119 | } |
116 | let potential_import_name = { | 120 | let potential_import_name = { |
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index 58e35bad9..14d6ae54e 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs | |||
@@ -49,35 +49,35 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
49 | return; | 49 | return; |
50 | } | 50 | } |
51 | 51 | ||
52 | let has_trait_or_impl_parent = ctx.has_impl_or_trait_parent(); | 52 | let expects_assoc_item = ctx.expects_assoc_item(); |
53 | let has_block_expr_parent = ctx.has_block_expr_parent(); | 53 | let has_block_expr_parent = ctx.has_block_expr_parent(); |
54 | let has_item_list_parent = ctx.has_item_list_parent(); | 54 | let expects_item = ctx.expects_item(); |
55 | if ctx.has_impl_or_trait_prev_sibling() { | 55 | if ctx.has_impl_or_trait_prev_sibling() { |
56 | add_keyword(ctx, acc, "where", "where "); | 56 | add_keyword(ctx, acc, "where", "where "); |
57 | return; | 57 | return; |
58 | } | 58 | } |
59 | if ctx.previous_token_is(T![unsafe]) { | 59 | if ctx.previous_token_is(T![unsafe]) { |
60 | if has_item_list_parent || has_block_expr_parent { | 60 | if expects_item || has_block_expr_parent { |
61 | add_keyword(ctx, acc, "fn", "fn $1($2) {\n $0\n}") | 61 | add_keyword(ctx, acc, "fn", "fn $1($2) {\n $0\n}") |
62 | } | 62 | } |
63 | 63 | ||
64 | if has_item_list_parent || has_block_expr_parent { | 64 | if expects_item || has_block_expr_parent { |
65 | add_keyword(ctx, acc, "trait", "trait $1 {\n $0\n}"); | 65 | add_keyword(ctx, acc, "trait", "trait $1 {\n $0\n}"); |
66 | add_keyword(ctx, acc, "impl", "impl $1 {\n $0\n}"); | 66 | add_keyword(ctx, acc, "impl", "impl $1 {\n $0\n}"); |
67 | } | 67 | } |
68 | 68 | ||
69 | return; | 69 | return; |
70 | } | 70 | } |
71 | if has_item_list_parent || has_trait_or_impl_parent || has_block_expr_parent { | 71 | if expects_item || expects_assoc_item || has_block_expr_parent { |
72 | add_keyword(ctx, acc, "fn", "fn $1($2) {\n $0\n}"); | 72 | add_keyword(ctx, acc, "fn", "fn $1($2) {\n $0\n}"); |
73 | } | 73 | } |
74 | if has_item_list_parent || has_block_expr_parent { | 74 | if expects_item || has_block_expr_parent { |
75 | add_keyword(ctx, acc, "use", "use "); | 75 | add_keyword(ctx, acc, "use", "use "); |
76 | add_keyword(ctx, acc, "impl", "impl $1 {\n $0\n}"); | 76 | add_keyword(ctx, acc, "impl", "impl $1 {\n $0\n}"); |
77 | add_keyword(ctx, acc, "trait", "trait $1 {\n $0\n}"); | 77 | add_keyword(ctx, acc, "trait", "trait $1 {\n $0\n}"); |
78 | } | 78 | } |
79 | 79 | ||
80 | if has_item_list_parent { | 80 | if expects_item { |
81 | add_keyword(ctx, acc, "enum", "enum $1 {\n $0\n}"); | 81 | add_keyword(ctx, acc, "enum", "enum $1 {\n $0\n}"); |
82 | add_keyword(ctx, acc, "struct", "struct $0"); | 82 | add_keyword(ctx, acc, "struct", "struct $0"); |
83 | add_keyword(ctx, acc, "union", "union $1 {\n $0\n}"); | 83 | add_keyword(ctx, acc, "union", "union $1 {\n $0\n}"); |
@@ -101,24 +101,23 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
101 | add_keyword(ctx, acc, "else", "else {\n $0\n}"); | 101 | add_keyword(ctx, acc, "else", "else {\n $0\n}"); |
102 | add_keyword(ctx, acc, "else if", "else if $1 {\n $0\n}"); | 102 | add_keyword(ctx, acc, "else if", "else if $1 {\n $0\n}"); |
103 | } | 103 | } |
104 | if has_item_list_parent || has_block_expr_parent { | 104 | if expects_item || has_block_expr_parent { |
105 | add_keyword(ctx, acc, "mod", "mod $0"); | 105 | add_keyword(ctx, acc, "mod", "mod $0"); |
106 | } | 106 | } |
107 | if ctx.has_ident_or_ref_pat_parent() { | 107 | if ctx.has_ident_or_ref_pat_parent() { |
108 | add_keyword(ctx, acc, "mut", "mut "); | 108 | add_keyword(ctx, acc, "mut", "mut "); |
109 | } | 109 | } |
110 | if has_item_list_parent || has_trait_or_impl_parent || has_block_expr_parent { | 110 | if expects_item || expects_assoc_item || has_block_expr_parent { |
111 | add_keyword(ctx, acc, "const", "const "); | 111 | add_keyword(ctx, acc, "const", "const "); |
112 | add_keyword(ctx, acc, "type", "type "); | 112 | add_keyword(ctx, acc, "type", "type "); |
113 | } | 113 | } |
114 | if has_item_list_parent || has_block_expr_parent { | 114 | if expects_item || has_block_expr_parent { |
115 | add_keyword(ctx, acc, "static", "static "); | 115 | add_keyword(ctx, acc, "static", "static "); |
116 | }; | 116 | }; |
117 | if has_item_list_parent || has_block_expr_parent { | 117 | if expects_item || has_block_expr_parent { |
118 | add_keyword(ctx, acc, "extern", "extern "); | 118 | add_keyword(ctx, acc, "extern", "extern "); |
119 | } | 119 | } |
120 | if has_item_list_parent || has_trait_or_impl_parent || has_block_expr_parent || ctx.is_match_arm | 120 | if expects_item || expects_assoc_item || has_block_expr_parent || ctx.is_match_arm { |
121 | { | ||
122 | add_keyword(ctx, acc, "unsafe", "unsafe "); | 121 | add_keyword(ctx, acc, "unsafe", "unsafe "); |
123 | } | 122 | } |
124 | if ctx.in_loop_body { | 123 | if ctx.in_loop_body { |
@@ -130,7 +129,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
130 | add_keyword(ctx, acc, "break", "break"); | 129 | add_keyword(ctx, acc, "break", "break"); |
131 | } | 130 | } |
132 | } | 131 | } |
133 | if has_item_list_parent || ctx.has_impl_parent() || ctx.has_field_list_parent() { | 132 | if expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_record_field() { |
134 | add_keyword(ctx, acc, "pub(crate)", "pub(crate) "); | 133 | add_keyword(ctx, acc, "pub(crate)", "pub(crate) "); |
135 | add_keyword(ctx, acc, "pub", "pub "); | 134 | add_keyword(ctx, acc, "pub", "pub "); |
136 | } | 135 | } |
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index ed48f61af..a90325e06 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs | |||
@@ -21,6 +21,18 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
21 | }; | 21 | }; |
22 | let context_module = ctx.scope.module(); | 22 | let context_module = ctx.scope.module(); |
23 | 23 | ||
24 | if ctx.expects_item() || ctx.expects_assoc_item() { | ||
25 | if let PathResolution::Def(hir::ModuleDef::Module(module)) = resolution { | ||
26 | let module_scope = module.scope(ctx.db, context_module); | ||
27 | for (name, def) in module_scope { | ||
28 | if let ScopeDef::MacroDef(macro_def) = def { | ||
29 | acc.add_macro(ctx, Some(name.to_string()), macro_def); | ||
30 | } | ||
31 | } | ||
32 | } | ||
33 | return; | ||
34 | } | ||
35 | |||
24 | // Add associated types on type parameters and `Self`. | 36 | // Add associated types on type parameters and `Self`. |
25 | resolution.assoc_type_shorthand_candidates(ctx.db, |_, alias| { | 37 | resolution.assoc_type_shorthand_candidates(ctx.db, |_, alias| { |
26 | acc.add_type_alias(ctx, alias); | 38 | acc.add_type_alias(ctx, alias); |
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 046a393ae..cbac88240 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs | |||
@@ -12,6 +12,14 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
12 | if ctx.is_path_disallowed() { | 12 | if ctx.is_path_disallowed() { |
13 | return; | 13 | return; |
14 | } | 14 | } |
15 | if ctx.expects_item() || ctx.expects_assoc_item() { | ||
16 | ctx.scope.process_all_names(&mut |name, def| { | ||
17 | if let ScopeDef::MacroDef(macro_def) = def { | ||
18 | acc.add_macro(ctx, Some(name.to_string()), macro_def); | ||
19 | } | ||
20 | }); | ||
21 | return; | ||
22 | } | ||
15 | 23 | ||
16 | if let Some(hir::Adt::Enum(e)) = | 24 | if let Some(hir::Adt::Enum(e)) = |
17 | ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) | 25 | ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) |
@@ -647,7 +655,7 @@ fn f() {} | |||
647 | } | 655 | } |
648 | 656 | ||
649 | #[test] | 657 | #[test] |
650 | fn completes_type_or_trait_in_impl_block() { | 658 | fn completes_target_type_or_trait_in_impl_block() { |
651 | check( | 659 | check( |
652 | r#" | 660 | r#" |
653 | trait MyTrait {} | 661 | trait MyTrait {} |
@@ -662,4 +670,21 @@ impl My$0 | |||
662 | "#]], | 670 | "#]], |
663 | ) | 671 | ) |
664 | } | 672 | } |
673 | |||
674 | #[test] | ||
675 | fn only_completes_macros_in_assoc_item_list() { | ||
676 | check( | ||
677 | r#" | ||
678 | struct MyStruct {} | ||
679 | macro_rules! foo {} | ||
680 | |||
681 | impl MyStruct { | ||
682 | $0 | ||
683 | } | ||
684 | "#, | ||
685 | expect![[r#" | ||
686 | ma foo! macro_rules! foo | ||
687 | "#]], | ||
688 | ) | ||
689 | } | ||
665 | } | 690 | } |
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 66577df94..b7e116dba 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs | |||
@@ -127,6 +127,7 @@ pub(crate) struct CompletionContext<'a> { | |||
127 | 127 | ||
128 | no_completion_required: bool, | 128 | no_completion_required: bool, |
129 | } | 129 | } |
130 | |||
130 | impl<'a> CompletionContext<'a> { | 131 | impl<'a> CompletionContext<'a> { |
131 | pub(super) fn new( | 132 | pub(super) fn new( |
132 | db: &'a RootDatabase, | 133 | db: &'a RootDatabase, |
@@ -281,21 +282,25 @@ impl<'a> CompletionContext<'a> { | |||
281 | self.previous_token.as_ref().map_or(false, |tok| tok.kind() == kind) | 282 | self.previous_token.as_ref().map_or(false, |tok| tok.kind() == kind) |
282 | } | 283 | } |
283 | 284 | ||
284 | pub(crate) fn has_impl_or_trait_parent(&self) -> bool { | 285 | pub(crate) fn expects_assoc_item(&self) -> bool { |
285 | matches!( | 286 | matches!( |
286 | self.completion_location, | 287 | self.completion_location, |
287 | Some(ImmediateLocation::Trait) | Some(ImmediateLocation::Impl) | 288 | Some(ImmediateLocation::Trait) | Some(ImmediateLocation::Impl) |
288 | ) | 289 | ) |
289 | } | 290 | } |
290 | 291 | ||
291 | pub(crate) fn has_block_expr_parent(&self) -> bool { | 292 | pub(crate) fn expects_non_trait_assoc_item(&self) -> bool { |
292 | matches!(self.completion_location, Some(ImmediateLocation::BlockExpr)) | 293 | matches!(self.completion_location, Some(ImmediateLocation::Impl)) |
293 | } | 294 | } |
294 | 295 | ||
295 | pub(crate) fn has_item_list_parent(&self) -> bool { | 296 | pub(crate) fn expects_item(&self) -> bool { |
296 | matches!(self.completion_location, Some(ImmediateLocation::ItemList)) | 297 | matches!(self.completion_location, Some(ImmediateLocation::ItemList)) |
297 | } | 298 | } |
298 | 299 | ||
300 | pub(crate) fn has_block_expr_parent(&self) -> bool { | ||
301 | matches!(self.completion_location, Some(ImmediateLocation::BlockExpr)) | ||
302 | } | ||
303 | |||
299 | pub(crate) fn has_ident_or_ref_pat_parent(&self) -> bool { | 304 | pub(crate) fn has_ident_or_ref_pat_parent(&self) -> bool { |
300 | matches!( | 305 | matches!( |
301 | self.completion_location, | 306 | self.completion_location, |
@@ -303,11 +308,7 @@ impl<'a> CompletionContext<'a> { | |||
303 | ) | 308 | ) |
304 | } | 309 | } |
305 | 310 | ||
306 | pub(crate) fn has_impl_parent(&self) -> bool { | 311 | pub(crate) fn expect_record_field(&self) -> bool { |
307 | matches!(self.completion_location, Some(ImmediateLocation::Impl)) | ||
308 | } | ||
309 | |||
310 | pub(crate) fn has_field_list_parent(&self) -> bool { | ||
311 | matches!(self.completion_location, Some(ImmediateLocation::RecordFieldList)) | 312 | matches!(self.completion_location, Some(ImmediateLocation::RecordFieldList)) |
312 | } | 313 | } |
313 | 314 | ||
@@ -320,10 +321,10 @@ impl<'a> CompletionContext<'a> { | |||
320 | || self.record_pat_syntax.is_some() | 321 | || self.record_pat_syntax.is_some() |
321 | || self.attribute_under_caret.is_some() | 322 | || self.attribute_under_caret.is_some() |
322 | || self.mod_declaration_under_caret.is_some() | 323 | || self.mod_declaration_under_caret.is_some() |
323 | || self.has_impl_or_trait_parent() | ||
324 | } | 324 | } |
325 | 325 | ||
326 | fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) { | 326 | fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) { |
327 | dbg!(file_with_fake_ident); | ||
327 | let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap(); | 328 | let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap(); |
328 | let syntax_element = NodeOrToken::Token(fake_ident_token); | 329 | let syntax_element = NodeOrToken::Token(fake_ident_token); |
329 | self.previous_token = previous_token(syntax_element.clone()); | 330 | self.previous_token = previous_token(syntax_element.clone()); |
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index 04f2c532b..f7bf4d638 100644 --- a/crates/ide_completion/src/patterns.rs +++ b/crates/ide_completion/src/patterns.rs | |||
@@ -92,9 +92,15 @@ fn test_has_ref_parent() { | |||
92 | } | 92 | } |
93 | 93 | ||
94 | pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool { | 94 | pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool { |
95 | match not_same_range_ancestor(element) { | 95 | let it = element |
96 | Some(it) => it.kind() == SOURCE_FILE || it.kind() == ITEM_LIST, | 96 | .ancestors() |
97 | None => true, | 97 | .take_while(|it| it.text_range() == element.text_range()) |
98 | .last() | ||
99 | .map(|it| (it.kind(), it.parent())); | ||
100 | match it { | ||
101 | Some((_, Some(it))) => it.kind() == SOURCE_FILE || it.kind() == ITEM_LIST, | ||
102 | Some((MACRO_ITEMS, None) | (SOURCE_FILE, None)) => true, | ||
103 | _ => false, | ||
98 | } | 104 | } |
99 | } | 105 | } |
100 | #[test] | 106 | #[test] |