aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_expand/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_expand/src/lib.rs')
-rw-r--r--crates/ra_hir_expand/src/lib.rs44
1 files changed, 30 insertions, 14 deletions
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index 5927a03ba..57e2e6cb1 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -18,8 +18,9 @@ use std::sync::Arc;
18 18
19use ra_db::{salsa, CrateId, FileId}; 19use ra_db::{salsa, CrateId, FileId};
20use ra_syntax::{ 20use ra_syntax::{
21 algo,
21 ast::{self, AstNode}, 22 ast::{self, AstNode},
22 SyntaxNode, TextRange, TextUnit, 23 SyntaxNode, SyntaxToken, TextRange, TextUnit,
23}; 24};
24 25
25use crate::ast_id_map::FileAstId; 26use crate::ast_id_map::FileAstId;
@@ -83,13 +84,21 @@ impl HirFileId {
83 loc.def.ast_id.to_node(db).token_tree()?.syntax().text_range().start(); 84 loc.def.ast_id.to_node(db).token_tree()?.syntax().text_range().start();
84 85
85 let macro_def = db.macro_def(loc.def)?; 86 let macro_def = db.macro_def(loc.def)?;
86 let exp_map = db.parse_macro(macro_file)?.1; 87 let (parse, exp_map) = db.parse_macro(macro_file)?;
88 let expanded = Source::new(self, parse.syntax_node());
87 let macro_arg = db.macro_arg(macro_file.macro_call_id)?; 89 let macro_arg = db.macro_arg(macro_file.macro_call_id)?;
88 90
89 let arg_start = (loc.ast_id.file_id, arg_start); 91 let arg_start = (loc.ast_id.file_id, arg_start);
90 let def_start = (loc.def.ast_id.file_id, def_start); 92 let def_start = (loc.def.ast_id.file_id, def_start);
91 93
92 Some(ExpansionInfo { arg_start, def_start, macro_arg, macro_def, exp_map }) 94 Some(ExpansionInfo {
95 expanded,
96 arg_start,
97 def_start,
98 macro_arg,
99 macro_def,
100 exp_map,
101 })
93 } 102 }
94 } 103 }
95 } 104 }
@@ -146,27 +155,34 @@ impl MacroCallId {
146 } 155 }
147} 156}
148 157
149#[derive(Debug, Clone, PartialEq, Eq)]
150/// ExpansionInfo mainly describes how to map text range between src and expanded macro 158/// ExpansionInfo mainly describes how to map text range between src and expanded macro
159#[derive(Debug, Clone, PartialEq, Eq)]
151pub struct ExpansionInfo { 160pub struct ExpansionInfo {
152 pub(crate) arg_start: (HirFileId, TextUnit), 161 expanded: Source<SyntaxNode>,
153 pub(crate) def_start: (HirFileId, TextUnit), 162 arg_start: (HirFileId, TextUnit),
163 def_start: (HirFileId, TextUnit),
154 164
155 pub(crate) macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>, 165 macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>,
156 pub(crate) macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>, 166 macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>,
157 pub(crate) exp_map: Arc<mbe::RevTokenMap>, 167 exp_map: Arc<mbe::RevTokenMap>,
158} 168}
159 169
160impl ExpansionInfo { 170impl ExpansionInfo {
161 pub fn translate_offset(&self, offset: TextUnit) -> Option<TextUnit> { 171 pub fn map_token_down(&self, token: Source<&SyntaxToken>) -> Option<Source<SyntaxToken>> {
162 let offset = offset.checked_sub(self.arg_start.1)?; 172 assert_eq!(token.file_id, self.arg_start.0);
163 let token_id = self.macro_arg.1.token_by_offset(offset)?; 173 let range = token.ast.text_range().checked_sub(self.arg_start.1)?;
174 let token_id = self.macro_arg.1.token_by_range(range)?;
164 let token_id = self.macro_def.0.map_id_down(token_id); 175 let token_id = self.macro_def.0.map_id_down(token_id);
165 176
166 let (r, _) = self.exp_map.ranges.iter().find(|(_, tid)| *tid == token_id)?; 177 let range = self.exp_map.range_by_token(token_id)?;
167 Some(r.start()) 178
179 let token = algo::find_covering_element(&self.expanded.ast, range).into_token()?;
180
181 Some(self.expanded.with_ast(token))
168 } 182 }
169 183
184 // FIXME: a more correct signature would be
185 // `pub fn map_token_up(&self, token: Source<&SyntaxToken>) -> Option<Source<SyntaxToken>>`
170 pub fn find_range(&self, from: TextRange) -> Option<(HirFileId, TextRange)> { 186 pub fn find_range(&self, from: TextRange) -> Option<(HirFileId, TextRange)> {
171 let token_id = look_in_rev_map(&self.exp_map, from)?; 187 let token_id = look_in_rev_map(&self.exp_map, from)?;
172 188