aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/syntax_tree.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/syntax_tree.rs')
-rw-r--r--crates/ra_ide_api/src/syntax_tree.rs202
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 @@
1use ra_db::SourceDatabase; 1use ra_db::SourceDatabase;
2use crate::db::RootDatabase; 2use crate::db::RootDatabase;
3use ra_syntax::{ 3use 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
8pub use ra_db::FileId; 9pub 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
31fn syntax_tree_for_string(node: &SyntaxNode, text_range: TextRange) -> Option<String> { 36fn 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
41fn syntax_tree_for_token<T: AstToken>(node: &T, text_range: TextRange) -> Option<String> { 46fn 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)]
90mod tests { 95mod 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#"
102SOURCE_FILE@[0; 11) 109SOURCE_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#"
134SOURCE_FILE@[0; 60) 141SOURCE_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#"
177FN_DEF@[0; 11) 184FN_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#"
207EXPR_STMT@[16; 58) 214EXPR_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#"
244SOURCE_FILE@[0; 12) 251SOURCE_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#"
278SOURCE_FILE@[0; 12) 285SOURCE_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#"
311SOURCE_FILE@[0; 25) 318SOURCE_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 );