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/body.rs | 22 ++++--- crates/ra_hir_def/src/data.rs | 119 +++++++++++++++++++++++------------ crates/ra_hir_def/src/lib.rs | 1 + crates/ra_hir_expand/src/db.rs | 1 + crates/ra_hir_ty/src/tests/macros.rs | 19 ++++++ 5 files changed, 114 insertions(+), 48 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 401fe0b9b..a92c01f86 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs @@ -23,7 +23,7 @@ use crate::{ DefWithBodyId, HasModule, Lookup, ModuleDefId, ModuleId, }; -struct Expander { +pub(crate) struct Expander { crate_def_map: Arc, current_file_id: HirFileId, hygiene: Hygiene, @@ -32,18 +32,22 @@ struct Expander { } 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( &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), @@ -54,7 +58,7 @@ impl Expander { 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 { @@ -77,14 +81,14 @@ impl Expander { 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(&self, value: T) -> InFile { + pub(crate) fn to_source(&self, value: T) -> InFile { InFile { file_id: self.current_file_id, value } } @@ -109,7 +113,7 @@ impl Expander { } } -struct Mark { +pub(crate) struct Mark { file_id: HirFileId, ast_id_map: Arc, bomb: DropBomb, 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() +} diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 8ed1599ff..6bb5408a8 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -47,6 +47,7 @@ use ra_arena::{impl_arena_id, RawId}; use ra_db::{impl_intern_key, salsa, CrateId}; use ra_syntax::{ast, AstNode}; +use crate::body::Expander; use crate::builtin_type::BuiltinType; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index f68aca789..d86445abf 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs @@ -188,6 +188,7 @@ fn to_fragment_kind(db: &dyn AstDatabase, macro_call_id: MacroCallId) -> Fragmen ARG_LIST => FragmentKind::Expr, TRY_EXPR => FragmentKind::Expr, TUPLE_EXPR => FragmentKind::Expr, + ITEM_LIST => FragmentKind::Items, _ => { // Unknown , Just guess it is `Items` FragmentKind::Items diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 812f171db..7fdbf996f 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs @@ -182,6 +182,25 @@ fn test() { S.foo()<|>; } assert_eq!(t, "u128"); } +#[test] +fn infer_impl_items_generated_by_macros() { + let t = type_at( + r#" +//- /main.rs +macro_rules! m { + () => (fn foo(&self) -> u128 {0}) +} +struct S; +impl S { + m!(); +} + +fn test() { S.foo()<|>; } +"#, + ); + assert_eq!(t, "u128"); +} + #[test] fn infer_macro_with_dollar_crate_is_correct_in_expr() { let (db, pos) = TestDB::with_position( -- cgit v1.2.3