diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs index 44510f2b7f..08c924d0e9 100644 --- a/crates/hir-expand/src/builtin_fn_macro.rs +++ b/crates/hir-expand/src/builtin_fn_macro.rs @@ -3,7 +3,7 @@ use base_db::{AnchoredPath, Edition, FileId}; use cfg::CfgExpr; use either::Either; -use mbe::{parse_exprs_with_sep, parse_to_token_tree}; +use mbe::{parse_exprs_with_sep, parse_to_token_tree, TokenMap}; use syntax::{ ast::{self, AstToken}, SmolStr, @@ -67,7 +67,7 @@ macro_rules! register_builtin { pub struct ExpandedEager { pub(crate) subtree: tt::Subtree, /// The included file ID of the include macro. - pub(crate) included_file: Option, + pub(crate) included_file: Option<(FileId, TokenMap)>, } impl ExpandedEager { @@ -566,14 +566,14 @@ fn include_expand( let path = parse_string(tt)?; let file_id = relative_file(db, arg_id, &path, false)?; - let subtree = - parse_to_token_tree(&db.file_text(file_id)).ok_or(mbe::ExpandError::ConversionError)?.0; - Ok((subtree, file_id)) + let (subtree, map) = + parse_to_token_tree(&db.file_text(file_id)).ok_or(mbe::ExpandError::ConversionError)?; + Ok((subtree, map, file_id)) })(); match res { - Ok((subtree, file_id)) => { - ExpandResult::ok(ExpandedEager { subtree, included_file: Some(file_id) }) + Ok((subtree, map, file_id)) => { + ExpandResult::ok(ExpandedEager { subtree, included_file: Some((file_id, map)) }) } Err(e) => ExpandResult::with_err( ExpandedEager { subtree: tt::Subtree::empty(), included_file: None }, diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index 45572499e8..37c3661540 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -13,10 +13,11 @@ use syntax::{ }; use crate::{ - ast_id_map::AstIdMap, builtin_attr_macro::pseudo_derive_attr_expansion, fixup, - hygiene::HygieneFrame, tt, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, - ExpandError, ExpandResult, ExpandTo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, - MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander, + ast_id_map::AstIdMap, builtin_attr_macro::pseudo_derive_attr_expansion, + builtin_fn_macro::EagerExpander, fixup, hygiene::HygieneFrame, tt, BuiltinAttrExpander, + BuiltinDeriveExpander, BuiltinFnLikeExpander, ExpandError, ExpandResult, ExpandTo, HirFileId, + HirFileIdRepr, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, + ProcMacroExpander, }; /// Total limit on the number of tokens produced by any macro invocation. @@ -33,6 +34,8 @@ pub enum TokenExpander { DeclarativeMacro { mac: mbe::DeclarativeMacro, def_site_token_map: mbe::TokenMap }, /// Stuff like `line!` and `file!`. Builtin(BuiltinFnLikeExpander), + /// Built-in eagerly expanded fn-like macros (`include!`, `concat!`, etc.) + BuiltinEager(EagerExpander), /// `global_allocator` and such. BuiltinAttr(BuiltinAttrExpander), /// `derive(Copy)` and such. @@ -51,6 +54,9 @@ impl TokenExpander { match self { TokenExpander::DeclarativeMacro { mac, .. } => mac.expand(tt).map_err(Into::into), TokenExpander::Builtin(it) => it.expand(db, id, tt).map_err(Into::into), + TokenExpander::BuiltinEager(it) => { + it.expand(db, id, tt).map_err(Into::into).map(|res| res.subtree) + } TokenExpander::BuiltinAttr(it) => it.expand(db, id, tt), TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt), TokenExpander::ProcMacro(_) => { @@ -66,6 +72,7 @@ impl TokenExpander { match self { TokenExpander::DeclarativeMacro { mac, .. } => mac.map_id_down(id), TokenExpander::Builtin(..) + | TokenExpander::BuiltinEager(..) | TokenExpander::BuiltinAttr(..) | TokenExpander::BuiltinDerive(..) | TokenExpander::ProcMacro(..) => id, @@ -76,6 +83,7 @@ impl TokenExpander { match self { TokenExpander::DeclarativeMacro { mac, .. } => mac.map_id_up(id), TokenExpander::Builtin(..) + | TokenExpander::BuiltinEager(..) | TokenExpander::BuiltinAttr(..) | TokenExpander::BuiltinDerive(..) | TokenExpander::ProcMacro(..) => (id, mbe::Origin::Call), @@ -412,10 +420,8 @@ fn macro_def( MacroDefKind::BuiltInDerive(expander, _) => { Ok(Arc::new(TokenExpander::BuiltinDerive(expander))) } - MacroDefKind::BuiltInEager(..) => { - // FIXME: Return a random error here just to make the types align. - // This obviously should do something real instead. - Err(mbe::ParseError::UnexpectedToken("unexpected eager macro".into())) + MacroDefKind::BuiltInEager(expander, ..) => { + Ok(Arc::new(TokenExpander::BuiltinEager(expander))) } MacroDefKind::ProcMacro(expander, ..) => Ok(Arc::new(TokenExpander::ProcMacro(expander))), } diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index 929dabcaf6..d26fdbf7d6 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -20,6 +20,7 @@ pub mod mod_path; pub mod attrs; mod fixup; +use mbe::TokenMap; pub use mbe::{Origin, ValueResult}; use ::tt::token_id as tt; @@ -139,7 +140,7 @@ pub enum MacroDefKind { struct EagerCallInfo { /// NOTE: This can be *either* the expansion result, *or* the argument to the eager macro! arg_or_expansion: Arc, - included_file: Option, + included_file: Option<(FileId, TokenMap)>, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -206,7 +207,7 @@ impl HirFileId { HirFileIdRepr::MacroFile(MacroFile { macro_call_id }) => { let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_call_id); file_id = match loc.eager { - Some(EagerCallInfo { included_file: Some(file), .. }) => file.into(), + Some(EagerCallInfo { included_file: Some((file, _)), .. }) => file.into(), _ => loc.kind.file_id(), }; } @@ -319,7 +320,7 @@ impl HirFileId { match self.macro_file() { Some(macro_file) => { let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - matches!(loc.eager, Some(EagerCallInfo { included_file: Some(_), .. })) + matches!(loc.eager, Some(EagerCallInfo { included_file: Some(..), .. })) } _ => false, } @@ -677,6 +678,16 @@ impl ExpansionInfo { let call_id = self.expanded.file_id.macro_file()?.macro_call_id; let loc = db.lookup_intern_macro_call(call_id); + if let Some((file, map)) = loc.eager.and_then(|e| e.included_file) { + // Special case: map tokens from `include!` expansions to the included file + let range = map.first_range_by_token(token_id, token.value.kind())?; + let source = db.parse(file); + + let token = source.syntax_node().covering_element(range).into_token()?; + + return Some((InFile::new(file.into(), token), Origin::Call)); + } + // Attributes are a bit special for us, they have two inputs, the input tokentree and the annotated item. let (token_map, tt) = match &loc.kind { MacroCallKind::Attr { attr_args, is_derive: true, .. } => { diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index cf0819a252..004c33a8a7 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs @@ -833,8 +833,7 @@ fn test() { #[rustc_builtin_macro] macro_rules! include {} - include!("foo.rs"); -//^^^^^^^^^^^^^^^^^^^ +include!("foo.rs"); fn f() { foo$0(); @@ -846,6 +845,7 @@ mod confuse_index { //- /foo.rs fn foo() {} + //^^^ "#, ); }