diff options
author | Seivan Heidari <[email protected]> | 2019-11-18 01:27:53 +0000 |
---|---|---|
committer | Seivan Heidari <[email protected]> | 2019-11-18 01:27:53 +0000 |
commit | 166636ba77adcf5bf2c4ef935e9aa75e20f25e10 (patch) | |
tree | 168be1ca55c73b016e20586c08417c608450c92c /crates/ra_hir_expand | |
parent | cb26df950699586b314731fb70786e0db8eaa049 (diff) | |
parent | 28c2d74b2150102a8756a5357a5a965d7610bd15 (diff) |
Merge branch 'master' of https://github.com/rust-analyzer/rust-analyzer into feature/themes
Diffstat (limited to 'crates/ra_hir_expand')
-rw-r--r-- | crates/ra_hir_expand/Cargo.toml | 3 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/db.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/lib.rs | 70 |
3 files changed, 66 insertions, 20 deletions
diff --git a/crates/ra_hir_expand/Cargo.toml b/crates/ra_hir_expand/Cargo.toml index 8f29bf7d9..c60152a79 100644 --- a/crates/ra_hir_expand/Cargo.toml +++ b/crates/ra_hir_expand/Cargo.toml | |||
@@ -4,6 +4,9 @@ name = "ra_hir_expand" | |||
4 | version = "0.1.0" | 4 | version = "0.1.0" |
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | 6 | ||
7 | [lib] | ||
8 | doctest = false | ||
9 | |||
7 | [dependencies] | 10 | [dependencies] |
8 | log = "0.4.5" | 11 | log = "0.4.5" |
9 | 12 | ||
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index 5eadee9c2..9de7c1ea8 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs | |||
@@ -32,10 +32,17 @@ impl TokenExpander { | |||
32 | } | 32 | } |
33 | } | 33 | } |
34 | 34 | ||
35 | pub fn shift(&self) -> u32 { | 35 | pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId { |
36 | match self { | 36 | match self { |
37 | TokenExpander::MacroRules(it) => it.shift(), | 37 | TokenExpander::MacroRules(it) => it.map_id_down(id), |
38 | TokenExpander::Builtin(_) => 0, | 38 | TokenExpander::Builtin(..) => id, |
39 | } | ||
40 | } | ||
41 | |||
42 | pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) { | ||
43 | match self { | ||
44 | TokenExpander::MacroRules(it) => it.map_id_up(id), | ||
45 | TokenExpander::Builtin(..) => (id, mbe::Origin::Def), | ||
39 | } | 46 | } |
40 | } | 47 | } |
41 | } | 48 | } |
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 930789b0f..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,14 +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 shift = macro_def.0.shift(); | 87 | let (parse, exp_map) = db.parse_macro(macro_file)?; |
87 | let exp_map = db.parse_macro(macro_file)?.1; | 88 | let expanded = Source::new(self, parse.syntax_node()); |
88 | let macro_arg = db.macro_arg(macro_file.macro_call_id)?; | 89 | let macro_arg = db.macro_arg(macro_file.macro_call_id)?; |
89 | 90 | ||
90 | let arg_start = (loc.ast_id.file_id, arg_start); | 91 | let arg_start = (loc.ast_id.file_id, arg_start); |
91 | let def_start = (loc.def.ast_id.file_id, def_start); | 92 | let def_start = (loc.def.ast_id.file_id, def_start); |
92 | 93 | ||
93 | Some(ExpansionInfo { arg_start, def_start, macro_arg, macro_def, exp_map, shift }) | 94 | Some(ExpansionInfo { |
95 | expanded, | ||
96 | arg_start, | ||
97 | def_start, | ||
98 | macro_arg, | ||
99 | macro_def, | ||
100 | exp_map, | ||
101 | }) | ||
94 | } | 102 | } |
95 | } | 103 | } |
96 | } | 104 | } |
@@ -147,26 +155,42 @@ impl MacroCallId { | |||
147 | } | 155 | } |
148 | } | 156 | } |
149 | 157 | ||
150 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
151 | /// 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)] | ||
152 | pub struct ExpansionInfo { | 160 | pub struct ExpansionInfo { |
153 | pub(crate) arg_start: (HirFileId, TextUnit), | 161 | expanded: Source<SyntaxNode>, |
154 | pub(crate) def_start: (HirFileId, TextUnit), | 162 | arg_start: (HirFileId, TextUnit), |
155 | pub(crate) shift: u32, | 163 | def_start: (HirFileId, TextUnit), |
156 | 164 | ||
157 | pub(crate) macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>, | 165 | macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>, |
158 | pub(crate) macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>, | 166 | macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>, |
159 | pub(crate) exp_map: Arc<mbe::RevTokenMap>, | 167 | exp_map: Arc<mbe::RevTokenMap>, |
160 | } | 168 | } |
161 | 169 | ||
162 | impl ExpansionInfo { | 170 | impl ExpansionInfo { |
171 | pub fn map_token_down(&self, token: Source<&SyntaxToken>) -> Option<Source<SyntaxToken>> { | ||
172 | assert_eq!(token.file_id, self.arg_start.0); | ||
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)?; | ||
175 | let token_id = self.macro_def.0.map_id_down(token_id); | ||
176 | |||
177 | let range = self.exp_map.range_by_token(token_id)?; | ||
178 | |||
179 | let token = algo::find_covering_element(&self.expanded.ast, range).into_token()?; | ||
180 | |||
181 | Some(self.expanded.with_ast(token)) | ||
182 | } | ||
183 | |||
184 | // FIXME: a more correct signature would be | ||
185 | // `pub fn map_token_up(&self, token: Source<&SyntaxToken>) -> Option<Source<SyntaxToken>>` | ||
163 | pub fn find_range(&self, from: TextRange) -> Option<(HirFileId, TextRange)> { | 186 | pub fn find_range(&self, from: TextRange) -> Option<(HirFileId, TextRange)> { |
164 | let token_id = look_in_rev_map(&self.exp_map, from)?; | 187 | let token_id = look_in_rev_map(&self.exp_map, from)?; |
165 | 188 | ||
166 | let (token_map, (file_id, start_offset), token_id) = if token_id.0 >= self.shift { | 189 | let (token_id, origin) = self.macro_def.0.map_id_up(token_id); |
167 | (&self.macro_arg.1, self.arg_start, tt::TokenId(token_id.0 - self.shift).into()) | 190 | |
168 | } else { | 191 | let (token_map, (file_id, start_offset)) = match origin { |
169 | (&self.macro_def.1, self.def_start, token_id) | 192 | mbe::Origin::Call => (&self.macro_arg.1, self.arg_start), |
193 | mbe::Origin::Def => (&self.macro_def.1, self.def_start), | ||
170 | }; | 194 | }; |
171 | 195 | ||
172 | let range = token_map.relative_range_of(token_id)?; | 196 | let range = token_map.relative_range_of(token_id)?; |
@@ -223,18 +247,30 @@ impl<N: AstNode> AstId<N> { | |||
223 | } | 247 | } |
224 | } | 248 | } |
225 | 249 | ||
250 | /// FIXME: https://github.com/matklad/with ? | ||
226 | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] | 251 | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] |
227 | pub struct Source<T> { | 252 | pub struct Source<T> { |
228 | pub file_id: HirFileId, | 253 | pub file_id: HirFileId, |
254 | // FIXME: this stores all kind of things, not only `ast`. | ||
255 | // There should be a better name... | ||
229 | pub ast: T, | 256 | pub ast: T, |
230 | } | 257 | } |
231 | 258 | ||
232 | impl<T> Source<T> { | 259 | impl<T> Source<T> { |
260 | pub fn new(file_id: HirFileId, ast: T) -> Source<T> { | ||
261 | Source { file_id, ast } | ||
262 | } | ||
263 | |||
264 | // Similarly, naming here is stupid... | ||
265 | pub fn with_ast<U>(&self, ast: U) -> Source<U> { | ||
266 | Source::new(self.file_id, ast) | ||
267 | } | ||
268 | |||
233 | pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { | 269 | pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { |
234 | Source { file_id: self.file_id, ast: f(self.ast) } | 270 | Source::new(self.file_id, f(self.ast)) |
235 | } | 271 | } |
236 | pub fn as_ref(&self) -> Source<&T> { | 272 | pub fn as_ref(&self) -> Source<&T> { |
237 | Source { file_id: self.file_id, ast: &self.ast } | 273 | self.with_ast(&self.ast) |
238 | } | 274 | } |
239 | pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode { | 275 | pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode { |
240 | db.parse_or_expand(self.file_id).expect("source created from invalid file") | 276 | db.parse_or_expand(self.file_id).expect("source created from invalid file") |