aboutsummaryrefslogtreecommitdiff
path: root/crates/libeditor
diff options
context:
space:
mode:
Diffstat (limited to 'crates/libeditor')
-rw-r--r--crates/libeditor/src/scope/mod_scope.rs88
1 files changed, 74 insertions, 14 deletions
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 {
6 entries: Vec<Entry>, 6 entries: Vec<Entry>,
7} 7}
8 8
9pub struct Entry {
10 node: SyntaxNode,
11 kind: EntryKind,
12}
13
14enum EntryKind {
15 Item, Import,
16}
17
9impl ModuleScope { 18impl ModuleScope {
10 pub fn new(m: ast::Root) -> ModuleScope { 19 pub fn new(m: ast::Root) -> ModuleScope {
11 let entries = m.items().filter_map(|item| { 20 let mut entries = Vec::new();
12 match item { 21 for item in m.items() {
22 let entry = match item {
13 ast::ModuleItem::StructDef(item) => Entry::new(item), 23 ast::ModuleItem::StructDef(item) => Entry::new(item),
14 ast::ModuleItem::EnumDef(item) => Entry::new(item), 24 ast::ModuleItem::EnumDef(item) => Entry::new(item),
15 ast::ModuleItem::FnDef(item) => Entry::new(item), 25 ast::ModuleItem::FnDef(item) => Entry::new(item),
16 ast::ModuleItem::ConstDef(item) => Entry::new(item), 26 ast::ModuleItem::ConstDef(item) => Entry::new(item),
17 ast::ModuleItem::StaticDef(item) => Entry::new(item), 27 ast::ModuleItem::StaticDef(item) => Entry::new(item),
18 ast::ModuleItem::TraitDef(item) => Entry::new(item), 28 ast::ModuleItem::TraitDef(item) => Entry::new(item),
29 ast::ModuleItem::Module(item) => Entry::new(item),
30 ast::ModuleItem::UseItem(item) => {
31 if let Some(tree) = item.use_tree() {
32 collect_imports(tree, &mut entries);
33 }
34 continue;
35 },
19 ast::ModuleItem::ExternCrateItem(_) | 36 ast::ModuleItem::ExternCrateItem(_) |
20 ast::ModuleItem::ImplItem(_) | 37 ast::ModuleItem::ImplItem(_) => continue,
21 ast::ModuleItem::UseItem(_) => None 38 };
22 } 39 entries.extend(entry)
23 }).collect(); 40 }
24 41
25 ModuleScope { entries } 42 ModuleScope { entries }
26 } 43 }
@@ -30,20 +47,63 @@ impl ModuleScope {
30 } 47 }
31} 48}
32 49
33pub struct Entry {
34 name: SyntaxNode,
35}
36
37impl Entry { 50impl Entry {
38 fn new<'a>(item: impl ast::NameOwner<'a>) -> Option<Entry> { 51 fn new<'a>(item: impl ast::NameOwner<'a>) -> Option<Entry> {
39 let name = item.name()?; 52 let name = item.name()?;
40 Some(Entry { name: name.syntax().owned() }) 53 Some(Entry { node: name.syntax().owned(), kind: EntryKind::Item })
54 }
55 fn new_import(path: ast::Path) -> Option<Entry> {
56 let name_ref = path.segment()?.name_ref()?;
57 Some(Entry { node: name_ref.syntax().owned(), kind: EntryKind::Import })
41 } 58 }
42 pub fn name(&self) -> SmolStr { 59 pub fn name(&self) -> SmolStr {
43 self.ast().text() 60 match self.kind {
61 EntryKind::Item =>
62 ast::Name::cast(self.node.borrowed()).unwrap()
63 .text(),
64 EntryKind::Import =>
65 ast::NameRef::cast(self.node.borrowed()).unwrap()
66 .text(),
67 }
44 } 68 }
45 fn ast(&self) -> ast::Name { 69}
46 ast::Name::cast(self.name.borrowed()).unwrap() 70
71fn collect_imports(tree: ast::UseTree, acc: &mut Vec<Entry>) {
72 if let Some(use_tree_list) = tree.use_tree_list() {
73 return use_tree_list.use_trees().for_each(|it| collect_imports(it, acc));
74 }
75 if let Some(path) = tree.path() {
76 acc.extend(Entry::new_import(path));
47 } 77 }
48} 78}
49 79
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use libsyntax2::File;
85
86 fn do_check(code: &str, expected: &[&str]) {
87 let file = File::parse(&code);
88 let scope = ModuleScope::new(file.ast());
89 let actual = scope.entries
90 .iter()
91 .map(|it| it.name())
92 .collect::<Vec<_>>();
93 assert_eq!(expected, actual.as_slice());
94 }
95
96 #[test]
97 fn test_module_scope() {
98 do_check("
99 struct Foo;
100 enum Bar {}
101 mod baz {}
102 fn quux() {}
103 use x::{
104 y::z,
105 t,
106 };
107 ", &["Foo", "Bar", "baz", "quux", "z", "t"])
108 }
109}