diff options
Diffstat (limited to 'crates/ra_ide_api/src/syntax_tree.rs')
-rw-r--r-- | crates/ra_ide_api/src/syntax_tree.rs | 202 |
1 files changed, 104 insertions, 98 deletions
diff --git a/crates/ra_ide_api/src/syntax_tree.rs b/crates/ra_ide_api/src/syntax_tree.rs index 276f8a8c8..c7288220c 100644 --- a/crates/ra_ide_api/src/syntax_tree.rs +++ b/crates/ra_ide_api/src/syntax_tree.rs | |||
@@ -1,8 +1,9 @@ | |||
1 | use ra_db::SourceDatabase; | 1 | use ra_db::SourceDatabase; |
2 | use crate::db::RootDatabase; | 2 | use crate::db::RootDatabase; |
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | SourceFile, SyntaxNode, TextRange, AstNode, | 4 | SourceFile, TextRange, AstNode, SyntaxToken, SyntaxElement, |
5 | algo::{self, visit::{visitor, Visitor}}, ast::{self, AstToken} | 5 | algo, |
6 | SyntaxKind::{STRING, RAW_STRING}, | ||
6 | }; | 7 | }; |
7 | 8 | ||
8 | pub use ra_db::FileId; | 9 | pub use ra_db::FileId; |
@@ -14,11 +15,15 @@ pub(crate) fn syntax_tree( | |||
14 | ) -> String { | 15 | ) -> String { |
15 | if let Some(text_range) = text_range { | 16 | if let Some(text_range) = text_range { |
16 | let file = db.parse(file_id); | 17 | let file = db.parse(file_id); |
17 | let node = algo::find_covering_node(file.syntax(), text_range); | 18 | let node = match algo::find_covering_element(file.syntax(), text_range) { |
18 | 19 | SyntaxElement::Node(node) => node, | |
19 | if let Some(tree) = syntax_tree_for_string(node, text_range) { | 20 | SyntaxElement::Token(token) => { |
20 | return tree; | 21 | if let Some(tree) = syntax_tree_for_string(token, text_range) { |
21 | } | 22 | return tree; |
23 | } | ||
24 | token.parent() | ||
25 | } | ||
26 | }; | ||
22 | 27 | ||
23 | node.debug_dump() | 28 | node.debug_dump() |
24 | } else { | 29 | } else { |
@@ -28,19 +33,19 @@ pub(crate) fn syntax_tree( | |||
28 | 33 | ||
29 | /// Attempts parsing the selected contents of a string literal | 34 | /// Attempts parsing the selected contents of a string literal |
30 | /// as rust syntax and returns its syntax tree | 35 | /// as rust syntax and returns its syntax tree |
31 | fn syntax_tree_for_string(node: &SyntaxNode, text_range: TextRange) -> Option<String> { | 36 | fn syntax_tree_for_string(token: SyntaxToken, text_range: TextRange) -> Option<String> { |
32 | // When the range is inside a string | 37 | // When the range is inside a string |
33 | // we'll attempt parsing it as rust syntax | 38 | // we'll attempt parsing it as rust syntax |
34 | // to provide the syntax tree of the contents of the string | 39 | // to provide the syntax tree of the contents of the string |
35 | visitor() | 40 | match token.kind() { |
36 | .visit(|node: &ast::String| syntax_tree_for_token(node, text_range)) | 41 | STRING | RAW_STRING => syntax_tree_for_token(token, text_range), |
37 | .visit(|node: &ast::RawString| syntax_tree_for_token(node, text_range)) | 42 | _ => None, |
38 | .accept(node)? | 43 | } |
39 | } | 44 | } |
40 | 45 | ||
41 | fn syntax_tree_for_token<T: AstToken>(node: &T, text_range: TextRange) -> Option<String> { | 46 | fn syntax_tree_for_token(node: SyntaxToken, text_range: TextRange) -> Option<String> { |
42 | // Range of the full node | 47 | // Range of the full node |
43 | let node_range = node.syntax().range(); | 48 | let node_range = node.range(); |
44 | let text = node.text().to_string(); | 49 | let text = node.text().to_string(); |
45 | 50 | ||
46 | // We start at some point inside the node | 51 | // We start at some point inside the node |
@@ -88,6 +93,8 @@ fn syntax_tree_for_token<T: AstToken>(node: &T, text_range: TextRange) -> Option | |||
88 | 93 | ||
89 | #[cfg(test)] | 94 | #[cfg(test)] |
90 | mod tests { | 95 | mod tests { |
96 | use test_utils::assert_eq_text; | ||
97 | |||
91 | use crate::mock_analysis::{single_file, single_file_with_range}; | 98 | use crate::mock_analysis::{single_file, single_file_with_range}; |
92 | 99 | ||
93 | #[test] | 100 | #[test] |
@@ -96,23 +103,23 @@ mod tests { | |||
96 | let (analysis, file_id) = single_file(r#"fn foo() {}"#); | 103 | let (analysis, file_id) = single_file(r#"fn foo() {}"#); |
97 | let syn = analysis.syntax_tree(file_id, None); | 104 | let syn = analysis.syntax_tree(file_id, None); |
98 | 105 | ||
99 | assert_eq!( | 106 | assert_eq_text!( |
100 | syn.trim(), | 107 | syn.trim(), |
101 | r#" | 108 | r#" |
102 | SOURCE_FILE@[0; 11) | 109 | SOURCE_FILE@[0; 11) |
103 | FN_DEF@[0; 11) | 110 | FN_DEF@[0; 11) |
104 | FN_KW@[0; 2) | 111 | FN_KW@[0; 2) "fn" |
105 | WHITESPACE@[2; 3) | 112 | WHITESPACE@[2; 3) " " |
106 | NAME@[3; 6) | 113 | NAME@[3; 6) |
107 | IDENT@[3; 6) "foo" | 114 | IDENT@[3; 6) "foo" |
108 | PARAM_LIST@[6; 8) | 115 | PARAM_LIST@[6; 8) |
109 | L_PAREN@[6; 7) | 116 | L_PAREN@[6; 7) "(" |
110 | R_PAREN@[7; 8) | 117 | R_PAREN@[7; 8) ")" |
111 | WHITESPACE@[8; 9) | 118 | WHITESPACE@[8; 9) " " |
112 | BLOCK@[9; 11) | 119 | BLOCK@[9; 11) |
113 | L_CURLY@[9; 10) | 120 | L_CURLY@[9; 10) "{" |
114 | R_CURLY@[10; 11) | 121 | R_CURLY@[10; 11) "}" |
115 | "# | 122 | "# |
116 | .trim() | 123 | .trim() |
117 | ); | 124 | ); |
118 | 125 | ||
@@ -128,40 +135,40 @@ fn test() { | |||
128 | ); | 135 | ); |
129 | let syn = analysis.syntax_tree(file_id, None); | 136 | let syn = analysis.syntax_tree(file_id, None); |
130 | 137 | ||
131 | assert_eq!( | 138 | assert_eq_text!( |
132 | syn.trim(), | 139 | syn.trim(), |
133 | r#" | 140 | r#" |
134 | SOURCE_FILE@[0; 60) | 141 | SOURCE_FILE@[0; 60) |
135 | FN_DEF@[0; 60) | 142 | FN_DEF@[0; 60) |
136 | FN_KW@[0; 2) | 143 | FN_KW@[0; 2) "fn" |
137 | WHITESPACE@[2; 3) | 144 | WHITESPACE@[2; 3) " " |
138 | NAME@[3; 7) | 145 | NAME@[3; 7) |
139 | IDENT@[3; 7) "test" | 146 | IDENT@[3; 7) "test" |
140 | PARAM_LIST@[7; 9) | 147 | PARAM_LIST@[7; 9) |
141 | L_PAREN@[7; 8) | 148 | L_PAREN@[7; 8) "(" |
142 | R_PAREN@[8; 9) | 149 | R_PAREN@[8; 9) ")" |
143 | WHITESPACE@[9; 10) | 150 | WHITESPACE@[9; 10) " " |
144 | BLOCK@[10; 60) | 151 | BLOCK@[10; 60) |
145 | L_CURLY@[10; 11) | 152 | L_CURLY@[10; 11) "{" |
146 | WHITESPACE@[11; 16) | 153 | WHITESPACE@[11; 16) "\n " |
147 | EXPR_STMT@[16; 58) | 154 | EXPR_STMT@[16; 58) |
148 | MACRO_CALL@[16; 57) | 155 | MACRO_CALL@[16; 57) |
149 | PATH@[16; 22) | 156 | PATH@[16; 22) |
150 | PATH_SEGMENT@[16; 22) | 157 | PATH_SEGMENT@[16; 22) |
151 | NAME_REF@[16; 22) | 158 | NAME_REF@[16; 22) |
152 | IDENT@[16; 22) "assert" | 159 | IDENT@[16; 22) "assert" |
153 | EXCL@[22; 23) | 160 | EXCL@[22; 23) "!" |
154 | TOKEN_TREE@[23; 57) | 161 | TOKEN_TREE@[23; 57) |
155 | L_PAREN@[23; 24) | 162 | L_PAREN@[23; 24) "(" |
156 | STRING@[24; 52) | 163 | STRING@[24; 52) "\"\n fn foo() {\n ..." |
157 | COMMA@[52; 53) | 164 | COMMA@[52; 53) "," |
158 | WHITESPACE@[53; 54) | 165 | WHITESPACE@[53; 54) " " |
159 | STRING@[54; 56) | 166 | STRING@[54; 56) "\"\"" |
160 | R_PAREN@[56; 57) | 167 | R_PAREN@[56; 57) ")" |
161 | SEMI@[57; 58) | 168 | SEMI@[57; 58) ";" |
162 | WHITESPACE@[58; 59) | 169 | WHITESPACE@[58; 59) "\n" |
163 | R_CURLY@[59; 60) | 170 | R_CURLY@[59; 60) "}" |
164 | "# | 171 | "# |
165 | .trim() | 172 | .trim() |
166 | ); | 173 | ); |
167 | } | 174 | } |
@@ -171,22 +178,22 @@ SOURCE_FILE@[0; 60) | |||
171 | let (analysis, range) = single_file_with_range(r#"<|>fn foo() {}<|>"#.trim()); | 178 | let (analysis, range) = single_file_with_range(r#"<|>fn foo() {}<|>"#.trim()); |
172 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)); | 179 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)); |
173 | 180 | ||
174 | assert_eq!( | 181 | assert_eq_text!( |
175 | syn.trim(), | 182 | syn.trim(), |
176 | r#" | 183 | r#" |
177 | FN_DEF@[0; 11) | 184 | FN_DEF@[0; 11) |
178 | FN_KW@[0; 2) | 185 | FN_KW@[0; 2) "fn" |
179 | WHITESPACE@[2; 3) | 186 | WHITESPACE@[2; 3) " " |
180 | NAME@[3; 6) | 187 | NAME@[3; 6) |
181 | IDENT@[3; 6) "foo" | 188 | IDENT@[3; 6) "foo" |
182 | PARAM_LIST@[6; 8) | 189 | PARAM_LIST@[6; 8) |
183 | L_PAREN@[6; 7) | 190 | L_PAREN@[6; 7) "(" |
184 | R_PAREN@[7; 8) | 191 | R_PAREN@[7; 8) ")" |
185 | WHITESPACE@[8; 9) | 192 | WHITESPACE@[8; 9) " " |
186 | BLOCK@[9; 11) | 193 | BLOCK@[9; 11) |
187 | L_CURLY@[9; 10) | 194 | L_CURLY@[9; 10) "{" |
188 | R_CURLY@[10; 11) | 195 | R_CURLY@[10; 11) "}" |
189 | "# | 196 | "# |
190 | .trim() | 197 | .trim() |
191 | ); | 198 | ); |
192 | 199 | ||
@@ -201,7 +208,7 @@ FN_DEF@[0; 11) | |||
201 | ); | 208 | ); |
202 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)); | 209 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)); |
203 | 210 | ||
204 | assert_eq!( | 211 | assert_eq_text!( |
205 | syn.trim(), | 212 | syn.trim(), |
206 | r#" | 213 | r#" |
207 | EXPR_STMT@[16; 58) | 214 | EXPR_STMT@[16; 58) |
@@ -210,16 +217,16 @@ EXPR_STMT@[16; 58) | |||
210 | PATH_SEGMENT@[16; 22) | 217 | PATH_SEGMENT@[16; 22) |
211 | NAME_REF@[16; 22) | 218 | NAME_REF@[16; 22) |
212 | IDENT@[16; 22) "assert" | 219 | IDENT@[16; 22) "assert" |
213 | EXCL@[22; 23) | 220 | EXCL@[22; 23) "!" |
214 | TOKEN_TREE@[23; 57) | 221 | TOKEN_TREE@[23; 57) |
215 | L_PAREN@[23; 24) | 222 | L_PAREN@[23; 24) "(" |
216 | STRING@[24; 52) | 223 | STRING@[24; 52) "\"\n fn foo() {\n ..." |
217 | COMMA@[52; 53) | 224 | COMMA@[52; 53) "," |
218 | WHITESPACE@[53; 54) | 225 | WHITESPACE@[53; 54) " " |
219 | STRING@[54; 56) | 226 | STRING@[54; 56) "\"\"" |
220 | R_PAREN@[56; 57) | 227 | R_PAREN@[56; 57) ")" |
221 | SEMI@[57; 58) | 228 | SEMI@[57; 58) ";" |
222 | "# | 229 | "# |
223 | .trim() | 230 | .trim() |
224 | ); | 231 | ); |
225 | } | 232 | } |
@@ -238,23 +245,23 @@ fn bar() { | |||
238 | .trim(), | 245 | .trim(), |
239 | ); | 246 | ); |
240 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)); | 247 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)); |
241 | assert_eq!( | 248 | assert_eq_text!( |
242 | syn.trim(), | 249 | syn.trim(), |
243 | r#" | 250 | r#" |
244 | SOURCE_FILE@[0; 12) | 251 | SOURCE_FILE@[0; 12) |
245 | FN_DEF@[0; 12) | 252 | FN_DEF@[0; 12) |
246 | FN_KW@[0; 2) | 253 | FN_KW@[0; 2) "fn" |
247 | WHITESPACE@[2; 3) | 254 | WHITESPACE@[2; 3) " " |
248 | NAME@[3; 6) | 255 | NAME@[3; 6) |
249 | IDENT@[3; 6) "foo" | 256 | IDENT@[3; 6) "foo" |
250 | PARAM_LIST@[6; 8) | 257 | PARAM_LIST@[6; 8) |
251 | L_PAREN@[6; 7) | 258 | L_PAREN@[6; 7) "(" |
252 | R_PAREN@[7; 8) | 259 | R_PAREN@[7; 8) ")" |
253 | WHITESPACE@[8; 9) | 260 | WHITESPACE@[8; 9) " " |
254 | BLOCK@[9; 12) | 261 | BLOCK@[9; 12) |
255 | L_CURLY@[9; 10) | 262 | L_CURLY@[9; 10) "{" |
256 | WHITESPACE@[10; 11) | 263 | WHITESPACE@[10; 11) "\n" |
257 | R_CURLY@[11; 12) | 264 | R_CURLY@[11; 12) "}" |
258 | "# | 265 | "# |
259 | .trim() | 266 | .trim() |
260 | ); | 267 | ); |
@@ -272,23 +279,23 @@ fn bar() { | |||
272 | .trim(), | 279 | .trim(), |
273 | ); | 280 | ); |
274 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)); | 281 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)); |
275 | assert_eq!( | 282 | assert_eq_text!( |
276 | syn.trim(), | 283 | syn.trim(), |
277 | r#" | 284 | r#" |
278 | SOURCE_FILE@[0; 12) | 285 | SOURCE_FILE@[0; 12) |
279 | FN_DEF@[0; 12) | 286 | FN_DEF@[0; 12) |
280 | FN_KW@[0; 2) | 287 | FN_KW@[0; 2) "fn" |
281 | WHITESPACE@[2; 3) | 288 | WHITESPACE@[2; 3) " " |
282 | NAME@[3; 6) | 289 | NAME@[3; 6) |
283 | IDENT@[3; 6) "foo" | 290 | IDENT@[3; 6) "foo" |
284 | PARAM_LIST@[6; 8) | 291 | PARAM_LIST@[6; 8) |
285 | L_PAREN@[6; 7) | 292 | L_PAREN@[6; 7) "(" |
286 | R_PAREN@[7; 8) | 293 | R_PAREN@[7; 8) ")" |
287 | WHITESPACE@[8; 9) | 294 | WHITESPACE@[8; 9) " " |
288 | BLOCK@[9; 12) | 295 | BLOCK@[9; 12) |
289 | L_CURLY@[9; 10) | 296 | L_CURLY@[9; 10) "{" |
290 | WHITESPACE@[10; 11) | 297 | WHITESPACE@[10; 11) "\n" |
291 | R_CURLY@[11; 12) | 298 | R_CURLY@[11; 12) "}" |
292 | "# | 299 | "# |
293 | .trim() | 300 | .trim() |
294 | ); | 301 | ); |
@@ -305,38 +312,37 @@ fn bar() { | |||
305 | .trim(), | 312 | .trim(), |
306 | ); | 313 | ); |
307 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)); | 314 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)); |
308 | assert_eq!( | 315 | assert_eq_text!( |
309 | syn.trim(), | 316 | syn.trim(), |
310 | r#" | 317 | r#" |
311 | SOURCE_FILE@[0; 25) | 318 | SOURCE_FILE@[0; 25) |
312 | FN_DEF@[0; 12) | 319 | FN_DEF@[0; 12) |
313 | FN_KW@[0; 2) | 320 | FN_KW@[0; 2) "fn" |
314 | WHITESPACE@[2; 3) | 321 | WHITESPACE@[2; 3) " " |
315 | NAME@[3; 6) | 322 | NAME@[3; 6) |
316 | IDENT@[3; 6) "foo" | 323 | IDENT@[3; 6) "foo" |
317 | PARAM_LIST@[6; 8) | 324 | PARAM_LIST@[6; 8) |
318 | L_PAREN@[6; 7) | 325 | L_PAREN@[6; 7) "(" |
319 | R_PAREN@[7; 8) | 326 | R_PAREN@[7; 8) ")" |
320 | WHITESPACE@[8; 9) | 327 | WHITESPACE@[8; 9) " " |
321 | BLOCK@[9; 12) | 328 | BLOCK@[9; 12) |
322 | L_CURLY@[9; 10) | 329 | L_CURLY@[9; 10) "{" |
323 | WHITESPACE@[10; 11) | 330 | WHITESPACE@[10; 11) "\n" |
324 | R_CURLY@[11; 12) | 331 | R_CURLY@[11; 12) "}" |
325 | WHITESPACE@[12; 13) | 332 | WHITESPACE@[12; 13) "\n" |
326 | FN_DEF@[13; 25) | 333 | FN_DEF@[13; 25) |
327 | FN_KW@[13; 15) | 334 | FN_KW@[13; 15) "fn" |
328 | WHITESPACE@[15; 16) | 335 | WHITESPACE@[15; 16) " " |
329 | NAME@[16; 19) | 336 | NAME@[16; 19) |
330 | IDENT@[16; 19) "bar" | 337 | IDENT@[16; 19) "bar" |
331 | PARAM_LIST@[19; 21) | 338 | PARAM_LIST@[19; 21) |
332 | L_PAREN@[19; 20) | 339 | L_PAREN@[19; 20) "(" |
333 | R_PAREN@[20; 21) | 340 | R_PAREN@[20; 21) ")" |
334 | WHITESPACE@[21; 22) | 341 | WHITESPACE@[21; 22) " " |
335 | BLOCK@[22; 25) | 342 | BLOCK@[22; 25) |
336 | L_CURLY@[22; 23) | 343 | L_CURLY@[22; 23) "{" |
337 | WHITESPACE@[23; 24) | 344 | WHITESPACE@[23; 24) "\n" |
338 | R_CURLY@[24; 25) | 345 | R_CURLY@[24; 25) "}" |
339 | |||
340 | "# | 346 | "# |
341 | .trim() | 347 | .trim() |
342 | ); | 348 | ); |