diff options
Diffstat (limited to 'crates/ra_analysis/src/descriptors/module')
-rw-r--r-- | crates/ra_analysis/src/descriptors/module/mod.rs | 1 | ||||
-rw-r--r-- | crates/ra_analysis/src/descriptors/module/nameres.rs | 156 |
2 files changed, 157 insertions, 0 deletions
diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index 091c150e5..958487541 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | pub(super) mod imp; | 1 | pub(super) mod imp; |
2 | mod scope; | 2 | mod scope; |
3 | mod nameres; | ||
3 | 4 | ||
4 | use std::sync::Arc; | 5 | use std::sync::Arc; |
5 | 6 | ||
diff --git a/crates/ra_analysis/src/descriptors/module/nameres.rs b/crates/ra_analysis/src/descriptors/module/nameres.rs new file mode 100644 index 000000000..137aa8b17 --- /dev/null +++ b/crates/ra_analysis/src/descriptors/module/nameres.rs | |||
@@ -0,0 +1,156 @@ | |||
1 | //! Name resolution algorithm | ||
2 | use rustc_hash::FxHashMap; | ||
3 | |||
4 | use ra_syntax::{ | ||
5 | SmolStr, SyntaxKind, | ||
6 | ast::{self, NameOwner} | ||
7 | }; | ||
8 | |||
9 | use crate::{ | ||
10 | descriptors::module::ModuleId, | ||
11 | syntax_ptr::LocalSyntaxPtr, | ||
12 | }; | ||
13 | |||
14 | /// A set of items and imports declared inside a module, without relation to | ||
15 | /// other modules. | ||
16 | /// | ||
17 | /// This stands in-between raw syntax and name resolution and alow us to avoid | ||
18 | /// recomputing name res: if `InputModuleItems` are the same, we can avoid | ||
19 | /// running name resolution. | ||
20 | #[derive(Debug, Default)] | ||
21 | struct InputModuleItems { | ||
22 | items: Vec<ModuleItem>, | ||
23 | glob_imports: Vec<Path>, | ||
24 | imports: Vec<Path>, | ||
25 | } | ||
26 | |||
27 | #[derive(Debug, Clone)] | ||
28 | struct Path { | ||
29 | kind: PathKind, | ||
30 | segments: Vec<SmolStr>, | ||
31 | } | ||
32 | |||
33 | #[derive(Debug, Clone, Copy)] | ||
34 | enum PathKind { | ||
35 | Abs, | ||
36 | Self_, | ||
37 | Super, | ||
38 | Crate, | ||
39 | } | ||
40 | |||
41 | #[derive(Debug)] | ||
42 | struct ItemMap { | ||
43 | per_module: FxHashMap<ModuleId, ModuleItems>, | ||
44 | } | ||
45 | |||
46 | #[derive(Debug)] | ||
47 | struct ModuleItems { | ||
48 | items: FxHashMap<SmolStr, PerNs<ModuleItem>>, | ||
49 | } | ||
50 | |||
51 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
52 | enum Namespace { | ||
53 | Types, | ||
54 | Values, | ||
55 | } | ||
56 | |||
57 | #[derive(Debug)] | ||
58 | struct PerNs<T> { | ||
59 | types: Option<T>, | ||
60 | values: Option<T>, | ||
61 | } | ||
62 | |||
63 | #[derive(Debug)] | ||
64 | struct ModuleItem { | ||
65 | ptr: LocalSyntaxPtr, | ||
66 | name: SmolStr, | ||
67 | kind: SyntaxKind, | ||
68 | vis: Vis, | ||
69 | } | ||
70 | |||
71 | #[derive(Debug)] | ||
72 | enum Vis { | ||
73 | Priv, | ||
74 | Other, | ||
75 | } | ||
76 | |||
77 | impl InputModuleItems { | ||
78 | fn new<'a>(items: impl Iterator<Item = ast::ModuleItem<'a>>) -> InputModuleItems { | ||
79 | let mut res = InputModuleItems::default(); | ||
80 | for item in items { | ||
81 | res.add_item(item); | ||
82 | } | ||
83 | res | ||
84 | } | ||
85 | |||
86 | fn add_item(&mut self, item: ast::ModuleItem) -> Option<()> { | ||
87 | match item { | ||
88 | ast::ModuleItem::StructDef(it) => self.items.push(ModuleItem::new(it)?), | ||
89 | ast::ModuleItem::EnumDef(it) => self.items.push(ModuleItem::new(it)?), | ||
90 | ast::ModuleItem::FnDef(it) => self.items.push(ModuleItem::new(it)?), | ||
91 | ast::ModuleItem::TraitDef(it) => self.items.push(ModuleItem::new(it)?), | ||
92 | ast::ModuleItem::TypeDef(it) => self.items.push(ModuleItem::new(it)?), | ||
93 | ast::ModuleItem::ImplItem(it) => { | ||
94 | // impls don't define items | ||
95 | } | ||
96 | ast::ModuleItem::UseItem(it) => self.add_use_item(it), | ||
97 | ast::ModuleItem::ExternCrateItem(it) => (), | ||
98 | ast::ModuleItem::ConstDef(it) => self.items.push(ModuleItem::new(it)?), | ||
99 | ast::ModuleItem::StaticDef(it) => self.items.push(ModuleItem::new(it)?), | ||
100 | ast::ModuleItem::Module(it) => self.items.push(ModuleItem::new(it)?), | ||
101 | } | ||
102 | Some(()) | ||
103 | } | ||
104 | |||
105 | fn add_use_item(&mut self, item: ast::UseItem) { | ||
106 | if let Some(tree) = item.use_tree() { | ||
107 | self.add_use_tree(None, tree); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | fn add_use_tree(&mut self, prefix: Option<Path>, tree: ast::UseTree) { | ||
112 | if let Some(use_tree_list) = tree.use_tree_list() { | ||
113 | let prefix = match tree.path() { | ||
114 | None => prefix, | ||
115 | Some(path) => match convert_path(prefix, path) { | ||
116 | Some(it) => Some(it), | ||
117 | None => return, // TODO: report errors somewhere | ||
118 | }, | ||
119 | }; | ||
120 | for tree in use_tree_list.use_trees() { | ||
121 | self.add_use_tree(prefix.clone(), tree); | ||
122 | } | ||
123 | } else { | ||
124 | if let Some(path) = tree.path() { | ||
125 | if let Some(path) = convert_path(prefix, path) { | ||
126 | if tree.has_star() { | ||
127 | &mut self.glob_imports | ||
128 | } else { | ||
129 | &mut self.imports | ||
130 | } | ||
131 | .push(path); | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | |||
138 | fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> { | ||
139 | prefix | ||
140 | } | ||
141 | |||
142 | impl ModuleItem { | ||
143 | fn new<'a>(item: impl ast::NameOwner<'a>) -> Option<ModuleItem> { | ||
144 | let name = item.name()?.text(); | ||
145 | let ptr = LocalSyntaxPtr::new(item.syntax()); | ||
146 | let kind = item.syntax().kind(); | ||
147 | let vis = Vis::Other; | ||
148 | let res = ModuleItem { | ||
149 | ptr, | ||
150 | name, | ||
151 | kind, | ||
152 | vis, | ||
153 | }; | ||
154 | Some(res) | ||
155 | } | ||
156 | } | ||