aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/source_binder.rs23
-rw-r--r--crates/ra_hir_expand/src/lib.rs18
-rw-r--r--crates/ra_ide/src/goto_definition.rs27
3 files changed, 63 insertions, 5 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 42c392513..cb4345ca1 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -76,18 +76,30 @@ fn def_with_body_from_child_node(
76 db: &impl HirDatabase, 76 db: &impl HirDatabase,
77 child: InFile<&SyntaxNode>, 77 child: InFile<&SyntaxNode>,
78) -> Option<DefWithBody> { 78) -> Option<DefWithBody> {
79 child.value.ancestors().find_map(|node| { 79 ancestors_with_macros(db, child).find_map(|node| {
80 let n = &node.value;
80 match_ast! { 81 match_ast! {
81 match node { 82 match n {
82 ast::FnDef(def) => { return Function::from_source(db, child.with_value(def)).map(DefWithBody::from); }, 83 ast::FnDef(def) => { return Function::from_source(db, node.with_value(def)).map(DefWithBody::from); },
83 ast::ConstDef(def) => { return Const::from_source(db, child.with_value(def)).map(DefWithBody::from); }, 84 ast::ConstDef(def) => { return Const::from_source(db, node.with_value(def)).map(DefWithBody::from); },
84 ast::StaticDef(def) => { return Static::from_source(db, child.with_value(def)).map(DefWithBody::from); }, 85 ast::StaticDef(def) => { return Static::from_source(db, node.with_value(def)).map(DefWithBody::from); },
85 _ => { None }, 86 _ => { None },
86 } 87 }
87 } 88 }
88 }) 89 })
89} 90}
90 91
92fn ancestors_with_macros<'a>(
93 db: &'a (impl HirDatabase),
94 node: InFile<&SyntaxNode>,
95) -> impl Iterator<Item = InFile<SyntaxNode>> + 'a {
96 let file = node.with_value(()); // keep just the file id for borrow checker purposes
97 let parent_node = node.file_id.call_node(db);
98 let parent_ancestors: Box<dyn Iterator<Item = InFile<SyntaxNode>>> =
99 Box::new(parent_node.into_iter().flat_map(move |n| ancestors_with_macros(db, n.as_ref())));
100 node.value.ancestors().map(move |n| file.with_value(n)).chain(parent_ancestors)
101}
102
91/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of 103/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
92/// original source files. It should not be used inside the HIR itself. 104/// original source files. It should not be used inside the HIR itself.
93#[derive(Debug)] 105#[derive(Debug)]
@@ -135,6 +147,7 @@ pub struct ReferenceDescriptor {
135 pub name: String, 147 pub name: String,
136} 148}
137 149
150#[derive(Debug)]
138pub struct Expansion { 151pub struct Expansion {
139 macro_file_kind: MacroFileKind, 152 macro_file_kind: MacroFileKind,
140 macro_call_id: MacroCallId, 153 macro_call_id: MacroCallId,
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index 59c69b91b..0c1dc87e6 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -76,6 +76,17 @@ impl HirFileId {
76 } 76 }
77 } 77 }
78 78
79 /// If this is a macro call, returns the syntax node of the call.
80 pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> {
81 match self.0 {
82 HirFileIdRepr::FileId(_) => None,
83 HirFileIdRepr::MacroFile(macro_file) => {
84 let loc = db.lookup_intern_macro(macro_file.macro_call_id);
85 Some(loc.kind.node(db))
86 }
87 }
88 }
89
79 /// Return expansion information if it is a macro-expansion file 90 /// Return expansion information if it is a macro-expansion file
80 pub fn expansion_info(self, db: &dyn db::AstDatabase) -> Option<ExpansionInfo> { 91 pub fn expansion_info(self, db: &dyn db::AstDatabase) -> Option<ExpansionInfo> {
81 match self.0 { 92 match self.0 {
@@ -176,6 +187,13 @@ impl MacroCallKind {
176 } 187 }
177 } 188 }
178 189
190 pub fn node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> {
191 match self {
192 MacroCallKind::FnLike(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()),
193 MacroCallKind::Attr(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()),
194 }
195 }
196
179 pub fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> { 197 pub fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> {
180 match self { 198 match self {
181 MacroCallKind::FnLike(ast_id) => { 199 MacroCallKind::FnLike(ast_id) => {
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
index 76a741207..b1d567ca7 100644
--- a/crates/ra_ide/src/goto_definition.rs
+++ b/crates/ra_ide/src/goto_definition.rs
@@ -693,4 +693,31 @@ mod tests {
693 "foo FN_DEF FileId(1) [52; 63) [55; 58)", 693 "foo FN_DEF FileId(1) [52; 63) [55; 58)",
694 ); 694 );
695 } 695 }
696
697 #[test]
698 fn goto_through_format() {
699 check_goto(
700 "
701 //- /lib.rs
702 #[macro_export]
703 macro_rules! format {
704 ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))
705 }
706 #[rustc_builtin_macro]
707 #[macro_export]
708 macro_rules! format_args {
709 ($fmt:expr) => ({ /* compiler built-in */ });
710 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
711 }
712 pub mod __export {
713 pub use crate::format_args;
714 }
715 fn foo() -> i8 {}
716 fn test() {
717 format!(\"{}\", fo<|>o())
718 }
719 ",
720 "foo FN_DEF FileId(1) [359; 376) [362; 365)",
721 );
722 }
696} 723}