show names for record fields in enum completion

This commit is contained in:
adamrk 2020-02-15 21:48:20 +01:00
parent b2b94cbf71
commit 04aff742b1
4 changed files with 109 additions and 7 deletions

View File

@ -3,6 +3,7 @@ use std::sync::Arc;
use either::Either; use either::Either;
use hir_def::{ use hir_def::{
adt::StructKind,
adt::VariantData, adt::VariantData,
builtin_type::BuiltinType, builtin_type::BuiltinType,
docs::Documentation, docs::Documentation,
@ -424,6 +425,10 @@ impl EnumVariant {
.collect() .collect()
} }
pub fn kind(self, db: &impl HirDatabase) -> StructKind {
self.variant_data(db).kind()
}
pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> { pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> {
db.enum_data(self.parent.id).variants[self.id].variant_data.clone() db.enum_data(self.parent.id).variants[self.id].variant_data.clone()
} }

View File

@ -50,6 +50,7 @@ pub use crate::{
}; };
pub use hir_def::{ pub use hir_def::{
adt::StructKind,
body::scope::ExprScopes, body::scope::ExprScopes,
builtin_type::BuiltinType, builtin_type::BuiltinType,
docs::Documentation, docs::Documentation,

View File

@ -140,6 +140,13 @@ impl VariantData {
self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None }) self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None })
} }
pub fn kind(&self) -> StructKind {
match self {
VariantData::Record(_) => StructKind::Record,
VariantData::Tuple(_) => StructKind::Tuple,
VariantData::Unit => StructKind::Unit,
}
}
pub fn is_unit(&self) -> bool { pub fn is_unit(&self) -> bool {
match self { match self {
VariantData::Unit => true, VariantData::Unit => true,
@ -173,7 +180,7 @@ impl HasChildSource for VariantId {
} }
} }
enum StructKind { pub enum StructKind {
Tuple, Tuple,
Record, Record,
Unit, Unit,

View File

@ -1,6 +1,6 @@
//! This modules takes care of rendering various definitions as completion items. //! This modules takes care of rendering various definitions as completion items.
use hir::{db::HirDatabase, Docs, HasAttrs, HasSource, HirDisplay, ScopeDef, Type}; use hir::{db::HirDatabase, Docs, HasAttrs, HasSource, HirDisplay, ScopeDef, StructKind, Type};
use join_to_string::join; use join_to_string::join;
use ra_syntax::ast::NameOwner; use ra_syntax::ast::NameOwner;
use test_utils::tested_by; use test_utils::tested_by;
@ -268,11 +268,22 @@ impl Completions {
pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) { pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) {
let is_deprecated = is_deprecated(variant, ctx.db); let is_deprecated = is_deprecated(variant, ctx.db);
let name = variant.name(ctx.db); let name = variant.name(ctx.db);
let detail_types = variant.fields(ctx.db).into_iter().map(|field| field.ty(ctx.db)); let detail_types =
let detail = join(detail_types.map(|t| t.display(ctx.db).to_string())) variant.fields(ctx.db).into_iter().map(|field| (field.name(ctx.db), field.ty(ctx.db)));
.separator(", ") let detail = match variant.kind(ctx.db) {
.surround_with("(", ")") StructKind::Tuple | StructKind::Unit => {
.to_string(); join(detail_types.map(|(_, t)| t.display(ctx.db).to_string()))
.separator(", ")
.surround_with("(", ")")
.to_string()
}
StructKind::Record => {
join(detail_types.map(|(n, t)| format!("{}: {}", n, t.display(ctx.db).to_string())))
.separator(", ")
.surround_with("{", "}")
.to_string()
}
};
CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
.kind(CompletionItemKind::EnumVariant) .kind(CompletionItemKind::EnumVariant)
.set_documentation(variant.docs(ctx.db)) .set_documentation(variant.docs(ctx.db))
@ -297,6 +308,84 @@ mod tests {
do_completion(code, CompletionKind::Reference) do_completion(code, CompletionKind::Reference)
} }
#[test]
fn enum_detail_includes_names_for_record() {
assert_debug_snapshot!(
do_reference_completion(
r#"
enum Foo {
Foo {x: i32, y: i32}
}
fn main() { Foo::Fo<|> }
"#,
),
@r###"
[
CompletionItem {
label: "Foo",
source_range: [121; 123),
delete: [121; 123),
insert: "Foo",
kind: EnumVariant,
detail: "{x: i32, y: i32}",
},
]"###
);
}
#[test]
fn enum_detail_doesnt_include_names_for_tuple() {
assert_debug_snapshot!(
do_reference_completion(
r#"
enum Foo {
Foo (i32, i32)
}
fn main() { Foo::Fo<|> }
"#,
),
@r###"
[
CompletionItem {
label: "Foo",
source_range: [115; 117),
delete: [115; 117),
insert: "Foo",
kind: EnumVariant,
detail: "(i32, i32)",
},
]"###
);
}
#[test]
fn enum_detail_just_parentheses_for_unit() {
assert_debug_snapshot!(
do_reference_completion(
r#"
enum Foo {
Foo
}
fn main() { Foo::Fo<|> }
"#,
),
@r###"
[
CompletionItem {
label: "Foo",
source_range: [104; 106),
delete: [104; 106),
insert: "Foo",
kind: EnumVariant,
detail: "()",
},
]"###
);
}
#[test] #[test]
fn sets_deprecated_flag_in_completion_items() { fn sets_deprecated_flag_in_completion_items() {
assert_debug_snapshot!( assert_debug_snapshot!(