Unnamed repository; edit this file 'description' to name the repository.
Add completion module tailored towards use trees
| -rw-r--r-- | crates/hir/src/display.rs | 2 | ||||
| -rw-r--r-- | crates/hir/src/lib.rs | 5 | ||||
| -rw-r--r-- | crates/ide_completion/src/completions.rs | 3 | ||||
| -rw-r--r-- | crates/ide_completion/src/completions/attribute.rs | 58 | ||||
| -rw-r--r-- | crates/ide_completion/src/completions/qualified_path.rs | 60 | ||||
| -rw-r--r-- | crates/ide_completion/src/completions/unqualified_path.rs | 18 | ||||
| -rw-r--r-- | crates/ide_completion/src/completions/use_.rs | 109 | ||||
| -rw-r--r-- | crates/ide_completion/src/lib.rs | 1 | ||||
| -rw-r--r-- | crates/ide_completion/src/tests/attribute.rs | 143 | ||||
| -rw-r--r-- | crates/ide_completion/src/tests/use_tree.rs | 19 | ||||
| -rw-r--r-- | crates/ide_completion/src/tests/visibility.rs | 9 | ||||
| -rw-r--r-- | crates/ide_db/src/search.rs | 6 |
12 files changed, 269 insertions, 164 deletions
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index d94f55e326..1e949771ea 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs @@ -481,7 +481,7 @@ impl HirDisplay for Module { // FIXME: Module doesn't have visibility saved in data. match self.name(f.db) { Some(name) => write!(f, "mod {}", name), - None if self.crate_root(f.db) == *self => match self.krate().display_name(f.db) { + None if self.is_crate_root(f.db) => match self.krate().display_name(f.db) { Some(name) => write!(f, "extern crate {}", name), None => write!(f, "extern crate {{unknown}}"), }, diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 918cadc869..032da5f50a 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -452,6 +452,11 @@ impl Module { Module { id: def_map.module_id(def_map.root()) } } + pub fn is_crate_root(self, db: &dyn HirDatabase) -> bool { + let def_map = db.crate_def_map(self.id.krate()); + def_map.root() == self.id.local_id + } + /// Iterates over all child modules. pub fn children(self, db: &dyn HirDatabase) -> impl Iterator<Item = Module> { let def_map = self.id.def_map(db.upcast()); diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs index 92074b3e10..715bd28e21 100644 --- a/crates/ide_completion/src/completions.rs +++ b/crates/ide_completion/src/completions.rs @@ -4,9 +4,11 @@ pub(crate) mod attribute; pub(crate) mod dot; pub(crate) mod flyimport; pub(crate) mod fn_param; +pub(crate) mod format_string; pub(crate) mod keyword; pub(crate) mod lifetime; pub(crate) mod mod_; +pub(crate) mod use_; pub(crate) mod pattern; pub(crate) mod postfix; pub(crate) mod qualified_path; @@ -14,7 +16,6 @@ pub(crate) mod record; pub(crate) mod snippet; pub(crate) mod trait_impl; pub(crate) mod unqualified_path; -pub(crate) mod format_string; use std::iter; diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs index 8950b13d6f..1a1fa533c1 100644 --- a/crates/ide_completion/src/completions/attribute.rs +++ b/crates/ide_completion/src/completions/attribute.rs @@ -1,9 +1,10 @@ -//! Completion for attributes +//! Completion for (built-in) attributes, derives and lints. //! -//! This module uses a bit of static metadata to provide completions -//! for built-in attributes. -//! Non-built-in attribute (excluding derives attributes) completions are done in [`super::unqualified_path`]. +//! This module uses a bit of static metadata to provide completions for builtin-in attributes and lints. +use std::iter; + +use hir::ScopeDef; use ide_db::{ helpers::{ generated_lints::{ @@ -85,24 +86,45 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) _ => return, }; - if !is_trivial_path { - return; - } + match qualifier { + Some((path, qualifier)) => { + let is_super_chain = iter::successors(Some(path.clone()), |p| p.qualifier()) + .all(|p| p.segment().and_then(|s| s.super_token()).is_some()); + if is_super_chain { + acc.add_keyword(ctx, "super::"); + } - if let Some((_, Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))))) = qualifier { - for (name, def) in module.scope(ctx.db, ctx.module) { - if let Some(def) = module_or_attr(def) { - acc.add_resolution(ctx, name, def); + let module = match qualifier { + Some(hir::PathResolution::Def(hir::ModuleDef::Module(it))) => it, + _ => return, + }; + + for (name, def) in module.scope(ctx.db, ctx.module) { + if let Some(def) = module_or_attr(def) { + acc.add_resolution(ctx, name, def); + } } + return; } - return; - } - - ctx.process_all_names(&mut |name, def| { - if let Some(def) = module_or_attr(def) { - acc.add_resolution(ctx, name, def); + // fresh use tree with leading colon2, only show crate roots + None if !is_trivial_path => { + ctx.process_all_names(&mut |name, res| match res { + ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root(ctx.db) => { + acc.add_resolution(ctx, name, res); + } + _ => (), + }); } - }); + // only show modules in a fresh UseTree + None => { + ctx.process_all_names(&mut |name, def| { + if let Some(def) = module_or_attr(def) { + acc.add_resolution(ctx, name, def); + } + }); + ["self::", "super::", "crate::"].into_iter().for_each(|kw| acc.add_keyword(ctx, kw)); + } + } let attributes = annotated_item_kind.and_then(|kind| { if ast::Expr::can_cast(kind) { diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index b15ec38b0a..14195e8149 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs @@ -1,10 +1,8 @@ //! Completion of paths, i.e. `some::prefix::$0`. -use std::iter; - use hir::{ScopeDef, Trait}; use rustc_hash::FxHashSet; -use syntax::{ast, AstNode}; +use syntax::ast; use crate::{ completions::module_or_fn_macro, @@ -17,14 +15,11 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon if ctx.is_path_disallowed() || ctx.has_impl_or_trait_prev_sibling() { return; } - let ((path, resolution), use_tree_parent, kind) = match ctx.path_context { + let ((path, resolution), kind) = match ctx.path_context { // let ... else, syntax would come in really handy here right now - Some(PathCompletionContext { - qualifier: Some(ref qualifier), - use_tree_parent, - kind, - .. - }) => (qualifier, use_tree_parent, kind), + Some(PathCompletionContext { qualifier: Some(ref qualifier), kind, .. }) => { + (qualifier, kind) + } _ => return, }; @@ -86,52 +81,23 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon } return; } - Some(PathKind::Attr { .. }) => { + Some(PathKind::Attr { .. } | PathKind::Use) => { return; } - Some(PathKind::Use) => { - 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"); - } + Some(PathKind::Pat) => (), + _ => { + // Add associated types on type parameters and `Self`. + ctx.scope.assoc_type_shorthand_candidates(&resolution, |_, alias| { + acc.add_type_alias(ctx, alias); + None::<()> + }); } - _ => (), - } - - if !matches!(kind, Some(PathKind::Pat)) { - // Add associated types on type parameters and `Self`. - ctx.scope.assoc_type_shorthand_candidates(&resolution, |_, alias| { - acc.add_type_alias(ctx, alias); - None::<()> - }); } match resolution { hir::PathResolution::Def(hir::ModuleDef::Module(module)) => { let module_scope = module.scope(ctx.db, ctx.module); for (name, def) in module_scope { - if let Some(PathKind::Use) = kind { - if let ScopeDef::Unknown = def { - if let Some(ast::NameLike::NameRef(name_ref)) = ctx.name_syntax.as_ref() { - if name_ref.syntax().text() == name.to_smol_str().as_str() { - // for `use self::foo$0`, don't suggest `foo` as a completion - cov_mark::hit!(dont_complete_current_use); - continue; - } - } - } - } - let add_resolution = match def { // Don't suggest attribute macros and derives. ScopeDef::MacroDef(mac) => mac.is_fn_like(), diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 01f3f777a1..1f78cfdf75 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs @@ -20,25 +20,11 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC _ => return, }; - if let Some(PathKind::Use) = kind { - // only show modules in a fresh UseTree - cov_mark::hit!(unqualified_path_only_modules_in_import); - ctx.process_all_names(&mut |name, res| { - if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { - acc.add_resolution(ctx, name, res); - } - }); - - ["self::", "super::", "crate::"].into_iter().for_each(|kw| acc.add_keyword(ctx, kw)); - return; - } - ["self", "super", "crate"].into_iter().for_each(|kw| acc.add_keyword(ctx, kw)); - match kind { - Some(PathKind::Vis { .. }) => return, - Some(PathKind::Attr { .. }) => return, + Some(PathKind::Vis { .. } | PathKind::Attr { .. } | PathKind::Use { .. }) => return, _ => (), } + ["self", "super", "crate"].into_iter().for_each(|kw| acc.add_keyword(ctx, kw)); match &ctx.completion_location { Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => { diff --git a/crates/ide_completion/src/completions/use_.rs b/crates/ide_completion/src/completions/use_.rs new file mode 100644 index 0000000000..b536095862 --- /dev/null +++ b/crates/ide_completion/src/completions/use_.rs @@ -0,0 +1,109 @@ +//! Completion for use trees +//! +//! This module uses a bit of static metadata to provide completions +//! for built-in attributes. +//! Non-built-in attribute (excluding derives attributes) completions are done in [`super::unqualified_path`]. + +use std::iter; + +use hir::ScopeDef; +use syntax::{ast, AstNode}; + +use crate::{ + context::{CompletionContext, PathCompletionContext, PathKind}, + Completions, +}; + +pub(crate) fn complete_use_tree(acc: &mut Completions, ctx: &CompletionContext) { + let (is_trivial_path, qualifier, use_tree_parent) = match ctx.path_context { + Some(PathCompletionContext { + kind: Some(PathKind::Use), + is_trivial_path, + use_tree_parent, + ref qualifier, + .. + }) => (is_trivial_path, qualifier, use_tree_parent), + _ => return, + }; + + match qualifier { + Some((path, qualifier)) => { + let is_super_chain = iter::successors(Some(path.clone()), |p| p.qualifier()) + .all(|p| p.segment().and_then(|s| s.super_token()).is_some()); + if is_super_chain { + acc.add_keyword(ctx, "super::"); + } + // only show `self` in a new use-tree when the qualifier doesn't end in self + let not_preceded_by_self = use_tree_parent + && !matches!( + path.segment().and_then(|it| it.kind()), + Some(ast::PathSegmentKind::SelfKw) + ); + if not_preceded_by_self { + acc.add_keyword(ctx, "self"); + } + + let qualifier = match qualifier { + Some(it) => it, + None => return, + }; + + match qualifier { + hir::PathResolution::Def(hir::ModuleDef::Module(module)) => { + let module_scope = module.scope(ctx.db, ctx.module); + let unknown_is_current = |name: &hir::Name| { + matches!( + ctx.name_syntax.as_ref(), + Some(ast::NameLike::NameRef(name_ref)) + if name_ref.syntax().text() == name.to_smol_str().as_str() + ) + }; + for (name, def) in module_scope { + let add_resolution = match def { + ScopeDef::Unknown if unknown_is_current(&name) => { + // for `use self::foo$0`, don't suggest `foo` as a completion + cov_mark::hit!(dont_complete_current_use); + continue; + } + ScopeDef::ModuleDef(_) | ScopeDef::MacroDef(_) | ScopeDef::Unknown => { + true + } + _ => false, + }; + + if add_resolution { + acc.add_resolution(ctx, name, def); + } + } + } + hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => { + cov_mark::hit!(enum_plain_qualified_use_tree); + e.variants(ctx.db) + .into_iter() + .for_each(|variant| acc.add_enum_variant(ctx, variant, None)); + } + _ => {} + } + } + // fresh use tree with leading colon2, only show crate roots + None if !is_trivial_path => { + cov_mark::hit!(use_tree_crate_roots_only); + ctx.process_all_names(&mut |name, res| match res { + ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root(ctx.db) => { + acc.add_resolution(ctx, name, res); + } + _ => (), + }); + } + // only show modules in a fresh UseTree + None => { + cov_mark::hit!(unqualified_path_only_modules_in_import); + ctx.process_all_names(&mut |name, res| { + if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { + acc.add_resolution(ctx, name, res); + } + }); + ["self::", "super::", "crate::"].into_iter().for_each(|kw| acc.add_keyword(ctx, kw)); + } + } +} diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs index 5b49a49911..2f7ca13ee8 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs @@ -153,6 +153,7 @@ pub fn completions( let mut acc = Completions::default(); completions::attribute::complete_known_attribute_input(&mut acc, &ctx); completions::attribute::complete_attribute(&mut acc, &ctx); + completions::use_::complete_use_tree(&mut acc, &ctx); completions::fn_param::complete_fn_param(&mut acc, &ctx); completions::keyword::complete_expr_keyword(&mut acc, &ctx); completions::snippet::complete_expr_snippet(&mut acc, &ctx); diff --git a/crates/ide_completion/src/tests/attribute.rs b/crates/ide_completion/src/tests/attribute.rs index ac43a67bdc..5a9c48a327 100644 --- a/crates/ide_completion/src/tests/attribute.rs +++ b/crates/ide_completion/src/tests/attribute.rs @@ -18,6 +18,9 @@ struct Foo; "#, expect![[r#" md proc_macros + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) @@ -33,9 +36,6 @@ struct Foo; at derive(…) at repr(…) at non_exhaustive - kw self - kw super - kw crate "#]], ) } @@ -61,7 +61,10 @@ fn proc_macros_qualified() { #[proc_macros::$0] struct Foo; "#, - expect![[r#""#]], + expect![[r#" + at input_replace pub macro input_replace + at identity pub macro identity + "#]], ) } @@ -75,15 +78,15 @@ fn with_existing_attr() { check( r#"#[no_mangle] #[$0] mcall!();"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) at deny(…) at forbid(…) at warn(…) - kw self - kw super - kw crate "#]], ) } @@ -93,6 +96,9 @@ fn attr_on_source_file() { check( r#"#![$0]"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) @@ -113,9 +119,6 @@ fn attr_on_source_file() { at recursion_limit = "…" at type_length_limit = … at windows_subsystem = "…" - kw self - kw super - kw crate "#]], ); } @@ -125,6 +128,9 @@ fn attr_on_module() { check( r#"#[$0] mod foo;"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) @@ -139,14 +145,14 @@ fn attr_on_module() { at no_mangle at macro_use at path = "…" - kw self - kw super - kw crate "#]], ); check( r#"mod foo {#![$0]}"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) @@ -160,9 +166,6 @@ fn attr_on_module() { at must_use at no_mangle at no_implicit_prelude - kw self - kw super - kw crate "#]], ); } @@ -172,6 +175,9 @@ fn attr_on_macro_rules() { check( r#"#[$0] macro_rules! foo {}"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) @@ -186,9 +192,6 @@ fn attr_on_macro_rules() { at no_mangle at macro_export at macro_use - kw self - kw super - kw crate "#]], ); } @@ -198,6 +201,9 @@ fn attr_on_macro_def() { check( r#"#[$0] macro foo {}"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) @@ -210,9 +216,6 @@ fn attr_on_macro_def() { at doc(alias = "…") at must_use at no_mangle - kw self - kw super - kw crate "#]], ); } @@ -222,6 +225,9 @@ fn attr_on_extern_crate() { check( r#"#[$0] extern crate foo;"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) @@ -235,9 +241,6 @@ fn attr_on_extern_crate() { at must_use at no_mangle at macro_use - kw self - kw super - kw crate "#]], ); } @@ -247,6 +250,9 @@ fn attr_on_use() { check( r#"#[$0] use foo;"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) @@ -259,9 +265,6 @@ fn attr_on_use() { at doc(alias = "…") at must_use at no_mangle - kw self - kw super - kw crate "#]], ); } @@ -271,6 +274,9 @@ fn attr_on_type_alias() { check( r#"#[$0] type foo = ();"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) @@ -283,9 +289,6 @@ fn attr_on_type_alias() { at doc(alias = "…") at must_use at no_mangle - kw self - kw super - kw crate "#]], ); } @@ -301,6 +304,9 @@ struct Foo; expect![[r#" md core at derive pub macro derive + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) @@ -316,9 +322,6 @@ struct Foo; at derive(…) at repr(…) at non_exhaustive - kw self - kw super - kw crate "#]], ); } @@ -328,6 +331,9 @@ fn attr_on_enum() { check( r#"#[$0] enum Foo {}"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) @@ -343,9 +349,6 @@ fn attr_on_enum() { at derive(…) at repr(…) at non_exhaustive - kw self - kw super - kw crate "#]], ); } @@ -355,6 +358,9 @@ fn attr_on_const() { check( r#"#[$0] const FOO: () = ();"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) @@ -367,9 +373,6 @@ fn attr_on_const() { at doc(alias = "…") at must_use at no_mangle - kw self - kw super - kw crate "#]], ); } @@ -379,6 +382,9 @@ fn attr_on_static() { check( r#"#[$0] static FOO: () = ()"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) @@ -396,9 +402,6 @@ fn attr_on_static() { at link_section = "…" at global_allocator at used - kw self - kw super - kw crate "#]], ); } @@ -408,6 +411,9 @@ fn attr_on_trait() { check( r#"#[$0] trait Foo {}"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) @@ -421,9 +427,6 @@ fn attr_on_trait() { at must_use at no_mangle at must_use - kw self - kw super - kw crate "#]], ); } @@ -433,6 +436,9 @@ fn attr_on_impl() { check( r#"#[$0] impl () {}"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) @@ -446,14 +452,14 @@ fn attr_on_impl() { at must_use at no_mangle at automatically_derived - kw self - kw super - kw crate "#]], ); check( r#"impl () {#![$0]}"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) @@ -466,9 +472,6 @@ fn attr_on_impl() { at doc(alias = "…") at must_use at no_mangle - kw self - kw super - kw crate "#]], ); } @@ -478,6 +481,9 @@ fn attr_on_extern_block() { check( r#"#[$0] extern {}"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) @@ -491,14 +497,14 @@ fn attr_on_extern_block() { at must_use at no_mangle at link - kw self - kw super - kw crate "#]], ); check( r#"extern {#![$0]}"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) @@ -512,9 +518,6 @@ fn attr_on_extern_block() { at must_use at no_mangle at link - kw self - kw super - kw crate "#]], ); } @@ -524,6 +527,9 @@ fn attr_on_variant() { check( r#"enum Foo { #[$0] Bar }"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) @@ -531,9 +537,6 @@ fn attr_on_variant() { at forbid(…) at warn(…) at non_exhaustive - kw self - kw super - kw crate "#]], ); } @@ -543,6 +546,9 @@ fn attr_on_fn() { check( r#"#[$0] fn main() {}"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) @@ -570,9 +576,6 @@ fn attr_on_fn() { at target_feature = "…" at test at track_caller - kw self - kw super - kw crate "#]], ); } @@ -583,15 +586,15 @@ fn attr_on_expr() { check( r#"fn main() { #[$0] foo() }"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at cfg(…) at cfg_attr(…) at deny(…) at forbid(…) at warn(…) - kw self - kw super - kw crate "#]], ); } @@ -601,6 +604,9 @@ fn attr_in_source_file_end() { check( r#"#[$0]"#, expect![[r#" + kw self:: + kw super:: + kw crate:: at allow(…) at automatically_derived at cfg(…) @@ -637,9 +643,6 @@ fn attr_in_source_file_end() { at track_caller at used at warn(…) - kw self - kw super - kw crate "#]], ); } diff --git a/crates/ide_completion/src/tests/use_tree.rs b/crates/ide_completion/src/tests/use_tree.rs index 5f20e342e0..ac7e75bd38 100644 --- a/crates/ide_completion/src/tests/use_tree.rs +++ b/crates/ide_completion/src/tests/use_tree.rs @@ -135,6 +135,25 @@ struct Bar; } #[test] +fn enum_plain_qualified_use_tree() { + cov_mark::check!(enum_plain_qualified_use_tree); + check( + r#" +use Foo::$0 + +enum Foo { Variant } +impl Foo { + const CONST: () = () + fn func() {} +} +"#, + expect![[r#" + ev Variant () + "#]], + ); +} + +#[test] fn self_qualified_use_tree() { check( r#" diff --git a/crates/ide_completion/src/tests/visibility.rs b/crates/ide_completion/src/tests/visibility.rs index 2fd16235dc..8fdfeccb9a 100644 --- a/crates/ide_completion/src/tests/visibility.rs +++ b/crates/ide_completion/src/tests/visibility.rs @@ -17,9 +17,6 @@ pub($0) "#, expect![[r#" kw in - kw self - kw super - kw crate "#]], ); } @@ -30,11 +27,7 @@ fn after_in_kw() { r#" pub(in $0) "#, - expect![[r#" - kw self - kw super - kw crate - "#]], + expect![[r#""#]], ); } diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs index dcfc2b7bfc..7ea2bc63f2 100644 --- a/crates/ide_db/src/search.rs +++ b/crates/ide_db/src/search.rs @@ -223,7 +223,7 @@ impl Definition { // def is crate root // FIXME: We don't do searches for crates currently, as a crate does not actually have a single name if let &Definition::Module(module) = self { - if module.crate_root(db) == module { + if module.is_crate_root(db) { return SearchScope::reverse_dependencies(db, module.krate()); } } @@ -378,7 +378,7 @@ impl<'a> FindUsages<'a> { let name = match self.def { // special case crate modules as these do not have a proper name - Definition::Module(module) if module.crate_root(self.sema.db) == module => { + Definition::Module(module) if module.is_crate_root(self.sema.db) => { // FIXME: This assumes the crate name is always equal to its display name when it really isn't module .krate() @@ -460,7 +460,7 @@ impl<'a> FindUsages<'a> { Definition::Module(module) => { let scope = search_scope.intersection(&SearchScope::module(self.sema.db, module)); - let is_crate_root = module.crate_root(self.sema.db) == module; + let is_crate_root = module.is_crate_root(self.sema.db); for (text, file_id, search_range) in scope_files(sema, &scope) { let tree = Lazy::new(move || sema.parse(file_id).syntax().clone()); |