diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index dba46df04f..debc3ee624 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1344,6 +1344,7 @@ impl MacroDef { MacroDefKind::Declarative(_) => MacroKind::Declarative, MacroDefKind::BuiltIn(_, _) | MacroDefKind::BuiltInEager(_, _) => MacroKind::BuiltIn, MacroDefKind::BuiltInDerive(_, _) => MacroKind::Derive, + MacroDefKind::BuiltInAttr(_, _) => MacroKind::Attr, MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::CustomDerive, _) => { MacroKind::Derive } diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index d019ba3a96..93f30f23dd 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs @@ -9,6 +9,7 @@ use base_db::{CrateId, Edition, FileId, ProcMacroId}; use cfg::{CfgExpr, CfgOptions}; use hir_expand::{ ast_id_map::FileAstId, + builtin_attr::find_builtin_attr, builtin_derive::find_builtin_derive, builtin_macro::find_builtin_macro, name::{name, AsName, Name}, @@ -1836,7 +1837,8 @@ impl ModCollector<'_, '_> { let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into()); if attrs.by_key("rustc_builtin_macro").exists() { let macro_id = find_builtin_macro(&mac.name, krate, ast_id) - .or_else(|| find_builtin_derive(&mac.name, krate, ast_id)); + .or_else(|| find_builtin_derive(&mac.name, krate, ast_id)) + .or_else(|| find_builtin_attr(&mac.name, krate, ast_id)); match macro_id { Some(macro_id) => { diff --git a/crates/hir_expand/src/builtin_attr.rs b/crates/hir_expand/src/builtin_attr.rs new file mode 100644 index 0000000000..3024410fb1 --- /dev/null +++ b/crates/hir_expand/src/builtin_attr.rs @@ -0,0 +1,115 @@ +//! Builtin derives. + +use syntax::ast; + +use crate::{db::AstDatabase, name, AstId, CrateId, MacroCallId, MacroDefId, MacroDefKind}; + +macro_rules! register_builtin { + ( $(($name:ident, $variant:ident) => $expand:ident),* ) => { + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub enum BuiltinAttrExpander { + $($variant),* + } + + impl BuiltinAttrExpander { + pub fn expand( + &self, + db: &dyn AstDatabase, + id: MacroCallId, + tt: &tt::Subtree, + ) -> Result { + let expander = match *self { + $( BuiltinAttrExpander::$variant => $expand, )* + }; + expander(db, id, tt) + } + + fn find_by_name(name: &name::Name) -> Option { + match name { + $( id if id == &name::name![$name] => Some(BuiltinAttrExpander::$variant), )* + _ => None, + } + } + } + + }; +} + +register_builtin! { + (bench, Bench) => bench_expand, + (cfg_accessible, CfgAccessible) => cfg_accessible_expand, + (cfg_eval, CfgEval) => cfg_eval_expand, + (derive, Derive) => derive_expand, + (global_allocator, GlobalAllocator) => global_allocator_expand, + (test, Test) => test_expand, + (test_case, TestCase) => test_case_expand +} + +pub fn find_builtin_attr( + ident: &name::Name, + krate: CrateId, + ast_id: AstId, +) -> Option { + let expander = BuiltinAttrExpander::find_by_name(ident)?; + Some(MacroDefId { + krate, + kind: MacroDefKind::BuiltInAttr(expander, ast_id), + local_inner: false, + }) +} + +fn bench_expand( + _db: &dyn AstDatabase, + _id: MacroCallId, + tt: &tt::Subtree, +) -> Result { + Ok(tt.clone()) +} + +fn cfg_accessible_expand( + _db: &dyn AstDatabase, + _id: MacroCallId, + tt: &tt::Subtree, +) -> Result { + Ok(tt.clone()) +} + +fn cfg_eval_expand( + _db: &dyn AstDatabase, + _id: MacroCallId, + tt: &tt::Subtree, +) -> Result { + Ok(tt.clone()) +} + +fn derive_expand( + _db: &dyn AstDatabase, + _id: MacroCallId, + tt: &tt::Subtree, +) -> Result { + Ok(tt.clone()) +} + +fn global_allocator_expand( + _db: &dyn AstDatabase, + _id: MacroCallId, + tt: &tt::Subtree, +) -> Result { + Ok(tt.clone()) +} + +fn test_expand( + _db: &dyn AstDatabase, + _id: MacroCallId, + tt: &tt::Subtree, +) -> Result { + Ok(tt.clone()) +} + +fn test_case_expand( + _db: &dyn AstDatabase, + _id: MacroCallId, + tt: &tt::Subtree, +) -> Result { + Ok(tt.clone()) +} diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 18a05579f4..45e6e446af 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs @@ -12,9 +12,9 @@ use syntax::{ }; use crate::{ - ast_id_map::AstIdMap, hygiene::HygieneFrame, input::process_macro_input, BuiltinDeriveExpander, - BuiltinFnLikeExpander, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, MacroCallLoc, - MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander, + ast_id_map::AstIdMap, hygiene::HygieneFrame, input::process_macro_input, BuiltinAttrExpander, + BuiltinDeriveExpander, BuiltinFnLikeExpander, HirFileId, HirFileIdRepr, MacroCallId, + MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander, }; /// Total limit on the number of tokens produced by any macro invocation. @@ -31,6 +31,8 @@ pub enum TokenExpander { MacroDef { mac: mbe::MacroDef, def_site_token_map: mbe::TokenMap }, /// Stuff like `line!` and `file!`. Builtin(BuiltinFnLikeExpander), + /// `global_allocator` and such. + BuiltinAttr(BuiltinAttrExpander), /// `derive(Copy)` and such. BuiltinDerive(BuiltinDeriveExpander), /// The thing we love the most here in rust-analyzer -- procedural macros. @@ -49,6 +51,7 @@ impl TokenExpander { TokenExpander::MacroDef { mac, .. } => mac.expand(tt), TokenExpander::Builtin(it) => it.expand(db, id, tt), // FIXME switch these to ExpandResult as well + TokenExpander::BuiltinAttr(it) => it.expand(db, id, tt).into(), TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(), TokenExpander::ProcMacro(_) => { // We store the result in salsa db to prevent non-deterministic behavior in @@ -64,6 +67,7 @@ impl TokenExpander { TokenExpander::MacroRules { mac, .. } => mac.map_id_down(id), TokenExpander::MacroDef { mac, .. } => mac.map_id_down(id), TokenExpander::Builtin(..) + | TokenExpander::BuiltinAttr(..) | TokenExpander::BuiltinDerive(..) | TokenExpander::ProcMacro(..) => id, } @@ -74,6 +78,7 @@ impl TokenExpander { TokenExpander::MacroRules { mac, .. } => mac.map_id_up(id), TokenExpander::MacroDef { mac, .. } => mac.map_id_up(id), TokenExpander::Builtin(..) + | TokenExpander::BuiltinAttr(..) | TokenExpander::BuiltinDerive(..) | TokenExpander::ProcMacro(..) => (id, mbe::Origin::Call), } @@ -299,6 +304,9 @@ fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option> } }, MacroDefKind::BuiltIn(expander, _) => Some(Arc::new(TokenExpander::Builtin(expander))), + MacroDefKind::BuiltInAttr(expander, _) => { + Some(Arc::new(TokenExpander::BuiltinAttr(expander))) + } MacroDefKind::BuiltInDerive(expander, _) => { Some(Arc::new(TokenExpander::BuiltinDerive(expander))) } diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs index 14af628a1f..9093255f4c 100644 --- a/crates/hir_expand/src/eager.rs +++ b/crates/hir_expand/src/eager.rs @@ -224,6 +224,7 @@ fn eager_macro_recur( } MacroDefKind::Declarative(_) | MacroDefKind::BuiltIn(..) + | MacroDefKind::BuiltInAttr(..) | MacroDefKind::BuiltInDerive(..) | MacroDefKind::ProcMacro(..) => { let res = lazy_expand(db, &def, curr.with_value(child.clone()), krate); diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs index d98913907a..05c6c3fb16 100644 --- a/crates/hir_expand/src/hygiene.rs +++ b/crates/hir_expand/src/hygiene.rs @@ -192,6 +192,7 @@ impl HygieneFrame { (info, Some(loc.def.krate), loc.def.local_inner) } MacroDefKind::BuiltIn(..) => (info, Some(loc.def.krate), false), + MacroDefKind::BuiltInAttr(..) => (info, None, false), MacroDefKind::BuiltInDerive(..) => (info, None, false), MacroDefKind::BuiltInEager(..) => (info, None, false), MacroDefKind::ProcMacro(..) => (info, None, false), diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index 618f26b954..623791b582 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs @@ -8,6 +8,7 @@ pub mod db; pub mod ast_id_map; pub mod name; pub mod hygiene; +pub mod builtin_attr; pub mod builtin_derive; pub mod builtin_macro; pub mod proc_macro; @@ -32,6 +33,7 @@ use syntax::{ }; use crate::ast_id_map::FileAstId; +use crate::builtin_attr::BuiltinAttrExpander; use crate::builtin_derive::BuiltinDeriveExpander; use crate::builtin_macro::{BuiltinFnLikeExpander, EagerExpander}; use crate::proc_macro::ProcMacroExpander; @@ -206,6 +208,7 @@ impl MacroDefId { let id = match &self.kind { MacroDefKind::Declarative(id) => id, MacroDefKind::BuiltIn(_, id) => id, + MacroDefKind::BuiltInAttr(_, id) => id, MacroDefKind::BuiltInDerive(_, id) => id, MacroDefKind::BuiltInEager(_, id) => id, MacroDefKind::ProcMacro(.., id) => return Either::Right(*id), @@ -223,6 +226,7 @@ pub enum MacroDefKind { Declarative(AstId), BuiltIn(BuiltinFnLikeExpander, AstId), // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander + BuiltInAttr(BuiltinAttrExpander, AstId), BuiltInDerive(BuiltinDeriveExpander, AstId), BuiltInEager(EagerExpander, AstId), ProcMacro(ProcMacroExpander, ProcMacroKind, AstId), diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs index 00b8adc1eb..376fe130f1 100644 --- a/crates/hir_expand/src/name.rs +++ b/crates/hir_expand/src/name.rs @@ -160,7 +160,6 @@ pub mod known { str, // Special names macro_rules, - derive, doc, cfg, cfg_attr, @@ -240,6 +239,14 @@ pub mod known { PartialOrd, Eq, PartialEq, + // Builtin attributes + bench, + cfg_accessible, + cfg_eval, + derive, + global_allocator, + test, + test_case, // Safe intrinsics abort, size_of, diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index 0b0a81410b..58d4dd9ee8 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs @@ -656,6 +656,32 @@ fn main() { let _ = crate::$0 } ); } + #[test] + fn does_not_complete_non_fn_macros() { + check( + r#" +mod m { + #[rustc_builtin_macro] + pub macro Clone {} +} + +fn f() {m::$0} +"#, + expect![[r#""#]], + ); + check( + r#" +mod m { + #[rustc_builtin_macro] + pub macro bench {} +} + +fn f() {m::$0} +"#, + expect![[r#""#]], + ); + } + #[test] fn completes_in_assoc_item_list() { check( diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 1f6c4069f0..b1e6b2b775 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs @@ -481,14 +481,14 @@ impl S { ); check( r#" -mod m { - #[rustc_builtin_macro] - pub macro Clone {} -} +#[rustc_builtin_macro] +pub macro bench {} -fn f() {m::$0} +fn f() {$0} "#, - expect![[r#""#]], + expect![[r#" + fn f() fn() + "#]], ); }