aboutsummaryrefslogtreecommitdiff
path: root/crates/completion
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-10-22 21:46:24 +0100
committerGitHub <[email protected]>2020-10-22 21:46:24 +0100
commit8b3c851dd37f39f79e7e8807378f45fdde7f6411 (patch)
treed6c20cd94e6291d6e4c3b8f58a17817d61463d79 /crates/completion
parentedf46a13a6a28093985d2d934ef97570947b9494 (diff)
parent3dbbcfca67ed09322227f2190b5364754a29a216 (diff)
Merge #6098
6098: Insert ref for completions r=adamrk a=adamrk Follow up to https://github.com/rust-analyzer/rust-analyzer/pull/5846. When we have a local in scope which needs a ref or mutable ref to match the name and type of the active in the completion context then a new completion item with `&` or `&mut ` is inserted. E.g. ```rust fn foo(arg: &i32){}; fn main() { let arg = 1_i32; foo(a<|>) } ``` now offers `&arg` as a completion option with the highest score. Co-authored-by: adamrk <[email protected]>
Diffstat (limited to 'crates/completion')
-rw-r--r--crates/completion/src/completion_context.rs13
-rw-r--r--crates/completion/src/completion_item.rs21
-rw-r--r--crates/completion/src/presentation.rs51
3 files changed, 66 insertions, 19 deletions
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> {
246 } 246 }
247 } 247 }
248 248
249 pub(crate) fn active_name_and_type(&self) -> Option<(String, Type)> {
250 if let Some(record_field) = &self.record_field_syntax {
251 mark::hit!(record_field_type_match);
252 let (struct_field, _local) = self.sema.resolve_record_field(record_field)?;
253 Some((struct_field.name(self.db).to_string(), struct_field.signature_ty(self.db)))
254 } else if let Some(active_parameter) = &self.active_parameter {
255 mark::hit!(active_param_type_match);
256 Some((active_parameter.name.clone(), active_parameter.ty.clone()))
257 } else {
258 None
259 }
260 }
261
249 fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) { 262 fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) {
250 let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap(); 263 let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap();
251 let syntax_element = NodeOrToken::Token(fake_ident_token); 264 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 @@
2 2
3use std::fmt; 3use std::fmt;
4 4
5use hir::Documentation; 5use hir::{Documentation, Mutability};
6use syntax::TextRange; 6use syntax::TextRange;
7use text_edit::TextEdit; 7use text_edit::TextEdit;
8 8
@@ -56,6 +56,10 @@ pub struct CompletionItem {
56 56
57 /// Score is useful to pre select or display in better order completion items 57 /// Score is useful to pre select or display in better order completion items
58 score: Option<CompletionScore>, 58 score: Option<CompletionScore>,
59
60 /// Indicates that a reference or mutable reference to this variable is a
61 /// possible match.
62 ref_match: Option<(Mutability, CompletionScore)>,
59} 63}
60 64
61// We use custom debug for CompletionItem to make snapshot tests more readable. 65// We use custom debug for CompletionItem to make snapshot tests more readable.
@@ -194,6 +198,7 @@ impl CompletionItem {
194 deprecated: None, 198 deprecated: None,
195 trigger_call_info: None, 199 trigger_call_info: None,
196 score: None, 200 score: None,
201 ref_match: None,
197 } 202 }
198 } 203 }
199 /// What user sees in pop-up in the UI. 204 /// What user sees in pop-up in the UI.
@@ -240,10 +245,15 @@ impl CompletionItem {
240 pub fn trigger_call_info(&self) -> bool { 245 pub fn trigger_call_info(&self) -> bool {
241 self.trigger_call_info 246 self.trigger_call_info
242 } 247 }
248
249 pub fn ref_match(&self) -> Option<(Mutability, CompletionScore)> {
250 self.ref_match
251 }
243} 252}
244 253
245/// A helper to make `CompletionItem`s. 254/// A helper to make `CompletionItem`s.
246#[must_use] 255#[must_use]
256#[derive(Clone)]
247pub(crate) struct Builder { 257pub(crate) struct Builder {
248 source_range: TextRange, 258 source_range: TextRange,
249 completion_kind: CompletionKind, 259 completion_kind: CompletionKind,
@@ -258,6 +268,7 @@ pub(crate) struct Builder {
258 deprecated: Option<bool>, 268 deprecated: Option<bool>,
259 trigger_call_info: Option<bool>, 269 trigger_call_info: Option<bool>,
260 score: Option<CompletionScore>, 270 score: Option<CompletionScore>,
271 ref_match: Option<(Mutability, CompletionScore)>,
261} 272}
262 273
263impl Builder { 274impl Builder {
@@ -288,6 +299,7 @@ impl Builder {
288 deprecated: self.deprecated.unwrap_or(false), 299 deprecated: self.deprecated.unwrap_or(false),
289 trigger_call_info: self.trigger_call_info.unwrap_or(false), 300 trigger_call_info: self.trigger_call_info.unwrap_or(false),
290 score: self.score, 301 score: self.score,
302 ref_match: self.ref_match,
291 } 303 }
292 } 304 }
293 pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder { 305 pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder {
@@ -350,6 +362,13 @@ impl Builder {
350 self.trigger_call_info = Some(true); 362 self.trigger_call_info = Some(true);
351 self 363 self
352 } 364 }
365 pub(crate) fn set_ref_match(
366 mut self,
367 ref_match: Option<(Mutability, CompletionScore)>,
368 ) -> Builder {
369 self.ref_match = ref_match;
370 self
371 }
353} 372}
354 373
355impl<'a> Into<CompletionItem> for Builder { 374impl<'a> Into<CompletionItem> 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 @@
1//! This modules takes care of rendering various definitions as completion items. 1//! This modules takes care of rendering various definitions as completion items.
2//! It also handles scoring (sorting) completions. 2//! It also handles scoring (sorting) completions.
3 3
4use hir::{HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type}; 4use hir::{HasAttrs, HasSource, HirDisplay, ModPath, Mutability, ScopeDef, StructKind, Type};
5use itertools::Itertools; 5use itertools::Itertools;
6use syntax::{ast::NameOwner, display::*}; 6use syntax::{ast::NameOwner, display::*};
7use test_utils::mark; 7use test_utils::mark;
@@ -107,9 +107,16 @@ impl Completions {
107 } 107 }
108 }; 108 };
109 109
110 let mut ref_match = None;
110 if let ScopeDef::Local(local) = resolution { 111 if let ScopeDef::Local(local) = resolution {
111 if let Some(score) = compute_score(ctx, &local.ty(ctx.db), &local_name) { 112 if let Some((active_name, active_type)) = ctx.active_name_and_type() {
112 completion_item = completion_item.set_score(score); 113 let ty = local.ty(ctx.db);
114 if let Some(score) =
115 compute_score_from_active(&active_type, &active_name, &ty, &local_name)
116 {
117 completion_item = completion_item.set_score(score);
118 }
119 ref_match = refed_type_matches(&active_type, &active_name, &ty, &local_name);
113 } 120 }
114 } 121 }
115 122
@@ -131,7 +138,7 @@ impl Completions {
131 } 138 }
132 } 139 }
133 140
134 completion_item.kind(kind).set_documentation(docs).add_to(self) 141 completion_item.kind(kind).set_documentation(docs).set_ref_match(ref_match).add_to(self)
135 } 142 }
136 143
137 pub(crate) fn add_macro( 144 pub(crate) fn add_macro(
@@ -342,25 +349,15 @@ impl Completions {
342 } 349 }
343} 350}
344 351
345pub(crate) fn compute_score( 352fn compute_score_from_active(
346 ctx: &CompletionContext, 353 active_type: &Type,
354 active_name: &str,
347 ty: &Type, 355 ty: &Type,
348 name: &str, 356 name: &str,
349) -> Option<CompletionScore> { 357) -> Option<CompletionScore> {
350 let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax {
351 mark::hit!(record_field_type_match);
352 let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?;
353 (struct_field.name(ctx.db).to_string(), struct_field.signature_ty(ctx.db))
354 } else if let Some(active_parameter) = &ctx.active_parameter {
355 mark::hit!(active_param_type_match);
356 (active_parameter.name.clone(), active_parameter.ty.clone())
357 } else {
358 return None;
359 };
360
361 // Compute score 358 // Compute score
362 // For the same type 359 // For the same type
363 if &active_type != ty { 360 if active_type != ty {
364 return None; 361 return None;
365 } 362 }
366 363
@@ -373,6 +370,24 @@ pub(crate) fn compute_score(
373 370
374 Some(res) 371 Some(res)
375} 372}
373fn refed_type_matches(
374 active_type: &Type,
375 active_name: &str,
376 ty: &Type,
377 name: &str,
378) -> Option<(Mutability, CompletionScore)> {
379 let derefed_active = active_type.remove_ref()?;
380 let score = compute_score_from_active(&derefed_active, &active_name, &ty, &name)?;
381 Some((
382 if active_type.is_mutable_reference() { Mutability::Mut } else { Mutability::Shared },
383 score,
384 ))
385}
386
387fn compute_score(ctx: &CompletionContext, ty: &Type, name: &str) -> Option<CompletionScore> {
388 let (active_name, active_type) = ctx.active_name_and_type()?;
389 compute_score_from_active(&active_type, &active_name, ty, name)
390}
376 391
377enum Params { 392enum Params {
378 Named(Vec<String>), 393 Named(Vec<String>),