aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_ide_api/src/folding_ranges.rs15
-rw-r--r--crates/ra_lsp_server/src/conv.rs24
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs38
-rw-r--r--crates/ra_mbe/src/tests.rs344
4 files changed, 202 insertions, 219 deletions
diff --git a/crates/ra_ide_api/src/folding_ranges.rs b/crates/ra_ide_api/src/folding_ranges.rs
index 3ab6c195e..79fadcc5d 100644
--- a/crates/ra_ide_api/src/folding_ranges.rs
+++ b/crates/ra_ide_api/src/folding_ranges.rs
@@ -87,6 +87,7 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
87 | EXTERN_ITEM_LIST 87 | EXTERN_ITEM_LIST
88 | USE_TREE_LIST 88 | USE_TREE_LIST
89 | BLOCK 89 | BLOCK
90 | MATCH_ARM_LIST
90 | ENUM_VARIANT_LIST 91 | ENUM_VARIANT_LIST
91 | TOKEN_TREE => Some(FoldKind::Block), 92 | TOKEN_TREE => Some(FoldKind::Block),
92 _ => None, 93 _ => None,
@@ -358,4 +359,18 @@ macro_rules! foo <fold>{
358 let folds = &[FoldKind::Block]; 359 let folds = &[FoldKind::Block];
359 do_check(text, folds); 360 do_check(text, folds);
360 } 361 }
362
363 #[test]
364 fn test_fold_match_arms() {
365 let text = r#"
366fn main() <fold>{
367 match 0 <fold>{
368 0 => 0,
369 _ => 1,
370 }</fold>
371}</fold>"#;
372
373 let folds = &[FoldKind::Block, FoldKind::Block];
374 do_check(text, folds);
375 }
361} 376}
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs
index 5fa52ec1b..d78f77925 100644
--- a/crates/ra_lsp_server/src/conv.rs
+++ b/crates/ra_lsp_server/src/conv.rs
@@ -6,8 +6,8 @@ use lsp_types::{
6}; 6};
7use ra_ide_api::{ 7use ra_ide_api::{
8 translate_offset_with_edit, CompletionItem, CompletionItemKind, FileId, FilePosition, 8 translate_offset_with_edit, CompletionItem, CompletionItemKind, FileId, FilePosition,
9 FileRange, FileSystemEdit, InsertTextFormat, LineCol, LineIndex, NavigationTarget, RangeInfo, 9 FileRange, FileSystemEdit, Fold, FoldKind, InsertTextFormat, LineCol, LineIndex,
10 Severity, SourceChange, SourceFileEdit, 10 NavigationTarget, RangeInfo, Severity, SourceChange, SourceFileEdit,
11}; 11};
12use ra_syntax::{SyntaxKind, TextRange, TextUnit}; 12use ra_syntax::{SyntaxKind, TextRange, TextUnit};
13use ra_text_edit::{AtomTextEdit, TextEdit}; 13use ra_text_edit::{AtomTextEdit, TextEdit};
@@ -225,6 +225,26 @@ impl ConvWith<(&LineIndex, LineEndings)> for &AtomTextEdit {
225 } 225 }
226} 226}
227 227
228impl ConvWith<&LineIndex> for Fold {
229 type Output = lsp_types::FoldingRange;
230
231 fn conv_with(self, line_index: &LineIndex) -> lsp_types::FoldingRange {
232 let range = self.range.conv_with(&line_index);
233 lsp_types::FoldingRange {
234 start_line: range.start.line,
235 start_character: Some(range.start.character),
236 end_line: range.end.line,
237 end_character: Some(range.end.character),
238 kind: match self.kind {
239 FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment),
240 FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports),
241 FoldKind::Mods => None,
242 FoldKind::Block => None,
243 },
244 }
245 }
246}
247
228impl<T: ConvWith<CTX>, CTX> ConvWith<CTX> for Option<T> { 248impl<T: ConvWith<CTX>, CTX> ConvWith<CTX> for Option<T> {
229 type Output = Option<T::Output>; 249 type Output = Option<T::Output>;
230 250
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 948d543ea..ae57e57e9 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -3,14 +3,11 @@ use std::{fmt::Write as _, io::Write as _};
3use lsp_server::ErrorCode; 3use lsp_server::ErrorCode;
4use lsp_types::{ 4use lsp_types::{
5 CodeAction, CodeActionResponse, CodeLens, Command, CompletionItem, Diagnostic, 5 CodeAction, CodeActionResponse, CodeLens, Command, CompletionItem, Diagnostic,
6 DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeKind, 6 DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeParams,
7 FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, MarkupKind, Position, 7 Hover, HoverContents, Location, MarkupContent, MarkupKind, Position, PrepareRenameResponse,
8 PrepareRenameResponse, Range, RenameParams, SymbolInformation, TextDocumentIdentifier, 8 Range, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit, WorkspaceEdit,
9 TextEdit, WorkspaceEdit,
10};
11use ra_ide_api::{
12 AssistId, FileId, FilePosition, FileRange, FoldKind, Query, Runnable, RunnableKind,
13}; 9};
10use ra_ide_api::{AssistId, FileId, FilePosition, FileRange, Query, Runnable, RunnableKind};
14use ra_prof::profile; 11use ra_prof::profile;
15use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit}; 12use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit};
16use rustc_hash::FxHashMap; 13use rustc_hash::FxHashMap;
@@ -383,32 +380,9 @@ pub fn handle_folding_range(
383 params: FoldingRangeParams, 380 params: FoldingRangeParams,
384) -> Result<Option<Vec<FoldingRange>>> { 381) -> Result<Option<Vec<FoldingRange>>> {
385 let file_id = params.text_document.try_conv_with(&world)?; 382 let file_id = params.text_document.try_conv_with(&world)?;
383 let folds = world.analysis().folding_ranges(file_id)?;
386 let line_index = world.analysis().file_line_index(file_id)?; 384 let line_index = world.analysis().file_line_index(file_id)?;
387 385 let res = Some(folds.into_iter().map_conv_with(&*line_index).collect());
388 let res = Some(
389 world
390 .analysis()
391 .folding_ranges(file_id)?
392 .into_iter()
393 .map(|fold| {
394 let kind = match fold.kind {
395 FoldKind::Comment => Some(FoldingRangeKind::Comment),
396 FoldKind::Imports => Some(FoldingRangeKind::Imports),
397 FoldKind::Mods => None,
398 FoldKind::Block => None,
399 };
400 let range = fold.range.conv_with(&line_index);
401 FoldingRange {
402 start_line: range.start.line,
403 start_character: Some(range.start.character),
404 end_line: range.end.line,
405 end_character: Some(range.start.character),
406 kind,
407 }
408 })
409 .collect(),
410 );
411
412 Ok(res) 386 Ok(res)
413} 387}
414 388
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs
index d7482c63d..f34ab52e1 100644
--- a/crates/ra_mbe/src/tests.rs
+++ b/crates/ra_mbe/src/tests.rs
@@ -1,4 +1,4 @@
1use ra_syntax::{ast, AstNode, NodeOrToken}; 1use ra_syntax::{ast, AstNode, NodeOrToken, WalkEvent};
2use test_utils::assert_eq_text; 2use test_utils::assert_eq_text;
3 3
4use super::*; 4use super::*;
@@ -78,18 +78,8 @@ macro_rules! impl_froms {
78impl_froms!(TokenTree: Leaf, Subtree); 78impl_froms!(TokenTree: Leaf, Subtree);
79"#; 79"#;
80 80
81 let source_file = ast::SourceFile::parse(macro_definition).ok().unwrap(); 81 let rules = create_rules(macro_definition);
82 let macro_definition = 82 let expansion = expand(&rules, macro_invocation);
83 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
84
85 let source_file = ast::SourceFile::parse(macro_invocation).ok().unwrap();
86 let macro_invocation =
87 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
88
89 let (definition_tt, _) = ast_to_token_tree(&macro_definition.token_tree().unwrap()).unwrap();
90 let (invocation_tt, _) = ast_to_token_tree(&macro_invocation.token_tree().unwrap()).unwrap();
91 let rules = crate::MacroRules::parse(&definition_tt).unwrap();
92 let expansion = rules.expand(&invocation_tt).unwrap();
93 assert_eq!( 83 assert_eq!(
94 expansion.to_string(), 84 expansion.to_string(),
95 "impl From <Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree ::Leaf (it)}} \ 85 "impl From <Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree ::Leaf (it)}} \
@@ -97,140 +87,48 @@ impl_froms!(TokenTree: Leaf, Subtree);
97 ) 87 )
98} 88}
99 89
100pub(crate) fn create_rules(macro_definition: &str) -> MacroRules { 90#[test]
101 let source_file = ast::SourceFile::parse(macro_definition).ok().unwrap(); 91fn test_expr_order() {
102 let macro_definition = 92 let rules = create_rules(
103 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); 93 r#"
104 94 macro_rules! foo {
105 let (definition_tt, _) = ast_to_token_tree(&macro_definition.token_tree().unwrap()).unwrap(); 95 ($ i:expr) => {
106 crate::MacroRules::parse(&definition_tt).unwrap() 96 fn bar() { $ i * 2; }
107}
108
109pub(crate) fn expand(rules: &MacroRules, invocation: &str) -> tt::Subtree {
110 let source_file = ast::SourceFile::parse(invocation).ok().unwrap();
111 let macro_invocation =
112 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
113
114 let (invocation_tt, _) = ast_to_token_tree(&macro_invocation.token_tree().unwrap()).unwrap();
115
116 rules.expand(&invocation_tt).unwrap()
117}
118
119pub(crate) fn expand_to_items(rules: &MacroRules, invocation: &str) -> ast::MacroItems {
120 let expanded = expand(rules, invocation);
121 token_tree_to_items(&expanded).unwrap().tree()
122}
123
124#[allow(unused)]
125pub(crate) fn expand_to_stmts(rules: &MacroRules, invocation: &str) -> ast::MacroStmts {
126 let expanded = expand(rules, invocation);
127 token_tree_to_macro_stmts(&expanded).unwrap().tree()
128}
129
130pub(crate) fn expand_to_expr(rules: &MacroRules, invocation: &str) -> ast::Expr {
131 let expanded = expand(rules, invocation);
132 token_tree_to_expr(&expanded).unwrap().tree()
133}
134
135pub(crate) fn text_to_tokentree(text: &str) -> tt::Subtree {
136 // wrap the given text to a macro call
137 let wrapped = format!("wrap_macro!( {} )", text);
138 let wrapped = ast::SourceFile::parse(&wrapped);
139 let wrapped = wrapped.tree().syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
140 let mut wrapped = ast_to_token_tree(&wrapped).unwrap().0;
141 wrapped.delimiter = tt::Delimiter::None;
142
143 wrapped
144}
145
146pub(crate) enum MacroKind {
147 Items,
148 Stmts,
149}
150
151use ra_syntax::WalkEvent;
152
153pub fn debug_dump_ignore_spaces(node: &ra_syntax::SyntaxNode) -> String {
154 use std::fmt::Write;
155
156 let mut level = 0;
157 let mut buf = String::new();
158 macro_rules! indent {
159 () => {
160 for _ in 0..level {
161 buf.push_str(" ");
162 }
163 };
164 }
165
166 for event in node.preorder_with_tokens() {
167 match event {
168 WalkEvent::Enter(element) => {
169 match element {
170 NodeOrToken::Node(node) => {
171 indent!();
172 writeln!(buf, "{:?}", node.kind()).unwrap();
173 }
174 NodeOrToken::Token(token) => match token.kind() {
175 ra_syntax::SyntaxKind::WHITESPACE => {}
176 _ => {
177 indent!();
178 writeln!(buf, "{:?}", token.kind()).unwrap();
179 }
180 },
181 }
182 level += 1;
183 } 97 }
184 WalkEvent::Leave(_) => level -= 1,
185 } 98 }
186 } 99"#,
187
188 buf
189}
190
191pub(crate) fn assert_expansion(
192 kind: MacroKind,
193 rules: &MacroRules,
194 invocation: &str,
195 expected: &str,
196) -> tt::Subtree {
197 let expanded = expand(rules, invocation);
198 assert_eq!(expanded.to_string(), expected);
199
200 let expected = expected.replace("$crate", "C_C__C");
201
202 // wrap the given text to a macro call
203 let expected = text_to_tokentree(&expected);
204 let (expanded_tree, expected_tree) = match kind {
205 MacroKind::Items => {
206 let expanded_tree = token_tree_to_items(&expanded).unwrap().tree();
207 let expected_tree = token_tree_to_items(&expected).unwrap().tree();
208
209 (
210 debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(),
211 debug_dump_ignore_spaces(expected_tree.syntax()).trim().to_string(),
212 )
213 }
214
215 MacroKind::Stmts => {
216 let expanded_tree = token_tree_to_macro_stmts(&expanded).unwrap().tree();
217 let expected_tree = token_tree_to_macro_stmts(&expected).unwrap().tree();
218
219 (
220 debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(),
221 debug_dump_ignore_spaces(expected_tree.syntax()).trim().to_string(),
222 )
223 }
224 };
225
226 let expected_tree = expected_tree.replace("C_C__C", "$crate");
227 assert_eq!(
228 expanded_tree, expected_tree,
229 "\nleft:\n{}\nright:\n{}",
230 expanded_tree, expected_tree,
231 ); 100 );
101 let expanded = expand(&rules, "foo! { 1 + 1}");
102 let tree = token_tree_to_items(&expanded).unwrap().tree();
232 103
233 expanded 104 let dump = format!("{:#?}", tree.syntax());
105 assert_eq_text!(
106 dump.trim(),
107 r#"MACRO_ITEMS@[0; 15)
108 FN_DEF@[0; 15)
109 FN_KW@[0; 2) "fn"
110 NAME@[2; 5)
111 IDENT@[2; 5) "bar"
112 PARAM_LIST@[5; 7)
113 L_PAREN@[5; 6) "("
114 R_PAREN@[6; 7) ")"
115 BLOCK_EXPR@[7; 15)
116 BLOCK@[7; 15)
117 L_CURLY@[7; 8) "{"
118 EXPR_STMT@[8; 14)
119 BIN_EXPR@[8; 13)
120 BIN_EXPR@[8; 11)
121 LITERAL@[8; 9)
122 INT_NUMBER@[8; 9) "1"
123 PLUS@[9; 10) "+"
124 LITERAL@[10; 11)
125 INT_NUMBER@[10; 11) "1"
126 STAR@[11; 12) "*"
127 LITERAL@[12; 13)
128 INT_NUMBER@[12; 13) "2"
129 SEMI@[13; 14) ";"
130 R_CURLY@[14; 15) "}""#,
131 );
234} 132}
235 133
236#[test] 134#[test]
@@ -705,47 +603,6 @@ fn test_expr() {
705} 603}
706 604
707#[test] 605#[test]
708fn test_expr_order() {
709 let rules = create_rules(
710 r#"
711 macro_rules! foo {
712 ($ i:expr) => {
713 fn bar() { $ i * 2; }
714 }
715 }
716"#,
717 );
718 let dump = format!("{:#?}", expand_to_items(&rules, "foo! { 1 + 1 }").syntax());
719 assert_eq_text!(
720 dump.trim(),
721 r#"MACRO_ITEMS@[0; 15)
722 FN_DEF@[0; 15)
723 FN_KW@[0; 2) "fn"
724 NAME@[2; 5)
725 IDENT@[2; 5) "bar"
726 PARAM_LIST@[5; 7)
727 L_PAREN@[5; 6) "("
728 R_PAREN@[6; 7) ")"
729 BLOCK_EXPR@[7; 15)
730 BLOCK@[7; 15)
731 L_CURLY@[7; 8) "{"
732 EXPR_STMT@[8; 14)
733 BIN_EXPR@[8; 13)
734 BIN_EXPR@[8; 11)
735 LITERAL@[8; 9)
736 INT_NUMBER@[8; 9) "1"
737 PLUS@[9; 10) "+"
738 LITERAL@[10; 11)
739 INT_NUMBER@[10; 11) "1"
740 STAR@[11; 12) "*"
741 LITERAL@[12; 13)
742 INT_NUMBER@[12; 13) "2"
743 SEMI@[13; 14) ";"
744 R_CURLY@[14; 15) "}""#,
745 );
746}
747
748#[test]
749fn test_last_expr() { 606fn test_last_expr() {
750 let rules = create_rules( 607 let rules = create_rules(
751 r#" 608 r#"
@@ -1061,8 +918,11 @@ fn test_vec() {
1061 r#"{let mut v = Vec :: new () ; v . push (1u32) ; v . push (2) ; v}"#, 918 r#"{let mut v = Vec :: new () ; v . push (1u32) ; v . push (2) ; v}"#,
1062 ); 919 );
1063 920
921 let expansion = expand(&rules, r#"vec![1u32,2];"#);
922 let tree = token_tree_to_expr(&expansion).unwrap().tree();
923
1064 assert_eq!( 924 assert_eq!(
1065 format!("{:#?}", expand_to_expr(&rules, r#"vec![1u32,2];"#).syntax()).trim(), 925 format!("{:#?}", tree.syntax()).trim(),
1066 r#"BLOCK_EXPR@[0; 45) 926 r#"BLOCK_EXPR@[0; 45)
1067 BLOCK@[0; 45) 927 BLOCK@[0; 45)
1068 L_CURLY@[0; 1) "{" 928 L_CURLY@[0; 1) "{"
@@ -1502,3 +1362,117 @@ macro_rules! delegate_impl {
1502 1362
1503 assert_expansion(MacroKind::Items, &rules, r#"delegate_impl ! {[G , & 'a mut G , deref] pub trait Data : GraphBase {@ section type type NodeWeight ;}}"#, "impl <> Data for & \'a mut G where G : Data {}"); 1363 assert_expansion(MacroKind::Items, &rules, r#"delegate_impl ! {[G , & 'a mut G , deref] pub trait Data : GraphBase {@ section type type NodeWeight ;}}"#, "impl <> Data for & \'a mut G where G : Data {}");
1504} 1364}
1365
1366pub(crate) fn create_rules(macro_definition: &str) -> MacroRules {
1367 let source_file = ast::SourceFile::parse(macro_definition).ok().unwrap();
1368 let macro_definition =
1369 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
1370
1371 let (definition_tt, _) = ast_to_token_tree(&macro_definition.token_tree().unwrap()).unwrap();
1372 crate::MacroRules::parse(&definition_tt).unwrap()
1373}
1374
1375pub(crate) fn expand(rules: &MacroRules, invocation: &str) -> tt::Subtree {
1376 let source_file = ast::SourceFile::parse(invocation).ok().unwrap();
1377 let macro_invocation =
1378 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
1379
1380 let (invocation_tt, _) = ast_to_token_tree(&macro_invocation.token_tree().unwrap()).unwrap();
1381
1382 rules.expand(&invocation_tt).unwrap()
1383}
1384
1385pub(crate) enum MacroKind {
1386 Items,
1387 Stmts,
1388}
1389
1390pub(crate) fn assert_expansion(
1391 kind: MacroKind,
1392 rules: &MacroRules,
1393 invocation: &str,
1394 expected: &str,
1395) -> tt::Subtree {
1396 let expanded = expand(rules, invocation);
1397 assert_eq!(expanded.to_string(), expected);
1398
1399 let expected = expected.replace("$crate", "C_C__C");
1400
1401 // wrap the given text to a macro call
1402 let expected = {
1403 let wrapped = format!("wrap_macro!( {} )", expected);
1404 let wrapped = ast::SourceFile::parse(&wrapped);
1405 let wrapped = wrapped.tree().syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
1406 let mut wrapped = ast_to_token_tree(&wrapped).unwrap().0;
1407 wrapped.delimiter = tt::Delimiter::None;
1408 wrapped
1409 };
1410 let (expanded_tree, expected_tree) = match kind {
1411 MacroKind::Items => {
1412 let expanded_tree = token_tree_to_items(&expanded).unwrap().tree();
1413 let expected_tree = token_tree_to_items(&expected).unwrap().tree();
1414
1415 (
1416 debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(),
1417 debug_dump_ignore_spaces(expected_tree.syntax()).trim().to_string(),
1418 )
1419 }
1420
1421 MacroKind::Stmts => {
1422 let expanded_tree = token_tree_to_macro_stmts(&expanded).unwrap().tree();
1423 let expected_tree = token_tree_to_macro_stmts(&expected).unwrap().tree();
1424
1425 (
1426 debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(),
1427 debug_dump_ignore_spaces(expected_tree.syntax()).trim().to_string(),
1428 )
1429 }
1430 };
1431
1432 let expected_tree = expected_tree.replace("C_C__C", "$crate");
1433 assert_eq!(
1434 expanded_tree, expected_tree,
1435 "\nleft:\n{}\nright:\n{}",
1436 expanded_tree, expected_tree,
1437 );
1438
1439 expanded
1440}
1441
1442pub fn debug_dump_ignore_spaces(node: &ra_syntax::SyntaxNode) -> String {
1443 use std::fmt::Write;
1444
1445 let mut level = 0;
1446 let mut buf = String::new();
1447 macro_rules! indent {
1448 () => {
1449 for _ in 0..level {
1450 buf.push_str(" ");
1451 }
1452 };
1453 }
1454
1455 for event in node.preorder_with_tokens() {
1456 match event {
1457 WalkEvent::Enter(element) => {
1458 match element {
1459 NodeOrToken::Node(node) => {
1460 indent!();
1461 writeln!(buf, "{:?}", node.kind()).unwrap();
1462 }
1463 NodeOrToken::Token(token) => match token.kind() {
1464 ra_syntax::SyntaxKind::WHITESPACE => {}
1465 _ => {
1466 indent!();
1467 writeln!(buf, "{:?}", token.kind()).unwrap();
1468 }
1469 },
1470 }
1471 level += 1;
1472 }
1473 WalkEvent::Leave(_) => level -= 1,
1474 }
1475 }
1476
1477 buf
1478}