From ad81d1dbc19803b5ccf1b230237642944edbff13 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sat, 21 Dec 2019 03:37:03 +0800 Subject: Add support macros in impl blocks --- crates/ra_hir_def/src/data.rs | 119 ++++++++++++++++++++++++++++-------------- 1 file changed, 80 insertions(+), 39 deletions(-) (limited to 'crates/ra_hir_def/src/data.rs') diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 14e86936b..b0a3f1784 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs @@ -4,16 +4,16 @@ use std::sync::Arc; use hir_expand::{ name::{name, AsName, Name}, - AstId, + AstId, InFile, }; -use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; +use ra_syntax::ast::{self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner}; use crate::{ db::DefDatabase, src::HasSource, type_ref::{Mutability, TypeRef}, - AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, ImplId, Intern, - Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc, + AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule, + ImplId, Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -167,46 +167,24 @@ pub struct ImplData { impl ImplData { pub(crate) fn impl_data_query(db: &impl DefDatabase, id: ImplId) -> Arc { - let src = id.lookup(db).source(db); - let items = db.ast_id_map(src.file_id); + let impl_loc = id.lookup(db); + let src = impl_loc.source(db); let target_trait = src.value.target_trait().map(TypeRef::from_ast); let target_type = TypeRef::from_ast_opt(src.value.target_type()); let is_negative = src.value.is_negative(); + let module_id = impl_loc.container.module(db); - let items = if let Some(item_list) = src.value.item_list() { - item_list - .impl_items() - .map(|item_node| match item_node { - ast::ImplItem::FnDef(it) => { - let def = FunctionLoc { - container: AssocContainerId::ImplId(id), - ast_id: AstId::new(src.file_id, items.ast_id(&it)), - } - .intern(db); - def.into() - } - ast::ImplItem::ConstDef(it) => { - let def = ConstLoc { - container: AssocContainerId::ImplId(id), - ast_id: AstId::new(src.file_id, items.ast_id(&it)), - } - .intern(db); - def.into() - } - ast::ImplItem::TypeAliasDef(it) => { - let def = TypeAliasLoc { - container: AssocContainerId::ImplId(id), - ast_id: AstId::new(src.file_id, items.ast_id(&it)), - } - .intern(db); - def.into() - } - }) - .collect() - } else { - Vec::new() - }; + let mut items = Vec::new(); + if let Some(item_list) = src.value.item_list() { + items.extend(collect_impl_items(db, item_list.impl_items(), src.file_id, id)); + items.extend(collect_impl_items_in_macros( + db, + module_id, + &src.with_value(item_list), + id, + )); + } let res = ImplData { target_trait, target_type, items, is_negative }; Arc::new(res) @@ -237,3 +215,66 @@ impl ConstData { ConstData { name, type_ref } } } + +fn collect_impl_items_in_macros( + db: &impl DefDatabase, + module_id: ModuleId, + impl_block: &InFile, + id: ImplId, +) -> Vec { + let mut expander = Expander::new(db, impl_block.file_id, module_id); + let mut res = Vec::new(); + + for m in impl_block.value.syntax().children().filter_map(ast::MacroCall::cast) { + if let Some((mark, items)) = expander.enter_expand(db, m) { + let items: InFile = expander.to_source(items); + expander.exit(db, mark); + res.extend(collect_impl_items( + db, + items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())), + items.file_id, + id, + )); + } + } + + res +} + +fn collect_impl_items( + db: &impl DefDatabase, + impl_items: impl Iterator, + file_id: crate::HirFileId, + id: ImplId, +) -> Vec { + let items = db.ast_id_map(file_id); + + impl_items + .map(|item_node| match item_node { + ast::ImplItem::FnDef(it) => { + let def = FunctionLoc { + container: AssocContainerId::ImplId(id), + ast_id: AstId::new(file_id, items.ast_id(&it)), + } + .intern(db); + def.into() + } + ast::ImplItem::ConstDef(it) => { + let def = ConstLoc { + container: AssocContainerId::ImplId(id), + ast_id: AstId::new(file_id, items.ast_id(&it)), + } + .intern(db); + def.into() + } + ast::ImplItem::TypeAliasDef(it) => { + let def = TypeAliasLoc { + container: AssocContainerId::ImplId(id), + ast_id: AstId::new(file_id, items.ast_id(&it)), + } + .intern(db); + def.into() + } + }) + .collect() +} -- cgit v1.2.3