4 algo::visit::{visitor, Visitor},
5 ast::{self, AttrsOwner, NameOwner, TypeAscriptionOwner, TypeParamsOwner},
6 AstNode, SourceFile, SyntaxKind, SyntaxNode, WalkEvent,
9 #[derive(Debug, Clone)]
10 pub struct StructureNode {
11 pub parent: Option<usize>,
13 pub navigation_range: TextRange,
14 pub node_range: TextRange,
16 pub detail: Option<String>,
20 pub fn file_structure(file: &SourceFile) -> Vec<StructureNode> {
21 let mut res = Vec::new();
22 let mut stack = Vec::new();
24 for event in file.syntax().preorder() {
26 WalkEvent::Enter(node) => {
27 if let Some(mut symbol) = structure_node(&node) {
28 symbol.parent = stack.last().copied();
29 stack.push(res.len());
33 WalkEvent::Leave(node) => {
34 if structure_node(&node).is_some() {
43 fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
44 fn decl<N: NameOwner + AttrsOwner>(node: N) -> Option<StructureNode> {
45 decl_with_detail(node, None)
48 fn decl_with_ascription<N: NameOwner + AttrsOwner + TypeAscriptionOwner>(
50 ) -> Option<StructureNode> {
51 let ty = node.ascribed_type();
52 decl_with_type_ref(node, ty)
55 fn decl_with_type_ref<N: NameOwner + AttrsOwner>(
57 type_ref: Option<ast::TypeRef>,
58 ) -> Option<StructureNode> {
59 let detail = type_ref.map(|type_ref| {
60 let mut detail = String::new();
61 collapse_ws(type_ref.syntax(), &mut detail);
64 decl_with_detail(node, detail)
67 fn decl_with_detail<N: NameOwner + AttrsOwner>(
69 detail: Option<String>,
70 ) -> Option<StructureNode> {
71 let name = node.name()?;
75 label: name.text().to_string(),
76 navigation_range: name.syntax().text_range(),
77 node_range: node.syntax().text_range(),
78 kind: node.syntax().kind(),
80 deprecated: node.attrs().filter_map(|x| x.simple_name()).any(|x| x == "deprecated"),
84 fn collapse_ws(node: &SyntaxNode, output: &mut String) {
85 let mut can_insert_ws = false;
86 node.text().for_each_chunk(|chunk| {
87 for line in chunk.lines() {
88 let line = line.trim();
92 can_insert_ws = false;
95 output.push_str(line);
103 .visit(|fn_def: ast::FnDef| {
104 let mut detail = String::from("fn");
105 if let Some(type_param_list) = fn_def.type_param_list() {
106 collapse_ws(type_param_list.syntax(), &mut detail);
108 if let Some(param_list) = fn_def.param_list() {
109 collapse_ws(param_list.syntax(), &mut detail);
111 if let Some(ret_type) = fn_def.ret_type() {
112 detail.push_str(" ");
113 collapse_ws(ret_type.syntax(), &mut detail);
116 decl_with_detail(fn_def, Some(detail))
118 .visit(decl::<ast::StructDef>)
119 .visit(decl::<ast::EnumDef>)
120 .visit(decl::<ast::EnumVariant>)
121 .visit(decl::<ast::TraitDef>)
122 .visit(decl::<ast::Module>)
123 .visit(|td: ast::TypeAliasDef| {
124 let ty = td.type_ref();
125 decl_with_type_ref(td, ty)
127 .visit(decl_with_ascription::<ast::RecordFieldDef>)
128 .visit(decl_with_ascription::<ast::ConstDef>)
129 .visit(decl_with_ascription::<ast::StaticDef>)
130 .visit(|im: ast::ImplBlock| {
131 let target_type = im.target_type()?;
132 let target_trait = im.target_trait();
133 let label = match target_trait {
134 None => format!("impl {}", target_type.syntax().text()),
136 format!("impl {} for {}", t.syntax().text(), target_type.syntax().text(),)
140 let node = StructureNode {
143 navigation_range: target_type.syntax().text_range(),
144 node_range: im.syntax().text_range(),
145 kind: im.syntax().kind(),
151 .visit(|mc: ast::MacroCall| {
152 let first_token = mc.syntax().first_token().unwrap();
153 if first_token.text().as_str() != "macro_rules" {
164 use insta::assert_debug_snapshot;
167 fn test_file_structure() {
168 let file = SourceFile::parse(
176 fn bar2<T>(t: T) -> T {}
191 impl fmt::Debug for E {}
200 #[deprecated(note = "for awhile")]
201 fn very_obsolete() {}
206 let structure = file_structure(&file);
207 assert_debug_snapshot!(structure,
212 navigation_range: [8; 11),
223 navigation_range: [18; 19),
224 node_range: [18; 24),
225 kind: RECORD_FIELD_DEF,
234 navigation_range: [32; 33),
235 node_range: [28; 158),
245 navigation_range: [43; 47),
246 node_range: [40; 52),
258 navigation_range: [60; 64),
259 node_range: [57; 81),
271 navigation_range: [89; 93),
272 node_range: [86; 156),
275 "fn<A, B>(a: A, b: B) -> Vec< u32 >",
282 navigation_range: [165; 166),
283 node_range: [160; 180),
293 navigation_range: [169; 170),
294 node_range: [169; 170),
304 navigation_range: [172; 173),
305 node_range: [172; 178),
313 navigation_range: [186; 187),
314 node_range: [181; 193),
315 kind: TYPE_ALIAS_DEF,
324 navigation_range: [201; 202),
325 node_range: [194; 213),
335 navigation_range: [220; 221),
336 node_range: [214; 232),
346 navigation_range: [239; 240),
347 node_range: [234; 243),
354 label: "impl fmt::Debug for E",
355 navigation_range: [265; 266),
356 node_range: [245; 269),
364 navigation_range: [284; 286),
365 node_range: [271; 303),
373 navigation_range: [322; 330),
374 node_range: [305; 335),
383 label: "very_obsolete",
384 navigation_range: [375; 388),
385 node_range: [337; 393),