diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs index f8b1ff7310..b22124cc69 100644 --- a/crates/ide-completion/src/completions.rs +++ b/crates/ide-completion/src/completions.rs @@ -2,6 +2,7 @@ pub(crate) mod attribute; pub(crate) mod dot; +pub(crate) mod expr; pub(crate) mod extern_abi; pub(crate) mod flyimport; pub(crate) mod fn_param; @@ -16,7 +17,7 @@ pub(crate) mod qualified_path; pub(crate) mod record; pub(crate) mod snippet; pub(crate) mod trait_impl; -pub(crate) mod unqualified_path; +pub(crate) mod r#type; pub(crate) mod use_; pub(crate) mod vis; diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs new file mode 100644 index 0000000000..f9717f1c2c --- /dev/null +++ b/crates/ide-completion/src/completions/expr.rs @@ -0,0 +1,49 @@ +//! Completion of names from the current scope in expression position. + +use hir::ScopeDef; + +use crate::{ + context::{PathCompletionCtx, PathKind, PathQualifierCtx}, + CompletionContext, Completions, +}; + +pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext) { + let _p = profile::span("complete_expr_path"); + if ctx.is_path_disallowed() { + return; + } + + let (&is_absolute_path, qualifier) = match &ctx.path_context { + Some(PathCompletionCtx { + kind: Some(PathKind::Expr), is_absolute_path, qualifier, .. + }) => (is_absolute_path, qualifier), + _ => return, + }; + + match qualifier { + Some(PathQualifierCtx { .. }) => return, + None if is_absolute_path => acc.add_crate_roots(ctx), + None => { + acc.add_nameref_keywords_with_colon(ctx); + if let Some(hir::Adt::Enum(e)) = + ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) + { + super::enum_variants_with_paths(acc, ctx, e, |acc, ctx, variant, path| { + acc.add_qualified_enum_variant(ctx, variant, path) + }); + } + ctx.process_all_names(&mut |name, def| { + use hir::{GenericParam::*, ModuleDef::*}; + let add_resolution = match def { + ScopeDef::GenericParam(LifetimeParam(_)) | ScopeDef::Label(_) => false, + // Don't suggest attribute macros and derives. + ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db), + _ => true, + }; + if add_resolution { + acc.add_resolution(ctx, name, def); + } + }); + } + } +} diff --git a/crates/ide-completion/src/completions/item_list.rs b/crates/ide-completion/src/completions/item_list.rs index 5ae119c534..ff1abd715d 100644 --- a/crates/ide-completion/src/completions/item_list.rs +++ b/crates/ide-completion/src/completions/item_list.rs @@ -7,7 +7,7 @@ use crate::{ }; pub(crate) fn complete_item_list(acc: &mut Completions, ctx: &CompletionContext) { - let _p = profile::span("complete_unqualified_path"); + let _p = profile::span("complete_item_list"); if ctx.is_path_disallowed() || ctx.has_unfinished_impl_or_trait_prev_sibling() { return; } diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs new file mode 100644 index 0000000000..4d0e2fb59a --- /dev/null +++ b/crates/ide-completion/src/completions/type.rs @@ -0,0 +1,90 @@ +//! Completion of names from the current scope in type position. + +use hir::ScopeDef; +use syntax::{ast, AstNode}; + +use crate::{ + context::{PathCompletionCtx, PathKind, PathQualifierCtx}, + patterns::ImmediateLocation, + CompletionContext, Completions, +}; + +pub(crate) fn complete_type_path(acc: &mut Completions, ctx: &CompletionContext) { + let _p = profile::span("complete_type_path"); + if ctx.is_path_disallowed() { + return; + } + + let (&is_absolute_path, qualifier) = match &ctx.path_context { + Some(PathCompletionCtx { + kind: Some(PathKind::Type), is_absolute_path, qualifier, .. + }) => (is_absolute_path, qualifier), + _ => return, + }; + + match qualifier { + Some(PathQualifierCtx { .. }) => return, + None if is_absolute_path => acc.add_crate_roots(ctx), + None => { + acc.add_nameref_keywords_with_colon(ctx); + if let Some(ImmediateLocation::TypeBound) = &ctx.completion_location { + ctx.process_all_names(&mut |name, res| { + let add_resolution = match res { + ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db), + ScopeDef::ModuleDef( + hir::ModuleDef::Trait(_) | hir::ModuleDef::Module(_), + ) => true, + _ => false, + }; + if add_resolution { + acc.add_resolution(ctx, name, res); + } + }); + return; + } + if let Some(ImmediateLocation::GenericArgList(arg_list)) = &ctx.completion_location { + if let Some(path_seg) = arg_list.syntax().parent().and_then(ast::PathSegment::cast) + { + if let Some(hir::PathResolution::Def(hir::ModuleDef::Trait(trait_))) = + ctx.sema.resolve_path(&path_seg.parent_path()) + { + trait_.items(ctx.sema.db).into_iter().for_each(|it| { + if let hir::AssocItem::TypeAlias(alias) = it { + acc.add_type_alias_with_eq(ctx, alias) + } + }); + } + } + } + ctx.process_all_names(&mut |name, def| { + use hir::{GenericParam::*, ModuleDef::*}; + let add_resolution = match def { + ScopeDef::GenericParam(LifetimeParam(_)) | ScopeDef::Label(_) => false, + // no values in type places + ScopeDef::ModuleDef(Function(_) | Variant(_) | Static(_)) + | ScopeDef::Local(_) => false, + // unless its a constant in a generic arg list position + ScopeDef::ModuleDef(Const(_)) | ScopeDef::GenericParam(ConstParam(_)) => { + ctx.expects_generic_arg() + } + ScopeDef::ImplSelfType(_) => { + !ctx.previous_token_is(syntax::T![impl]) + && !ctx.previous_token_is(syntax::T![for]) + } + // Don't suggest attribute macros and derives. + ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db), + // Type things are fine + ScopeDef::ModuleDef( + BuiltinType(_) | Adt(_) | Module(_) | Trait(_) | TypeAlias(_), + ) + | ScopeDef::AdtSelfType(_) + | ScopeDef::Unknown + | ScopeDef::GenericParam(TypeParam(_)) => true, + }; + if add_resolution { + acc.add_resolution(ctx, name, def); + } + }); + } + } +} diff --git a/crates/ide-completion/src/completions/unqualified_path.rs b/crates/ide-completion/src/completions/unqualified_path.rs deleted file mode 100644 index 5de602e613..0000000000 --- a/crates/ide-completion/src/completions/unqualified_path.rs +++ /dev/null @@ -1,289 +0,0 @@ -//! Completion of names from the current scope, e.g. locals and imported items. - -use hir::ScopeDef; -use syntax::{ast, AstNode}; - -use crate::{ - context::{PathCompletionCtx, PathKind}, - patterns::ImmediateLocation, - CompletionContext, Completions, -}; - -pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { - let _p = profile::span("complete_unqualified_path"); - if ctx.is_path_disallowed() || ctx.has_unfinished_impl_or_trait_prev_sibling() { - return; - } - - match &ctx.path_context { - Some(PathCompletionCtx { - is_absolute_path: false, - qualifier: None, - kind: None | Some(PathKind::Expr | PathKind::Type), - .. - }) => (), - _ => return, - } - - acc.add_nameref_keywords(ctx); - - match &ctx.completion_location { - Some(ImmediateLocation::TypeBound) => { - ctx.process_all_names(&mut |name, res| { - let add_resolution = match res { - ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db), - ScopeDef::ModuleDef(hir::ModuleDef::Trait(_) | hir::ModuleDef::Module(_)) => { - true - } - _ => false, - }; - if add_resolution { - acc.add_resolution(ctx, name, res); - } - }); - return; - } - _ => (), - } - - if !ctx.expects_type() { - if let Some(hir::Adt::Enum(e)) = - ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) - { - super::enum_variants_with_paths(acc, ctx, e, |acc, ctx, variant, path| { - acc.add_qualified_enum_variant(ctx, variant, path) - }); - } - } - - if let Some(ImmediateLocation::GenericArgList(arg_list)) = &ctx.completion_location { - if let Some(path_seg) = arg_list.syntax().parent().and_then(ast::PathSegment::cast) { - if let Some(hir::PathResolution::Def(hir::ModuleDef::Trait(trait_))) = - ctx.sema.resolve_path(&path_seg.parent_path()) - { - trait_.items(ctx.sema.db).into_iter().for_each(|it| { - if let hir::AssocItem::TypeAlias(alias) = it { - acc.add_type_alias_with_eq(ctx, alias) - } - }); - } - } - } - - ctx.process_all_names(&mut |name, res| { - let add_resolution = match res { - ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) => { - cov_mark::hit!(unqualified_skip_lifetime_completion); - return; - } - ScopeDef::ImplSelfType(_) => { - !ctx.previous_token_is(syntax::T![impl]) && !ctx.previous_token_is(syntax::T![for]) - } - // Don't suggest attribute macros and derives. - ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db), - // no values in type places - ScopeDef::ModuleDef( - hir::ModuleDef::Function(_) - | hir::ModuleDef::Variant(_) - | hir::ModuleDef::Static(_), - ) - | ScopeDef::Local(_) => !ctx.expects_type(), - // unless its a constant in a generic arg list position - ScopeDef::ModuleDef(hir::ModuleDef::Const(_)) - | ScopeDef::GenericParam(hir::GenericParam::ConstParam(_)) => { - !ctx.expects_type() || ctx.expects_generic_arg() - } - _ => true, - }; - if add_resolution { - acc.add_resolution(ctx, name, res); - } - }); -} - -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - - use crate::tests::{check_edit, completion_list_no_kw}; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list_no_kw(ra_fixture); - expect.assert_eq(&actual) - } - - #[test] - fn completes_if_prefix_is_keyword() { - check_edit( - "wherewolf", - r#" -fn main() { - let wherewolf = 92; - drop(where$0) -} -"#, - r#" -fn main() { - let wherewolf = 92; - drop(wherewolf) -} -"#, - ) - } - - /// Regression test for issue #6091. - #[test] - fn correctly_completes_module_items_prefixed_with_underscore() { - check_edit( - "_alpha", - r#" -fn main() { - _$0 -} -fn _alpha() {} -"#, - r#" -fn main() { - _alpha()$0 -} -fn _alpha() {} -"#, - ) - } - - #[test] - fn completes_prelude() { - check( - r#" -//- /main.rs crate:main deps:std -fn foo() { let x: $0 } - -//- /std/lib.rs crate:std -pub mod prelude { - pub mod rust_2018 { - pub struct Option; - } -} -"#, - expect![[r#" - md std - st Option - bt u32 - "#]], - ); - } - - #[test] - fn completes_prelude_macros() { - check( - r#" -//- /main.rs crate:main deps:std -fn f() {$0} - -//- /std/lib.rs crate:std -pub mod prelude { - pub mod rust_2018 { - pub use crate::concat; - } -} - -mod macros { - #[rustc_builtin_macro] - #[macro_export] - macro_rules! concat { } -} -"#, - expect![[r#" - fn f() fn() - ma concat!(…) macro_rules! concat - md std - bt u32 - "#]], - ); - } - - #[test] - fn completes_std_prelude_if_core_is_defined() { - check( - r#" -//- /main.rs crate:main deps:core,std -fn foo() { let x: $0 } - -//- /core/lib.rs crate:core -pub mod prelude { - pub mod rust_2018 { - pub struct Option; - } -} - -//- /std/lib.rs crate:std deps:core -pub mod prelude { - pub mod rust_2018 { - pub struct String; - } -} -"#, - expect![[r#" - md core - md std - st String - bt u32 - "#]], - ); - } - - #[test] - fn respects_doc_hidden() { - check( - r#" -//- /lib.rs crate:lib deps:std -fn f() { - format_$0 -} - -//- /std.rs crate:std -#[doc(hidden)] -#[macro_export] -macro_rules! format_args_nl { - () => {} -} - -pub mod prelude { - pub mod rust_2018 {} -} - "#, - expect![[r#" - fn f() fn() - md std - bt u32 - "#]], - ); - } - - #[test] - fn respects_doc_hidden_in_assoc_item_list() { - check( - r#" -//- /lib.rs crate:lib deps:std -struct S; -impl S { - format_$0 -} - -//- /std.rs crate:std -#[doc(hidden)] -#[macro_export] -macro_rules! format_args_nl { - () => {} -} - -pub mod prelude { - pub mod rust_2018 {} -} - "#, - expect![[r#" - md std - "#]], - ); - } -} diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index 6682bc56d1..87677e28e8 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -71,6 +71,10 @@ pub(crate) struct PathCompletionCtx { pub(super) is_absolute_path: bool, /// The qualifier of the current path if it exists. pub(super) qualifier: Option, + #[allow(dead_code)] + // FIXME: use this + /// The parent of the path we are completing. + pub(super) parent: Option, pub(super) kind: Option, /// Whether the path segment has type args or not. pub(super) has_type_args: bool, @@ -949,13 +953,14 @@ impl<'a> CompletionContext<'a> { let mut path_ctx = PathCompletionCtx { has_call_parens: false, + has_macro_bang: false, is_absolute_path: false, qualifier: None, + parent: path.parent_path(), + kind: None, has_type_args: false, can_be_stmt: false, in_loop_body: false, - has_macro_bang: false, - kind: None, }; let mut pat_ctx = None; path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax()); diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs index 473900397a..3a0bd042da 100644 --- a/crates/ide-completion/src/lib.rs +++ b/crates/ide-completion/src/lib.rs @@ -144,34 +144,38 @@ pub fn completions( config: &CompletionConfig, position: FilePosition, ) -> Option { - let ctx = CompletionContext::new(db, position, config)?; - + let ctx = &CompletionContext::new(db, position, config)?; let mut acc = Completions::default(); - completions::attribute::complete_attribute(&mut acc, &ctx); - completions::attribute::complete_derive(&mut acc, &ctx); - completions::attribute::complete_known_attribute_input(&mut acc, &ctx); - completions::dot::complete_dot(&mut acc, &ctx); - completions::extern_abi::complete_extern_abi(&mut acc, &ctx); - completions::flyimport::import_on_the_fly(&mut acc, &ctx); - completions::fn_param::complete_fn_param(&mut acc, &ctx); - completions::format_string::format_string(&mut acc, &ctx); - completions::item_list::complete_item_list(&mut acc, &ctx); - completions::inferred_type(&mut acc, &ctx); - completions::keyword::complete_expr_keyword(&mut acc, &ctx); - completions::lifetime::complete_label(&mut acc, &ctx); - completions::lifetime::complete_lifetime(&mut acc, &ctx); - completions::mod_::complete_mod(&mut acc, &ctx); - completions::pattern::complete_pattern(&mut acc, &ctx); - completions::postfix::complete_postfix(&mut acc, &ctx); - completions::qualified_path::complete_qualified_path(&mut acc, &ctx); - completions::record::complete_record_literal(&mut acc, &ctx); - completions::record::complete_record(&mut acc, &ctx); - completions::snippet::complete_expr_snippet(&mut acc, &ctx); - completions::snippet::complete_item_snippet(&mut acc, &ctx); - completions::trait_impl::complete_trait_impl(&mut acc, &ctx); - completions::unqualified_path::complete_unqualified_path(&mut acc, &ctx); - completions::use_::complete_use_tree(&mut acc, &ctx); - completions::vis::complete_vis(&mut acc, &ctx); + + { + let acc = &mut acc; + completions::attribute::complete_attribute(acc, ctx); + completions::attribute::complete_derive(acc, ctx); + completions::attribute::complete_known_attribute_input(acc, ctx); + completions::dot::complete_dot(acc, ctx); + completions::expr::complete_expr_path(acc, ctx); + completions::extern_abi::complete_extern_abi(acc, ctx); + completions::flyimport::import_on_the_fly(acc, ctx); + completions::fn_param::complete_fn_param(acc, ctx); + completions::format_string::format_string(acc, ctx); + completions::item_list::complete_item_list(acc, ctx); + completions::inferred_type(acc, ctx); + completions::keyword::complete_expr_keyword(acc, ctx); + completions::lifetime::complete_label(acc, ctx); + completions::lifetime::complete_lifetime(acc, ctx); + completions::mod_::complete_mod(acc, ctx); + completions::pattern::complete_pattern(acc, ctx); + completions::postfix::complete_postfix(acc, ctx); + completions::qualified_path::complete_qualified_path(acc, ctx); + completions::record::complete_record_literal(acc, ctx); + completions::record::complete_record(acc, ctx); + completions::snippet::complete_expr_snippet(acc, ctx); + completions::snippet::complete_item_snippet(acc, ctx); + completions::trait_impl::complete_trait_impl(acc, ctx); + completions::r#type::complete_type_path(acc, ctx); + completions::use_::complete_use_tree(acc, ctx); + completions::vis::complete_vis(acc, ctx); + } Some(acc) } diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs index 5387b455f0..8d9d1bc4b9 100644 --- a/crates/ide-completion/src/tests.rs +++ b/crates/ide-completion/src/tests.rs @@ -10,6 +10,7 @@ mod attribute; mod expression; +mod flyimport; mod fn_param; mod item_list; mod item; @@ -17,10 +18,10 @@ mod pattern; mod predicate; mod proc_macros; mod record; +mod special; mod type_pos; mod use_tree; mod visibility; -mod flyimport; use std::mem; diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs index a068d5bf7a..61246b963e 100644 --- a/crates/ide-completion/src/tests/expression.rs +++ b/crates/ide-completion/src/tests/expression.rs @@ -48,7 +48,7 @@ fn baz() { un Union ev TupleV(…) TupleV(u32) bt u32 - kw crate + kw crate:: kw false kw for kw if @@ -57,8 +57,8 @@ fn baz() { kw match kw mut kw return - kw self - kw super + kw self:: + kw super:: kw true kw unsafe kw while @@ -91,7 +91,7 @@ fn func(param0 @ (param1, param2): (i32, i32)) { lc param1 i32 lc param2 i32 bt u32 - kw crate + kw crate:: kw false kw for kw if @@ -99,8 +99,8 @@ fn func(param0 @ (param1, param2): (i32, i32)) { kw loop kw match kw return - kw self - kw super + kw self:: + kw super:: kw true kw unsafe kw while @@ -111,7 +111,6 @@ fn func(param0 @ (param1, param2): (i32, i32)) { #[test] fn completes_all_the_things_in_fn_body() { - cov_mark::check!(unqualified_skip_lifetime_completion); check( r#" use non_existant::Unresolved; @@ -146,7 +145,7 @@ impl Unit { ev TupleV(…) TupleV(u32) bt u32 kw const - kw crate + kw crate:: kw enum kw extern kw false @@ -160,10 +159,10 @@ impl Unit { kw match kw mod kw return - kw self + kw self:: kw static kw struct - kw super + kw super:: kw trait kw true kw type @@ -224,7 +223,7 @@ fn complete_in_block() { fn foo() fn() bt u32 kw const - kw crate + kw crate:: kw enum kw extern kw false @@ -238,10 +237,10 @@ fn complete_in_block() { kw match kw mod kw return - kw self + kw self:: kw static kw struct - kw super + kw super:: kw trait kw true kw type @@ -270,7 +269,7 @@ fn complete_after_if_expr() { fn foo() fn() bt u32 kw const - kw crate + kw crate:: kw else kw else if kw enum @@ -286,10 +285,10 @@ fn complete_after_if_expr() { kw match kw mod kw return - kw self + kw self:: kw static kw struct - kw super + kw super:: kw trait kw true kw type @@ -318,7 +317,7 @@ fn complete_in_match_arm() { expect![[r#" fn foo() fn() bt u32 - kw crate + kw crate:: kw false kw for kw if @@ -326,8 +325,8 @@ fn complete_in_match_arm() { kw loop kw match kw return - kw self - kw super + kw self:: + kw super:: kw true kw unsafe kw while @@ -346,7 +345,7 @@ fn completes_in_loop_ctx() { kw break kw const kw continue - kw crate + kw crate:: kw enum kw extern kw false @@ -360,10 +359,10 @@ fn completes_in_loop_ctx() { kw match kw mod kw return - kw self + kw self:: kw static kw struct - kw super + kw super:: kw trait kw true kw type @@ -386,7 +385,7 @@ fn completes_in_let_initializer() { expect![[r#" fn main() fn() bt u32 - kw crate + kw crate:: kw false kw for kw if @@ -394,8 +393,8 @@ fn completes_in_let_initializer() { kw loop kw match kw return - kw self - kw super + kw self:: + kw super:: kw true kw unsafe kw while @@ -421,7 +420,7 @@ fn foo() { fn foo() fn() st Foo bt u32 - kw crate + kw crate:: kw false kw for kw if @@ -429,8 +428,8 @@ fn foo() { kw loop kw match kw return - kw self - kw super + kw self:: + kw super:: kw true kw unsafe kw while @@ -457,7 +456,7 @@ fn foo() { fn foo() fn() lc bar i32 bt u32 - kw crate + kw crate:: kw false kw for kw if @@ -465,8 +464,8 @@ fn foo() { kw loop kw match kw return - kw self - kw super + kw self:: + kw super:: kw true kw unsafe kw while @@ -489,7 +488,7 @@ fn quux(x: i32) { lc x i32 ma m!(…) macro_rules! m bt u32 - kw crate + kw crate:: kw false kw for kw if @@ -497,8 +496,8 @@ fn quux(x: i32) { kw loop kw match kw return - kw self - kw super + kw self:: + kw super:: kw true kw unsafe kw while @@ -517,7 +516,7 @@ fn quux(x: i32) { lc x i32 ma m!(…) macro_rules! m bt u32 - kw crate + kw crate:: kw false kw for kw if @@ -525,8 +524,8 @@ fn quux(x: i32) { kw loop kw match kw return - kw self - kw super + kw self:: + kw super:: kw true kw unsafe kw while diff --git a/crates/ide-completion/src/tests/item.rs b/crates/ide-completion/src/tests/item.rs index 5d324f0965..e4b70f97e3 100644 --- a/crates/ide-completion/src/tests/item.rs +++ b/crates/ide-completion/src/tests/item.rs @@ -27,9 +27,9 @@ impl Tra$0 tt Trait un Union bt u32 - kw crate - kw self - kw super + kw crate:: + kw self:: + kw super:: "#]], ) } @@ -50,9 +50,9 @@ impl Trait for Str$0 tt Trait un Union bt u32 - kw crate - kw self - kw super + kw crate:: + kw self:: + kw super:: "#]], ) } diff --git a/crates/ide-completion/src/tests/predicate.rs b/crates/ide-completion/src/tests/predicate.rs index cc18bf4453..f2b9c061dc 100644 --- a/crates/ide-completion/src/tests/predicate.rs +++ b/crates/ide-completion/src/tests/predicate.rs @@ -26,9 +26,9 @@ struct Foo<'lt, T, const C: usize> where $0 {} tt Trait un Union bt u32 - kw crate - kw self - kw super + kw crate:: + kw self:: + kw super:: "#]], ); } @@ -43,9 +43,9 @@ struct Foo<'lt, T, const C: usize> where T: $0 {} ma makro!(…) macro_rules! makro md module tt Trait - kw crate - kw self - kw super + kw crate:: + kw self:: + kw super:: "#]], ); } @@ -62,9 +62,9 @@ struct Foo<'lt, T, const C: usize> where 'lt: $0 {} ma makro!(…) macro_rules! makro md module tt Trait - kw crate - kw self - kw super + kw crate:: + kw self:: + kw super:: "#]], ); } @@ -79,9 +79,9 @@ struct Foo<'lt, T, const C: usize> where for<'a> T: $0 {} ma makro!(…) macro_rules! makro md module tt Trait - kw crate - kw self - kw super + kw crate:: + kw self:: + kw super:: "#]], ); } @@ -103,9 +103,9 @@ struct Foo<'lt, T, const C: usize> where for<'a> $0 {} tt Trait un Union bt u32 - kw crate - kw self - kw super + kw crate:: + kw self:: + kw super:: "#]], ); } @@ -129,9 +129,9 @@ impl Record { tt Trait un Union bt u32 - kw crate - kw self - kw super + kw crate:: + kw self:: + kw super:: "#]], ); } diff --git a/crates/ide-completion/src/tests/record.rs b/crates/ide-completion/src/tests/record.rs index bae5ddb539..a0f8b24867 100644 --- a/crates/ide-completion/src/tests/record.rs +++ b/crates/ide-completion/src/tests/record.rs @@ -167,7 +167,7 @@ fn main() { tt Default tt Sized bt u32 - kw crate + kw crate:: kw false kw for kw if @@ -175,8 +175,8 @@ fn main() { kw loop kw match kw return - kw self - kw super + kw self:: + kw super:: kw true kw unsafe kw while diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs new file mode 100644 index 0000000000..79235e5ca0 --- /dev/null +++ b/crates/ide-completion/src/tests/special.rs @@ -0,0 +1,183 @@ +use expect_test::{expect, Expect}; + +use crate::tests::{check_edit, completion_list_no_kw}; + +fn check(ra_fixture: &str, expect: Expect) { + let actual = completion_list_no_kw(ra_fixture); + expect.assert_eq(&actual) +} + +#[test] +fn completes_if_prefix_is_keyword() { + check_edit( + "wherewolf", + r#" +fn main() { + let wherewolf = 92; + drop(where$0) +} +"#, + r#" +fn main() { + let wherewolf = 92; + drop(wherewolf) +} +"#, + ) +} + +/// Regression test for issue #6091. +#[test] +fn correctly_completes_module_items_prefixed_with_underscore() { + check_edit( + "_alpha", + r#" +fn main() { + _$0 +} +fn _alpha() {} +"#, + r#" +fn main() { + _alpha()$0 +} +fn _alpha() {} +"#, + ) +} + +#[test] +fn completes_prelude() { + check( + r#" +//- /main.rs crate:main deps:std +fn foo() { let x: $0 } + +//- /std/lib.rs crate:std +pub mod prelude { + pub mod rust_2018 { + pub struct Option; + } +} +"#, + expect![[r#" + md std + st Option + bt u32 + "#]], + ); +} + +#[test] +fn completes_prelude_macros() { + check( + r#" +//- /main.rs crate:main deps:std +fn f() {$0} + +//- /std/lib.rs crate:std +pub mod prelude { + pub mod rust_2018 { + pub use crate::concat; + } +} + +mod macros { + #[rustc_builtin_macro] + #[macro_export] + macro_rules! concat { } +} +"#, + expect![[r#" + fn f() fn() + ma concat!(…) macro_rules! concat + md std + bt u32 + "#]], + ); +} + +#[test] +fn completes_std_prelude_if_core_is_defined() { + check( + r#" +//- /main.rs crate:main deps:core,std +fn foo() { let x: $0 } + +//- /core/lib.rs crate:core +pub mod prelude { + pub mod rust_2018 { + pub struct Option; + } +} + +//- /std/lib.rs crate:std deps:core +pub mod prelude { + pub mod rust_2018 { + pub struct String; + } +} +"#, + expect![[r#" + md core + md std + st String + bt u32 + "#]], + ); +} + +#[test] +fn respects_doc_hidden() { + check( + r#" +//- /lib.rs crate:lib deps:std +fn f() { + format_$0 +} + +//- /std.rs crate:std +#[doc(hidden)] +#[macro_export] +macro_rules! format_args_nl { + () => {} +} + +pub mod prelude { + pub mod rust_2018 {} +} + "#, + expect![[r#" + fn f() fn() + md std + bt u32 + "#]], + ); +} + +#[test] +fn respects_doc_hidden_in_assoc_item_list() { + check( + r#" +//- /lib.rs crate:lib deps:std +struct S; +impl S { + format_$0 +} + +//- /std.rs crate:std +#[doc(hidden)] +#[macro_export] +macro_rules! format_args_nl { + () => {} +} + +pub mod prelude { + pub mod rust_2018 {} +} + "#, + expect![[r#" + md std + "#]], + ); +} diff --git a/crates/ide-completion/src/tests/type_pos.rs b/crates/ide-completion/src/tests/type_pos.rs index fcbb2e05a7..5224bc4b48 100644 --- a/crates/ide-completion/src/tests/type_pos.rs +++ b/crates/ide-completion/src/tests/type_pos.rs @@ -29,9 +29,9 @@ struct Foo<'lt, T, const C: usize> { tp T un Union bt u32 - kw crate - kw self - kw super + kw crate:: + kw self:: + kw super:: "#]], ) } @@ -55,12 +55,12 @@ struct Foo<'lt, T, const C: usize>(f$0); tp T un Union bt u32 - kw crate + kw crate:: kw pub kw pub(crate) kw pub(super) - kw self - kw super + kw self:: + kw super:: "#]], ) } @@ -82,9 +82,9 @@ fn x<'lt, T, const C: usize>() -> $0 tp T un Union bt u32 - kw crate - kw self - kw super + kw crate:: + kw self:: + kw super:: "#]], ); } @@ -108,9 +108,9 @@ const FOO: $0 = Foo(2); un Union bt u32 it Foo - kw crate - kw self - kw super + kw crate:: + kw self:: + kw super:: "#]], ); } @@ -135,9 +135,9 @@ fn f2() { un Union bt u32 it i32 - kw crate - kw self - kw super + kw crate:: + kw self:: + kw super:: "#]], ); } @@ -164,9 +164,9 @@ fn f2() { un Union bt u32 it u64 - kw crate - kw self - kw super + kw crate:: + kw self:: + kw super:: "#]], ); } @@ -190,9 +190,9 @@ fn f2(x: u64) -> $0 { un Union bt u32 it u64 - kw crate - kw self - kw super + kw crate:: + kw self:: + kw super:: "#]], ); } @@ -217,9 +217,9 @@ fn f2(x: $0) { un Union bt u32 it i32 - kw crate - kw self - kw super + kw crate:: + kw self:: + kw super:: "#]], ); } @@ -252,9 +252,9 @@ fn foo<'lt, T, const C: usize>() { un Union bt u32 it a::Foo> - kw crate - kw self - kw super + kw crate:: + kw self:: + kw super:: "#]], ); } @@ -282,9 +282,9 @@ fn foo<'lt, T, const C: usize>() { un Union bt u32 it Foo - kw crate - kw self - kw super + kw crate:: + kw self:: + kw super:: "#]], ); } @@ -309,9 +309,9 @@ fn foo<'lt, T, const C: usize>() { tp T un Union bt u32 - kw crate - kw self - kw super + kw crate:: + kw self:: + kw super:: "#]], ); check( @@ -359,9 +359,9 @@ fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {} tp T un Union bt u32 - kw crate - kw self - kw super + kw crate:: + kw self:: + kw super:: "#]], ); check(