From 3bb9efb6b70445076858ab72bebbbd7e31347307 Mon Sep 17 00:00:00 2001 From: Yilin Chen Date: Sun, 21 Mar 2021 23:02:01 +0800 Subject: use the included file as the source of expanded include macro Signed-off-by: Yilin Chen --- crates/hir_def/src/nameres/mod_resolution.rs | 10 ++++- crates/hir_expand/src/builtin_macro.rs | 66 ++++++++++++++++++---------- crates/hir_expand/src/eager.rs | 13 ++++-- crates/hir_expand/src/lib.rs | 23 +++++++++- crates/hir_ty/src/tests/macros.rs | 23 ++++++++++ 5 files changed, 107 insertions(+), 28 deletions(-) diff --git a/crates/hir_def/src/nameres/mod_resolution.rs b/crates/hir_def/src/nameres/mod_resolution.rs index d5de9899c..afb06fd82 100644 --- a/crates/hir_def/src/nameres/mod_resolution.rs +++ b/crates/hir_def/src/nameres/mod_resolution.rs @@ -62,6 +62,7 @@ impl ModDir { name: &Name, attr_path: Option<&SmolStr>, ) -> Result<(FileId, bool, ModDir), String> { + let is_include_macro = file_id.is_include_macro(db.upcast()); let file_id = file_id.original_file(db.upcast()); let mut candidate_files = Vec::new(); @@ -70,8 +71,13 @@ impl ModDir { candidate_files.push(self.dir_path.join_attr(attr_path, self.root_non_dir_owner)) } None => { - candidate_files.push(format!("{}{}.rs", self.dir_path.0, name)); - candidate_files.push(format!("{}{}/mod.rs", self.dir_path.0, name)); + if is_include_macro { + candidate_files.push(format!("{}.rs", name)); + candidate_files.push(format!("{}/mod.rs", name)); + } else { + candidate_files.push(format!("{}{}.rs", self.dir_path.0, name)); + candidate_files.push(format!("{}{}/mod.rs", self.dir_path.0, name)); + } } }; diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs index 8529b43b6..4d52904b9 100644 --- a/crates/hir_expand/src/builtin_macro.rs +++ b/crates/hir_expand/src/builtin_macro.rs @@ -43,7 +43,7 @@ macro_rules! register_builtin { db: &dyn AstDatabase, arg_id: EagerMacroId, tt: &tt::Subtree, - ) -> ExpandResult> { + ) -> ExpandResult> { let expander = match *self { $( EagerExpander::$e_kind => $e_expand, )* }; @@ -61,6 +61,20 @@ macro_rules! register_builtin { }; } +#[derive(Debug)] +pub struct ExpandedEager { + pub(crate) subtree: tt::Subtree, + pub(crate) fragment: FragmentKind, + /// The included file ID of the include macro. + pub(crate) included_file: Option, +} + +impl ExpandedEager { + fn new(subtree: tt::Subtree, fragment: FragmentKind) -> Self { + ExpandedEager { subtree, fragment, included_file: None } + } +} + pub fn find_builtin_macro( ident: &name::Name, krate: CrateId, @@ -280,7 +294,7 @@ fn compile_error_expand( _db: &dyn AstDatabase, _id: EagerMacroId, tt: &tt::Subtree, -) -> ExpandResult> { +) -> ExpandResult> { let err = match &*tt.token_trees { [tt::TokenTree::Leaf(tt::Leaf::Literal(it))] => { let text = it.text.as_str(); @@ -294,14 +308,14 @@ fn compile_error_expand( _ => mbe::ExpandError::BindingError("`compile_error!` argument must be a string".into()), }; - ExpandResult { value: Some((quote! {}, FragmentKind::Items)), err: Some(err) } + ExpandResult { value: Some(ExpandedEager::new(quote! {}, FragmentKind::Items)), err: Some(err) } } fn concat_expand( _db: &dyn AstDatabase, _arg_id: EagerMacroId, tt: &tt::Subtree, -) -> ExpandResult> { +) -> ExpandResult> { let mut err = None; let mut text = String::new(); for (i, t) in tt.token_trees.iter().enumerate() { @@ -325,7 +339,7 @@ fn concat_expand( } } } - ExpandResult { value: Some((quote!(#text), FragmentKind::Expr)), err } + ExpandResult { value: Some(ExpandedEager::new(quote!(#text), FragmentKind::Expr)), err } } fn relative_file( @@ -361,21 +375,27 @@ fn include_expand( db: &dyn AstDatabase, arg_id: EagerMacroId, tt: &tt::Subtree, -) -> ExpandResult> { +) -> ExpandResult> { let res = (|| { let path = parse_string(tt)?; let file_id = relative_file(db, arg_id.into(), &path, false)?; - Ok(parse_to_token_tree(&db.file_text(file_id)) + let subtree = parse_to_token_tree(&db.file_text(file_id)) .ok_or_else(|| mbe::ExpandError::ConversionError)? - .0) + .0; + Ok((subtree, file_id)) })(); match res { - Ok(res) => { + Ok((subtree, file_id)) => { // FIXME: // Handle include as expression - ExpandResult::ok(Some((res, FragmentKind::Items))) + + ExpandResult::ok(Some(ExpandedEager { + subtree, + fragment: FragmentKind::Items, + included_file: Some(file_id), + })) } Err(e) => ExpandResult::only_err(e), } @@ -385,7 +405,7 @@ fn include_bytes_expand( _db: &dyn AstDatabase, _arg_id: EagerMacroId, tt: &tt::Subtree, -) -> ExpandResult> { +) -> ExpandResult> { if let Err(e) = parse_string(tt) { return ExpandResult::only_err(e); } @@ -398,14 +418,14 @@ fn include_bytes_expand( id: tt::TokenId::unspecified(), }))], }; - ExpandResult::ok(Some((res, FragmentKind::Expr))) + ExpandResult::ok(Some(ExpandedEager::new(res, FragmentKind::Expr))) } fn include_str_expand( db: &dyn AstDatabase, arg_id: EagerMacroId, tt: &tt::Subtree, -) -> ExpandResult> { +) -> ExpandResult> { let path = match parse_string(tt) { Ok(it) => it, Err(e) => return ExpandResult::only_err(e), @@ -418,14 +438,14 @@ fn include_str_expand( let file_id = match relative_file(db, arg_id.into(), &path, true) { Ok(file_id) => file_id, Err(_) => { - return ExpandResult::ok(Some((quote!(""), FragmentKind::Expr))); + return ExpandResult::ok(Some(ExpandedEager::new(quote!(""), FragmentKind::Expr))); } }; let text = db.file_text(file_id); let text = &*text; - ExpandResult::ok(Some((quote!(#text), FragmentKind::Expr))) + ExpandResult::ok(Some(ExpandedEager::new(quote!(#text), FragmentKind::Expr))) } fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option { @@ -437,7 +457,7 @@ fn env_expand( db: &dyn AstDatabase, arg_id: EagerMacroId, tt: &tt::Subtree, -) -> ExpandResult> { +) -> ExpandResult> { let key = match parse_string(tt) { Ok(it) => it, Err(e) => return ExpandResult::only_err(e), @@ -461,14 +481,14 @@ fn env_expand( }); let expanded = quote! { #s }; - ExpandResult { value: Some((expanded, FragmentKind::Expr)), err } + ExpandResult { value: Some(ExpandedEager::new(expanded, FragmentKind::Expr)), err } } fn option_env_expand( db: &dyn AstDatabase, arg_id: EagerMacroId, tt: &tt::Subtree, -) -> ExpandResult> { +) -> ExpandResult> { let key = match parse_string(tt) { Ok(it) => it, Err(e) => return ExpandResult::only_err(e), @@ -479,7 +499,7 @@ fn option_env_expand( Some(s) => quote! { std::option::Some(#s) }, }; - ExpandResult::ok(Some((expanded, FragmentKind::Expr))) + ExpandResult::ok(Some(ExpandedEager::new(expanded, FragmentKind::Expr))) } #[cfg(test)] @@ -553,16 +573,18 @@ mod tests { subtree: Arc::new(parsed_args.clone()), krate, call: call_id, + included_file: None, } }); - let (subtree, fragment) = expander.expand(&db, arg_id, &parsed_args).value.unwrap(); + let expanded = expander.expand(&db, arg_id, &parsed_args).value.unwrap(); let eager = EagerCallLoc { def, - fragment, - subtree: Arc::new(subtree), + fragment: expanded.fragment, + subtree: Arc::new(expanded.subtree), krate, call: call_id, + included_file: expanded.included_file, }; let id: MacroCallId = db.intern_eager_expansion(eager).into(); diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs index 04f374a29..9eedc8461 100644 --- a/crates/hir_expand/src/eager.rs +++ b/crates/hir_expand/src/eager.rs @@ -124,6 +124,7 @@ pub fn expand_eager_macro( subtree: Arc::new(parsed_args.clone()), krate, call: call_id, + included_file: None, } }); let arg_file_id: MacroCallId = arg_id.into(); @@ -143,9 +144,15 @@ pub fn expand_eager_macro( if let MacroDefKind::BuiltInEager(eager, _) = def.kind { let res = eager.expand(db, arg_id, &subtree); - let (subtree, fragment) = diagnostic_sink.expand_result_option(res)?; - let eager = - EagerCallLoc { def, fragment, subtree: Arc::new(subtree), krate, call: call_id }; + let expanded = diagnostic_sink.expand_result_option(res)?; + let eager = EagerCallLoc { + def, + fragment: expanded.fragment, + subtree: Arc::new(expanded.subtree), + krate, + call: call_id, + included_file: expanded.included_file, + }; Ok(db.intern_eager_expansion(eager)) } else { diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index f49fd4fda..b8045fda9 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs @@ -84,7 +84,11 @@ impl HirFileId { } MacroCallId::EagerMacro(id) => { let loc = db.lookup_intern_eager_expansion(id); - loc.call.file_id + if let Some(included_file) = loc.included_file { + return included_file; + } else { + loc.call.file_id + } } }; file_id.original_file(db) @@ -188,6 +192,21 @@ impl HirFileId { } } } + + /// Return whether this file is an include macro + pub fn is_include_macro(&self, db: &dyn db::AstDatabase) -> bool { + match self.0 { + HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id { + MacroCallId::EagerMacro(id) => { + let loc = db.lookup_intern_eager_expansion(id); + return loc.included_file.is_some(); + } + _ => {} + }, + _ => {} + } + false + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -315,6 +334,8 @@ pub struct EagerCallLoc { pub(crate) subtree: Arc, pub(crate) krate: CrateId, pub(crate) call: AstId, + // The included file ID of the include macro. + pub(crate) included_file: Option, } /// ExpansionInfo mainly describes how to map text range between src and expanded macro diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index c1e605740..12951fb16 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs @@ -606,6 +606,29 @@ fn bar() -> u32 {0} ); } +#[test] +fn infer_builtin_macros_include_child_mod() { + check_types( + r#" +//- /main.rs +#[rustc_builtin_macro] +macro_rules! include {() => {}} + +include!("f/foo.rs"); + +fn main() { + bar::bar(); +} //^ u32 + +//- /f/foo.rs +pub mod bar; + +//- /f/bar.rs +pub fn bar() -> u32 {0} +"#, + ); +} + #[test] fn infer_builtin_macros_include_str() { check_types( -- cgit v1.2.3