Repository: rust-analyzer/rust-analyzer
Pull request #5877 (2020-08-25 15:21:30)

Complete `pub` in fields

bors r+
🤖


Patch:
diff --git a/crates/ide/src/completion/complete_keyword.rs b/crates/ide/src/completion/complete_keyword.rs
index 95e4ff1ac6..53ba76e0e9 100644
--- a/crates/ide/src/completion/complete_keyword.rs
+++ b/crates/ide/src/completion/complete_keyword.rs
@@ -129,8 +129,9 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
             add_keyword(ctx, acc, "break", "break");
         }
     }
-    if ctx.has_item_list_or_source_file_parent || ctx.has_impl_parent {
-        add_keyword(ctx, acc, "pub", "pub ")
+    if ctx.has_item_list_or_source_file_parent || ctx.has_impl_parent | ctx.has_field_list_parent {
+        add_keyword(ctx, acc, "pub(crate)", "pub(crate) ");
+        add_keyword(ctx, acc, "pub", "pub ");
     }
 
     if !ctx.is_trivial_path {
@@ -227,6 +228,7 @@ mod tests {
                 kw impl
                 kw mod
                 kw pub
+                kw pub(crate)
                 kw static
                 kw struct
                 kw trait
@@ -364,6 +366,7 @@ fn quux() -> i32 {
                 kw const
                 kw fn
                 kw pub
+                kw pub(crate)
                 kw type
                 kw unsafe
             "#]],
@@ -524,4 +527,20 @@ pub mod future {
             "#]],
         )
     }
+
+    #[test]
+    fn before_field() {
+        check(
+            r#"
+struct Foo {
+    <|>
+    pub f: i32,
+}
+"#,
+            expect![[r#"
+                kw pub
+                kw pub(crate)
+            "#]],
+        )
+    }
 }
diff --git a/crates/ide/src/completion/complete_snippet.rs b/crates/ide/src/completion/complete_snippet.rs
index c3b03b199e..4837d29100 100644
--- a/crates/ide/src/completion/complete_snippet.rs
+++ b/crates/ide/src/completion/complete_snippet.rs
@@ -65,7 +65,6 @@ fn ${1:feature}() {
     .add_to(acc);
 
     snippet(ctx, cap, "macro_rules", "macro_rules! $1 {\n\t($2) => {\n\t\t$0\n\t};\n}").add_to(acc);
-    snippet(ctx, cap, "pub(crate)", "pub(crate) $0").add_to(acc);
 }
 
 #[cfg(test)]
@@ -107,7 +106,6 @@ mod tests {
 "#,
             expect![[r#"
                 sn macro_rules
-                sn pub(crate)
                 sn tfn (Test function)
                 sn tmod (Test module)
             "#]],
diff --git a/crates/ide/src/completion/completion_context.rs b/crates/ide/src/completion/completion_context.rs
index 5adac7ebcc..47355d5dcb 100644
--- a/crates/ide/src/completion/completion_context.rs
+++ b/crates/ide/src/completion/completion_context.rs
@@ -16,9 +16,10 @@ use crate::{
     call_info::ActiveParameter,
     completion::{
         patterns::{
-            has_bind_pat_parent, has_block_expr_parent, has_impl_as_prev_sibling, has_impl_parent,
-            has_item_list_or_source_file_parent, has_ref_parent, has_trait_as_prev_sibling,
-            has_trait_parent, if_is_prev, is_in_loop_body, is_match_arm, unsafe_is_prev,
+            has_bind_pat_parent, has_block_expr_parent, has_field_list_parent,
+            has_impl_as_prev_sibling, has_impl_parent, has_item_list_or_source_file_parent,
+            has_ref_parent, has_trait_as_prev_sibling, has_trait_parent, if_is_prev,
+            is_in_loop_body, is_match_arm, unsafe_is_prev,
         },
         CompletionConfig,
     },
@@ -84,6 +85,7 @@ pub(crate) struct CompletionContext<'a> {
     pub(super) in_loop_body: bool,
     pub(super) has_trait_parent: bool,
     pub(super) has_impl_parent: bool,
+    pub(super) has_field_list_parent: bool,
     pub(super) trait_as_prev_sibling: bool,
     pub(super) impl_as_prev_sibling: bool,
     pub(super) is_match_arm: bool,
@@ -157,6 +159,7 @@ impl<'a> CompletionContext<'a> {
             block_expr_parent: false,
             has_trait_parent: false,
             has_impl_parent: false,
+            has_field_list_parent: false,
             trait_as_prev_sibling: false,
             impl_as_prev_sibling: false,
             if_is_prev: false,
@@ -230,6 +233,7 @@ impl<'a> CompletionContext<'a> {
         self.in_loop_body = is_in_loop_body(syntax_element.clone());
         self.has_trait_parent = has_trait_parent(syntax_element.clone());
         self.has_impl_parent = has_impl_parent(syntax_element.clone());
+        self.has_field_list_parent = has_field_list_parent(syntax_element.clone());
         self.impl_as_prev_sibling = has_impl_as_prev_sibling(syntax_element.clone());
         self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone());
         self.is_match_arm = is_match_arm(syntax_element.clone());
diff --git a/crates/ide/src/completion/patterns.rs b/crates/ide/src/completion/patterns.rs
index ffc97c076a..c6ae589db0 100644
--- a/crates/ide/src/completion/patterns.rs
+++ b/crates/ide/src/completion/patterns.rs
@@ -34,6 +34,14 @@ pub(crate) fn has_impl_parent(element: SyntaxElement) -> bool {
 fn test_has_impl_parent() {
     check_pattern_is_applicable(r"impl A { f<|> }", has_impl_parent);
 }
+pub(crate) fn has_field_list_parent(element: SyntaxElement) -> bool {
+    not_same_range_ancestor(element).filter(|it| it.kind() == RECORD_FIELD_LIST).is_some()
+}
+#[test]
+fn test_has_field_list_parent() {
+    check_pattern_is_applicable(r"struct Foo { f<|> }", has_field_list_parent);
+    check_pattern_is_applicable(r"struct Foo { f<|> pub f: i32}", has_field_list_parent);
+}
 
 pub(crate) fn has_block_expr_parent(element: SyntaxElement) -> bool {
     not_same_range_ancestor(element).filter(|it| it.kind() == BLOCK_EXPR).is_some()
diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs
index c876545f44..9d00eb9b90 100644
--- a/crates/parser/src/grammar/types.rs
+++ b/crates/parser/src/grammar/types.rs
@@ -18,7 +18,14 @@ pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(token_set![
     T![dyn],
 ]);
 
-const TYPE_RECOVERY_SET: TokenSet = token_set![R_PAREN, COMMA, L_DOLLAR];
+const TYPE_RECOVERY_SET: TokenSet = token_set![
+    T![')'],
+    T![,],
+    L_DOLLAR,
+    // test_err struct_field_recover
+    // struct S { f pub g: () }
+    T![pub],
+];
 
 pub(crate) fn type_(p: &mut Parser) {
     type_with_bounds_cond(p, true);


Test patch:
diff --git a/crates/syntax/test_data/parser/inline/err/0014_struct_field_recover.rast b/crates/syntax/test_data/parser/inline/err/0014_struct_field_recover.rast
new file mode 100644
index 0000000000..ba8e50993d
--- /dev/null
+++ b/crates/syntax/test_data/parser/inline/err/0014_struct_field_recover.rast
@@ -0,0 +1,31 @@
+SOURCE_FILE@0..25
+  STRUCT@0..24
+    STRUCT_KW@0..6 "struct"
+    WHITESPACE@6..7 " "
+    NAME@7..8
+      IDENT@7..8 "S"
+    WHITESPACE@8..9 " "
+    RECORD_FIELD_LIST@9..24
+      L_CURLY@9..10 "{"
+      WHITESPACE@10..11 " "
+      RECORD_FIELD@11..12
+        NAME@11..12
+          IDENT@11..12 "f"
+      WHITESPACE@12..13 " "
+      RECORD_FIELD@13..22
+        VISIBILITY@13..16
+          PUB_KW@13..16 "pub"
+        WHITESPACE@16..17 " "
+        NAME@17..18
+          IDENT@17..18 "g"
+        COLON@18..19 ":"
+        WHITESPACE@19..20 " "
+        TUPLE_TYPE@20..22
+          L_PAREN@20..21 "("
+          R_PAREN@21..22 ")"
+      WHITESPACE@22..23 " "
+      R_CURLY@23..24 "}"
+  WHITESPACE@24..25 "\n"
+error 12..12: expected COLON
+error 12..12: expected type
+error 12..12: expected COMMA
diff --git a/crates/syntax/test_data/parser/inline/err/0014_struct_field_recover.rs b/crates/syntax/test_data/parser/inline/err/0014_struct_field_recover.rs
new file mode 100644
index 0000000000..da32227adc
--- /dev/null
+++ b/crates/syntax/test_data/parser/inline/err/0014_struct_field_recover.rs
@@ -0,0 +1,1 @@
+struct S { f pub g: () }