aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src')
-rw-r--r--crates/ra_ide_api/src/lib.rs4
-rw-r--r--crates/ra_ide_api/src/references.rs154
-rw-r--r--crates/ra_ide_api/src/syntax_tree.rs714
3 files changed, 443 insertions, 429 deletions
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index 514dcaf96..e90fbd428 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -466,7 +466,7 @@ impl Analysis {
466 &self, 466 &self,
467 position: FilePosition, 467 position: FilePosition,
468 ) -> Cancelable<Option<ReferenceSearchResult>> { 468 ) -> Cancelable<Option<ReferenceSearchResult>> {
469 self.with_db(|db| references::find_all_refs(db, position)) 469 self.with_db(|db| references::find_all_refs(db, position).map(|it| it.info))
470 } 470 }
471 471
472 /// Returns a short text describing element at position. 472 /// Returns a short text describing element at position.
@@ -536,7 +536,7 @@ impl Analysis {
536 &self, 536 &self,
537 position: FilePosition, 537 position: FilePosition,
538 new_name: &str, 538 new_name: &str,
539 ) -> Cancelable<Option<SourceChange>> { 539 ) -> Cancelable<Option<RangeInfo<SourceChange>>> {
540 self.with_db(|db| references::rename(db, position, new_name)) 540 self.with_db(|db| references::rename(db, position, new_name))
541 } 541 }
542 542
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs
index d8a00067f..5f1f0efc3 100644
--- a/crates/ra_ide_api/src/references.rs
+++ b/crates/ra_ide_api/src/references.rs
@@ -4,7 +4,7 @@ use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode}
4use relative_path::{RelativePath, RelativePathBuf}; 4use relative_path::{RelativePath, RelativePathBuf};
5 5
6use crate::{ 6use crate::{
7 db::RootDatabase, FileId, FilePosition, FileRange, FileSystemEdit, NavigationTarget, 7 db::RootDatabase, FileId, FilePosition, FileRange, FileSystemEdit, NavigationTarget, RangeInfo,
8 SourceChange, SourceFileEdit, TextRange, 8 SourceChange, SourceFileEdit, TextRange,
9}; 9};
10 10
@@ -48,9 +48,9 @@ impl IntoIterator for ReferenceSearchResult {
48pub(crate) fn find_all_refs( 48pub(crate) fn find_all_refs(
49 db: &RootDatabase, 49 db: &RootDatabase,
50 position: FilePosition, 50 position: FilePosition,
51) -> Option<ReferenceSearchResult> { 51) -> Option<RangeInfo<ReferenceSearchResult>> {
52 let parse = db.parse(position.file_id); 52 let parse = db.parse(position.file_id);
53 let (binding, analyzer) = find_binding(db, &parse.tree(), position)?; 53 let RangeInfo { range, info: (binding, analyzer) } = find_binding(db, &parse.tree(), position)?;
54 let declaration = NavigationTarget::from_bind_pat(position.file_id, &binding); 54 let declaration = NavigationTarget::from_bind_pat(position.file_id, &binding);
55 55
56 let references = analyzer 56 let references = analyzer
@@ -59,24 +59,26 @@ pub(crate) fn find_all_refs(
59 .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range }) 59 .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range })
60 .collect::<Vec<_>>(); 60 .collect::<Vec<_>>();
61 61
62 return Some(ReferenceSearchResult { declaration, references }); 62 return Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references }));
63 63
64 fn find_binding<'a>( 64 fn find_binding<'a>(
65 db: &RootDatabase, 65 db: &RootDatabase,
66 source_file: &SourceFile, 66 source_file: &SourceFile,
67 position: FilePosition, 67 position: FilePosition,
68 ) -> Option<(ast::BindPat, hir::SourceAnalyzer)> { 68 ) -> Option<RangeInfo<(ast::BindPat, hir::SourceAnalyzer)>> {
69 let syntax = source_file.syntax(); 69 let syntax = source_file.syntax();
70 if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) { 70 if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) {
71 let range = binding.syntax().text_range();
71 let analyzer = hir::SourceAnalyzer::new(db, position.file_id, binding.syntax(), None); 72 let analyzer = hir::SourceAnalyzer::new(db, position.file_id, binding.syntax(), None);
72 return Some((binding, analyzer)); 73 return Some(RangeInfo::new(range, (binding, analyzer)));
73 }; 74 };
74 let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?; 75 let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?;
76 let range = name_ref.syntax().text_range();
75 let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None); 77 let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None);
76 let resolved = analyzer.resolve_local_name(&name_ref)?; 78 let resolved = analyzer.resolve_local_name(&name_ref)?;
77 if let Either::A(ptr) = resolved.ptr() { 79 if let Either::A(ptr) = resolved.ptr() {
78 if let ast::Pat::BindPat(binding) = ptr.to_node(source_file.syntax()) { 80 if let ast::Pat::BindPat(binding) = ptr.to_node(source_file.syntax()) {
79 return Some((binding, analyzer)); 81 return Some(RangeInfo::new(range, (binding, analyzer)));
80 } 82 }
81 } 83 }
82 None 84 None
@@ -87,12 +89,14 @@ pub(crate) fn rename(
87 db: &RootDatabase, 89 db: &RootDatabase,
88 position: FilePosition, 90 position: FilePosition,
89 new_name: &str, 91 new_name: &str,
90) -> Option<SourceChange> { 92) -> Option<RangeInfo<SourceChange>> {
91 let parse = db.parse(position.file_id); 93 let parse = db.parse(position.file_id);
92 if let Some((ast_name, ast_module)) = 94 if let Some((ast_name, ast_module)) =
93 find_name_and_module_at_offset(parse.tree().syntax(), position) 95 find_name_and_module_at_offset(parse.tree().syntax(), position)
94 { 96 {
97 let range = ast_name.syntax().text_range();
95 rename_mod(db, &ast_name, &ast_module, position, new_name) 98 rename_mod(db, &ast_name, &ast_module, position, new_name)
99 .map(|info| RangeInfo::new(range, info))
96 } else { 100 } else {
97 rename_reference(db, position, new_name) 101 rename_reference(db, position, new_name)
98 } 102 }
@@ -107,7 +111,7 @@ fn find_name_and_module_at_offset(
107 Some((ast_name, ast_module)) 111 Some((ast_name, ast_module))
108} 112}
109 113
110fn source_edit_from_fileid_range( 114fn source_edit_from_file_id_range(
111 file_id: FileId, 115 file_id: FileId,
112 range: TextRange, 116 range: TextRange,
113 new_name: &str, 117 new_name: &str,
@@ -179,19 +183,19 @@ fn rename_reference(
179 db: &RootDatabase, 183 db: &RootDatabase,
180 position: FilePosition, 184 position: FilePosition,
181 new_name: &str, 185 new_name: &str,
182) -> Option<SourceChange> { 186) -> Option<RangeInfo<SourceChange>> {
183 let refs = find_all_refs(db, position)?; 187 let RangeInfo { range, info: refs } = find_all_refs(db, position)?;
184 188
185 let edit = refs 189 let edit = refs
186 .into_iter() 190 .into_iter()
187 .map(|range| source_edit_from_fileid_range(range.file_id, range.range, new_name)) 191 .map(|range| source_edit_from_file_id_range(range.file_id, range.range, new_name))
188 .collect::<Vec<_>>(); 192 .collect::<Vec<_>>();
189 193
190 if edit.is_empty() { 194 if edit.is_empty() {
191 return None; 195 return None;
192 } 196 }
193 197
194 Some(SourceChange::source_file_edits("rename", edit)) 198 Some(RangeInfo::new(range, SourceChange::source_file_edits("rename", edit)))
195} 199}
196 200
197#[cfg(test)] 201#[cfg(test)]
@@ -342,38 +346,43 @@ mod tests {
342 let new_name = "foo2"; 346 let new_name = "foo2";
343 let source_change = analysis.rename(position, new_name).unwrap(); 347 let source_change = analysis.rename(position, new_name).unwrap();
344 assert_debug_snapshot!(&source_change, 348 assert_debug_snapshot!(&source_change,
345@r#"Some( 349@r###"
346 SourceChange { 350 Some(
347 label: "rename", 351 RangeInfo {
348 source_file_edits: [ 352 range: [4; 7),
349 SourceFileEdit { 353 info: SourceChange {
350 file_id: FileId( 354 label: "rename",
351 2, 355 source_file_edits: [
352 ), 356 SourceFileEdit {
353 edit: TextEdit { 357 file_id: FileId(
354 atoms: [ 358 2,
355 AtomTextEdit { 359 ),
356 delete: [4; 7), 360 edit: TextEdit {
357 insert: "foo2", 361 atoms: [
362 AtomTextEdit {
363 delete: [4; 7),
364 insert: "foo2",
365 },
366 ],
367 },
368 },
369 ],
370 file_system_edits: [
371 MoveFile {
372 src: FileId(
373 3,
374 ),
375 dst_source_root: SourceRootId(
376 0,
377 ),
378 dst_path: "bar/foo2.rs",
358 }, 379 },
359 ], 380 ],
381 cursor_position: None,
360 }, 382 },
361 }, 383 },
362 ], 384 )
363 file_system_edits: [ 385 "###);
364 MoveFile {
365 src: FileId(
366 3,
367 ),
368 dst_source_root: SourceRootId(
369 0,
370 ),
371 dst_path: "bar/foo2.rs",
372 },
373 ],
374 cursor_position: None,
375 },
376)"#);
377 } 386 }
378 387
379 #[test] 388 #[test]
@@ -389,38 +398,43 @@ mod tests {
389 let new_name = "foo2"; 398 let new_name = "foo2";
390 let source_change = analysis.rename(position, new_name).unwrap(); 399 let source_change = analysis.rename(position, new_name).unwrap();
391 assert_debug_snapshot!(&source_change, 400 assert_debug_snapshot!(&source_change,
392 @r###"Some( 401 @r###"
393 SourceChange { 402 Some(
394 label: "rename", 403 RangeInfo {
395 source_file_edits: [ 404 range: [4; 7),
396 SourceFileEdit { 405 info: SourceChange {
397 file_id: FileId( 406 label: "rename",
398 1, 407 source_file_edits: [
399 ), 408 SourceFileEdit {
400 edit: TextEdit { 409 file_id: FileId(
401 atoms: [ 410 1,
402 AtomTextEdit { 411 ),
403 delete: [4; 7), 412 edit: TextEdit {
404 insert: "foo2", 413 atoms: [
414 AtomTextEdit {
415 delete: [4; 7),
416 insert: "foo2",
417 },
418 ],
419 },
420 },
421 ],
422 file_system_edits: [
423 MoveFile {
424 src: FileId(
425 2,
426 ),
427 dst_source_root: SourceRootId(
428 0,
429 ),
430 dst_path: "foo2/mod.rs",
405 }, 431 },
406 ], 432 ],
433 cursor_position: None,
407 }, 434 },
408 }, 435 },
409 ], 436 )
410 file_system_edits: [ 437 "###
411 MoveFile {
412 src: FileId(
413 2,
414 ),
415 dst_source_root: SourceRootId(
416 0,
417 ),
418 dst_path: "foo2/mod.rs",
419 },
420 ],
421 cursor_position: None,
422 },
423)"###
424 ); 438 );
425 } 439 }
426 440
@@ -430,7 +444,7 @@ mod tests {
430 let mut text_edit_builder = ra_text_edit::TextEditBuilder::default(); 444 let mut text_edit_builder = ra_text_edit::TextEditBuilder::default();
431 let mut file_id: Option<FileId> = None; 445 let mut file_id: Option<FileId> = None;
432 if let Some(change) = source_change { 446 if let Some(change) = source_change {
433 for edit in change.source_file_edits { 447 for edit in change.info.source_file_edits {
434 file_id = Some(edit.file_id); 448 file_id = Some(edit.file_id);
435 for atom in edit.edit.as_atoms() { 449 for atom in edit.edit.as_atoms() {
436 text_edit_builder.replace(atom.delete, atom.insert.clone()); 450 text_edit_builder.replace(atom.delete, atom.insert.clone());
diff --git a/crates/ra_ide_api/src/syntax_tree.rs b/crates/ra_ide_api/src/syntax_tree.rs
index 914759709..e2bb120b4 100644
--- a/crates/ra_ide_api/src/syntax_tree.rs
+++ b/crates/ra_ide_api/src/syntax_tree.rs
@@ -1,357 +1,357 @@
1use crate::db::RootDatabase; 1use crate::db::RootDatabase;
2use ra_db::SourceDatabase; 2use ra_db::SourceDatabase;
3use ra_syntax::{ 3use ra_syntax::{
4 algo, AstNode, NodeOrToken, SourceFile, 4 algo, AstNode, NodeOrToken, SourceFile,
5 SyntaxKind::{RAW_STRING, STRING}, 5 SyntaxKind::{RAW_STRING, STRING},
6 SyntaxToken, TextRange, 6 SyntaxToken, TextRange,
7}; 7};
8 8
9pub use ra_db::FileId; 9pub use ra_db::FileId;
10 10
11pub(crate) fn syntax_tree( 11pub(crate) fn syntax_tree(
12 db: &RootDatabase, 12 db: &RootDatabase,
13 file_id: FileId, 13 file_id: FileId,
14 text_range: Option<TextRange>, 14 text_range: Option<TextRange>,
15) -> String { 15) -> String {
16 let parse = db.parse(file_id); 16 let parse = db.parse(file_id);
17 if let Some(text_range) = text_range { 17 if let Some(text_range) = text_range {
18 let node = match algo::find_covering_element(parse.tree().syntax(), text_range) { 18 let node = match algo::find_covering_element(parse.tree().syntax(), text_range) {
19 NodeOrToken::Node(node) => node, 19 NodeOrToken::Node(node) => node,
20 NodeOrToken::Token(token) => { 20 NodeOrToken::Token(token) => {
21 if let Some(tree) = syntax_tree_for_string(&token, text_range) { 21 if let Some(tree) = syntax_tree_for_string(&token, text_range) {
22 return tree; 22 return tree;
23 } 23 }
24 token.parent() 24 token.parent()
25 } 25 }
26 }; 26 };
27 27
28 format!("{:#?}", node) 28 format!("{:#?}", node)
29 } else { 29 } else {
30 format!("{:#?}", parse.tree().syntax()) 30 format!("{:#?}", parse.tree().syntax())
31 } 31 }
32} 32}
33 33
34/// Attempts parsing the selected contents of a string literal 34/// Attempts parsing the selected contents of a string literal
35/// as rust syntax and returns its syntax tree 35/// as rust syntax and returns its syntax tree
36fn syntax_tree_for_string(token: &SyntaxToken, text_range: TextRange) -> Option<String> { 36fn syntax_tree_for_string(token: &SyntaxToken, text_range: TextRange) -> Option<String> {
37 // When the range is inside a string 37 // When the range is inside a string
38 // we'll attempt parsing it as rust syntax 38 // we'll attempt parsing it as rust syntax
39 // to provide the syntax tree of the contents of the string 39 // to provide the syntax tree of the contents of the string
40 match token.kind() { 40 match token.kind() {
41 STRING | RAW_STRING => syntax_tree_for_token(token, text_range), 41 STRING | RAW_STRING => syntax_tree_for_token(token, text_range),
42 _ => None, 42 _ => None,
43 } 43 }
44} 44}
45 45
46fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option<String> { 46fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option<String> {
47 // Range of the full node 47 // Range of the full node
48 let node_range = node.text_range(); 48 let node_range = node.text_range();
49 let text = node.text().to_string(); 49 let text = node.text().to_string();
50 50
51 // We start at some point inside the node 51 // We start at some point inside the node
52 // Either we have selected the whole string 52 // Either we have selected the whole string
53 // or our selection is inside it 53 // or our selection is inside it
54 let start = text_range.start() - node_range.start(); 54 let start = text_range.start() - node_range.start();
55 55
56 // how many characters we have selected 56 // how many characters we have selected
57 let len = text_range.len().to_usize(); 57 let len = text_range.len().to_usize();
58 58
59 let node_len = node_range.len().to_usize(); 59 let node_len = node_range.len().to_usize();
60 60
61 let start = start.to_usize(); 61 let start = start.to_usize();
62 62
63 // We want to cap our length 63 // We want to cap our length
64 let len = len.min(node_len); 64 let len = len.min(node_len);
65 65
66 // Ensure our slice is inside the actual string 66 // Ensure our slice is inside the actual string
67 let end = if start + len < text.len() { start + len } else { text.len() - start }; 67 let end = if start + len < text.len() { start + len } else { text.len() - start };
68 68
69 let text = &text[start..end]; 69 let text = &text[start..end];
70 70
71 // Remove possible extra string quotes from the start 71 // Remove possible extra string quotes from the start
72 // and the end of the string 72 // and the end of the string
73 let text = text 73 let text = text
74 .trim_start_matches('r') 74 .trim_start_matches('r')
75 .trim_start_matches('#') 75 .trim_start_matches('#')
76 .trim_start_matches('"') 76 .trim_start_matches('"')
77 .trim_end_matches('#') 77 .trim_end_matches('#')
78 .trim_end_matches('"') 78 .trim_end_matches('"')
79 .trim() 79 .trim()
80 // Remove custom markers 80 // Remove custom markers
81 .replace("<|>", ""); 81 .replace("<|>", "");
82 82
83 let parsed = SourceFile::parse(&text); 83 let parsed = SourceFile::parse(&text);
84 84
85 // If the "file" parsed without errors, 85 // If the "file" parsed without errors,
86 // return its syntax 86 // return its syntax
87 if parsed.errors().is_empty() { 87 if parsed.errors().is_empty() {
88 return Some(format!("{:#?}", parsed.tree().syntax())); 88 return Some(format!("{:#?}", parsed.tree().syntax()));
89 } 89 }
90 90
91 None 91 None
92} 92}
93 93
94#[cfg(test)] 94#[cfg(test)]
95mod tests { 95mod tests {
96 use test_utils::assert_eq_text; 96 use test_utils::assert_eq_text;
97 97
98 use crate::mock_analysis::{single_file, single_file_with_range}; 98 use crate::mock_analysis::{single_file, single_file_with_range};
99 99
100 #[test] 100 #[test]
101 fn test_syntax_tree_without_range() { 101 fn test_syntax_tree_without_range() {
102 // Basic syntax 102 // Basic syntax
103 let (analysis, file_id) = single_file(r#"fn foo() {}"#); 103 let (analysis, file_id) = single_file(r#"fn foo() {}"#);
104 let syn = analysis.syntax_tree(file_id, None).unwrap(); 104 let syn = analysis.syntax_tree(file_id, None).unwrap();
105 105
106 assert_eq_text!( 106 assert_eq_text!(
107 syn.trim(), 107 syn.trim(),
108 r#" 108 r#"
109SOURCE_FILE@[0; 11) 109SOURCE_FILE@[0; 11)
110 FN_DEF@[0; 11) 110 FN_DEF@[0; 11)
111 FN_KW@[0; 2) "fn" 111 FN_KW@[0; 2) "fn"
112 WHITESPACE@[2; 3) " " 112 WHITESPACE@[2; 3) " "
113 NAME@[3; 6) 113 NAME@[3; 6)
114 IDENT@[3; 6) "foo" 114 IDENT@[3; 6) "foo"
115 PARAM_LIST@[6; 8) 115 PARAM_LIST@[6; 8)
116 L_PAREN@[6; 7) "(" 116 L_PAREN@[6; 7) "("
117 R_PAREN@[7; 8) ")" 117 R_PAREN@[7; 8) ")"
118 WHITESPACE@[8; 9) " " 118 WHITESPACE@[8; 9) " "
119 BLOCK_EXPR@[9; 11) 119 BLOCK_EXPR@[9; 11)
120 BLOCK@[9; 11) 120 BLOCK@[9; 11)
121 L_CURLY@[9; 10) "{" 121 L_CURLY@[9; 10) "{"
122 R_CURLY@[10; 11) "}" 122 R_CURLY@[10; 11) "}"
123"# 123"#
124 .trim() 124 .trim()
125 ); 125 );
126 126
127 let (analysis, file_id) = single_file( 127 let (analysis, file_id) = single_file(
128 r#" 128 r#"
129fn test() { 129fn test() {
130 assert!(" 130 assert!("
131 fn foo() { 131 fn foo() {
132 } 132 }
133 ", ""); 133 ", "");
134}"# 134}"#
135 .trim(), 135 .trim(),
136 ); 136 );
137 let syn = analysis.syntax_tree(file_id, None).unwrap(); 137 let syn = analysis.syntax_tree(file_id, None).unwrap();
138 138
139 assert_eq_text!( 139 assert_eq_text!(
140 syn.trim(), 140 syn.trim(),
141 r#" 141 r#"
142SOURCE_FILE@[0; 60) 142SOURCE_FILE@[0; 60)
143 FN_DEF@[0; 60) 143 FN_DEF@[0; 60)
144 FN_KW@[0; 2) "fn" 144 FN_KW@[0; 2) "fn"
145 WHITESPACE@[2; 3) " " 145 WHITESPACE@[2; 3) " "
146 NAME@[3; 7) 146 NAME@[3; 7)
147 IDENT@[3; 7) "test" 147 IDENT@[3; 7) "test"
148 PARAM_LIST@[7; 9) 148 PARAM_LIST@[7; 9)
149 L_PAREN@[7; 8) "(" 149 L_PAREN@[7; 8) "("
150 R_PAREN@[8; 9) ")" 150 R_PAREN@[8; 9) ")"
151 WHITESPACE@[9; 10) " " 151 WHITESPACE@[9; 10) " "
152 BLOCK_EXPR@[10; 60) 152 BLOCK_EXPR@[10; 60)
153 BLOCK@[10; 60) 153 BLOCK@[10; 60)
154 L_CURLY@[10; 11) "{" 154 L_CURLY@[10; 11) "{"
155 WHITESPACE@[11; 16) "\n " 155 WHITESPACE@[11; 16) "\n "
156 EXPR_STMT@[16; 58) 156 EXPR_STMT@[16; 58)
157 MACRO_CALL@[16; 57) 157 MACRO_CALL@[16; 57)
158 PATH@[16; 22) 158 PATH@[16; 22)
159 PATH_SEGMENT@[16; 22) 159 PATH_SEGMENT@[16; 22)
160 NAME_REF@[16; 22) 160 NAME_REF@[16; 22)
161 IDENT@[16; 22) "assert" 161 IDENT@[16; 22) "assert"
162 EXCL@[22; 23) "!" 162 EXCL@[22; 23) "!"
163 TOKEN_TREE@[23; 57) 163 TOKEN_TREE@[23; 57)
164 L_PAREN@[23; 24) "(" 164 L_PAREN@[23; 24) "("
165 STRING@[24; 52) "\"\n fn foo() {\n ..." 165 STRING@[24; 52) "\"\n fn foo() {\n ..."
166 COMMA@[52; 53) "," 166 COMMA@[52; 53) ","
167 WHITESPACE@[53; 54) " " 167 WHITESPACE@[53; 54) " "
168 STRING@[54; 56) "\"\"" 168 STRING@[54; 56) "\"\""
169 R_PAREN@[56; 57) ")" 169 R_PAREN@[56; 57) ")"
170 SEMI@[57; 58) ";" 170 SEMI@[57; 58) ";"
171 WHITESPACE@[58; 59) "\n" 171 WHITESPACE@[58; 59) "\n"
172 R_CURLY@[59; 60) "}" 172 R_CURLY@[59; 60) "}"
173"# 173"#
174 .trim() 174 .trim()
175 ); 175 );
176 } 176 }
177 177
178 #[test] 178 #[test]
179 fn test_syntax_tree_with_range() { 179 fn test_syntax_tree_with_range() {
180 let (analysis, range) = single_file_with_range(r#"<|>fn foo() {}<|>"#.trim()); 180 let (analysis, range) = single_file_with_range(r#"<|>fn foo() {}<|>"#.trim());
181 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); 181 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap();
182 182
183 assert_eq_text!( 183 assert_eq_text!(
184 syn.trim(), 184 syn.trim(),
185 r#" 185 r#"
186FN_DEF@[0; 11) 186FN_DEF@[0; 11)
187 FN_KW@[0; 2) "fn" 187 FN_KW@[0; 2) "fn"
188 WHITESPACE@[2; 3) " " 188 WHITESPACE@[2; 3) " "
189 NAME@[3; 6) 189 NAME@[3; 6)
190 IDENT@[3; 6) "foo" 190 IDENT@[3; 6) "foo"
191 PARAM_LIST@[6; 8) 191 PARAM_LIST@[6; 8)
192 L_PAREN@[6; 7) "(" 192 L_PAREN@[6; 7) "("
193 R_PAREN@[7; 8) ")" 193 R_PAREN@[7; 8) ")"
194 WHITESPACE@[8; 9) " " 194 WHITESPACE@[8; 9) " "
195 BLOCK_EXPR@[9; 11) 195 BLOCK_EXPR@[9; 11)
196 BLOCK@[9; 11) 196 BLOCK@[9; 11)
197 L_CURLY@[9; 10) "{" 197 L_CURLY@[9; 10) "{"
198 R_CURLY@[10; 11) "}" 198 R_CURLY@[10; 11) "}"
199"# 199"#
200 .trim() 200 .trim()
201 ); 201 );
202 202
203 let (analysis, range) = single_file_with_range( 203 let (analysis, range) = single_file_with_range(
204 r#"fn test() { 204 r#"fn test() {
205 <|>assert!(" 205 <|>assert!("
206 fn foo() { 206 fn foo() {
207 } 207 }
208 ", "");<|> 208 ", "");<|>
209}"# 209}"#
210 .trim(), 210 .trim(),
211 ); 211 );
212 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); 212 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap();
213 213
214 assert_eq_text!( 214 assert_eq_text!(
215 syn.trim(), 215 syn.trim(),
216 r#" 216 r#"
217EXPR_STMT@[16; 58) 217EXPR_STMT@[16; 58)
218 MACRO_CALL@[16; 57) 218 MACRO_CALL@[16; 57)
219 PATH@[16; 22) 219 PATH@[16; 22)
220 PATH_SEGMENT@[16; 22) 220 PATH_SEGMENT@[16; 22)
221 NAME_REF@[16; 22) 221 NAME_REF@[16; 22)
222 IDENT@[16; 22) "assert" 222 IDENT@[16; 22) "assert"
223 EXCL@[22; 23) "!" 223 EXCL@[22; 23) "!"
224 TOKEN_TREE@[23; 57) 224 TOKEN_TREE@[23; 57)
225 L_PAREN@[23; 24) "(" 225 L_PAREN@[23; 24) "("
226 STRING@[24; 52) "\"\n fn foo() {\n ..." 226 STRING@[24; 52) "\"\n fn foo() {\n ..."
227 COMMA@[52; 53) "," 227 COMMA@[52; 53) ","
228 WHITESPACE@[53; 54) " " 228 WHITESPACE@[53; 54) " "
229 STRING@[54; 56) "\"\"" 229 STRING@[54; 56) "\"\""
230 R_PAREN@[56; 57) ")" 230 R_PAREN@[56; 57) ")"
231 SEMI@[57; 58) ";" 231 SEMI@[57; 58) ";"
232"# 232"#
233 .trim() 233 .trim()
234 ); 234 );
235 } 235 }
236 236
237 #[test] 237 #[test]
238 fn test_syntax_tree_inside_string() { 238 fn test_syntax_tree_inside_string() {
239 let (analysis, range) = single_file_with_range( 239 let (analysis, range) = single_file_with_range(
240 r#"fn test() { 240 r#"fn test() {
241 assert!(" 241 assert!("
242<|>fn foo() { 242<|>fn foo() {
243}<|> 243}<|>
244fn bar() { 244fn bar() {
245} 245}
246 ", ""); 246 ", "");
247}"# 247}"#
248 .trim(), 248 .trim(),
249 ); 249 );
250 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); 250 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap();
251 assert_eq_text!( 251 assert_eq_text!(
252 syn.trim(), 252 syn.trim(),
253 r#" 253 r#"
254SOURCE_FILE@[0; 12) 254SOURCE_FILE@[0; 12)
255 FN_DEF@[0; 12) 255 FN_DEF@[0; 12)
256 FN_KW@[0; 2) "fn" 256 FN_KW@[0; 2) "fn"
257 WHITESPACE@[2; 3) " " 257 WHITESPACE@[2; 3) " "
258 NAME@[3; 6) 258 NAME@[3; 6)
259 IDENT@[3; 6) "foo" 259 IDENT@[3; 6) "foo"
260 PARAM_LIST@[6; 8) 260 PARAM_LIST@[6; 8)
261 L_PAREN@[6; 7) "(" 261 L_PAREN@[6; 7) "("
262 R_PAREN@[7; 8) ")" 262 R_PAREN@[7; 8) ")"
263 WHITESPACE@[8; 9) " " 263 WHITESPACE@[8; 9) " "
264 BLOCK_EXPR@[9; 12) 264 BLOCK_EXPR@[9; 12)
265 BLOCK@[9; 12) 265 BLOCK@[9; 12)
266 L_CURLY@[9; 10) "{" 266 L_CURLY@[9; 10) "{"
267 WHITESPACE@[10; 11) "\n" 267 WHITESPACE@[10; 11) "\n"
268 R_CURLY@[11; 12) "}" 268 R_CURLY@[11; 12) "}"
269"# 269"#
270 .trim() 270 .trim()
271 ); 271 );
272 272
273 // With a raw string 273 // With a raw string
274 let (analysis, range) = single_file_with_range( 274 let (analysis, range) = single_file_with_range(
275 r###"fn test() { 275 r###"fn test() {
276 assert!(r#" 276 assert!(r#"
277<|>fn foo() { 277<|>fn foo() {
278}<|> 278}<|>
279fn bar() { 279fn bar() {
280} 280}
281 "#, ""); 281 "#, "");
282}"### 282}"###
283 .trim(), 283 .trim(),
284 ); 284 );
285 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); 285 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap();
286 assert_eq_text!( 286 assert_eq_text!(
287 syn.trim(), 287 syn.trim(),
288 r#" 288 r#"
289SOURCE_FILE@[0; 12) 289SOURCE_FILE@[0; 12)
290 FN_DEF@[0; 12) 290 FN_DEF@[0; 12)
291 FN_KW@[0; 2) "fn" 291 FN_KW@[0; 2) "fn"
292 WHITESPACE@[2; 3) " " 292 WHITESPACE@[2; 3) " "
293 NAME@[3; 6) 293 NAME@[3; 6)
294 IDENT@[3; 6) "foo" 294 IDENT@[3; 6) "foo"
295 PARAM_LIST@[6; 8) 295 PARAM_LIST@[6; 8)
296 L_PAREN@[6; 7) "(" 296 L_PAREN@[6; 7) "("
297 R_PAREN@[7; 8) ")" 297 R_PAREN@[7; 8) ")"
298 WHITESPACE@[8; 9) " " 298 WHITESPACE@[8; 9) " "
299 BLOCK_EXPR@[9; 12) 299 BLOCK_EXPR@[9; 12)
300 BLOCK@[9; 12) 300 BLOCK@[9; 12)
301 L_CURLY@[9; 10) "{" 301 L_CURLY@[9; 10) "{"
302 WHITESPACE@[10; 11) "\n" 302 WHITESPACE@[10; 11) "\n"
303 R_CURLY@[11; 12) "}" 303 R_CURLY@[11; 12) "}"
304"# 304"#
305 .trim() 305 .trim()
306 ); 306 );
307 307
308 // With a raw string 308 // With a raw string
309 let (analysis, range) = single_file_with_range( 309 let (analysis, range) = single_file_with_range(
310 r###"fn test() { 310 r###"fn test() {
311 assert!(r<|>#" 311 assert!(r<|>#"
312fn foo() { 312fn foo() {
313} 313}
314fn bar() { 314fn bar() {
315}"<|>#, ""); 315}"<|>#, "");
316}"### 316}"###
317 .trim(), 317 .trim(),
318 ); 318 );
319 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); 319 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap();
320 assert_eq_text!( 320 assert_eq_text!(
321 syn.trim(), 321 syn.trim(),
322 r#" 322 r#"
323SOURCE_FILE@[0; 25) 323SOURCE_FILE@[0; 25)
324 FN_DEF@[0; 12) 324 FN_DEF@[0; 12)
325 FN_KW@[0; 2) "fn" 325 FN_KW@[0; 2) "fn"
326 WHITESPACE@[2; 3) " " 326 WHITESPACE@[2; 3) " "
327 NAME@[3; 6) 327 NAME@[3; 6)
328 IDENT@[3; 6) "foo" 328 IDENT@[3; 6) "foo"
329 PARAM_LIST@[6; 8) 329 PARAM_LIST@[6; 8)
330 L_PAREN@[6; 7) "(" 330 L_PAREN@[6; 7) "("
331 R_PAREN@[7; 8) ")" 331 R_PAREN@[7; 8) ")"
332 WHITESPACE@[8; 9) " " 332 WHITESPACE@[8; 9) " "
333 BLOCK_EXPR@[9; 12) 333 BLOCK_EXPR@[9; 12)
334 BLOCK@[9; 12) 334 BLOCK@[9; 12)
335 L_CURLY@[9; 10) "{" 335 L_CURLY@[9; 10) "{"
336 WHITESPACE@[10; 11) "\n" 336 WHITESPACE@[10; 11) "\n"
337 R_CURLY@[11; 12) "}" 337 R_CURLY@[11; 12) "}"
338 WHITESPACE@[12; 13) "\n" 338 WHITESPACE@[12; 13) "\n"
339 FN_DEF@[13; 25) 339 FN_DEF@[13; 25)
340 FN_KW@[13; 15) "fn" 340 FN_KW@[13; 15) "fn"
341 WHITESPACE@[15; 16) " " 341 WHITESPACE@[15; 16) " "
342 NAME@[16; 19) 342 NAME@[16; 19)
343 IDENT@[16; 19) "bar" 343 IDENT@[16; 19) "bar"
344 PARAM_LIST@[19; 21) 344 PARAM_LIST@[19; 21)
345 L_PAREN@[19; 20) "(" 345 L_PAREN@[19; 20) "("
346 R_PAREN@[20; 21) ")" 346 R_PAREN@[20; 21) ")"
347 WHITESPACE@[21; 22) " " 347 WHITESPACE@[21; 22) " "
348 BLOCK_EXPR@[22; 25) 348 BLOCK_EXPR@[22; 25)
349 BLOCK@[22; 25) 349 BLOCK@[22; 25)
350 L_CURLY@[22; 23) "{" 350 L_CURLY@[22; 23) "{"
351 WHITESPACE@[23; 24) "\n" 351 WHITESPACE@[23; 24) "\n"
352 R_CURLY@[24; 25) "}" 352 R_CURLY@[24; 25) "}"
353"# 353"#
354 .trim() 354 .trim()
355 ); 355 );
356 } 356 }
357} 357}