diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs index 715bd28e21..be056a9b63 100644 --- a/crates/ide_completion/src/completions.rs +++ b/crates/ide_completion/src/completions.rs @@ -8,7 +8,6 @@ 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; @@ -16,6 +15,8 @@ pub(crate) mod record; pub(crate) mod snippet; pub(crate) mod trait_impl; pub(crate) mod unqualified_path; +pub(crate) mod use_; +pub(crate) mod vis; use std::iter; diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index 6b013c9122..7403e02458 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs @@ -34,11 +34,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte let has_block_expr_parent = ctx.has_block_expr_parent(); let expects_item = ctx.expects_item(); - if let Some(PathKind::Vis { has_in_token }) = ctx.path_kind() { - if !has_in_token { - cov_mark::hit!(kw_completion_in); - add_keyword("in", "in"); - } + if let Some(PathKind::Vis { .. }) = ctx.path_kind() { return; } if ctx.has_impl_or_trait_prev_sibling() { diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index 14195e8149..3ddbd5e2a2 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs @@ -62,26 +62,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon } match kind { - // Complete next child module that comes after the qualified module which is still our parent - Some(PathKind::Vis { .. }) => { - if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution { - if let Some(current_module) = ctx.module { - let next_towards_current = current_module - .path_to_root(ctx.db) - .into_iter() - .take_while(|it| it != module) - .next(); - if let Some(next) = next_towards_current { - if let Some(name) = next.name(ctx.db) { - cov_mark::hit!(visibility_qualified); - acc.add_resolution(ctx, name, ScopeDef::ModuleDef(next.into())); - } - } - } - } - return; - } - Some(PathKind::Attr { .. } | PathKind::Use) => { + Some(PathKind::Attr { .. } | PathKind::Vis { .. } | PathKind::Use) => { return; } Some(PathKind::Pat) => (), diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 1f78cfdf75..b7f6d8d883 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs @@ -15,15 +15,15 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC if ctx.is_path_disallowed() || ctx.has_impl_or_trait_prev_sibling() { return; } - let kind = match ctx.path_context { - Some(PathCompletionContext { is_trivial_path: true, kind, .. }) => kind, + match ctx.path_context { + Some(PathCompletionContext { + kind: Some(PathKind::Vis { .. } | PathKind::Attr { .. } | PathKind::Use { .. }), + .. + }) => return, + Some(PathCompletionContext { is_trivial_path: true, .. }) => (), _ => return, - }; - - match kind { - 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 { diff --git a/crates/ide_completion/src/completions/use_.rs b/crates/ide_completion/src/completions/use_.rs index b536095862..222f95258e 100644 --- a/crates/ide_completion/src/completions/use_.rs +++ b/crates/ide_completion/src/completions/use_.rs @@ -1,8 +1,4 @@ //! 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; diff --git a/crates/ide_completion/src/completions/vis.rs b/crates/ide_completion/src/completions/vis.rs new file mode 100644 index 0000000000..0ac1393b53 --- /dev/null +++ b/crates/ide_completion/src/completions/vis.rs @@ -0,0 +1,56 @@ +//! Completion for visibility specifiers. + +use std::iter; + +use hir::ScopeDef; + +use crate::{ + context::{CompletionContext, PathCompletionContext, PathKind}, + Completions, +}; + +pub(crate) fn complete_vis(acc: &mut Completions, ctx: &CompletionContext) { + let (is_trivial_path, qualifier, has_in_token) = match ctx.path_context { + Some(PathCompletionContext { + kind: Some(PathKind::Vis { has_in_token }), + is_trivial_path, + ref qualifier, + .. + }) => (is_trivial_path, qualifier, has_in_token), + _ => return, + }; + + match qualifier { + Some((path, qualifier)) => { + if let Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) = qualifier { + if let Some(current_module) = ctx.module { + let next_towards_current = current_module + .path_to_root(ctx.db) + .into_iter() + .take_while(|it| it != module) + .next(); + if let Some(next) = next_towards_current { + if let Some(name) = next.name(ctx.db) { + cov_mark::hit!(visibility_qualified); + acc.add_resolution(ctx, name, ScopeDef::ModuleDef(next.into())); + } + } + } + } + + 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::"); + } + } + None if is_trivial_path => { + if !has_in_token { + cov_mark::hit!(kw_completion_in); + acc.add_keyword(ctx, "in"); + } + ["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 2f7ca13ee8..f0cd125973 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs @@ -154,6 +154,7 @@ pub fn completions( 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::vis::complete_vis(&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/visibility.rs b/crates/ide_completion/src/tests/visibility.rs index 8fdfeccb9a..2fd16235dc 100644 --- a/crates/ide_completion/src/tests/visibility.rs +++ b/crates/ide_completion/src/tests/visibility.rs @@ -17,6 +17,9 @@ pub($0) "#, expect![[r#" kw in + kw self + kw super + kw crate "#]], ); } @@ -27,7 +30,11 @@ fn after_in_kw() { r#" pub(in $0) "#, - expect![[r#""#]], + expect![[r#" + kw self + kw super + kw crate + "#]], ); }