mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 22:31:43 +00:00
Complete enum variants identically to structures.
In particular: - unit variants now display in the menu as "Variant", complete to "Variant", and display a detail of "Variant" (was "()") - tuple variants now display in the menu as "Variant(…)", complete to "Variant(${1:()})$0" (was "Variant($0)"), and display a detail of "Variant(type)" (was "(type)") - record variants now display in the menu as "Variant {…}", complete to "Variant { x: ${1:()} }$0" (was "Variant"), and display a detail of "Variant { x: type }" (was "{x: type}") This behavior is identical to that of struct completions. In addition, tuple variants no longer set triggers_call_info, as to my understanding it's unnecessary now that we're emitting placeholders. Tests have been updated to match, and the render::enum_variant::tests::inserts_parens_for_tuple_enums test has been removed entirely as it's covered by other tests (render::enum_detail_includes_{record, tuple}_fields, render::enum_detail_just_name_for_unit, render::pattern::enum_qualified).
This commit is contained in:
parent
1c5b2c7d03
commit
2a22cf8efc
7 changed files with 69 additions and 90 deletions
|
@ -580,8 +580,8 @@ impl Foo {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ev Bar ()
|
ev Bar Bar
|
||||||
ev Baz ()
|
ev Baz Baz
|
||||||
me foo(…) fn(self)
|
me foo(…) fn(self)
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -626,7 +626,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ev Bar ()
|
ev Bar Bar
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -429,14 +429,14 @@ fn main() { Foo::Fo$0 }
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
[
|
[
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "Foo",
|
label: "Foo {…}",
|
||||||
source_range: 54..56,
|
source_range: 54..56,
|
||||||
delete: 54..56,
|
delete: 54..56,
|
||||||
insert: "Foo",
|
insert: "Foo { x: ${1:()}, y: ${2:()} }$0",
|
||||||
kind: SymbolKind(
|
kind: SymbolKind(
|
||||||
Variant,
|
Variant,
|
||||||
),
|
),
|
||||||
detail: "{x: i32, y: i32}",
|
detail: "Foo { x: i32, y: i32 }",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -444,7 +444,7 @@ fn main() { Foo::Fo$0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn enum_detail_doesnt_include_tuple_fields() {
|
fn enum_detail_includes_tuple_fields() {
|
||||||
check(
|
check(
|
||||||
r#"
|
r#"
|
||||||
enum Foo { Foo (i32, i32) }
|
enum Foo { Foo (i32, i32) }
|
||||||
|
@ -458,13 +458,11 @@ fn main() { Foo::Fo$0 }
|
||||||
label: "Foo(…)",
|
label: "Foo(…)",
|
||||||
source_range: 46..48,
|
source_range: 46..48,
|
||||||
delete: 46..48,
|
delete: 46..48,
|
||||||
insert: "Foo($0)",
|
insert: "Foo(${1:()}, ${2:()})$0",
|
||||||
kind: SymbolKind(
|
kind: SymbolKind(
|
||||||
Variant,
|
Variant,
|
||||||
),
|
),
|
||||||
lookup: "Foo",
|
detail: "Foo(i32, i32)",
|
||||||
detail: "(i32, i32)",
|
|
||||||
trigger_call_info: true,
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -511,7 +509,7 @@ fn main() { fo$0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn enum_detail_just_parentheses_for_unit() {
|
fn enum_detail_just_name_for_unit() {
|
||||||
check(
|
check(
|
||||||
r#"
|
r#"
|
||||||
enum Foo { Foo }
|
enum Foo { Foo }
|
||||||
|
@ -525,11 +523,11 @@ fn main() { Foo::Fo$0 }
|
||||||
label: "Foo",
|
label: "Foo",
|
||||||
source_range: 35..37,
|
source_range: 35..37,
|
||||||
delete: 35..37,
|
delete: 35..37,
|
||||||
insert: "Foo",
|
insert: "Foo$0",
|
||||||
kind: SymbolKind(
|
kind: SymbolKind(
|
||||||
Variant,
|
Variant,
|
||||||
),
|
),
|
||||||
detail: "()",
|
detail: "Foo",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -573,15 +571,15 @@ fn main() { let _: m::Spam = S$0 }
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "Spam::Bar(…)",
|
label: "m::Spam::Bar(…)",
|
||||||
source_range: 75..76,
|
source_range: 75..76,
|
||||||
delete: 75..76,
|
delete: 75..76,
|
||||||
insert: "Spam::Bar($0)",
|
insert: "m::Spam::Bar(${1:()})$0",
|
||||||
kind: SymbolKind(
|
kind: SymbolKind(
|
||||||
Variant,
|
Variant,
|
||||||
),
|
),
|
||||||
lookup: "Spam::Bar",
|
lookup: "Spam::Bar",
|
||||||
detail: "(i32)",
|
detail: "m::Spam::Bar(i32)",
|
||||||
relevance: CompletionRelevance {
|
relevance: CompletionRelevance {
|
||||||
exact_name_match: false,
|
exact_name_match: false,
|
||||||
type_match: Some(
|
type_match: Some(
|
||||||
|
@ -592,18 +590,17 @@ fn main() { let _: m::Spam = S$0 }
|
||||||
is_private_editable: false,
|
is_private_editable: false,
|
||||||
exact_postfix_snippet_match: false,
|
exact_postfix_snippet_match: false,
|
||||||
},
|
},
|
||||||
trigger_call_info: true,
|
|
||||||
},
|
},
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "m::Spam::Foo",
|
label: "m::Spam::Foo",
|
||||||
source_range: 75..76,
|
source_range: 75..76,
|
||||||
delete: 75..76,
|
delete: 75..76,
|
||||||
insert: "m::Spam::Foo",
|
insert: "m::Spam::Foo$0",
|
||||||
kind: SymbolKind(
|
kind: SymbolKind(
|
||||||
Variant,
|
Variant,
|
||||||
),
|
),
|
||||||
lookup: "Spam::Foo",
|
lookup: "Spam::Foo",
|
||||||
detail: "()",
|
detail: "m::Spam::Foo",
|
||||||
relevance: CompletionRelevance {
|
relevance: CompletionRelevance {
|
||||||
exact_name_match: false,
|
exact_name_match: false,
|
||||||
type_match: Some(
|
type_match: Some(
|
||||||
|
@ -788,11 +785,11 @@ use self::E::*;
|
||||||
label: "V",
|
label: "V",
|
||||||
source_range: 10..12,
|
source_range: 10..12,
|
||||||
delete: 10..12,
|
delete: 10..12,
|
||||||
insert: "V",
|
insert: "V$0",
|
||||||
kind: SymbolKind(
|
kind: SymbolKind(
|
||||||
Variant,
|
Variant,
|
||||||
),
|
),
|
||||||
detail: "()",
|
detail: "V",
|
||||||
documentation: Documentation(
|
documentation: Documentation(
|
||||||
"variant docs",
|
"variant docs",
|
||||||
),
|
),
|
||||||
|
|
|
@ -8,6 +8,7 @@ use crate::{context::PathKind, item::Builder, patterns::ImmediateLocation, Compl
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) enum Params {
|
pub(super) enum Params {
|
||||||
Named(Option<hir::SelfParam>, Vec<hir::Param>),
|
Named(Option<hir::SelfParam>, Vec<hir::Param>),
|
||||||
|
#[allow(dead_code)]
|
||||||
Anonymous(usize),
|
Anonymous(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
//! Renderer for `enum` variants.
|
//! Renderer for `enum` variants.
|
||||||
|
|
||||||
use hir::{db::HirDatabase, HasAttrs, HirDisplay, StructKind};
|
use hir::{HasAttrs, StructKind};
|
||||||
use ide_db::SymbolKind;
|
use ide_db::SymbolKind;
|
||||||
use itertools::Itertools;
|
|
||||||
use syntax::SmolStr;
|
use syntax::SmolStr;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
item::{CompletionItem, ImportEdit},
|
item::{CompletionItem, ImportEdit},
|
||||||
render::{builder_ext::Params, compute_ref_match, compute_type_match, RenderContext},
|
render::{
|
||||||
|
compound::{render_record, render_tuple, RenderedCompound},
|
||||||
|
compute_ref_match, compute_type_match, RenderContext,
|
||||||
|
},
|
||||||
CompletionRelevance,
|
CompletionRelevance,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -46,20 +48,46 @@ fn render(
|
||||||
let qualified_name = qualified_name.to_string();
|
let qualified_name = qualified_name.to_string();
|
||||||
let short_qualified_name: SmolStr = short_qualified_name.to_string().into();
|
let short_qualified_name: SmolStr = short_qualified_name.to_string().into();
|
||||||
|
|
||||||
let mut item = CompletionItem::new(SymbolKind::Variant, ctx.source_range(), qualified_name);
|
let mut rendered = match variant_kind {
|
||||||
|
StructKind::Tuple => {
|
||||||
|
render_tuple(db, ctx.snippet_cap(), &variant.fields(db), Some(&qualified_name))
|
||||||
|
}
|
||||||
|
StructKind::Record => {
|
||||||
|
render_record(db, ctx.snippet_cap(), &variant.fields(db), Some(&qualified_name))
|
||||||
|
}
|
||||||
|
StructKind::Unit => {
|
||||||
|
RenderedCompound { literal: qualified_name.clone(), detail: qualified_name.clone() }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if ctx.snippet_cap().is_some() {
|
||||||
|
rendered.literal.push_str("$0");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut item = CompletionItem::new(
|
||||||
|
SymbolKind::Variant,
|
||||||
|
ctx.source_range(),
|
||||||
|
match variant_kind {
|
||||||
|
StructKind::Tuple => SmolStr::from_iter([&qualified_name, "(…)"]),
|
||||||
|
StructKind::Record => SmolStr::from_iter([&qualified_name, " {…}"]),
|
||||||
|
StructKind::Unit => qualified_name.into(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
item.set_documentation(variant.docs(db))
|
item.set_documentation(variant.docs(db))
|
||||||
.set_deprecated(ctx.is_deprecated(variant))
|
.set_deprecated(ctx.is_deprecated(variant))
|
||||||
.detail(detail(db, variant, variant_kind));
|
.detail(rendered.detail);
|
||||||
|
|
||||||
|
match ctx.snippet_cap() {
|
||||||
|
Some(snippet_cap) => item.insert_snippet(snippet_cap, rendered.literal),
|
||||||
|
None => item.insert_text(rendered.literal),
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(import_to_add) = import_to_add {
|
if let Some(import_to_add) = import_to_add {
|
||||||
item.add_import(import_to_add);
|
item.add_import(import_to_add);
|
||||||
}
|
}
|
||||||
|
|
||||||
if variant_kind == hir::StructKind::Tuple {
|
if qualified {
|
||||||
cov_mark::hit!(inserts_parens_for_tuple_enums);
|
|
||||||
let params = Params::Anonymous(variant.fields(db).len());
|
|
||||||
item.add_call_parens(completion, short_qualified_name, params);
|
|
||||||
} else if qualified {
|
|
||||||
item.lookup_by(short_qualified_name);
|
item.lookup_by(short_qualified_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,50 +103,3 @@ fn render(
|
||||||
|
|
||||||
item.build()
|
item.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn detail(db: &dyn HirDatabase, variant: hir::Variant, variant_kind: StructKind) -> String {
|
|
||||||
let detail_types = variant.fields(db).into_iter().map(|field| (field.name(db), field.ty(db)));
|
|
||||||
|
|
||||||
match variant_kind {
|
|
||||||
hir::StructKind::Tuple | hir::StructKind::Unit => {
|
|
||||||
format!("({})", detail_types.format_with(", ", |(_, t), f| f(&t.display(db))))
|
|
||||||
}
|
|
||||||
hir::StructKind::Record => {
|
|
||||||
format!(
|
|
||||||
"{{{}}}",
|
|
||||||
detail_types.format_with(", ", |(n, t), f| {
|
|
||||||
f(&n)?;
|
|
||||||
f(&": ")?;
|
|
||||||
f(&t.display(db))
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::tests::check_edit;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn inserts_parens_for_tuple_enums() {
|
|
||||||
cov_mark::check!(inserts_parens_for_tuple_enums);
|
|
||||||
check_edit(
|
|
||||||
"Some",
|
|
||||||
r#"
|
|
||||||
enum Option<T> { Some(T), None }
|
|
||||||
use Option::*;
|
|
||||||
fn main() -> Option<i32> {
|
|
||||||
Som$0
|
|
||||||
}
|
|
||||||
"#,
|
|
||||||
r#"
|
|
||||||
enum Option<T> { Some(T), None }
|
|
||||||
use Option::*;
|
|
||||||
fn main() -> Option<i32> {
|
|
||||||
Some($0)
|
|
||||||
}
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ fn baz() {
|
||||||
fn function() fn()
|
fn function() fn()
|
||||||
sc STATIC
|
sc STATIC
|
||||||
un Union
|
un Union
|
||||||
ev TupleV(…) (u32)
|
ev TupleV(…) TupleV(u32)
|
||||||
ct CONST
|
ct CONST
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
|
@ -171,7 +171,7 @@ impl Unit {
|
||||||
fn function() fn()
|
fn function() fn()
|
||||||
sc STATIC
|
sc STATIC
|
||||||
un Union
|
un Union
|
||||||
ev TupleV(…) (u32)
|
ev TupleV(…) TupleV(u32)
|
||||||
ct CONST
|
ct CONST
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -200,7 +200,7 @@ impl Unit {
|
||||||
fn function() fn()
|
fn function() fn()
|
||||||
sc STATIC
|
sc STATIC
|
||||||
un Union
|
un Union
|
||||||
ev TupleV(…) (u32)
|
ev TupleV(…) TupleV(u32)
|
||||||
ct CONST
|
ct CONST
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -543,9 +543,9 @@ fn func() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ev TupleV(…) (u32)
|
ev TupleV(…) TupleV(u32)
|
||||||
ev RecordV {field: u32}
|
ev RecordV {…} RecordV { field: u32 }
|
||||||
ev UnitV ()
|
ev UnitV UnitV
|
||||||
ct ASSOC_CONST const ASSOC_CONST: ()
|
ct ASSOC_CONST const ASSOC_CONST: ()
|
||||||
fn assoc_fn() fn()
|
fn assoc_fn() fn()
|
||||||
ta AssocType type AssocType = ()
|
ta AssocType type AssocType = ()
|
||||||
|
|
|
@ -218,7 +218,7 @@ fn foo() {
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
kw ref
|
kw ref
|
||||||
kw mut
|
kw mut
|
||||||
ev E::X ()
|
ev E::X E::X
|
||||||
en E
|
en E
|
||||||
ma m!(…) macro_rules! m
|
ma m!(…) macro_rules! m
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -291,9 +291,9 @@ fn func() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ev TupleV(…) (u32)
|
ev TupleV(…) TupleV(u32)
|
||||||
ev RecordV {field: u32}
|
ev RecordV {…} RecordV { field: u32 }
|
||||||
ev UnitV ()
|
ev UnitV UnitV
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,7 +167,7 @@ impl Foo {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
ev Variant ()
|
ev Variant Variant
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue