diff options
Diffstat (limited to 'crates/ra_ide/src/syntax_tree.rs')
-rw-r--r-- | crates/ra_ide/src/syntax_tree.rs | 359 |
1 files changed, 0 insertions, 359 deletions
diff --git a/crates/ra_ide/src/syntax_tree.rs b/crates/ra_ide/src/syntax_tree.rs deleted file mode 100644 index f80044959..000000000 --- a/crates/ra_ide/src/syntax_tree.rs +++ /dev/null | |||
@@ -1,359 +0,0 @@ | |||
1 | use base_db::{FileId, SourceDatabase}; | ||
2 | use ide_db::RootDatabase; | ||
3 | use syntax::{ | ||
4 | algo, AstNode, NodeOrToken, SourceFile, | ||
5 | SyntaxKind::{RAW_STRING, STRING}, | ||
6 | SyntaxToken, TextRange, TextSize, | ||
7 | }; | ||
8 | |||
9 | // Feature: Show Syntax Tree | ||
10 | // | ||
11 | // Shows the parse tree of the current file. It exists mostly for debugging | ||
12 | // rust-analyzer itself. | ||
13 | // | ||
14 | // |=== | ||
15 | // | Editor | Action Name | ||
16 | // | ||
17 | // | VS Code | **Rust Analyzer: Show Syntax Tree** | ||
18 | // |=== | ||
19 | pub(crate) fn syntax_tree( | ||
20 | db: &RootDatabase, | ||
21 | file_id: FileId, | ||
22 | text_range: Option<TextRange>, | ||
23 | ) -> String { | ||
24 | let parse = db.parse(file_id); | ||
25 | if let Some(text_range) = text_range { | ||
26 | let node = match algo::find_covering_element(parse.tree().syntax(), text_range) { | ||
27 | NodeOrToken::Node(node) => node, | ||
28 | NodeOrToken::Token(token) => { | ||
29 | if let Some(tree) = syntax_tree_for_string(&token, text_range) { | ||
30 | return tree; | ||
31 | } | ||
32 | token.parent() | ||
33 | } | ||
34 | }; | ||
35 | |||
36 | format!("{:#?}", node) | ||
37 | } else { | ||
38 | format!("{:#?}", parse.tree().syntax()) | ||
39 | } | ||
40 | } | ||
41 | |||
42 | /// Attempts parsing the selected contents of a string literal | ||
43 | /// as rust syntax and returns its syntax tree | ||
44 | fn syntax_tree_for_string(token: &SyntaxToken, text_range: TextRange) -> Option<String> { | ||
45 | // When the range is inside a string | ||
46 | // we'll attempt parsing it as rust syntax | ||
47 | // to provide the syntax tree of the contents of the string | ||
48 | match token.kind() { | ||
49 | STRING | RAW_STRING => syntax_tree_for_token(token, text_range), | ||
50 | _ => None, | ||
51 | } | ||
52 | } | ||
53 | |||
54 | fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option<String> { | ||
55 | // Range of the full node | ||
56 | let node_range = node.text_range(); | ||
57 | let text = node.text().to_string(); | ||
58 | |||
59 | // We start at some point inside the node | ||
60 | // Either we have selected the whole string | ||
61 | // or our selection is inside it | ||
62 | let start = text_range.start() - node_range.start(); | ||
63 | |||
64 | // how many characters we have selected | ||
65 | let len = text_range.len(); | ||
66 | |||
67 | let node_len = node_range.len(); | ||
68 | |||
69 | let start = start; | ||
70 | |||
71 | // We want to cap our length | ||
72 | let len = len.min(node_len); | ||
73 | |||
74 | // Ensure our slice is inside the actual string | ||
75 | let end = | ||
76 | if start + len < TextSize::of(&text) { start + len } else { TextSize::of(&text) - start }; | ||
77 | |||
78 | let text = &text[TextRange::new(start, end)]; | ||
79 | |||
80 | // Remove possible extra string quotes from the start | ||
81 | // and the end of the string | ||
82 | let text = text | ||
83 | .trim_start_matches('r') | ||
84 | .trim_start_matches('#') | ||
85 | .trim_start_matches('"') | ||
86 | .trim_end_matches('#') | ||
87 | .trim_end_matches('"') | ||
88 | .trim() | ||
89 | // Remove custom markers | ||
90 | .replace("<|>", ""); | ||
91 | |||
92 | let parsed = SourceFile::parse(&text); | ||
93 | |||
94 | // If the "file" parsed without errors, | ||
95 | // return its syntax | ||
96 | if parsed.errors().is_empty() { | ||
97 | return Some(format!("{:#?}", parsed.tree().syntax())); | ||
98 | } | ||
99 | |||
100 | None | ||
101 | } | ||
102 | |||
103 | #[cfg(test)] | ||
104 | mod tests { | ||
105 | use test_utils::assert_eq_text; | ||
106 | |||
107 | use crate::mock_analysis::{analysis_and_range, single_file}; | ||
108 | |||
109 | #[test] | ||
110 | fn test_syntax_tree_without_range() { | ||
111 | // Basic syntax | ||
112 | let (analysis, file_id) = single_file(r#"fn foo() {}"#); | ||
113 | let syn = analysis.syntax_tree(file_id, None).unwrap(); | ||
114 | |||
115 | assert_eq_text!( | ||
116 | syn.trim(), | ||
117 | r#" | ||
118 | [email protected] | ||
119 | [email protected] | ||
120 | [email protected] "fn" | ||
121 | [email protected] " " | ||
122 | [email protected] | ||
123 | [email protected] "foo" | ||
124 | [email protected] | ||
125 | [email protected] "(" | ||
126 | [email protected] ")" | ||
127 | [email protected] " " | ||
128 | [email protected] | ||
129 | [email protected] "{" | ||
130 | [email protected] "}" | ||
131 | "# | ||
132 | .trim() | ||
133 | ); | ||
134 | |||
135 | let (analysis, file_id) = single_file( | ||
136 | r#" | ||
137 | fn test() { | ||
138 | assert!(" | ||
139 | fn foo() { | ||
140 | } | ||
141 | ", ""); | ||
142 | }"# | ||
143 | .trim(), | ||
144 | ); | ||
145 | let syn = analysis.syntax_tree(file_id, None).unwrap(); | ||
146 | |||
147 | assert_eq_text!( | ||
148 | syn.trim(), | ||
149 | r#" | ||
150 | [email protected] | ||
151 | [email protected] | ||
152 | [email protected] "fn" | ||
153 | [email protected] " " | ||
154 | [email protected] | ||
155 | [email protected] "test" | ||
156 | [email protected] | ||
157 | [email protected] "(" | ||
158 | [email protected] ")" | ||
159 | [email protected] " " | ||
160 | [email protected] | ||
161 | [email protected] "{" | ||
162 | [email protected] "\n " | ||
163 | [email protected] | ||
164 | [email protected] | ||
165 | [email protected] | ||
166 | [email protected] | ||
167 | [email protected] | ||
168 | [email protected] "assert" | ||
169 | [email protected] "!" | ||
170 | [email protected] | ||
171 | [email protected] "(" | ||
172 | [email protected] "\"\n fn foo() {\n ..." | ||
173 | [email protected] "," | ||
174 | [email protected] " " | ||
175 | [email protected] "\"\"" | ||
176 | [email protected] ")" | ||
177 | [email protected] ";" | ||
178 | [email protected] "\n" | ||
179 | [email protected] "}" | ||
180 | "# | ||
181 | .trim() | ||
182 | ); | ||
183 | } | ||
184 | |||
185 | #[test] | ||
186 | fn test_syntax_tree_with_range() { | ||
187 | let (analysis, range) = analysis_and_range(r#"<|>fn foo() {}<|>"#.trim()); | ||
188 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); | ||
189 | |||
190 | assert_eq_text!( | ||
191 | syn.trim(), | ||
192 | r#" | ||
193 | [email protected] | ||
194 | [email protected] "fn" | ||
195 | [email protected] " " | ||
196 | [email protected] | ||
197 | [email protected] "foo" | ||
198 | [email protected] | ||
199 | [email protected] "(" | ||
200 | [email protected] ")" | ||
201 | [email protected] " " | ||
202 | [email protected] | ||
203 | [email protected] "{" | ||
204 | [email protected] "}" | ||
205 | "# | ||
206 | .trim() | ||
207 | ); | ||
208 | |||
209 | let (analysis, range) = analysis_and_range( | ||
210 | r#"fn test() { | ||
211 | <|>assert!(" | ||
212 | fn foo() { | ||
213 | } | ||
214 | ", "");<|> | ||
215 | }"# | ||
216 | .trim(), | ||
217 | ); | ||
218 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); | ||
219 | |||
220 | assert_eq_text!( | ||
221 | syn.trim(), | ||
222 | r#" | ||
223 | [email protected] | ||
224 | [email protected] | ||
225 | [email protected] | ||
226 | [email protected] | ||
227 | [email protected] | ||
228 | [email protected] "assert" | ||
229 | [email protected] "!" | ||
230 | [email protected] | ||
231 | [email protected] "(" | ||
232 | [email protected] "\"\n fn foo() {\n ..." | ||
233 | [email protected] "," | ||
234 | [email protected] " " | ||
235 | [email protected] "\"\"" | ||
236 | [email protected] ")" | ||
237 | [email protected] ";" | ||
238 | "# | ||
239 | .trim() | ||
240 | ); | ||
241 | } | ||
242 | |||
243 | #[test] | ||
244 | fn test_syntax_tree_inside_string() { | ||
245 | let (analysis, range) = analysis_and_range( | ||
246 | r#"fn test() { | ||
247 | assert!(" | ||
248 | <|>fn foo() { | ||
249 | }<|> | ||
250 | fn bar() { | ||
251 | } | ||
252 | ", ""); | ||
253 | }"# | ||
254 | .trim(), | ||
255 | ); | ||
256 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); | ||
257 | assert_eq_text!( | ||
258 | syn.trim(), | ||
259 | r#" | ||
260 | [email protected] | ||
261 | [email protected] | ||
262 | [email protected] "fn" | ||
263 | [email protected] " " | ||
264 | [email protected] | ||
265 | [email protected] "foo" | ||
266 | [email protected] | ||
267 | [email protected] "(" | ||
268 | [email protected] ")" | ||
269 | [email protected] " " | ||
270 | [email protected] | ||
271 | [email protected] "{" | ||
272 | [email protected] "\n" | ||
273 | [email protected] "}" | ||
274 | "# | ||
275 | .trim() | ||
276 | ); | ||
277 | |||
278 | // With a raw string | ||
279 | let (analysis, range) = analysis_and_range( | ||
280 | r###"fn test() { | ||
281 | assert!(r#" | ||
282 | <|>fn foo() { | ||
283 | }<|> | ||
284 | fn bar() { | ||
285 | } | ||
286 | "#, ""); | ||
287 | }"### | ||
288 | .trim(), | ||
289 | ); | ||
290 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); | ||
291 | assert_eq_text!( | ||
292 | syn.trim(), | ||
293 | r#" | ||
294 | [email protected] | ||
295 | [email protected] | ||
296 | [email protected] "fn" | ||
297 | [email protected] " " | ||
298 | [email protected] | ||
299 | [email protected] "foo" | ||
300 | [email protected] | ||
301 | [email protected] "(" | ||
302 | [email protected] ")" | ||
303 | [email protected] " " | ||
304 | [email protected] | ||
305 | [email protected] "{" | ||
306 | [email protected] "\n" | ||
307 | [email protected] "}" | ||
308 | "# | ||
309 | .trim() | ||
310 | ); | ||
311 | |||
312 | // With a raw string | ||
313 | let (analysis, range) = analysis_and_range( | ||
314 | r###"fn test() { | ||
315 | assert!(r<|>#" | ||
316 | fn foo() { | ||
317 | } | ||
318 | fn bar() { | ||
319 | }"<|>#, ""); | ||
320 | }"### | ||
321 | .trim(), | ||
322 | ); | ||
323 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); | ||
324 | assert_eq_text!( | ||
325 | syn.trim(), | ||
326 | r#" | ||
327 | [email protected] | ||
328 | [email protected] | ||
329 | [email protected] "fn" | ||
330 | [email protected] " " | ||
331 | [email protected] | ||
332 | [email protected] "foo" | ||
333 | [email protected] | ||
334 | [email protected] "(" | ||
335 | [email protected] ")" | ||
336 | [email protected] " " | ||
337 | [email protected] | ||
338 | [email protected] "{" | ||
339 | [email protected] "\n" | ||
340 | [email protected] "}" | ||
341 | [email protected] "\n" | ||
342 | [email protected] | ||
343 | [email protected] "fn" | ||
344 | [email protected] " " | ||
345 | [email protected] | ||
346 | [email protected] "bar" | ||
347 | [email protected] | ||
348 | [email protected] "(" | ||
349 | [email protected] ")" | ||
350 | [email protected] " " | ||
351 | [email protected] | ||
352 | [email protected] "{" | ||
353 | [email protected] "\n" | ||
354 | [email protected] "}" | ||
355 | "# | ||
356 | .trim() | ||
357 | ); | ||
358 | } | ||
359 | } | ||