about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2022-06-03 15:41:51 +0200
committerLukas Wirth <lukastw97@gmail.com>2022-06-03 15:42:28 +0200
commitc5dcc77b40a19dada837e50374d1851754f5eb2a (patch)
tree7c46792f59c6555456a9db89ec63eba0e406f437
parent519ac81b578fcda24f8f71eb99f287bce829bb71 (diff)
downloadrust-c5dcc77b40a19dada837e50374d1851754f5eb2a.tar.gz
rust-c5dcc77b40a19dada837e50374d1851754f5eb2a.zip
Fix visibility mods not being completed for field defs
-rw-r--r--crates/ide-completion/src/completions.rs1
-rw-r--r--crates/ide-completion/src/completions/field.rs53
-rw-r--r--crates/ide-completion/src/completions/flyimport.rs9
-rw-r--r--crates/ide-completion/src/completions/type.rs9
-rw-r--r--crates/ide-completion/src/context.rs10
-rw-r--r--crates/ide-completion/src/lib.rs1
-rw-r--r--crates/ide-completion/src/render.rs2
-rw-r--r--crates/ide-completion/src/render/function.rs2
-rw-r--r--crates/ide-completion/src/tests/item.rs7
-rw-r--r--crates/ide-completion/src/tests/type_pos.rs6
10 files changed, 85 insertions, 15 deletions
diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index 931b92dec3f..d020b49cde5 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -4,6 +4,7 @@ pub(crate) mod attribute;
 pub(crate) mod dot;
 pub(crate) mod expr;
 pub(crate) mod extern_abi;
+pub(crate) mod field;
 pub(crate) mod flyimport;
 pub(crate) mod fn_param;
 pub(crate) mod format_string;
diff --git a/crates/ide-completion/src/completions/field.rs b/crates/ide-completion/src/completions/field.rs
new file mode 100644
index 00000000000..d81e48cbabd
--- /dev/null
+++ b/crates/ide-completion/src/completions/field.rs
@@ -0,0 +1,53 @@
+//! Completion of field list position.
+
+use crate::{
+    context::{IdentContext, NameContext, NameKind, NameRefContext, PathCompletionCtx, PathKind},
+    CompletionContext, CompletionItem, CompletionItemKind, Completions,
+};
+
+pub(crate) fn complete_field_list(acc: &mut Completions, ctx: &CompletionContext) {
+    match &ctx.ident_ctx {
+        IdentContext::Name(NameContext { kind: NameKind::RecordField, .. })
+        | IdentContext::NameRef(NameRefContext {
+            path_ctx:
+                Some(PathCompletionCtx {
+                    has_macro_bang: false,
+                    is_absolute_path: false,
+                    qualifier: None,
+                    parent: None,
+                    kind: PathKind::Type { in_tuple_struct: true },
+                    has_type_args: false,
+                    ..
+                }),
+            ..
+        }) => {
+            if ctx.qualifier_ctx.vis_node.is_none() {
+                let mut add_keyword = |kw, snippet| add_keyword(acc, ctx, kw, snippet);
+                add_keyword("pub(crate)", "pub(crate)");
+                add_keyword("pub(super)", "pub(super)");
+                add_keyword("pub", "pub");
+            }
+        }
+        _ => return,
+    }
+}
+
+pub(super) fn add_keyword(acc: &mut Completions, ctx: &CompletionContext, kw: &str, snippet: &str) {
+    let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw);
+
+    match ctx.config.snippet_cap {
+        Some(cap) => {
+            if snippet.ends_with('}') && ctx.incomplete_let {
+                // complete block expression snippets with a trailing semicolon, if inside an incomplete let
+                cov_mark::hit!(let_semi);
+                item.insert_snippet(cap, format!("{};", snippet));
+            } else {
+                item.insert_snippet(cap, snippet);
+            }
+        }
+        None => {
+            item.insert_text(if snippet.contains('$') { kw } else { snippet });
+        }
+    };
+    item.add_to(acc);
+}
diff --git a/crates/ide-completion/src/completions/flyimport.rs b/crates/ide-completion/src/completions/flyimport.rs
index 873db300b84..c3bf298bc6e 100644
--- a/crates/ide-completion/src/completions/flyimport.rs
+++ b/crates/ide-completion/src/completions/flyimport.rs
@@ -160,7 +160,10 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
             (_, ItemInNs::Types(hir::ModuleDef::Module(_))) => true,
             // and so are macros(except for attributes)
             (
-                PathKind::Expr { .. } | PathKind::Type | PathKind::Item { .. } | PathKind::Pat,
+                PathKind::Expr { .. }
+                | PathKind::Type { .. }
+                | PathKind::Item { .. }
+                | PathKind::Pat,
                 ItemInNs::Macros(mac),
             ) => mac.is_fn_like(ctx.db),
             (PathKind::Item { .. }, _) => true,
@@ -170,14 +173,14 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
             (PathKind::Pat, ItemInNs::Types(_)) => true,
             (PathKind::Pat, ItemInNs::Values(def)) => matches!(def, hir::ModuleDef::Const(_)),
 
-            (PathKind::Type, ItemInNs::Types(ty)) => {
+            (PathKind::Type { .. }, ItemInNs::Types(ty)) => {
                 if matches!(ctx.completion_location, Some(ImmediateLocation::TypeBound)) {
                     matches!(ty, ModuleDef::Trait(_))
                 } else {
                     true
                 }
             }
-            (PathKind::Type, ItemInNs::Values(_)) => false,
+            (PathKind::Type { .. }, ItemInNs::Values(_)) => false,
 
             (PathKind::Attr { .. }, ItemInNs::Macros(mac)) => mac.is_attr(ctx.db),
             (PathKind::Attr { .. }, _) => false,
diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs
index 91414c8bf6a..bc8c070c14d 100644
--- a/crates/ide-completion/src/completions/type.rs
+++ b/crates/ide-completion/src/completions/type.rs
@@ -18,9 +18,12 @@ pub(crate) fn complete_type_path(acc: &mut Completions, ctx: &CompletionContext)
     }
 
     let (&is_absolute_path, qualifier) = match ctx.path_context() {
-        Some(PathCompletionCtx { kind: PathKind::Type, is_absolute_path, qualifier, .. }) => {
-            (is_absolute_path, qualifier)
-        }
+        Some(PathCompletionCtx {
+            kind: PathKind::Type { .. },
+            is_absolute_path,
+            qualifier,
+            ..
+        }) => (is_absolute_path, qualifier),
         _ => return,
     };
 
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 4eac86162a3..a4b38d3f246 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -49,7 +49,9 @@ pub(super) enum PathKind {
         in_block_expr: bool,
         in_loop_body: bool,
     },
-    Type,
+    Type {
+        in_tuple_struct: bool,
+    },
     Attr {
         kind: AttrKind,
         annotated_item_kind: Option<SyntaxKind>,
@@ -1222,7 +1224,9 @@ impl<'a> CompletionContext<'a> {
             // using Option<Option<PathKind>> as extra controlflow
             let kind = match_ast! {
                 match it {
-                    ast::PathType(_) => Some(PathKind::Type),
+                    ast::PathType(it) => Some(PathKind::Type {
+                        in_tuple_struct: it.syntax().parent().map_or(false, |it| ast::TupleField::can_cast(it.kind()))
+                    }),
                     ast::PathExpr(it) => {
                         if let Some(p) = it.syntax().parent() {
                             if ast::ExprStmt::can_cast(p.kind()) {
@@ -1262,7 +1266,7 @@ impl<'a> CompletionContext<'a> {
                         let parent = it.syntax().parent();
                         match parent.as_ref().map(|it| it.kind()) {
                             Some(SyntaxKind::MACRO_PAT) => Some(PathKind::Pat),
-                            Some(SyntaxKind::MACRO_TYPE) => Some(PathKind::Type),
+                            Some(SyntaxKind::MACRO_TYPE) => Some(PathKind::Type { in_tuple_struct: false }),
                             Some(SyntaxKind::ITEM_LIST) => Some(PathKind::Item { kind: ItemListKind::Module }),
                             Some(SyntaxKind::ASSOC_ITEM_LIST) => Some(PathKind::Item { kind: match parent.and_then(|it| it.parent()) {
                                 Some(it) => match_ast! {
diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs
index 9659efad619..c100dd63eac 100644
--- a/crates/ide-completion/src/lib.rs
+++ b/crates/ide-completion/src/lib.rs
@@ -158,6 +158,7 @@ pub fn completions(
             completions::dot::complete_dot(acc, ctx);
             completions::expr::complete_expr_path(acc, ctx);
             completions::extern_abi::complete_extern_abi(acc, ctx);
+            completions::field::complete_field_list(acc, ctx);
             completions::flyimport::import_on_the_fly(acc, ctx);
             completions::fn_param::complete_fn_param(acc, ctx);
             completions::format_string::format_string(acc, ctx);
diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs
index d51bc517d65..ca2b3ad3435 100644
--- a/crates/ide-completion/src/render.rs
+++ b/crates/ide-completion/src/render.rs
@@ -286,7 +286,7 @@ fn render_resolution_simple_(
     // Add `<>` for generic types
     let type_path_no_ty_args = matches!(
         ctx.completion.path_context(),
-        Some(PathCompletionCtx { kind: PathKind::Type, has_type_args: false, .. })
+        Some(PathCompletionCtx { kind: PathKind::Type { .. }, has_type_args: false, .. })
     ) && ctx.completion.config.callable.is_some();
     if type_path_no_ty_args {
         if let Some(cap) = ctx.snippet_cap() {
diff --git a/crates/ide-completion/src/render/function.rs b/crates/ide-completion/src/render/function.rs
index 5e1fbfa4a21..0be51b0e3ff 100644
--- a/crates/ide-completion/src/render/function.rs
+++ b/crates/ide-completion/src/render/function.rs
@@ -202,7 +202,7 @@ fn should_add_parens(ctx: &CompletionContext) -> bool {
         Some(PathCompletionCtx { kind: PathKind::Expr { .. }, has_call_parens: true, .. }) => {
             return false
         }
-        Some(PathCompletionCtx { kind: PathKind::Use | PathKind::Type, .. }) => {
+        Some(PathCompletionCtx { kind: PathKind::Use | PathKind::Type { .. }, .. }) => {
             cov_mark::hit!(no_parens_in_use_item);
             return false;
         }
diff --git a/crates/ide-completion/src/tests/item.rs b/crates/ide-completion/src/tests/item.rs
index d1f5d2a33c0..9e50e00ab73 100644
--- a/crates/ide-completion/src/tests/item.rs
+++ b/crates/ide-completion/src/tests/item.rs
@@ -100,7 +100,6 @@ fn after_fn_name() {
 
 #[test]
 fn before_record_field() {
-    // FIXME: This should emit visibility qualifiers
     check(
         r#"
 struct Foo {
@@ -108,6 +107,10 @@ struct Foo {
     pub f: i32,
 }
 "#,
-        expect![[r#""#]],
+        expect![[r#"
+            kw pub
+            kw pub(crate)
+            kw pub(super)
+        "#]],
     )
 }
diff --git a/crates/ide-completion/src/tests/type_pos.rs b/crates/ide-completion/src/tests/type_pos.rs
index 76942110f88..1e5e86eef59 100644
--- a/crates/ide-completion/src/tests/type_pos.rs
+++ b/crates/ide-completion/src/tests/type_pos.rs
@@ -38,14 +38,13 @@ struct Foo<'lt, T, const C: usize> {
 
 #[test]
 fn tuple_struct_field() {
-    // FIXME: This should emit visibility qualifiers
     check(
         r#"
 struct Foo<'lt, T, const C: usize>(f$0);
 "#,
         expect![[r#"
             en Enum
-            ma makro!(…) macro_rules! makro
+            ma makro!(…)  macro_rules! makro
             md module
             sp Self
             st Foo<…>
@@ -57,6 +56,9 @@ struct Foo<'lt, T, const C: usize>(f$0);
             un Union
             bt u32
             kw crate::
+            kw pub
+            kw pub(crate)
+            kw pub(super)
             kw self::
             kw super::
         "#]],