Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-completion/src/completions/unqualified_path.rs')
-rw-r--r--crates/ide-completion/src/completions/unqualified_path.rs298
1 files changed, 298 insertions, 0 deletions
diff --git a/crates/ide-completion/src/completions/unqualified_path.rs b/crates/ide-completion/src/completions/unqualified_path.rs
new file mode 100644
index 0000000000..94142e274a
--- /dev/null
+++ b/crates/ide-completion/src/completions/unqualified_path.rs
@@ -0,0 +1,298 @@
+//! Completion of names from the current scope, e.g. locals and imported items.
+
+use hir::ScopeDef;
+use syntax::{ast, AstNode};
+
+use crate::{
+ completions::module_or_fn_macro,
+ 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_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 | PathKind::Mac),
+ ..
+ }) => (),
+ _ => return,
+ }
+
+ acc.add_nameref_keywords(ctx);
+
+ match &ctx.completion_location {
+ Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => {
+ // only show macros in {Assoc}ItemList
+ ctx.process_all_names(&mut |name, def| {
+ if let Some(def) = module_or_fn_macro(ctx.db, def) {
+ acc.add_resolution(ctx, name, def);
+ }
+ });
+ return;
+ }
+ 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
+ bt u32
+ st Option
+ "#]],
+ );
+ }
+
+ #[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 std
+ md core
+ bt u32
+ st String
+ "#]],
+ );
+ }
+
+ #[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
+ "#]],
+ );
+ }
+}