mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 04:23:25 +00:00
Implement dummy expansions for builtin attributes
This commit is contained in:
parent
5f592f4f58
commit
ae8d74ab2c
10 changed files with 176 additions and 11 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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) => {
|
||||
|
|
115
crates/hir_expand/src/builtin_attr.rs
Normal file
115
crates/hir_expand/src/builtin_attr.rs
Normal file
|
@ -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<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) => 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<ast::Macro>,
|
||||
) -> Option<MacroDefId> {
|
||||
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<tt::Subtree, mbe::ExpandError> {
|
||||
Ok(tt.clone())
|
||||
}
|
||||
|
||||
fn cfg_accessible_expand(
|
||||
_db: &dyn AstDatabase,
|
||||
_id: MacroCallId,
|
||||
tt: &tt::Subtree,
|
||||
) -> Result<tt::Subtree, mbe::ExpandError> {
|
||||
Ok(tt.clone())
|
||||
}
|
||||
|
||||
fn cfg_eval_expand(
|
||||
_db: &dyn AstDatabase,
|
||||
_id: MacroCallId,
|
||||
tt: &tt::Subtree,
|
||||
) -> Result<tt::Subtree, mbe::ExpandError> {
|
||||
Ok(tt.clone())
|
||||
}
|
||||
|
||||
fn derive_expand(
|
||||
_db: &dyn AstDatabase,
|
||||
_id: MacroCallId,
|
||||
tt: &tt::Subtree,
|
||||
) -> Result<tt::Subtree, mbe::ExpandError> {
|
||||
Ok(tt.clone())
|
||||
}
|
||||
|
||||
fn global_allocator_expand(
|
||||
_db: &dyn AstDatabase,
|
||||
_id: MacroCallId,
|
||||
tt: &tt::Subtree,
|
||||
) -> Result<tt::Subtree, mbe::ExpandError> {
|
||||
Ok(tt.clone())
|
||||
}
|
||||
|
||||
fn test_expand(
|
||||
_db: &dyn AstDatabase,
|
||||
_id: MacroCallId,
|
||||
tt: &tt::Subtree,
|
||||
) -> Result<tt::Subtree, mbe::ExpandError> {
|
||||
Ok(tt.clone())
|
||||
}
|
||||
|
||||
fn test_case_expand(
|
||||
_db: &dyn AstDatabase,
|
||||
_id: MacroCallId,
|
||||
tt: &tt::Subtree,
|
||||
) -> Result<tt::Subtree, mbe::ExpandError> {
|
||||
Ok(tt.clone())
|
||||
}
|
|
@ -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<Arc<TokenExpander>>
|
|||
}
|
||||
},
|
||||
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)))
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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<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>),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -481,14 +481,14 @@ impl S {
|
|||
);
|
||||
check(
|
||||
r#"
|
||||
mod m {
|
||||
#[rustc_builtin_macro]
|
||||
pub macro Clone {}
|
||||
}
|
||||
pub macro bench {}
|
||||
|
||||
fn f() {m::$0}
|
||||
fn f() {$0}
|
||||
"#,
|
||||
expect![[r#""#]],
|
||||
expect![[r#"
|
||||
fn f() fn()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue