From 8b6216df05a1d17e58f789bbd323ce2679f9ab4a Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sun, 3 May 2020 22:08:39 +0800 Subject: [PATCH] Support macro for trait items --- crates/ra_hir_def/src/data.rs | 149 ++++++++++++--------------- crates/ra_hir_ty/src/tests/traits.rs | 40 +++---- 2 files changed, 88 insertions(+), 101 deletions(-) diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 7a2067e49cb..0633eddee0f 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs @@ -150,51 +150,31 @@ pub struct TraitData { impl TraitData { pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc { - let src = tr.lookup(db).source(db); + let tr_loc = tr.lookup(db); + let src = tr_loc.source(db); let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); let auto = src.value.auto_token().is_some(); - let ast_id_map = db.ast_id_map(src.file_id); + let module_id = tr_loc.container.module(db); let container = AssocContainerId::TraitId(tr); - 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 name = it.name().map_or_else(Name::missing, |it| it.as_name()); - let def = FunctionLoc { - container, - ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)), - } - .intern(db) - .into(); - (name, def) - } - ast::ImplItem::ConstDef(it) => { - let name = it.name().map_or_else(Name::missing, |it| it.as_name()); - let def = ConstLoc { - container, - ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)), - } - .intern(db) - .into(); - (name, def) - } - ast::ImplItem::TypeAliasDef(it) => { - let name = it.name().map_or_else(Name::missing, |it| it.as_name()); - let def = TypeAliasLoc { - container, - ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)), - } - .intern(db) - .into(); - (name, def) - } - }) - .collect() - } else { - Vec::new() - }; + let mut items = Vec::new(); + + if let Some(item_list) = src.value.item_list() { + let mut expander = Expander::new(db, tr_loc.ast_id.file_id, module_id); + items.extend(collect_impl_items( + db, + &mut expander, + item_list.impl_items(), + src.file_id, + container, + )); + items.extend(collect_impl_items_in_macros( + db, + &mut expander, + &src.with_value(item_list), + container, + )); + } Arc::new(TraitData { name, items, auto }) } @@ -232,24 +212,33 @@ impl ImplData { let target_type = TypeRef::from_ast_opt(&lower_ctx, src.value.target_type()); let is_negative = src.value.excl_token().is_some(); let module_id = impl_loc.container.module(db); + let container = AssocContainerId::ImplId(id); - let mut items = Vec::new(); + let mut items: Vec = Vec::new(); if let Some(item_list) = src.value.item_list() { let mut expander = Expander::new(db, impl_loc.ast_id.file_id, module_id); - items.extend(collect_impl_items( - db, - &mut expander, - item_list.impl_items(), - src.file_id, - id, - )); - items.extend(collect_impl_items_in_macros( - db, - &mut expander, - &src.with_value(item_list), - id, - )); + items.extend( + collect_impl_items( + db, + &mut expander, + item_list.impl_items(), + src.file_id, + container, + ) + .into_iter() + .map(|(_, item)| item), + ); + items.extend( + collect_impl_items_in_macros( + db, + &mut expander, + &src.with_value(item_list), + container, + ) + .into_iter() + .map(|(_, item)| item), + ); } let res = ImplData { target_trait, target_type, items, is_negative }; @@ -296,15 +285,15 @@ fn collect_impl_items_in_macros( db: &dyn DefDatabase, expander: &mut Expander, impl_def: &InFile, - id: ImplId, -) -> Vec { + container: AssocContainerId, +) -> Vec<(Name, AssocItemId)> { let mut res = Vec::new(); // We set a limit to protect against infinite recursion let limit = 100; for m in impl_def.value.syntax().children().filter_map(ast::MacroCall::cast) { - res.extend(collect_impl_items_in_macro(db, expander, m, id, limit)) + res.extend(collect_impl_items_in_macro(db, expander, m, container, limit)) } res @@ -314,9 +303,9 @@ fn collect_impl_items_in_macro( db: &dyn DefDatabase, expander: &mut Expander, m: ast::MacroCall, - id: ImplId, + container: AssocContainerId, limit: usize, -) -> Vec { +) -> Vec<(Name, AssocItemId)> { if limit == 0 { return Vec::new(); } @@ -328,13 +317,14 @@ fn collect_impl_items_in_macro( expander, items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())), items.file_id, - id, + container, ); + // Recursive collect macros // Note that ast::ModuleItem do not include ast::MacroCall // We cannot use ModuleItemOwner::items here for it in items.value.syntax().children().filter_map(ast::MacroCall::cast) { - res.extend(collect_impl_items_in_macro(db, expander, it, id, limit - 1)) + res.extend(collect_impl_items_in_macro(db, expander, it, container, limit - 1)) } expander.exit(db, mark); res @@ -348,39 +338,34 @@ fn collect_impl_items( expander: &mut Expander, impl_items: impl Iterator, file_id: crate::HirFileId, - id: ImplId, -) -> Vec { + container: AssocContainerId, +) -> Vec<(Name, AssocItemId)> { let items = db.ast_id_map(file_id); impl_items .filter_map(|item_node| match item_node { ast::ImplItem::FnDef(it) => { + let name = it.name().map_or_else(Name::missing, |it| it.as_name()); let attrs = expander.parse_attrs(&it); if !expander.is_cfg_enabled(&attrs) { return None; } - let def = FunctionLoc { - container: AssocContainerId::ImplId(id), - ast_id: AstId::new(file_id, items.ast_id(&it)), - } - .intern(db); - Some(def.into()) + let def = FunctionLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } + .intern(db); + Some((name, 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); - Some(def.into()) + let name = it.name().map_or_else(Name::missing, |it| it.as_name()); + let def = ConstLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } + .intern(db); + Some((name, 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); - Some(def.into()) + let name = it.name().map_or_else(Name::missing, |it| it.as_name()); + let def = + TypeAliasLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } + .intern(db); + Some((name, def.into())) } }) .collect() diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index e555c879a04..23f682effaa 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -2055,7 +2055,7 @@ fn test>>() { #[test] fn proc_macro_server_types() { assert_snapshot!( - infer_with_mismatches(r#" + infer(r#" macro_rules! with_api { ($S:ident, $self:ident, $m:ident) => { $m! { @@ -2069,9 +2069,9 @@ macro_rules! with_api { } macro_rules! associated_item { (type TokenStream) => - (type TokenStream: 'static + Clone;); + (type TokenStream: 'static;); (type Group) => - (type Group: 'static + Clone;); + (type Group: 'static;); ($($item:tt)*) => ($($item)*;) } macro_rules! declare_server_traits { @@ -2083,39 +2083,41 @@ macro_rules! declare_server_traits { } $(pub trait $name: Types { - $(associated_item!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)* + $(associated_item!(fn $method($($arg: $arg_ty),*) $(-> $ret_ty)?);)* })* pub trait Server: Types $(+ $name)* {} impl Server for S {} } } + with_api!(Self, self_, declare_server_traits); -struct Group {} -struct TokenStream {} +struct G {} +struct T {} struct Rustc; impl Types for Rustc { - type TokenStream = TokenStream; - type Group = Group; + type TokenStream = T; + type Group = G; } + fn make() -> T { loop {} } impl TokenStream for Rustc { fn new() -> Self::TokenStream { let group: Self::Group = make(); make() } -} -"#, true), +} +"#), @r###" - 1115..1126 '{ loop {} }': T - 1117..1124 'loop {}': ! - 1122..1124 '{}': () - 1190..1253 '{ ... }': {unknown} - 1204..1209 'group': {unknown} - 1225..1229 'make': fn make<{unknown}>() -> {unknown} - 1225..1231 'make()': {unknown} - 1241..1245 'make': fn make<{unknown}>() -> {unknown} - 1241..1247 'make()': {unknown} + 1062..1073 '{ loop {} }': T + 1064..1071 'loop {}': ! + 1069..1071 '{}': () + 1137..1200 '{ ... }': T + 1151..1156 'group': G + 1172..1176 'make': fn make() -> G + 1172..1178 'make()': G + 1188..1192 'make': fn make() -> T + 1188..1194 'make()': T "### ); }