aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs6
-rw-r--r--crates/ide_completion/src/completions/keyword.rs27
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs12
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs27
-rw-r--r--crates/ide_completion/src/context.rs21
-rw-r--r--crates/ide_completion/src/patterns.rs12
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#"
653trait MyTrait {} 661trait 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#"
678struct MyStruct {}
679macro_rules! foo {}
680
681impl 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
130impl<'a> CompletionContext<'a> { 131impl<'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
94pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool { 94pub(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]