DefWithBodyId, HasModule, Lookup, ModuleDefId, ModuleId,
};
-struct Expander {
+pub(crate) struct Expander {
crate_def_map: Arc<CrateDefMap>,
current_file_id: HirFileId,
hygiene: Hygiene,
}
impl Expander {
- fn new(db: &impl DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander {
+ pub(crate) fn new(
+ db: &impl DefDatabase,
+ current_file_id: HirFileId,
+ module: ModuleId,
+ ) -> Expander {
let crate_def_map = db.crate_def_map(module.krate);
let hygiene = Hygiene::new(db, current_file_id);
let ast_id_map = db.ast_id_map(current_file_id);
Expander { crate_def_map, current_file_id, hygiene, ast_id_map, module }
}
- fn enter_expand(
+ pub(crate) fn enter_expand<T: ast::AstNode, DB: DefDatabase>(
&mut self,
- db: &impl DefDatabase,
+ db: &DB,
macro_call: ast::MacroCall,
- ) -> Option<(Mark, ast::Expr)> {
+ ) -> Option<(Mark, T)> {
let ast_id = AstId::new(
self.current_file_id,
db.ast_id_map(self.current_file_id).ast_id(¯o_call),
let call_id = def.as_call_id(db, MacroCallKind::FnLike(ast_id));
let file_id = call_id.as_file();
if let Some(node) = db.parse_or_expand(file_id) {
- if let Some(expr) = ast::Expr::cast(node) {
+ if let Some(expr) = T::cast(node) {
log::debug!("macro expansion {:#?}", expr.syntax());
let mark = Mark {
None
}
- fn exit(&mut self, db: &impl DefDatabase, mut mark: Mark) {
+ pub(crate) fn exit(&mut self, db: &impl DefDatabase, mut mark: Mark) {
self.hygiene = Hygiene::new(db, mark.file_id);
self.current_file_id = mark.file_id;
self.ast_id_map = mem::take(&mut mark.ast_id_map);
mark.bomb.defuse();
}
- fn to_source<T>(&self, value: T) -> InFile<T> {
+ pub(crate) fn to_source<T>(&self, value: T) -> InFile<T> {
InFile { file_id: self.current_file_id, value }
}
}
}
-struct Mark {
+pub(crate) struct Mark {
file_id: HirFileId,
ast_id_map: Arc<AstIdMap>,
bomb: DropBomb,
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)]
impl ImplData {
pub(crate) fn impl_data_query(db: &impl DefDatabase, id: ImplId) -> Arc<ImplData> {
- 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)
ConstData { name, type_ref }
}
}
+
+fn collect_impl_items_in_macros(
+ db: &impl DefDatabase,
+ module_id: ModuleId,
+ impl_block: &InFile<ast::ItemList>,
+ id: ImplId,
+) -> Vec<AssocItemId> {
+ 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<ast::MacroItems> = 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<Item = ImplItem>,
+ file_id: crate::HirFileId,
+ id: ImplId,
+) -> Vec<AssocItemId> {
+ 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()
+}