mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Merge #6897
6897: Basic support for macros 2.0 r=jonas-schievink a=jonas-schievink This adds support for (built-in-only) macros 2.0, and removes some hacks used for builtin derives, which are declared via macros 2.0 in libcore. First steps for https://github.com/rust-analyzer/rust-analyzer/issues/2248. Blocked on https://github.com/rust-analyzer/ungrammar/pull/16. Co-authored-by: Jonas Schievink <jonasschievink@gmail.com> Co-authored-by: Jonas Schievink <jonas.schievink@ferrous-systems.com>
This commit is contained in:
commit
63bbdb31e5
23 changed files with 286 additions and 68 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -1827,9 +1827,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ungrammar"
|
name = "ungrammar"
|
||||||
version = "1.2.2"
|
version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "873186a460627379e7e28880a0d33b729c205634f6f021321f50b323235e62d7"
|
checksum = "7311ee93faac43aa9da26b043eb244092a29a3078c79af9396f63f800cc3a59a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicase"
|
name = "unicase"
|
||||||
|
|
|
@ -970,7 +970,7 @@ impl MacroDef {
|
||||||
/// defines this macro. The reasons for this is that macros are expanded
|
/// defines this macro. The reasons for this is that macros are expanded
|
||||||
/// early, in `hir_expand`, where modules simply do not exist yet.
|
/// early, in `hir_expand`, where modules simply do not exist yet.
|
||||||
pub fn module(self, db: &dyn HirDatabase) -> Option<Module> {
|
pub fn module(self, db: &dyn HirDatabase) -> Option<Module> {
|
||||||
let krate = self.id.krate?;
|
let krate = self.id.krate;
|
||||||
let module_id = db.crate_def_map(krate).root;
|
let module_id = db.crate_def_map(krate).root;
|
||||||
Some(Module::new(Crate { id: krate }, module_id))
|
Some(Module::new(Crate { id: krate }, module_id))
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,8 +110,8 @@ impl HasSource for TypeAlias {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl HasSource for MacroDef {
|
impl HasSource for MacroDef {
|
||||||
type Ast = ast::MacroRules;
|
type Ast = ast::Macro;
|
||||||
fn source(self, db: &dyn HirDatabase) -> InFile<ast::MacroRules> {
|
fn source(self, db: &dyn HirDatabase) -> InFile<ast::Macro> {
|
||||||
InFile {
|
InFile {
|
||||||
file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id,
|
file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id,
|
||||||
value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db.upcast()),
|
value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db.upcast()),
|
||||||
|
|
|
@ -157,8 +157,8 @@ impl SourceToDefCtx<'_, '_> {
|
||||||
let file_id = src.file_id.original_file(self.db.upcast());
|
let file_id = src.file_id.original_file(self.db.upcast());
|
||||||
let krate = self.file_to_def(file_id)?.krate;
|
let krate = self.file_to_def(file_id)?.krate;
|
||||||
let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value);
|
let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value);
|
||||||
let ast_id = Some(AstId::new(src.file_id, file_ast_id));
|
let ast_id = Some(AstId::new(src.file_id, file_ast_id.upcast()));
|
||||||
Some(MacroDefId { krate: Some(krate), ast_id, kind, local_inner: false })
|
Some(MacroDefId { krate, ast_id, kind, local_inner: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> {
|
pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> {
|
||||||
|
|
|
@ -772,7 +772,10 @@ impl ExprCollector<'_> {
|
||||||
| ast::Item::Module(_)
|
| ast::Item::Module(_)
|
||||||
| ast::Item::MacroCall(_) => return None,
|
| ast::Item::MacroCall(_) => return None,
|
||||||
ast::Item::MacroRules(def) => {
|
ast::Item::MacroRules(def) => {
|
||||||
return Some(Either::Right(def));
|
return Some(Either::Right(ast::Macro::from(def)));
|
||||||
|
}
|
||||||
|
ast::Item::MacroDef(def) => {
|
||||||
|
return Some(Either::Right(ast::Macro::from(def)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -800,7 +803,7 @@ impl ExprCollector<'_> {
|
||||||
}
|
}
|
||||||
Either::Right(e) => {
|
Either::Right(e) => {
|
||||||
let mac = MacroDefId {
|
let mac = MacroDefId {
|
||||||
krate: Some(self.expander.module.krate),
|
krate: self.expander.module.krate,
|
||||||
ast_id: Some(self.expander.ast_id(&e)),
|
ast_id: Some(self.expander.ast_id(&e)),
|
||||||
kind: MacroDefKind::Declarative,
|
kind: MacroDefKind::Declarative,
|
||||||
local_inner: false,
|
local_inner: false,
|
||||||
|
|
|
@ -363,7 +363,7 @@ impl ItemInNs {
|
||||||
ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db).krate,
|
ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db).krate,
|
||||||
ModuleDefId::BuiltinType(_) => return None,
|
ModuleDefId::BuiltinType(_) => return None,
|
||||||
},
|
},
|
||||||
ItemInNs::Macros(id) => return id.krate,
|
ItemInNs::Macros(id) => return Some(id.krate),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,6 +143,7 @@ impl ItemTree {
|
||||||
mods,
|
mods,
|
||||||
macro_calls,
|
macro_calls,
|
||||||
macro_rules,
|
macro_rules,
|
||||||
|
macro_defs,
|
||||||
exprs,
|
exprs,
|
||||||
vis,
|
vis,
|
||||||
generics,
|
generics,
|
||||||
|
@ -164,6 +165,7 @@ impl ItemTree {
|
||||||
mods.shrink_to_fit();
|
mods.shrink_to_fit();
|
||||||
macro_calls.shrink_to_fit();
|
macro_calls.shrink_to_fit();
|
||||||
macro_rules.shrink_to_fit();
|
macro_rules.shrink_to_fit();
|
||||||
|
macro_defs.shrink_to_fit();
|
||||||
exprs.shrink_to_fit();
|
exprs.shrink_to_fit();
|
||||||
|
|
||||||
vis.arena.shrink_to_fit();
|
vis.arena.shrink_to_fit();
|
||||||
|
@ -283,6 +285,7 @@ struct ItemTreeData {
|
||||||
mods: Arena<Mod>,
|
mods: Arena<Mod>,
|
||||||
macro_calls: Arena<MacroCall>,
|
macro_calls: Arena<MacroCall>,
|
||||||
macro_rules: Arena<MacroRules>,
|
macro_rules: Arena<MacroRules>,
|
||||||
|
macro_defs: Arena<MacroDef>,
|
||||||
exprs: Arena<Expr>,
|
exprs: Arena<Expr>,
|
||||||
|
|
||||||
vis: ItemVisibilities,
|
vis: ItemVisibilities,
|
||||||
|
@ -431,6 +434,7 @@ mod_items! {
|
||||||
Mod in mods -> ast::Module,
|
Mod in mods -> ast::Module,
|
||||||
MacroCall in macro_calls -> ast::MacroCall,
|
MacroCall in macro_calls -> ast::MacroCall,
|
||||||
MacroRules in macro_rules -> ast::MacroRules,
|
MacroRules in macro_rules -> ast::MacroRules,
|
||||||
|
MacroDef in macro_defs -> ast::MacroDef,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_index {
|
macro_rules! impl_index {
|
||||||
|
@ -640,7 +644,7 @@ pub struct MacroCall {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct MacroRules {
|
pub struct MacroRules {
|
||||||
/// For `macro_rules!` declarations, this is the name of the declared macro.
|
/// The name of the declared macro.
|
||||||
pub name: Name,
|
pub name: Name,
|
||||||
/// Has `#[macro_export]`.
|
/// Has `#[macro_export]`.
|
||||||
pub is_export: bool,
|
pub is_export: bool,
|
||||||
|
@ -651,6 +655,16 @@ pub struct MacroRules {
|
||||||
pub ast_id: FileAstId<ast::MacroRules>,
|
pub ast_id: FileAstId<ast::MacroRules>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// "Macros 2.0" macro definition.
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub struct MacroDef {
|
||||||
|
pub name: Name,
|
||||||
|
pub visibility: RawVisibilityId,
|
||||||
|
/// Has `#[rustc_builtin_macro]`.
|
||||||
|
pub is_builtin: bool,
|
||||||
|
pub ast_id: FileAstId<ast::MacroDef>,
|
||||||
|
}
|
||||||
|
|
||||||
// NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array
|
// NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array
|
||||||
// lengths, but we don't do much with them yet.
|
// lengths, but we don't do much with them yet.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
@ -680,7 +694,8 @@ impl ModItem {
|
||||||
| ModItem::Trait(_)
|
| ModItem::Trait(_)
|
||||||
| ModItem::Impl(_)
|
| ModItem::Impl(_)
|
||||||
| ModItem::Mod(_)
|
| ModItem::Mod(_)
|
||||||
| ModItem::MacroRules(_) => None,
|
| ModItem::MacroRules(_)
|
||||||
|
| ModItem::MacroDef(_) => None,
|
||||||
ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)),
|
ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)),
|
||||||
ModItem::Const(konst) => Some(AssocItem::Const(*konst)),
|
ModItem::Const(konst) => Some(AssocItem::Const(*konst)),
|
||||||
ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)),
|
ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)),
|
||||||
|
@ -708,6 +723,7 @@ impl ModItem {
|
||||||
ModItem::Mod(it) => tree[it.index].ast_id().upcast(),
|
ModItem::Mod(it) => tree[it.index].ast_id().upcast(),
|
||||||
ModItem::MacroCall(it) => tree[it.index].ast_id().upcast(),
|
ModItem::MacroCall(it) => tree[it.index].ast_id().upcast(),
|
||||||
ModItem::MacroRules(it) => tree[it.index].ast_id().upcast(),
|
ModItem::MacroRules(it) => tree[it.index].ast_id().upcast(),
|
||||||
|
ModItem::MacroDef(it) => tree[it.index].ast_id().upcast(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,7 +101,8 @@ impl Ctx {
|
||||||
| ast::Item::ExternCrate(_)
|
| ast::Item::ExternCrate(_)
|
||||||
| ast::Item::Use(_)
|
| ast::Item::Use(_)
|
||||||
| ast::Item::MacroCall(_)
|
| ast::Item::MacroCall(_)
|
||||||
| ast::Item::MacroRules(_) => {}
|
| ast::Item::MacroRules(_)
|
||||||
|
| ast::Item::MacroDef(_) => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
let attrs = Attrs::new(item, &self.hygiene);
|
let attrs = Attrs::new(item, &self.hygiene);
|
||||||
|
@ -122,6 +123,7 @@ impl Ctx {
|
||||||
ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast).map(Into::into),
|
ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast).map(Into::into),
|
||||||
ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
|
ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
|
||||||
ast::Item::MacroRules(ast) => self.lower_macro_rules(ast).map(Into::into),
|
ast::Item::MacroRules(ast) => self.lower_macro_rules(ast).map(Into::into),
|
||||||
|
ast::Item::MacroDef(ast) => self.lower_macro_def(ast).map(Into::into),
|
||||||
ast::Item::ExternBlock(ast) => {
|
ast::Item::ExternBlock(ast) => {
|
||||||
Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>()))
|
Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>()))
|
||||||
}
|
}
|
||||||
|
@ -561,6 +563,18 @@ impl Ctx {
|
||||||
Some(id(self.data().macro_rules.alloc(res)))
|
Some(id(self.data().macro_rules.alloc(res)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn lower_macro_def(&mut self, m: &ast::MacroDef) -> Option<FileItemTreeId<MacroDef>> {
|
||||||
|
let name = m.name().map(|it| it.as_name())?;
|
||||||
|
let attrs = Attrs::new(m, &self.hygiene);
|
||||||
|
|
||||||
|
let ast_id = self.source_ast_id_map.ast_id(m);
|
||||||
|
let visibility = self.lower_visibility(m);
|
||||||
|
|
||||||
|
let is_builtin = attrs.by_key("rustc_builtin_macro").exists();
|
||||||
|
let res = MacroDef { name, is_builtin, ast_id, visibility };
|
||||||
|
Some(id(self.data().macro_defs.alloc(res)))
|
||||||
|
}
|
||||||
|
|
||||||
fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> {
|
fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> {
|
||||||
block.extern_item_list().map_or(Vec::new(), |list| {
|
block.extern_item_list().map_or(Vec::new(), |list| {
|
||||||
list.extern_items()
|
list.extern_items()
|
||||||
|
|
|
@ -309,13 +309,13 @@ impl DefCollector<'_> {
|
||||||
let macro_def = match self.proc_macros.iter().find(|(n, _)| n == name) {
|
let macro_def = match self.proc_macros.iter().find(|(n, _)| n == name) {
|
||||||
Some((_, expander)) => MacroDefId {
|
Some((_, expander)) => MacroDefId {
|
||||||
ast_id: None,
|
ast_id: None,
|
||||||
krate: Some(self.def_map.krate),
|
krate: self.def_map.krate,
|
||||||
kind: MacroDefKind::ProcMacro(*expander),
|
kind: MacroDefKind::ProcMacro(*expander),
|
||||||
local_inner: false,
|
local_inner: false,
|
||||||
},
|
},
|
||||||
None => MacroDefId {
|
None => MacroDefId {
|
||||||
ast_id: None,
|
ast_id: None,
|
||||||
krate: Some(self.def_map.krate),
|
krate: self.def_map.krate,
|
||||||
kind: MacroDefKind::ProcMacro(ProcMacroExpander::dummy(self.def_map.krate)),
|
kind: MacroDefKind::ProcMacro(ProcMacroExpander::dummy(self.def_map.krate)),
|
||||||
local_inner: false,
|
local_inner: false,
|
||||||
},
|
},
|
||||||
|
@ -784,14 +784,6 @@ impl DefCollector<'_> {
|
||||||
directive: &DeriveDirective,
|
directive: &DeriveDirective,
|
||||||
path: &ModPath,
|
path: &ModPath,
|
||||||
) -> Option<MacroDefId> {
|
) -> Option<MacroDefId> {
|
||||||
if let Some(name) = path.as_ident() {
|
|
||||||
// FIXME this should actually be handled with the normal name
|
|
||||||
// resolution; the std lib defines built-in stubs for the derives,
|
|
||||||
// but these are new-style `macro`s, which we don't support yet
|
|
||||||
if let Some(def_id) = find_builtin_derive(name) {
|
|
||||||
return Some(def_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let resolved_res = self.def_map.resolve_path_fp_with_macro(
|
let resolved_res = self.def_map.resolve_path_fp_with_macro(
|
||||||
self.db,
|
self.db,
|
||||||
ResolveMode::Other,
|
ResolveMode::Other,
|
||||||
|
@ -976,6 +968,35 @@ impl ModCollector<'_, '_> {
|
||||||
}
|
}
|
||||||
ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]),
|
ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]),
|
||||||
ModItem::MacroRules(mac) => self.collect_macro_rules(&self.item_tree[mac]),
|
ModItem::MacroRules(mac) => self.collect_macro_rules(&self.item_tree[mac]),
|
||||||
|
ModItem::MacroDef(id) => {
|
||||||
|
let mac = &self.item_tree[id];
|
||||||
|
let ast_id = InFile::new(self.file_id, mac.ast_id.upcast());
|
||||||
|
|
||||||
|
// "Macro 2.0" is not currently supported by rust-analyzer, but libcore uses it
|
||||||
|
// to define builtin macros, so we support at least that part.
|
||||||
|
if mac.is_builtin {
|
||||||
|
let krate = self.def_collector.def_map.krate;
|
||||||
|
let macro_id = find_builtin_macro(&mac.name, krate, ast_id)
|
||||||
|
.or_else(|| find_builtin_derive(&mac.name, krate, ast_id));
|
||||||
|
if let Some(macro_id) = macro_id {
|
||||||
|
let vis = self
|
||||||
|
.def_collector
|
||||||
|
.def_map
|
||||||
|
.resolve_visibility(
|
||||||
|
self.def_collector.db,
|
||||||
|
self.module_id,
|
||||||
|
&self.item_tree[mac.visibility],
|
||||||
|
)
|
||||||
|
.unwrap_or(Visibility::Public);
|
||||||
|
self.def_collector.update(
|
||||||
|
self.module_id,
|
||||||
|
&[(Some(mac.name.clone()), PerNs::macros(macro_id, vis))],
|
||||||
|
vis,
|
||||||
|
ImportType::Named,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
ModItem::Impl(imp) => {
|
ModItem::Impl(imp) => {
|
||||||
let module = ModuleId {
|
let module = ModuleId {
|
||||||
krate: self.def_collector.def_map.krate,
|
krate: self.def_collector.def_map.krate,
|
||||||
|
@ -1280,7 +1301,7 @@ impl ModCollector<'_, '_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_macro_rules(&mut self, mac: &MacroRules) {
|
fn collect_macro_rules(&mut self, mac: &MacroRules) {
|
||||||
let ast_id = InFile::new(self.file_id, mac.ast_id);
|
let ast_id = InFile::new(self.file_id, mac.ast_id.upcast());
|
||||||
|
|
||||||
// Case 1: builtin macros
|
// Case 1: builtin macros
|
||||||
if mac.is_builtin {
|
if mac.is_builtin {
|
||||||
|
@ -1299,7 +1320,7 @@ impl ModCollector<'_, '_> {
|
||||||
// Case 2: normal `macro_rules!` macro
|
// Case 2: normal `macro_rules!` macro
|
||||||
let macro_id = MacroDefId {
|
let macro_id = MacroDefId {
|
||||||
ast_id: Some(ast_id),
|
ast_id: Some(ast_id),
|
||||||
krate: Some(self.def_collector.def_map.krate),
|
krate: self.def_collector.def_map.krate,
|
||||||
kind: MacroDefKind::Declarative,
|
kind: MacroDefKind::Declarative,
|
||||||
local_inner: mac.is_local_inner,
|
local_inner: mac.is_local_inner,
|
||||||
};
|
};
|
||||||
|
|
|
@ -633,14 +633,43 @@ pub struct bar;
|
||||||
fn expand_derive() {
|
fn expand_derive() {
|
||||||
let map = compute_crate_def_map(
|
let map = compute_crate_def_map(
|
||||||
"
|
"
|
||||||
//- /main.rs
|
//- /main.rs crate:main deps:core
|
||||||
|
use core::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
struct Foo;
|
struct Foo;
|
||||||
|
|
||||||
|
//- /core.rs crate:core
|
||||||
|
#[rustc_builtin_macro]
|
||||||
|
pub macro Copy {}
|
||||||
|
|
||||||
|
#[rustc_builtin_macro]
|
||||||
|
pub macro Clone {}
|
||||||
",
|
",
|
||||||
);
|
);
|
||||||
assert_eq!(map.modules[map.root].scope.impls().len(), 2);
|
assert_eq!(map.modules[map.root].scope.impls().len(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn resolve_builtin_derive() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- /main.rs crate:main deps:core
|
||||||
|
use core::*;
|
||||||
|
|
||||||
|
//- /core.rs crate:core
|
||||||
|
#[rustc_builtin_macro]
|
||||||
|
pub macro Clone {}
|
||||||
|
|
||||||
|
pub trait Clone {}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
crate
|
||||||
|
Clone: t m
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn macro_expansion_overflow() {
|
fn macro_expansion_overflow() {
|
||||||
mark::check!(macro_expansion_overflow);
|
mark::check!(macro_expansion_overflow);
|
||||||
|
|
|
@ -8,7 +8,7 @@ use syntax::{
|
||||||
match_ast,
|
match_ast,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{db::AstDatabase, name, quote, LazyMacroId, MacroDefId, MacroDefKind};
|
use crate::{db::AstDatabase, name, quote, AstId, CrateId, LazyMacroId, MacroDefId, MacroDefKind};
|
||||||
|
|
||||||
macro_rules! register_builtin {
|
macro_rules! register_builtin {
|
||||||
( $($trait:ident => $expand:ident),* ) => {
|
( $($trait:ident => $expand:ident),* ) => {
|
||||||
|
@ -29,16 +29,15 @@ macro_rules! register_builtin {
|
||||||
};
|
};
|
||||||
expander(db, id, tt)
|
expander(db, id, tt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_by_name(name: &name::Name) -> Option<Self> {
|
||||||
|
match name {
|
||||||
|
$( id if id == &name::name![$trait] => Some(BuiltinDeriveExpander::$trait), )*
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_builtin_derive(ident: &name::Name) -> Option<MacroDefId> {
|
|
||||||
let kind = match ident {
|
|
||||||
$( id if id == &name::name![$trait] => BuiltinDeriveExpander::$trait, )*
|
|
||||||
_ => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(kind), local_inner: false })
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +53,20 @@ register_builtin! {
|
||||||
PartialEq => partial_eq_expand
|
PartialEq => partial_eq_expand
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn find_builtin_derive(
|
||||||
|
ident: &name::Name,
|
||||||
|
krate: CrateId,
|
||||||
|
ast_id: AstId<ast::Macro>,
|
||||||
|
) -> Option<MacroDefId> {
|
||||||
|
let expander = BuiltinDeriveExpander::find_by_name(ident)?;
|
||||||
|
Some(MacroDefId {
|
||||||
|
krate,
|
||||||
|
ast_id: Some(ast_id),
|
||||||
|
kind: MacroDefKind::BuiltInDerive(expander),
|
||||||
|
local_inner: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
struct BasicAdtInfo {
|
struct BasicAdtInfo {
|
||||||
name: tt::Ident,
|
name: tt::Ident,
|
||||||
type_params: usize,
|
type_params: usize,
|
||||||
|
@ -261,7 +274,7 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn expand_builtin_derive(s: &str, name: Name) -> String {
|
fn expand_builtin_derive(s: &str, name: Name) -> String {
|
||||||
let def = find_builtin_derive(&name).unwrap();
|
let expander = BuiltinDeriveExpander::find_by_name(&name).unwrap();
|
||||||
let fixture = format!(
|
let fixture = format!(
|
||||||
r#"//- /main.rs crate:main deps:core
|
r#"//- /main.rs crate:main deps:core
|
||||||
<|>
|
<|>
|
||||||
|
@ -283,7 +296,12 @@ mod tests {
|
||||||
let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0]));
|
let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0]));
|
||||||
|
|
||||||
let loc = MacroCallLoc {
|
let loc = MacroCallLoc {
|
||||||
def,
|
def: MacroDefId {
|
||||||
|
krate: CrateId(0),
|
||||||
|
ast_id: None,
|
||||||
|
kind: MacroDefKind::BuiltInDerive(expander),
|
||||||
|
local_inner: false,
|
||||||
|
},
|
||||||
krate: CrateId(0),
|
krate: CrateId(0),
|
||||||
kind: MacroCallKind::Attr(attr_id, name.to_string()),
|
kind: MacroCallKind::Attr(attr_id, name.to_string()),
|
||||||
};
|
};
|
||||||
|
|
|
@ -63,19 +63,19 @@ macro_rules! register_builtin {
|
||||||
pub fn find_builtin_macro(
|
pub fn find_builtin_macro(
|
||||||
ident: &name::Name,
|
ident: &name::Name,
|
||||||
krate: CrateId,
|
krate: CrateId,
|
||||||
ast_id: AstId<ast::MacroRules>,
|
ast_id: AstId<ast::Macro>,
|
||||||
) -> Option<MacroDefId> {
|
) -> Option<MacroDefId> {
|
||||||
let kind = find_by_name(ident)?;
|
let kind = find_by_name(ident)?;
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
Either::Left(kind) => Some(MacroDefId {
|
Either::Left(kind) => Some(MacroDefId {
|
||||||
krate: Some(krate),
|
krate,
|
||||||
ast_id: Some(ast_id),
|
ast_id: Some(ast_id),
|
||||||
kind: MacroDefKind::BuiltIn(kind),
|
kind: MacroDefKind::BuiltIn(kind),
|
||||||
local_inner: false,
|
local_inner: false,
|
||||||
}),
|
}),
|
||||||
Either::Right(kind) => Some(MacroDefId {
|
Either::Right(kind) => Some(MacroDefId {
|
||||||
krate: Some(krate),
|
krate,
|
||||||
ast_id: Some(ast_id),
|
ast_id: Some(ast_id),
|
||||||
kind: MacroDefKind::BuiltInEager(kind),
|
kind: MacroDefKind::BuiltInEager(kind),
|
||||||
local_inner: false,
|
local_inner: false,
|
||||||
|
@ -515,24 +515,27 @@ mod tests {
|
||||||
fn expand_builtin_macro(ra_fixture: &str) -> String {
|
fn expand_builtin_macro(ra_fixture: &str) -> String {
|
||||||
let (db, file_id) = TestDB::with_single_file(&ra_fixture);
|
let (db, file_id) = TestDB::with_single_file(&ra_fixture);
|
||||||
let parsed = db.parse(file_id);
|
let parsed = db.parse(file_id);
|
||||||
let macro_rules: Vec<_> =
|
let mut macro_rules: Vec<_> =
|
||||||
parsed.syntax_node().descendants().filter_map(ast::MacroRules::cast).collect();
|
parsed.syntax_node().descendants().filter_map(ast::MacroRules::cast).collect();
|
||||||
let macro_calls: Vec<_> =
|
let mut macro_calls: Vec<_> =
|
||||||
parsed.syntax_node().descendants().filter_map(ast::MacroCall::cast).collect();
|
parsed.syntax_node().descendants().filter_map(ast::MacroCall::cast).collect();
|
||||||
|
|
||||||
let ast_id_map = db.ast_id_map(file_id.into());
|
let ast_id_map = db.ast_id_map(file_id.into());
|
||||||
|
|
||||||
assert_eq!(macro_rules.len(), 1, "test must contain exactly 1 `macro_rules!`");
|
assert_eq!(macro_rules.len(), 1, "test must contain exactly 1 `macro_rules!`");
|
||||||
assert_eq!(macro_calls.len(), 1, "test must contain exactly 1 macro call");
|
assert_eq!(macro_calls.len(), 1, "test must contain exactly 1 macro call");
|
||||||
let expander = find_by_name(¯o_rules[0].name().unwrap().as_name()).unwrap();
|
let macro_rules = ast::Macro::from(macro_rules.pop().unwrap());
|
||||||
|
let macro_call = macro_calls.pop().unwrap();
|
||||||
|
|
||||||
|
let expander = find_by_name(¯o_rules.name().unwrap().as_name()).unwrap();
|
||||||
|
|
||||||
let krate = CrateId(0);
|
let krate = CrateId(0);
|
||||||
let file_id = match expander {
|
let file_id = match expander {
|
||||||
Either::Left(expander) => {
|
Either::Left(expander) => {
|
||||||
// the first one should be a macro_rules
|
// the first one should be a macro_rules
|
||||||
let def = MacroDefId {
|
let def = MacroDefId {
|
||||||
krate: Some(CrateId(0)),
|
krate: CrateId(0),
|
||||||
ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_rules[0]))),
|
ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_rules))),
|
||||||
kind: MacroDefKind::BuiltIn(expander),
|
kind: MacroDefKind::BuiltIn(expander),
|
||||||
local_inner: false,
|
local_inner: false,
|
||||||
};
|
};
|
||||||
|
@ -542,7 +545,7 @@ mod tests {
|
||||||
krate,
|
krate,
|
||||||
kind: MacroCallKind::FnLike(AstId::new(
|
kind: MacroCallKind::FnLike(AstId::new(
|
||||||
file_id.into(),
|
file_id.into(),
|
||||||
ast_id_map.ast_id(¯o_calls[0]),
|
ast_id_map.ast_id(¯o_call),
|
||||||
)),
|
)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -552,13 +555,13 @@ mod tests {
|
||||||
Either::Right(expander) => {
|
Either::Right(expander) => {
|
||||||
// the first one should be a macro_rules
|
// the first one should be a macro_rules
|
||||||
let def = MacroDefId {
|
let def = MacroDefId {
|
||||||
krate: Some(krate),
|
krate,
|
||||||
ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_rules[0]))),
|
ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_rules))),
|
||||||
kind: MacroDefKind::BuiltInEager(expander),
|
kind: MacroDefKind::BuiltInEager(expander),
|
||||||
local_inner: false,
|
local_inner: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let args = macro_calls[0].token_tree().unwrap();
|
let args = macro_call.token_tree().unwrap();
|
||||||
let parsed_args = mbe::ast_to_token_tree(&args).unwrap().0;
|
let parsed_args = mbe::ast_to_token_tree(&args).unwrap().0;
|
||||||
|
|
||||||
let arg_id = db.intern_eager_expansion({
|
let arg_id = db.intern_eager_expansion({
|
||||||
|
|
|
@ -129,7 +129,10 @@ fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
|
||||||
fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> {
|
fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> {
|
||||||
match id.kind {
|
match id.kind {
|
||||||
MacroDefKind::Declarative => {
|
MacroDefKind::Declarative => {
|
||||||
let macro_call = id.ast_id?.to_node(db);
|
let macro_call = match id.ast_id?.to_node(db) {
|
||||||
|
syntax::ast::Macro::MacroRules(mac) => mac,
|
||||||
|
syntax::ast::Macro::MacroDef(_) => return None,
|
||||||
|
};
|
||||||
let arg = macro_call.token_tree()?;
|
let arg = macro_call.token_tree()?;
|
||||||
let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| {
|
let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| {
|
||||||
log::warn!("fail on macro_def to token tree: {:#?}", arg);
|
log::warn!("fail on macro_def to token tree: {:#?}", arg);
|
||||||
|
|
|
@ -29,8 +29,8 @@ impl Hygiene {
|
||||||
MacroCallId::LazyMacro(id) => {
|
MacroCallId::LazyMacro(id) => {
|
||||||
let loc = db.lookup_intern_macro(id);
|
let loc = db.lookup_intern_macro(id);
|
||||||
match loc.def.kind {
|
match loc.def.kind {
|
||||||
MacroDefKind::Declarative => (loc.def.krate, loc.def.local_inner),
|
MacroDefKind::Declarative => (Some(loc.def.krate), loc.def.local_inner),
|
||||||
MacroDefKind::BuiltIn(_) => (loc.def.krate, false),
|
MacroDefKind::BuiltIn(_) => (Some(loc.def.krate), false),
|
||||||
MacroDefKind::BuiltInDerive(_) => (None, false),
|
MacroDefKind::BuiltInDerive(_) => (None, false),
|
||||||
MacroDefKind::BuiltInEager(_) => (None, false),
|
MacroDefKind::BuiltInEager(_) => (None, false),
|
||||||
MacroDefKind::ProcMacro(_) => (None, false),
|
MacroDefKind::ProcMacro(_) => (None, false),
|
||||||
|
|
|
@ -145,7 +145,10 @@ impl HirFileId {
|
||||||
let arg_tt = loc.kind.arg(db)?;
|
let arg_tt = loc.kind.arg(db)?;
|
||||||
|
|
||||||
let def = loc.def.ast_id.and_then(|id| {
|
let def = loc.def.ast_id.and_then(|id| {
|
||||||
let def_tt = id.to_node(db).token_tree()?;
|
let def_tt = match id.to_node(db) {
|
||||||
|
ast::Macro::MacroRules(mac) => mac.token_tree()?,
|
||||||
|
ast::Macro::MacroDef(_) => return None,
|
||||||
|
};
|
||||||
Some(InFile::new(id.file_id, def_tt))
|
Some(InFile::new(id.file_id, def_tt))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -221,14 +224,8 @@ impl From<EagerMacroId> for MacroCallId {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct MacroDefId {
|
pub struct MacroDefId {
|
||||||
// FIXME: krate and ast_id are currently optional because we don't have a
|
pub krate: CrateId,
|
||||||
// definition location for built-in derives. There is one, though: the
|
pub ast_id: Option<AstId<ast::Macro>>,
|
||||||
// standard library defines them. The problem is that it uses the new
|
|
||||||
// `macro` syntax for this, which we don't support yet. As soon as we do
|
|
||||||
// (which will probably require touching this code), we can instead use
|
|
||||||
// that (and also remove the hacks for resolving built-in derives).
|
|
||||||
pub krate: Option<CrateId>,
|
|
||||||
pub ast_id: Option<AstId<ast::MacroRules>>,
|
|
||||||
pub kind: MacroDefKind,
|
pub kind: MacroDefKind,
|
||||||
|
|
||||||
pub local_inner: bool,
|
pub local_inner: bool,
|
||||||
|
|
|
@ -686,6 +686,8 @@ mod clone {
|
||||||
trait Clone {
|
trait Clone {
|
||||||
fn clone(&self) -> Self;
|
fn clone(&self) -> Self;
|
||||||
}
|
}
|
||||||
|
#[rustc_builtin_macro]
|
||||||
|
macro Clone {}
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
@ -702,6 +704,8 @@ mod clone {
|
||||||
trait Clone {
|
trait Clone {
|
||||||
fn clone(&self) -> Self;
|
fn clone(&self) -> Self;
|
||||||
}
|
}
|
||||||
|
#[rustc_builtin_macro]
|
||||||
|
macro Clone {}
|
||||||
}
|
}
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct S;
|
pub struct S;
|
||||||
|
@ -737,6 +741,8 @@ mod clone {
|
||||||
trait Clone {
|
trait Clone {
|
||||||
fn clone(&self) -> Self;
|
fn clone(&self) -> Self;
|
||||||
}
|
}
|
||||||
|
#[rustc_builtin_macro]
|
||||||
|
macro Clone {}
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
|
@ -221,6 +221,8 @@ struct Foo<|>;
|
||||||
mod marker {
|
mod marker {
|
||||||
trait Copy {}
|
trait Copy {}
|
||||||
}
|
}
|
||||||
|
#[rustc_builtin_macro]
|
||||||
|
macro Copy {}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,9 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
<pre><code><span class="keyword">use</span> <span class="module">inner</span><span class="operator">::</span><span class="punctuation">{</span><span class="self_keyword">self</span> <span class="keyword">as</span> <span class="module declaration">inner_mod</span><span class="punctuation">}</span><span class="punctuation">;</span>
|
<pre><code><span class="keyword">use</span> <span class="module">inner</span><span class="operator">::</span><span class="punctuation">{</span><span class="self_keyword">self</span> <span class="keyword">as</span> <span class="module declaration">inner_mod</span><span class="punctuation">}</span><span class="punctuation">;</span>
|
||||||
<span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="punctuation">{</span><span class="punctuation">}</span>
|
<span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="punctuation">{</span><span class="punctuation">}</span>
|
||||||
|
|
||||||
|
<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span>
|
||||||
|
<span class="keyword">macro</span> <span class="unresolved_reference declaration">Copy</span> <span class="punctuation">{</span><span class="punctuation">}</span>
|
||||||
|
|
||||||
<span class="comment">// Needed for function consuming vs normal</span>
|
<span class="comment">// Needed for function consuming vs normal</span>
|
||||||
<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">marker</span> <span class="punctuation">{</span>
|
<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">marker</span> <span class="punctuation">{</span>
|
||||||
<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"copy"</span><span class="attribute attribute">]</span>
|
<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">lang</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"copy"</span><span class="attribute attribute">]</span>
|
||||||
|
@ -119,7 +122,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
<span class="value_param callable">f</span><span class="punctuation">(</span><span class="punctuation">)</span>
|
<span class="value_param callable">f</span><span class="punctuation">(</span><span class="punctuation">)</span>
|
||||||
<span class="punctuation">}</span>
|
<span class="punctuation">}</span>
|
||||||
|
|
||||||
<span class="keyword">fn</span> <span class="function declaration">foobar</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="keyword">impl</span> <span class="unresolved_reference">Copy</span> <span class="punctuation">{</span><span class="punctuation">}</span>
|
<span class="keyword">fn</span> <span class="function declaration">foobar</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="keyword">impl</span> <span class="macro">Copy</span> <span class="punctuation">{</span><span class="punctuation">}</span>
|
||||||
|
|
||||||
<span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
|
<span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
|
||||||
<span class="keyword">let</span> <span class="variable declaration">bar</span> <span class="operator">=</span> <span class="function">foobar</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
|
<span class="keyword">let</span> <span class="variable declaration">bar</span> <span class="operator">=</span> <span class="function">foobar</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
|
||||||
|
|
|
@ -12,6 +12,9 @@ fn test_highlighting() {
|
||||||
use inner::{self as inner_mod};
|
use inner::{self as inner_mod};
|
||||||
mod inner {}
|
mod inner {}
|
||||||
|
|
||||||
|
#[rustc_builtin_macro]
|
||||||
|
macro Copy {}
|
||||||
|
|
||||||
// Needed for function consuming vs normal
|
// Needed for function consuming vs normal
|
||||||
pub mod marker {
|
pub mod marker {
|
||||||
#[lang = "copy"]
|
#[lang = "copy"]
|
||||||
|
|
|
@ -19,8 +19,8 @@ pub use self::{
|
||||||
expr_ext::{ArrayExprKind, BinOp, Effect, ElseBranch, LiteralKind, PrefixOp, RangeOp},
|
expr_ext::{ArrayExprKind, BinOp, Effect, ElseBranch, LiteralKind, PrefixOp, RangeOp},
|
||||||
generated::{nodes::*, tokens::*},
|
generated::{nodes::*, tokens::*},
|
||||||
node_ext::{
|
node_ext::{
|
||||||
AttrKind, FieldKind, NameOrNameRef, PathSegmentKind, SelfParamKind, SlicePatComponents,
|
AttrKind, FieldKind, Macro, NameOrNameRef, PathSegmentKind, SelfParamKind,
|
||||||
StructKind, TypeBoundKind, VisibilityKind,
|
SlicePatComponents, StructKind, TypeBoundKind, VisibilityKind,
|
||||||
},
|
},
|
||||||
token_ext::*,
|
token_ext::*,
|
||||||
traits::*,
|
traits::*,
|
||||||
|
|
|
@ -286,6 +286,18 @@ impl MacroRules {
|
||||||
pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
|
pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct MacroDef {
|
||||||
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
}
|
||||||
|
impl ast::AttrsOwner for MacroDef {}
|
||||||
|
impl ast::NameOwner for MacroDef {}
|
||||||
|
impl ast::VisibilityOwner for MacroDef {}
|
||||||
|
impl MacroDef {
|
||||||
|
pub fn macro_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![macro]) }
|
||||||
|
pub fn args(&self) -> Option<TokenTree> { support::child(&self.syntax) }
|
||||||
|
pub fn body(&self) -> Option<TokenTree> { support::child(&self.syntax) }
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
pub(crate) syntax: SyntaxNode,
|
pub(crate) syntax: SyntaxNode,
|
||||||
}
|
}
|
||||||
|
@ -1332,6 +1344,7 @@ pub enum Item {
|
||||||
Impl(Impl),
|
Impl(Impl),
|
||||||
MacroCall(MacroCall),
|
MacroCall(MacroCall),
|
||||||
MacroRules(MacroRules),
|
MacroRules(MacroRules),
|
||||||
|
MacroDef(MacroDef),
|
||||||
Module(Module),
|
Module(Module),
|
||||||
Static(Static),
|
Static(Static),
|
||||||
Struct(Struct),
|
Struct(Struct),
|
||||||
|
@ -1689,6 +1702,17 @@ impl AstNode for MacroRules {
|
||||||
}
|
}
|
||||||
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
}
|
}
|
||||||
|
impl AstNode for MacroDef {
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_DEF }
|
||||||
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
if Self::can_cast(syntax.kind()) {
|
||||||
|
Some(Self { syntax })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
|
}
|
||||||
impl AstNode for Module {
|
impl AstNode for Module {
|
||||||
fn can_cast(kind: SyntaxKind) -> bool { kind == MODULE }
|
fn can_cast(kind: SyntaxKind) -> bool { kind == MODULE }
|
||||||
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
@ -3086,6 +3110,9 @@ impl From<MacroCall> for Item {
|
||||||
impl From<MacroRules> for Item {
|
impl From<MacroRules> for Item {
|
||||||
fn from(node: MacroRules) -> Item { Item::MacroRules(node) }
|
fn from(node: MacroRules) -> Item { Item::MacroRules(node) }
|
||||||
}
|
}
|
||||||
|
impl From<MacroDef> for Item {
|
||||||
|
fn from(node: MacroDef) -> Item { Item::MacroDef(node) }
|
||||||
|
}
|
||||||
impl From<Module> for Item {
|
impl From<Module> for Item {
|
||||||
fn from(node: Module) -> Item { Item::Module(node) }
|
fn from(node: Module) -> Item { Item::Module(node) }
|
||||||
}
|
}
|
||||||
|
@ -3111,7 +3138,7 @@ impl AstNode for Item {
|
||||||
fn can_cast(kind: SyntaxKind) -> bool {
|
fn can_cast(kind: SyntaxKind) -> bool {
|
||||||
match kind {
|
match kind {
|
||||||
CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL | MACRO_CALL | MACRO_RULES
|
CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL | MACRO_CALL | MACRO_RULES
|
||||||
| MODULE | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE => true,
|
| MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3125,6 +3152,7 @@ impl AstNode for Item {
|
||||||
IMPL => Item::Impl(Impl { syntax }),
|
IMPL => Item::Impl(Impl { syntax }),
|
||||||
MACRO_CALL => Item::MacroCall(MacroCall { syntax }),
|
MACRO_CALL => Item::MacroCall(MacroCall { syntax }),
|
||||||
MACRO_RULES => Item::MacroRules(MacroRules { syntax }),
|
MACRO_RULES => Item::MacroRules(MacroRules { syntax }),
|
||||||
|
MACRO_DEF => Item::MacroDef(MacroDef { syntax }),
|
||||||
MODULE => Item::Module(Module { syntax }),
|
MODULE => Item::Module(Module { syntax }),
|
||||||
STATIC => Item::Static(Static { syntax }),
|
STATIC => Item::Static(Static { syntax }),
|
||||||
STRUCT => Item::Struct(Struct { syntax }),
|
STRUCT => Item::Struct(Struct { syntax }),
|
||||||
|
@ -3146,6 +3174,7 @@ impl AstNode for Item {
|
||||||
Item::Impl(it) => &it.syntax,
|
Item::Impl(it) => &it.syntax,
|
||||||
Item::MacroCall(it) => &it.syntax,
|
Item::MacroCall(it) => &it.syntax,
|
||||||
Item::MacroRules(it) => &it.syntax,
|
Item::MacroRules(it) => &it.syntax,
|
||||||
|
Item::MacroDef(it) => &it.syntax,
|
||||||
Item::Module(it) => &it.syntax,
|
Item::Module(it) => &it.syntax,
|
||||||
Item::Static(it) => &it.syntax,
|
Item::Static(it) => &it.syntax,
|
||||||
Item::Struct(it) => &it.syntax,
|
Item::Struct(it) => &it.syntax,
|
||||||
|
@ -3615,6 +3644,11 @@ impl std::fmt::Display for MacroRules {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl std::fmt::Display for MacroDef {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl std::fmt::Display for Module {
|
impl std::fmt::Display for Module {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use ast::AttrsOwner;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use parser::SyntaxKind;
|
use parser::SyntaxKind;
|
||||||
|
|
||||||
|
@ -31,6 +32,57 @@ fn text_of_first_token(node: &SyntaxNode) -> &SmolStr {
|
||||||
node.green().children().next().and_then(|it| it.into_token()).unwrap().text()
|
node.green().children().next().and_then(|it| it.into_token()).unwrap().text()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum Macro {
|
||||||
|
MacroRules(ast::MacroRules),
|
||||||
|
MacroDef(ast::MacroDef),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ast::MacroRules> for Macro {
|
||||||
|
fn from(it: ast::MacroRules) -> Self {
|
||||||
|
Macro::MacroRules(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ast::MacroDef> for Macro {
|
||||||
|
fn from(it: ast::MacroDef) -> Self {
|
||||||
|
Macro::MacroDef(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AstNode for Macro {
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool {
|
||||||
|
match kind {
|
||||||
|
SyntaxKind::MACRO_RULES | SyntaxKind::MACRO_DEF => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
let res = match syntax.kind() {
|
||||||
|
SyntaxKind::MACRO_RULES => Macro::MacroRules(ast::MacroRules { syntax }),
|
||||||
|
SyntaxKind::MACRO_DEF => Macro::MacroDef(ast::MacroDef { syntax }),
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
Some(res)
|
||||||
|
}
|
||||||
|
fn syntax(&self) -> &SyntaxNode {
|
||||||
|
match self {
|
||||||
|
Macro::MacroRules(it) => it.syntax(),
|
||||||
|
Macro::MacroDef(it) => it.syntax(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NameOwner for Macro {
|
||||||
|
fn name(&self) -> Option<ast::Name> {
|
||||||
|
match self {
|
||||||
|
Macro::MacroRules(mac) => mac.name(),
|
||||||
|
Macro::MacroDef(mac) => mac.name(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AttrsOwner for Macro {}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum AttrKind {
|
pub enum AttrKind {
|
||||||
Inner,
|
Inner,
|
||||||
|
@ -462,4 +514,6 @@ impl ast::DocCommentsOwner for ast::Const {}
|
||||||
impl ast::DocCommentsOwner for ast::TypeAlias {}
|
impl ast::DocCommentsOwner for ast::TypeAlias {}
|
||||||
impl ast::DocCommentsOwner for ast::Impl {}
|
impl ast::DocCommentsOwner for ast::Impl {}
|
||||||
impl ast::DocCommentsOwner for ast::MacroRules {}
|
impl ast::DocCommentsOwner for ast::MacroRules {}
|
||||||
|
impl ast::DocCommentsOwner for ast::MacroDef {}
|
||||||
|
impl ast::DocCommentsOwner for ast::Macro {}
|
||||||
impl ast::DocCommentsOwner for ast::Use {}
|
impl ast::DocCommentsOwner for ast::Use {}
|
||||||
|
|
|
@ -76,8 +76,20 @@ pub fn type_label(node: &ast::TypeAlias) -> String {
|
||||||
label.trim().to_owned()
|
label.trim().to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn macro_label(node: &ast::MacroRules) -> String {
|
pub fn macro_label(node: &ast::Macro) -> String {
|
||||||
let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default();
|
let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default();
|
||||||
let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" };
|
match node {
|
||||||
format!("{}macro_rules! {}", vis, name)
|
ast::Macro::MacroRules(node) => {
|
||||||
|
let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" };
|
||||||
|
format!("{}macro_rules! {}", vis, name)
|
||||||
|
}
|
||||||
|
ast::Macro::MacroDef(node) => {
|
||||||
|
let mut s = String::new();
|
||||||
|
if let Some(vis) = node.visibility() {
|
||||||
|
format_to!(s, "{} ", vis);
|
||||||
|
}
|
||||||
|
format_to!(s, "macro {}", name);
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue