diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir_expand/src/db.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/lib.rs | 55 | ||||
-rw-r--r-- | crates/ra_ide_api/src/display/navigation_target.rs | 99 | ||||
-rw-r--r-- | crates/ra_ide_api/src/expand.rs | 59 | ||||
-rw-r--r-- | crates/ra_ide_api/src/goto_definition.rs | 60 | ||||
-rw-r--r-- | crates/ra_ide_api/src/hover.rs | 4 | ||||
-rw-r--r-- | crates/ra_ide_api/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_ide_api/src/references.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide_api/src/references/classify.rs | 38 | ||||
-rw-r--r-- | crates/ra_ide_api/src/syntax_highlighting.rs | 3 | ||||
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_mbe/src/syntax_bridge.rs | 206 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/extensions.rs | 12 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 1 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 3 |
15 files changed, 273 insertions, 280 deletions
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index 9de7c1ea8..3c11c8a22 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs | |||
@@ -59,10 +59,8 @@ pub trait AstDatabase: SourceDatabase { | |||
59 | fn intern_macro(&self, macro_call: MacroCallLoc) -> MacroCallId; | 59 | fn intern_macro(&self, macro_call: MacroCallLoc) -> MacroCallId; |
60 | fn macro_arg(&self, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>>; | 60 | fn macro_arg(&self, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>>; |
61 | fn macro_def(&self, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>>; | 61 | fn macro_def(&self, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>>; |
62 | fn parse_macro( | 62 | fn parse_macro(&self, macro_file: MacroFile) |
63 | &self, | 63 | -> Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>; |
64 | macro_file: MacroFile, | ||
65 | ) -> Option<(Parse<SyntaxNode>, Arc<mbe::RevTokenMap>)>; | ||
66 | fn macro_expand(&self, macro_call: MacroCallId) -> Result<Arc<tt::Subtree>, String>; | 64 | fn macro_expand(&self, macro_call: MacroCallId) -> Result<Arc<tt::Subtree>, String>; |
67 | } | 65 | } |
68 | 66 | ||
@@ -136,7 +134,7 @@ pub(crate) fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Optio | |||
136 | pub(crate) fn parse_macro( | 134 | pub(crate) fn parse_macro( |
137 | db: &dyn AstDatabase, | 135 | db: &dyn AstDatabase, |
138 | macro_file: MacroFile, | 136 | macro_file: MacroFile, |
139 | ) -> Option<(Parse<SyntaxNode>, Arc<mbe::RevTokenMap>)> { | 137 | ) -> Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)> { |
140 | let _p = profile("parse_macro_query"); | 138 | let _p = profile("parse_macro_query"); |
141 | 139 | ||
142 | let macro_call_id = macro_file.macro_call_id; | 140 | let macro_call_id = macro_file.macro_call_id; |
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 57e2e6cb1..cfe7e6d15 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs | |||
@@ -20,7 +20,7 @@ use ra_db::{salsa, CrateId, FileId}; | |||
20 | use ra_syntax::{ | 20 | use ra_syntax::{ |
21 | algo, | 21 | algo, |
22 | ast::{self, AstNode}, | 22 | ast::{self, AstNode}, |
23 | SyntaxNode, SyntaxToken, TextRange, TextUnit, | 23 | SyntaxNode, SyntaxToken, TextUnit, |
24 | }; | 24 | }; |
25 | 25 | ||
26 | use crate::ast_id_map::FileAstId; | 26 | use crate::ast_id_map::FileAstId; |
@@ -79,22 +79,17 @@ impl HirFileId { | |||
79 | HirFileIdRepr::MacroFile(macro_file) => { | 79 | HirFileIdRepr::MacroFile(macro_file) => { |
80 | let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id); | 80 | let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id); |
81 | 81 | ||
82 | let arg_start = loc.ast_id.to_node(db).token_tree()?.syntax().text_range().start(); | 82 | let arg_tt = loc.ast_id.to_node(db).token_tree()?; |
83 | let def_start = | 83 | let def_tt = loc.def.ast_id.to_node(db).token_tree()?; |
84 | loc.def.ast_id.to_node(db).token_tree()?.syntax().text_range().start(); | ||
85 | 84 | ||
86 | let macro_def = db.macro_def(loc.def)?; | 85 | let macro_def = db.macro_def(loc.def)?; |
87 | let (parse, exp_map) = db.parse_macro(macro_file)?; | 86 | let (parse, exp_map) = db.parse_macro(macro_file)?; |
88 | let expanded = Source::new(self, parse.syntax_node()); | ||
89 | let macro_arg = db.macro_arg(macro_file.macro_call_id)?; | 87 | let macro_arg = db.macro_arg(macro_file.macro_call_id)?; |
90 | 88 | ||
91 | let arg_start = (loc.ast_id.file_id, arg_start); | ||
92 | let def_start = (loc.def.ast_id.file_id, def_start); | ||
93 | |||
94 | Some(ExpansionInfo { | 89 | Some(ExpansionInfo { |
95 | expanded, | 90 | expanded: Source::new(self, parse.syntax_node()), |
96 | arg_start, | 91 | arg: Source::new(loc.ast_id.file_id, arg_tt), |
97 | def_start, | 92 | def: Source::new(loc.ast_id.file_id, def_tt), |
98 | macro_arg, | 93 | macro_arg, |
99 | macro_def, | 94 | macro_def, |
100 | exp_map, | 95 | exp_map, |
@@ -159,18 +154,19 @@ impl MacroCallId { | |||
159 | #[derive(Debug, Clone, PartialEq, Eq)] | 154 | #[derive(Debug, Clone, PartialEq, Eq)] |
160 | pub struct ExpansionInfo { | 155 | pub struct ExpansionInfo { |
161 | expanded: Source<SyntaxNode>, | 156 | expanded: Source<SyntaxNode>, |
162 | arg_start: (HirFileId, TextUnit), | 157 | arg: Source<ast::TokenTree>, |
163 | def_start: (HirFileId, TextUnit), | 158 | def: Source<ast::TokenTree>, |
164 | 159 | ||
165 | macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>, | 160 | macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>, |
166 | macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>, | 161 | macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>, |
167 | exp_map: Arc<mbe::RevTokenMap>, | 162 | exp_map: Arc<mbe::TokenMap>, |
168 | } | 163 | } |
169 | 164 | ||
170 | impl ExpansionInfo { | 165 | impl ExpansionInfo { |
171 | pub fn map_token_down(&self, token: Source<&SyntaxToken>) -> Option<Source<SyntaxToken>> { | 166 | pub fn map_token_down(&self, token: Source<&SyntaxToken>) -> Option<Source<SyntaxToken>> { |
172 | assert_eq!(token.file_id, self.arg_start.0); | 167 | assert_eq!(token.file_id, self.arg.file_id); |
173 | let range = token.ast.text_range().checked_sub(self.arg_start.1)?; | 168 | let range = |
169 | token.ast.text_range().checked_sub(self.arg.ast.syntax().text_range().start())?; | ||
174 | let token_id = self.macro_arg.1.token_by_range(range)?; | 170 | let token_id = self.macro_arg.1.token_by_range(range)?; |
175 | let token_id = self.macro_def.0.map_id_down(token_id); | 171 | let token_id = self.macro_def.0.map_id_down(token_id); |
176 | 172 | ||
@@ -181,25 +177,22 @@ impl ExpansionInfo { | |||
181 | Some(self.expanded.with_ast(token)) | 177 | Some(self.expanded.with_ast(token)) |
182 | } | 178 | } |
183 | 179 | ||
184 | // FIXME: a more correct signature would be | 180 | pub fn map_token_up(&self, token: Source<&SyntaxToken>) -> Option<Source<SyntaxToken>> { |
185 | // `pub fn map_token_up(&self, token: Source<&SyntaxToken>) -> Option<Source<SyntaxToken>>` | 181 | let token_id = self.exp_map.token_by_range(token.ast.text_range())?; |
186 | pub fn find_range(&self, from: TextRange) -> Option<(HirFileId, TextRange)> { | ||
187 | let token_id = look_in_rev_map(&self.exp_map, from)?; | ||
188 | 182 | ||
189 | let (token_id, origin) = self.macro_def.0.map_id_up(token_id); | 183 | let (token_id, origin) = self.macro_def.0.map_id_up(token_id); |
190 | 184 | let (token_map, tt) = match origin { | |
191 | let (token_map, (file_id, start_offset)) = match origin { | 185 | mbe::Origin::Call => (&self.macro_arg.1, &self.arg), |
192 | mbe::Origin::Call => (&self.macro_arg.1, self.arg_start), | 186 | mbe::Origin::Def => (&self.macro_def.1, &self.def), |
193 | mbe::Origin::Def => (&self.macro_def.1, self.def_start), | ||
194 | }; | 187 | }; |
195 | 188 | ||
196 | let range = token_map.relative_range_of(token_id)?; | 189 | let range = token_map.range_by_token(token_id)?; |
197 | 190 | let token = algo::find_covering_element( | |
198 | return Some((file_id, range + start_offset)); | 191 | tt.ast.syntax(), |
199 | 192 | range + tt.ast.syntax().text_range().start(), | |
200 | fn look_in_rev_map(exp_map: &mbe::RevTokenMap, from: TextRange) -> Option<tt::TokenId> { | 193 | ) |
201 | exp_map.ranges.iter().find(|&it| it.0.is_subrange(&from)).map(|it| it.1) | 194 | .into_token()?; |
202 | } | 195 | Some(tt.with_ast(token)) |
203 | } | 196 | } |
204 | } | 197 | } |
205 | 198 | ||
diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs index f7ad08515..b30ef8e05 100644 --- a/crates/ra_ide_api/src/display/navigation_target.rs +++ b/crates/ra_ide_api/src/display/navigation_target.rs | |||
@@ -1,16 +1,17 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::{AssocItem, Either, FieldSource, HasSource, ModuleSource}; | 3 | use hir::{AssocItem, Either, FieldSource, HasSource, ModuleSource, Source}; |
4 | use ra_db::{FileId, SourceDatabase}; | 4 | use ra_db::{FileId, SourceDatabase}; |
5 | use ra_syntax::{ | 5 | use ra_syntax::{ |
6 | ast::{self, DocCommentsOwner, NameOwner}, | 6 | ast::{self, DocCommentsOwner, NameOwner}, |
7 | match_ast, AstNode, SmolStr, | 7 | match_ast, AstNode, SmolStr, |
8 | SyntaxKind::{self, BIND_PAT}, | 8 | SyntaxKind::{self, BIND_PAT}, |
9 | SyntaxNode, TextRange, | 9 | TextRange, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::{db::RootDatabase, expand::original_range, FileSymbol}; | ||
13 | |||
12 | use super::short_label::ShortLabel; | 14 | use super::short_label::ShortLabel; |
13 | use crate::{db::RootDatabase, FileSymbol}; | ||
14 | 15 | ||
15 | /// `NavigationTarget` represents and element in the editor's UI which you can | 16 | /// `NavigationTarget` represents and element in the editor's UI which you can |
16 | /// click on to navigate to a particular piece of code. | 17 | /// click on to navigate to a particular piece of code. |
@@ -79,13 +80,13 @@ impl NavigationTarget { | |||
79 | pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { | 80 | pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { |
80 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); | 81 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); |
81 | if let Some(src) = module.declaration_source(db) { | 82 | if let Some(src) = module.declaration_source(db) { |
82 | let (file_id, text_range) = find_range_from_node(db, src.file_id, src.ast.syntax()); | 83 | let frange = original_range(db, src.as_ref().map(|it| it.syntax())); |
83 | return NavigationTarget::from_syntax( | 84 | return NavigationTarget::from_syntax( |
84 | file_id, | 85 | frange.file_id, |
85 | name, | 86 | name, |
86 | None, | 87 | None, |
87 | text_range, | 88 | frange.range, |
88 | src.ast.syntax(), | 89 | src.ast.syntax().kind(), |
89 | src.ast.doc_comment_text(), | 90 | src.ast.doc_comment_text(), |
90 | src.ast.short_label(), | 91 | src.ast.short_label(), |
91 | ); | 92 | ); |
@@ -140,22 +141,22 @@ impl NavigationTarget { | |||
140 | /// Allows `NavigationTarget` to be created from a `NameOwner` | 141 | /// Allows `NavigationTarget` to be created from a `NameOwner` |
141 | pub(crate) fn from_named( | 142 | pub(crate) fn from_named( |
142 | db: &RootDatabase, | 143 | db: &RootDatabase, |
143 | file_id: hir::HirFileId, | 144 | node: Source<&dyn ast::NameOwner>, |
144 | node: &impl ast::NameOwner, | ||
145 | docs: Option<String>, | 145 | docs: Option<String>, |
146 | description: Option<String>, | 146 | description: Option<String>, |
147 | ) -> NavigationTarget { | 147 | ) -> NavigationTarget { |
148 | //FIXME: use `_` instead of empty string | 148 | //FIXME: use `_` instead of empty string |
149 | let name = node.name().map(|it| it.text().clone()).unwrap_or_default(); | 149 | let name = node.ast.name().map(|it| it.text().clone()).unwrap_or_default(); |
150 | let focus_range = node.name().map(|it| find_range_from_node(db, file_id, it.syntax()).1); | 150 | let focus_range = |
151 | let (file_id, full_range) = find_range_from_node(db, file_id, node.syntax()); | 151 | node.ast.name().map(|it| original_range(db, node.with_ast(it.syntax())).range); |
152 | let frange = original_range(db, node.map(|it| it.syntax())); | ||
152 | 153 | ||
153 | NavigationTarget::from_syntax( | 154 | NavigationTarget::from_syntax( |
154 | file_id, | 155 | frange.file_id, |
155 | name, | 156 | name, |
156 | focus_range, | 157 | focus_range, |
157 | full_range, | 158 | frange.range, |
158 | node.syntax(), | 159 | node.ast.syntax().kind(), |
159 | docs, | 160 | docs, |
160 | description, | 161 | description, |
161 | ) | 162 | ) |
@@ -166,14 +167,14 @@ impl NavigationTarget { | |||
166 | name: SmolStr, | 167 | name: SmolStr, |
167 | focus_range: Option<TextRange>, | 168 | focus_range: Option<TextRange>, |
168 | full_range: TextRange, | 169 | full_range: TextRange, |
169 | node: &SyntaxNode, | 170 | kind: SyntaxKind, |
170 | docs: Option<String>, | 171 | docs: Option<String>, |
171 | description: Option<String>, | 172 | description: Option<String>, |
172 | ) -> NavigationTarget { | 173 | ) -> NavigationTarget { |
173 | NavigationTarget { | 174 | NavigationTarget { |
174 | file_id, | 175 | file_id, |
175 | name, | 176 | name, |
176 | kind: node.kind(), | 177 | kind, |
177 | full_range, | 178 | full_range, |
178 | focus_range, | 179 | focus_range, |
179 | container_name: None, | 180 | container_name: None, |
@@ -218,8 +219,7 @@ where | |||
218 | let src = self.source(db); | 219 | let src = self.source(db); |
219 | NavigationTarget::from_named( | 220 | NavigationTarget::from_named( |
220 | db, | 221 | db, |
221 | src.file_id, | 222 | src.as_ref().map(|it| it as &dyn ast::NameOwner), |
222 | &src.ast, | ||
223 | src.ast.doc_comment_text(), | 223 | src.ast.doc_comment_text(), |
224 | src.ast.short_label(), | 224 | src.ast.short_label(), |
225 | ) | 225 | ) |
@@ -230,29 +230,29 @@ impl ToNav for hir::Module { | |||
230 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 230 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { |
231 | let src = self.definition_source(db); | 231 | let src = self.definition_source(db); |
232 | let name = self.name(db).map(|it| it.to_string().into()).unwrap_or_default(); | 232 | let name = self.name(db).map(|it| it.to_string().into()).unwrap_or_default(); |
233 | match src.ast { | 233 | match &src.ast { |
234 | ModuleSource::SourceFile(node) => { | 234 | ModuleSource::SourceFile(node) => { |
235 | let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax()); | 235 | let frange = original_range(db, src.with_ast(node.syntax())); |
236 | 236 | ||
237 | NavigationTarget::from_syntax( | 237 | NavigationTarget::from_syntax( |
238 | file_id, | 238 | frange.file_id, |
239 | name, | 239 | name, |
240 | None, | 240 | None, |
241 | text_range, | 241 | frange.range, |
242 | node.syntax(), | 242 | node.syntax().kind(), |
243 | None, | 243 | None, |
244 | None, | 244 | None, |
245 | ) | 245 | ) |
246 | } | 246 | } |
247 | ModuleSource::Module(node) => { | 247 | ModuleSource::Module(node) => { |
248 | let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax()); | 248 | let frange = original_range(db, src.with_ast(node.syntax())); |
249 | 249 | ||
250 | NavigationTarget::from_syntax( | 250 | NavigationTarget::from_syntax( |
251 | file_id, | 251 | frange.file_id, |
252 | name, | 252 | name, |
253 | None, | 253 | None, |
254 | text_range, | 254 | frange.range, |
255 | node.syntax(), | 255 | node.syntax().kind(), |
256 | node.doc_comment_text(), | 256 | node.doc_comment_text(), |
257 | node.short_label(), | 257 | node.short_label(), |
258 | ) | 258 | ) |
@@ -264,14 +264,14 @@ impl ToNav for hir::Module { | |||
264 | impl ToNav for hir::ImplBlock { | 264 | impl ToNav for hir::ImplBlock { |
265 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 265 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { |
266 | let src = self.source(db); | 266 | let src = self.source(db); |
267 | let (file_id, text_range) = find_range_from_node(db, src.file_id, src.ast.syntax()); | 267 | let frange = original_range(db, src.as_ref().map(|it| it.syntax())); |
268 | 268 | ||
269 | NavigationTarget::from_syntax( | 269 | NavigationTarget::from_syntax( |
270 | file_id, | 270 | frange.file_id, |
271 | "impl".into(), | 271 | "impl".into(), |
272 | None, | 272 | None, |
273 | text_range, | 273 | frange.range, |
274 | src.ast.syntax(), | 274 | src.ast.syntax().kind(), |
275 | None, | 275 | None, |
276 | None, | 276 | None, |
277 | ) | 277 | ) |
@@ -282,22 +282,21 @@ impl ToNav for hir::StructField { | |||
282 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 282 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { |
283 | let src = self.source(db); | 283 | let src = self.source(db); |
284 | 284 | ||
285 | match src.ast { | 285 | match &src.ast { |
286 | FieldSource::Named(it) => NavigationTarget::from_named( | 286 | FieldSource::Named(it) => NavigationTarget::from_named( |
287 | db, | 287 | db, |
288 | src.file_id, | 288 | src.with_ast(it), |
289 | &it, | ||
290 | it.doc_comment_text(), | 289 | it.doc_comment_text(), |
291 | it.short_label(), | 290 | it.short_label(), |
292 | ), | 291 | ), |
293 | FieldSource::Pos(it) => { | 292 | FieldSource::Pos(it) => { |
294 | let (file_id, text_range) = find_range_from_node(db, src.file_id, it.syntax()); | 293 | let frange = original_range(db, src.with_ast(it.syntax())); |
295 | NavigationTarget::from_syntax( | 294 | NavigationTarget::from_syntax( |
296 | file_id, | 295 | frange.file_id, |
297 | "".into(), | 296 | "".into(), |
298 | None, | 297 | None, |
299 | text_range, | 298 | frange.range, |
300 | it.syntax(), | 299 | it.syntax().kind(), |
301 | None, | 300 | None, |
302 | None, | 301 | None, |
303 | ) | 302 | ) |
@@ -310,7 +309,12 @@ impl ToNav for hir::MacroDef { | |||
310 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 309 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { |
311 | let src = self.source(db); | 310 | let src = self.source(db); |
312 | log::debug!("nav target {:#?}", src.ast.syntax()); | 311 | log::debug!("nav target {:#?}", src.ast.syntax()); |
313 | NavigationTarget::from_named(db, src.file_id, &src.ast, src.ast.doc_comment_text(), None) | 312 | NavigationTarget::from_named( |
313 | db, | ||
314 | src.as_ref().map(|it| it as &dyn ast::NameOwner), | ||
315 | src.ast.doc_comment_text(), | ||
316 | None, | ||
317 | ) | ||
314 | } | 318 | } |
315 | } | 319 | } |
316 | 320 | ||
@@ -360,21 +364,6 @@ impl ToNav for hir::Local { | |||
360 | } | 364 | } |
361 | } | 365 | } |
362 | 366 | ||
363 | fn find_range_from_node( | ||
364 | db: &RootDatabase, | ||
365 | src: hir::HirFileId, | ||
366 | node: &SyntaxNode, | ||
367 | ) -> (FileId, TextRange) { | ||
368 | let text_range = node.text_range(); | ||
369 | let (file_id, text_range) = src | ||
370 | .expansion_info(db) | ||
371 | .and_then(|expansion_info| expansion_info.find_range(text_range)) | ||
372 | .unwrap_or((src, text_range)); | ||
373 | |||
374 | // FIXME: handle recursive macro generated macro | ||
375 | (file_id.original_file(db), text_range) | ||
376 | } | ||
377 | |||
378 | pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> { | 367 | pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> { |
379 | let parse = db.parse(symbol.file_id); | 368 | let parse = db.parse(symbol.file_id); |
380 | let node = symbol.ptr.to_node(parse.tree().syntax()); | 369 | let node = symbol.ptr.to_node(parse.tree().syntax()); |
diff --git a/crates/ra_ide_api/src/expand.rs b/crates/ra_ide_api/src/expand.rs new file mode 100644 index 000000000..7f59e46d2 --- /dev/null +++ b/crates/ra_ide_api/src/expand.rs | |||
@@ -0,0 +1,59 @@ | |||
1 | //! Utilities to work with files, produced by macros. | ||
2 | use std::iter::successors; | ||
3 | |||
4 | use hir::Source; | ||
5 | use ra_db::FileId; | ||
6 | use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxToken}; | ||
7 | |||
8 | use crate::{db::RootDatabase, FileRange}; | ||
9 | |||
10 | pub(crate) fn original_range(db: &RootDatabase, node: Source<&SyntaxNode>) -> FileRange { | ||
11 | let expansion = match node.file_id.expansion_info(db) { | ||
12 | None => { | ||
13 | return FileRange { | ||
14 | file_id: node.file_id.original_file(db), | ||
15 | range: node.ast.text_range(), | ||
16 | } | ||
17 | } | ||
18 | Some(it) => it, | ||
19 | }; | ||
20 | // FIXME: the following completely wrong. | ||
21 | // | ||
22 | // *First*, we should try to map first and last tokens of node, and, if that | ||
23 | // fails, return the range of the overall macro expansions. | ||
24 | // | ||
25 | // *Second*, we should handle recurside macro expansions | ||
26 | |||
27 | let token = node | ||
28 | .ast | ||
29 | .descendants_with_tokens() | ||
30 | .filter_map(|it| it.into_token()) | ||
31 | .find_map(|it| expansion.map_token_up(node.with_ast(&it))); | ||
32 | |||
33 | match token { | ||
34 | Some(it) => FileRange { file_id: it.file_id.original_file(db), range: it.ast.text_range() }, | ||
35 | None => FileRange { file_id: node.file_id.original_file(db), range: node.ast.text_range() }, | ||
36 | } | ||
37 | } | ||
38 | |||
39 | pub(crate) fn descend_into_macros( | ||
40 | db: &RootDatabase, | ||
41 | file_id: FileId, | ||
42 | token: SyntaxToken, | ||
43 | ) -> Source<SyntaxToken> { | ||
44 | let src = Source::new(file_id.into(), token); | ||
45 | |||
46 | successors(Some(src), |token| { | ||
47 | let macro_call = token.ast.ancestors().find_map(ast::MacroCall::cast)?; | ||
48 | let tt = macro_call.token_tree()?; | ||
49 | if !token.ast.text_range().is_subrange(&tt.syntax().text_range()) { | ||
50 | return None; | ||
51 | } | ||
52 | let source_analyzer = | ||
53 | hir::SourceAnalyzer::new(db, token.with_ast(token.ast.parent()).as_ref(), None); | ||
54 | let exp = source_analyzer.expand(db, ¯o_call)?; | ||
55 | exp.map_token_down(db, token.as_ref()) | ||
56 | }) | ||
57 | .last() | ||
58 | .unwrap() | ||
59 | } | ||
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index b693a4c31..3f16e9566 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs | |||
@@ -1,16 +1,15 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use std::iter::successors; | ||
4 | |||
5 | use hir::{db::AstDatabase, Source}; | 3 | use hir::{db::AstDatabase, Source}; |
6 | use ra_syntax::{ | 4 | use ra_syntax::{ |
7 | ast::{self, DocCommentsOwner}, | 5 | ast::{self, DocCommentsOwner}, |
8 | match_ast, AstNode, SyntaxNode, SyntaxToken, | 6 | match_ast, AstNode, SyntaxNode, |
9 | }; | 7 | }; |
10 | 8 | ||
11 | use crate::{ | 9 | use crate::{ |
12 | db::RootDatabase, | 10 | db::RootDatabase, |
13 | display::{ShortLabel, ToNav}, | 11 | display::{ShortLabel, ToNav}, |
12 | expand::descend_into_macros, | ||
14 | references::{classify_name_ref, NameKind::*}, | 13 | references::{classify_name_ref, NameKind::*}, |
15 | FilePosition, NavigationTarget, RangeInfo, | 14 | FilePosition, NavigationTarget, RangeInfo, |
16 | }; | 15 | }; |
@@ -19,7 +18,9 @@ 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 token = descend_into_macros(db, position)?; | 21 | let file = db.parse_or_expand(position.file_id.into())?; |
22 | let token = file.token_at_offset(position.offset).filter(|it| !it.kind().is_trivia()).next()?; | ||
23 | let token = descend_into_macros(db, position.file_id, token); | ||
23 | 24 | ||
24 | let res = match_ast! { | 25 | let res = match_ast! { |
25 | match (token.ast.parent()) { | 26 | match (token.ast.parent()) { |
@@ -39,24 +40,6 @@ pub(crate) fn goto_definition( | |||
39 | Some(res) | 40 | Some(res) |
40 | } | 41 | } |
41 | 42 | ||
42 | fn descend_into_macros(db: &RootDatabase, position: FilePosition) -> Option<Source<SyntaxToken>> { | ||
43 | let file = db.parse_or_expand(position.file_id.into())?; | ||
44 | let token = file.token_at_offset(position.offset).filter(|it| !it.kind().is_trivia()).next()?; | ||
45 | |||
46 | successors(Some(Source::new(position.file_id.into(), token)), |token| { | ||
47 | let macro_call = token.ast.ancestors().find_map(ast::MacroCall::cast)?; | ||
48 | let tt = macro_call.token_tree()?; | ||
49 | if !token.ast.text_range().is_subrange(&tt.syntax().text_range()) { | ||
50 | return None; | ||
51 | } | ||
52 | let source_analyzer = | ||
53 | hir::SourceAnalyzer::new(db, token.with_ast(token.ast.parent()).as_ref(), None); | ||
54 | let exp = source_analyzer.expand(db, ¯o_call)?; | ||
55 | exp.map_token_down(db, token.as_ref()) | ||
56 | }) | ||
57 | .last() | ||
58 | } | ||
59 | |||
60 | #[derive(Debug)] | 43 | #[derive(Debug)] |
61 | pub(crate) enum ReferenceResult { | 44 | pub(crate) enum ReferenceResult { |
62 | Exact(NavigationTarget), | 45 | Exact(NavigationTarget), |
@@ -137,8 +120,7 @@ fn named_target(db: &RootDatabase, node: Source<&SyntaxNode>) -> Option<Navigati | |||
137 | ast::StructDef(it) => { | 120 | ast::StructDef(it) => { |
138 | Some(NavigationTarget::from_named( | 121 | Some(NavigationTarget::from_named( |
139 | db, | 122 | db, |
140 | node.file_id, | 123 | node.with_ast(&it), |
141 | &it, | ||
142 | it.doc_comment_text(), | 124 | it.doc_comment_text(), |
143 | it.short_label(), | 125 | it.short_label(), |
144 | )) | 126 | )) |
@@ -146,8 +128,7 @@ fn named_target(db: &RootDatabase, node: Source<&SyntaxNode>) -> Option<Navigati | |||
146 | ast::EnumDef(it) => { | 128 | ast::EnumDef(it) => { |
147 | Some(NavigationTarget::from_named( | 129 | Some(NavigationTarget::from_named( |
148 | db, | 130 | db, |
149 | node.file_id, | 131 | node.with_ast(&it), |
150 | &it, | ||
151 | it.doc_comment_text(), | 132 | it.doc_comment_text(), |
152 | it.short_label(), | 133 | it.short_label(), |
153 | )) | 134 | )) |
@@ -155,8 +136,7 @@ fn named_target(db: &RootDatabase, node: Source<&SyntaxNode>) -> Option<Navigati | |||
155 | ast::EnumVariant(it) => { | 136 | ast::EnumVariant(it) => { |
156 | Some(NavigationTarget::from_named( | 137 | Some(NavigationTarget::from_named( |
157 | db, | 138 | db, |
158 | node.file_id, | 139 | node.with_ast(&it), |
159 | &it, | ||
160 | it.doc_comment_text(), | 140 | it.doc_comment_text(), |
161 | it.short_label(), | 141 | it.short_label(), |
162 | )) | 142 | )) |
@@ -164,8 +144,7 @@ fn named_target(db: &RootDatabase, node: Source<&SyntaxNode>) -> Option<Navigati | |||
164 | ast::FnDef(it) => { | 144 | ast::FnDef(it) => { |
165 | Some(NavigationTarget::from_named( | 145 | Some(NavigationTarget::from_named( |
166 | db, | 146 | db, |
167 | node.file_id, | 147 | node.with_ast(&it), |
168 | &it, | ||
169 | it.doc_comment_text(), | 148 | it.doc_comment_text(), |
170 | it.short_label(), | 149 | it.short_label(), |
171 | )) | 150 | )) |
@@ -173,8 +152,7 @@ fn named_target(db: &RootDatabase, node: Source<&SyntaxNode>) -> Option<Navigati | |||
173 | ast::TypeAliasDef(it) => { | 152 | ast::TypeAliasDef(it) => { |
174 | Some(NavigationTarget::from_named( | 153 | Some(NavigationTarget::from_named( |
175 | db, | 154 | db, |
176 | node.file_id, | 155 | node.with_ast(&it), |
177 | &it, | ||
178 | it.doc_comment_text(), | 156 | it.doc_comment_text(), |
179 | it.short_label(), | 157 | it.short_label(), |
180 | )) | 158 | )) |
@@ -182,8 +160,7 @@ fn named_target(db: &RootDatabase, node: Source<&SyntaxNode>) -> Option<Navigati | |||
182 | ast::ConstDef(it) => { | 160 | ast::ConstDef(it) => { |
183 | Some(NavigationTarget::from_named( | 161 | Some(NavigationTarget::from_named( |
184 | db, | 162 | db, |
185 | node.file_id, | 163 | node.with_ast(&it), |
186 | &it, | ||
187 | it.doc_comment_text(), | 164 | it.doc_comment_text(), |
188 | it.short_label(), | 165 | it.short_label(), |
189 | )) | 166 | )) |
@@ -191,8 +168,7 @@ fn named_target(db: &RootDatabase, node: Source<&SyntaxNode>) -> Option<Navigati | |||
191 | ast::StaticDef(it) => { | 168 | ast::StaticDef(it) => { |
192 | Some(NavigationTarget::from_named( | 169 | Some(NavigationTarget::from_named( |
193 | db, | 170 | db, |
194 | node.file_id, | 171 | node.with_ast(&it), |
195 | &it, | ||
196 | it.doc_comment_text(), | 172 | it.doc_comment_text(), |
197 | it.short_label(), | 173 | it.short_label(), |
198 | )) | 174 | )) |
@@ -200,8 +176,7 @@ fn named_target(db: &RootDatabase, node: Source<&SyntaxNode>) -> Option<Navigati | |||
200 | ast::TraitDef(it) => { | 176 | ast::TraitDef(it) => { |
201 | Some(NavigationTarget::from_named( | 177 | Some(NavigationTarget::from_named( |
202 | db, | 178 | db, |
203 | node.file_id, | 179 | node.with_ast(&it), |
204 | &it, | ||
205 | it.doc_comment_text(), | 180 | it.doc_comment_text(), |
206 | it.short_label(), | 181 | it.short_label(), |
207 | )) | 182 | )) |
@@ -209,8 +184,7 @@ fn named_target(db: &RootDatabase, node: Source<&SyntaxNode>) -> Option<Navigati | |||
209 | ast::RecordFieldDef(it) => { | 184 | ast::RecordFieldDef(it) => { |
210 | Some(NavigationTarget::from_named( | 185 | Some(NavigationTarget::from_named( |
211 | db, | 186 | db, |
212 | node.file_id, | 187 | node.with_ast(&it), |
213 | &it, | ||
214 | it.doc_comment_text(), | 188 | it.doc_comment_text(), |
215 | it.short_label(), | 189 | it.short_label(), |
216 | )) | 190 | )) |
@@ -218,8 +192,7 @@ fn named_target(db: &RootDatabase, node: Source<&SyntaxNode>) -> Option<Navigati | |||
218 | ast::Module(it) => { | 192 | ast::Module(it) => { |
219 | Some(NavigationTarget::from_named( | 193 | Some(NavigationTarget::from_named( |
220 | db, | 194 | db, |
221 | node.file_id, | 195 | node.with_ast(&it), |
222 | &it, | ||
223 | it.doc_comment_text(), | 196 | it.doc_comment_text(), |
224 | it.short_label(), | 197 | it.short_label(), |
225 | )) | 198 | )) |
@@ -227,8 +200,7 @@ fn named_target(db: &RootDatabase, node: Source<&SyntaxNode>) -> Option<Navigati | |||
227 | ast::MacroCall(it) => { | 200 | ast::MacroCall(it) => { |
228 | Some(NavigationTarget::from_named( | 201 | Some(NavigationTarget::from_named( |
229 | db, | 202 | db, |
230 | node.file_id, | 203 | node.with_ast(&it), |
231 | &it, | ||
232 | it.doc_comment_text(), | 204 | it.doc_comment_text(), |
233 | None, | 205 | None, |
234 | )) | 206 | )) |
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index cc25f4c37..c6d678c0c 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs | |||
@@ -193,7 +193,9 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
193 | None | 193 | None |
194 | } | 194 | } |
195 | } else if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), position.offset) { | 195 | } else if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), position.offset) { |
196 | if let Some(name_kind) = classify_name(db, position.file_id, &name).map(|d| d.kind) { | 196 | if let Some(name_kind) = |
197 | classify_name(db, Source::new(position.file_id.into(), &name)).map(|d| d.kind) | ||
198 | { | ||
197 | let mut _b: bool = true; | 199 | let mut _b: bool = true; |
198 | res.extend(hover_text_from_name_kind(db, name_kind, &mut _b)); | 200 | res.extend(hover_text_from_name_kind(db, name_kind, &mut _b)); |
199 | } | 201 | } |
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index 484fbcc82..110ddcd62 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs | |||
@@ -41,6 +41,7 @@ mod matching_brace; | |||
41 | mod display; | 41 | mod display; |
42 | mod inlay_hints; | 42 | mod inlay_hints; |
43 | mod wasm_shims; | 43 | mod wasm_shims; |
44 | mod expand; | ||
44 | 45 | ||
45 | #[cfg(test)] | 46 | #[cfg(test)] |
46 | mod marks; | 47 | mod marks; |
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index 1af7e8a9f..cb343e59a 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs | |||
@@ -110,7 +110,7 @@ fn find_name<'a>( | |||
110 | position: FilePosition, | 110 | position: FilePosition, |
111 | ) -> Option<RangeInfo<(String, NameDefinition)>> { | 111 | ) -> Option<RangeInfo<(String, NameDefinition)>> { |
112 | if let Some(name) = find_node_at_offset::<ast::Name>(&syntax, position.offset) { | 112 | if let Some(name) = find_node_at_offset::<ast::Name>(&syntax, position.offset) { |
113 | let def = classify_name(db, position.file_id, &name)?; | 113 | let def = classify_name(db, Source::new(position.file_id.into(), &name))?; |
114 | let range = name.syntax().text_range(); | 114 | let range = name.syntax().text_range(); |
115 | return Some(RangeInfo::new(range, (name.text().to_string(), def))); | 115 | return Some(RangeInfo::new(range, (name.text().to_string(), def))); |
116 | } | 116 | } |
diff --git a/crates/ra_ide_api/src/references/classify.rs b/crates/ra_ide_api/src/references/classify.rs index 5ca9da15e..ea9d20e71 100644 --- a/crates/ra_ide_api/src/references/classify.rs +++ b/crates/ra_ide_api/src/references/classify.rs | |||
@@ -1,7 +1,6 @@ | |||
1 | //! Functions that are used to classify an element from its definition or reference. | 1 | //! Functions that are used to classify an element from its definition or reference. |
2 | 2 | ||
3 | use hir::{FromSource, Module, ModuleSource, Path, PathResolution, Source, SourceAnalyzer}; | 3 | use hir::{FromSource, Module, ModuleSource, Path, PathResolution, Source, SourceAnalyzer}; |
4 | use ra_db::FileId; | ||
5 | use ra_prof::profile; | 4 | use ra_prof::profile; |
6 | use ra_syntax::{ast, match_ast, AstNode}; | 5 | use ra_syntax::{ast, match_ast, AstNode}; |
7 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
@@ -12,19 +11,14 @@ use super::{ | |||
12 | }; | 11 | }; |
13 | use crate::db::RootDatabase; | 12 | use crate::db::RootDatabase; |
14 | 13 | ||
15 | pub(crate) fn classify_name( | 14 | pub(crate) fn classify_name(db: &RootDatabase, name: Source<&ast::Name>) -> Option<NameDefinition> { |
16 | db: &RootDatabase, | ||
17 | file_id: FileId, | ||
18 | name: &ast::Name, | ||
19 | ) -> Option<NameDefinition> { | ||
20 | let _p = profile("classify_name"); | 15 | let _p = profile("classify_name"); |
21 | let parent = name.syntax().parent()?; | 16 | let parent = name.ast.syntax().parent()?; |
22 | let file_id = file_id.into(); | ||
23 | 17 | ||
24 | match_ast! { | 18 | match_ast! { |
25 | match parent { | 19 | match parent { |
26 | ast::BindPat(it) => { | 20 | ast::BindPat(it) => { |
27 | let src = hir::Source { file_id, ast: it }; | 21 | let src = name.with_ast(it); |
28 | let local = hir::Local::from_source(db, src)?; | 22 | let local = hir::Local::from_source(db, src)?; |
29 | Some(NameDefinition { | 23 | Some(NameDefinition { |
30 | visibility: None, | 24 | visibility: None, |
@@ -34,7 +28,7 @@ pub(crate) fn classify_name( | |||
34 | }, | 28 | }, |
35 | ast::RecordFieldDef(it) => { | 29 | ast::RecordFieldDef(it) => { |
36 | let ast = hir::FieldSource::Named(it); | 30 | let ast = hir::FieldSource::Named(it); |
37 | let src = hir::Source { file_id, ast }; | 31 | let src = name.with_ast(ast); |
38 | let field = hir::StructField::from_source(db, src)?; | 32 | let field = hir::StructField::from_source(db, src)?; |
39 | Some(from_struct_field(db, field)) | 33 | Some(from_struct_field(db, field)) |
40 | }, | 34 | }, |
@@ -42,42 +36,42 @@ pub(crate) fn classify_name( | |||
42 | let def = { | 36 | let def = { |
43 | if !it.has_semi() { | 37 | if !it.has_semi() { |
44 | let ast = hir::ModuleSource::Module(it); | 38 | let ast = hir::ModuleSource::Module(it); |
45 | let src = hir::Source { file_id, ast }; | 39 | let src = name.with_ast(ast); |
46 | hir::Module::from_definition(db, src) | 40 | hir::Module::from_definition(db, src) |
47 | } else { | 41 | } else { |
48 | let src = hir::Source { file_id, ast: it }; | 42 | let src = name.with_ast(it); |
49 | hir::Module::from_declaration(db, src) | 43 | hir::Module::from_declaration(db, src) |
50 | } | 44 | } |
51 | }?; | 45 | }?; |
52 | Some(from_module_def(db, def.into(), None)) | 46 | Some(from_module_def(db, def.into(), None)) |
53 | }, | 47 | }, |
54 | ast::StructDef(it) => { | 48 | ast::StructDef(it) => { |
55 | let src = hir::Source { file_id, ast: it }; | 49 | let src = name.with_ast(it); |
56 | let def = hir::Struct::from_source(db, src)?; | 50 | let def = hir::Struct::from_source(db, src)?; |
57 | Some(from_module_def(db, def.into(), None)) | 51 | Some(from_module_def(db, def.into(), None)) |
58 | }, | 52 | }, |
59 | ast::EnumDef(it) => { | 53 | ast::EnumDef(it) => { |
60 | let src = hir::Source { file_id, ast: it }; | 54 | let src = name.with_ast(it); |
61 | let def = hir::Enum::from_source(db, src)?; | 55 | let def = hir::Enum::from_source(db, src)?; |
62 | Some(from_module_def(db, def.into(), None)) | 56 | Some(from_module_def(db, def.into(), None)) |
63 | }, | 57 | }, |
64 | ast::TraitDef(it) => { | 58 | ast::TraitDef(it) => { |
65 | let src = hir::Source { file_id, ast: it }; | 59 | let src = name.with_ast(it); |
66 | let def = hir::Trait::from_source(db, src)?; | 60 | let def = hir::Trait::from_source(db, src)?; |
67 | Some(from_module_def(db, def.into(), None)) | 61 | Some(from_module_def(db, def.into(), None)) |
68 | }, | 62 | }, |
69 | ast::StaticDef(it) => { | 63 | ast::StaticDef(it) => { |
70 | let src = hir::Source { file_id, ast: it }; | 64 | let src = name.with_ast(it); |
71 | let def = hir::Static::from_source(db, src)?; | 65 | let def = hir::Static::from_source(db, src)?; |
72 | Some(from_module_def(db, def.into(), None)) | 66 | Some(from_module_def(db, def.into(), None)) |
73 | }, | 67 | }, |
74 | ast::EnumVariant(it) => { | 68 | ast::EnumVariant(it) => { |
75 | let src = hir::Source { file_id, ast: it }; | 69 | let src = name.with_ast(it); |
76 | let def = hir::EnumVariant::from_source(db, src)?; | 70 | let def = hir::EnumVariant::from_source(db, src)?; |
77 | Some(from_module_def(db, def.into(), None)) | 71 | Some(from_module_def(db, def.into(), None)) |
78 | }, | 72 | }, |
79 | ast::FnDef(it) => { | 73 | ast::FnDef(it) => { |
80 | let src = hir::Source { file_id, ast: it }; | 74 | let src = name.with_ast(it); |
81 | let def = hir::Function::from_source(db, src)?; | 75 | let def = hir::Function::from_source(db, src)?; |
82 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | 76 | if parent.parent().and_then(ast::ItemList::cast).is_some() { |
83 | Some(from_assoc_item(db, def.into())) | 77 | Some(from_assoc_item(db, def.into())) |
@@ -86,7 +80,7 @@ pub(crate) fn classify_name( | |||
86 | } | 80 | } |
87 | }, | 81 | }, |
88 | ast::ConstDef(it) => { | 82 | ast::ConstDef(it) => { |
89 | let src = hir::Source { file_id, ast: it }; | 83 | let src = name.with_ast(it); |
90 | let def = hir::Const::from_source(db, src)?; | 84 | let def = hir::Const::from_source(db, src)?; |
91 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | 85 | if parent.parent().and_then(ast::ItemList::cast).is_some() { |
92 | Some(from_assoc_item(db, def.into())) | 86 | Some(from_assoc_item(db, def.into())) |
@@ -95,7 +89,7 @@ pub(crate) fn classify_name( | |||
95 | } | 89 | } |
96 | }, | 90 | }, |
97 | ast::TypeAliasDef(it) => { | 91 | ast::TypeAliasDef(it) => { |
98 | let src = hir::Source { file_id, ast: it }; | 92 | let src = name.with_ast(it); |
99 | let def = hir::TypeAlias::from_source(db, src)?; | 93 | let def = hir::TypeAlias::from_source(db, src)?; |
100 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | 94 | if parent.parent().and_then(ast::ItemList::cast).is_some() { |
101 | Some(from_assoc_item(db, def.into())) | 95 | Some(from_assoc_item(db, def.into())) |
@@ -104,11 +98,11 @@ pub(crate) fn classify_name( | |||
104 | } | 98 | } |
105 | }, | 99 | }, |
106 | ast::MacroCall(it) => { | 100 | ast::MacroCall(it) => { |
107 | let src = hir::Source { file_id, ast: it}; | 101 | let src = name.with_ast(it); |
108 | let def = hir::MacroDef::from_source(db, src.clone())?; | 102 | let def = hir::MacroDef::from_source(db, src.clone())?; |
109 | 103 | ||
110 | let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax())); | 104 | let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax())); |
111 | let module = Module::from_definition(db, Source::new(file_id, module_src))?; | 105 | let module = Module::from_definition(db, src.with_ast(module_src))?; |
112 | 106 | ||
113 | Some(NameDefinition { | 107 | Some(NameDefinition { |
114 | visibility: None, | 108 | visibility: None, |
diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs index 584657ca2..2b653fe8f 100644 --- a/crates/ra_ide_api/src/syntax_highlighting.rs +++ b/crates/ra_ide_api/src/syntax_highlighting.rs | |||
@@ -94,7 +94,8 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa | |||
94 | } | 94 | } |
95 | NAME => { | 95 | NAME => { |
96 | let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap(); | 96 | let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap(); |
97 | let name_kind = classify_name(db, file_id, &name).map(|d| d.kind); | 97 | let name_kind = |
98 | classify_name(db, Source::new(file_id.into(), &name)).map(|d| d.kind); | ||
98 | 99 | ||
99 | if let Some(Local(local)) = &name_kind { | 100 | if let Some(Local(local)) = &name_kind { |
100 | if let Some(name) = local.name(db) { | 101 | if let Some(name) = local.name(db) { |
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index 58ca95368..bbddebe67 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs | |||
@@ -31,7 +31,7 @@ pub enum ExpandError { | |||
31 | } | 31 | } |
32 | 32 | ||
33 | pub use crate::syntax_bridge::{ | 33 | pub use crate::syntax_bridge::{ |
34 | ast_to_token_tree, syntax_node_to_token_tree, token_tree_to_syntax_node, RevTokenMap, TokenMap, | 34 | ast_to_token_tree, syntax_node_to_token_tree, token_tree_to_syntax_node, TokenMap, |
35 | }; | 35 | }; |
36 | 36 | ||
37 | /// This struct contains AST for a single `macro_rules` definition. What might | 37 | /// This struct contains AST for a single `macro_rules` definition. What might |
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs index 8398c9ac7..d1c49c0b3 100644 --- a/crates/ra_mbe/src/syntax_bridge.rs +++ b/crates/ra_mbe/src/syntax_bridge.rs | |||
@@ -14,30 +14,22 @@ use crate::ExpandError; | |||
14 | #[derive(Debug, PartialEq, Eq, Default)] | 14 | #[derive(Debug, PartialEq, Eq, Default)] |
15 | pub struct TokenMap { | 15 | pub struct TokenMap { |
16 | /// Maps `tt::TokenId` to the *relative* source range. | 16 | /// Maps `tt::TokenId` to the *relative* source range. |
17 | tokens: Vec<TextRange>, | 17 | entries: Vec<(tt::TokenId, TextRange)>, |
18 | } | ||
19 | |||
20 | /// Maps relative range of the expanded syntax node to `tt::TokenId` | ||
21 | #[derive(Debug, PartialEq, Eq, Default)] | ||
22 | pub struct RevTokenMap { | ||
23 | pub ranges: Vec<(TextRange, tt::TokenId)>, | ||
24 | } | 18 | } |
25 | 19 | ||
26 | /// Convert the syntax tree (what user has written) to a `TokenTree` (what macro | 20 | /// Convert the syntax tree (what user has written) to a `TokenTree` (what macro |
27 | /// will consume). | 21 | /// will consume). |
28 | pub fn ast_to_token_tree(ast: &ast::TokenTree) -> Option<(tt::Subtree, TokenMap)> { | 22 | pub fn ast_to_token_tree(ast: &ast::TokenTree) -> Option<(tt::Subtree, TokenMap)> { |
29 | let mut token_map = TokenMap::default(); | 23 | syntax_node_to_token_tree(ast.syntax()) |
30 | let node = ast.syntax(); | ||
31 | let tt = convert_tt(&mut token_map, node.text_range().start(), node)?; | ||
32 | Some((tt, token_map)) | ||
33 | } | 24 | } |
34 | 25 | ||
35 | /// Convert the syntax node to a `TokenTree` (what macro | 26 | /// Convert the syntax node to a `TokenTree` (what macro |
36 | /// will consume). | 27 | /// will consume). |
37 | pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> Option<(tt::Subtree, TokenMap)> { | 28 | pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> Option<(tt::Subtree, TokenMap)> { |
38 | let mut token_map = TokenMap::default(); | 29 | let global_offset = node.text_range().start(); |
39 | let tt = convert_tt(&mut token_map, node.text_range().start(), node)?; | 30 | let mut c = Convertor { map: TokenMap::default(), global_offset, next_id: 0 }; |
40 | Some((tt, token_map)) | 31 | let subtree = c.go(node)?; |
32 | Some((subtree, c.map)) | ||
41 | } | 33 | } |
42 | 34 | ||
43 | // The following items are what `rustc` macro can be parsed into : | 35 | // The following items are what `rustc` macro can be parsed into : |
@@ -55,7 +47,7 @@ pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> Option<(tt::Subtree, Toke | |||
55 | pub fn token_tree_to_syntax_node( | 47 | pub fn token_tree_to_syntax_node( |
56 | tt: &tt::Subtree, | 48 | tt: &tt::Subtree, |
57 | fragment_kind: FragmentKind, | 49 | fragment_kind: FragmentKind, |
58 | ) -> Result<(Parse<SyntaxNode>, RevTokenMap), ExpandError> { | 50 | ) -> Result<(Parse<SyntaxNode>, TokenMap), ExpandError> { |
59 | let tmp; | 51 | let tmp; |
60 | let tokens = match tt { | 52 | let tokens = match tt { |
61 | tt::Subtree { delimiter: tt::Delimiter::None, token_trees } => token_trees.as_slice(), | 53 | tt::Subtree { delimiter: tt::Delimiter::None, token_trees } => token_trees.as_slice(), |
@@ -78,31 +70,17 @@ pub fn token_tree_to_syntax_node( | |||
78 | 70 | ||
79 | impl TokenMap { | 71 | impl TokenMap { |
80 | pub fn token_by_range(&self, relative_range: TextRange) -> Option<tt::TokenId> { | 72 | pub fn token_by_range(&self, relative_range: TextRange) -> Option<tt::TokenId> { |
81 | let (idx, _) = | 73 | let &(token_id, _) = self.entries.iter().find(|(_, range)| *range == relative_range)?; |
82 | self.tokens.iter().enumerate().find(|(_, range)| **range == relative_range)?; | 74 | Some(token_id) |
83 | Some(tt::TokenId(idx as u32)) | ||
84 | } | ||
85 | |||
86 | pub fn relative_range_of(&self, token_id: tt::TokenId) -> Option<TextRange> { | ||
87 | let idx = token_id.0 as usize; | ||
88 | self.tokens.get(idx).copied() | ||
89 | } | ||
90 | |||
91 | fn alloc(&mut self, relative_range: TextRange) -> tt::TokenId { | ||
92 | let id = self.tokens.len(); | ||
93 | self.tokens.push(relative_range); | ||
94 | tt::TokenId(id as u32) | ||
95 | } | 75 | } |
96 | } | ||
97 | 76 | ||
98 | impl RevTokenMap { | ||
99 | pub fn range_by_token(&self, token_id: tt::TokenId) -> Option<TextRange> { | 77 | pub fn range_by_token(&self, token_id: tt::TokenId) -> Option<TextRange> { |
100 | let &(r, _) = self.ranges.iter().find(|(_, tid)| *tid == token_id)?; | 78 | let &(_, range) = self.entries.iter().find(|(tid, _)| *tid == token_id)?; |
101 | Some(r) | 79 | Some(range) |
102 | } | 80 | } |
103 | 81 | ||
104 | fn add(&mut self, relative_range: TextRange, token_id: tt::TokenId) { | 82 | fn insert(&mut self, token_id: tt::TokenId, relative_range: TextRange) { |
105 | self.ranges.push((relative_range, token_id.clone())) | 83 | self.entries.push((token_id, relative_range)); |
106 | } | 84 | } |
107 | } | 85 | } |
108 | 86 | ||
@@ -167,84 +145,98 @@ fn convert_doc_comment(token: &ra_syntax::SyntaxToken) -> Option<Vec<tt::TokenTr | |||
167 | } | 145 | } |
168 | } | 146 | } |
169 | 147 | ||
170 | fn convert_tt( | 148 | struct Convertor { |
171 | token_map: &mut TokenMap, | 149 | map: TokenMap, |
172 | global_offset: TextUnit, | 150 | global_offset: TextUnit, |
173 | tt: &SyntaxNode, | 151 | next_id: u32, |
174 | ) -> Option<tt::Subtree> { | 152 | } |
175 | // This tree is empty | ||
176 | if tt.first_child_or_token().is_none() { | ||
177 | return Some(tt::Subtree { token_trees: vec![], delimiter: tt::Delimiter::None }); | ||
178 | } | ||
179 | 153 | ||
180 | let first_child = tt.first_child_or_token()?; | 154 | impl Convertor { |
181 | let last_child = tt.last_child_or_token()?; | 155 | fn go(&mut self, tt: &SyntaxNode) -> Option<tt::Subtree> { |
182 | let (delimiter, skip_first) = match (first_child.kind(), last_child.kind()) { | 156 | // This tree is empty |
183 | (T!['('], T![')']) => (tt::Delimiter::Parenthesis, true), | 157 | if tt.first_child_or_token().is_none() { |
184 | (T!['{'], T!['}']) => (tt::Delimiter::Brace, true), | 158 | return Some(tt::Subtree { token_trees: vec![], delimiter: tt::Delimiter::None }); |
185 | (T!['['], T![']']) => (tt::Delimiter::Bracket, true), | 159 | } |
186 | _ => (tt::Delimiter::None, false), | ||
187 | }; | ||
188 | 160 | ||
189 | let mut token_trees = Vec::new(); | 161 | let first_child = tt.first_child_or_token()?; |
190 | let mut child_iter = tt.children_with_tokens().skip(skip_first as usize).peekable(); | 162 | let last_child = tt.last_child_or_token()?; |
163 | let (delimiter, skip_first) = match (first_child.kind(), last_child.kind()) { | ||
164 | (T!['('], T![')']) => (tt::Delimiter::Parenthesis, true), | ||
165 | (T!['{'], T!['}']) => (tt::Delimiter::Brace, true), | ||
166 | (T!['['], T![']']) => (tt::Delimiter::Bracket, true), | ||
167 | _ => (tt::Delimiter::None, false), | ||
168 | }; | ||
191 | 169 | ||
192 | while let Some(child) = child_iter.next() { | 170 | let mut token_trees = Vec::new(); |
193 | if skip_first && (child == first_child || child == last_child) { | 171 | let mut child_iter = tt.children_with_tokens().skip(skip_first as usize).peekable(); |
194 | continue; | ||
195 | } | ||
196 | 172 | ||
197 | match child { | 173 | while let Some(child) = child_iter.next() { |
198 | NodeOrToken::Token(token) => { | 174 | if skip_first && (child == first_child || child == last_child) { |
199 | if let Some(doc_tokens) = convert_doc_comment(&token) { | 175 | continue; |
200 | token_trees.extend(doc_tokens); | 176 | } |
201 | } else if token.kind().is_trivia() { | 177 | |
202 | continue; | 178 | match child { |
203 | } else if token.kind().is_punct() { | 179 | NodeOrToken::Token(token) => { |
204 | assert!(token.text().len() == 1, "Input ast::token punct must be single char."); | 180 | if let Some(doc_tokens) = convert_doc_comment(&token) { |
205 | let char = token.text().chars().next().unwrap(); | 181 | token_trees.extend(doc_tokens); |
206 | 182 | } else if token.kind().is_trivia() { | |
207 | let spacing = match child_iter.peek() { | 183 | continue; |
208 | Some(NodeOrToken::Token(token)) => { | 184 | } else if token.kind().is_punct() { |
209 | if token.kind().is_punct() { | 185 | assert!( |
210 | tt::Spacing::Joint | 186 | token.text().len() == 1, |
211 | } else { | 187 | "Input ast::token punct must be single char." |
212 | tt::Spacing::Alone | 188 | ); |
189 | let char = token.text().chars().next().unwrap(); | ||
190 | |||
191 | let spacing = match child_iter.peek() { | ||
192 | Some(NodeOrToken::Token(token)) => { | ||
193 | if token.kind().is_punct() { | ||
194 | tt::Spacing::Joint | ||
195 | } else { | ||
196 | tt::Spacing::Alone | ||
197 | } | ||
213 | } | 198 | } |
214 | } | 199 | _ => tt::Spacing::Alone, |
215 | _ => tt::Spacing::Alone, | ||
216 | }; | ||
217 | |||
218 | token_trees.push(tt::Leaf::from(tt::Punct { char, spacing }).into()); | ||
219 | } else { | ||
220 | let child: tt::TokenTree = | ||
221 | if token.kind() == T![true] || token.kind() == T![false] { | ||
222 | tt::Leaf::from(tt::Literal { text: token.text().clone() }).into() | ||
223 | } else if token.kind().is_keyword() | ||
224 | || token.kind() == IDENT | ||
225 | || token.kind() == LIFETIME | ||
226 | { | ||
227 | let relative_range = token.text_range() - global_offset; | ||
228 | let id = token_map.alloc(relative_range); | ||
229 | let text = token.text().clone(); | ||
230 | tt::Leaf::from(tt::Ident { text, id }).into() | ||
231 | } else if token.kind().is_literal() { | ||
232 | tt::Leaf::from(tt::Literal { text: token.text().clone() }).into() | ||
233 | } else { | ||
234 | return None; | ||
235 | }; | 200 | }; |
201 | |||
202 | token_trees.push(tt::Leaf::from(tt::Punct { char, spacing }).into()); | ||
203 | } else { | ||
204 | let child: tt::TokenTree = | ||
205 | if token.kind() == T![true] || token.kind() == T![false] { | ||
206 | tt::Leaf::from(tt::Literal { text: token.text().clone() }).into() | ||
207 | } else if token.kind().is_keyword() | ||
208 | || token.kind() == IDENT | ||
209 | || token.kind() == LIFETIME | ||
210 | { | ||
211 | let id = self.alloc(token.text_range()); | ||
212 | let text = token.text().clone(); | ||
213 | tt::Leaf::from(tt::Ident { text, id }).into() | ||
214 | } else if token.kind().is_literal() { | ||
215 | tt::Leaf::from(tt::Literal { text: token.text().clone() }).into() | ||
216 | } else { | ||
217 | return None; | ||
218 | }; | ||
219 | token_trees.push(child); | ||
220 | } | ||
221 | } | ||
222 | NodeOrToken::Node(node) => { | ||
223 | let child = self.go(&node)?.into(); | ||
236 | token_trees.push(child); | 224 | token_trees.push(child); |
237 | } | 225 | } |
238 | } | 226 | }; |
239 | NodeOrToken::Node(node) => { | 227 | } |
240 | let child = convert_tt(token_map, global_offset, &node)?.into(); | 228 | |
241 | token_trees.push(child); | 229 | let res = tt::Subtree { delimiter, token_trees }; |
242 | } | 230 | Some(res) |
243 | }; | ||
244 | } | 231 | } |
245 | 232 | ||
246 | let res = tt::Subtree { delimiter, token_trees }; | 233 | fn alloc(&mut self, absolute_range: TextRange) -> tt::TokenId { |
247 | Some(res) | 234 | let relative_range = absolute_range - self.global_offset; |
235 | let token_id = tt::TokenId(self.next_id); | ||
236 | self.next_id += 1; | ||
237 | self.map.insert(token_id, relative_range); | ||
238 | token_id | ||
239 | } | ||
248 | } | 240 | } |
249 | 241 | ||
250 | struct TtTreeSink<'a> { | 242 | struct TtTreeSink<'a> { |
@@ -252,7 +244,7 @@ struct TtTreeSink<'a> { | |||
252 | cursor: Cursor<'a>, | 244 | cursor: Cursor<'a>, |
253 | text_pos: TextUnit, | 245 | text_pos: TextUnit, |
254 | inner: SyntaxTreeBuilder, | 246 | inner: SyntaxTreeBuilder, |
255 | range_map: RevTokenMap, | 247 | token_map: TokenMap, |
256 | 248 | ||
257 | // Number of roots | 249 | // Number of roots |
258 | // Use for detect ill-form tree which is not single root | 250 | // Use for detect ill-form tree which is not single root |
@@ -267,12 +259,12 @@ impl<'a> TtTreeSink<'a> { | |||
267 | text_pos: 0.into(), | 259 | text_pos: 0.into(), |
268 | inner: SyntaxTreeBuilder::default(), | 260 | inner: SyntaxTreeBuilder::default(), |
269 | roots: smallvec::SmallVec::new(), | 261 | roots: smallvec::SmallVec::new(), |
270 | range_map: RevTokenMap::default(), | 262 | token_map: TokenMap::default(), |
271 | } | 263 | } |
272 | } | 264 | } |
273 | 265 | ||
274 | fn finish(self) -> (Parse<SyntaxNode>, RevTokenMap) { | 266 | fn finish(self) -> (Parse<SyntaxNode>, TokenMap) { |
275 | (self.inner.finish(), self.range_map) | 267 | (self.inner.finish(), self.token_map) |
276 | } | 268 | } |
277 | } | 269 | } |
278 | 270 | ||
@@ -308,7 +300,7 @@ impl<'a> TreeSink for TtTreeSink<'a> { | |||
308 | if kind == IDENT { | 300 | if kind == IDENT { |
309 | let range = | 301 | let range = |
310 | TextRange::offset_len(self.text_pos, TextUnit::of_str(&ident.text)); | 302 | TextRange::offset_len(self.text_pos, TextUnit::of_str(&ident.text)); |
311 | self.range_map.add(range, ident.id); | 303 | self.token_map.insert(ident.id, range); |
312 | } | 304 | } |
313 | } | 305 | } |
314 | 306 | ||
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index cefc00402..761b2435c 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | //! Extensions for various expressions live in a sibling `expr_extensions` module. | 2 | //! Extensions for various expressions live in a sibling `expr_extensions` module. |
3 | 3 | ||
4 | use crate::{ | 4 | use crate::{ |
5 | ast::{self, child_opt, children, AstChildren, AstNode, AttrInput, SyntaxNode}, | 5 | ast::{self, child_opt, children, AstNode, AttrInput, SyntaxNode}, |
6 | SmolStr, SyntaxElement, | 6 | SmolStr, SyntaxElement, |
7 | SyntaxKind::*, | 7 | SyntaxKind::*, |
8 | SyntaxToken, T, | 8 | SyntaxToken, T, |
@@ -176,16 +176,6 @@ impl ast::ImplBlock { | |||
176 | } | 176 | } |
177 | } | 177 | } |
178 | 178 | ||
179 | impl ast::AttrsOwner for ast::ImplItem { | ||
180 | fn attrs(&self) -> AstChildren<ast::Attr> { | ||
181 | match self { | ||
182 | ast::ImplItem::FnDef(it) => it.attrs(), | ||
183 | ast::ImplItem::TypeAliasDef(it) => it.attrs(), | ||
184 | ast::ImplItem::ConstDef(it) => it.attrs(), | ||
185 | } | ||
186 | } | ||
187 | } | ||
188 | |||
189 | #[derive(Debug, Clone, PartialEq, Eq)] | 179 | #[derive(Debug, Clone, PartialEq, Eq)] |
190 | pub enum StructKind { | 180 | pub enum StructKind { |
191 | Tuple(ast::TupleFieldDefList), | 181 | Tuple(ast::TupleFieldDefList), |
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 34b22c3e2..2b381dcdb 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -1298,6 +1298,7 @@ impl AstNode for ImplItem { | |||
1298 | } | 1298 | } |
1299 | } | 1299 | } |
1300 | } | 1300 | } |
1301 | impl ast::AttrsOwner for ImplItem {} | ||
1301 | impl ImplItem {} | 1302 | impl ImplItem {} |
1302 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 1303 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
1303 | pub struct ImplTraitType { | 1304 | pub struct ImplTraitType { |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 0a8fd0612..70d85a8e6 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -401,7 +401,8 @@ Grammar( | |||
401 | traits: ["AttrsOwner"] | 401 | traits: ["AttrsOwner"] |
402 | ), | 402 | ), |
403 | "ImplItem": ( | 403 | "ImplItem": ( |
404 | enum: ["FnDef", "TypeAliasDef", "ConstDef"] | 404 | enum: ["FnDef", "TypeAliasDef", "ConstDef"], |
405 | traits: ["AttrsOwner"] | ||
405 | ), | 406 | ), |
406 | 407 | ||
407 | "TupleExpr": ( | 408 | "TupleExpr": ( |