aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src/descriptors/path.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis/src/descriptors/path.rs')
-rw-r--r--crates/ra_analysis/src/descriptors/path.rs106
1 files changed, 106 insertions, 0 deletions
diff --git a/crates/ra_analysis/src/descriptors/path.rs b/crates/ra_analysis/src/descriptors/path.rs
new file mode 100644
index 000000000..4ed561b51
--- /dev/null
+++ b/crates/ra_analysis/src/descriptors/path.rs
@@ -0,0 +1,106 @@
1use ra_syntax::{SmolStr, ast, AstNode};
2
3use crate::syntax_ptr::LocalSyntaxPtr;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub(crate) struct Path {
7 pub(crate) kind: PathKind,
8 pub(crate) segments: Vec<SmolStr>,
9}
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub(crate) enum PathKind {
13 Abs,
14 Self_,
15 Super,
16 Crate,
17}
18
19impl Path {
20 pub(crate) fn expand_use_item(
21 item: ast::UseItem,
22 mut cb: impl FnMut(Path, Option<LocalSyntaxPtr>),
23 ) {
24 if let Some(tree) = item.use_tree() {
25 expand_use_tree(None, tree, &mut cb);
26 }
27 }
28}
29
30fn expand_use_tree(
31 prefix: Option<Path>,
32 tree: ast::UseTree,
33 cb: &mut impl FnMut(Path, Option<LocalSyntaxPtr>),
34) {
35 if let Some(use_tree_list) = tree.use_tree_list() {
36 let prefix = match tree.path() {
37 None => prefix,
38 Some(path) => match convert_path(prefix, path) {
39 Some(it) => Some(it),
40 None => return, // TODO: report errors somewhere
41 },
42 };
43 for tree in use_tree_list.use_trees() {
44 expand_use_tree(prefix.clone(), tree, cb);
45 }
46 } else {
47 if let Some(ast_path) = tree.path() {
48 if let Some(path) = convert_path(prefix, ast_path) {
49 let ptr = if tree.has_star() {
50 None
51 } else {
52 let ptr = LocalSyntaxPtr::new(ast_path.segment().unwrap().syntax());
53 Some(ptr)
54 };
55 cb(path, ptr)
56 }
57 }
58 }
59}
60
61fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> {
62 let prefix = if let Some(qual) = path.qualifier() {
63 Some(convert_path(prefix, qual)?)
64 } else {
65 None
66 };
67 let segment = path.segment()?;
68 let res = match segment.kind()? {
69 ast::PathSegmentKind::Name(name) => {
70 let mut res = prefix.unwrap_or_else(|| Path {
71 kind: PathKind::Abs,
72 segments: Vec::with_capacity(1),
73 });
74 res.segments.push(name.text());
75 res
76 }
77 ast::PathSegmentKind::CrateKw => {
78 if prefix.is_some() {
79 return None;
80 }
81 Path {
82 kind: PathKind::Crate,
83 segments: Vec::new(),
84 }
85 }
86 ast::PathSegmentKind::SelfKw => {
87 if prefix.is_some() {
88 return None;
89 }
90 Path {
91 kind: PathKind::Self_,
92 segments: Vec::new(),
93 }
94 }
95 ast::PathSegmentKind::SuperKw => {
96 if prefix.is_some() {
97 return None;
98 }
99 Path {
100 kind: PathKind::Super,
101 segments: Vec::new(),
102 }
103 }
104 };
105 Some(res)
106}