diff options
author | Aleksey Kladov <[email protected]> | 2019-11-17 17:15:55 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-11-17 17:15:55 +0000 |
commit | fd52d721e1ed9794048d63e546f43805d24d7ab8 (patch) | |
tree | 4a57f22e985709c4206fb95fda04367a8e90b5a3 /crates/ra_hir_expand | |
parent | c8f858d04323f93a4bacb143d92c976b2bc1e179 (diff) |
More correct expansion mapping
We can't really map arbitrary ranges, we only can map tokens
Diffstat (limited to 'crates/ra_hir_expand')
-rw-r--r-- | crates/ra_hir_expand/src/lib.rs | 44 |
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 | ||
19 | use ra_db::{salsa, CrateId, FileId}; | 19 | use ra_db::{salsa, CrateId, FileId}; |
20 | use ra_syntax::{ | 20 | use 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 | ||
25 | use crate::ast_id_map::FileAstId; | 26 | use 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)] | ||
151 | pub struct ExpansionInfo { | 160 | pub 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 | ||
160 | impl ExpansionInfo { | 170 | impl 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 | ||