Repository: rust-analyzer/rust-analyzer
Pull request #4811 (2020-06-09 10:12:34)

Unwrap block works with match arms


bors r+
🤖


Patch:
diff --git a/crates/ra_assists/src/handlers/unwrap_block.rs b/crates/ra_assists/src/handlers/unwrap_block.rs
index c48ecaae8a..1fb13f4814 100644
--- a/crates/ra_assists/src/handlers/unwrap_block.rs
+++ b/crates/ra_assists/src/handlers/unwrap_block.rs
@@ -1,5 +1,11 @@
 use ra_fmt::unwrap_trivial_block;
-use ra_syntax::{ast, AstNode, TextRange, T};
+use ra_syntax::{
+    ast::{
+        self,
+        edit::{AstNodeEdit, IndentLevel},
+    },
+    AstNode, TextRange, T,
+};
 
 use crate::{AssistContext, AssistId, Assists};
 
@@ -21,15 +27,21 @@ use crate::{AssistContext, AssistId, Assists};
 // }
 // ```
 pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
-    let l_curly_token = ctx.find_token_at_offset(T!['{'])?;
-    let block = ast::BlockExpr::cast(l_curly_token.parent())?;
-    let parent = block.syntax().parent()?;
     let assist_id = AssistId("unwrap_block");
     let assist_label = "Unwrap block";
+
+    let l_curly_token = ctx.find_token_at_offset(T!['{'])?;
+    let mut block = ast::BlockExpr::cast(l_curly_token.parent())?;
+    let mut parent = block.syntax().parent()?;
+    if ast::MatchArm::can_cast(parent.kind()) {
+        parent = parent.ancestors().find(|it| ast::MatchExpr::can_cast(it.kind()))?
+    }
+
     let parent = ast::Expr::cast(parent)?;
 
     match parent.clone() {
         ast::Expr::ForExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::LoopExpr(_) => (),
+        ast::Expr::MatchExpr(_) => block = block.dedent(IndentLevel(1)),
         ast::Expr::IfExpr(if_expr) => {
             let then_branch = if_expr.then_branch()?;
             if then_branch == block {
@@ -459,6 +471,30 @@ mod tests {
         );
     }
 
+    #[test]
+    fn unwrap_match_arm() {
+        check_assist(
+            unwrap_block,
+            r#"
+fn main() {
+    match rel_path {
+        Ok(rel_path) => {<|>
+            let rel_path = RelativePathBuf::from_path(rel_path).ok()?;
+            Some((*id, rel_path))
+        }
+        Err(_) => None,
+    }
+}
+"#,
+            r#"
+fn main() {
+    let rel_path = RelativePathBuf::from_path(rel_path).ok()?;
+    Some((*id, rel_path))
+}
+"#,
+        );
+    }
+
     #[test]
     fn simple_if_in_while_bad_cursor_position() {
         check_assist_not_applicable(
diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs
index 97642bc244..9c14b954af 100644
--- a/crates/ra_parser/src/grammar/items.rs
+++ b/crates/ra_parser/src/grammar/items.rs
@@ -121,12 +121,7 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul
             T![unsafe] => {
                 // test default_unsafe_impl
                 // default unsafe impl Foo {}
-
-                // test default_unsafe_fn
-                // impl T for Foo {
-                //     default unsafe fn foo() {}
-                // }
-                if p.nth(2) == T![impl] || p.nth(2) == T![fn] {
+                if p.nth(2) == T![impl] {
                     p.bump_remap(T![default]);
                     p.bump(T![unsafe]);
                     has_mods = true;
diff --git a/crates/ra_project_model/src/json_project.rs b/crates/ra_project_model/src/json_project.rs
index ee2de4c256..09c06fef93 100644
--- a/crates/ra_project_model/src/json_project.rs
+++ b/crates/ra_project_model/src/json_project.rs
@@ -2,7 +2,7 @@
 
 use std::path::PathBuf;
 
-use rustc_hash::FxHashSet;
+use rustc_hash::{FxHashMap, FxHashSet};
 use serde::Deserialize;
 
 /// Roots and crates that compose this Rust project.
@@ -28,9 +28,16 @@ pub struct Crate {
     pub(crate) edition: Edition,
     pub(crate) deps: Vec<Dep>,
 
+    // This is the preferred method of providing cfg options.
     #[serde(default)]
     pub(crate) cfg: FxHashSet<String>,
 
+    // These two are here for transition only.
+    #[serde(default)]
+    pub(crate) atom_cfgs: FxHashSet<String>,
+    #[serde(default)]
+    pub(crate) key_value_cfgs: FxHashMap<String, String>,
+
     pub(crate) out_dir: Option<PathBuf>,
     pub(crate) proc_macro_dylib_path: Option<PathBuf>,
 }
@@ -92,4 +99,37 @@ mod tests {
         assert!(krate.cfg.contains(&"feature=feature_2".to_string()));
         assert!(krate.cfg.contains(&"other=value".to_string()));
     }
+
+    #[test]
+    fn test_crate_deserialization_old_json() {
+        let raw_json = json!(    {
+           "crate_id": 2,
+           "root_module": "this/is/a/file/path.rs",
+           "deps": [
+             {
+               "crate": 1,
+               "name": "some_dep_crate"
+             },
+           ],
+           "edition": "2015",
+           "atom_cfgs": [
+             "atom_1",
+             "atom_2",
+           ],
+           "key_value_cfgs": {
+             "feature": "feature_1",
+             "feature": "feature_2",
+             "other": "value",
+           },
+        });
+
+        let krate: Crate = serde_json::from_value(raw_json).unwrap();
+
+        assert!(krate.atom_cfgs.contains(&"atom_1".to_string()));
+        assert!(krate.atom_cfgs.contains(&"atom_2".to_string()));
+        assert!(krate.key_value_cfgs.contains_key(&"feature".to_string()));
+        assert_eq!(krate.key_value_cfgs.get("feature"), Some(&"feature_2".to_string()));
+        assert!(krate.key_value_cfgs.contains_key(&"other".to_string()));
+        assert_eq!(krate.key_value_cfgs.get("other"), Some(&"value".to_string()));
+    }
 }
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index 47fa34ddfb..fe03b509e4 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -280,6 +280,12 @@ impl ProjectWorkspace {
                                     }
                                 }
                             }
+                            for name in &krate.atom_cfgs {
+                                opts.insert_atom(name.into());
+                            }
+                            for (key, value) in &krate.key_value_cfgs {
+                                opts.insert_key_value(key.into(), value.into());
+                            }
                             opts
                         };
 


Test patch:
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
deleted file mode 100644
index adb6159f47..0000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast
+++ /dev/null
@@ -1,40 +0,0 @@
-SOURCE_FILE@0..50
-  IMPL_DEF@0..49
-    IMPL_KW@0..4 "impl"
-    WHITESPACE@4..5 " "
-    PATH_TYPE@5..6
-      PATH@5..6
-        PATH_SEGMENT@5..6
-          NAME_REF@5..6
-            IDENT@5..6 "T"
-    WHITESPACE@6..7 " "
-    FOR_KW@7..10 "for"
-    WHITESPACE@10..11 " "
-    PATH_TYPE@11..14
-      PATH@11..14
-        PATH_SEGMENT@11..14
-          NAME_REF@11..14
-            IDENT@11..14 "Foo"
-    WHITESPACE@14..15 " "
-    ITEM_LIST@15..49
-      L_CURLY@15..16 "{"
-      WHITESPACE@16..21 "\n    "
-      FN_DEF@21..47
-        DEFAULT_KW@21..28 "default"
-        WHITESPACE@28..29 " "
-        UNSAFE_KW@29..35 "unsafe"
-        WHITESPACE@35..36 " "
-        FN_KW@36..38 "fn"
-        WHITESPACE@38..39 " "
-        NAME@39..42
-          IDENT@39..42 "foo"
-        PARAM_LIST@42..44
-          L_PAREN@42..43 "("
-          R_PAREN@43..44 ")"
-        WHITESPACE@44..45 " "
-        BLOCK_EXPR@45..47
-          L_CURLY@45..46 "{"
-          R_CURLY@46..47 "}"
-      WHITESPACE@47..48 "\n"
-      R_CURLY@48..49 "}"
-  WHITESPACE@49..50 "\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
deleted file mode 100644
index 12926cd8a1..0000000000
--- a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-impl T for Foo {
-    default unsafe fn foo() {}
-}