diff --git a/crates/ra_ide/src/completion/complete_pattern.rs b/crates/ra_ide/src/completion/complete_pattern.rs index cb84bb9348..bc8fade6f3 100644 --- a/crates/ra_ide/src/completion/complete_pattern.rs +++ b/crates/ra_ide/src/completion/complete_pattern.rs @@ -55,6 +55,20 @@ mod tests { ); assert_debug_snapshot!(completions, @r###" [ + CompletionItem { + label: "Bar", + source_range: [246; 246), + delete: [246; 246), + insert: "Bar", + kind: Struct, + }, + CompletionItem { + label: "E", + source_range: [246; 246), + delete: [246; 246), + insert: "E", + kind: Enum, + }, CompletionItem { label: "E", source_range: [246; 246), @@ -69,6 +83,13 @@ mod tests { insert: "X", kind: EnumVariant, }, + CompletionItem { + label: "X", + source_range: [246; 246), + delete: [246; 246), + insert: "X", + kind: EnumVariant, + }, CompletionItem { label: "Z", source_range: [246; 246), @@ -76,6 +97,20 @@ mod tests { insert: "Z", kind: Const, }, + CompletionItem { + label: "Z", + source_range: [246; 246), + delete: [246; 246), + insert: "Z", + kind: Const, + }, + CompletionItem { + label: "m", + source_range: [246; 246), + delete: [246; 246), + insert: "m", + kind: Module, + }, CompletionItem { label: "m", source_range: [246; 246), @@ -110,6 +145,21 @@ mod tests { insert: "E", kind: Enum, }, + CompletionItem { + label: "E", + source_range: [151; 151), + delete: [151; 151), + insert: "E", + kind: Enum, + }, + CompletionItem { + label: "m!", + source_range: [151; 151), + delete: [151; 151), + insert: "m!($0)", + kind: Macro, + detail: "macro_rules! m", + }, ] "###); } diff --git a/crates/ra_ide/src/completion/complete_scope.rs b/crates/ra_ide/src/completion/complete_scope.rs index 81d3cc1b66..2ca5527331 100644 --- a/crates/ra_ide/src/completion/complete_scope.rs +++ b/crates/ra_ide/src/completion/complete_scope.rs @@ -1,13 +1,19 @@ //! Completion of names from the current scope, e.g. locals and imported items. use crate::completion::{CompletionContext, Completions}; +use hir::{ModuleDef, ScopeDef}; pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { - if !ctx.is_trivial_path { + if !ctx.is_trivial_path && !ctx.is_pat_binding_and_path { return; } - ctx.scope().process_all_names(&mut |name, res| acc.add_resolution(ctx, name.to_string(), &res)); + ctx.scope().process_all_names(&mut |name, res| match (ctx.is_pat_binding_and_path, &res) { + (true, ScopeDef::ModuleDef(ModuleDef::Function(..))) => (), + (true, ScopeDef::ModuleDef(ModuleDef::Static(..))) => (), + (true, ScopeDef::Local(..)) => (), + _ => acc.add_resolution(ctx, name.to_string(), &res), + }); } #[cfg(test)] @@ -20,6 +26,79 @@ mod tests { do_completion(ra_fixture, CompletionKind::Reference) } + #[test] + fn bind_pat_and_path_ignore_at() { + assert_debug_snapshot!( + do_reference_completion( + r" + enum Enum { + A, + B, + } + fn quux(x: Option) { + match x { + None => (), + Some(en<|> @ Enum::A) => (), + } + } + " + ), + @r###"[]"### + ); + } + + #[test] + fn bind_pat_and_path_ignore_ref() { + assert_debug_snapshot!( + do_reference_completion( + r" + enum Enum { + A, + B, + } + fn quux(x: Option) { + match x { + None => (), + Some(ref en<|>) => (), + } + } + " + ), + @r###"[]"### + ); + } + + #[test] + fn bind_pat_and_path() { + assert_debug_snapshot!( + do_reference_completion( + r" + enum Enum { + A, + B, + } + fn quux(x: Option) { + match x { + None => (), + Some(En<|>) => (), + } + } + " + ), + @r###" + [ + CompletionItem { + label: "Enum", + source_range: [231; 233), + delete: [231; 233), + insert: "Enum", + kind: Enum, + }, + ] + "### + ); + } + #[test] fn completes_bindings_from_let() { assert_debug_snapshot!( diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index 54589a2a83..319e33b615 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs @@ -36,6 +36,9 @@ pub(crate) struct CompletionContext<'a> { /// If a name-binding or reference to a const in a pattern. /// Irrefutable patterns (like let) are excluded. pub(super) is_pat_binding: bool, + // A bind battern which may also be part of a path. + // if let Some(En<|>) = Some(Enum::A) + pub(super) is_pat_binding_and_path: bool, /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. pub(super) is_trivial_path: bool, /// If not a trivial path, the prefix (qualifier). @@ -95,6 +98,7 @@ impl<'a> CompletionContext<'a> { impl_def: None, is_param: false, is_pat_binding: false, + is_pat_binding_and_path: false, is_trivial_path: false, path_prefix: None, after_if: false, @@ -188,10 +192,17 @@ impl<'a> CompletionContext<'a> { if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) { let parent = bind_pat.syntax().parent(); if parent.clone().and_then(ast::MatchArm::cast).is_some() - || parent.and_then(ast::Condition::cast).is_some() + || parent.clone().and_then(ast::Condition::cast).is_some() { self.is_pat_binding = true; } + + if parent.and_then(ast::RecordFieldPatList::cast).is_none() + && bind_pat.pat().is_none() + && !bind_pat.is_ref() + { + self.is_pat_binding_and_path = true; + } } if is_node::(name.syntax()) { self.is_param = true;