aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-11-18 11:24:35 +0000
committerGitHub <[email protected]>2019-11-18 11:24:35 +0000
commit91509073c54a6f815a443f70fd8f9e505b750177 (patch)
treeffc9afa4bd6f436e51eaa3de9758916a1bdc7124
parent614c034ffc3a7120f125eede8323f01c8f4411d3 (diff)
parent9fcd98e956a46d90c708abb9739f067a88ae3c4a (diff)
Merge #2298
2298: Add ra_ide_api::expand r=matklad a=matklad Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r--crates/ra_ide_api/src/display/navigation_target.rs65
-rw-r--r--crates/ra_ide_api/src/expand.rs42
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs27
-rw-r--r--crates/ra_ide_api/src/lib.rs1
4 files changed, 74 insertions, 61 deletions
diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs
index f7ad08515..291b5ee40 100644
--- a/crates/ra_ide_api/src/display/navigation_target.rs
+++ b/crates/ra_ide_api/src/display/navigation_target.rs
@@ -1,6 +1,6 @@
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},
@@ -9,8 +9,9 @@ use ra_syntax::{
9 SyntaxNode, TextRange, 9 SyntaxNode, 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,12 +80,12 @@ 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(),
89 src.ast.doc_comment_text(), 90 src.ast.doc_comment_text(),
90 src.ast.short_label(), 91 src.ast.short_label(),
@@ -147,14 +148,15 @@ impl NavigationTarget {
147 ) -> NavigationTarget { 148 ) -> NavigationTarget {
148 //FIXME: use `_` instead of empty string 149 //FIXME: use `_` instead of empty string
149 let name = node.name().map(|it| it.text().clone()).unwrap_or_default(); 150 let name = node.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); 151 let focus_range =
151 let (file_id, full_range) = find_range_from_node(db, file_id, node.syntax()); 152 node.name().map(|it| original_range(db, Source::new(file_id, it.syntax())).range);
153 let frange = original_range(db, Source::new(file_id, node.syntax()));
152 154
153 NavigationTarget::from_syntax( 155 NavigationTarget::from_syntax(
154 file_id, 156 frange.file_id,
155 name, 157 name,
156 focus_range, 158 focus_range,
157 full_range, 159 frange.range,
158 node.syntax(), 160 node.syntax(),
159 docs, 161 docs,
160 description, 162 description,
@@ -230,28 +232,28 @@ impl ToNav for hir::Module {
230 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 232 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
231 let src = self.definition_source(db); 233 let src = self.definition_source(db);
232 let name = self.name(db).map(|it| it.to_string().into()).unwrap_or_default(); 234 let name = self.name(db).map(|it| it.to_string().into()).unwrap_or_default();
233 match src.ast { 235 match &src.ast {
234 ModuleSource::SourceFile(node) => { 236 ModuleSource::SourceFile(node) => {
235 let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax()); 237 let frange = original_range(db, src.with_ast(node.syntax()));
236 238
237 NavigationTarget::from_syntax( 239 NavigationTarget::from_syntax(
238 file_id, 240 frange.file_id,
239 name, 241 name,
240 None, 242 None,
241 text_range, 243 frange.range,
242 node.syntax(), 244 node.syntax(),
243 None, 245 None,
244 None, 246 None,
245 ) 247 )
246 } 248 }
247 ModuleSource::Module(node) => { 249 ModuleSource::Module(node) => {
248 let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax()); 250 let frange = original_range(db, src.with_ast(node.syntax()));
249 251
250 NavigationTarget::from_syntax( 252 NavigationTarget::from_syntax(
251 file_id, 253 frange.file_id,
252 name, 254 name,
253 None, 255 None,
254 text_range, 256 frange.range,
255 node.syntax(), 257 node.syntax(),
256 node.doc_comment_text(), 258 node.doc_comment_text(),
257 node.short_label(), 259 node.short_label(),
@@ -264,13 +266,13 @@ impl ToNav for hir::Module {
264impl ToNav for hir::ImplBlock { 266impl ToNav for hir::ImplBlock {
265 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 267 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
266 let src = self.source(db); 268 let src = self.source(db);
267 let (file_id, text_range) = find_range_from_node(db, src.file_id, src.ast.syntax()); 269 let frange = original_range(db, src.as_ref().map(|it| it.syntax()));
268 270
269 NavigationTarget::from_syntax( 271 NavigationTarget::from_syntax(
270 file_id, 272 frange.file_id,
271 "impl".into(), 273 "impl".into(),
272 None, 274 None,
273 text_range, 275 frange.range,
274 src.ast.syntax(), 276 src.ast.syntax(),
275 None, 277 None,
276 None, 278 None,
@@ -282,21 +284,21 @@ impl ToNav for hir::StructField {
282 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 284 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
283 let src = self.source(db); 285 let src = self.source(db);
284 286
285 match src.ast { 287 match &src.ast {
286 FieldSource::Named(it) => NavigationTarget::from_named( 288 FieldSource::Named(it) => NavigationTarget::from_named(
287 db, 289 db,
288 src.file_id, 290 src.file_id,
289 &it, 291 it,
290 it.doc_comment_text(), 292 it.doc_comment_text(),
291 it.short_label(), 293 it.short_label(),
292 ), 294 ),
293 FieldSource::Pos(it) => { 295 FieldSource::Pos(it) => {
294 let (file_id, text_range) = find_range_from_node(db, src.file_id, it.syntax()); 296 let frange = original_range(db, src.with_ast(it.syntax()));
295 NavigationTarget::from_syntax( 297 NavigationTarget::from_syntax(
296 file_id, 298 frange.file_id,
297 "".into(), 299 "".into(),
298 None, 300 None,
299 text_range, 301 frange.range,
300 it.syntax(), 302 it.syntax(),
301 None, 303 None,
302 None, 304 None,
@@ -360,21 +362,6 @@ impl ToNav for hir::Local {
360 } 362 }
361} 363}
362 364
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> { 365pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> {
379 let parse = db.parse(symbol.file_id); 366 let parse = db.parse(symbol.file_id);
380 let node = symbol.ptr.to_node(parse.tree().syntax()); 367 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..5f1fb9a12
--- /dev/null
+++ b/crates/ra_ide_api/src/expand.rs
@@ -0,0 +1,42 @@
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 text_range = node.ast.text_range();
12 let (file_id, range) = node
13 .file_id
14 .expansion_info(db)
15 .and_then(|expansion_info| expansion_info.find_range(text_range))
16 .unwrap_or((node.file_id, text_range));
17
18 // FIXME: handle recursive macro generated macro
19 FileRange { file_id: file_id.original_file(db), range }
20}
21
22pub(crate) fn descend_into_macros(
23 db: &RootDatabase,
24 file_id: FileId,
25 token: SyntaxToken,
26) -> Source<SyntaxToken> {
27 let src = Source::new(file_id.into(), token);
28
29 successors(Some(src), |token| {
30 let macro_call = token.ast.ancestors().find_map(ast::MacroCall::cast)?;
31 let tt = macro_call.token_tree()?;
32 if !token.ast.text_range().is_subrange(&tt.syntax().text_range()) {
33 return None;
34 }
35 let source_analyzer =
36 hir::SourceAnalyzer::new(db, token.with_ast(token.ast.parent()).as_ref(), None);
37 let exp = source_analyzer.expand(db, &macro_call)?;
38 exp.map_token_down(db, token.as_ref())
39 })
40 .last()
41 .unwrap()
42}
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index b693a4c31..1a8db0ea0 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),
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;