diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index c2b68a85301..b5209546c76 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1351,6 +1351,13 @@ impl MacroDef { MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::FuncLike, _) => MacroKind::ProcMacro, } } + + pub fn is_fn_like(&self) -> bool { + match self.kind() { + MacroKind::Declarative | MacroKind::BuiltIn | MacroKind::ProcMacro => true, + MacroKind::Attr | MacroKind::Derive => false, + } + } } /// Invariant: `inner.as_assoc_item(db).is_some()` diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs index 8a728c67eff..1daa8595a6a 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) { | hir::ModuleDef::Module(..) => refutable, _ => false, }, - hir::ScopeDef::MacroDef(_) => true, + hir::ScopeDef::MacroDef(mac) => mac.is_fn_like(), hir::ScopeDef::ImplSelfType(impl_) => match impl_.self_ty(ctx.db).as_adt() { Some(hir::Adt::Struct(strukt)) => { acc.add_struct_pat(ctx, strukt, Some(name.clone())); @@ -101,6 +101,28 @@ fn foo() { ); } + #[test] + fn does_not_complete_non_fn_macros() { + check( + r#" +macro_rules! m { ($e:expr) => { $e } } +enum E { X } + +#[rustc_builtin_macro] +macro Clone {} + +fn foo() { + match E::X { $0 } +} +"#, + expect![[r#" + ev E::X () + en E + ma m!(…) macro_rules! m + "#]], + ); + } + #[test] fn completes_in_simple_macro_call() { check( diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index d58745fb4da..4dfdc5ced4a 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs @@ -26,7 +26,9 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon let module_scope = module.scope(ctx.db, context_module); for (name, def) in module_scope { if let hir::ScopeDef::MacroDef(macro_def) = def { - acc.add_macro(ctx, Some(name.clone()), macro_def); + if macro_def.is_fn_like() { + acc.add_macro(ctx, Some(name.clone()), macro_def); + } } if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def { acc.add_resolution(ctx, name, &def); @@ -58,6 +60,13 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon } } + if let hir::ScopeDef::MacroDef(macro_def) = def { + if !macro_def.is_fn_like() { + // Don't suggest attribute macros and derives. + continue; + } + } + acc.add_resolution(ctx, name, &def); } } diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 8b22933e0a2..52f40d49618 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs @@ -13,7 +13,9 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC // only show macros in {Assoc}ItemList ctx.scope.process_all_names(&mut |name, res| { if let hir::ScopeDef::MacroDef(mac) = res { - acc.add_macro(ctx, Some(name.clone()), mac); + if mac.is_fn_like() { + acc.add_macro(ctx, Some(name.clone()), mac); + } } if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { acc.add_resolution(ctx, name, &res); @@ -46,7 +48,13 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC cov_mark::hit!(skip_lifetime_completion); return; } - acc.add_resolution(ctx, name, &res); + let add_resolution = match res { + ScopeDef::MacroDef(mac) => mac.is_fn_like(), + _ => true, + }; + if add_resolution { + acc.add_resolution(ctx, name, &res); + } }); } @@ -426,6 +434,44 @@ mod macros { ); } + #[test] + fn does_not_complete_non_fn_macros() { + check( + r#" +#[rustc_builtin_macro] +pub macro Clone {} + +fn f() {$0} +"#, + expect![[r#" + fn f() fn() + "#]], + ); + check( + r#" +#[rustc_builtin_macro] +pub macro Clone {} + +struct S; +impl S { + $0 +} +"#, + expect![[r#""#]], + ); + check( + r#" +mod m { + #[rustc_builtin_macro] + pub macro Clone {} +} + +fn f() {m::$0} +"#, + expect![[r#""#]], + ); + } + #[test] fn completes_std_prelude_if_core_is_defined() { check(