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