aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorSeivan Heidari <[email protected]>2019-11-18 19:53:40 +0000
committerSeivan Heidari <[email protected]>2019-11-18 19:53:40 +0000
commit4bdb6351ac557851607df9d142c9e573c0fb5e1d (patch)
tree48b349958afceeeebecccd63e55004d5a924baff /crates
parentaceeb0b85ee8228503f970ea602af71ff22216a0 (diff)
parenta4f21801c54c65eafa337edc5e86de2c46b37544 (diff)
Merge branch 'master' of https://github.com/rust-analyzer/rust-analyzer into feature/themes
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir_expand/src/db.rs8
-rw-r--r--crates/ra_hir_expand/src/lib.rs55
-rw-r--r--crates/ra_ide_api/src/display/navigation_target.rs99
-rw-r--r--crates/ra_ide_api/src/expand.rs59
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs60
-rw-r--r--crates/ra_ide_api/src/hover.rs4
-rw-r--r--crates/ra_ide_api/src/lib.rs1
-rw-r--r--crates/ra_ide_api/src/references.rs2
-rw-r--r--crates/ra_ide_api/src/references/classify.rs38
-rw-r--r--crates/ra_ide_api/src/syntax_highlighting.rs3
-rw-r--r--crates/ra_mbe/src/lib.rs2
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs206
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs12
-rw-r--r--crates/ra_syntax/src/ast/generated.rs1
-rw-r--r--crates/ra_syntax/src/grammar.ron3
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
136pub(crate) fn parse_macro( 134pub(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};
20use ra_syntax::{ 20use 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
26use crate::ast_id_map::FileAstId; 26use 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)]
160pub struct ExpansionInfo { 155pub 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
170impl ExpansionInfo { 165impl 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
3use hir::{AssocItem, Either, FieldSource, HasSource, ModuleSource}; 3use hir::{AssocItem, Either, FieldSource, HasSource, ModuleSource, Source};
4use ra_db::{FileId, SourceDatabase}; 4use ra_db::{FileId, SourceDatabase};
5use ra_syntax::{ 5use 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
12use crate::{db::RootDatabase, expand::original_range, FileSymbol};
13
12use super::short_label::ShortLabel; 14use super::short_label::ShortLabel;
13use 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 {
264impl ToNav for hir::ImplBlock { 264impl 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
363fn 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
378pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> { 367pub(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.
2use std::iter::successors;
3
4use hir::Source;
5use ra_db::FileId;
6use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxToken};
7
8use crate::{db::RootDatabase, FileRange};
9
10pub(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
39pub(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, &macro_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
3use std::iter::successors;
4
5use hir::{db::AstDatabase, Source}; 3use hir::{db::AstDatabase, Source};
6use ra_syntax::{ 4use 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
11use crate::{ 9use 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
42fn 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, &macro_call)?;
55 exp.map_token_down(db, token.as_ref())
56 })
57 .last()
58}
59
60#[derive(Debug)] 43#[derive(Debug)]
61pub(crate) enum ReferenceResult { 44pub(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;
41mod display; 41mod display;
42mod inlay_hints; 42mod inlay_hints;
43mod wasm_shims; 43mod wasm_shims;
44mod expand;
44 45
45#[cfg(test)] 46#[cfg(test)]
46mod marks; 47mod 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
3use hir::{FromSource, Module, ModuleSource, Path, PathResolution, Source, SourceAnalyzer}; 3use hir::{FromSource, Module, ModuleSource, Path, PathResolution, Source, SourceAnalyzer};
4use ra_db::FileId;
5use ra_prof::profile; 4use ra_prof::profile;
6use ra_syntax::{ast, match_ast, AstNode}; 5use ra_syntax::{ast, match_ast, AstNode};
7use test_utils::tested_by; 6use test_utils::tested_by;
@@ -12,19 +11,14 @@ use super::{
12}; 11};
13use crate::db::RootDatabase; 12use crate::db::RootDatabase;
14 13
15pub(crate) fn classify_name( 14pub(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
33pub use crate::syntax_bridge::{ 33pub 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)]
15pub struct TokenMap { 15pub 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)]
22pub 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).
28pub fn ast_to_token_tree(ast: &ast::TokenTree) -> Option<(tt::Subtree, TokenMap)> { 22pub 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).
37pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> Option<(tt::Subtree, TokenMap)> { 28pub 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
55pub fn token_tree_to_syntax_node( 47pub 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
79impl TokenMap { 71impl 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
98impl 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
170fn convert_tt( 148struct 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()?; 154impl 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
250struct TtTreeSink<'a> { 242struct 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
4use crate::{ 4use 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
179impl 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)]
190pub enum StructKind { 180pub 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}
1301impl ast::AttrsOwner for ImplItem {}
1301impl ImplItem {} 1302impl ImplItem {}
1302#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1303#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1303pub struct ImplTraitType { 1304pub 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": (