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
}
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},
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) => {
--- /dev/null
+//! 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<tt::Subtree, mbe::ExpandError> {
+ let expander = match *self {
+ $( BuiltinAttrExpander::$variant => $expand, )*
+ };
+ expander(db, id, tt)
+ }
+
+ fn find_by_name(name: &name::Name) -> Option<Self> {
+ match name {
+ $( id if id == &name::name![$name] => Some(BuiltinAttrExpander::$variant), )*
+ _ => None,
+ }
+ }
+ }
+
+ };
+}
+
+register_builtin! {
+ (bench, Bench) => dummy_attr_expand,
+ (cfg_accessible, CfgAccessible) => dummy_attr_expand,
+ (cfg_eval, CfgEval) => dummy_attr_expand,
+ (derive, Derive) => dummy_attr_expand,
+ (global_allocator, GlobalAllocator) => dummy_attr_expand,
+ (test, Test) => dummy_attr_expand,
+ (test_case, TestCase) => dummy_attr_expand
+}
+
+pub fn find_builtin_attr(
+ ident: &name::Name,
+ krate: CrateId,
+ ast_id: AstId<ast::Macro>,
+) -> Option<MacroDefId> {
+ let expander = BuiltinAttrExpander::find_by_name(ident)?;
+ Some(MacroDefId {
+ krate,
+ kind: MacroDefKind::BuiltInAttr(expander, ast_id),
+ local_inner: false,
+ })
+}
+
+fn dummy_attr_expand(
+ _db: &dyn AstDatabase,
+ _id: MacroCallId,
+ tt: &tt::Subtree,
+) -> Result<tt::Subtree, mbe::ExpandError> {
+ Ok(tt.clone())
+}
};
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.
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.
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
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,
}
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),
}
}
},
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)))
}
}
MacroDefKind::Declarative(_)
| MacroDefKind::BuiltIn(..)
+ | MacroDefKind::BuiltInAttr(..)
| MacroDefKind::BuiltInDerive(..)
| MacroDefKind::ProcMacro(..) => {
let res = lazy_expand(db, &def, curr.with_value(child.clone()), krate);
(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),
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;
};
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;
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),
Declarative(AstId<ast::Macro>),
BuiltIn(BuiltinFnLikeExpander, AstId<ast::Macro>),
// FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander
+ BuiltInAttr(BuiltinAttrExpander, AstId<ast::Macro>),
BuiltInDerive(BuiltinDeriveExpander, AstId<ast::Macro>),
BuiltInEager(EagerExpander, AstId<ast::Macro>),
ProcMacro(ProcMacroExpander, ProcMacroKind, AstId<ast::Fn>),
str,
// Special names
macro_rules,
- derive,
doc,
cfg,
cfg_attr,
PartialOrd,
Eq,
PartialEq,
+ // Builtin attributes
+ bench,
+ cfg_accessible,
+ cfg_eval,
+ derive,
+ global_allocator,
+ test,
+ test_case,
// Safe intrinsics
abort,
size_of,
);
}
+ #[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(
);
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()
+ "#]],
);
}