diff options
Diffstat (limited to 'crates/ra_hir/src/path.rs')
-rw-r--r-- | crates/ra_hir/src/path.rs | 66 |
1 files changed, 54 insertions, 12 deletions
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 39d1b7e46..394617e1a 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use std::{iter, sync::Arc}; | 3 | use std::{iter, sync::Arc}; |
2 | 4 | ||
3 | use ra_syntax::{ | 5 | use ra_syntax::{ |
@@ -5,7 +7,7 @@ use ra_syntax::{ | |||
5 | AstNode, | 7 | AstNode, |
6 | }; | 8 | }; |
7 | 9 | ||
8 | use crate::{name, type_ref::TypeRef, AsName, Name}; | 10 | use crate::{db::AstDatabase, name, type_ref::TypeRef, AsName, Crate, Name, Source}; |
9 | 11 | ||
10 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 12 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
11 | pub struct Path { | 13 | pub struct Path { |
@@ -52,16 +54,19 @@ pub enum PathKind { | |||
52 | Abs, | 54 | Abs, |
53 | // Type based path like `<T>::foo` | 55 | // Type based path like `<T>::foo` |
54 | Type(Box<TypeRef>), | 56 | Type(Box<TypeRef>), |
57 | // `$crate` from macro expansion | ||
58 | DollarCrate(Crate), | ||
55 | } | 59 | } |
56 | 60 | ||
57 | impl Path { | 61 | impl Path { |
58 | /// Calls `cb` with all paths, represented by this use item. | 62 | /// Calls `cb` with all paths, represented by this use item. |
59 | pub fn expand_use_item( | 63 | pub fn expand_use_item( |
60 | item: &ast::UseItem, | 64 | item_src: Source<ast::UseItem>, |
65 | db: &impl AstDatabase, | ||
61 | mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>), | 66 | mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>), |
62 | ) { | 67 | ) { |
63 | if let Some(tree) = item.use_tree() { | 68 | if let Some(tree) = item_src.ast.use_tree() { |
64 | expand_use_tree(None, tree, &mut cb); | 69 | expand_use_tree(None, tree, &|| item_src.file_id.macro_crate(db), &mut cb); |
65 | } | 70 | } |
66 | } | 71 | } |
67 | 72 | ||
@@ -76,7 +81,19 @@ impl Path { | |||
76 | } | 81 | } |
77 | 82 | ||
78 | /// Converts an `ast::Path` to `Path`. Works with use trees. | 83 | /// Converts an `ast::Path` to `Path`. Works with use trees. |
79 | pub fn from_ast(mut path: ast::Path) -> Option<Path> { | 84 | /// DEPRECATED: It does not handle `$crate` from macro call. |
85 | pub fn from_ast(path: ast::Path) -> Option<Path> { | ||
86 | Path::parse(path, &|| None) | ||
87 | } | ||
88 | |||
89 | /// Converts an `ast::Path` to `Path`. Works with use trees. | ||
90 | /// It correctly handles `$crate` based path from macro call. | ||
91 | pub fn from_src(source: Source<ast::Path>, db: &impl AstDatabase) -> Option<Path> { | ||
92 | let file_id = source.file_id; | ||
93 | Path::parse(source.ast, &|| file_id.macro_crate(db)) | ||
94 | } | ||
95 | |||
96 | fn parse(mut path: ast::Path, macro_crate: &impl Fn() -> Option<Crate>) -> Option<Path> { | ||
80 | let mut kind = PathKind::Plain; | 97 | let mut kind = PathKind::Plain; |
81 | let mut segments = Vec::new(); | 98 | let mut segments = Vec::new(); |
82 | loop { | 99 | loop { |
@@ -88,6 +105,13 @@ impl Path { | |||
88 | 105 | ||
89 | match segment.kind()? { | 106 | match segment.kind()? { |
90 | ast::PathSegmentKind::Name(name) => { | 107 | ast::PathSegmentKind::Name(name) => { |
108 | if name.text() == "$crate" { | ||
109 | if let Some(macro_crate) = macro_crate() { | ||
110 | kind = PathKind::DollarCrate(macro_crate); | ||
111 | break; | ||
112 | } | ||
113 | } | ||
114 | |||
91 | let args = segment | 115 | let args = segment |
92 | .type_arg_list() | 116 | .type_arg_list() |
93 | .and_then(GenericArgs::from_ast) | 117 | .and_then(GenericArgs::from_ast) |
@@ -113,7 +137,7 @@ impl Path { | |||
113 | } | 137 | } |
114 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo | 138 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo |
115 | Some(trait_ref) => { | 139 | Some(trait_ref) => { |
116 | let path = Path::from_ast(trait_ref.path()?)?; | 140 | let path = Path::parse(trait_ref.path()?, macro_crate)?; |
117 | kind = path.kind; | 141 | kind = path.kind; |
118 | let mut prefix_segments = path.segments; | 142 | let mut prefix_segments = path.segments; |
119 | prefix_segments.reverse(); | 143 | prefix_segments.reverse(); |
@@ -264,6 +288,7 @@ impl From<Name> for Path { | |||
264 | fn expand_use_tree( | 288 | fn expand_use_tree( |
265 | prefix: Option<Path>, | 289 | prefix: Option<Path>, |
266 | tree: ast::UseTree, | 290 | tree: ast::UseTree, |
291 | macro_crate: &impl Fn() -> Option<Crate>, | ||
267 | cb: &mut impl FnMut(Path, &ast::UseTree, bool, Option<Name>), | 292 | cb: &mut impl FnMut(Path, &ast::UseTree, bool, Option<Name>), |
268 | ) { | 293 | ) { |
269 | if let Some(use_tree_list) = tree.use_tree_list() { | 294 | if let Some(use_tree_list) = tree.use_tree_list() { |
@@ -272,13 +297,13 @@ fn expand_use_tree( | |||
272 | None => prefix, | 297 | None => prefix, |
273 | // E.g. `use something::{inner}` (prefix is `None`, path is `something`) | 298 | // E.g. `use something::{inner}` (prefix is `None`, path is `something`) |
274 | // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) | 299 | // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) |
275 | Some(path) => match convert_path(prefix, path) { | 300 | Some(path) => match convert_path(prefix, path, macro_crate) { |
276 | Some(it) => Some(it), | 301 | Some(it) => Some(it), |
277 | None => return, // FIXME: report errors somewhere | 302 | None => return, // FIXME: report errors somewhere |
278 | }, | 303 | }, |
279 | }; | 304 | }; |
280 | for child_tree in use_tree_list.use_trees() { | 305 | for child_tree in use_tree_list.use_trees() { |
281 | expand_use_tree(prefix.clone(), child_tree, cb); | 306 | expand_use_tree(prefix.clone(), child_tree, macro_crate, cb); |
282 | } | 307 | } |
283 | } else { | 308 | } else { |
284 | let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name()); | 309 | let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name()); |
@@ -295,7 +320,7 @@ fn expand_use_tree( | |||
295 | } | 320 | } |
296 | } | 321 | } |
297 | } | 322 | } |
298 | if let Some(path) = convert_path(prefix, ast_path) { | 323 | if let Some(path) = convert_path(prefix, ast_path, macro_crate) { |
299 | let is_glob = tree.has_star(); | 324 | let is_glob = tree.has_star(); |
300 | cb(path, &tree, is_glob, alias) | 325 | cb(path, &tree, is_glob, alias) |
301 | } | 326 | } |
@@ -305,12 +330,29 @@ fn expand_use_tree( | |||
305 | } | 330 | } |
306 | } | 331 | } |
307 | 332 | ||
308 | fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> { | 333 | fn convert_path( |
309 | let prefix = | 334 | prefix: Option<Path>, |
310 | if let Some(qual) = path.qualifier() { Some(convert_path(prefix, qual)?) } else { prefix }; | 335 | path: ast::Path, |
336 | macro_crate: &impl Fn() -> Option<Crate>, | ||
337 | ) -> Option<Path> { | ||
338 | let prefix = if let Some(qual) = path.qualifier() { | ||
339 | Some(convert_path(prefix, qual, macro_crate)?) | ||
340 | } else { | ||
341 | prefix | ||
342 | }; | ||
343 | |||
311 | let segment = path.segment()?; | 344 | let segment = path.segment()?; |
312 | let res = match segment.kind()? { | 345 | let res = match segment.kind()? { |
313 | ast::PathSegmentKind::Name(name) => { | 346 | ast::PathSegmentKind::Name(name) => { |
347 | if name.text() == "$crate" { | ||
348 | if let Some(krate) = macro_crate() { | ||
349 | return Some(Path::from_simple_segments( | ||
350 | PathKind::DollarCrate(krate), | ||
351 | iter::empty(), | ||
352 | )); | ||
353 | } | ||
354 | } | ||
355 | |||
314 | // no type args in use | 356 | // no type args in use |
315 | let mut res = prefix | 357 | let mut res = prefix |
316 | .unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) }); | 358 | .unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) }); |