diff options
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 23 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/lib.rs | 18 | ||||
-rw-r--r-- | crates/ra_ide/src/goto_definition.rs | 27 |
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 | ||
92 | fn 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)] | ||
138 | pub struct Expansion { | 151 | pub 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 | } |