mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 11:20:54 +00:00
Merge #9310
9310: internal: Refine and test UseTree completions r=Veykril a=Veykril bors r+ Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
This commit is contained in:
commit
c82a9141ab
@ -109,7 +109,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
|
|||||||
if !ctx.config.enable_imports_on_the_fly {
|
if !ctx.config.enable_imports_on_the_fly {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if ctx.use_item_syntax.is_some()
|
if ctx.in_use_tree()
|
||||||
|| ctx.is_path_disallowed()
|
|| ctx.is_path_disallowed()
|
||||||
|| ctx.expects_item()
|
|| ctx.expects_item()
|
||||||
|| ctx.expects_assoc_item()
|
|| ctx.expects_assoc_item()
|
||||||
|
@ -18,17 +18,24 @@ pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC
|
|||||||
item
|
item
|
||||||
};
|
};
|
||||||
|
|
||||||
if ctx.use_item_syntax.is_some() {
|
if ctx.in_use_tree() {
|
||||||
let qual = ctx.path_qual();
|
match &ctx.path_context {
|
||||||
if qual.is_none() {
|
Some(PathCompletionContext { qualifier: Some(qual), use_tree_parent, .. }) => {
|
||||||
kw_completion("crate::").add_to(acc);
|
if iter::successors(Some(qual.clone()), |p| p.qualifier())
|
||||||
}
|
.all(|p| p.segment().and_then(|s| s.super_token()).is_some())
|
||||||
kw_completion("self").add_to(acc);
|
{
|
||||||
if iter::successors(qual.cloned(), |p| p.qualifier())
|
kw_completion("super::").add_to(acc);
|
||||||
.all(|p| p.segment().and_then(|s| s.super_token()).is_some())
|
}
|
||||||
{
|
if *use_tree_parent {
|
||||||
kw_completion("super::").add_to(acc);
|
kw_completion("self").add_to(acc);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
kw_completion("crate::").add_to(acc);
|
||||||
|
kw_completion("self::").add_to(acc);
|
||||||
|
kw_completion("super::").add_to(acc);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Suggest .await syntax for types that implement Future trait
|
// Suggest .await syntax for types that implement Future trait
|
||||||
@ -199,41 +206,6 @@ mod tests {
|
|||||||
expect.assert_eq(&actual)
|
expect.assert_eq(&actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_keywords_in_use_stmt() {
|
|
||||||
check(
|
|
||||||
r"use $0",
|
|
||||||
expect![[r#"
|
|
||||||
kw crate::
|
|
||||||
kw self
|
|
||||||
kw super::
|
|
||||||
"#]],
|
|
||||||
);
|
|
||||||
|
|
||||||
// FIXME: `self` shouldn't be shown here and the check below
|
|
||||||
check(
|
|
||||||
r"use a::$0",
|
|
||||||
expect![[r#"
|
|
||||||
kw self
|
|
||||||
"#]],
|
|
||||||
);
|
|
||||||
|
|
||||||
check(
|
|
||||||
r"use super::$0",
|
|
||||||
expect![[r#"
|
|
||||||
kw self
|
|
||||||
kw super::
|
|
||||||
"#]],
|
|
||||||
);
|
|
||||||
|
|
||||||
check(
|
|
||||||
r"use a::{b, $0}",
|
|
||||||
expect![[r#"
|
|
||||||
kw self
|
|
||||||
"#]],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_keywords_in_function() {
|
fn test_keywords_in_function() {
|
||||||
check(
|
check(
|
||||||
|
@ -49,7 +49,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
|||||||
hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
|
hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
|
||||||
let module_scope = module.scope(ctx.db, context_module);
|
let module_scope = module.scope(ctx.db, context_module);
|
||||||
for (name, def) in module_scope {
|
for (name, def) in module_scope {
|
||||||
if ctx.use_item_syntax.is_some() {
|
if ctx.in_use_tree() {
|
||||||
if let hir::ScopeDef::Unknown = def {
|
if let hir::ScopeDef::Unknown = def {
|
||||||
if let Some(name_ref) = ctx.name_ref_syntax.as_ref() {
|
if let Some(name_ref) = ctx.name_ref_syntax.as_ref() {
|
||||||
if name_ref.syntax().text() == name.to_string().as_str() {
|
if name_ref.syntax().text() == name.to_string().as_str() {
|
||||||
@ -212,12 +212,6 @@ mod tests {
|
|||||||
expect.assert_eq(&actual);
|
expect.assert_eq(&actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn dont_complete_current_use() {
|
|
||||||
cov_mark::check!(dont_complete_current_use);
|
|
||||||
check(r#"use self::foo$0;"#, expect![[""]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn dont_complete_values_in_type_pos() {
|
fn dont_complete_values_in_type_pos() {
|
||||||
check(
|
check(
|
||||||
@ -248,20 +242,6 @@ fn foo() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn dont_complete_current_use_in_braces_with_glob() {
|
|
||||||
check(
|
|
||||||
r#"
|
|
||||||
mod foo { pub struct S; }
|
|
||||||
use self::{foo::*, bar$0};
|
|
||||||
"#,
|
|
||||||
expect![[r#"
|
|
||||||
st S
|
|
||||||
md foo
|
|
||||||
"#]],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn dont_complete_primitive_in_use() {
|
fn dont_complete_primitive_in_use() {
|
||||||
check_builtin(r#"use self::$0;"#, expect![[""]]);
|
check_builtin(r#"use self::$0;"#, expect![[""]]);
|
||||||
@ -298,108 +278,6 @@ use self::{foo::*, bar$0};
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn completes_mod_with_same_name_as_function() {
|
|
||||||
check(
|
|
||||||
r#"
|
|
||||||
use self::my::$0;
|
|
||||||
|
|
||||||
mod my { pub struct Bar; }
|
|
||||||
fn my() {}
|
|
||||||
"#,
|
|
||||||
expect![[r#"
|
|
||||||
st Bar
|
|
||||||
"#]],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn filters_visibility() {
|
|
||||||
check(
|
|
||||||
r#"
|
|
||||||
use self::my::$0;
|
|
||||||
|
|
||||||
mod my {
|
|
||||||
struct Bar;
|
|
||||||
pub struct Foo;
|
|
||||||
pub use Bar as PublicBar;
|
|
||||||
}
|
|
||||||
"#,
|
|
||||||
expect![[r#"
|
|
||||||
st Foo
|
|
||||||
st PublicBar
|
|
||||||
"#]],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn completes_use_item_starting_with_self() {
|
|
||||||
check(
|
|
||||||
r#"
|
|
||||||
use self::m::$0;
|
|
||||||
|
|
||||||
mod m { pub struct Bar; }
|
|
||||||
"#,
|
|
||||||
expect![[r#"
|
|
||||||
st Bar
|
|
||||||
"#]],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn completes_use_item_starting_with_crate() {
|
|
||||||
check(
|
|
||||||
r#"
|
|
||||||
//- /lib.rs
|
|
||||||
mod foo;
|
|
||||||
struct Spam;
|
|
||||||
//- /foo.rs
|
|
||||||
use crate::Sp$0
|
|
||||||
"#,
|
|
||||||
expect![[r#"
|
|
||||||
md foo
|
|
||||||
st Spam
|
|
||||||
"#]],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn completes_nested_use_tree() {
|
|
||||||
check(
|
|
||||||
r#"
|
|
||||||
//- /lib.rs
|
|
||||||
mod foo;
|
|
||||||
struct Spam;
|
|
||||||
//- /foo.rs
|
|
||||||
use crate::{Sp$0};
|
|
||||||
"#,
|
|
||||||
expect![[r#"
|
|
||||||
md foo
|
|
||||||
st Spam
|
|
||||||
"#]],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn completes_deeply_nested_use_tree() {
|
|
||||||
check(
|
|
||||||
r#"
|
|
||||||
//- /lib.rs
|
|
||||||
mod foo;
|
|
||||||
pub mod bar {
|
|
||||||
pub mod baz {
|
|
||||||
pub struct Spam;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//- /foo.rs
|
|
||||||
use crate::{bar::{baz::Sp$0}};
|
|
||||||
"#,
|
|
||||||
expect![[r#"
|
|
||||||
st Spam
|
|
||||||
"#]],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn completes_enum_variant() {
|
fn completes_enum_variant() {
|
||||||
check(
|
check(
|
||||||
@ -496,22 +374,6 @@ fn foo() { let _ = U::$0 }
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn completes_use_paths_across_crates() {
|
|
||||||
check(
|
|
||||||
r#"
|
|
||||||
//- /main.rs crate:main deps:foo
|
|
||||||
use foo::$0;
|
|
||||||
|
|
||||||
//- /foo/lib.rs crate:foo
|
|
||||||
pub mod bar { pub struct S; }
|
|
||||||
"#,
|
|
||||||
expect![[r#"
|
|
||||||
md bar
|
|
||||||
"#]],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn completes_trait_associated_method_1() {
|
fn completes_trait_associated_method_1() {
|
||||||
check(
|
check(
|
||||||
@ -713,25 +575,6 @@ impl MyStruct {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_super_super_completion() {
|
|
||||||
check(
|
|
||||||
r#"
|
|
||||||
mod a {
|
|
||||||
const A: usize = 0;
|
|
||||||
mod b {
|
|
||||||
const B: usize = 0;
|
|
||||||
mod c { use super::super::$0 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"#,
|
|
||||||
expect![[r#"
|
|
||||||
md b
|
|
||||||
ct A
|
|
||||||
"#]],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn completes_reexported_items_under_correct_name() {
|
fn completes_reexported_items_under_correct_name() {
|
||||||
check(
|
check(
|
||||||
|
@ -25,7 +25,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.expects_use_tree() {
|
if ctx.in_use_tree() {
|
||||||
// only show modules in a fresh UseTree
|
// only show modules in a fresh UseTree
|
||||||
cov_mark::hit!(only_completes_modules_in_import);
|
cov_mark::hit!(only_completes_modules_in_import);
|
||||||
ctx.scope.process_all_names(&mut |name, res| {
|
ctx.scope.process_all_names(&mut |name, res| {
|
||||||
@ -129,22 +129,6 @@ fn foo() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn only_completes_modules_in_import() {
|
|
||||||
cov_mark::check!(only_completes_modules_in_import);
|
|
||||||
check(
|
|
||||||
r#"
|
|
||||||
use f$0
|
|
||||||
|
|
||||||
struct Foo;
|
|
||||||
mod foo {}
|
|
||||||
"#,
|
|
||||||
expect![[r#"
|
|
||||||
md foo
|
|
||||||
"#]],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bind_pat_and_path_ignore_at() {
|
fn bind_pat_and_path_ignore_at() {
|
||||||
check(
|
check(
|
||||||
@ -358,22 +342,6 @@ fn _alpha() {}
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn completes_extern_prelude() {
|
|
||||||
check(
|
|
||||||
r#"
|
|
||||||
//- /lib.rs crate:main deps:other_crate
|
|
||||||
use $0;
|
|
||||||
|
|
||||||
//- /other_crate/lib.rs crate:other_crate
|
|
||||||
// nothing here
|
|
||||||
"#,
|
|
||||||
expect![[r#"
|
|
||||||
md other_crate
|
|
||||||
"#]],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn completes_module_items_in_nested_modules() {
|
fn completes_module_items_in_nested_modules() {
|
||||||
check(
|
check(
|
||||||
|
@ -43,6 +43,8 @@ pub(crate) struct PathCompletionContext {
|
|||||||
pub(super) is_trivial_path: bool,
|
pub(super) is_trivial_path: bool,
|
||||||
/// If not a trivial path, the prefix (qualifier).
|
/// If not a trivial path, the prefix (qualifier).
|
||||||
pub(super) qualifier: Option<ast::Path>,
|
pub(super) qualifier: Option<ast::Path>,
|
||||||
|
/// Whether the qualifier comes from a use tree parent or not
|
||||||
|
pub(super) use_tree_parent: bool,
|
||||||
pub(super) kind: Option<PathKind>,
|
pub(super) kind: Option<PathKind>,
|
||||||
/// Whether the path segment has type args or not.
|
/// Whether the path segment has type args or not.
|
||||||
pub(super) has_type_args: bool,
|
pub(super) has_type_args: bool,
|
||||||
@ -79,7 +81,6 @@ pub(crate) struct CompletionContext<'a> {
|
|||||||
/// The parent impl of the cursor position if it exists.
|
/// The parent impl of the cursor position if it exists.
|
||||||
pub(super) impl_def: Option<ast::Impl>,
|
pub(super) impl_def: Option<ast::Impl>,
|
||||||
pub(super) name_ref_syntax: Option<ast::NameRef>,
|
pub(super) name_ref_syntax: Option<ast::NameRef>,
|
||||||
pub(super) use_item_syntax: Option<ast::Use>,
|
|
||||||
|
|
||||||
// potentially set if we are completing a lifetime
|
// potentially set if we are completing a lifetime
|
||||||
pub(super) lifetime_syntax: Option<ast::Lifetime>,
|
pub(super) lifetime_syntax: Option<ast::Lifetime>,
|
||||||
@ -151,7 +152,6 @@ impl<'a> CompletionContext<'a> {
|
|||||||
function_def: None,
|
function_def: None,
|
||||||
impl_def: None,
|
impl_def: None,
|
||||||
name_ref_syntax: None,
|
name_ref_syntax: None,
|
||||||
use_item_syntax: None,
|
|
||||||
lifetime_syntax: None,
|
lifetime_syntax: None,
|
||||||
lifetime_param_syntax: None,
|
lifetime_param_syntax: None,
|
||||||
lifetime_allowed: false,
|
lifetime_allowed: false,
|
||||||
@ -264,10 +264,6 @@ 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))
|
||||||
}
|
}
|
||||||
@ -295,6 +291,13 @@ impl<'a> CompletionContext<'a> {
|
|||||||
matches!(self.completion_location, Some(ImmediateLocation::RecordField))
|
matches!(self.completion_location, Some(ImmediateLocation::RecordField))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn in_use_tree(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self.completion_location,
|
||||||
|
Some(ImmediateLocation::Use) | Some(ImmediateLocation::UseTree)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool {
|
pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self.prev_sibling,
|
self.prev_sibling,
|
||||||
@ -578,9 +581,6 @@ impl<'a> CompletionContext<'a> {
|
|||||||
self.name_ref_syntax =
|
self.name_ref_syntax =
|
||||||
find_node_at_offset(original_file, name_ref.syntax().text_range().start());
|
find_node_at_offset(original_file, name_ref.syntax().text_range().start());
|
||||||
|
|
||||||
self.use_item_syntax =
|
|
||||||
self.sema.token_ancestors_with_macros(self.token.clone()).find_map(ast::Use::cast);
|
|
||||||
|
|
||||||
self.function_def = self
|
self.function_def = self
|
||||||
.sema
|
.sema
|
||||||
.token_ancestors_with_macros(self.token.clone())
|
.token_ancestors_with_macros(self.token.clone())
|
||||||
@ -600,6 +600,7 @@ impl<'a> CompletionContext<'a> {
|
|||||||
has_type_args: false,
|
has_type_args: false,
|
||||||
can_be_stmt: false,
|
can_be_stmt: false,
|
||||||
in_loop_body: false,
|
in_loop_body: false,
|
||||||
|
use_tree_parent: false,
|
||||||
kind: None,
|
kind: None,
|
||||||
});
|
});
|
||||||
path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax());
|
path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax());
|
||||||
@ -627,7 +628,8 @@ impl<'a> CompletionContext<'a> {
|
|||||||
}
|
}
|
||||||
path_ctx.has_type_args = segment.generic_arg_list().is_some();
|
path_ctx.has_type_args = segment.generic_arg_list().is_some();
|
||||||
|
|
||||||
if let Some(path) = path_or_use_tree_qualifier(&path) {
|
if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
|
||||||
|
path_ctx.use_tree_parent = use_tree_parent;
|
||||||
path_ctx.qualifier = path
|
path_ctx.qualifier = path
|
||||||
.segment()
|
.segment()
|
||||||
.and_then(|it| {
|
.and_then(|it| {
|
||||||
@ -681,13 +683,13 @@ fn is_node<N: AstNode>(node: &SyntaxNode) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<ast::Path> {
|
fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<(ast::Path, bool)> {
|
||||||
if let Some(qual) = path.qualifier() {
|
if let Some(qual) = path.qualifier() {
|
||||||
return Some(qual);
|
return Some((qual, false));
|
||||||
}
|
}
|
||||||
let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
|
let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
|
||||||
let use_tree = use_tree_list.syntax().parent().and_then(ast::UseTree::cast)?;
|
let use_tree = use_tree_list.syntax().parent().and_then(ast::UseTree::cast)?;
|
||||||
use_tree.path()
|
use_tree.path().zip(Some(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -27,6 +27,7 @@ pub(crate) enum ImmediatePrevSibling {
|
|||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub(crate) enum ImmediateLocation {
|
pub(crate) enum ImmediateLocation {
|
||||||
Use,
|
Use,
|
||||||
|
UseTree,
|
||||||
Impl,
|
Impl,
|
||||||
Trait,
|
Trait,
|
||||||
RecordField,
|
RecordField,
|
||||||
@ -180,6 +181,8 @@ pub(crate) fn determine_location(
|
|||||||
match parent {
|
match parent {
|
||||||
ast::IdentPat(_it) => ImmediateLocation::IdentPat,
|
ast::IdentPat(_it) => ImmediateLocation::IdentPat,
|
||||||
ast::Use(_it) => ImmediateLocation::Use,
|
ast::Use(_it) => ImmediateLocation::Use,
|
||||||
|
ast::UseTree(_it) => ImmediateLocation::UseTree,
|
||||||
|
ast::UseTreeList(_it) => ImmediateLocation::UseTree,
|
||||||
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,
|
||||||
@ -373,8 +376,8 @@ mod tests {
|
|||||||
fn test_use_loc() {
|
fn test_use_loc() {
|
||||||
check_location(r"use f$0", ImmediateLocation::Use);
|
check_location(r"use f$0", ImmediateLocation::Use);
|
||||||
check_location(r"use f$0;", ImmediateLocation::Use);
|
check_location(r"use f$0;", ImmediateLocation::Use);
|
||||||
check_location(r"use f::{f$0}", None);
|
check_location(r"use f::{f$0}", ImmediateLocation::UseTree);
|
||||||
check_location(r"use {f$0}", None);
|
check_location(r"use {f$0}", ImmediateLocation::UseTree);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -28,7 +28,7 @@ impl Builder {
|
|||||||
if !ctx.config.add_call_parenthesis {
|
if !ctx.config.add_call_parenthesis {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ctx.use_item_syntax.is_some() {
|
if ctx.in_use_tree() {
|
||||||
cov_mark::hit!(no_parens_in_use_item);
|
cov_mark::hit!(no_parens_in_use_item);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ impl<'a> MacroRender<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn needs_bang(&self) -> bool {
|
fn needs_bang(&self) -> bool {
|
||||||
self.ctx.completion.use_item_syntax.is_none()
|
!self.ctx.completion.in_use_tree()
|
||||||
&& !matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac))
|
&& !matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
mod item_list;
|
mod item_list;
|
||||||
|
mod use_tree;
|
||||||
|
|
||||||
use hir::{PrefixKind, Semantics};
|
use hir::{PrefixKind, Semantics};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
|
255
crates/ide_completion/src/tests/use_tree.rs
Normal file
255
crates/ide_completion/src/tests/use_tree.rs
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn use_tree_start() {
|
||||||
|
cov_mark::check!(only_completes_modules_in_import);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- /lib.rs crate:main deps:other_crate
|
||||||
|
use f$0
|
||||||
|
|
||||||
|
struct Foo;
|
||||||
|
mod foo {}
|
||||||
|
//- /other_crate/lib.rs crate:other_crate
|
||||||
|
// nothing here
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
kw crate::
|
||||||
|
kw self::
|
||||||
|
kw super::
|
||||||
|
md foo
|
||||||
|
md other_crate
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dont_complete_current_use() {
|
||||||
|
cov_mark::check!(dont_complete_current_use);
|
||||||
|
check(r#"use self::foo$0;"#, expect![[r#""#]]);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
mod foo { pub struct S; }
|
||||||
|
use self::{foo::*, bar$0};
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
kw self
|
||||||
|
st S
|
||||||
|
md foo
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nested_use_tree() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
mod foo {
|
||||||
|
pub mod bar {
|
||||||
|
pub struct FooBar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
use foo::{bar::$0}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
st FooBar
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
mod foo {
|
||||||
|
pub mod bar {
|
||||||
|
pub struct FooBar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
use foo::{$0}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
kw self
|
||||||
|
md bar
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deeply_nested_use_tree() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
mod foo {
|
||||||
|
pub mod bar {
|
||||||
|
pub mod baz {
|
||||||
|
pub struct FooBarBaz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
use foo::{bar::{baz::$0}}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
st FooBarBaz
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
mod foo {
|
||||||
|
pub mod bar {
|
||||||
|
pub mod baz {
|
||||||
|
pub struct FooBarBaz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
use foo::{bar::{$0}}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
kw self
|
||||||
|
md baz
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn plain_qualified_use_tree() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
use foo::$0
|
||||||
|
|
||||||
|
mod foo {
|
||||||
|
struct Private;
|
||||||
|
pub struct Foo;
|
||||||
|
}
|
||||||
|
struct Bar;
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
st Foo
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn self_qualified_use_tree() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
use self::$0
|
||||||
|
|
||||||
|
mod foo {}
|
||||||
|
struct Bar;
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
md foo
|
||||||
|
st Bar
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn super_qualified_use_tree() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
mod bar {
|
||||||
|
use super::$0
|
||||||
|
}
|
||||||
|
|
||||||
|
mod foo {}
|
||||||
|
struct Bar;
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
kw super::
|
||||||
|
st Bar
|
||||||
|
md bar
|
||||||
|
md foo
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn super_super_qualified_use_tree() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
mod a {
|
||||||
|
const A: usize = 0;
|
||||||
|
mod b {
|
||||||
|
const B: usize = 0;
|
||||||
|
mod c { use super::super::$0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
kw super::
|
||||||
|
md b
|
||||||
|
ct A
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn crate_qualified_use_tree() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
use crate::$0
|
||||||
|
|
||||||
|
mod foo {}
|
||||||
|
struct Bar;
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
md foo
|
||||||
|
st Bar
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn extern_crate_qualified_use_tree() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- /lib.rs crate:main deps:other_crate
|
||||||
|
use other_crate::$0
|
||||||
|
//- /other_crate/lib.rs crate:other_crate
|
||||||
|
pub struct Foo;
|
||||||
|
pub mod foo {}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
st Foo
|
||||||
|
md foo
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pub_use_tree() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
pub struct X;
|
||||||
|
pub mod bar {}
|
||||||
|
pub use $0;
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
kw crate::
|
||||||
|
kw self::
|
||||||
|
kw super::
|
||||||
|
md bar
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn use_tree_braces_at_start() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
struct X;
|
||||||
|
mod bar {}
|
||||||
|
use {$0};
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
kw crate::
|
||||||
|
kw self::
|
||||||
|
kw super::
|
||||||
|
md bar
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user