Unnamed repository; edit this file 'description' to name the repository.
20 files changed, 199 insertions, 135 deletions
diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs index 07f5eab514..ac33d56858 100644 --- a/crates/ide_assists/src/handlers/generate_function.rs +++ b/crates/ide_assists/src/handlers/generate_function.rs @@ -111,6 +111,10 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { fn gen_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { let call: ast::MethodCallExpr = ctx.find_node_at_offset()?; + if ctx.sema.resolve_method_call(&call).is_some() { + return None; + } + let fn_name = call.name_ref()?; let adt = ctx.sema.type_of_expr(&call.receiver()?)?.original().strip_references().as_adt()?; @@ -481,7 +485,12 @@ fn fn_arg_name(sema: &Semantics<RootDatabase>, arg_expr: &ast::Expr) -> String { let name = (|| match arg_expr { ast::Expr::CastExpr(cast_expr) => Some(fn_arg_name(sema, &cast_expr.expr()?)), expr => { - let name_ref = expr.syntax().descendants().filter_map(ast::NameRef::cast).last()?; + let name_ref = expr + .syntax() + .descendants() + .filter_map(ast::NameRef::cast) + .filter(|name| name.ident_token().is_some()) + .last()?; if let Some(NameRefClass::Definition(Definition::Const(_) | Definition::Static(_))) = NameRefClass::classify(sema, &name_ref) { @@ -1660,7 +1669,7 @@ fn main() { foo(a.0); } -fn foo(arg0: ()) ${0:-> _} { +fn foo(a: ()) ${0:-> _} { todo!() } ", diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs index a072d223e0..92074b3e10 100644 --- a/crates/ide_completion/src/completions.rs +++ b/crates/ide_completion/src/completions.rs @@ -18,16 +18,16 @@ pub(crate) mod format_string; use std::iter; -use hir::known; +use hir::{known, ScopeDef}; use ide_db::SymbolKind; use crate::{ + context::Visible, item::Builder, render::{ const_::render_const, enum_variant::render_variant, function::{render_fn, render_method}, - macro_::render_macro, pattern::{render_struct_pat, render_variant_pat}, render_field, render_resolution, render_tuple_field, struct_literal::render_struct_literal, @@ -37,6 +37,22 @@ use crate::{ CompletionContext, CompletionItem, CompletionItemKind, }; +fn module_or_attr(def: ScopeDef) -> Option<ScopeDef> { + match def { + ScopeDef::MacroDef(mac) if mac.is_attr() => Some(def), + ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => Some(def), + _ => None, + } +} + +fn module_or_fn_macro(def: ScopeDef) -> Option<ScopeDef> { + match def { + ScopeDef::MacroDef(mac) if mac.is_fn_like() => Some(def), + ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => Some(def), + _ => None, + } +} + /// Represents an in-progress set of completions being built. #[derive(Debug, Default)] pub struct Completions { @@ -91,20 +107,7 @@ impl Completions { cov_mark::hit!(qualified_path_doc_hidden); return; } - self.add(render_resolution(RenderContext::new(ctx), local_name, resolution)); - } - - pub(crate) fn add_macro( - &mut self, - ctx: &CompletionContext, - name: Option<hir::Name>, - macro_: hir::MacroDef, - ) { - let name = match name { - Some(it) => it, - None => return, - }; - self.add(render_macro(RenderContext::new(ctx), None, name, macro_)); + self.add(render_resolution(RenderContext::new(ctx, false), local_name, resolution)); } pub(crate) fn add_function( @@ -113,10 +116,12 @@ impl Completions { func: hir::Function, local_name: Option<hir::Name>, ) { - if !ctx.is_visible(&func) { - return; - } - self.add(render_fn(RenderContext::new(ctx), None, local_name, func)); + let is_private_editable = match ctx.is_visible(&func) { + Visible::Yes => false, + Visible::Editable => true, + Visible::No => return, + }; + self.add(render_fn(RenderContext::new(ctx, is_private_editable), None, local_name, func)); } pub(crate) fn add_method( @@ -126,24 +131,36 @@ impl Completions { receiver: Option<hir::Name>, local_name: Option<hir::Name>, ) { - if !ctx.is_visible(&func) { - return; - } - self.add(render_method(RenderContext::new(ctx), None, receiver, local_name, func)); + let is_private_editable = match ctx.is_visible(&func) { + Visible::Yes => false, + Visible::Editable => true, + Visible::No => return, + }; + self.add(render_method( + RenderContext::new(ctx, is_private_editable), + None, + receiver, + local_name, + func, + )); } pub(crate) fn add_const(&mut self, ctx: &CompletionContext, konst: hir::Const) { - if !ctx.is_visible(&konst) { - return; - } - self.add_opt(render_const(RenderContext::new(ctx), konst)); + let is_private_editable = match ctx.is_visible(&konst) { + Visible::Yes => false, + Visible::Editable => true, + Visible::No => return, + }; + self.add_opt(render_const(RenderContext::new(ctx, is_private_editable), konst)); } pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) { - if !ctx.is_visible(&type_alias) { - return; - } - self.add_opt(render_type_alias(RenderContext::new(ctx), type_alias)); + let is_private_editable = match ctx.is_visible(&type_alias) { + Visible::Yes => false, + Visible::Editable => true, + Visible::No => return, + }; + self.add_opt(render_type_alias(RenderContext::new(ctx, is_private_editable), type_alias)); } pub(crate) fn add_type_alias_with_eq( @@ -151,7 +168,7 @@ impl Completions { ctx: &CompletionContext, type_alias: hir::TypeAlias, ) { - self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias)); + self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx, false), type_alias)); } pub(crate) fn add_qualified_enum_variant( @@ -160,7 +177,7 @@ impl Completions { variant: hir::Variant, path: hir::ModPath, ) { - let item = render_variant(RenderContext::new(ctx), None, None, variant, Some(path)); + let item = render_variant(RenderContext::new(ctx, false), None, None, variant, Some(path)); self.add(item); } @@ -170,7 +187,7 @@ impl Completions { variant: hir::Variant, local_name: Option<hir::Name>, ) { - let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None); + let item = render_variant(RenderContext::new(ctx, false), None, local_name, variant, None); self.add(item); } @@ -181,10 +198,12 @@ impl Completions { field: hir::Field, ty: &hir::Type, ) { - if !ctx.is_visible(&field) { - return; - } - let item = render_field(RenderContext::new(ctx), receiver, field, ty); + let is_private_editable = match ctx.is_visible(&field) { + Visible::Yes => false, + Visible::Editable => true, + Visible::No => return, + }; + let item = render_field(RenderContext::new(ctx, is_private_editable), receiver, field, ty); self.add(item); } @@ -195,7 +214,7 @@ impl Completions { path: Option<hir::ModPath>, local_name: Option<hir::Name>, ) { - let item = render_struct_literal(RenderContext::new(ctx), strukt, path, local_name); + let item = render_struct_literal(RenderContext::new(ctx, false), strukt, path, local_name); self.add_opt(item); } @@ -206,13 +225,17 @@ impl Completions { field: usize, ty: &hir::Type, ) { - let item = render_tuple_field(RenderContext::new(ctx), receiver, field, ty); + let item = render_tuple_field(RenderContext::new(ctx, false), receiver, field, ty); self.add(item); } - pub(crate) fn add_static_lifetime(&mut self, ctx: &CompletionContext) { - let item = CompletionItem::new(SymbolKind::LifetimeParam, ctx.source_range(), "'static"); - self.add(item.build()); + pub(crate) fn add_lifetime(&mut self, ctx: &CompletionContext, name: hir::Name) { + CompletionItem::new(SymbolKind::LifetimeParam, ctx.source_range(), name.to_smol_str()) + .add_to(self) + } + + pub(crate) fn add_label(&mut self, ctx: &CompletionContext, name: hir::Name) { + CompletionItem::new(SymbolKind::Label, ctx.source_range(), name.to_smol_str()).add_to(self) } pub(crate) fn add_variant_pat( @@ -221,7 +244,7 @@ impl Completions { variant: hir::Variant, local_name: Option<hir::Name>, ) { - self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, local_name, None)); + self.add_opt(render_variant_pat(RenderContext::new(ctx, false), variant, local_name, None)); } pub(crate) fn add_qualified_variant_pat( @@ -230,7 +253,7 @@ impl Completions { variant: hir::Variant, path: hir::ModPath, ) { - self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, None, Some(path))); + self.add_opt(render_variant_pat(RenderContext::new(ctx, false), variant, None, Some(path))); } pub(crate) fn add_struct_pat( @@ -239,7 +262,7 @@ impl Completions { strukt: hir::Struct, local_name: Option<hir::Name>, ) { - self.add_opt(render_struct_pat(RenderContext::new(ctx), strukt, local_name)); + self.add_opt(render_struct_pat(RenderContext::new(ctx, false), strukt, local_name)); } } diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs index 782a119c9e..8ca4634be2 100644 --- a/crates/ide_completion/src/completions/flyimport.rs +++ b/crates/ide_completion/src/completions/flyimport.rs @@ -193,7 +193,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) }) .filter_map(|import| { render_resolution_with_import( - RenderContext::new(ctx), + RenderContext::new(ctx, false), ImportEdit { import, scope: import_scope.clone() }, ) }), diff --git a/crates/ide_completion/src/completions/lifetime.rs b/crates/ide_completion/src/completions/lifetime.rs index 4082414f02..878d72ea0f 100644 --- a/crates/ide_completion/src/completions/lifetime.rs +++ b/crates/ide_completion/src/completions/lifetime.rs @@ -7,7 +7,7 @@ //! there is no value in lifting these out into the outline module test since they will either not //! show up for normal completions, or they won't show completions other than lifetimes depending //! on the fixture input. -use hir::ScopeDef; +use hir::{known, ScopeDef}; use syntax::ast; use crate::{ @@ -35,12 +35,12 @@ pub(crate) fn complete_lifetime(acc: &mut Completions, ctx: &CompletionContext) ctx.scope.process_all_names(&mut |name, res| { if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { if param_lifetime != Some(&*name.to_smol_str()) { - acc.add_resolution(ctx, name, res); + acc.add_lifetime(ctx, name); } } }); if param_lifetime.is_none() { - acc.add_static_lifetime(ctx); + acc.add_lifetime(ctx, known::STATIC_LIFETIME); } } @@ -51,7 +51,7 @@ pub(crate) fn complete_label(acc: &mut Completions, ctx: &CompletionContext) { } ctx.scope.process_all_names(&mut |name, res| { if let ScopeDef::Label(_) = res { - acc.add_resolution(ctx, name, res); + acc.add_label(ctx, name); } }); } diff --git a/crates/ide_completion/src/completions/mod_.rs b/crates/ide_completion/src/completions/mod_.rs index 64e992c2e6..7699c530c6 100644 --- a/crates/ide_completion/src/completions/mod_.rs +++ b/crates/ide_completion/src/completions/mod_.rs @@ -13,7 +13,7 @@ use crate::{patterns::ImmediateLocation, CompletionItem}; use crate::{context::CompletionContext, Completions}; -/// Complete mod declaration, i.e. `mod $0 ;` +/// Complete mod declaration, i.e. `mod $0;` pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { let mod_under_caret = match &ctx.completion_location { Some(ImmediateLocation::ModDeclaration(mod_under_caret)) => mod_under_caret, diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index 85df19f1dd..cd1022b2e3 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs @@ -7,6 +7,7 @@ use rustc_hash::FxHashSet; use syntax::{ast, AstNode}; use crate::{ + completions::{module_or_attr, module_or_fn_macro}, context::{PathCompletionContext, PathKind}, patterns::ImmediateLocation, CompletionContext, Completions, @@ -57,12 +58,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => { if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution { for (name, def) in module.scope(ctx.db, context_module) { - if let ScopeDef::MacroDef(macro_def) = def { - if macro_def.is_fn_like() { - acc.add_macro(ctx, Some(name.clone()), macro_def); - } - } - if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def { + if let Some(def) = module_or_fn_macro(def) { acc.add_resolution(ctx, name, def); } } @@ -73,16 +69,18 @@ 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 { - if let Some(next) = current_module + let next_towards_current = current_module .path_to_root(ctx.db) .into_iter() .take_while(|&it| it != module) - .next() - { + .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())); } } @@ -93,12 +91,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon Some(PathKind::Attr) => { if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution { for (name, def) in module.scope(ctx.db, context_module) { - let add_resolution = match def { - ScopeDef::MacroDef(mac) => mac.is_attr(), - ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true, - _ => false, - }; - if add_resolution { + if let Some(def) = module_or_attr(def) { acc.add_resolution(ctx, name, def); } } @@ -263,7 +256,6 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon ); } } - hir::PathResolution::Macro(mac) => acc.add_macro(ctx, None, mac), _ => {} } } diff --git a/crates/ide_completion/src/completions/record.rs b/crates/ide_completion/src/completions/record.rs index ec1ee292be..13b4735619 100644 --- a/crates/ide_completion/src/completions/record.rs +++ b/crates/ide_completion/src/completions/record.rs @@ -3,7 +3,8 @@ use ide_db::SymbolKind; use syntax::{ast::Expr, T}; use crate::{ - patterns::ImmediateLocation, CompletionContext, CompletionItem, CompletionItemKind, Completions, + patterns::ImmediateLocation, CompletionContext, CompletionItem, CompletionItemKind, + CompletionRelevance, Completions, }; pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { @@ -25,7 +26,10 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text); let completion_text = completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text); - item.insert_text(completion_text); + item.insert_text(completion_text).set_relevance(CompletionRelevance { + exact_postfix_snippet_match: true, + ..Default::default() + }); item.add_to(acc); } if ctx.previous_token_is(T![.]) { diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs index b214c5c154..7a42cfbd42 100644 --- a/crates/ide_completion/src/completions/trait_impl.rs +++ b/crates/ide_completion/src/completions/trait_impl.rs @@ -42,7 +42,7 @@ use text_edit::TextEdit; use crate::{CompletionContext, CompletionItem, CompletionItemKind, Completions}; -#[derive(Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] enum ImplCompletionKind { All, Fn, @@ -53,23 +53,22 @@ enum ImplCompletionKind { pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { if let Some((kind, trigger, impl_def)) = completion_match(ctx.token.clone()) { if let Some(hir_impl) = ctx.sema.to_def(&impl_def) { - get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| match item { - hir::AssocItem::Function(fn_item) - if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Fn => - { - add_function_impl(&trigger, acc, ctx, fn_item, hir_impl) + get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| { + match (item, kind) { + ( + hir::AssocItem::Function(fn_item), + ImplCompletionKind::All | ImplCompletionKind::Fn, + ) => add_function_impl(&trigger, acc, ctx, fn_item, hir_impl), + ( + hir::AssocItem::TypeAlias(type_item), + ImplCompletionKind::All | ImplCompletionKind::TypeAlias, + ) => add_type_alias_impl(&trigger, acc, ctx, type_item), + ( + hir::AssocItem::Const(const_item), + ImplCompletionKind::All | ImplCompletionKind::Const, + ) => add_const_impl(&trigger, acc, ctx, const_item, hir_impl), + _ => {} } - hir::AssocItem::TypeAlias(type_item) - if kind == ImplCompletionKind::All || kind == ImplCompletionKind::TypeAlias => - { - add_type_alias_impl(&trigger, acc, ctx, type_item) - } - hir::AssocItem::Const(const_item) - if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Const => - { - add_const_impl(&trigger, acc, ctx, const_item, hir_impl) - } - _ => {} }); } } @@ -194,7 +193,7 @@ fn get_transformed_assoc_item( transform.apply(assoc_item.syntax()); if let ast::AssocItem::Fn(func) = &assoc_item { - func.remove_attrs_and_docs() + func.remove_attrs_and_docs(); } Some(assoc_item) } diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index e7980c12d7..7e06b074ce 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs @@ -4,6 +4,7 @@ use hir::ScopeDef; use syntax::{ast, AstNode}; use crate::{ + completions::{module_or_attr, module_or_fn_macro}, context::{PathCompletionContext, PathKind}, patterns::ImmediateLocation, CompletionContext, Completions, @@ -36,14 +37,9 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC match kind { Some(PathKind::Vis { .. }) => return, Some(PathKind::Attr) => { - ctx.process_all_names(&mut |name, res| { - let add_resolution = match res { - ScopeDef::MacroDef(mac) => mac.is_attr(), - ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true, - _ => false, - }; - if add_resolution { - acc.add_resolution(ctx, name, res); + ctx.process_all_names(&mut |name, def| { + if let Some(def) = module_or_attr(def) { + acc.add_resolution(ctx, name, def); } }); return; @@ -54,14 +50,9 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC match &ctx.completion_location { Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => { // only show macros in {Assoc}ItemList - ctx.process_all_names(&mut |name, res| { - if let hir::ScopeDef::MacroDef(mac) = res { - if mac.is_fn_like() { - acc.add_macro(ctx, Some(name.clone()), mac); - } - } - if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { - acc.add_resolution(ctx, name, res); + ctx.process_all_names(&mut |name, def| { + if let Some(def) = module_or_fn_macro(def) { + acc.add_resolution(ctx, name, def); } }); return; diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index a31a552dad..ab55d9cc04 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs @@ -34,6 +34,11 @@ pub(crate) enum PatternRefutability { Refutable, Irrefutable, } +pub(crate) enum Visible { + Yes, + Editable, + No, +} #[derive(Copy, Clone, Debug)] pub(super) enum PathKind { @@ -103,7 +108,7 @@ pub(crate) struct CompletionContext<'a> { pub(super) token: SyntaxToken, /// The crate of the current file. pub(super) krate: Option<hir::Crate>, - /// The crate of the `scope`. + /// The module of the `scope`. pub(super) module: Option<hir::Module>, pub(super) expected_name: Option<NameOrNameRef>, pub(super) expected_type: Option<Type>, @@ -285,7 +290,7 @@ impl<'a> CompletionContext<'a> { } /// Checks if an item is visible and not `doc(hidden)` at the completion site. - pub(crate) fn is_visible<I>(&self, item: &I) -> bool + pub(crate) fn is_visible<I>(&self, item: &I) -> Visible where I: hir::HasVisibility + hir::HasAttrs + hir::HasCrate + Copy, { @@ -339,20 +344,24 @@ impl<'a> CompletionContext<'a> { vis: &hir::Visibility, attrs: &hir::Attrs, defining_crate: hir::Crate, - ) -> bool { + ) -> Visible { let module = match self.module { Some(it) => it, - None => return false, + None => return Visible::No, }; if !vis.is_visible_from(self.db, module.into()) { // If the definition location is editable, also show private items let root_file = defining_crate.root_file(self.db); let source_root_id = self.db.file_source_root(root_file); let is_editable = !self.db.source_root(source_root_id).is_library; - return is_editable; + return if is_editable { Visible::Editable } else { Visible::No }; } - !self.is_doc_hidden(attrs, defining_crate) + if self.is_doc_hidden(attrs, defining_crate) { + Visible::No + } else { + Visible::Yes + } } fn is_doc_hidden(&self, attrs: &hir::Attrs, defining_crate: hir::Crate) -> bool { diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs index b2a0b04b4f..acaf17c255 100644 --- a/crates/ide_completion/src/item.rs +++ b/crates/ide_completion/src/item.rs @@ -141,6 +141,8 @@ pub struct CompletionRelevance { pub is_local: bool, /// Set for method completions of the `core::ops` and `core::cmp` family. pub is_op_method: bool, + /// Set for item completions that are private but in the workspace. + pub is_private_editable: bool, /// This is set in cases like these: /// /// ``` @@ -177,7 +179,7 @@ pub enum CompletionRelevanceTypeMatch { } impl CompletionRelevance { - const BASE_LINE: u32 = 1; + const BASE_LINE: u32 = 2; /// Provides a relevance score. Higher values are more relevant. /// /// The absolute value of the relevance score is not meaningful, for @@ -190,6 +192,15 @@ impl CompletionRelevance { pub fn score(&self) -> u32 { let mut score = Self::BASE_LINE; + // score decreases + if self.is_op_method { + score -= 1; + } + if self.is_private_editable { + score -= 1; + } + + // score increases if self.exact_name_match { score += 1; } @@ -201,9 +212,6 @@ impl CompletionRelevance { if self.is_local { score += 1; } - if self.is_op_method { - score -= 1; - } if self.exact_postfix_snippet_match { score += 100; } @@ -214,7 +222,7 @@ impl CompletionRelevance { /// some threshold such that we think it is especially likely /// to be relevant. pub fn is_relevant(&self) -> bool { - self.score() > (Self::BASE_LINE + 1) + self.score() > Self::BASE_LINE } } @@ -564,7 +572,15 @@ mod tests { // This test asserts that the relevance score for these items is ascending, and // that any items in the same vec have the same score. let expected_relevance_order = vec![ - vec![CompletionRelevance { is_op_method: true, ..CompletionRelevance::default() }], + vec![CompletionRelevance { + is_op_method: true, + is_private_editable: true, + ..CompletionRelevance::default() + }], + vec![ + CompletionRelevance { is_private_editable: true, ..CompletionRelevance::default() }, + CompletionRelevance { is_op_method: true, ..CompletionRelevance::default() }, + ], vec![CompletionRelevance::default()], vec![ CompletionRelevance { exact_name_match: true, ..CompletionRelevance::default() }, diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index 5feee48a96..6be2651123 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs @@ -28,11 +28,15 @@ use crate::{ #[derive(Debug)] pub(crate) struct RenderContext<'a> { completion: &'a CompletionContext<'a>, + is_private_editable: bool, } impl<'a> RenderContext<'a> { - pub(crate) fn new(completion: &'a CompletionContext<'a>) -> RenderContext<'a> { - RenderContext { completion } + pub(crate) fn new( + completion: &'a CompletionContext<'a>, + is_private_editable: bool, + ) -> RenderContext<'a> { + RenderContext { completion, is_private_editable } } fn snippet_cap(&self) -> Option<SnippetCap> { @@ -47,6 +51,10 @@ impl<'a> RenderContext<'a> { self.completion.source_range() } + fn completion_relevance(&self) -> CompletionRelevance { + CompletionRelevance { is_private_editable: self.is_private_editable, ..Default::default() } + } + fn is_deprecated(&self, def: impl HasAttrs) -> bool { let attrs = def.attrs(self.db()); attrs.by_key("deprecated").exists() || attrs.by_key("rustc_deprecated").exists() @@ -582,6 +590,7 @@ fn main() { let _: m::Spam = S$0 } ), is_local: false, is_op_method: false, + is_private_editable: false, exact_postfix_snippet_match: false, }, trigger_call_info: true, @@ -603,6 +612,7 @@ fn main() { let _: m::Spam = S$0 } ), is_local: false, is_op_method: false, + is_private_editable: false, exact_postfix_snippet_match: false, }, }, @@ -689,6 +699,7 @@ fn foo() { A { the$0 } } ), is_local: false, is_op_method: false, + is_private_editable: false, exact_postfix_snippet_match: false, }, }, diff --git a/crates/ide_completion/src/render/const_.rs b/crates/ide_completion/src/render/const_.rs index 4c8258f12c..89e6c82dde 100644 --- a/crates/ide_completion/src/render/const_.rs +++ b/crates/ide_completion/src/render/const_.rs @@ -18,7 +18,8 @@ fn render(ctx: RenderContext<'_>, const_: hir::Const) -> Option<CompletionItem> let mut item = CompletionItem::new(SymbolKind::Const, ctx.source_range(), name.clone()); item.set_documentation(ctx.docs(const_)) .set_deprecated(ctx.is_deprecated(const_) || ctx.is_deprecated_assoc_item(const_)) - .detail(detail); + .detail(detail) + .set_relevance(ctx.completion_relevance()); if let Some(actm) = const_.as_assoc_item(db) { if let Some(trt) = actm.containing_trait_or_trait_impl(db) { diff --git a/crates/ide_completion/src/render/enum_variant.rs b/crates/ide_completion/src/render/enum_variant.rs index f0fb3c7a7f..914ace910d 100644 --- a/crates/ide_completion/src/render/enum_variant.rs +++ b/crates/ide_completion/src/render/enum_variant.rs @@ -23,7 +23,7 @@ pub(crate) fn render_variant( } fn render( - ctx @ RenderContext { completion }: RenderContext<'_>, + ctx @ RenderContext { completion, .. }: RenderContext<'_>, local_name: Option<hir::Name>, variant: hir::Variant, path: Option<hir::ModPath>, @@ -58,18 +58,18 @@ fn render( if variant_kind == hir::StructKind::Tuple { cov_mark::hit!(inserts_parens_for_tuple_enums); let params = Params::Anonymous(variant.fields(db).len()); - item.add_call_parens(ctx.completion, short_qualified_name, params); + item.add_call_parens(completion, short_qualified_name, params); } else if qualified { item.lookup_by(short_qualified_name); } - let ty = variant.parent_enum(ctx.completion.db).ty(ctx.completion.db); + let ty = variant.parent_enum(completion.db).ty(completion.db); item.set_relevance(CompletionRelevance { - type_match: compute_type_match(ctx.completion, &ty), - ..CompletionRelevance::default() + type_match: compute_type_match(completion, &ty), + ..ctx.completion_relevance() }); - if let Some(ref_match) = compute_ref_match(ctx.completion, &ty) { + if let Some(ref_match) = compute_ref_match(completion, &ty) { item.ref_match(ref_match); } diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs index 224d4b054e..20c7fe657c 100644 --- a/crates/ide_completion/src/render/function.rs +++ b/crates/ide_completion/src/render/function.rs @@ -41,7 +41,7 @@ pub(crate) fn render_method( } fn render( - ctx @ RenderContext { completion }: RenderContext<'_>, + ctx @ RenderContext { completion, .. }: RenderContext<'_>, local_name: Option<hir::Name>, func: hir::Function, func_type: FuncType, @@ -75,7 +75,7 @@ fn render( type_match: compute_type_match(completion, &ret_type), exact_name_match: compute_exact_name_match(completion, &call), is_op_method, - ..CompletionRelevance::default() + ..ctx.completion_relevance() }); if let Some(ref_match) = compute_ref_match(completion, &ret_type) { diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs index 8d6a634953..29bd90aec9 100644 --- a/crates/ide_completion/src/render/macro_.rs +++ b/crates/ide_completion/src/render/macro_.rs @@ -25,7 +25,7 @@ pub(crate) fn render_macro( } fn render( - ctx @ RenderContext { completion }: RenderContext<'_>, + ctx @ RenderContext { completion, .. }: RenderContext<'_>, name: hir::Name, macro_: hir::MacroDef, import_to_add: Option<ImportEdit>, @@ -53,7 +53,8 @@ fn render( ); item.set_deprecated(ctx.is_deprecated(macro_)) .set_detail(detail(&completion.sema, macro_)) - .set_documentation(docs); + .set_documentation(docs) + .set_relevance(ctx.completion_relevance()); if let Some(import_to_add) = import_to_add { item.add_import(import_to_add); diff --git a/crates/ide_completion/src/render/pattern.rs b/crates/ide_completion/src/render/pattern.rs index 641a15aa65..68e29246d7 100644 --- a/crates/ide_completion/src/render/pattern.rs +++ b/crates/ide_completion/src/render/pattern.rs @@ -59,7 +59,10 @@ fn build_completion( def: impl HasAttrs + Copy, ) -> CompletionItem { let mut item = CompletionItem::new(CompletionItemKind::Binding, ctx.source_range(), name); - item.set_documentation(ctx.docs(def)).set_deprecated(ctx.is_deprecated(def)).detail(&pat); + item.set_documentation(ctx.docs(def)) + .set_deprecated(ctx.is_deprecated(def)) + .detail(&pat) + .set_relevance(ctx.completion_relevance()); match ctx.snippet_cap() { Some(snippet_cap) => item.insert_snippet(snippet_cap, pat), None => item.insert_text(pat), diff --git a/crates/ide_completion/src/render/struct_literal.rs b/crates/ide_completion/src/render/struct_literal.rs index 6be7b9d43b..a3d4bcf29e 100644 --- a/crates/ide_completion/src/render/struct_literal.rs +++ b/crates/ide_completion/src/render/struct_literal.rs @@ -41,7 +41,10 @@ fn build_completion( ctx.source_range(), SmolStr::from_iter([&name, " {…}"]), ); - item.set_documentation(ctx.docs(def)).set_deprecated(ctx.is_deprecated(def)).detail(&literal); + item.set_documentation(ctx.docs(def)) + .set_deprecated(ctx.is_deprecated(def)) + .detail(&literal) + .set_relevance(ctx.completion_relevance()); match ctx.snippet_cap() { Some(snippet_cap) => item.insert_snippet(snippet_cap, literal), None => item.insert_text(literal), diff --git a/crates/ide_completion/src/render/type_alias.rs b/crates/ide_completion/src/render/type_alias.rs index 5bfb4349ed..a518be87bf 100644 --- a/crates/ide_completion/src/render/type_alias.rs +++ b/crates/ide_completion/src/render/type_alias.rs @@ -39,7 +39,8 @@ fn render( let mut item = CompletionItem::new(SymbolKind::TypeAlias, ctx.source_range(), name.clone()); item.set_documentation(ctx.docs(type_alias)) .set_deprecated(ctx.is_deprecated(type_alias) || ctx.is_deprecated_assoc_item(type_alias)) - .detail(detail); + .detail(detail) + .set_relevance(ctx.completion_relevance()); if let Some(actm) = type_alias.as_assoc_item(db) { if let Some(trt) = actm.containing_trait_or_trait_impl(db) { diff --git a/crates/ide_completion/src/tests/visibility.rs b/crates/ide_completion/src/tests/visibility.rs index 8a024af24b..2fd16235dc 100644 --- a/crates/ide_completion/src/tests/visibility.rs +++ b/crates/ide_completion/src/tests/visibility.rs @@ -40,6 +40,7 @@ pub(in $0) #[test] fn qualified() { + cov_mark::check!(visibility_qualified); check( r#" mod foo { |