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.rs213
1 files changed, 193 insertions, 20 deletions
diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs
index 35bdbafbf..6bca14444 100644
--- a/crates/ra_hir/src/nameres/lower.rs
+++ b/crates/ra_hir/src/nameres/lower.rs
@@ -1,10 +1,11 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 TextRange, SyntaxKind, AstNode, 4 TextRange, SyntaxKind, AstNode, SourceFile, TreeArc,
5 ast::{self, ModuleItemOwner}, 5 ast::{self, ModuleItemOwner},
6}; 6};
7use ra_db::{FileId, SourceRootId}; 7use ra_db::{SourceRootId, LocalSyntaxPtr};
8use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
8 9
9use crate::{ 10use crate::{
10 SourceItemId, SourceFileItemId, Path, ModuleSource, HirDatabase, Name, SourceFileItems, 11 SourceItemId, SourceFileItemId, Path, ModuleSource, HirDatabase, Name, SourceFileItems,
@@ -139,12 +140,12 @@ impl InputModuleItems {
139 fn add_use_item(&mut self, file_items: &SourceFileItems, item: &ast::UseItem) { 140 fn add_use_item(&mut self, file_items: &SourceFileItems, item: &ast::UseItem) {
140 let file_item_id = file_items.id_of_unchecked(item.syntax()); 141 let file_item_id = file_items.id_of_unchecked(item.syntax());
141 let start_offset = item.syntax().range().start(); 142 let start_offset = item.syntax().range().start();
142 Path::expand_use_item(item, |path, range| { 143 Path::expand_use_item(item, |path, segment| {
143 let kind = match range { 144 let kind = match segment {
144 None => ImportKind::Glob, 145 None => ImportKind::Glob,
145 Some(range) => ImportKind::Named(NamedImport { 146 Some(segment) => ImportKind::Named(NamedImport {
146 file_item_id, 147 file_item_id,
147 relative_range: range - start_offset, 148 relative_range: segment.syntax().range() - start_offset,
148 }), 149 }),
149 }; 150 };
150 self.imports.push(Import { kind, path }) 151 self.imports.push(Import { kind, path })
@@ -199,22 +200,194 @@ pub struct NamedImport {
199 pub relative_range: TextRange, 200 pub relative_range: TextRange,
200} 201}
201 202
202impl NamedImport {
203 // FIXME: this is only here for one use-case in completion. Seems like a
204 // pretty gross special case.
205 pub fn range(&self, db: &impl HirDatabase, file_id: FileId) -> TextRange {
206 let source_item_id = SourceItemId {
207 file_id: file_id.into(),
208 item_id: Some(self.file_item_id),
209 };
210 let syntax = db.file_item(source_item_id);
211 let offset = syntax.range().start();
212 self.relative_range + offset
213 }
214}
215
216#[derive(Debug, Clone, PartialEq, Eq)] 203#[derive(Debug, Clone, PartialEq, Eq)]
217pub(super) enum ImportKind { 204pub(super) enum ImportKind {
218 Glob, 205 Glob,
219 Named(NamedImport), 206 Named(NamedImport),
220} 207}
208
209#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
210pub struct LoweredImport(RawId);
211impl_arena_id!(LoweredImport);
212
213#[derive(Debug, PartialEq, Eq)]
214pub(super) struct ImportData {
215 pub(super) path: Path,
216 pub(super) is_glob: bool,
217}
218
219#[derive(Debug, Default, PartialEq, Eq)]
220pub struct LoweredModule {
221 pub(super) items: Vec<ModuleItem>,
222 pub(super) imports: Arena<LoweredImport, ImportData>,
223}
224
225#[derive(Debug, Default, PartialEq, Eq)]
226pub struct ImportSourceMap {
227 map: ArenaMap<LoweredImport, LocalSyntaxPtr>,
228}
229
230impl ImportSourceMap {
231 fn insert(&mut self, import: LoweredImport, segment: &ast::PathSegment) {
232 self.map
233 .insert(import, LocalSyntaxPtr::new(segment.syntax()))
234 }
235
236 pub fn get(&self, source: &ModuleSource, import: LoweredImport) -> TreeArc<ast::PathSegment> {
237 let file = match source {
238 ModuleSource::SourceFile(file) => &*file,
239 ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
240 };
241
242 ast::PathSegment::cast(&self.map[import].resolve(file))
243 .unwrap()
244 .to_owned()
245 }
246}
247
248impl LoweredModule {
249 pub(crate) fn lower_module_module_query(
250 db: &impl HirDatabase,
251 source_root_id: SourceRootId,
252 module_id: ModuleId,
253 ) -> Arc<LoweredModule> {
254 db.lower_module(source_root_id, module_id).0
255 }
256
257 pub(crate) fn lower_module_source_map_query(
258 db: &impl HirDatabase,
259 source_root_id: SourceRootId,
260 module_id: ModuleId,
261 ) -> Arc<ImportSourceMap> {
262 db.lower_module(source_root_id, module_id).1
263 }
264
265 pub(crate) fn lower_module_query(
266 db: &impl HirDatabase,
267 source_root_id: SourceRootId,
268 module_id: ModuleId,
269 ) -> (Arc<LoweredModule>, Arc<ImportSourceMap>) {
270 let module_tree = db.module_tree(source_root_id);
271 let source = module_id.source(&module_tree);
272 let file_id = source.file_id;
273 let source = ModuleSource::from_source_item_id(db, source);
274 let mut source_map = ImportSourceMap::default();
275 let mut res = LoweredModule::default();
276 match source {
277 ModuleSource::SourceFile(it) => res.fill(
278 &mut source_map,
279 db,
280 source_root_id,
281 module_id,
282 file_id,
283 &mut it.items_with_macros(),
284 ),
285 ModuleSource::Module(it) => {
286 if let Some(item_list) = it.item_list() {
287 res.fill(
288 &mut source_map,
289 db,
290 source_root_id,
291 module_id,
292 file_id,
293 &mut item_list.items_with_macros(),
294 )
295 }
296 }
297 };
298 (Arc::new(res), Arc::new(source_map))
299 }
300
301 fn fill(
302 &mut self,
303 source_map: &mut ImportSourceMap,
304 db: &impl HirDatabase,
305 source_root_id: SourceRootId,
306 module_id: ModuleId,
307 file_id: HirFileId,
308 items: &mut Iterator<Item = ast::ItemOrMacro>,
309 ) {
310 let file_items = db.file_items(file_id);
311
312 for item in items {
313 match item {
314 ast::ItemOrMacro::Item(it) => {
315 self.add_item(source_map, file_id, &file_items, it);
316 }
317 ast::ItemOrMacro::Macro(macro_call) => {
318 let item_id = file_items.id_of_unchecked(macro_call.syntax());
319 let loc = MacroCallLoc {
320 source_root_id,
321 module_id,
322 source_item_id: SourceItemId {
323 file_id,
324 item_id: Some(item_id),
325 },
326 };
327 let id = loc.id(db);
328 let file_id = HirFileId::from(id);
329 let file_items = db.file_items(file_id);
330 //FIXME: expand recursively
331 for item in db.hir_source_file(file_id).items() {
332 self.add_item(source_map, file_id, &file_items, item);
333 }
334 }
335 }
336 }
337 }
338
339 fn add_item(
340 &mut self,
341 source_map: &mut ImportSourceMap,
342 file_id: HirFileId,
343 file_items: &SourceFileItems,
344 item: &ast::ModuleItem,
345 ) -> Option<()> {
346 match item.kind() {
347 ast::ModuleItemKind::StructDef(it) => {
348 self.items.push(ModuleItem::new(file_id, file_items, it)?)
349 }
350 ast::ModuleItemKind::EnumDef(it) => {
351 self.items.push(ModuleItem::new(file_id, file_items, it)?)
352 }
353 ast::ModuleItemKind::FnDef(it) => {
354 self.items.push(ModuleItem::new(file_id, file_items, it)?)
355 }
356 ast::ModuleItemKind::TraitDef(it) => {
357 self.items.push(ModuleItem::new(file_id, file_items, it)?)
358 }
359 ast::ModuleItemKind::TypeDef(it) => {
360 self.items.push(ModuleItem::new(file_id, file_items, it)?)
361 }
362 ast::ModuleItemKind::ImplBlock(_) => {
363 // impls don't define items
364 }
365 ast::ModuleItemKind::UseItem(it) => self.add_use_item(source_map, it),
366 ast::ModuleItemKind::ExternCrateItem(_) => {
367 // TODO
368 }
369 ast::ModuleItemKind::ConstDef(it) => {
370 self.items.push(ModuleItem::new(file_id, file_items, it)?)
371 }
372 ast::ModuleItemKind::StaticDef(it) => {
373 self.items.push(ModuleItem::new(file_id, file_items, it)?)
374 }
375 ast::ModuleItemKind::Module(it) => {
376 self.items.push(ModuleItem::new(file_id, file_items, it)?)
377 }
378 }
379 Some(())
380 }
381
382 fn add_use_item(&mut self, source_map: &mut ImportSourceMap, item: &ast::UseItem) {
383 Path::expand_use_item(item, |path, segment| {
384 let import = self.imports.alloc(ImportData {
385 path,
386 is_glob: segment.is_none(),
387 });
388 if let Some(segment) = segment {
389 source_map.insert(import, segment)
390 }
391 })
392 }
393}