aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_analysis/src/imp.rs4
-rw-r--r--crates/ra_analysis/src/lib.rs5
-rw-r--r--crates/ra_analysis/src/symbol_index.rs123
-rw-r--r--crates/ra_editor/src/lib.rs4
-rw-r--r--crates/ra_editor/src/structure.rs129
-rw-r--r--crates/ra_editor/src/symbols.rs246
6 files changed, 255 insertions, 256 deletions
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index 5669aa94d..f3b513de1 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -10,7 +10,7 @@ use hir::{
10 self, FnSignatureInfo, Problem, source_binder, 10 self, FnSignatureInfo, Problem, source_binder,
11}; 11};
12use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase}; 12use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase};
13use ra_editor::{self, FileSymbol, find_node_at_offset, LineIndex, LocalEdit, Severity}; 13use ra_editor::{self, find_node_at_offset, LineIndex, LocalEdit, Severity};
14use ra_syntax::{ 14use ra_syntax::{
15 algo::find_covering_node, 15 algo::find_covering_node,
16 ast::{self, ArgListOwner, Expr, FnDef, NameOwner}, 16 ast::{self, ArgListOwner, Expr, FnDef, NameOwner},
@@ -25,7 +25,7 @@ use crate::{
25 completion::{CompletionItem, completions}, 25 completion::{CompletionItem, completions},
26 CrateId, db, Diagnostic, FileId, FilePosition, FileRange, FileSystemEdit, 26 CrateId, db, Diagnostic, FileId, FilePosition, FileRange, FileSystemEdit,
27 Query, ReferenceResolution, RootChange, SourceChange, SourceFileEdit, 27 Query, ReferenceResolution, RootChange, SourceChange, SourceFileEdit,
28 symbol_index::{LibrarySymbolsQuery, SymbolIndex, SymbolsDatabase}, 28 symbol_index::{LibrarySymbolsQuery, SymbolIndex, SymbolsDatabase, FileSymbol},
29}; 29};
30 30
31#[derive(Debug, Default)] 31#[derive(Debug, Default)]
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index e6cfaecc3..ff28271ab 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -36,10 +36,11 @@ use crate::{
36 36
37pub use crate::{ 37pub use crate::{
38 completion::{CompletionItem, CompletionItemKind, InsertText}, 38 completion::{CompletionItem, CompletionItemKind, InsertText},
39 runnables::{Runnable, RunnableKind} 39 runnables::{Runnable, RunnableKind},
40 symbol_index::FileSymbol,
40}; 41};
41pub use ra_editor::{ 42pub use ra_editor::{
42 FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, StructureNode, Severity 43 Fold, FoldKind, HighlightedRange, LineIndex, StructureNode, Severity
43}; 44};
44pub use hir::FnSignatureInfo; 45pub use hir::FnSignatureInfo;
45 46
diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs
index e5bdf0aa1..edb2268fb 100644
--- a/crates/ra_analysis/src/symbol_index.rs
+++ b/crates/ra_analysis/src/symbol_index.rs
@@ -4,10 +4,11 @@ use std::{
4}; 4};
5 5
6use fst::{self, Streamer}; 6use fst::{self, Streamer};
7use ra_editor::{self, FileSymbol};
8use ra_syntax::{ 7use ra_syntax::{
9 SourceFileNode, 8 AstNode, SyntaxNodeRef, SourceFileNode, SmolStr, TextRange,
9 algo::visit::{visitor, Visitor},
10 SyntaxKind::{self, *}, 10 SyntaxKind::{self, *},
11 ast::{self, NameOwner, DocCommentsOwner},
11}; 12};
12use ra_db::{SyntaxDatabase, SourceRootId}; 13use ra_db::{SyntaxDatabase, SourceRootId};
13use rayon::prelude::*; 14use rayon::prelude::*;
@@ -65,8 +66,9 @@ impl SymbolIndex {
65 ) -> SymbolIndex { 66 ) -> SymbolIndex {
66 let mut symbols = files 67 let mut symbols = files
67 .flat_map(|(file_id, file)| { 68 .flat_map(|(file_id, file)| {
68 ra_editor::file_symbols(&file) 69 file.syntax()
69 .into_iter() 70 .descendants()
71 .filter_map(to_symbol)
70 .map(move |symbol| (symbol.name.as_str().to_lowercase(), (file_id, symbol))) 72 .map(move |symbol| (symbol.name.as_str().to_lowercase(), (file_id, symbol)))
71 .collect::<Vec<_>>() 73 .collect::<Vec<_>>()
72 }) 74 })
@@ -121,3 +123,116 @@ fn is_type(kind: SyntaxKind) -> bool {
121 _ => false, 123 _ => false,
122 } 124 }
123} 125}
126
127#[derive(Debug, Clone, PartialEq, Eq, Hash)]
128pub struct FileSymbol {
129 pub name: SmolStr,
130 pub node_range: TextRange,
131 pub kind: SyntaxKind,
132}
133
134impl FileSymbol {
135 pub fn docs(&self, file: &SourceFileNode) -> Option<String> {
136 file.syntax()
137 .descendants()
138 .filter(|node| node.kind() == self.kind && node.range() == self.node_range)
139 .filter_map(|node: SyntaxNodeRef| {
140 fn doc_comments<'a, N: DocCommentsOwner<'a>>(node: N) -> Option<String> {
141 let comments = node.doc_comment_text();
142 if comments.is_empty() {
143 None
144 } else {
145 Some(comments)
146 }
147 }
148
149 visitor()
150 .visit(doc_comments::<ast::FnDef>)
151 .visit(doc_comments::<ast::StructDef>)
152 .visit(doc_comments::<ast::EnumDef>)
153 .visit(doc_comments::<ast::TraitDef>)
154 .visit(doc_comments::<ast::Module>)
155 .visit(doc_comments::<ast::TypeDef>)
156 .visit(doc_comments::<ast::ConstDef>)
157 .visit(doc_comments::<ast::StaticDef>)
158 .accept(node)?
159 })
160 .nth(0)
161 }
162 /// Get a description of this node.
163 ///
164 /// e.g. `struct Name`, `enum Name`, `fn Name`
165 pub fn description(&self, file: &SourceFileNode) -> Option<String> {
166 // TODO: After type inference is done, add type information to improve the output
167 file.syntax()
168 .descendants()
169 .filter(|node| node.kind() == self.kind && node.range() == self.node_range)
170 .filter_map(|node: SyntaxNodeRef| {
171 // TODO: Refactor to be have less repetition
172 visitor()
173 .visit(|node: ast::FnDef| {
174 let mut string = "fn ".to_string();
175 node.name()?.syntax().text().push_to(&mut string);
176 Some(string)
177 })
178 .visit(|node: ast::StructDef| {
179 let mut string = "struct ".to_string();
180 node.name()?.syntax().text().push_to(&mut string);
181 Some(string)
182 })
183 .visit(|node: ast::EnumDef| {
184 let mut string = "enum ".to_string();
185 node.name()?.syntax().text().push_to(&mut string);
186 Some(string)
187 })
188 .visit(|node: ast::TraitDef| {
189 let mut string = "trait ".to_string();
190 node.name()?.syntax().text().push_to(&mut string);
191 Some(string)
192 })
193 .visit(|node: ast::Module| {
194 let mut string = "mod ".to_string();
195 node.name()?.syntax().text().push_to(&mut string);
196 Some(string)
197 })
198 .visit(|node: ast::TypeDef| {
199 let mut string = "type ".to_string();
200 node.name()?.syntax().text().push_to(&mut string);
201 Some(string)
202 })
203 .visit(|node: ast::ConstDef| {
204 let mut string = "const ".to_string();
205 node.name()?.syntax().text().push_to(&mut string);
206 Some(string)
207 })
208 .visit(|node: ast::StaticDef| {
209 let mut string = "static ".to_string();
210 node.name()?.syntax().text().push_to(&mut string);
211 Some(string)
212 })
213 .accept(node)?
214 })
215 .nth(0)
216 }
217}
218
219fn to_symbol(node: SyntaxNodeRef) -> Option<FileSymbol> {
220 fn decl<'a, N: NameOwner<'a>>(node: N) -> Option<FileSymbol> {
221 let name = node.name()?;
222 Some(FileSymbol {
223 name: name.text(),
224 node_range: node.syntax().range(),
225 kind: node.syntax().kind(),
226 })
227 }
228 visitor()
229 .visit(decl::<ast::FnDef>)
230 .visit(decl::<ast::StructDef>)
231 .visit(decl::<ast::EnumDef>)
232 .visit(decl::<ast::TraitDef>)
233 .visit(decl::<ast::Module>)
234 .visit(decl::<ast::TypeDef>)
235 .visit(decl::<ast::ConstDef>)
236 .visit(decl::<ast::StaticDef>)
237 .accept(node)?
238}
diff --git a/crates/ra_editor/src/lib.rs b/crates/ra_editor/src/lib.rs
index b03f9ea54..bfc745e58 100644
--- a/crates/ra_editor/src/lib.rs
+++ b/crates/ra_editor/src/lib.rs
@@ -3,7 +3,7 @@ mod extend_selection;
3mod folding_ranges; 3mod folding_ranges;
4mod line_index; 4mod line_index;
5mod line_index_utils; 5mod line_index_utils;
6mod symbols; 6mod structure;
7#[cfg(test)] 7#[cfg(test)]
8mod test_utils; 8mod test_utils;
9mod typing; 9mod typing;
@@ -15,7 +15,7 @@ pub use self::{
15 folding_ranges::{folding_ranges, Fold, FoldKind}, 15 folding_ranges::{folding_ranges, Fold, FoldKind},
16 line_index::{LineCol, LineIndex}, 16 line_index::{LineCol, LineIndex},
17 line_index_utils::translate_offset_with_edit, 17 line_index_utils::translate_offset_with_edit,
18 symbols::{file_structure, file_symbols, FileSymbol, StructureNode}, 18 structure::{file_structure, StructureNode},
19 typing::{join_lines, on_enter, on_eq_typed}, 19 typing::{join_lines, on_enter, on_eq_typed},
20 diagnostics::diagnostics 20 diagnostics::diagnostics
21}; 21};
diff --git a/crates/ra_editor/src/structure.rs b/crates/ra_editor/src/structure.rs
new file mode 100644
index 000000000..2292b1ddf
--- /dev/null
+++ b/crates/ra_editor/src/structure.rs
@@ -0,0 +1,129 @@
1use crate::TextRange;
2
3use ra_syntax::{
4 algo::visit::{visitor, Visitor},
5 ast::{self, NameOwner},
6 AstNode, SourceFileNode, SyntaxKind, SyntaxNodeRef, WalkEvent,
7};
8
9#[derive(Debug, Clone)]
10pub struct StructureNode {
11 pub parent: Option<usize>,
12 pub label: String,
13 pub navigation_range: TextRange,
14 pub node_range: TextRange,
15 pub kind: SyntaxKind,
16}
17
18pub fn file_structure(file: &SourceFileNode) -> Vec<StructureNode> {
19 let mut res = Vec::new();
20 let mut stack = Vec::new();
21
22 for event in file.syntax().preorder() {
23 match event {
24 WalkEvent::Enter(node) => {
25 if let Some(mut symbol) = structure_node(node) {
26 symbol.parent = stack.last().map(|&n| n);
27 stack.push(res.len());
28 res.push(symbol);
29 }
30 }
31 WalkEvent::Leave(node) => {
32 if structure_node(node).is_some() {
33 stack.pop().unwrap();
34 }
35 }
36 }
37 }
38 res
39}
40
41fn structure_node(node: SyntaxNodeRef) -> Option<StructureNode> {
42 fn decl<'a, N: NameOwner<'a>>(node: N) -> Option<StructureNode> {
43 let name = node.name()?;
44 Some(StructureNode {
45 parent: None,
46 label: name.text().to_string(),
47 navigation_range: name.syntax().range(),
48 node_range: node.syntax().range(),
49 kind: node.syntax().kind(),
50 })
51 }
52
53 visitor()
54 .visit(decl::<ast::FnDef>)
55 .visit(decl::<ast::StructDef>)
56 .visit(decl::<ast::NamedFieldDef>)
57 .visit(decl::<ast::EnumDef>)
58 .visit(decl::<ast::TraitDef>)
59 .visit(decl::<ast::Module>)
60 .visit(decl::<ast::TypeDef>)
61 .visit(decl::<ast::ConstDef>)
62 .visit(decl::<ast::StaticDef>)
63 .visit(|im: ast::ImplItem| {
64 let target_type = im.target_type()?;
65 let target_trait = im.target_trait();
66 let label = match target_trait {
67 None => format!("impl {}", target_type.syntax().text()),
68 Some(t) => format!(
69 "impl {} for {}",
70 t.syntax().text(),
71 target_type.syntax().text(),
72 ),
73 };
74
75 let node = StructureNode {
76 parent: None,
77 label,
78 navigation_range: target_type.syntax().range(),
79 node_range: im.syntax().range(),
80 kind: im.syntax().kind(),
81 };
82 Some(node)
83 })
84 .accept(node)?
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90 use test_utils::assert_eq_dbg;
91
92 #[test]
93 fn test_file_structure() {
94 let file = SourceFileNode::parse(
95 r#"
96struct Foo {
97 x: i32
98}
99
100mod m {
101 fn bar() {}
102}
103
104enum E { X, Y(i32) }
105type T = ();
106static S: i32 = 92;
107const C: i32 = 92;
108
109impl E {}
110
111impl fmt::Debug for E {}
112"#,
113 );
114 let structure = file_structure(&file);
115 assert_eq_dbg(
116 r#"[StructureNode { parent: None, label: "Foo", navigation_range: [8; 11), node_range: [1; 26), kind: STRUCT_DEF },
117 StructureNode { parent: Some(0), label: "x", navigation_range: [18; 19), node_range: [18; 24), kind: NAMED_FIELD_DEF },
118 StructureNode { parent: None, label: "m", navigation_range: [32; 33), node_range: [28; 53), kind: MODULE },
119 StructureNode { parent: Some(2), label: "bar", navigation_range: [43; 46), node_range: [40; 51), kind: FN_DEF },
120 StructureNode { parent: None, label: "E", navigation_range: [60; 61), node_range: [55; 75), kind: ENUM_DEF },
121 StructureNode { parent: None, label: "T", navigation_range: [81; 82), node_range: [76; 88), kind: TYPE_DEF },
122 StructureNode { parent: None, label: "S", navigation_range: [96; 97), node_range: [89; 108), kind: STATIC_DEF },
123 StructureNode { parent: None, label: "C", navigation_range: [115; 116), node_range: [109; 127), kind: CONST_DEF },
124 StructureNode { parent: None, label: "impl E", navigation_range: [134; 135), node_range: [129; 138), kind: IMPL_ITEM },
125 StructureNode { parent: None, label: "impl fmt::Debug for E", navigation_range: [160; 161), node_range: [140; 164), kind: IMPL_ITEM }]"#,
126 &structure,
127 )
128 }
129}
diff --git a/crates/ra_editor/src/symbols.rs b/crates/ra_editor/src/symbols.rs
deleted file mode 100644
index 9e25decfb..000000000
--- a/crates/ra_editor/src/symbols.rs
+++ /dev/null
@@ -1,246 +0,0 @@
1use crate::TextRange;
2
3use ra_syntax::{
4 algo::visit::{visitor, Visitor},
5 ast::{self, DocCommentsOwner, NameOwner},
6 AstNode, SourceFileNode, SmolStr, SyntaxKind, SyntaxNodeRef, WalkEvent,
7};
8
9#[derive(Debug, Clone)]
10pub struct StructureNode {
11 pub parent: Option<usize>,
12 pub label: String,
13 pub navigation_range: TextRange,
14 pub node_range: TextRange,
15 pub kind: SyntaxKind,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq, Hash)]
19pub struct FileSymbol {
20 pub name: SmolStr,
21 pub node_range: TextRange,
22 pub kind: SyntaxKind,
23}
24
25impl FileSymbol {
26 pub fn docs(&self, file: &SourceFileNode) -> Option<String> {
27 file.syntax()
28 .descendants()
29 .filter(|node| node.kind() == self.kind && node.range() == self.node_range)
30 .filter_map(|node: SyntaxNodeRef| {
31 fn doc_comments<'a, N: DocCommentsOwner<'a>>(node: N) -> Option<String> {
32 let comments = node.doc_comment_text();
33 if comments.is_empty() {
34 None
35 } else {
36 Some(comments)
37 }
38 }
39
40 visitor()
41 .visit(doc_comments::<ast::FnDef>)
42 .visit(doc_comments::<ast::StructDef>)
43 .visit(doc_comments::<ast::EnumDef>)
44 .visit(doc_comments::<ast::TraitDef>)
45 .visit(doc_comments::<ast::Module>)
46 .visit(doc_comments::<ast::TypeDef>)
47 .visit(doc_comments::<ast::ConstDef>)
48 .visit(doc_comments::<ast::StaticDef>)
49 .accept(node)?
50 })
51 .nth(0)
52 }
53 /// Get a description of this node.
54 ///
55 /// e.g. `struct Name`, `enum Name`, `fn Name`
56 pub fn description(&self, file: &SourceFileNode) -> Option<String> {
57 // TODO: After type inference is done, add type information to improve the output
58 file.syntax()
59 .descendants()
60 .filter(|node| node.kind() == self.kind && node.range() == self.node_range)
61 .filter_map(|node: SyntaxNodeRef| {
62 // TODO: Refactor to be have less repetition
63 visitor()
64 .visit(|node: ast::FnDef| {
65 let mut string = "fn ".to_string();
66 node.name()?.syntax().text().push_to(&mut string);
67 Some(string)
68 })
69 .visit(|node: ast::StructDef| {
70 let mut string = "struct ".to_string();
71 node.name()?.syntax().text().push_to(&mut string);
72 Some(string)
73 })
74 .visit(|node: ast::EnumDef| {
75 let mut string = "enum ".to_string();
76 node.name()?.syntax().text().push_to(&mut string);
77 Some(string)
78 })
79 .visit(|node: ast::TraitDef| {
80 let mut string = "trait ".to_string();
81 node.name()?.syntax().text().push_to(&mut string);
82 Some(string)
83 })
84 .visit(|node: ast::Module| {
85 let mut string = "mod ".to_string();
86 node.name()?.syntax().text().push_to(&mut string);
87 Some(string)
88 })
89 .visit(|node: ast::TypeDef| {
90 let mut string = "type ".to_string();
91 node.name()?.syntax().text().push_to(&mut string);
92 Some(string)
93 })
94 .visit(|node: ast::ConstDef| {
95 let mut string = "const ".to_string();
96 node.name()?.syntax().text().push_to(&mut string);
97 Some(string)
98 })
99 .visit(|node: ast::StaticDef| {
100 let mut string = "static ".to_string();
101 node.name()?.syntax().text().push_to(&mut string);
102 Some(string)
103 })
104 .accept(node)?
105 })
106 .nth(0)
107 }
108}
109
110pub fn file_symbols(file: &SourceFileNode) -> Vec<FileSymbol> {
111 file.syntax().descendants().filter_map(to_symbol).collect()
112}
113
114fn to_symbol(node: SyntaxNodeRef) -> Option<FileSymbol> {
115 fn decl<'a, N: NameOwner<'a>>(node: N) -> Option<FileSymbol> {
116 let name = node.name()?;
117 Some(FileSymbol {
118 name: name.text(),
119 node_range: node.syntax().range(),
120 kind: node.syntax().kind(),
121 })
122 }
123 visitor()
124 .visit(decl::<ast::FnDef>)
125 .visit(decl::<ast::StructDef>)
126 .visit(decl::<ast::EnumDef>)
127 .visit(decl::<ast::TraitDef>)
128 .visit(decl::<ast::Module>)
129 .visit(decl::<ast::TypeDef>)
130 .visit(decl::<ast::ConstDef>)
131 .visit(decl::<ast::StaticDef>)
132 .accept(node)?
133}
134
135pub fn file_structure(file: &SourceFileNode) -> Vec<StructureNode> {
136 let mut res = Vec::new();
137 let mut stack = Vec::new();
138
139 for event in file.syntax().preorder() {
140 match event {
141 WalkEvent::Enter(node) => {
142 if let Some(mut symbol) = structure_node(node) {
143 symbol.parent = stack.last().map(|&n| n);
144 stack.push(res.len());
145 res.push(symbol);
146 }
147 }
148 WalkEvent::Leave(node) => {
149 if structure_node(node).is_some() {
150 stack.pop().unwrap();
151 }
152 }
153 }
154 }
155 res
156}
157
158fn structure_node(node: SyntaxNodeRef) -> Option<StructureNode> {
159 fn decl<'a, N: NameOwner<'a>>(node: N) -> Option<StructureNode> {
160 let name = node.name()?;
161 Some(StructureNode {
162 parent: None,
163 label: name.text().to_string(),
164 navigation_range: name.syntax().range(),
165 node_range: node.syntax().range(),
166 kind: node.syntax().kind(),
167 })
168 }
169
170 visitor()
171 .visit(decl::<ast::FnDef>)
172 .visit(decl::<ast::StructDef>)
173 .visit(decl::<ast::NamedFieldDef>)
174 .visit(decl::<ast::EnumDef>)
175 .visit(decl::<ast::TraitDef>)
176 .visit(decl::<ast::Module>)
177 .visit(decl::<ast::TypeDef>)
178 .visit(decl::<ast::ConstDef>)
179 .visit(decl::<ast::StaticDef>)
180 .visit(|im: ast::ImplItem| {
181 let target_type = im.target_type()?;
182 let target_trait = im.target_trait();
183 let label = match target_trait {
184 None => format!("impl {}", target_type.syntax().text()),
185 Some(t) => format!(
186 "impl {} for {}",
187 t.syntax().text(),
188 target_type.syntax().text(),
189 ),
190 };
191
192 let node = StructureNode {
193 parent: None,
194 label,
195 navigation_range: target_type.syntax().range(),
196 node_range: im.syntax().range(),
197 kind: im.syntax().kind(),
198 };
199 Some(node)
200 })
201 .accept(node)?
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207 use test_utils::assert_eq_dbg;
208
209 #[test]
210 fn test_file_structure() {
211 let file = SourceFileNode::parse(
212 r#"
213struct Foo {
214 x: i32
215}
216
217mod m {
218 fn bar() {}
219}
220
221enum E { X, Y(i32) }
222type T = ();
223static S: i32 = 92;
224const C: i32 = 92;
225
226impl E {}
227
228impl fmt::Debug for E {}
229"#,
230 );
231 let symbols = file_structure(&file);
232 assert_eq_dbg(
233 r#"[StructureNode { parent: None, label: "Foo", navigation_range: [8; 11), node_range: [1; 26), kind: STRUCT_DEF },
234 StructureNode { parent: Some(0), label: "x", navigation_range: [18; 19), node_range: [18; 24), kind: NAMED_FIELD_DEF },
235 StructureNode { parent: None, label: "m", navigation_range: [32; 33), node_range: [28; 53), kind: MODULE },
236 StructureNode { parent: Some(2), label: "bar", navigation_range: [43; 46), node_range: [40; 51), kind: FN_DEF },
237 StructureNode { parent: None, label: "E", navigation_range: [60; 61), node_range: [55; 75), kind: ENUM_DEF },
238 StructureNode { parent: None, label: "T", navigation_range: [81; 82), node_range: [76; 88), kind: TYPE_DEF },
239 StructureNode { parent: None, label: "S", navigation_range: [96; 97), node_range: [89; 108), kind: STATIC_DEF },
240 StructureNode { parent: None, label: "C", navigation_range: [115; 116), node_range: [109; 127), kind: CONST_DEF },
241 StructureNode { parent: None, label: "impl E", navigation_range: [134; 135), node_range: [129; 138), kind: IMPL_ITEM },
242 StructureNode { parent: None, label: "impl fmt::Debug for E", navigation_range: [160; 161), node_range: [140; 164), kind: IMPL_ITEM }]"#,
243 &symbols,
244 )
245 }
246}