Complete crate, super and self in non-usetree paths

This commit is contained in:
Lukas Wirth 2021-07-07 19:08:37 +02:00
parent 2b6770c936
commit 9f9cc72ee5
10 changed files with 126 additions and 57 deletions

View File

@ -74,6 +74,12 @@ pub(crate) fn add_all<I>(&mut self, items: I)
items.into_iter().for_each(|item| self.add(item.into()))
}
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);
item.add_to(self);
}
pub(crate) fn add_resolution(
&mut self,
ctx: &CompletionContext,

View File

@ -1,7 +1,5 @@
//! Completes keywords.
use std::iter;
use syntax::{SyntaxKind, T};
use crate::{
@ -9,36 +7,6 @@
CompletionItemKind, CompletionKind, Completions,
};
pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) {
// complete keyword "crate" in use stmt
let source_range = ctx.source_range();
let kw_completion = move |text: &str| {
let mut item = CompletionItem::new(CompletionKind::Keyword, source_range, text);
item.kind(CompletionItemKind::Keyword).insert_text(text);
item
};
if ctx.in_use_tree() {
match &ctx.path_context {
Some(PathCompletionContext { qualifier: Some(qual), use_tree_parent, .. }) => {
if iter::successors(Some(qual.clone()), |p| p.qualifier())
.all(|p| p.segment().and_then(|s| s.super_token()).is_some())
{
kw_completion("super::").add_to(acc);
}
if *use_tree_parent {
kw_completion("self").add_to(acc);
}
}
_ => {
kw_completion("crate::").add_to(acc);
kw_completion("self::").add_to(acc);
kw_completion("super::").add_to(acc);
}
};
}
}
pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
if ctx.token.kind() == SyntaxKind::COMMENT {
cov_mark::hit!(no_keyword_completion_in_comments);
@ -243,6 +211,9 @@ fn test_keywords_in_function() {
kw for
kw let
kw return
kw self
kw super
kw crate
"#]],
);
}
@ -271,6 +242,9 @@ fn test_keywords_inside_block() {
kw for
kw let
kw return
kw self
kw super
kw crate
"#]],
);
}
@ -301,6 +275,9 @@ fn test_keywords_after_if() {
kw else
kw else if
kw return
kw self
kw super
kw crate
"#]],
);
check_edit(
@ -330,6 +307,9 @@ fn quux() -> i32 {
kw if let
kw for
kw return
kw self
kw super
kw crate
"#]],
);
}
@ -360,6 +340,9 @@ fn test_keywords_in_loop() {
kw continue
kw break
kw return
kw self
kw super
kw crate
"#]],
);
}
@ -448,6 +431,9 @@ fn after_let() {
kw if let
kw for
kw return
kw self
kw super
kw crate
"#]],
)
}
@ -493,6 +479,9 @@ fn foo() {
kw if let
kw for
kw return
kw self
kw super
kw crate
"#]],
);
}

View File

@ -1,18 +1,22 @@
//! Completion of paths, i.e. `some::prefix::$0`.
use std::iter;
use hir::HasVisibility;
use rustc_hash::FxHashSet;
use syntax::AstNode;
use syntax::{ast, AstNode};
use crate::{CompletionContext, Completions};
use crate::{context::PathCompletionContext, CompletionContext, Completions};
pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) {
if ctx.is_path_disallowed() {
return;
}
let path = match ctx.path_qual() {
Some(path) => path,
None => return,
let (path, use_tree_parent) = match &ctx.path_context {
Some(PathCompletionContext { qualifier: Some(qualifier), use_tree_parent, .. }) => {
(qualifier, *use_tree_parent)
}
_ => return,
};
let resolution = match ctx.sema.resolve_path(path) {
@ -39,6 +43,23 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
return;
}
if ctx.in_use_tree() {
if iter::successors(Some(path.clone()), |p| p.qualifier())
.all(|p| p.segment().and_then(|s| s.super_token()).is_some())
{
acc.add_keyword(ctx, "super::");
}
// only show `self` in a new use-tree when the qualifier doesn't end in self
if use_tree_parent
&& !matches!(
path.segment().and_then(|it| it.kind()),
Some(ast::PathSegmentKind::SelfKw)
)
{
acc.add_keyword(ctx, "self");
}
}
// Add associated types on type parameters and `Self`.
resolution.assoc_type_shorthand_candidates(ctx.db, |_, alias| {
acc.add_type_alias(ctx, alias);

View File

@ -10,6 +10,21 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
return;
}
if ctx.in_use_tree() {
// only show modules in a fresh UseTree
cov_mark::hit!(only_completes_modules_in_import);
ctx.scope.process_all_names(&mut |name, res| {
if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
acc.add_resolution(ctx, name, &res);
}
});
std::array::IntoIter::new(["self::", "super::", "crate::"])
.for_each(|kw| acc.add_keyword(ctx, kw));
return;
}
std::array::IntoIter::new(["self", "super", "crate"]).for_each(|kw| acc.add_keyword(ctx, kw));
if ctx.expects_item() || ctx.expects_assoc_item() {
// only show macros in {Assoc}ItemList
ctx.scope.process_all_names(&mut |name, res| {
@ -25,17 +40,6 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
return;
}
if ctx.in_use_tree() {
// only show modules in a fresh UseTree
cov_mark::hit!(only_completes_modules_in_import);
ctx.scope.process_all_names(&mut |name, res| {
if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
acc.add_resolution(ctx, name, &res);
}
});
return;
}
if matches!(&ctx.completion_location, Some(ImmediateLocation::TypeBound)) {
ctx.scope.process_all_names(&mut |name, res| {
let add_resolution = match res {

View File

@ -150,7 +150,6 @@ pub fn completions(
completions::attribute::complete_attribute(&mut acc, &ctx);
completions::fn_param::complete_fn_param(&mut acc, &ctx);
completions::keyword::complete_expr_keyword(&mut acc, &ctx);
completions::keyword::complete_use_tree_keyword(&mut acc, &ctx);
completions::snippet::complete_expr_snippet(&mut acc, &ctx);
completions::snippet::complete_item_snippet(&mut acc, &ctx);
completions::qualified_path::complete_qualified_path(&mut acc, &ctx);

View File

@ -30,6 +30,9 @@ fn in_mod_item_list() {
sn tmod (Test module)
sn tfn (Test function)
sn macro_rules
kw self
kw super
kw crate
ma makro!() #[macro_export] macro_rules! makro
"##]],
)
@ -58,6 +61,9 @@ fn in_source_file_item_list() {
sn tmod (Test module)
sn tfn (Test function)
sn macro_rules
kw self
kw super
kw crate
ma makro!() #[macro_export] macro_rules! makro
md module
ma makro!() #[macro_export] macro_rules! makro
@ -174,6 +180,9 @@ fn in_impl_assoc_item_list() {
kw fn
kw const
kw type
kw self
kw super
kw crate
ma makro!() #[macro_export] macro_rules! makro
md module
ma makro!() #[macro_export] macro_rules! makro
@ -205,6 +214,9 @@ fn in_trait_assoc_item_list() {
kw fn
kw const
kw type
kw self
kw super
kw crate
md module
ma makro!() #[macro_export] macro_rules! makro
ma makro!() #[macro_export] macro_rules! makro

View File

@ -18,6 +18,9 @@ fn target_type_or_trait_in_impl_block() {
impl Tra$0
"#,
expect![[r##"
kw self
kw super
kw crate
tt Trait
en Enum
st Record
@ -38,6 +41,9 @@ fn target_type_in_trait_impl_block() {
impl Trait for Str$0
"#,
expect![[r##"
kw self
kw super
kw crate
tt Trait
en Enum
st Record

View File

@ -16,6 +16,9 @@ fn predicate_start() {
struct Foo<'lt, T, const C: usize> where $0 {}
"#,
expect![[r##"
kw self
kw super
kw crate
tt Trait
en Enum
st Record
@ -38,6 +41,9 @@ fn bound_for_type_pred() {
struct Foo<'lt, T, const C: usize> where T: $0 {}
"#,
expect![[r##"
kw self
kw super
kw crate
tt Trait
md module
ma makro!() #[macro_export] macro_rules! makro
@ -54,6 +60,9 @@ fn bound_for_lifetime_pred() {
struct Foo<'lt, T, const C: usize> where 'lt: $0 {}
"#,
expect![[r##"
kw self
kw super
kw crate
tt Trait
md module
ma makro!() #[macro_export] macro_rules! makro
@ -69,6 +78,9 @@ fn bound_for_for_pred() {
struct Foo<'lt, T, const C: usize> where for<'a> T: $0 {}
"#,
expect![[r##"
kw self
kw super
kw crate
tt Trait
md module
ma makro!() #[macro_export] macro_rules! makro
@ -84,6 +96,9 @@ fn param_list_for_for_pred() {
struct Foo<'lt, T, const C: usize> where for<'a> $0 {}
"#,
expect![[r##"
kw self
kw super
kw crate
tt Trait
en Enum
st Record
@ -107,6 +122,9 @@ fn method(self) where $0 {}
}
"#,
expect![[r##"
kw self
kw super
kw crate
sp Self
tt Trait
en Enum

View File

@ -30,6 +30,9 @@ struct Foo<'lt, T, const C: usize> {
}
"#,
expect![[r#"
kw self
kw super
kw crate
sp Self
tp T
tt Trait
@ -54,6 +57,9 @@ fn tuple_struct_field() {
expect![[r#"
kw pub(crate)
kw pub
kw self
kw super
kw crate
sp Self
tp T
tt Trait
@ -76,6 +82,9 @@ fn fn_return_type() {
fn x<'lt, T, const C: usize>() -> $0
"#,
expect![[r#"
kw self
kw super
kw crate
tp T
tt Trait
en Enum
@ -99,6 +108,9 @@ fn foo<'lt, T, const C: usize>() {
}
"#,
expect![[r#"
kw self
kw super
kw crate
tp T
tt Trait
en Enum
@ -140,6 +152,9 @@ trait Trait2 {
fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {}
"#,
expect![[r#"
kw self
kw super
kw crate
ta Foo = (as Trait2) type Foo;
tp T
cp CONST_PARAM

View File

@ -22,11 +22,11 @@ mod foo {}
// nothing here
"#,
expect![[r#"
kw crate::
kw self::
kw super::
md foo
md other_crate
kw self::
kw super::
kw crate::
"#]],
);
}
@ -41,7 +41,6 @@ fn dont_complete_current_use() {
use self::{foo::*, bar$0};
"#,
expect![[r#"
kw self
st S
md foo
"#]],
@ -230,10 +229,10 @@ pub mod bar {}
pub use $0;
"#,
expect![[r#"
kw crate::
md bar
kw self::
kw super::
md bar
kw crate::
"#]],
);
}
@ -247,10 +246,10 @@ mod bar {}
use {$0};
"#,
expect![[r#"
kw crate::
md bar
kw self::
kw super::
md bar
kw crate::
"#]],
);
}