From 3dbbcfca67ed09322227f2190b5364754a29a216 Mon Sep 17 00:00:00 2001 From: adamrk Date: Tue, 29 Sep 2020 22:24:56 +0200 Subject: Insert ref for completions --- crates/completion/src/completion_context.rs | 13 ++++++++ crates/completion/src/completion_item.rs | 21 +++++++++++- crates/completion/src/presentation.rs | 51 +++++++++++++++++++---------- 3 files changed, 66 insertions(+), 19 deletions(-) (limited to 'crates/completion') diff --git a/crates/completion/src/completion_context.rs b/crates/completion/src/completion_context.rs index dc4e136c6..e4f86d0e0 100644 --- a/crates/completion/src/completion_context.rs +++ b/crates/completion/src/completion_context.rs @@ -246,6 +246,19 @@ impl<'a> CompletionContext<'a> { } } + pub(crate) fn active_name_and_type(&self) -> Option<(String, Type)> { + if let Some(record_field) = &self.record_field_syntax { + mark::hit!(record_field_type_match); + let (struct_field, _local) = self.sema.resolve_record_field(record_field)?; + Some((struct_field.name(self.db).to_string(), struct_field.signature_ty(self.db))) + } else if let Some(active_parameter) = &self.active_parameter { + mark::hit!(active_param_type_match); + Some((active_parameter.name.clone(), active_parameter.ty.clone())) + } else { + None + } + } + fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) { let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap(); let syntax_element = NodeOrToken::Token(fake_ident_token); diff --git a/crates/completion/src/completion_item.rs b/crates/completion/src/completion_item.rs index f8be0ad2b..2e1ca0e59 100644 --- a/crates/completion/src/completion_item.rs +++ b/crates/completion/src/completion_item.rs @@ -2,7 +2,7 @@ use std::fmt; -use hir::Documentation; +use hir::{Documentation, Mutability}; use syntax::TextRange; use text_edit::TextEdit; @@ -56,6 +56,10 @@ pub struct CompletionItem { /// Score is useful to pre select or display in better order completion items score: Option, + + /// Indicates that a reference or mutable reference to this variable is a + /// possible match. + ref_match: Option<(Mutability, CompletionScore)>, } // We use custom debug for CompletionItem to make snapshot tests more readable. @@ -194,6 +198,7 @@ impl CompletionItem { deprecated: None, trigger_call_info: None, score: None, + ref_match: None, } } /// What user sees in pop-up in the UI. @@ -240,10 +245,15 @@ impl CompletionItem { pub fn trigger_call_info(&self) -> bool { self.trigger_call_info } + + pub fn ref_match(&self) -> Option<(Mutability, CompletionScore)> { + self.ref_match + } } /// A helper to make `CompletionItem`s. #[must_use] +#[derive(Clone)] pub(crate) struct Builder { source_range: TextRange, completion_kind: CompletionKind, @@ -258,6 +268,7 @@ pub(crate) struct Builder { deprecated: Option, trigger_call_info: Option, score: Option, + ref_match: Option<(Mutability, CompletionScore)>, } impl Builder { @@ -288,6 +299,7 @@ impl Builder { deprecated: self.deprecated.unwrap_or(false), trigger_call_info: self.trigger_call_info.unwrap_or(false), score: self.score, + ref_match: self.ref_match, } } pub(crate) fn lookup_by(mut self, lookup: impl Into) -> Builder { @@ -350,6 +362,13 @@ impl Builder { self.trigger_call_info = Some(true); self } + pub(crate) fn set_ref_match( + mut self, + ref_match: Option<(Mutability, CompletionScore)>, + ) -> Builder { + self.ref_match = ref_match; + self + } } impl<'a> Into for Builder { diff --git a/crates/completion/src/presentation.rs b/crates/completion/src/presentation.rs index 0a0dc1ce5..2a19281cf 100644 --- a/crates/completion/src/presentation.rs +++ b/crates/completion/src/presentation.rs @@ -1,7 +1,7 @@ //! This modules takes care of rendering various definitions as completion items. //! It also handles scoring (sorting) completions. -use hir::{HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type}; +use hir::{HasAttrs, HasSource, HirDisplay, ModPath, Mutability, ScopeDef, StructKind, Type}; use itertools::Itertools; use syntax::{ast::NameOwner, display::*}; use test_utils::mark; @@ -107,9 +107,16 @@ impl Completions { } }; + let mut ref_match = None; if let ScopeDef::Local(local) = resolution { - if let Some(score) = compute_score(ctx, &local.ty(ctx.db), &local_name) { - completion_item = completion_item.set_score(score); + if let Some((active_name, active_type)) = ctx.active_name_and_type() { + let ty = local.ty(ctx.db); + if let Some(score) = + compute_score_from_active(&active_type, &active_name, &ty, &local_name) + { + completion_item = completion_item.set_score(score); + } + ref_match = refed_type_matches(&active_type, &active_name, &ty, &local_name); } } @@ -131,7 +138,7 @@ impl Completions { } } - completion_item.kind(kind).set_documentation(docs).add_to(self) + completion_item.kind(kind).set_documentation(docs).set_ref_match(ref_match).add_to(self) } pub(crate) fn add_macro( @@ -342,25 +349,15 @@ impl Completions { } } -pub(crate) fn compute_score( - ctx: &CompletionContext, +fn compute_score_from_active( + active_type: &Type, + active_name: &str, ty: &Type, name: &str, ) -> Option { - let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { - mark::hit!(record_field_type_match); - let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?; - (struct_field.name(ctx.db).to_string(), struct_field.signature_ty(ctx.db)) - } else if let Some(active_parameter) = &ctx.active_parameter { - mark::hit!(active_param_type_match); - (active_parameter.name.clone(), active_parameter.ty.clone()) - } else { - return None; - }; - // Compute score // For the same type - if &active_type != ty { + if active_type != ty { return None; } @@ -373,6 +370,24 @@ pub(crate) fn compute_score( Some(res) } +fn refed_type_matches( + active_type: &Type, + active_name: &str, + ty: &Type, + name: &str, +) -> Option<(Mutability, CompletionScore)> { + let derefed_active = active_type.remove_ref()?; + let score = compute_score_from_active(&derefed_active, &active_name, &ty, &name)?; + Some(( + if active_type.is_mutable_reference() { Mutability::Mut } else { Mutability::Shared }, + score, + )) +} + +fn compute_score(ctx: &CompletionContext, ty: &Type, name: &str) -> Option { + let (active_name, active_type) = ctx.active_name_and_type()?; + compute_score_from_active(&active_type, &active_name, ty, name) +} enum Params { Named(Vec), -- cgit v1.2.3