10649: internal: Remove `CompletionKind` in favor of `CompletionItemKind` r=Veykril a=Veykril

and move some more tests around
bors r+

Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
This commit is contained in:
bors[bot] 2021-10-27 15:38:42 +00:00 committed by GitHub
commit 9d1f15086a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 1558 additions and 1563 deletions

View File

@ -21,7 +21,7 @@ use hir::known;
use ide_db::SymbolKind;
use crate::{
item::{Builder, CompletionKind},
item::Builder,
render::{
const_::render_const,
enum_variant::render_variant,
@ -76,8 +76,7 @@ impl Completions {
}
pub(crate) fn add_keyword(&mut self, ctx: &CompletionContext, keyword: &'static str) {
let mut item = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), keyword);
item.kind(CompletionItemKind::Keyword);
let item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), keyword);
item.add_to(self);
}
@ -191,9 +190,7 @@ impl Completions {
}
pub(crate) fn add_static_lifetime(&mut self, ctx: &CompletionContext) {
let mut item =
CompletionItem::new(CompletionKind::Reference, ctx.source_range(), "'static");
item.kind(CompletionItemKind::SymbolKind(SymbolKind::LifetimeParam));
let item = CompletionItem::new(SymbolKind::LifetimeParam, ctx.source_range(), "'static");
self.add(item.build());
}

View File

@ -12,7 +12,7 @@ use syntax::{algo::non_trivia_sibling, ast, AstNode, Direction, SyntaxKind, T};
use crate::{
context::CompletionContext,
item::{CompletionItem, CompletionItemKind, CompletionKind},
item::{CompletionItem, CompletionItemKind},
Completions,
};
@ -69,11 +69,10 @@ fn complete_new_attribute(acc: &mut Completions, ctx: &CompletionContext, attrib
let add_completion = |attr_completion: &AttrCompletion| {
let mut item = CompletionItem::new(
CompletionKind::Attribute,
CompletionItemKind::Attribute,
ctx.source_range(),
attr_completion.label,
);
item.kind(CompletionItemKind::Attribute);
if let Some(lookup) = attr_completion.lookup {
item.lookup_by(lookup);
@ -103,11 +102,10 @@ fn complete_new_attribute(acc: &mut Completions, ctx: &CompletionContext, attrib
if let hir::ScopeDef::MacroDef(mac) = scope_def {
if mac.kind() == hir::MacroKind::Attr {
let mut item = CompletionItem::new(
CompletionKind::Attribute,
CompletionItemKind::Attribute,
ctx.source_range(),
name.to_string(),
);
item.kind(CompletionItemKind::Attribute);
if let Some(docs) = mac.docs(ctx.sema.db) {
item.documentation(docs);
}

View File

@ -5,16 +5,14 @@ use std::iter;
use syntax::SyntaxKind;
use crate::{
completions::Completions, context::CompletionContext, item::CompletionKind, CompletionItem,
CompletionItemKind,
completions::Completions, context::CompletionContext, CompletionItem, CompletionItemKind,
};
pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext) {
let add_completion = |item: &str| {
let mut completion =
CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), item);
CompletionItem::new(CompletionItemKind::Attribute, ctx.source_range(), item);
completion.insert_text(format!(r#""{}""#, item));
completion.kind(CompletionItemKind::Attribute);
acc.add(completion.build());
};
@ -35,7 +33,7 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext) {
if let Some(krate) = ctx.krate {
krate.potential_cfg(ctx.db).get_cfg_values(&name).iter().for_each(|s| {
let mut item = CompletionItem::new(
CompletionKind::Attribute,
CompletionItemKind::Attribute,
ctx.source_range(),
s.as_str(),
);
@ -49,7 +47,7 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext) {
if let Some(krate) = ctx.krate {
krate.potential_cfg(ctx.db).get_cfg_keys().iter().for_each(|s| {
let item = CompletionItem::new(
CompletionKind::Attribute,
CompletionItemKind::Attribute,
ctx.source_range(),
s.as_str(),
);

View File

@ -7,7 +7,7 @@ use syntax::ast;
use crate::{
context::CompletionContext,
item::{CompletionItem, CompletionItemKind, CompletionKind},
item::{CompletionItem, CompletionItemKind},
Completions,
};
@ -56,8 +56,8 @@ pub(super) fn complete_derive(
_ => (&*name, None),
};
let mut item = CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label);
item.kind(CompletionItemKind::Attribute);
let mut item =
CompletionItem::new(CompletionItemKind::Attribute, ctx.source_range(), label);
if let Some(docs) = mac.docs(ctx.db) {
item.documentation(docs);
}

View File

@ -4,7 +4,7 @@ use syntax::{ast, T};
use crate::{
context::CompletionContext,
item::{CompletionItem, CompletionItemKind, CompletionKind},
item::{CompletionItem, CompletionItemKind},
Completions,
};
@ -58,9 +58,9 @@ pub(super) fn complete_lint(
Some(qual) if !is_qualified => format!("{}::{}", qual, name),
_ => name.to_owned(),
};
let mut item = CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label);
item.kind(CompletionItemKind::Attribute)
.documentation(hir::Documentation::new(description.to_owned()));
let mut item =
CompletionItem::new(CompletionItemKind::Attribute, ctx.source_range(), label);
item.documentation(hir::Documentation::new(description.to_owned()));
item.add_to(acc)
}
}

View File

@ -4,7 +4,7 @@ use syntax::ast;
use crate::{
context::CompletionContext,
item::{CompletionItem, CompletionItemKind, CompletionKind},
item::{CompletionItem, CompletionItemKind},
Completions,
};
@ -30,8 +30,7 @@ pub(super) fn complete_repr(acc: &mut Completions, ctx: &CompletionContext, inpu
}
let mut item =
CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label);
item.kind(CompletionItemKind::Attribute);
CompletionItem::new(CompletionItemKind::Attribute, ctx.source_range(), label);
if let Some(lookup) = lookup {
item.lookup_by(lookup);
}

View File

@ -99,13 +99,10 @@ fn complete_methods(
mod tests {
use expect_test::{expect, Expect};
use crate::{
tests::{check_edit, filtered_completion_list},
CompletionKind,
};
use crate::tests::{check_edit, completion_list_no_kw};
fn check(ra_fixture: &str, expect: Expect) {
let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference);
let actual = completion_list_no_kw(ra_fixture);
expect.assert_eq(&actual);
}
@ -166,7 +163,7 @@ impl A {
struct A { the_field: u32 }
fn foo(a: A) { a.$0() }
"#,
expect![[""]],
expect![[r#""#]],
);
}
@ -405,7 +402,7 @@ fn foo(a: A) {
a.$0
}
"#,
expect![[""]],
expect![[r#""#]],
);
}
@ -654,6 +651,7 @@ impl Foo { fn foo(&self) { $0 } }"#,
lc self &Foo
sp Self
st Foo
bt u32
fd self.field i32
me self.foo() fn(&self)
"#]],
@ -667,6 +665,7 @@ impl Foo { fn foo(&mut self) { $0 } }"#,
lc self &mut Foo
sp Self
st Foo
bt u32
fd self.0 i32
me self.foo() fn(&mut self)
"#]],

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@ use syntax::{
use crate::{
context::{ParamKind, PatternContext},
CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
CompletionContext, CompletionItem, CompletionItemKind, Completions,
};
/// Complete repeated parameters, both name and type. For example, if all
@ -75,7 +75,7 @@ fn add_new_item_to_acc(
label: String,
lookup: String,
) {
let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label);
item.kind(CompletionItemKind::Binding).lookup_by(lookup);
let mut item = CompletionItem::new(CompletionItemKind::Binding, ctx.source_range(), label);
item.lookup_by(lookup);
item.add_to(acc)
}

View File

@ -6,7 +6,7 @@ use syntax::{SyntaxKind, T};
use crate::{
context::PathCompletionContext, patterns::ImmediateLocation, CompletionContext, CompletionItem,
CompletionItemKind, CompletionKind, Completions,
CompletionItemKind, Completions,
};
pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
@ -158,8 +158,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
}
fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) {
let mut item = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw);
item.kind(CompletionItemKind::Keyword);
let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw);
match ctx.config.snippet_cap {
Some(cap) => {
@ -181,115 +180,15 @@ fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet
mod tests {
use expect_test::{expect, Expect};
use crate::{
tests::{check_edit, filtered_completion_list},
CompletionKind,
};
use crate::tests::{check_edit, completion_list};
fn check(ra_fixture: &str, expect: Expect) {
let actual = filtered_completion_list(ra_fixture, CompletionKind::Keyword);
let actual = completion_list(ra_fixture);
expect.assert_eq(&actual)
}
#[test]
fn test_keywords_in_function() {
check(
r"fn quux() { $0 }",
expect![[r#"
kw unsafe
kw fn
kw const
kw type
kw impl
kw extern
kw use
kw trait
kw static
kw mod
kw match
kw while
kw while let
kw loop
kw if
kw if let
kw for
kw true
kw false
kw let
kw return
kw self
kw super
kw crate
"#]],
);
}
#[test]
fn test_keywords_inside_block() {
check(
r"fn quux() { if true { $0 } }",
expect![[r#"
kw unsafe
kw fn
kw const
kw type
kw impl
kw extern
kw use
kw trait
kw static
kw mod
kw match
kw while
kw while let
kw loop
kw if
kw if let
kw for
kw true
kw false
kw let
kw return
kw self
kw super
kw crate
"#]],
);
}
#[test]
fn test_keywords_after_if() {
check(
r#"fn quux() { if true { () } $0 }"#,
expect![[r#"
kw unsafe
kw fn
kw const
kw type
kw impl
kw extern
kw use
kw trait
kw static
kw mod
kw match
kw while
kw while let
kw loop
kw if
kw if let
kw for
kw true
kw false
kw let
kw else
kw else if
kw return
kw self
kw super
kw crate
"#]],
);
fn test_else_edit_after_if() {
check_edit(
"else",
r#"fn quux() { if true { () } $0 }"#,
@ -299,68 +198,6 @@ mod tests {
);
}
#[test]
fn test_keywords_in_match_arm() {
check(
r#"
fn quux() -> i32 {
match () { () => $0 }
}
"#,
expect![[r#"
kw unsafe
kw match
kw while
kw while let
kw loop
kw if
kw if let
kw for
kw true
kw false
kw return
kw self
kw super
kw crate
"#]],
);
}
#[test]
fn test_keywords_in_loop() {
check(
r"fn my() { loop { $0 } }",
expect![[r#"
kw unsafe
kw fn
kw const
kw type
kw impl
kw extern
kw use
kw trait
kw static
kw mod
kw match
kw while
kw while let
kw loop
kw if
kw if let
kw for
kw true
kw false
kw let
kw continue
kw break
kw return
kw self
kw super
kw crate
"#]],
);
}
#[test]
fn test_keywords_after_unsafe_in_block_expr() {
check(
@ -369,38 +206,12 @@ fn quux() -> i32 {
kw fn
kw trait
kw impl
sn pd
sn ppd
"#]],
);
}
#[test]
fn no_keyword_completion_in_comments() {
cov_mark::check!(no_keyword_completion_in_comments);
check(
r#"
fn test() {
let x = 2; // A comment$0
}
"#,
expect![[""]],
);
check(
r#"
/*
Some multi-line comment$0
*/
"#,
expect![[""]],
);
check(
r#"
/// Some doc comment
/// let test$0 = 1
"#,
expect![[""]],
);
}
#[test]
fn test_completion_await_impls_future() {
check(
@ -413,6 +224,18 @@ fn foo(a: A) { a.$0 }
"#,
expect![[r#"
kw await expr.await
sn ref &expr
sn refm &mut expr
sn match match expr {}
sn box Box::new(expr)
sn ok Ok(expr)
sn err Err(expr)
sn some Some(expr)
sn dbg dbg!(expr)
sn dbgr dbg!(&expr)
sn call function(expr)
sn let let
sn letm let mut
"#]],
);
@ -427,83 +250,22 @@ fn foo() {
"#,
expect![[r#"
kw await expr.await
sn ref &expr
sn refm &mut expr
sn match match expr {}
sn box Box::new(expr)
sn ok Ok(expr)
sn err Err(expr)
sn some Some(expr)
sn dbg dbg!(expr)
sn dbgr dbg!(&expr)
sn call function(expr)
sn let let
sn letm let mut
"#]],
)
}
#[test]
fn after_let() {
check(
r#"fn main() { let _ = $0 }"#,
expect![[r#"
kw unsafe
kw match
kw while
kw while let
kw loop
kw if
kw if let
kw for
kw true
kw false
kw return
kw self
kw super
kw crate
"#]],
)
}
#[test]
fn skip_struct_initializer() {
cov_mark::check!(no_keyword_completion_in_record_lit);
check(
r#"
struct Foo {
pub f: i32,
}
fn foo() {
Foo {
$0
}
}
"#,
expect![[r#""#]],
);
}
#[test]
fn struct_initializer_field_expr() {
check(
r#"
struct Foo {
pub f: i32,
}
fn foo() {
Foo {
f: $0
}
}
"#,
expect![[r#"
kw unsafe
kw match
kw while
kw while let
kw loop
kw if
kw if let
kw for
kw true
kw false
kw return
kw self
kw super
kw crate
"#]],
);
}
#[test]
fn let_semi() {
cov_mark::check!(let_semi);

View File

@ -11,7 +11,7 @@ use rustc_hash::FxHashSet;
use crate::{patterns::ImmediateLocation, CompletionItem};
use crate::{context::CompletionContext, item::CompletionKind, Completions};
use crate::{context::CompletionContext, Completions};
/// Complete mod declaration, i.e. `mod $0 ;`
pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
@ -80,8 +80,7 @@ pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Op
if mod_under_caret.semicolon_token().is_none() {
label.push(';');
}
let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), &label);
item.kind(SymbolKind::Module);
let item = CompletionItem::new(SymbolKind::Module, ctx.source_range(), &label);
item.add_to(acc)
});
@ -141,9 +140,10 @@ fn module_chain_to_containing_module_file(
#[cfg(test)]
mod tests {
use crate::tests::completion_list;
use expect_test::{expect, Expect};
use crate::tests::completion_list;
fn check(ra_fixture: &str, expect: Expect) {
let actual = completion_list(ra_fixture);
expect.assert_eq(&actual);

View File

@ -15,11 +15,9 @@ use syntax::{
use text_edit::TextEdit;
use crate::{
completions::postfix::format_like::add_format_like_completions,
context::CompletionContext,
item::{Builder, CompletionKind},
patterns::ImmediateLocation,
CompletionItem, CompletionItemKind, CompletionRelevance, Completions, SnippetScope,
completions::postfix::format_like::add_format_like_completions, context::CompletionContext,
item::Builder, patterns::ImmediateLocation, CompletionItem, CompletionItemKind,
CompletionRelevance, Completions, SnippetScope,
};
pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
@ -45,8 +43,9 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
// Suggest .await syntax for types that implement Future trait
if receiver_ty.impls_future(ctx.db) {
let mut item = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await");
item.kind(CompletionItemKind::Keyword).detail("expr.await");
let mut item =
CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), "await");
item.detail("expr.await");
item.add_to(acc);
}
@ -224,8 +223,9 @@ fn build_postfix_snippet_builder<'ctx>(
) -> impl Fn(&str, &str, &str) -> Builder + 'ctx {
move |label, detail, snippet| {
let edit = TextEdit::replace(delete_range, snippet.to_string());
let mut item = CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label);
item.detail(detail).kind(CompletionItemKind::Snippet).snippet_edit(cap, edit);
let mut item =
CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label);
item.detail(detail).snippet_edit(cap, edit);
if ctx.original_token.text() == label {
let relevance =
CompletionRelevance { exact_postfix_snippet_match: true, ..Default::default() };
@ -270,12 +270,12 @@ mod tests {
use expect_test::{expect, Expect};
use crate::{
tests::{check_edit, check_edit_with_config, filtered_completion_list, TEST_CONFIG},
CompletionConfig, CompletionKind, Snippet,
tests::{check_edit, check_edit_with_config, completion_list, TEST_CONFIG},
CompletionConfig, Snippet,
};
fn check(ra_fixture: &str, expect: Expect) {
let actual = filtered_completion_list(ra_fixture, CompletionKind::Postfix);
let actual = completion_list(ra_fixture);
expect.assert_eq(&actual)
}

View File

@ -250,13 +250,10 @@ fn add_enum_variants(acc: &mut Completions, ctx: &CompletionContext, e: hir::Enu
mod tests {
use expect_test::{expect, Expect};
use crate::{
tests::{check_edit, filtered_completion_list},
CompletionKind,
};
use crate::tests::{check_edit, completion_list_no_kw};
fn check(ra_fixture: &str, expect: Expect) {
let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference);
let actual = completion_list_no_kw(ra_fixture);
expect.assert_eq(&actual);
}

View File

@ -3,8 +3,7 @@ use ide_db::{helpers::FamousDefs, SymbolKind};
use syntax::{ast::Expr, T};
use crate::{
item::CompletionKind, patterns::ImmediateLocation, CompletionContext, CompletionItem,
CompletionItemKind, Completions,
patterns::ImmediateLocation, CompletionContext, CompletionItem, CompletionItemKind, Completions,
};
pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
@ -22,20 +21,17 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
if impl_default_trait && !missing_fields.is_empty() && ctx.path_qual().is_none() {
let completion_text = "..Default::default()";
let mut item = CompletionItem::new(
CompletionKind::Snippet,
ctx.source_range(),
completion_text,
);
let mut item =
CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text);
let completion_text =
completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text);
item.insert_text(completion_text).kind(SymbolKind::Field);
item.insert_text(completion_text);
item.add_to(acc);
}
if ctx.previous_token_is(T![.]) {
let mut item =
CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), "..");
item.insert_text(".").kind(CompletionItemKind::Snippet);
CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), "..");
item.insert_text(".");
item.add_to(acc);
return None;
}

View File

@ -6,12 +6,12 @@ use syntax::T;
use crate::{
context::PathCompletionContext, item::Builder, CompletionContext, CompletionItem,
CompletionItemKind, CompletionKind, Completions, SnippetScope,
CompletionItemKind, Completions, SnippetScope,
};
fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder {
let mut item = CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), label);
item.insert_snippet(cap, snippet).kind(CompletionItemKind::Snippet);
let mut item = CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label);
item.insert_snippet(cap, snippet);
item
}

View File

@ -40,7 +40,7 @@ use syntax::{
};
use text_edit::TextEdit;
use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions};
use crate::{CompletionContext, CompletionItem, CompletionItemKind, Completions};
#[derive(Debug, PartialEq, Eq)]
enum ImplCompletionKind {
@ -141,14 +141,14 @@ fn add_function_impl(
format!("fn {}(..)", fn_name)
};
let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label);
item.lookup_by(fn_name).set_documentation(func.docs(ctx.db));
let completion_kind = if func.self_param(ctx.db).is_some() {
CompletionItemKind::Method
} else {
CompletionItemKind::SymbolKind(SymbolKind::Function)
};
let mut item = CompletionItem::new(completion_kind, ctx.source_range(), label);
item.lookup_by(fn_name).set_documentation(func.docs(ctx.db));
let range = replacement_range(ctx, fn_def_node);
if let Some(source) = func.source(ctx.db) {
@ -170,7 +170,6 @@ fn add_function_impl(
item.text_edit(TextEdit::replace(range, header));
}
};
item.kind(completion_kind);
item.add_to(acc);
}
}
@ -211,10 +210,9 @@ fn add_type_alias_impl(
let snippet = format!("type {} = ", alias_name);
let range = replacement_range(ctx, type_def_node);
let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone());
let mut item = CompletionItem::new(SymbolKind::TypeAlias, ctx.source_range(), snippet.clone());
item.text_edit(TextEdit::replace(range, snippet))
.lookup_by(alias_name)
.kind(SymbolKind::TypeAlias)
.set_documentation(type_alias.docs(ctx.db));
item.add_to(acc);
}
@ -241,10 +239,9 @@ fn add_const_impl(
let range = replacement_range(ctx, const_def_node);
let mut item =
CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone());
CompletionItem::new(SymbolKind::Const, ctx.source_range(), snippet.clone());
item.text_edit(TextEdit::replace(range, snippet))
.lookup_by(const_name)
.kind(SymbolKind::Const)
.set_documentation(const_.docs(ctx.db));
item.add_to(acc);
}
@ -290,13 +287,10 @@ fn replacement_range(ctx: &CompletionContext, item: &SyntaxNode) -> TextRange {
mod tests {
use expect_test::{expect, Expect};
use crate::{
tests::{check_edit, filtered_completion_list},
CompletionKind,
};
use crate::tests::{check_edit, completion_list_no_kw};
fn check(ra_fixture: &str, expect: Expect) {
let actual = filtered_completion_list(ra_fixture, CompletionKind::Magic);
let actual = completion_list_no_kw(ra_fixture);
expect.assert_eq(&actual)
}
@ -313,7 +307,12 @@ impl Test for T {
}
}
",
expect![[""]],
expect![[r#"
sp Self
tt Test
st T
bt u32
"#]],
);
check(
@ -356,7 +355,7 @@ impl Test for T {
}
}
",
expect![[""]],
expect![[r#""#]],
);
check(
@ -368,7 +367,10 @@ impl Test for T {
fn test(t$0)
}
",
expect![[""]],
expect![[r#"
sp Self
st T
"#]],
);
check(
@ -380,7 +382,10 @@ impl Test for T {
fn test(f: fn $0)
}
",
expect![[""]],
expect![[r#"
sp Self
st T
"#]],
);
}
@ -395,7 +400,7 @@ impl Test for T {
const TEST: fn $0
}
",
expect![[""]],
expect![[r#""#]],
);
check(
@ -407,7 +412,12 @@ impl Test for T {
const TEST: T$0
}
",
expect![[""]],
expect![[r#"
sp Self
tt Test
st T
bt u32
"#]],
);
check(
@ -419,7 +429,12 @@ impl Test for T {
const TEST: u32 = f$0
}
",
expect![[""]],
expect![[r#"
sp Self
tt Test
st T
bt u32
"#]],
);
check(
@ -433,7 +448,12 @@ impl Test for T {
};
}
",
expect![[""]],
expect![[r#"
sp Self
tt Test
st T
bt u32
"#]],
);
check(
@ -476,7 +496,12 @@ impl Test for T {
type Test = T$0;
}
",
expect![[""]],
expect![[r#"
sp Self
tt Test
st T
bt u32
"#]],
);
check(
@ -488,7 +513,12 @@ impl Test for T {
type Test = fn $0;
}
",
expect![[""]],
expect![[r#"
sp Self
tt Test
st T
bt u32
"#]],
);
}

View File

@ -117,24 +117,15 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
mod tests {
use expect_test::{expect, Expect};
use crate::{
tests::{check_edit, filtered_completion_list_with_config, TEST_CONFIG},
CompletionConfig, CompletionKind,
};
use crate::tests::{check_edit, completion_list_no_kw};
fn check(ra_fixture: &str, expect: Expect) {
check_with_config(TEST_CONFIG, ra_fixture, expect);
}
fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) {
let actual =
filtered_completion_list_with_config(config, ra_fixture, CompletionKind::Reference);
let actual = completion_list_no_kw(ra_fixture);
expect.assert_eq(&actual)
}
#[test]
fn completes_if_prefix_is_keyword() {
cov_mark::check!(completes_if_prefix_is_keyword);
check_edit(
"wherewolf",
r#"
@ -188,6 +179,7 @@ pub mod prelude {
"#,
expect![[r#"
md std
bt u32
st Option
"#]],
);
@ -217,6 +209,7 @@ mod macros {
fn f() fn()
ma concat!() #[macro_export] macro_rules! concat
md std
bt u32
"##]],
);
}
@ -245,6 +238,7 @@ pub mod prelude {
expect![[r#"
md std
md core
bt u32
st String
"#]],
);
@ -273,6 +267,7 @@ pub mod prelude {
expect![[r#"
fn f() fn()
md std
bt u32
"#]],
);
}

View File

@ -134,7 +134,6 @@ impl<'a> CompletionContext<'a> {
// check kind of macro-expanded token, but use range of original token
let kind = self.token.kind();
if kind == IDENT || kind == LIFETIME_IDENT || kind == UNDERSCORE || kind.is_keyword() {
cov_mark::hit!(completes_if_prefix_is_keyword);
self.original_token.text_range()
} else if kind == CHAR {
// assume we are completing a lifetime but the user has only typed the '

View File

@ -21,10 +21,6 @@ use text_edit::TextEdit;
/// `CompletionItem`, use `new` method and the `Builder` struct.
#[derive(Clone)]
pub struct CompletionItem {
/// Used only internally in tests, to check only specific kind of
/// completion (postfix, keyword, reference, etc).
#[allow(unused)]
pub(crate) completion_kind: CompletionKind,
/// Label in the completion pop up which identifies completion.
label: String,
/// Range of identifier that is being completed.
@ -43,7 +39,7 @@ pub struct CompletionItem {
is_snippet: bool,
/// What item (struct, function, etc) are we completing.
kind: Option<CompletionItemKind>,
kind: CompletionItemKind,
/// Lookup is used to check if completion item indeed can complete current
/// ident.
@ -92,9 +88,7 @@ impl fmt::Debug for CompletionItem {
} else {
s.field("text_edit", &self.text_edit);
}
if let Some(kind) = self.kind().as_ref() {
s.field("kind", kind);
}
s.field("kind", &self.kind());
if self.lookup() != self.label() {
s.field("lookup", &self.lookup());
}
@ -270,32 +264,15 @@ impl CompletionItemKind {
}
}
// FIXME remove this?
/// Like [`CompletionItemKind`] but solely used for filtering test results.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub(crate) enum CompletionKind {
/// Parser-based keyword completion.
Keyword,
/// Your usual "complete all valid identifiers".
Reference,
/// "Secret sauce" completions.
Magic,
Snippet,
Postfix,
BuiltinType,
Attribute,
}
impl CompletionItem {
pub(crate) fn new(
completion_kind: CompletionKind,
kind: impl Into<CompletionItemKind>,
source_range: TextRange,
label: impl Into<String>,
) -> Builder {
let label = label.into();
Builder {
source_range,
completion_kind,
label,
insert_text: None,
is_snippet: false,
@ -303,7 +280,7 @@ impl CompletionItem {
detail: None,
documentation: None,
lookup: None,
kind: None,
kind: kind.into(),
text_edit: None,
deprecated: false,
trigger_call_info: None,
@ -342,7 +319,7 @@ impl CompletionItem {
self.lookup.as_deref().unwrap_or(&self.label)
}
pub fn kind(&self) -> Option<CompletionItemKind> {
pub fn kind(&self) -> CompletionItemKind {
self.kind
}
@ -401,7 +378,6 @@ impl ImportEdit {
#[derive(Clone)]
pub(crate) struct Builder {
source_range: TextRange,
completion_kind: CompletionKind,
imports_to_add: SmallVec<[ImportEdit; 1]>,
trait_name: Option<String>,
label: String,
@ -410,7 +386,7 @@ pub(crate) struct Builder {
detail: Option<String>,
documentation: Option<Documentation>,
lookup: Option<String>,
kind: Option<CompletionItemKind>,
kind: CompletionItemKind,
text_edit: Option<TextEdit>,
deprecated: bool,
trigger_call_info: Option<bool>,
@ -454,7 +430,6 @@ impl Builder {
documentation: self.documentation,
lookup,
kind: self.kind,
completion_kind: self.completion_kind,
deprecated: self.deprecated,
trigger_call_info: self.trigger_call_info.unwrap_or(false),
relevance: self.relevance,
@ -487,10 +462,6 @@ impl Builder {
self.is_snippet = true;
self.insert_text(snippet)
}
pub(crate) fn kind(&mut self, kind: impl Into<CompletionItemKind>) -> &mut Builder {
self.kind = Some(kind.into());
self
}
pub(crate) fn text_edit(&mut self, edit: TextEdit) -> &mut Builder {
self.text_edit = Some(edit);
self

View File

@ -24,7 +24,7 @@ use ide_db::{
use syntax::algo;
use text_edit::TextEdit;
use crate::{completions::Completions, context::CompletionContext, item::CompletionKind};
use crate::{completions::Completions, context::CompletionContext};
pub use crate::{
config::CompletionConfig,

View File

@ -22,7 +22,7 @@ use crate::{
context::{PathCompletionContext, PathKind},
item::{CompletionRelevanceTypeMatch, ImportEdit},
render::{enum_variant::render_variant, function::render_fn, macro_::render_macro},
CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance,
CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
};
/// Interface for data and methods required for items rendering.
#[derive(Debug)]
@ -85,7 +85,7 @@ pub(crate) fn render_field(
let is_deprecated = ctx.is_deprecated(field);
let name = field.name(ctx.db()).to_string();
let mut item = CompletionItem::new(
CompletionKind::Reference,
SymbolKind::Field,
ctx.source_range(),
receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)),
);
@ -94,8 +94,7 @@ pub(crate) fn render_field(
exact_name_match: compute_exact_name_match(ctx.completion, name.as_str()),
..CompletionRelevance::default()
});
item.kind(SymbolKind::Field)
.detail(ty.display(ctx.db()).to_string())
item.detail(ty.display(ctx.db()).to_string())
.set_documentation(field.docs(ctx.db()))
.set_deprecated(is_deprecated)
.lookup_by(name.as_str());
@ -118,13 +117,11 @@ pub(crate) fn render_tuple_field(
ty: &hir::Type,
) -> CompletionItem {
let mut item = CompletionItem::new(
CompletionKind::Reference,
SymbolKind::Field,
ctx.source_range(),
receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)),
);
item.kind(SymbolKind::Field)
.detail(ty.display(ctx.db()).to_string())
.lookup_by(field.to_string());
item.detail(ty.display(ctx.db()).to_string()).lookup_by(field.to_string());
item.build()
}
@ -147,10 +144,7 @@ pub(crate) fn render_resolution_with_import(
hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db),
_ => item_name(ctx.db(), import_edit.import.original_item)?,
};
render_resolution_(ctx, local_name, Some(import_edit), &resolution).map(|mut item| {
item.completion_kind = CompletionKind::Magic;
item
})
render_resolution_(ctx, local_name, Some(import_edit), &resolution)
}
fn render_resolution_(
@ -162,11 +156,6 @@ fn render_resolution_(
let _p = profile::span("render_resolution");
use hir::ModuleDef::*;
let completion_kind = match resolution {
hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType,
_ => CompletionKind::Reference,
};
let kind = match resolution {
hir::ScopeDef::ModuleDef(Function(func)) => {
return render_fn(ctx, import_to_add, Some(local_name), *func);
@ -208,11 +197,10 @@ fn render_resolution_(
}
hir::ScopeDef::Unknown => {
let mut item = CompletionItem::new(
CompletionKind::Reference,
CompletionItemKind::UnresolvedReference,
ctx.source_range(),
local_name.to_string(),
);
item.kind(CompletionItemKind::UnresolvedReference);
if let Some(import_to_add) = import_to_add {
item.add_import(import_to_add);
}
@ -221,7 +209,7 @@ fn render_resolution_(
};
let local_name = local_name.to_string();
let mut item = CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone());
let mut item = CompletionItem::new(kind, ctx.source_range(), local_name.clone());
if let hir::ScopeDef::Local(local) = resolution {
let ty = local.ty(ctx.db());
if !ty.is_unknown() {
@ -260,8 +248,7 @@ fn render_resolution_(
}
}
}
item.kind(kind)
.set_documentation(scope_def_docs(ctx.db(), resolution))
item.set_documentation(scope_def_docs(ctx.db(), resolution))
.set_deprecated(scope_def_is_deprecated(&ctx, resolution));
if let Some(import_to_add) = import_to_add {
@ -344,37 +331,54 @@ mod tests {
use std::cmp;
use expect_test::{expect, Expect};
use ide_db::SymbolKind;
use itertools::Itertools;
use crate::{
item::CompletionRelevanceTypeMatch,
tests::{check_edit, do_completion, get_all_items, TEST_CONFIG},
CompletionKind, CompletionRelevance,
CompletionItem, CompletionItemKind, CompletionRelevance,
};
#[track_caller]
fn check(ra_fixture: &str, expect: Expect) {
let actual = do_completion(ra_fixture, CompletionKind::Reference);
fn check(ra_fixture: &str, kind: impl Into<CompletionItemKind>, expect: Expect) {
let actual = do_completion(ra_fixture, kind.into());
expect.assert_debug_eq(&actual);
}
#[track_caller]
fn check_relevance(ra_fixture: &str, expect: Expect) {
check_relevance_for_kinds(&[CompletionKind::Reference], ra_fixture, expect)
fn check_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect) {
let actual: Vec<_> =
kinds.iter().flat_map(|&kind| do_completion(ra_fixture, kind)).collect();
expect.assert_debug_eq(&actual);
}
#[track_caller]
fn check_relevance_for_kinds(kinds: &[CompletionKind], ra_fixture: &str, expect: Expect) {
fn check_relevance_for_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect) {
let mut actual = get_all_items(TEST_CONFIG, ra_fixture);
actual.retain(|it| kinds.contains(&it.completion_kind));
actual.retain(|it| kinds.contains(&it.kind()));
actual.sort_by_key(|it| cmp::Reverse(it.relevance().score()));
check_relevance_(actual, expect);
}
#[track_caller]
fn check_relevance(ra_fixture: &str, expect: Expect) {
let mut actual = get_all_items(TEST_CONFIG, ra_fixture);
actual.retain(|it| it.kind() != CompletionItemKind::Snippet);
actual.retain(|it| it.kind() != CompletionItemKind::Keyword);
actual.retain(|it| it.kind() != CompletionItemKind::BuiltinType);
actual.sort_by_key(|it| cmp::Reverse(it.relevance().score()));
check_relevance_(actual, expect);
}
#[track_caller]
fn check_relevance_(actual: Vec<CompletionItem>, expect: Expect) {
let actual = actual
.into_iter()
.flat_map(|it| {
let mut items = vec![];
let tag = it.kind().unwrap().tag();
let tag = it.kind().tag();
let relevance = display_relevance(it.relevance());
items.push(format!("{} {} {}\n", tag, it.label(), relevance));
@ -418,6 +422,7 @@ enum Foo { Foo { x: i32, y: i32 } }
fn main() { Foo::Fo$0 }
"#,
SymbolKind::Variant,
expect![[r#"
[
CompletionItem {
@ -443,6 +448,7 @@ enum Foo { Foo (i32, i32) }
fn main() { Foo::Fo$0 }
"#,
SymbolKind::Variant,
expect![[r#"
[
CompletionItem {
@ -470,6 +476,7 @@ fn foo<T>(a: u32, b: u32, t: T) -> (u32, T) { (a, t) }
fn main() { fo$0 }
"#,
SymbolKind::Function,
expect![[r#"
[
CompletionItem {
@ -508,6 +515,7 @@ enum Foo { Foo }
fn main() { Foo::Fo$0 }
"#,
SymbolKind::Variant,
expect![[r#"
[
CompletionItem {
@ -527,15 +535,40 @@ fn main() { Foo::Fo$0 }
#[test]
fn lookup_enums_by_two_qualifiers() {
check(
check_kinds(
r#"
mod m {
pub enum Spam { Foo, Bar(i32) }
}
fn main() { let _: m::Spam = S$0 }
"#,
&[
CompletionItemKind::SymbolKind(SymbolKind::Function),
CompletionItemKind::SymbolKind(SymbolKind::Module),
CompletionItemKind::SymbolKind(SymbolKind::Variant),
],
expect![[r#"
[
CompletionItem {
label: "main()",
source_range: 75..76,
delete: 75..76,
insert: "main()$0",
kind: SymbolKind(
Function,
),
lookup: "main",
detail: "fn()",
},
CompletionItem {
label: "m",
source_range: 75..76,
delete: 75..76,
insert: "m",
kind: SymbolKind(
Module,
),
},
CompletionItem {
label: "Spam::Bar(…)",
source_range: 75..76,
@ -556,15 +589,6 @@ fn main() { let _: m::Spam = S$0 }
},
trigger_call_info: true,
},
CompletionItem {
label: "m",
source_range: 75..76,
delete: 75..76,
insert: "m",
kind: SymbolKind(
Module,
),
},
CompletionItem {
label: "m::Spam::Foo",
source_range: 75..76,
@ -584,17 +608,6 @@ fn main() { let _: m::Spam = S$0 }
exact_postfix_snippet_match: false,
},
},
CompletionItem {
label: "main()",
source_range: 75..76,
delete: 75..76,
insert: "main()$0",
kind: SymbolKind(
Function,
),
lookup: "main",
detail: "fn()",
},
]
"#]],
)
@ -611,6 +624,7 @@ fn something_else_deprecated() {}
fn main() { som$0 }
"#,
SymbolKind::Function,
expect![[r#"
[
CompletionItem {
@ -657,6 +671,7 @@ fn main() { som$0 }
struct A { #[deprecated] the_field: u32 }
fn foo() { A { the$0 } }
"#,
SymbolKind::Field,
expect![[r#"
[
CompletionItem {
@ -685,7 +700,7 @@ fn foo() { A { the$0 } }
#[test]
fn renders_docs() {
check(
check_kinds(
r#"
struct S {
/// Field docs
@ -695,6 +710,7 @@ impl S {
/// Method docs
fn bar(self) { self.$0 }
}"#,
&[CompletionItemKind::Method, CompletionItemKind::SymbolKind(SymbolKind::Field)],
expect![[r#"
[
CompletionItem {
@ -726,7 +742,7 @@ impl S {
"#]],
);
check(
check_kinds(
r#"
use self::my$0;
@ -740,18 +756,23 @@ enum E {
}
use self::E::*;
"#,
&[
CompletionItemKind::SymbolKind(SymbolKind::Module),
CompletionItemKind::SymbolKind(SymbolKind::Variant),
CompletionItemKind::SymbolKind(SymbolKind::Enum),
],
expect![[r#"
[
CompletionItem {
label: "E",
label: "my",
source_range: 10..12,
delete: 10..12,
insert: "E",
insert: "my",
kind: SymbolKind(
Enum,
Module,
),
documentation: Documentation(
"enum docs",
"mod docs",
),
},
CompletionItem {
@ -768,15 +789,15 @@ use self::E::*;
),
},
CompletionItem {
label: "my",
label: "E",
source_range: 10..12,
delete: 10..12,
insert: "my",
insert: "E",
kind: SymbolKind(
Module,
Enum,
),
documentation: Documentation(
"mod docs",
"enum docs",
),
},
]
@ -795,6 +816,7 @@ impl S {
}
fn foo(s: S) { s.$0 }
"#,
CompletionItemKind::Method,
expect![[r#"
[
CompletionItem {
@ -1318,18 +1340,28 @@ fn main() {
#[test]
fn struct_field_method_ref() {
check(
check_kinds(
r#"
struct Foo { bar: u32 }
impl Foo { fn baz(&self) -> u32 { 0 } }
fn foo(f: Foo) { let _: &u32 = f.b$0 }
"#,
&[CompletionItemKind::Method, CompletionItemKind::SymbolKind(SymbolKind::Field)],
// FIXME
// Ideally we'd also suggest &f.bar and &f.baz() as exact
// type matches. See #8058.
expect![[r#"
[
CompletionItem {
label: "baz()",
source_range: 98..99,
delete: 98..99,
insert: "baz()$0",
kind: Method,
lookup: "baz",
detail: "fn(&self) -> u32",
},
CompletionItem {
label: "bar",
source_range: 98..99,
@ -1340,15 +1372,6 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 }
),
detail: "u32",
},
CompletionItem {
label: "baz()",
source_range: 98..99,
delete: 98..99,
insert: "baz()$0",
kind: Method,
lookup: "baz",
detail: "fn(&self) -> u32",
},
]
"#]],
);
@ -1387,7 +1410,6 @@ fn foo() {
#[test]
fn postfix_completion_relevance() {
check_relevance_for_kinds(
&[CompletionKind::Postfix, CompletionKind::Magic],
r#"
mod ops {
pub trait Not {
@ -1404,7 +1426,8 @@ mod ops {
fn main() {
let _: bool = (9 > 2).not$0;
}
"#,
"#,
&[CompletionItemKind::Snippet, CompletionItemKind::Method],
expect![[r#"
sn not [snippet]
me not() (use ops::Not) [type_could_unify]

View File

@ -7,10 +7,7 @@ use syntax::{
display::const_label,
};
use crate::{
item::{CompletionItem, CompletionKind},
render::RenderContext,
};
use crate::{item::CompletionItem, render::RenderContext};
pub(crate) fn render_const(ctx: RenderContext<'_>, const_: hir::Const) -> Option<CompletionItem> {
ConstRender::new(ctx, const_)?.render()
@ -34,9 +31,8 @@ impl<'a> ConstRender<'a> {
let detail = self.detail();
let mut item =
CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name.clone());
item.kind(SymbolKind::Const)
.set_documentation(self.ctx.docs(self.const_))
CompletionItem::new(SymbolKind::Const, self.ctx.source_range(), name.clone());
item.set_documentation(self.ctx.docs(self.const_))
.set_deprecated(
self.ctx.is_deprecated(self.const_)
|| self.ctx.is_deprecated_assoc_item(self.const_),

View File

@ -7,7 +7,7 @@ use ide_db::SymbolKind;
use itertools::Itertools;
use crate::{
item::{CompletionItem, CompletionKind, ImportEdit},
item::{CompletionItem, ImportEdit},
render::{builder_ext::Params, compute_ref_match, compute_type_match, RenderContext},
CompletionRelevance,
};
@ -61,12 +61,11 @@ impl<'a> EnumRender<'a> {
}
fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
let mut item = CompletionItem::new(
CompletionKind::Reference,
SymbolKind::Variant,
self.ctx.source_range(),
self.qualified_name.to_string(),
);
item.kind(SymbolKind::Variant)
.set_documentation(self.variant.docs(self.ctx.db()))
item.set_documentation(self.variant.docs(self.ctx.db()))
.set_deprecated(self.ctx.is_deprecated(self.variant))
.detail(self.detail());

View File

@ -7,7 +7,7 @@ use itertools::Itertools;
use syntax::ast;
use crate::{
item::{CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, ImportEdit},
item::{CompletionItem, CompletionItemKind, CompletionRelevance, ImportEdit},
render::{
builder_ext::Params, compute_exact_name_match, compute_ref_match, compute_type_match,
RenderContext,
@ -79,10 +79,8 @@ impl<'a> FunctionRender<'a> {
Some(receiver) => format!("{}.{}", receiver, &self.name),
None => self.name.clone(),
};
let mut item =
CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), call.clone());
item.kind(self.kind())
.set_documentation(self.ctx.docs(self.func))
let mut item = CompletionItem::new(self.kind(), self.ctx.source_range(), call.clone());
item.set_documentation(self.ctx.docs(self.func))
.set_deprecated(
self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func),
)

View File

@ -6,7 +6,7 @@ use syntax::display::macro_label;
use crate::{
context::CallKind,
item::{CompletionItem, CompletionKind, ImportEdit},
item::{CompletionItem, ImportEdit},
render::RenderContext,
};
@ -47,9 +47,8 @@ impl<'a> MacroRender<'a> {
} else {
Some(self.ctx.source_range())
}?;
let mut item = CompletionItem::new(CompletionKind::Reference, source_range, &self.label());
item.kind(SymbolKind::Macro)
.set_documentation(self.docs.clone())
let mut item = CompletionItem::new(SymbolKind::Macro, source_range, &self.label());
item.set_documentation(self.docs.clone())
.set_deprecated(self.ctx.is_deprecated(self.macro_))
.set_detail(self.detail());

View File

@ -6,7 +6,6 @@ use itertools::Itertools;
use crate::{
context::{ParamKind, PatternContext},
item::CompletionKind,
render::RenderContext,
CompletionItem, CompletionItemKind,
};
@ -58,11 +57,8 @@ fn build_completion(
pat: String,
def: impl HasAttrs + Copy,
) -> CompletionItem {
let mut item = CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), name);
item.kind(CompletionItemKind::Binding)
.set_documentation(ctx.docs(def))
.set_deprecated(ctx.is_deprecated(def))
.detail(&pat);
let mut item = CompletionItem::new(CompletionItemKind::Binding, ctx.source_range(), name);
item.set_documentation(ctx.docs(def)).set_deprecated(ctx.is_deprecated(def)).detail(&pat);
match ctx.snippet_cap() {
Some(snippet_cap) => item.insert_snippet(snippet_cap, pat),
None => item.insert_text(pat),

View File

@ -4,7 +4,7 @@ use hir::{db::HirDatabase, HasAttrs, HasVisibility, Name, StructKind};
use ide_db::helpers::SnippetCap;
use itertools::Itertools;
use crate::{item::CompletionKind, render::RenderContext, CompletionItem, CompletionItemKind};
use crate::{render::RenderContext, CompletionItem, CompletionItemKind};
pub(crate) fn render_struct_literal(
ctx: RenderContext<'_>,
@ -33,11 +33,9 @@ fn build_completion(
literal: String,
def: impl HasAttrs + Copy,
) -> CompletionItem {
let mut item = CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), name + " {…}");
item.kind(CompletionItemKind::Snippet)
.set_documentation(ctx.docs(def))
.set_deprecated(ctx.is_deprecated(def))
.detail(&literal);
let mut item =
CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), name + " {…}");
item.set_documentation(ctx.docs(def)).set_deprecated(ctx.is_deprecated(def)).detail(&literal);
match ctx.snippet_cap() {
Some(snippet_cap) => item.insert_snippet(snippet_cap, literal),
None => item.insert_text(literal),

View File

@ -7,10 +7,7 @@ use syntax::{
display::type_label,
};
use crate::{
item::{CompletionItem, CompletionKind},
render::RenderContext,
};
use crate::{item::CompletionItem, render::RenderContext};
pub(crate) fn render_type_alias(
ctx: RenderContext<'_>,
@ -50,9 +47,8 @@ impl<'a> TypeAliasRender<'a> {
let detail = self.detail();
let mut item =
CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name.clone());
item.kind(SymbolKind::TypeAlias)
.set_documentation(self.ctx.docs(self.type_alias))
CompletionItem::new(SymbolKind::TypeAlias, self.ctx.source_range(), name.clone());
item.set_documentation(self.ctx.docs(self.type_alias))
.set_deprecated(
self.ctx.is_deprecated(self.type_alias)
|| self.ctx.is_deprecated_assoc_item(self.type_alias),

View File

@ -20,6 +20,7 @@ mod record;
mod type_pos;
mod use_tree;
mod visibility;
mod flyimport;
use std::mem;
@ -37,7 +38,7 @@ use stdx::{format_to, trim_indent};
use syntax::{AstNode, NodeOrToken, SyntaxElement};
use test_utils::assert_eq_text;
use crate::{item::CompletionKind, CompletionConfig, CompletionItem};
use crate::{CompletionConfig, CompletionItem, CompletionItemKind};
/// Lots of basic item definitions
const BASE_ITEMS_FIXTURE: &str = r#"
@ -77,18 +78,28 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
};
pub(crate) fn completion_list(ra_fixture: &str) -> String {
completion_list_with_config(TEST_CONFIG, ra_fixture)
completion_list_with_config(TEST_CONFIG, ra_fixture, true)
}
fn completion_list_with_config(config: CompletionConfig, ra_fixture: &str) -> String {
pub(crate) fn completion_list_no_kw(ra_fixture: &str) -> String {
completion_list_with_config(TEST_CONFIG, ra_fixture, false)
}
fn completion_list_with_config(
config: CompletionConfig,
ra_fixture: &str,
include_keywords: bool,
) -> String {
// filter out all but one builtintype completion for smaller test outputs
let items = get_all_items(config, ra_fixture);
let mut bt_seen = false;
let items = items
.into_iter()
.filter(|it| {
it.completion_kind != CompletionKind::BuiltinType || !mem::replace(&mut bt_seen, true)
it.kind() != CompletionItemKind::BuiltinType || !mem::replace(&mut bt_seen, true)
})
.filter(|it| include_keywords || it.kind() != CompletionItemKind::Keyword)
.filter(|it| include_keywords || it.kind() != CompletionItemKind::Snippet)
.collect();
render_completion_list(items)
}
@ -104,36 +115,22 @@ pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
(database, FilePosition { file_id, offset })
}
pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> {
pub(crate) fn do_completion(code: &str, kind: CompletionItemKind) -> Vec<CompletionItem> {
do_completion_with_config(TEST_CONFIG, code, kind)
}
pub(crate) fn do_completion_with_config(
config: CompletionConfig,
code: &str,
kind: CompletionKind,
kind: CompletionItemKind,
) -> Vec<CompletionItem> {
get_all_items(config, code)
.into_iter()
.filter(|c| c.completion_kind == kind)
.filter(|c| c.kind() == kind)
.sorted_by(|l, r| l.label().cmp(r.label()))
.collect()
}
pub(crate) fn filtered_completion_list(code: &str, kind: CompletionKind) -> String {
filtered_completion_list_with_config(TEST_CONFIG, code, kind)
}
pub(crate) fn filtered_completion_list_with_config(
config: CompletionConfig,
code: &str,
kind: CompletionKind,
) -> String {
let kind_completions: Vec<CompletionItem> =
get_all_items(config, code).into_iter().filter(|c| c.completion_kind == kind).collect();
render_completion_list(kind_completions)
}
fn render_completion_list(completions: Vec<CompletionItem>) -> String {
fn monospace_width(s: &str) -> usize {
s.chars().count()
@ -143,7 +140,7 @@ fn render_completion_list(completions: Vec<CompletionItem>) -> String {
completions
.into_iter()
.map(|it| {
let tag = it.kind().unwrap().tag();
let tag = it.kind().tag();
let var_name = format!("{} {}", tag, it.label());
let mut buf = var_name;
if let Some(detail) = it.detail() {
@ -254,3 +251,37 @@ fn foo() {
"#,
);
}
#[test]
fn no_completions_in_comments() {
cov_mark::check!(no_keyword_completion_in_comments);
assert_eq!(
completion_list(
r#"
fn test() {
let x = 2; // A comment$0
}
"#,
),
String::new(),
);
assert_eq!(
completion_list(
r#"
/*
Some multi-line comment$0
*/
"#,
),
String::new(),
);
assert_eq!(
completion_list(
r#"
/// Some doc comment
/// let test$0 = 1
"#,
),
String::new(),
);
}

View File

@ -110,7 +110,7 @@ fn func(param0 @ (param1, param2): (i32, i32)) {
}
#[test]
fn completes_all_the_things() {
fn completes_all_the_things_in_fn_body() {
cov_mark::check!(unqualified_skip_lifetime_completion);
check(
r#"
@ -206,6 +206,223 @@ impl Unit {
);
}
#[test]
fn complete_in_block() {
check_empty(
r#"
fn foo() {
if true {
$0
}
}
"#,
expect![[r#"
kw unsafe
kw fn
kw const
kw type
kw impl
kw extern
kw use
kw trait
kw static
kw mod
kw match
kw while
kw while let
kw loop
kw if
kw if let
kw for
kw true
kw false
kw let
kw return
sn pd
sn ppd
kw self
kw super
kw crate
fn foo() fn()
bt u32
"#]],
)
}
#[test]
fn complete_after_if_expr() {
check_empty(
r#"
fn foo() {
if true {}
$0
}
"#,
expect![[r#"
kw unsafe
kw fn
kw const
kw type
kw impl
kw extern
kw use
kw trait
kw static
kw mod
kw match
kw while
kw while let
kw loop
kw if
kw if let
kw for
kw true
kw false
kw let
kw else
kw else if
kw return
sn pd
sn ppd
kw self
kw super
kw crate
fn foo() fn()
bt u32
"#]],
)
}
#[test]
fn complete_in_match_arm() {
check_empty(
r#"
fn foo() {
match () {
() => $0
}
}
"#,
expect![[r#"
kw unsafe
kw match
kw while
kw while let
kw loop
kw if
kw if let
kw for
kw true
kw false
kw return
kw self
kw super
kw crate
fn foo() fn()
bt u32
"#]],
)
}
#[test]
fn completes_in_loop_ctx() {
check_empty(
r"fn my() { loop { $0 } }",
expect![[r#"
kw unsafe
kw fn
kw const
kw type
kw impl
kw extern
kw use
kw trait
kw static
kw mod
kw match
kw while
kw while let
kw loop
kw if
kw if let
kw for
kw true
kw false
kw let
kw continue
kw break
kw return
sn pd
sn ppd
kw self
kw super
kw crate
fn my() fn()
bt u32
"#]],
);
}
#[test]
fn completes_in_let_initializer() {
check_empty(
r#"fn main() { let _ = $0 }"#,
expect![[r#"
kw unsafe
kw match
kw while
kw while let
kw loop
kw if
kw if let
kw for
kw true
kw false
kw return
kw self
kw super
kw crate
fn main() fn()
bt u32
"#]],
)
}
#[test]
fn struct_initializer_field_expr() {
check_empty(
r#"
struct Foo {
pub f: i32,
}
fn foo() {
Foo {
f: $0
}
}
"#,
expect![[r#"
kw unsafe
kw match
kw while
kw while let
kw loop
kw if
kw if let
kw for
kw true
kw false
kw return
kw self
kw super
kw crate
st Foo
fn foo() fn()
bt u32
"#]],
);
}
#[test]
fn shadowing_shows_single_completion() {
cov_mark::check!(shadowing_shows_single_completion);

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,7 @@ fn check(ra_fixture: &str, expect: Expect) {
#[test]
fn without_default_impl() {
cov_mark::check!(no_keyword_completion_in_record_lit);
check(
r#"
struct Struct { foo: u32, bar: usize }

View File

@ -248,7 +248,7 @@ fn completion_item(
label: item.label().to_string(),
detail: item.detail().map(|it| it.to_string()),
filter_text: Some(item.lookup().to_string()),
kind: item.kind().map(completion_item_kind),
kind: Some(completion_item_kind(item.kind())),
text_edit: Some(text_edit),
additional_text_edits: Some(additional_text_edits),
documentation: item.documentation().map(documentation),

View File

@ -313,6 +313,7 @@ fn check_dbg(path: &Path, text: &str) {
"handlers/remove_dbg.rs",
// We have .dbg postfix
"ide_completion/src/completions/postfix.rs",
"ide_completion/src/completions/keyword.rs",
"ide_completion/src/tests/proc_macros.rs",
// The documentation in string literals may contain anything for its own purposes
"ide_completion/src/lib.rs",