mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-08-30 23:27:24 +00:00
Fix visibility mods not being completed for field defs
This commit is contained in:
parent
519ac81b57
commit
c5dcc77b40
10 changed files with 85 additions and 15 deletions
|
@ -4,6 +4,7 @@ pub(crate) mod attribute;
|
||||||
pub(crate) mod dot;
|
pub(crate) mod dot;
|
||||||
pub(crate) mod expr;
|
pub(crate) mod expr;
|
||||||
pub(crate) mod extern_abi;
|
pub(crate) mod extern_abi;
|
||||||
|
pub(crate) mod field;
|
||||||
pub(crate) mod flyimport;
|
pub(crate) mod flyimport;
|
||||||
pub(crate) mod fn_param;
|
pub(crate) mod fn_param;
|
||||||
pub(crate) mod format_string;
|
pub(crate) mod format_string;
|
||||||
|
|
53
crates/ide-completion/src/completions/field.rs
Normal file
53
crates/ide-completion/src/completions/field.rs
Normal file
|
@ -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);
|
||||||
|
}
|
|
@ -160,7 +160,10 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
|
||||||
(_, ItemInNs::Types(hir::ModuleDef::Module(_))) => true,
|
(_, ItemInNs::Types(hir::ModuleDef::Module(_))) => true,
|
||||||
// and so are macros(except for attributes)
|
// 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),
|
ItemInNs::Macros(mac),
|
||||||
) => mac.is_fn_like(ctx.db),
|
) => mac.is_fn_like(ctx.db),
|
||||||
(PathKind::Item { .. }, _) => true,
|
(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::Types(_)) => true,
|
||||||
(PathKind::Pat, ItemInNs::Values(def)) => matches!(def, hir::ModuleDef::Const(_)),
|
(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)) {
|
if matches!(ctx.completion_location, Some(ImmediateLocation::TypeBound)) {
|
||||||
matches!(ty, ModuleDef::Trait(_))
|
matches!(ty, ModuleDef::Trait(_))
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(PathKind::Type, ItemInNs::Values(_)) => false,
|
(PathKind::Type { .. }, ItemInNs::Values(_)) => false,
|
||||||
|
|
||||||
(PathKind::Attr { .. }, ItemInNs::Macros(mac)) => mac.is_attr(ctx.db),
|
(PathKind::Attr { .. }, ItemInNs::Macros(mac)) => mac.is_attr(ctx.db),
|
||||||
(PathKind::Attr { .. }, _) => false,
|
(PathKind::Attr { .. }, _) => false,
|
||||||
|
|
|
@ -18,9 +18,12 @@ pub(crate) fn complete_type_path(acc: &mut Completions, ctx: &CompletionContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
let (&is_absolute_path, qualifier) = match ctx.path_context() {
|
let (&is_absolute_path, qualifier) = match ctx.path_context() {
|
||||||
Some(PathCompletionCtx { kind: PathKind::Type, is_absolute_path, qualifier, .. }) => {
|
Some(PathCompletionCtx {
|
||||||
(is_absolute_path, qualifier)
|
kind: PathKind::Type { .. },
|
||||||
}
|
is_absolute_path,
|
||||||
|
qualifier,
|
||||||
|
..
|
||||||
|
}) => (is_absolute_path, qualifier),
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,9 @@ pub(super) enum PathKind {
|
||||||
in_block_expr: bool,
|
in_block_expr: bool,
|
||||||
in_loop_body: bool,
|
in_loop_body: bool,
|
||||||
},
|
},
|
||||||
Type,
|
Type {
|
||||||
|
in_tuple_struct: bool,
|
||||||
|
},
|
||||||
Attr {
|
Attr {
|
||||||
kind: AttrKind,
|
kind: AttrKind,
|
||||||
annotated_item_kind: Option<SyntaxKind>,
|
annotated_item_kind: Option<SyntaxKind>,
|
||||||
|
@ -1222,7 +1224,9 @@ impl<'a> CompletionContext<'a> {
|
||||||
// using Option<Option<PathKind>> as extra controlflow
|
// using Option<Option<PathKind>> as extra controlflow
|
||||||
let kind = match_ast! {
|
let kind = match_ast! {
|
||||||
match it {
|
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) => {
|
ast::PathExpr(it) => {
|
||||||
if let Some(p) = it.syntax().parent() {
|
if let Some(p) = it.syntax().parent() {
|
||||||
if ast::ExprStmt::can_cast(p.kind()) {
|
if ast::ExprStmt::can_cast(p.kind()) {
|
||||||
|
@ -1262,7 +1266,7 @@ impl<'a> CompletionContext<'a> {
|
||||||
let parent = it.syntax().parent();
|
let parent = it.syntax().parent();
|
||||||
match parent.as_ref().map(|it| it.kind()) {
|
match parent.as_ref().map(|it| it.kind()) {
|
||||||
Some(SyntaxKind::MACRO_PAT) => Some(PathKind::Pat),
|
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::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(SyntaxKind::ASSOC_ITEM_LIST) => Some(PathKind::Item { kind: match parent.and_then(|it| it.parent()) {
|
||||||
Some(it) => match_ast! {
|
Some(it) => match_ast! {
|
||||||
|
|
|
@ -158,6 +158,7 @@ pub fn completions(
|
||||||
completions::dot::complete_dot(acc, ctx);
|
completions::dot::complete_dot(acc, ctx);
|
||||||
completions::expr::complete_expr_path(acc, ctx);
|
completions::expr::complete_expr_path(acc, ctx);
|
||||||
completions::extern_abi::complete_extern_abi(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::flyimport::import_on_the_fly(acc, ctx);
|
||||||
completions::fn_param::complete_fn_param(acc, ctx);
|
completions::fn_param::complete_fn_param(acc, ctx);
|
||||||
completions::format_string::format_string(acc, ctx);
|
completions::format_string::format_string(acc, ctx);
|
||||||
|
|
|
@ -286,7 +286,7 @@ fn render_resolution_simple_(
|
||||||
// Add `<>` for generic types
|
// Add `<>` for generic types
|
||||||
let type_path_no_ty_args = matches!(
|
let type_path_no_ty_args = matches!(
|
||||||
ctx.completion.path_context(),
|
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();
|
) && ctx.completion.config.callable.is_some();
|
||||||
if type_path_no_ty_args {
|
if type_path_no_ty_args {
|
||||||
if let Some(cap) = ctx.snippet_cap() {
|
if let Some(cap) = ctx.snippet_cap() {
|
||||||
|
|
|
@ -202,7 +202,7 @@ fn should_add_parens(ctx: &CompletionContext) -> bool {
|
||||||
Some(PathCompletionCtx { kind: PathKind::Expr { .. }, has_call_parens: true, .. }) => {
|
Some(PathCompletionCtx { kind: PathKind::Expr { .. }, has_call_parens: true, .. }) => {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
Some(PathCompletionCtx { kind: PathKind::Use | PathKind::Type, .. }) => {
|
Some(PathCompletionCtx { kind: PathKind::Use | PathKind::Type { .. }, .. }) => {
|
||||||
cov_mark::hit!(no_parens_in_use_item);
|
cov_mark::hit!(no_parens_in_use_item);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,6 @@ fn after_fn_name() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn before_record_field() {
|
fn before_record_field() {
|
||||||
// FIXME: This should emit visibility qualifiers
|
|
||||||
check(
|
check(
|
||||||
r#"
|
r#"
|
||||||
struct Foo {
|
struct Foo {
|
||||||
|
@ -108,6 +107,10 @@ struct Foo {
|
||||||
pub f: i32,
|
pub f: i32,
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#""#]],
|
expect![[r#"
|
||||||
|
kw pub
|
||||||
|
kw pub(crate)
|
||||||
|
kw pub(super)
|
||||||
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,14 +38,13 @@ struct Foo<'lt, T, const C: usize> {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tuple_struct_field() {
|
fn tuple_struct_field() {
|
||||||
// FIXME: This should emit visibility qualifiers
|
|
||||||
check(
|
check(
|
||||||
r#"
|
r#"
|
||||||
struct Foo<'lt, T, const C: usize>(f$0);
|
struct Foo<'lt, T, const C: usize>(f$0);
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
en Enum
|
en Enum
|
||||||
ma makro!(…) macro_rules! makro
|
ma makro!(…) macro_rules! makro
|
||||||
md module
|
md module
|
||||||
sp Self
|
sp Self
|
||||||
st Foo<…>
|
st Foo<…>
|
||||||
|
@ -57,6 +56,9 @@ struct Foo<'lt, T, const C: usize>(f$0);
|
||||||
un Union
|
un Union
|
||||||
bt u32
|
bt u32
|
||||||
kw crate::
|
kw crate::
|
||||||
|
kw pub
|
||||||
|
kw pub(crate)
|
||||||
|
kw pub(super)
|
||||||
kw self::
|
kw self::
|
||||||
kw super::
|
kw super::
|
||||||
"#]],
|
"#]],
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue