aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/path.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-10-30 15:41:50 +0000
committerAleksey Kladov <[email protected]>2019-10-30 15:41:50 +0000
commit0bc7d285189caaffc13e4d6856baf895f72ed80c (patch)
tree792693f3b35d2a23107ee5a1e4bbb13bc2806c41 /crates/ra_hir_def/src/path.rs
parente34e71c62d9b4cf0ab237969e03ecde893ab347b (diff)
refactor $crate handling
Introduce proper hygiene module, which should grow quite a bit eventually.
Diffstat (limited to 'crates/ra_hir_def/src/path.rs')
-rw-r--r--crates/ra_hir_def/src/path.rs101
1 files changed, 49 insertions, 52 deletions
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
index fe060437d..39f394c3f 100644
--- a/crates/ra_hir_def/src/path.rs
+++ b/crates/ra_hir_def/src/path.rs
@@ -2,7 +2,6 @@
2 2
3use std::{iter, sync::Arc}; 3use std::{iter, sync::Arc};
4 4
5use hir_expand::db::AstDatabase;
6use ra_db::CrateId; 5use ra_db::CrateId;
7use ra_syntax::{ 6use ra_syntax::{
8 ast::{self, NameOwner, TypeAscriptionOwner}, 7 ast::{self, NameOwner, TypeAscriptionOwner},
@@ -10,6 +9,8 @@ use ra_syntax::{
10}; 9};
11 10
12use crate::{ 11use crate::{
12 either::Either,
13 hygiene::Hygiene,
13 name::{self, AsName, Name}, 14 name::{self, AsName, Name},
14 type_ref::TypeRef, 15 type_ref::TypeRef,
15 Source, 16 Source,
@@ -68,11 +69,11 @@ impl Path {
68 /// Calls `cb` with all paths, represented by this use item. 69 /// Calls `cb` with all paths, represented by this use item.
69 pub fn expand_use_item( 70 pub fn expand_use_item(
70 item_src: Source<ast::UseItem>, 71 item_src: Source<ast::UseItem>,
71 db: &impl AstDatabase, 72 hygiene: &Hygiene,
72 mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>), 73 mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>),
73 ) { 74 ) {
74 if let Some(tree) = item_src.ast.use_tree() { 75 if let Some(tree) = item_src.ast.use_tree() {
75 expand_use_tree(None, tree, &|| item_src.file_id.macro_crate(db), &mut cb); 76 expand_use_tree(None, tree, hygiene, &mut cb);
76 } 77 }
77 } 78 }
78 79
@@ -89,17 +90,12 @@ impl Path {
89 /// Converts an `ast::Path` to `Path`. Works with use trees. 90 /// Converts an `ast::Path` to `Path`. Works with use trees.
90 /// DEPRECATED: It does not handle `$crate` from macro call. 91 /// DEPRECATED: It does not handle `$crate` from macro call.
91 pub fn from_ast(path: ast::Path) -> Option<Path> { 92 pub fn from_ast(path: ast::Path) -> Option<Path> {
92 Path::parse(path, &|| None) 93 Path::from_src(path, &Hygiene::new_unhygienic())
93 } 94 }
94 95
95 /// Converts an `ast::Path` to `Path`. Works with use trees. 96 /// Converts an `ast::Path` to `Path`. Works with use trees.
96 /// It correctly handles `$crate` based path from macro call. 97 /// It correctly handles `$crate` based path from macro call.
97 pub fn from_src(source: Source<ast::Path>, db: &impl AstDatabase) -> Option<Path> { 98 pub fn from_src(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
98 let file_id = source.file_id;
99 Path::parse(source.ast, &|| file_id.macro_crate(db))
100 }
101
102 fn parse(mut path: ast::Path, macro_crate: &impl Fn() -> Option<CrateId>) -> Option<Path> {
103 let mut kind = PathKind::Plain; 99 let mut kind = PathKind::Plain;
104 let mut segments = Vec::new(); 100 let mut segments = Vec::new();
105 loop { 101 loop {
@@ -110,26 +106,28 @@ impl Path {
110 } 106 }
111 107
112 match segment.kind()? { 108 match segment.kind()? {
113 ast::PathSegmentKind::Name(name) => { 109 ast::PathSegmentKind::Name(name_ref) => {
114 if name.text() == "$crate" { 110 // FIXME: this should just return name
115 if let Some(macro_crate) = macro_crate() { 111 match hygiene.name_ref_to_name(name_ref) {
116 kind = PathKind::DollarCrate(macro_crate); 112 Either::A(name) => {
113 let args = segment
114 .type_arg_list()
115 .and_then(GenericArgs::from_ast)
116 .or_else(|| {
117 GenericArgs::from_fn_like_path_ast(
118 segment.param_list(),
119 segment.ret_type(),
120 )
121 })
122 .map(Arc::new);
123 let segment = PathSegment { name, args_and_bindings: args };
124 segments.push(segment);
125 }
126 Either::B(crate_id) => {
127 kind = PathKind::DollarCrate(crate_id);
117 break; 128 break;
118 } 129 }
119 } 130 }
120
121 let args = segment
122 .type_arg_list()
123 .and_then(GenericArgs::from_ast)
124 .or_else(|| {
125 GenericArgs::from_fn_like_path_ast(
126 segment.param_list(),
127 segment.ret_type(),
128 )
129 })
130 .map(Arc::new);
131 let segment = PathSegment { name: name.as_name(), args_and_bindings: args };
132 segments.push(segment);
133 } 131 }
134 ast::PathSegmentKind::Type { type_ref, trait_ref } => { 132 ast::PathSegmentKind::Type { type_ref, trait_ref } => {
135 assert!(path.qualifier().is_none()); // this can only occur at the first segment 133 assert!(path.qualifier().is_none()); // this can only occur at the first segment
@@ -143,7 +141,7 @@ impl Path {
143 } 141 }
144 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo 142 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
145 Some(trait_ref) => { 143 Some(trait_ref) => {
146 let path = Path::parse(trait_ref.path()?, macro_crate)?; 144 let path = Path::from_src(trait_ref.path()?, hygiene)?;
147 kind = path.kind; 145 kind = path.kind;
148 let mut prefix_segments = path.segments; 146 let mut prefix_segments = path.segments;
149 prefix_segments.reverse(); 147 prefix_segments.reverse();
@@ -294,7 +292,7 @@ impl From<Name> for Path {
294fn expand_use_tree( 292fn expand_use_tree(
295 prefix: Option<Path>, 293 prefix: Option<Path>,
296 tree: ast::UseTree, 294 tree: ast::UseTree,
297 macro_crate: &impl Fn() -> Option<CrateId>, 295 hygiene: &Hygiene,
298 cb: &mut impl FnMut(Path, &ast::UseTree, bool, Option<Name>), 296 cb: &mut impl FnMut(Path, &ast::UseTree, bool, Option<Name>),
299) { 297) {
300 if let Some(use_tree_list) = tree.use_tree_list() { 298 if let Some(use_tree_list) = tree.use_tree_list() {
@@ -303,13 +301,13 @@ fn expand_use_tree(
303 None => prefix, 301 None => prefix,
304 // E.g. `use something::{inner}` (prefix is `None`, path is `something`) 302 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
305 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) 303 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
306 Some(path) => match convert_path(prefix, path, macro_crate) { 304 Some(path) => match convert_path(prefix, path, hygiene) {
307 Some(it) => Some(it), 305 Some(it) => Some(it),
308 None => return, // FIXME: report errors somewhere 306 None => return, // FIXME: report errors somewhere
309 }, 307 },
310 }; 308 };
311 for child_tree in use_tree_list.use_trees() { 309 for child_tree in use_tree_list.use_trees() {
312 expand_use_tree(prefix.clone(), child_tree, macro_crate, cb); 310 expand_use_tree(prefix.clone(), child_tree, hygiene, cb);
313 } 311 }
314 } else { 312 } else {
315 let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name()); 313 let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name());
@@ -326,7 +324,7 @@ fn expand_use_tree(
326 } 324 }
327 } 325 }
328 } 326 }
329 if let Some(path) = convert_path(prefix, ast_path, macro_crate) { 327 if let Some(path) = convert_path(prefix, ast_path, hygiene) {
330 let is_glob = tree.has_star(); 328 let is_glob = tree.has_star();
331 cb(path, &tree, is_glob, alias) 329 cb(path, &tree, is_glob, alias)
332 } 330 }
@@ -336,37 +334,36 @@ fn expand_use_tree(
336 } 334 }
337} 335}
338 336
339fn convert_path( 337fn convert_path(prefix: Option<Path>, path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
340 prefix: Option<Path>,
341 path: ast::Path,
342 macro_crate: &impl Fn() -> Option<CrateId>,
343) -> Option<Path> {
344 let prefix = if let Some(qual) = path.qualifier() { 338 let prefix = if let Some(qual) = path.qualifier() {
345 Some(convert_path(prefix, qual, macro_crate)?) 339 Some(convert_path(prefix, qual, hygiene)?)
346 } else { 340 } else {
347 prefix 341 prefix
348 }; 342 };
349 343
350 let segment = path.segment()?; 344 let segment = path.segment()?;
351 let res = match segment.kind()? { 345 let res = match segment.kind()? {
352 ast::PathSegmentKind::Name(name) => { 346 ast::PathSegmentKind::Name(name_ref) => {
353 if name.text() == "$crate" { 347 match hygiene.name_ref_to_name(name_ref) {
354 if let Some(krate) = macro_crate() { 348 Either::A(name) => {
349 // no type args in use
350 let mut res = prefix.unwrap_or_else(|| Path {
351 kind: PathKind::Plain,
352 segments: Vec::with_capacity(1),
353 });
354 res.segments.push(PathSegment {
355 name,
356 args_and_bindings: None, // no type args in use
357 });
358 res
359 }
360 Either::B(crate_id) => {
355 return Some(Path::from_simple_segments( 361 return Some(Path::from_simple_segments(
356 PathKind::DollarCrate(krate), 362 PathKind::DollarCrate(crate_id),
357 iter::empty(), 363 iter::empty(),
358 )); 364 ))
359 } 365 }
360 } 366 }
361
362 // no type args in use
363 let mut res = prefix
364 .unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) });
365 res.segments.push(PathSegment {
366 name: name.as_name(),
367 args_and_bindings: None, // no type args in use
368 });
369 res
370 } 367 }
371 ast::PathSegmentKind::CrateKw => { 368 ast::PathSegmentKind::CrateKw => {
372 if prefix.is_some() { 369 if prefix.is_some() {