From 0a06c7e6e6d4f59cacc22b9c1d3122b3faecb62d Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Fri, 6 Mar 2020 22:58:45 +0800 Subject: Implment include macro --- crates/ra_hir_expand/src/builtin_macro.rs | 52 +++++++++++++++++++++++++++---- crates/ra_hir_expand/src/eager.rs | 28 +++++++++-------- crates/ra_hir_expand/src/name.rs | 1 + crates/ra_hir_ty/src/tests/macros.rs | 45 ++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 19 deletions(-) diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index b2c8a911f..9fc33e4b1 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs @@ -5,8 +5,9 @@ use crate::{ name, AstId, CrateId, MacroDefId, MacroDefKind, TextUnit, }; -use crate::{quote, LazyMacroId}; +use crate::{quote, EagerMacroId, LazyMacroId, MacroCallId}; use either::Either; +use ra_db::{FileId, RelativePath}; use ra_parser::FragmentKind; macro_rules! register_builtin { @@ -38,12 +39,14 @@ macro_rules! register_builtin { impl EagerExpander { pub fn expand( &self, + db: &dyn AstDatabase, + arg_id: EagerMacroId, tt: &tt::Subtree, ) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { let expander = match *self { $( EagerExpander::$e_kind => $e_expand, )* }; - expander(tt) + expander(db,arg_id,tt) } } @@ -80,7 +83,6 @@ pub fn find_builtin_macro( register_builtin! { LAZY: - (column, Column) => column_expand, (compile_error, CompileError) => compile_error_expand, (file, File) => file_expand, @@ -94,8 +96,8 @@ register_builtin! { (format_args_nl, FormatArgsNl) => format_args_expand, EAGER: - // eagers - (concat, Concat) => concat_expand + (concat, Concat) => concat_expand, + (include, Include) => include_expand } fn line_expand( @@ -251,7 +253,11 @@ fn unquote_str(lit: &tt::Literal) -> Option { token.value() } -fn concat_expand(tt: &tt::Subtree) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { +fn concat_expand( + _db: &dyn AstDatabase, + _arg_id: EagerMacroId, + tt: &tt::Subtree, +) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { let mut text = String::new(); for (i, t) in tt.token_trees.iter().enumerate() { match t { @@ -266,6 +272,40 @@ fn concat_expand(tt: &tt::Subtree) -> Result<(tt::Subtree, FragmentKind), mbe::E Ok((quote!(#text), FragmentKind::Expr)) } +fn relative_file(db: &dyn AstDatabase, call_id: MacroCallId, path: &str) -> Option { + let call_site = call_id.as_file().original_file(db); + let path = RelativePath::new(&path); + + db.resolve_relative_path(call_site, &path) +} + +fn include_expand( + db: &dyn AstDatabase, + arg_id: EagerMacroId, + tt: &tt::Subtree, +) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { + let path = tt + .token_trees + .get(0) + .and_then(|tt| match tt { + tt::TokenTree::Leaf(tt::Leaf::Literal(it)) => unquote_str(&it), + _ => None, + }) + .ok_or_else(|| mbe::ExpandError::ConversionError)?; + + let file_id = + relative_file(db, arg_id.into(), &path).ok_or_else(|| mbe::ExpandError::ConversionError)?; + + // FIXME: + // Handle include as expression + let node = + db.parse_or_expand(file_id.into()).ok_or_else(|| mbe::ExpandError::ConversionError)?; + let res = + mbe::syntax_node_to_token_tree(&node).ok_or_else(|| mbe::ExpandError::ConversionError)?.0; + + Ok((res, FragmentKind::Items)) +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/ra_hir_expand/src/eager.rs b/crates/ra_hir_expand/src/eager.rs index f95f37ede..2e6dd3dd8 100644 --- a/crates/ra_hir_expand/src/eager.rs +++ b/crates/ra_hir_expand/src/eager.rs @@ -42,24 +42,26 @@ pub fn expand_eager_macro( // When `lazy_expand` is called, its *parent* file must be already exists. // Here we store an eager macro id for the argument expanded subtree here // for that purpose. - let arg_id: MacroCallId = db - .intern_eager_expansion({ - EagerCallLoc { - def, - fragment: FragmentKind::Expr, - subtree: Arc::new(parsed_args.clone()), - file_id: macro_call.file_id, - } - }) - .into(); + let arg_id = db.intern_eager_expansion({ + EagerCallLoc { + def, + fragment: FragmentKind::Expr, + subtree: Arc::new(parsed_args.clone()), + file_id: macro_call.file_id, + } + }); + let arg_file_id: MacroCallId = arg_id.into(); let parsed_args = mbe::token_tree_to_syntax_node(&parsed_args, FragmentKind::Expr).ok()?.0; - let result = - eager_macro_recur(db, InFile::new(arg_id.as_file(), parsed_args.syntax_node()), resolver)?; + let result = eager_macro_recur( + db, + InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()), + resolver, + )?; let subtree = to_subtree(&result)?; if let MacroDefKind::BuiltInEager(eager) = def.kind { - let (subtree, fragment) = eager.expand(&subtree).ok()?; + let (subtree, fragment) = eager.expand(db, arg_id, &subtree).ok()?; let eager = EagerCallLoc { def, fragment, subtree: Arc::new(subtree), file_id: macro_call.file_id }; diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs index 036cf7d1e..6d201256f 100644 --- a/crates/ra_hir_expand/src/name.rs +++ b/crates/ra_hir_expand/src/name.rs @@ -174,6 +174,7 @@ pub mod known { line, stringify, concat, + include, format_args, format_args_nl, env, diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 5d0efa0f4..42814941f 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs @@ -438,6 +438,51 @@ fn main() { ); } +#[test] +fn infer_builtin_macros_include() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs +#[rustc_builtin_macro] +macro_rules! include {() => {}} + +include!("foo.rs"); + +fn main() { + bar()<|>; +} + +//- /foo.rs +fn bar() -> u32 {0} +"#, + ); + assert_eq!("u32", type_at_pos(&db, pos)); +} + +#[test] +fn infer_builtin_macros_include_concat() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs +#[rustc_builtin_macro] +macro_rules! include {() => {}} + +#[rustc_builtin_macro] +macro_rules! concat {() => {}} + +include!(concat!("f", "oo.rs")); + +fn main() { + bar()<|>; +} + +//- /foo.rs +fn bar() -> u32 {0} +"#, + ); + assert_eq!("u32", type_at_pos(&db, pos)); +} + #[test] fn infer_builtin_macros_concat_with_lazy() { assert_snapshot!( -- cgit v1.2.3