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