From e4267967a8ee3b35d902931cecf06bb4e19f86c5 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Fri, 1 May 2020 11:23:03 +0800 Subject: Support local_inner_macros --- crates/ra_hir/src/semantics/source_to_def.rs | 2 +- crates/ra_hir_def/src/body/lower.rs | 1 + crates/ra_hir_def/src/nameres/collector.rs | 2 ++ crates/ra_hir_def/src/nameres/raw.rs | 27 ++++++++++++++++++------ crates/ra_hir_def/src/path/lower.rs | 19 ++++++++++++++++- crates/ra_hir_expand/src/builtin_derive.rs | 2 +- crates/ra_hir_expand/src/builtin_macro.rs | 4 ++++ crates/ra_hir_expand/src/hygiene.rs | 31 +++++++++++++++++++--------- crates/ra_hir_expand/src/lib.rs | 2 ++ crates/ra_hir_ty/src/tests/macros.rs | 26 +++++++++++++++++++++++ 10 files changed, 97 insertions(+), 19 deletions(-) diff --git a/crates/ra_hir/src/semantics/source_to_def.rs b/crates/ra_hir/src/semantics/source_to_def.rs index 6f3b5b2da..8af64fdc1 100644 --- a/crates/ra_hir/src/semantics/source_to_def.rs +++ b/crates/ra_hir/src/semantics/source_to_def.rs @@ -151,7 +151,7 @@ impl SourceToDefCtx<'_, '_> { 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 ast_id = Some(AstId::new(src.file_id, file_ast_id)); - Some(MacroDefId { krate: Some(krate), ast_id, kind }) + Some(MacroDefId { krate: Some(krate), ast_id, kind, local_inner: false }) } pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option { diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index f467ed3fe..8c1aefbf5 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -430,6 +430,7 @@ impl ExprCollector<'_> { krate: Some(self.expander.module.krate), ast_id: Some(self.expander.ast_id(&e)), kind: MacroDefKind::Declarative, + local_inner: false, }; self.body.item_scope.define_legacy_macro(name, mac); diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 98c74fe25..bf3968bd6 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -204,6 +204,7 @@ impl DefCollector<'_> { ast_id: None, krate: Some(krate), kind: MacroDefKind::CustomDerive(expander), + local_inner: false, }; self.define_proc_macro(name.clone(), macro_id); @@ -941,6 +942,7 @@ impl ModCollector<'_, '_> { ast_id: Some(ast_id.ast_id), krate: Some(self.def_collector.def_map.krate), kind: MacroDefKind::Declarative, + local_inner: mac.local_inner, }; self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export); } diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index 39b011ad7..aed9dcc72 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs @@ -188,6 +188,7 @@ pub(super) struct MacroData { pub(super) path: ModPath, pub(super) name: Option, pub(super) export: bool, + pub(super) local_inner: bool, pub(super) builtin: bool, } @@ -401,14 +402,28 @@ impl RawItemsCollector { let name = m.name().map(|it| it.as_name()); let ast_id = self.source_ast_id_map.ast_id(&m); - // FIXME: cfg_attr - let export = m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "macro_export"); // FIXME: cfg_attr - let builtin = - m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "rustc_builtin_macro"); - - let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export, builtin }); + let export = attrs.by_key("macro_export").exists(); + let local_inner = + attrs.by_key("macro_export").tt_values().map(|it| &it.token_trees).flatten().any( + |it| match it { + tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { + ident.text.contains("local_inner_macros") + } + _ => false, + }, + ); + let builtin = attrs.by_key("rustc_builtin_macro").exists(); + + let m = self.raw_items.macros.alloc(MacroData { + ast_id, + path, + name, + export, + local_inner, + builtin, + }); self.push_item(current_module, attrs, RawItemKind::Macro(m)); } diff --git a/crates/ra_hir_def/src/path/lower.rs b/crates/ra_hir_def/src/path/lower.rs index 9ec2e0dcd..e632f1afb 100644 --- a/crates/ra_hir_def/src/path/lower.rs +++ b/crates/ra_hir_def/src/path/lower.rs @@ -9,7 +9,10 @@ use hir_expand::{ hygiene::Hygiene, name::{name, AsName}, }; -use ra_syntax::ast::{self, AstNode, TypeAscriptionOwner, TypeBoundsOwner}; +use ra_syntax::{ + ast::{self, AstNode, TypeAscriptionOwner, TypeBoundsOwner}, + T, +}; use super::AssociatedTypeBinding; use crate::{ @@ -113,6 +116,20 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option } segments.reverse(); generic_args.reverse(); + + // handle local_inner_macros : + // Basically, even in rustc it is quite hacky: + // https://github.com/rust-lang/rust/blob/614f273e9388ddd7804d5cbc80b8865068a3744e/src/librustc_resolve/macros.rs#L456 + // We follow what it did anyway :) + if segments.len() == 1 && kind == PathKind::Plain { + let next = path.syntax().last_token().and_then(|it| it.next_token()); + if next.map_or(false, |it| it.kind() == T![!]) { + if let Some(crate_id) = hygiene.local_inner_macros() { + kind = PathKind::DollarCrate(crate_id); + } + } + } + let mod_path = ModPath { kind, segments }; return Some(Path { type_anchor, mod_path, generic_args }); diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs index e60f879a3..25bb5cee3 100644 --- a/crates/ra_hir_expand/src/builtin_derive.rs +++ b/crates/ra_hir_expand/src/builtin_derive.rs @@ -38,7 +38,7 @@ macro_rules! register_builtin { _ => return None, }; - Some(MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(kind) }) + Some(MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(kind),local_inner:false }) } }; } diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index e0fef613d..d8b3d342c 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs @@ -73,11 +73,13 @@ pub fn find_builtin_macro( krate: Some(krate), ast_id: Some(ast_id), kind: MacroDefKind::BuiltIn(kind), + local_inner: false, }), Either::Right(kind) => Some(MacroDefId { krate: Some(krate), ast_id: Some(ast_id), kind: MacroDefKind::BuiltInEager(kind), + local_inner: false, }), } } @@ -406,6 +408,7 @@ mod tests { krate: Some(CrateId(0)), ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))), kind: MacroDefKind::BuiltIn(expander), + local_inner: false, }; let loc = MacroCallLoc { @@ -425,6 +428,7 @@ mod tests { krate: Some(CrateId(0)), ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))), kind: MacroDefKind::BuiltInEager(expander), + local_inner: false, }; let args = macro_calls[1].token_tree().unwrap(); diff --git a/crates/ra_hir_expand/src/hygiene.rs b/crates/ra_hir_expand/src/hygiene.rs index 0b41d0e95..3da93de21 100644 --- a/crates/ra_hir_expand/src/hygiene.rs +++ b/crates/ra_hir_expand/src/hygiene.rs @@ -16,31 +16,34 @@ use crate::{ pub struct Hygiene { // This is what `$crate` expands to def_crate: Option, + + // Indiciate this is a local inner macro + local_inner: bool, } impl Hygiene { pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Hygiene { - let def_crate = match file_id.0 { - HirFileIdRepr::FileId(_) => None, + let (def_crate, local_inner) = match file_id.0 { + HirFileIdRepr::FileId(_) => (None, false), HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id { MacroCallId::LazyMacro(id) => { let loc = db.lookup_intern_macro(id); match loc.def.kind { - MacroDefKind::Declarative => loc.def.krate, - MacroDefKind::BuiltIn(_) => None, - MacroDefKind::BuiltInDerive(_) => None, - MacroDefKind::BuiltInEager(_) => None, - MacroDefKind::CustomDerive(_) => None, + MacroDefKind::Declarative => (loc.def.krate, loc.def.local_inner), + MacroDefKind::BuiltIn(_) => (None, false), + MacroDefKind::BuiltInDerive(_) => (None, false), + MacroDefKind::BuiltInEager(_) => (None, false), + MacroDefKind::CustomDerive(_) => (None, false), } } - MacroCallId::EagerMacro(_id) => None, + MacroCallId::EagerMacro(_id) => (None, false), }, }; - Hygiene { def_crate } + Hygiene { def_crate, local_inner } } pub fn new_unhygienic() -> Hygiene { - Hygiene { def_crate: None } + Hygiene { def_crate: None, local_inner: false } } // FIXME: this should just return name @@ -52,4 +55,12 @@ impl Hygiene { } Either::Left(name_ref.as_name()) } + + pub fn local_inner_macros(&self) -> Option { + if self.local_inner { + self.def_crate + } else { + None + } + } } diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 754a0f005..f440c073b 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -204,6 +204,8 @@ pub struct MacroDefId { pub krate: Option, pub ast_id: Option>, pub kind: MacroDefKind, + + pub local_inner: bool, } impl MacroDefId { diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 5ddecbdc6..70e17bc94 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs @@ -387,6 +387,32 @@ fn main() { ); } +#[test] +fn infer_local_inner_macros() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:foo +fn test() { + let x = foo::foo!(1); + x<|>; +} + +//- /lib.rs crate:foo +#[macro_export(local_inner_macros)] +macro_rules! foo { + (1) => { bar!() }; +} + +#[macro_export] +macro_rules! bar { + () => { 42 } +} + +"#, + ); + assert_eq!("i32", type_at_pos(&db, pos)); +} + #[test] fn infer_builtin_macros_line() { assert_snapshot!( -- cgit v1.2.3