Only complete modules in empty use-statements

This commit is contained in:
Lukas Wirth 2021-05-28 02:40:40 +02:00
parent 01bfc5f5c0
commit 9e71dd9799
3 changed files with 27 additions and 14 deletions

View file

@ -1,7 +1,6 @@
//! Completion of names from the current scope, e.g. locals and imported items. //! Completion of names from the current scope, e.g. locals and imported items.
use hir::ScopeDef; use hir::ScopeDef;
use syntax::AstNode;
use crate::{CompletionContext, Completions}; use crate::{CompletionContext, Completions};
@ -24,6 +23,15 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
return; return;
} }
if ctx.expects_use_tree() {
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.to_string(), &res);
}
});
return;
}
if let Some(hir::Adt::Enum(e)) = if let Some(hir::Adt::Enum(e)) =
ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt())
{ {
@ -37,14 +45,6 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
cov_mark::hit!(skip_lifetime_completion); cov_mark::hit!(skip_lifetime_completion);
return; return;
} }
if ctx.use_item_syntax.is_some() {
if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) {
if name_ref.syntax().text() == name.to_string().as_str() {
cov_mark::hit!(self_fulfilling_completion);
return;
}
}
}
acc.add_resolution(ctx, name.to_string(), &res); acc.add_resolution(ctx, name.to_string(), &res);
}); });
} }
@ -68,15 +68,17 @@ mod tests {
} }
#[test] #[test]
fn self_fulfilling_completion() { fn only_completes_modules_in_import() {
cov_mark::check!(self_fulfilling_completion); cov_mark::check!(only_completes_modules_in_import);
check( check(
r#" r#"
use foo$0 use f$0
use std::collections;
struct Foo;
mod foo {}
"#, "#,
expect![[r#" expect![[r#"
?? collections md foo
"#]], "#]],
); );
} }

View file

@ -276,6 +276,10 @@ impl<'a> CompletionContext<'a> {
) )
} }
pub(crate) fn expects_use_tree(&self) -> bool {
matches!(self.completion_location, Some(ImmediateLocation::Use))
}
pub(crate) fn expects_non_trait_assoc_item(&self) -> bool { pub(crate) fn expects_non_trait_assoc_item(&self) -> bool {
matches!(self.completion_location, Some(ImmediateLocation::Impl)) matches!(self.completion_location, Some(ImmediateLocation::Impl))
} }

View file

@ -14,6 +14,7 @@ use crate::test_utils::{check_pattern_is_applicable, check_pattern_is_not_applic
/// Direct parent container of the cursor position /// Direct parent container of the cursor position
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum ImmediateLocation { pub(crate) enum ImmediateLocation {
Use,
Impl, Impl,
Trait, Trait,
RecordField, RecordField,
@ -58,6 +59,7 @@ pub(crate) fn determine_location(tok: SyntaxToken) -> Option<ImmediateLocation>
let res = match_ast! { let res = match_ast! {
match parent { match parent {
ast::IdentPat(_it) => ImmediateLocation::IdentPat, ast::IdentPat(_it) => ImmediateLocation::IdentPat,
ast::Use(_it) => ImmediateLocation::Use,
ast::BlockExpr(_it) => ImmediateLocation::BlockExpr, ast::BlockExpr(_it) => ImmediateLocation::BlockExpr,
ast::SourceFile(_it) => ImmediateLocation::ItemList, ast::SourceFile(_it) => ImmediateLocation::ItemList,
ast::ItemList(_it) => ImmediateLocation::ItemList, ast::ItemList(_it) => ImmediateLocation::ItemList,
@ -87,6 +89,11 @@ fn test_has_trait_parent() {
check_location(r"trait A { f$0 }", ImmediateLocation::Trait); check_location(r"trait A { f$0 }", ImmediateLocation::Trait);
} }
#[test]
fn test_has_use_parent() {
check_location(r"use f$0", ImmediateLocation::Use);
}
#[test] #[test]
fn test_has_impl_parent() { fn test_has_impl_parent() {
check_location(r"impl A { f$0 }", ImmediateLocation::Impl); check_location(r"impl A { f$0 }", ImmediateLocation::Impl);