aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/handlers/early_return.rs2
-rw-r--r--crates/ra_assists/src/handlers/replace_if_let_with_match.rs37
-rw-r--r--crates/ra_assists/src/handlers/unwrap_block.rs164
-rw-r--r--crates/ra_parser/src/grammar/items.rs7
-rw-r--r--crates/ra_project_model/src/json_project.rs42
-rw-r--r--crates/ra_project_model/src/lib.rs6
-rw-r--r--crates/ra_syntax/src/ast/edit.rs13
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast40
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rs3
9 files changed, 180 insertions, 134 deletions
diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs
index 4cc75a7ce..dfade7432 100644
--- a/crates/ra_assists/src/handlers/early_return.rs
+++ b/crates/ra_assists/src/handlers/early_return.rs
@@ -154,7 +154,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
154 parent_block: &ast::BlockExpr, 154 parent_block: &ast::BlockExpr,
155 if_expr: &ast::IfExpr, 155 if_expr: &ast::IfExpr,
156 ) -> SyntaxNode { 156 ) -> SyntaxNode {
157 let then_block_items = then_block.dedent(IndentLevel::from(1)); 157 let then_block_items = then_block.dedent(IndentLevel(1));
158 let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); 158 let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
159 let end_of_then = 159 let end_of_then =
160 if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { 160 if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
diff --git a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
index e016f51c3..dfcd787de 100644
--- a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
+++ b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
@@ -51,6 +51,7 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext)
51 acc.add(AssistId("replace_if_let_with_match"), "Replace with match", target, move |edit| { 51 acc.add(AssistId("replace_if_let_with_match"), "Replace with match", target, move |edit| {
52 let match_expr = { 52 let match_expr = {
53 let then_arm = { 53 let then_arm = {
54 let then_block = then_block.reset_indent().indent(IndentLevel(1));
54 let then_expr = unwrap_trivial_block(then_block); 55 let then_expr = unwrap_trivial_block(then_block);
55 make::match_arm(vec![pat.clone()], then_expr) 56 make::match_arm(vec![pat.clone()], then_expr)
56 }; 57 };
@@ -64,8 +65,8 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext)
64 let else_expr = unwrap_trivial_block(else_block); 65 let else_expr = unwrap_trivial_block(else_block);
65 make::match_arm(vec![pattern], else_expr) 66 make::match_arm(vec![pattern], else_expr)
66 }; 67 };
67 make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm])) 68 let match_expr = make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm]));
68 .indent(IndentLevel::from_node(if_expr.syntax())) 69 match_expr.indent(IndentLevel::from_node(if_expr.syntax()))
69 }; 70 };
70 71
71 edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr); 72 edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr);
@@ -213,4 +214,36 @@ fn foo(x: Result<i32, ()>) {
213 "#, 214 "#,
214 ); 215 );
215 } 216 }
217
218 #[test]
219 fn nested_indent() {
220 check_assist(
221 replace_if_let_with_match,
222 r#"
223fn main() {
224 if true {
225 <|>if let Ok(rel_path) = path.strip_prefix(root_path) {
226 let rel_path = RelativePathBuf::from_path(rel_path).ok()?;
227 Some((*id, rel_path))
228 } else {
229 None
230 }
231 }
232}
233"#,
234 r#"
235fn main() {
236 if true {
237 match path.strip_prefix(root_path) {
238 Ok(rel_path) => {
239 let rel_path = RelativePathBuf::from_path(rel_path).ok()?;
240 Some((*id, rel_path))
241 }
242 _ => None,
243 }
244 }
245}
246"#,
247 )
248 }
216} 249}
diff --git a/crates/ra_assists/src/handlers/unwrap_block.rs b/crates/ra_assists/src/handlers/unwrap_block.rs
index 8440c7d0f..1fb13f481 100644
--- a/crates/ra_assists/src/handlers/unwrap_block.rs
+++ b/crates/ra_assists/src/handlers/unwrap_block.rs
@@ -1,7 +1,10 @@
1use ra_fmt::unwrap_trivial_block; 1use ra_fmt::unwrap_trivial_block;
2use ra_syntax::{ 2use ra_syntax::{
3 ast::{self, ElseBranch, Expr, LoopBodyOwner}, 3 ast::{
4 match_ast, AstNode, TextRange, T, 4 self,
5 edit::{AstNodeEdit, IndentLevel},
6 },
7 AstNode, TextRange, T,
5}; 8};
6 9
7use crate::{AssistContext, AssistId, Assists}; 10use crate::{AssistContext, AssistId, Assists};
@@ -24,94 +27,73 @@ use crate::{AssistContext, AssistId, Assists};
24// } 27// }
25// ``` 28// ```
26pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 29pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
27 let l_curly_token = ctx.find_token_at_offset(T!['{'])?;
28 let block = ast::BlockExpr::cast(l_curly_token.parent())?;
29 let parent = block.syntax().parent()?;
30 let assist_id = AssistId("unwrap_block"); 30 let assist_id = AssistId("unwrap_block");
31 let assist_label = "Unwrap block"; 31 let assist_label = "Unwrap block";
32 32
33 let (expr, expr_to_unwrap) = match_ast! { 33 let l_curly_token = ctx.find_token_at_offset(T!['{'])?;
34 match parent { 34 let mut block = ast::BlockExpr::cast(l_curly_token.parent())?;
35 ast::ForExpr(for_expr) => { 35 let mut parent = block.syntax().parent()?;
36 let block_expr = for_expr.loop_body()?; 36 if ast::MatchArm::can_cast(parent.kind()) {
37 let expr_to_unwrap = extract_expr(ctx.frange.range, block_expr)?; 37 parent = parent.ancestors().find(|it| ast::MatchExpr::can_cast(it.kind()))?
38 (ast::Expr::ForExpr(for_expr), expr_to_unwrap) 38 }
39 },
40 ast::WhileExpr(while_expr) => {
41 let block_expr = while_expr.loop_body()?;
42 let expr_to_unwrap = extract_expr(ctx.frange.range, block_expr)?;
43 (ast::Expr::WhileExpr(while_expr), expr_to_unwrap)
44 },
45 ast::LoopExpr(loop_expr) => {
46 let block_expr = loop_expr.loop_body()?;
47 let expr_to_unwrap = extract_expr(ctx.frange.range, block_expr)?;
48 (ast::Expr::LoopExpr(loop_expr), expr_to_unwrap)
49 },
50 ast::IfExpr(if_expr) => {
51 let mut resp = None;
52
53 let then_branch = if_expr.then_branch()?;
54 if then_branch.l_curly_token()?.text_range().contains_range(ctx.frange.range) {
55 if let Some(ancestor) = if_expr.syntax().parent().and_then(ast::IfExpr::cast) {
56 // For `else if` blocks
57 let ancestor_then_branch = ancestor.then_branch()?;
58 let l_curly_token = then_branch.l_curly_token()?;
59
60 let target = then_branch.syntax().text_range();
61 return acc.add(assist_id, assist_label, target, |edit| {
62 let range_to_del_else_if = TextRange::new(ancestor_then_branch.syntax().text_range().end(), l_curly_token.text_range().start());
63 let range_to_del_rest = TextRange::new(then_branch.syntax().text_range().end(), if_expr.syntax().text_range().end());
64
65 edit.delete(range_to_del_rest);
66 edit.delete(range_to_del_else_if);
67 edit.replace(target, update_expr_string(then_branch.to_string(), &[' ', '{']));
68 });
69 } else {
70 resp = Some((ast::Expr::IfExpr(if_expr.clone()), Expr::BlockExpr(then_branch)));
71 }
72 } else if let Some(else_branch) = if_expr.else_branch() {
73 match else_branch {
74 ElseBranch::Block(else_block) => {
75 let l_curly_token = else_block.l_curly_token()?;
76 if l_curly_token.text_range().contains_range(ctx.frange.range) {
77 let target = else_block.syntax().text_range();
78 return acc.add(assist_id, assist_label, target, |edit| {
79 let range_to_del = TextRange::new(then_branch.syntax().text_range().end(), l_curly_token.text_range().start());
80
81 edit.delete(range_to_del);
82 edit.replace(target, update_expr_string(else_block.to_string(), &[' ', '{']));
83 });
84 }
85 },
86 ElseBranch::IfExpr(_) => {},
87 }
88 }
89 39
90 resp? 40 let parent = ast::Expr::cast(parent)?;
91 }, 41
92 _ => return None, 42 match parent.clone() {
43 ast::Expr::ForExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::LoopExpr(_) => (),
44 ast::Expr::MatchExpr(_) => block = block.dedent(IndentLevel(1)),
45 ast::Expr::IfExpr(if_expr) => {
46 let then_branch = if_expr.then_branch()?;
47 if then_branch == block {
48 if let Some(ancestor) = if_expr.syntax().parent().and_then(ast::IfExpr::cast) {
49 // For `else if` blocks
50 let ancestor_then_branch = ancestor.then_branch()?;
51
52 let target = then_branch.syntax().text_range();
53 return acc.add(assist_id, assist_label, target, |edit| {
54 let range_to_del_else_if = TextRange::new(
55 ancestor_then_branch.syntax().text_range().end(),
56 l_curly_token.text_range().start(),
57 );
58 let range_to_del_rest = TextRange::new(
59 then_branch.syntax().text_range().end(),
60 if_expr.syntax().text_range().end(),
61 );
62
63 edit.delete(range_to_del_rest);
64 edit.delete(range_to_del_else_if);
65 edit.replace(
66 target,
67 update_expr_string(then_branch.to_string(), &[' ', '{']),
68 );
69 });
70 }
71 } else {
72 let target = block.syntax().text_range();
73 return acc.add(assist_id, assist_label, target, |edit| {
74 let range_to_del = TextRange::new(
75 then_branch.syntax().text_range().end(),
76 l_curly_token.text_range().start(),
77 );
78
79 edit.delete(range_to_del);
80 edit.replace(target, update_expr_string(block.to_string(), &[' ', '{']));
81 });
82 }
93 } 83 }
84 _ => return None,
94 }; 85 };
95 86
96 let target = expr_to_unwrap.syntax().text_range(); 87 let unwrapped = unwrap_trivial_block(block);
97 acc.add(assist_id, assist_label, target, |edit| { 88 let target = unwrapped.syntax().text_range();
98 edit.replace( 89 acc.add(assist_id, assist_label, target, |builder| {
99 expr.syntax().text_range(), 90 builder.replace(
100 update_expr_string(expr_to_unwrap.to_string(), &[' ', '{', '\n']), 91 parent.syntax().text_range(),
92 update_expr_string(unwrapped.to_string(), &[' ', '{', '\n']),
101 ); 93 );
102 }) 94 })
103} 95}
104 96
105fn extract_expr(cursor_range: TextRange, block: ast::BlockExpr) -> Option<ast::Expr> {
106 let cursor_in_range = block.l_curly_token()?.text_range().contains_range(cursor_range);
107
108 if cursor_in_range {
109 Some(unwrap_trivial_block(block))
110 } else {
111 None
112 }
113}
114
115fn update_expr_string(expr_str: String, trim_start_pat: &[char]) -> String { 97fn update_expr_string(expr_str: String, trim_start_pat: &[char]) -> String {
116 let expr_string = expr_str.trim_start_matches(trim_start_pat); 98 let expr_string = expr_str.trim_start_matches(trim_start_pat);
117 let mut expr_string_lines: Vec<&str> = expr_string.lines().collect(); 99 let mut expr_string_lines: Vec<&str> = expr_string.lines().collect();
@@ -490,6 +472,30 @@ mod tests {
490 } 472 }
491 473
492 #[test] 474 #[test]
475 fn unwrap_match_arm() {
476 check_assist(
477 unwrap_block,
478 r#"
479fn main() {
480 match rel_path {
481 Ok(rel_path) => {<|>
482 let rel_path = RelativePathBuf::from_path(rel_path).ok()?;
483 Some((*id, rel_path))
484 }
485 Err(_) => None,
486 }
487}
488"#,
489 r#"
490fn main() {
491 let rel_path = RelativePathBuf::from_path(rel_path).ok()?;
492 Some((*id, rel_path))
493}
494"#,
495 );
496 }
497
498 #[test]
493 fn simple_if_in_while_bad_cursor_position() { 499 fn simple_if_in_while_bad_cursor_position() {
494 check_assist_not_applicable( 500 check_assist_not_applicable(
495 unwrap_block, 501 unwrap_block,
diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs
index 9c14b954a..97642bc24 100644
--- a/crates/ra_parser/src/grammar/items.rs
+++ b/crates/ra_parser/src/grammar/items.rs
@@ -121,7 +121,12 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul
121 T![unsafe] => { 121 T![unsafe] => {
122 // test default_unsafe_impl 122 // test default_unsafe_impl
123 // default unsafe impl Foo {} 123 // default unsafe impl Foo {}
124 if p.nth(2) == T![impl] { 124
125 // test default_unsafe_fn
126 // impl T for Foo {
127 // default unsafe fn foo() {}
128 // }
129 if p.nth(2) == T![impl] || p.nth(2) == T![fn] {
125 p.bump_remap(T![default]); 130 p.bump_remap(T![default]);
126 p.bump(T![unsafe]); 131 p.bump(T![unsafe]);
127 has_mods = true; 132 has_mods = true;
diff --git a/crates/ra_project_model/src/json_project.rs b/crates/ra_project_model/src/json_project.rs
index 09c06fef9..ee2de4c25 100644
--- a/crates/ra_project_model/src/json_project.rs
+++ b/crates/ra_project_model/src/json_project.rs
@@ -2,7 +2,7 @@
2 2
3use std::path::PathBuf; 3use std::path::PathBuf;
4 4
5use rustc_hash::{FxHashMap, FxHashSet}; 5use rustc_hash::FxHashSet;
6use serde::Deserialize; 6use serde::Deserialize;
7 7
8/// Roots and crates that compose this Rust project. 8/// Roots and crates that compose this Rust project.
@@ -28,16 +28,9 @@ pub struct Crate {
28 pub(crate) edition: Edition, 28 pub(crate) edition: Edition,
29 pub(crate) deps: Vec<Dep>, 29 pub(crate) deps: Vec<Dep>,
30 30
31 // This is the preferred method of providing cfg options.
32 #[serde(default)] 31 #[serde(default)]
33 pub(crate) cfg: FxHashSet<String>, 32 pub(crate) cfg: FxHashSet<String>,
34 33
35 // These two are here for transition only.
36 #[serde(default)]
37 pub(crate) atom_cfgs: FxHashSet<String>,
38 #[serde(default)]
39 pub(crate) key_value_cfgs: FxHashMap<String, String>,
40
41 pub(crate) out_dir: Option<PathBuf>, 34 pub(crate) out_dir: Option<PathBuf>,
42 pub(crate) proc_macro_dylib_path: Option<PathBuf>, 35 pub(crate) proc_macro_dylib_path: Option<PathBuf>,
43} 36}
@@ -99,37 +92,4 @@ mod tests {
99 assert!(krate.cfg.contains(&"feature=feature_2".to_string())); 92 assert!(krate.cfg.contains(&"feature=feature_2".to_string()));
100 assert!(krate.cfg.contains(&"other=value".to_string())); 93 assert!(krate.cfg.contains(&"other=value".to_string()));
101 } 94 }
102
103 #[test]
104 fn test_crate_deserialization_old_json() {
105 let raw_json = json!( {
106 "crate_id": 2,
107 "root_module": "this/is/a/file/path.rs",
108 "deps": [
109 {
110 "crate": 1,
111 "name": "some_dep_crate"
112 },
113 ],
114 "edition": "2015",
115 "atom_cfgs": [
116 "atom_1",
117 "atom_2",
118 ],
119 "key_value_cfgs": {
120 "feature": "feature_1",
121 "feature": "feature_2",
122 "other": "value",
123 },
124 });
125
126 let krate: Crate = serde_json::from_value(raw_json).unwrap();
127
128 assert!(krate.atom_cfgs.contains(&"atom_1".to_string()));
129 assert!(krate.atom_cfgs.contains(&"atom_2".to_string()));
130 assert!(krate.key_value_cfgs.contains_key(&"feature".to_string()));
131 assert_eq!(krate.key_value_cfgs.get("feature"), Some(&"feature_2".to_string()));
132 assert!(krate.key_value_cfgs.contains_key(&"other".to_string()));
133 assert_eq!(krate.key_value_cfgs.get("other"), Some(&"value".to_string()));
134 }
135} 95}
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index fe03b509e..47fa34ddf 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -280,12 +280,6 @@ impl ProjectWorkspace {
280 } 280 }
281 } 281 }
282 } 282 }
283 for name in &krate.atom_cfgs {
284 opts.insert_atom(name.into());
285 }
286 for (key, value) in &krate.key_value_cfgs {
287 opts.insert_key_value(key.into(), value.into());
288 }
289 opts 283 opts
290 }; 284 };
291 285
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
index 29eb3fcb9..2ef173a03 100644
--- a/crates/ra_syntax/src/ast/edit.rs
+++ b/crates/ra_syntax/src/ast/edit.rs
@@ -579,12 +579,17 @@ pub trait AstNodeEdit: AstNode + Clone + Sized {
579 rewriter.rewrite_ast(self) 579 rewriter.rewrite_ast(self)
580 } 580 }
581 #[must_use] 581 #[must_use]
582 fn indent(&self, indent: IndentLevel) -> Self { 582 fn indent(&self, level: IndentLevel) -> Self {
583 Self::cast(indent.increase_indent(self.syntax().clone())).unwrap() 583 Self::cast(level.increase_indent(self.syntax().clone())).unwrap()
584 } 584 }
585 #[must_use] 585 #[must_use]
586 fn dedent(&self, indent: IndentLevel) -> Self { 586 fn dedent(&self, level: IndentLevel) -> Self {
587 Self::cast(indent.decrease_indent(self.syntax().clone())).unwrap() 587 Self::cast(level.decrease_indent(self.syntax().clone())).unwrap()
588 }
589 #[must_use]
590 fn reset_indent(&self) -> Self {
591 let level = IndentLevel::from_node(self.syntax());
592 self.dedent(level)
588 } 593 }
589} 594}
590 595
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast
new file mode 100644
index 000000000..adb6159f4
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast
@@ -0,0 +1,40 @@
1[email protected]
2 [email protected]
3 [email protected] "impl"
4 [email protected] " "
5 [email protected]
6 [email protected]
7 [email protected]
8 [email protected]
9 [email protected] "T"
10 [email protected] " "
11 [email protected] "for"
12 [email protected] " "
13 [email protected]
14 [email protected]
15 [email protected]
16 [email protected]
17 [email protected] "Foo"
18 [email protected] " "
19 [email protected]
20 [email protected] "{"
21 [email protected] "\n "
22 [email protected]
23 [email protected] "default"
24 [email protected] " "
25 [email protected] "unsafe"
26 [email protected] " "
27 [email protected] "fn"
28 [email protected] " "
29 [email protected]
30 [email protected] "foo"
31 [email protected]
32 [email protected] "("
33 [email protected] ")"
34 [email protected] " "
35 [email protected]
36 [email protected] "{"
37 [email protected] "}"
38 [email protected] "\n"
39 [email protected] "}"
40 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rs b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rs
new file mode 100644
index 000000000..12926cd8a
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rs
@@ -0,0 +1,3 @@
1impl T for Foo {
2 default unsafe fn foo() {}
3}