diff options
Diffstat (limited to 'crates/ra_analysis/src/descriptors/path.rs')
-rw-r--r-- | crates/ra_analysis/src/descriptors/path.rs | 106 |
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 @@ | |||
1 | use ra_syntax::{SmolStr, ast, AstNode}; | ||
2 | |||
3 | use crate::syntax_ptr::LocalSyntaxPtr; | ||
4 | |||
5 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
6 | pub(crate) struct Path { | ||
7 | pub(crate) kind: PathKind, | ||
8 | pub(crate) segments: Vec<SmolStr>, | ||
9 | } | ||
10 | |||
11 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
12 | pub(crate) enum PathKind { | ||
13 | Abs, | ||
14 | Self_, | ||
15 | Super, | ||
16 | Crate, | ||
17 | } | ||
18 | |||
19 | impl 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 | |||
30 | fn 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 | |||
61 | fn 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 | } | ||