aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/display/navigation_target.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/display/navigation_target.rs')
-rw-r--r--crates/ra_ide_api/src/display/navigation_target.rs120
1 files changed, 88 insertions, 32 deletions
diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs
index 5cb67fb95..1bf81e7d5 100644
--- a/crates/ra_ide_api/src/display/navigation_target.rs
+++ b/crates/ra_ide_api/src/display/navigation_target.rs
@@ -29,6 +29,21 @@ pub struct NavigationTarget {
29 docs: Option<String>, 29 docs: Option<String>,
30} 30}
31 31
32fn find_range_from_node(
33 db: &RootDatabase,
34 src: hir::HirFileId,
35 node: &SyntaxNode,
36) -> (FileId, TextRange) {
37 let text_range = node.text_range();
38 let (file_id, text_range) = src
39 .expansion_info(db)
40 .and_then(|expansion_info| expansion_info.find_range(text_range))
41 .unwrap_or((src, text_range));
42
43 // FIXME: handle recursive macro generated macro
44 (file_id.original_file(db), text_range)
45}
46
32impl NavigationTarget { 47impl NavigationTarget {
33 /// When `focus_range` is specified, returns it. otherwise 48 /// When `focus_range` is specified, returns it. otherwise
34 /// returns `full_range` 49 /// returns `full_range`
@@ -72,8 +87,12 @@ impl NavigationTarget {
72 self.focus_range 87 self.focus_range
73 } 88 }
74 89
75 pub(crate) fn from_bind_pat(file_id: FileId, pat: &ast::BindPat) -> NavigationTarget { 90 pub(crate) fn from_bind_pat(
76 NavigationTarget::from_named(file_id, pat, None, None) 91 db: &RootDatabase,
92 file_id: FileId,
93 pat: &ast::BindPat,
94 ) -> NavigationTarget {
95 NavigationTarget::from_named(db, file_id.into(), pat, None, None)
77 } 96 }
78 97
79 pub(crate) fn from_symbol(db: &RootDatabase, symbol: FileSymbol) -> NavigationTarget { 98 pub(crate) fn from_symbol(db: &RootDatabase, symbol: FileSymbol) -> NavigationTarget {
@@ -96,7 +115,7 @@ impl NavigationTarget {
96 ) -> NavigationTarget { 115 ) -> NavigationTarget {
97 let parse = db.parse(file_id); 116 let parse = db.parse(file_id);
98 let pat = pat.to_node(parse.tree().syntax()); 117 let pat = pat.to_node(parse.tree().syntax());
99 NavigationTarget::from_bind_pat(file_id, &pat) 118 NavigationTarget::from_bind_pat(db, file_id, &pat)
100 } 119 }
101 120
102 pub(crate) fn from_self_param( 121 pub(crate) fn from_self_param(
@@ -119,31 +138,46 @@ impl NavigationTarget {
119 138
120 pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget { 139 pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
121 let src = module.definition_source(db); 140 let src = module.definition_source(db);
122 let file_id = src.file_id.original_file(db);
123 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); 141 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
124 match src.ast { 142 match src.ast {
125 ModuleSource::SourceFile(node) => { 143 ModuleSource::SourceFile(node) => {
126 NavigationTarget::from_syntax(file_id, name, None, node.syntax(), None, None) 144 let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax());
145
146 NavigationTarget::from_syntax(
147 file_id,
148 name,
149 None,
150 text_range,
151 node.syntax(),
152 None,
153 None,
154 )
155 }
156 ModuleSource::Module(node) => {
157 let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax());
158
159 NavigationTarget::from_syntax(
160 file_id,
161 name,
162 None,
163 text_range,
164 node.syntax(),
165 node.doc_comment_text(),
166 node.short_label(),
167 )
127 } 168 }
128 ModuleSource::Module(node) => NavigationTarget::from_syntax(
129 file_id,
130 name,
131 None,
132 node.syntax(),
133 node.doc_comment_text(),
134 node.short_label(),
135 ),
136 } 169 }
137 } 170 }
138 171
139 pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { 172 pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
140 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); 173 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
141 if let Some(src) = module.declaration_source(db) { 174 if let Some(src) = module.declaration_source(db) {
142 let file_id = src.file_id.original_file(db); 175 let (file_id, text_range) = find_range_from_node(db, src.file_id, src.ast.syntax());
143 return NavigationTarget::from_syntax( 176 return NavigationTarget::from_syntax(
144 file_id, 177 file_id,
145 name, 178 name,
146 None, 179 None,
180 text_range,
147 src.ast.syntax(), 181 src.ast.syntax(),
148 src.ast.doc_comment_text(), 182 src.ast.doc_comment_text(),
149 src.ast.short_label(), 183 src.ast.short_label(),
@@ -154,13 +188,25 @@ impl NavigationTarget {
154 188
155 pub(crate) fn from_field(db: &RootDatabase, field: hir::StructField) -> NavigationTarget { 189 pub(crate) fn from_field(db: &RootDatabase, field: hir::StructField) -> NavigationTarget {
156 let src = field.source(db); 190 let src = field.source(db);
157 let file_id = src.file_id.original_file(db);
158 match src.ast { 191 match src.ast {
159 FieldSource::Named(it) => { 192 FieldSource::Named(it) => NavigationTarget::from_named(
160 NavigationTarget::from_named(file_id, &it, it.doc_comment_text(), it.short_label()) 193 db,
161 } 194 src.file_id,
195 &it,
196 it.doc_comment_text(),
197 it.short_label(),
198 ),
162 FieldSource::Pos(it) => { 199 FieldSource::Pos(it) => {
163 NavigationTarget::from_syntax(file_id, "".into(), None, it.syntax(), None, None) 200 let (file_id, text_range) = find_range_from_node(db, src.file_id, it.syntax());
201 NavigationTarget::from_syntax(
202 file_id,
203 "".into(),
204 None,
205 text_range,
206 it.syntax(),
207 None,
208 None,
209 )
164 } 210 }
165 } 211 }
166 } 212 }
@@ -172,7 +218,8 @@ impl NavigationTarget {
172 { 218 {
173 let src = def.source(db); 219 let src = def.source(db);
174 NavigationTarget::from_named( 220 NavigationTarget::from_named(
175 src.file_id.original_file(db), 221 db,
222 src.file_id,
176 &src.ast, 223 &src.ast,
177 src.ast.doc_comment_text(), 224 src.ast.doc_comment_text(),
178 src.ast.short_label(), 225 src.ast.short_label(),
@@ -212,10 +259,13 @@ impl NavigationTarget {
212 impl_block: hir::ImplBlock, 259 impl_block: hir::ImplBlock,
213 ) -> NavigationTarget { 260 ) -> NavigationTarget {
214 let src = impl_block.source(db); 261 let src = impl_block.source(db);
262 let (file_id, text_range) = find_range_from_node(db, src.file_id, src.ast.syntax());
263
215 NavigationTarget::from_syntax( 264 NavigationTarget::from_syntax(
216 src.file_id.original_file(db), 265 file_id,
217 "impl".into(), 266 "impl".into(),
218 None, 267 None,
268 text_range,
219 src.ast.syntax(), 269 src.ast.syntax(),
220 None, 270 None,
221 None, 271 None,
@@ -236,12 +286,7 @@ impl NavigationTarget {
236 pub(crate) fn from_macro_def(db: &RootDatabase, macro_call: hir::MacroDef) -> NavigationTarget { 286 pub(crate) fn from_macro_def(db: &RootDatabase, macro_call: hir::MacroDef) -> NavigationTarget {
237 let src = macro_call.source(db); 287 let src = macro_call.source(db);
238 log::debug!("nav target {:#?}", src.ast.syntax()); 288 log::debug!("nav target {:#?}", src.ast.syntax());
239 NavigationTarget::from_named( 289 NavigationTarget::from_named(db, src.file_id, &src.ast, src.ast.doc_comment_text(), None)
240 src.file_id.original_file(db),
241 &src.ast,
242 src.ast.doc_comment_text(),
243 None,
244 )
245 } 290 }
246 291
247 #[cfg(test)] 292 #[cfg(test)]
@@ -270,21 +315,33 @@ impl NavigationTarget {
270 315
271 /// Allows `NavigationTarget` to be created from a `NameOwner` 316 /// Allows `NavigationTarget` to be created from a `NameOwner`
272 pub(crate) fn from_named( 317 pub(crate) fn from_named(
273 file_id: FileId, 318 db: &RootDatabase,
319 file_id: hir::HirFileId,
274 node: &impl ast::NameOwner, 320 node: &impl ast::NameOwner,
275 docs: Option<String>, 321 docs: Option<String>,
276 description: Option<String>, 322 description: Option<String>,
277 ) -> NavigationTarget { 323 ) -> NavigationTarget {
278 //FIXME: use `_` instead of empty string 324 //FIXME: use `_` instead of empty string
279 let name = node.name().map(|it| it.text().clone()).unwrap_or_default(); 325 let name = node.name().map(|it| it.text().clone()).unwrap_or_default();
280 let focus_range = node.name().map(|it| it.syntax().text_range()); 326 let focus_range = node.name().map(|it| find_range_from_node(db, file_id, it.syntax()).1);
281 NavigationTarget::from_syntax(file_id, name, focus_range, node.syntax(), docs, description) 327 let (file_id, full_range) = find_range_from_node(db, file_id, node.syntax());
328
329 NavigationTarget::from_syntax(
330 file_id,
331 name,
332 focus_range,
333 full_range,
334 node.syntax(),
335 docs,
336 description,
337 )
282 } 338 }
283 339
284 fn from_syntax( 340 fn from_syntax(
285 file_id: FileId, 341 file_id: FileId,
286 name: SmolStr, 342 name: SmolStr,
287 focus_range: Option<TextRange>, 343 focus_range: Option<TextRange>,
344 full_range: TextRange,
288 node: &SyntaxNode, 345 node: &SyntaxNode,
289 docs: Option<String>, 346 docs: Option<String>,
290 description: Option<String>, 347 description: Option<String>,
@@ -293,9 +350,8 @@ impl NavigationTarget {
293 file_id, 350 file_id,
294 name, 351 name,
295 kind: node.kind(), 352 kind: node.kind(),
296 full_range: node.text_range(), 353 full_range,
297 focus_range, 354 focus_range,
298 // ptr: Some(LocalSyntaxPtr::new(node)),
299 container_name: None, 355 container_name: None,
300 description, 356 description,
301 docs, 357 docs,