From 80ab3433d3376b7c44787d63af6e7b3217ae41d8 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 30 Aug 2018 20:37:33 +0300 Subject: complete imports --- crates/libeditor/src/scope/mod_scope.rs | 88 +++++++++++++++++++++++++++------ 1 file changed, 74 insertions(+), 14 deletions(-) (limited to 'crates/libeditor/src/scope/mod_scope.rs') diff --git a/crates/libeditor/src/scope/mod_scope.rs b/crates/libeditor/src/scope/mod_scope.rs index aa8dd93a7..25faee3b8 100644 --- a/crates/libeditor/src/scope/mod_scope.rs +++ b/crates/libeditor/src/scope/mod_scope.rs @@ -6,21 +6,38 @@ pub struct ModuleScope { entries: Vec, } +pub struct Entry { + node: SyntaxNode, + kind: EntryKind, +} + +enum EntryKind { + Item, Import, +} + impl ModuleScope { pub fn new(m: ast::Root) -> ModuleScope { - let entries = m.items().filter_map(|item| { - match item { + let mut entries = Vec::new(); + for item in m.items() { + let entry = match item { ast::ModuleItem::StructDef(item) => Entry::new(item), ast::ModuleItem::EnumDef(item) => Entry::new(item), ast::ModuleItem::FnDef(item) => Entry::new(item), ast::ModuleItem::ConstDef(item) => Entry::new(item), ast::ModuleItem::StaticDef(item) => Entry::new(item), ast::ModuleItem::TraitDef(item) => Entry::new(item), + ast::ModuleItem::Module(item) => Entry::new(item), + ast::ModuleItem::UseItem(item) => { + if let Some(tree) = item.use_tree() { + collect_imports(tree, &mut entries); + } + continue; + }, ast::ModuleItem::ExternCrateItem(_) | - ast::ModuleItem::ImplItem(_) | - ast::ModuleItem::UseItem(_) => None - } - }).collect(); + ast::ModuleItem::ImplItem(_) => continue, + }; + entries.extend(entry) + } ModuleScope { entries } } @@ -30,20 +47,63 @@ impl ModuleScope { } } -pub struct Entry { - name: SyntaxNode, -} - impl Entry { fn new<'a>(item: impl ast::NameOwner<'a>) -> Option { let name = item.name()?; - Some(Entry { name: name.syntax().owned() }) + Some(Entry { node: name.syntax().owned(), kind: EntryKind::Item }) + } + fn new_import(path: ast::Path) -> Option { + let name_ref = path.segment()?.name_ref()?; + Some(Entry { node: name_ref.syntax().owned(), kind: EntryKind::Import }) } pub fn name(&self) -> SmolStr { - self.ast().text() + match self.kind { + EntryKind::Item => + ast::Name::cast(self.node.borrowed()).unwrap() + .text(), + EntryKind::Import => + ast::NameRef::cast(self.node.borrowed()).unwrap() + .text(), + } } - fn ast(&self) -> ast::Name { - ast::Name::cast(self.name.borrowed()).unwrap() +} + +fn collect_imports(tree: ast::UseTree, acc: &mut Vec) { + if let Some(use_tree_list) = tree.use_tree_list() { + return use_tree_list.use_trees().for_each(|it| collect_imports(it, acc)); + } + if let Some(path) = tree.path() { + acc.extend(Entry::new_import(path)); } } + +#[cfg(test)] +mod tests { + use super::*; + use libsyntax2::File; + + fn do_check(code: &str, expected: &[&str]) { + let file = File::parse(&code); + let scope = ModuleScope::new(file.ast()); + let actual = scope.entries + .iter() + .map(|it| it.name()) + .collect::>(); + assert_eq!(expected, actual.as_slice()); + } + + #[test] + fn test_module_scope() { + do_check(" + struct Foo; + enum Bar {} + mod baz {} + fn quux() {} + use x::{ + y::z, + t, + }; + ", &["Foo", "Bar", "baz", "quux", "z", "t"]) + } +} -- cgit v1.2.3