aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src/completions
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion/src/completions')
-rw-r--r--crates/ide_completion/src/completions/keyword.rs20
-rw-r--r--crates/ide_completion/src/completions/macro_in_item_position.rs48
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs11
-rw-r--r--crates/ide_completion/src/completions/snippet.rs14
-rw-r--r--crates/ide_completion/src/completions/trait_impl.rs18
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs22
6 files changed, 43 insertions, 90 deletions
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs
index 0ca97a0e4..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;
5use syntax::{SyntaxKind, T}; 5use syntax::{SyntaxKind, T};
6 6
7use crate::{ 7use 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
12pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) { 12pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) {
@@ -128,8 +128,15 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
128 add_keyword("mut", "mut "); 128 add_keyword("mut", "mut ");
129 } 129 }
130 130
131 if ctx.in_loop_body { 131 let (can_be_stmt, in_loop_body) = match ctx.path_context {
132 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 {
133 add_keyword("continue", "continue;"); 140 add_keyword("continue", "continue;");
134 add_keyword("break", "break;"); 141 add_keyword("break", "break;");
135 } else { 142 } else {
@@ -138,9 +145,6 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
138 } 145 }
139 } 146 }
140 147
141 if !ctx.is_trivial_path() {
142 return;
143 }
144 let fn_def = match &ctx.function_def { 148 let fn_def = match &ctx.function_def {
145 Some(it) => it, 149 Some(it) => it,
146 None => return, 150 None => return,
@@ -148,7 +152,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
148 152
149 add_keyword( 153 add_keyword(
150 "return", 154 "return",
151 match (ctx.can_be_stmt(), fn_def.ret_type().is_some()) { 155 match (can_be_stmt, fn_def.ret_type().is_some()) {
152 (true, true) => "return $0;", 156 (true, true) => "return $0;",
153 (true, false) => "return;", 157 (true, false) => "return;",
154 (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
3use crate::{CompletionContext, Completions};
4
5// Ideally this should be removed and moved into `(un)qualified_path` respectively
6pub(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)]
24mod 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#"
38macro_rules! foo { () => {} }
39fn 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/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index c072de7b5..d58745fb4 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -7,7 +7,7 @@ use syntax::AstNode;
7use crate::{CompletionContext, Completions}; 7use crate::{CompletionContext, Completions};
8 8
9pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) { 9pub(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() {
@@ -20,7 +20,8 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
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 {
@@ -631,17 +632,17 @@ impl MyStruct {
631"#, 632"#,
632 expect![[r##" 633 expect![[r##"
633 md bar 634 md bar
634 ma foo! #[macro_export] macro_rules! foo 635 ma foo!(…) #[macro_export] macro_rules! foo
635 "##]], 636 "##]],
636 ); 637 );
637 } 638 }
638 639
639 #[test] 640 #[test]
640 #[ignore] // FIXME doesn't complete anything atm
641 fn completes_in_item_list() { 641 fn completes_in_item_list() {
642 check( 642 check(
643 r#" 643 r#"
644struct MyStruct {} 644struct MyStruct {}
645#[macro_export]
645macro_rules! foo {} 646macro_rules! foo {}
646mod bar {} 647mod bar {}
647 648
@@ -649,7 +650,7 @@ crate::$0
649"#, 650"#,
650 expect![[r#" 651 expect![[r#"
651 md bar 652 md bar
652 ma foo! macro_rules! foo 653 ma foo!(…) #[macro_export] macro_rules! foo
653 "#]], 654 "#]],
654 ) 655 )
655 } 656 }
diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs
index 59a338e7b..b9862de67 100644
--- a/crates/ide_completion/src/completions/snippet.rs
+++ b/crates/ide_completion/src/completions/snippet.rs
@@ -3,8 +3,8 @@
3use ide_db::helpers::SnippetCap; 3use ide_db::helpers::SnippetCap;
4 4
5use crate::{ 5use 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
10fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder { 10fn 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
16pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionContext) { 16pub(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 @@
34use hir::{self, HasAttrs, HasSource}; 34use hir::{self, HasAttrs, HasSource};
35use ide_db::{traits::get_missing_assoc_items, SymbolKind}; 35use ide_db::{traits::get_missing_assoc_items, SymbolKind};
36use syntax::{ 36use 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};
41use text_edit::TextEdit; 41use text_edit::TextEdit;
42 42
43use crate::{ 43use 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)]
53enum ImplCompletionKind { 46enum ImplCompletionKind {
@@ -58,7 +51,7 @@ enum ImplCompletionKind {
58} 51}
59 52
60pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { 53pub(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
83fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, SyntaxNode, Impl)> { 76fn 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 f321ed52b..8b22933e0 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -5,26 +5,25 @@ use hir::ScopeDef;
5use crate::{CompletionContext, Completions}; 5use crate::{CompletionContext, Completions};
6 6
7pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 7pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
8 if !ctx.is_trivial_path() { 8 if ctx.is_path_disallowed() || !ctx.is_trivial_path() {
9 return;
10 }
11 if ctx.is_path_disallowed() || ctx.expects_item() {
12 return; 9 return;
13 } 10 }
14 11
15 if ctx.expects_assoc_item() { 12 if ctx.expects_item() || ctx.expects_assoc_item() {
16 ctx.scope.process_all_names(&mut |name, def| { 13 // only show macros in {Assoc}ItemList
17 if let ScopeDef::MacroDef(macro_def) = def { 14 ctx.scope.process_all_names(&mut |name, res| {
18 acc.add_macro(ctx, Some(name.clone()), macro_def); 15 if let hir::ScopeDef::MacroDef(mac) = res {
16 acc.add_macro(ctx, Some(name.clone()), mac);
19 } 17 }
20 if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def { 18 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
21 acc.add_resolution(ctx, name, &def); 19 acc.add_resolution(ctx, name, &res);
22 } 20 }
23 }); 21 });
24 return; 22 return;
25 } 23 }
26 24
27 if ctx.expects_use_tree() { 25 if ctx.expects_use_tree() {
26 // only show modules in a fresh UseTree
28 cov_mark::hit!(only_completes_modules_in_import); 27 cov_mark::hit!(only_completes_modules_in_import);
29 ctx.scope.process_all_names(&mut |name, res| { 28 ctx.scope.process_all_names(&mut |name, res| {
30 if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { 29 if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
@@ -693,12 +692,11 @@ impl MyStruct {
693"#, 692"#,
694 expect![[r#" 693 expect![[r#"
695 md bar 694 md bar
696 ma foo! macro_rules! foo 695 ma foo!(…) macro_rules! foo
697 "#]], 696 "#]],
698 ) 697 )
699 } 698 }
700 699
701 // FIXME: The completions here currently come from `macro_in_item_position`, but they shouldn't
702 #[test] 700 #[test]
703 fn completes_in_item_list() { 701 fn completes_in_item_list() {
704 check( 702 check(