diff options
author | Aleksey Kladov <[email protected]> | 2019-11-16 13:49:26 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-11-16 14:00:54 +0000 |
commit | 2eaa8c94a8a6b5cd86139c5e010ae95268b28658 (patch) | |
tree | ba86bbb6e4e82fb1a85ab6a830173c00f2415d5e /crates | |
parent | 786cae520ad62c9a0a13f5ab18e5bd7e5b0c9825 (diff) |
Goto definition works inside macros
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 23 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/lib.rs | 9 | ||||
-rw-r--r-- | crates/ra_ide_api/src/goto_definition.rs | 50 | ||||
-rw-r--r-- | crates/ra_mbe/src/syntax_bridge.rs | 6 |
4 files changed, 77 insertions, 11 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 5764dc26d..75a467fb3 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -11,7 +11,7 @@ use hir_def::{ | |||
11 | expr::{ExprId, PatId}, | 11 | expr::{ExprId, PatId}, |
12 | path::known, | 12 | path::known, |
13 | }; | 13 | }; |
14 | use hir_expand::{name::AsName, Source}; | 14 | use hir_expand::{name::AsName, AstId, MacroCallId, MacroCallLoc, MacroFileKind, Source}; |
15 | use ra_syntax::{ | 15 | use ra_syntax::{ |
16 | ast::{self, AstNode}, | 16 | ast::{self, AstNode}, |
17 | match_ast, AstPtr, | 17 | match_ast, AstPtr, |
@@ -126,6 +126,20 @@ pub struct ReferenceDescriptor { | |||
126 | pub name: String, | 126 | pub name: String, |
127 | } | 127 | } |
128 | 128 | ||
129 | pub struct Expansion { | ||
130 | macro_call_id: MacroCallId, | ||
131 | } | ||
132 | |||
133 | impl Expansion { | ||
134 | pub fn translate_offset(&self, db: &impl HirDatabase, offset: TextUnit) -> Option<TextUnit> { | ||
135 | let exp_info = self.file_id().expansion_info(db)?; | ||
136 | exp_info.translate_offset(offset) | ||
137 | } | ||
138 | pub fn file_id(&self) -> HirFileId { | ||
139 | self.macro_call_id.as_file(MacroFileKind::Items) | ||
140 | } | ||
141 | } | ||
142 | |||
129 | impl SourceAnalyzer { | 143 | impl SourceAnalyzer { |
130 | pub fn new( | 144 | pub fn new( |
131 | db: &impl HirDatabase, | 145 | db: &impl HirDatabase, |
@@ -386,6 +400,13 @@ impl SourceAnalyzer { | |||
386 | implements_trait(&canonical_ty, db, &self.resolver, krate, std_future_trait) | 400 | implements_trait(&canonical_ty, db, &self.resolver, krate, std_future_trait) |
387 | } | 401 | } |
388 | 402 | ||
403 | pub fn expand(&self, db: &impl HirDatabase, macro_call: &ast::MacroCall) -> Option<Expansion> { | ||
404 | let def = self.resolve_macro_call(db, macro_call)?.id; | ||
405 | let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(macro_call)); | ||
406 | let macro_call_loc = MacroCallLoc { def, ast_id }; | ||
407 | Some(Expansion { macro_call_id: db.intern_macro(macro_call_loc) }) | ||
408 | } | ||
409 | |||
389 | #[cfg(test)] | 410 | #[cfg(test)] |
390 | pub(crate) fn body_source_map(&self) -> Arc<BodySourceMap> { | 411 | pub(crate) fn body_source_map(&self) -> Arc<BodySourceMap> { |
391 | self.body_source_map.clone().unwrap() | 412 | self.body_source_map.clone().unwrap() |
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 26531cb05..6bfbb2f79 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs | |||
@@ -160,6 +160,15 @@ pub struct ExpansionInfo { | |||
160 | } | 160 | } |
161 | 161 | ||
162 | impl ExpansionInfo { | 162 | impl ExpansionInfo { |
163 | pub fn translate_offset(&self, offset: TextUnit) -> Option<TextUnit> { | ||
164 | let offset = offset.checked_sub(self.arg_start.1)?; | ||
165 | let token_id = self.macro_arg.1.token_by_offset(offset)?; | ||
166 | let token_id = tt::TokenId(token_id.0 + self.shift); | ||
167 | |||
168 | let (r, _) = self.exp_map.ranges.iter().find(|(_, tid)| *tid == token_id)?; | ||
169 | Some(r.start()) | ||
170 | } | ||
171 | |||
163 | pub fn find_range(&self, from: TextRange) -> Option<(HirFileId, TextRange)> { | 172 | pub fn find_range(&self, from: TextRange) -> Option<(HirFileId, TextRange)> { |
164 | let token_id = look_in_rev_map(&self.exp_map, from)?; | 173 | let token_id = look_in_rev_map(&self.exp_map, from)?; |
165 | 174 | ||
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index 821796e5f..4b1581499 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs | |||
@@ -1,11 +1,10 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::Source; | 3 | use hir::{db::AstDatabase, Source}; |
4 | use ra_db::SourceDatabase; | ||
5 | use ra_syntax::{ | 4 | use ra_syntax::{ |
6 | algo::find_node_at_offset, | 5 | algo::find_node_at_offset, |
7 | ast::{self, DocCommentsOwner}, | 6 | ast::{self, DocCommentsOwner}, |
8 | match_ast, AstNode, SyntaxNode, | 7 | match_ast, AstNode, SyntaxNode, TextUnit, |
9 | }; | 8 | }; |
10 | 9 | ||
11 | use crate::{ | 10 | use crate::{ |
@@ -19,17 +18,29 @@ pub(crate) fn goto_definition( | |||
19 | db: &RootDatabase, | 18 | db: &RootDatabase, |
20 | position: FilePosition, | 19 | position: FilePosition, |
21 | ) -> Option<RangeInfo<Vec<NavigationTarget>>> { | 20 | ) -> Option<RangeInfo<Vec<NavigationTarget>>> { |
22 | let parse = db.parse(position.file_id); | 21 | go(db, Source::new(position.file_id.into(), position.offset)) |
23 | let syntax = parse.tree().syntax().clone(); | 22 | } |
24 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(&syntax, position.offset) { | 23 | |
25 | let navs = | 24 | fn go(db: &RootDatabase, offset: Source<TextUnit>) -> Option<RangeInfo<Vec<NavigationTarget>>> { |
26 | reference_definition(db, Source::new(position.file_id.into(), &name_ref)).to_vec(); | 25 | let syntax = db.parse_or_expand(offset.file_id)?; |
26 | |||
27 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(&syntax, offset.ast) { | ||
28 | let navs = reference_definition(db, offset.with_ast(&name_ref)).to_vec(); | ||
27 | return Some(RangeInfo::new(name_ref.syntax().text_range(), navs.to_vec())); | 29 | return Some(RangeInfo::new(name_ref.syntax().text_range(), navs.to_vec())); |
28 | } | 30 | } |
29 | if let Some(name) = find_node_at_offset::<ast::Name>(&syntax, position.offset) { | 31 | if let Some(name) = find_node_at_offset::<ast::Name>(&syntax, offset.ast) { |
30 | let navs = name_definition(db, Source::new(position.file_id.into(), &name))?; | 32 | let navs = name_definition(db, offset.with_ast(&name))?; |
31 | return Some(RangeInfo::new(name.syntax().text_range(), navs)); | 33 | return Some(RangeInfo::new(name.syntax().text_range(), navs)); |
32 | } | 34 | } |
35 | if let Some(macro_call) = find_node_at_offset::<ast::MacroCall>(&syntax, offset.ast) { | ||
36 | let source_analyzer = | ||
37 | hir::SourceAnalyzer::new(db, offset.with_ast(macro_call.syntax()), None); | ||
38 | if let Some(exp) = source_analyzer.expand(db, ¯o_call) { | ||
39 | if let Some(offset) = exp.translate_offset(db, offset.ast) { | ||
40 | return go(db, Source::new(exp.file_id(), offset)); | ||
41 | } | ||
42 | } | ||
43 | } | ||
33 | None | 44 | None |
34 | } | 45 | } |
35 | 46 | ||
@@ -677,4 +688,23 @@ mod tests { | |||
677 | "bar MODULE FileId(1) [0; 11) [4; 7)", | 688 | "bar MODULE FileId(1) [0; 11) [4; 7)", |
678 | ); | 689 | ); |
679 | } | 690 | } |
691 | |||
692 | #[test] | ||
693 | fn goto_from_macro() { | ||
694 | check_goto( | ||
695 | " | ||
696 | //- /lib.rs | ||
697 | macro_rules! id { | ||
698 | ($($tt:tt)*) => { $($tt)* } | ||
699 | } | ||
700 | fn foo() {} | ||
701 | id! { | ||
702 | fn bar() { | ||
703 | fo<|>o(); | ||
704 | } | ||
705 | } | ||
706 | ", | ||
707 | "foo FN_DEF FileId(1) [52; 63) [55; 58)", | ||
708 | ); | ||
709 | } | ||
680 | } | 710 | } |
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs index 3f57ce3b5..37382d2df 100644 --- a/crates/ra_mbe/src/syntax_bridge.rs +++ b/crates/ra_mbe/src/syntax_bridge.rs | |||
@@ -77,6 +77,12 @@ pub fn token_tree_to_syntax_node( | |||
77 | } | 77 | } |
78 | 78 | ||
79 | impl TokenMap { | 79 | impl TokenMap { |
80 | pub fn token_by_offset(&self, relative_offset: TextUnit) -> Option<tt::TokenId> { | ||
81 | let (idx, _) = | ||
82 | self.tokens.iter().enumerate().find(|(_, range)| range.contains(relative_offset))?; | ||
83 | Some(tt::TokenId(idx as u32)) | ||
84 | } | ||
85 | |||
80 | pub fn relative_range_of(&self, tt: tt::TokenId) -> Option<TextRange> { | 86 | pub fn relative_range_of(&self, tt: tt::TokenId) -> Option<TextRange> { |
81 | let idx = tt.0 as usize; | 87 | let idx = tt.0 as usize; |
82 | self.tokens.get(idx).copied() | 88 | self.tokens.get(idx).copied() |