aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/nameres/lower.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/nameres/lower.rs')
-rw-r--r--crates/ra_hir/src/nameres/lower.rs200
1 files changed, 200 insertions, 0 deletions
diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs
new file mode 100644
index 000000000..dd3bf245f
--- /dev/null
+++ b/crates/ra_hir/src/nameres/lower.rs
@@ -0,0 +1,200 @@
1use std::sync::Arc;
2
3use ra_syntax::{
4 TextRange, SyntaxKind, AstNode,
5 ast::{self, ModuleItemOwner},
6};
7use ra_db::{FileId, SourceRootId};
8
9use crate::{
10 SourceItemId, SourceFileItemId, Path, ModuleSource, HirDatabase, Name, SourceFileItems,
11 HirFileId, MacroCallLoc, AsName,
12 module_tree::ModuleId
13};
14/// A set of items and imports declared inside a module, without relation to
15/// other modules.
16///
17/// This sits in-between raw syntax and name resolution and allows us to avoid
18/// recomputing name res: if two instance of `InputModuleItems` are the same, we
19/// can avoid redoing name resolution.
20#[derive(Debug, Default, PartialEq, Eq)]
21pub struct InputModuleItems {
22 pub(crate) items: Vec<ModuleItem>,
23 pub(super) imports: Vec<Import>,
24}
25
26impl InputModuleItems {
27 pub(crate) fn input_module_items_query(
28 db: &impl HirDatabase,
29 source_root_id: SourceRootId,
30 module_id: ModuleId,
31 ) -> Arc<InputModuleItems> {
32 let module_tree = db.module_tree(source_root_id);
33 let source = module_id.source(&module_tree);
34 let file_id = source.file_id;
35 let source = ModuleSource::from_source_item_id(db, source);
36 let file_items = db.file_items(file_id);
37 let fill = |acc: &mut InputModuleItems, items: &mut Iterator<Item = ast::ItemOrMacro>| {
38 for item in items {
39 match item {
40 ast::ItemOrMacro::Item(it) => {
41 acc.add_item(file_id, &file_items, it);
42 }
43 ast::ItemOrMacro::Macro(macro_call) => {
44 let item_id = file_items.id_of_unchecked(macro_call.syntax());
45 let loc = MacroCallLoc {
46 source_root_id,
47 module_id,
48 source_item_id: SourceItemId {
49 file_id,
50 item_id: Some(item_id),
51 },
52 };
53 let id = loc.id(db);
54 let file_id = HirFileId::from(id);
55 let file_items = db.file_items(file_id);
56 //FIXME: expand recursively
57 for item in db.hir_source_file(file_id).items() {
58 acc.add_item(file_id, &file_items, item);
59 }
60 }
61 }
62 }
63 };
64
65 let mut res = InputModuleItems::default();
66 match source {
67 ModuleSource::SourceFile(it) => fill(&mut res, &mut it.items_with_macros()),
68 ModuleSource::Module(it) => {
69 if let Some(item_list) = it.item_list() {
70 fill(&mut res, &mut item_list.items_with_macros())
71 }
72 }
73 };
74 Arc::new(res)
75 }
76
77 pub(crate) fn add_item(
78 &mut self,
79 file_id: HirFileId,
80 file_items: &SourceFileItems,
81 item: &ast::ModuleItem,
82 ) -> Option<()> {
83 match item.kind() {
84 ast::ModuleItemKind::StructDef(it) => {
85 self.items.push(ModuleItem::new(file_id, file_items, it)?)
86 }
87 ast::ModuleItemKind::EnumDef(it) => {
88 self.items.push(ModuleItem::new(file_id, file_items, it)?)
89 }
90 ast::ModuleItemKind::FnDef(it) => {
91 self.items.push(ModuleItem::new(file_id, file_items, it)?)
92 }
93 ast::ModuleItemKind::TraitDef(it) => {
94 self.items.push(ModuleItem::new(file_id, file_items, it)?)
95 }
96 ast::ModuleItemKind::TypeDef(it) => {
97 self.items.push(ModuleItem::new(file_id, file_items, it)?)
98 }
99 ast::ModuleItemKind::ImplBlock(_) => {
100 // impls don't define items
101 }
102 ast::ModuleItemKind::UseItem(it) => self.add_use_item(file_items, it),
103 ast::ModuleItemKind::ExternCrateItem(_) => {
104 // TODO
105 }
106 ast::ModuleItemKind::ConstDef(it) => {
107 self.items.push(ModuleItem::new(file_id, file_items, it)?)
108 }
109 ast::ModuleItemKind::StaticDef(it) => {
110 self.items.push(ModuleItem::new(file_id, file_items, it)?)
111 }
112 ast::ModuleItemKind::Module(it) => {
113 self.items.push(ModuleItem::new(file_id, file_items, it)?)
114 }
115 }
116 Some(())
117 }
118
119 fn add_use_item(&mut self, file_items: &SourceFileItems, item: &ast::UseItem) {
120 let file_item_id = file_items.id_of_unchecked(item.syntax());
121 let start_offset = item.syntax().range().start();
122 Path::expand_use_item(item, |path, range| {
123 let kind = match range {
124 None => ImportKind::Glob,
125 Some(range) => ImportKind::Named(NamedImport {
126 file_item_id,
127 relative_range: range - start_offset,
128 }),
129 };
130 self.imports.push(Import { kind, path })
131 })
132 }
133}
134
135#[derive(Debug, PartialEq, Eq)]
136pub(super) enum Vis {
137 // Priv,
138 Other,
139}
140
141#[derive(Debug, PartialEq, Eq)]
142pub(crate) struct ModuleItem {
143 pub(crate) id: SourceItemId,
144 pub(crate) name: Name,
145 pub(super) kind: SyntaxKind,
146 pub(super) vis: Vis,
147}
148
149impl ModuleItem {
150 fn new(
151 file_id: HirFileId,
152 file_items: &SourceFileItems,
153 item: &impl ast::NameOwner,
154 ) -> Option<ModuleItem> {
155 let name = item.name()?.as_name();
156 let kind = item.syntax().kind();
157 let vis = Vis::Other;
158 let item_id = Some(file_items.id_of_unchecked(item.syntax()));
159 let id = SourceItemId { file_id, item_id };
160 let res = ModuleItem {
161 id,
162 name,
163 kind,
164 vis,
165 };
166 Some(res)
167 }
168}
169
170#[derive(Debug, Clone, PartialEq, Eq)]
171pub(super) struct Import {
172 pub(super) path: Path,
173 pub(super) kind: ImportKind,
174}
175
176#[derive(Debug, Clone, Copy, PartialEq, Eq)]
177pub struct NamedImport {
178 pub file_item_id: SourceFileItemId,
179 pub relative_range: TextRange,
180}
181
182impl NamedImport {
183 // FIXME: this is only here for one use-case in completion. Seems like a
184 // pretty gross special case.
185 pub fn range(&self, db: &impl HirDatabase, file_id: FileId) -> TextRange {
186 let source_item_id = SourceItemId {
187 file_id: file_id.into(),
188 item_id: Some(self.file_item_id),
189 };
190 let syntax = db.file_item(source_item_id);
191 let offset = syntax.range().start();
192 self.relative_range + offset
193 }
194}
195
196#[derive(Debug, Clone, PartialEq, Eq)]
197pub(super) enum ImportKind {
198 Glob,
199 Named(NamedImport),
200}