mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 21:05:02 +00:00
feat: Deprioritize ops methods in completion
This commit is contained in:
parent
41a0e95d61
commit
ca0633c808
6 changed files with 106 additions and 30 deletions
|
@ -1610,6 +1610,12 @@ pub struct Trait {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Trait {
|
impl Trait {
|
||||||
|
pub fn lang(db: &dyn HirDatabase, krate: Crate, name: &Name) -> Option<Trait> {
|
||||||
|
db.lang_item(krate.into(), name.to_smol_str())
|
||||||
|
.and_then(LangItemTarget::as_trait)
|
||||||
|
.map(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn module(self, db: &dyn HirDatabase) -> Module {
|
pub fn module(self, db: &dyn HirDatabase) -> Module {
|
||||||
Module { id: self.id.lookup(db.upcast()).container }
|
Module { id: self.id.lookup(db.upcast()).container }
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,8 +144,8 @@ impl LangItems {
|
||||||
let _p = profile::span("lang_item_query");
|
let _p = profile::span("lang_item_query");
|
||||||
let lang_items = db.crate_lang_items(start_crate);
|
let lang_items = db.crate_lang_items(start_crate);
|
||||||
let start_crate_target = lang_items.items.get(&item);
|
let start_crate_target = lang_items.items.get(&item);
|
||||||
if let Some(target) = start_crate_target {
|
if let Some(&target) = start_crate_target {
|
||||||
return Some(*target);
|
return Some(target);
|
||||||
}
|
}
|
||||||
db.crate_graph()[start_crate]
|
db.crate_graph()[start_crate]
|
||||||
.dependencies
|
.dependencies
|
||||||
|
|
|
@ -309,26 +309,6 @@ pub mod known {
|
||||||
wrapping_mul,
|
wrapping_mul,
|
||||||
wrapping_sub,
|
wrapping_sub,
|
||||||
// known methods of lang items
|
// known methods of lang items
|
||||||
add,
|
|
||||||
mul,
|
|
||||||
sub,
|
|
||||||
div,
|
|
||||||
rem,
|
|
||||||
shl,
|
|
||||||
shr,
|
|
||||||
bitxor,
|
|
||||||
bitor,
|
|
||||||
bitand,
|
|
||||||
add_assign,
|
|
||||||
mul_assign,
|
|
||||||
sub_assign,
|
|
||||||
div_assign,
|
|
||||||
rem_assign,
|
|
||||||
shl_assign,
|
|
||||||
shr_assign,
|
|
||||||
bitxor_assign,
|
|
||||||
bitor_assign,
|
|
||||||
bitand_assign,
|
|
||||||
eq,
|
eq,
|
||||||
ne,
|
ne,
|
||||||
ge,
|
ge,
|
||||||
|
@ -336,12 +316,38 @@ pub mod known {
|
||||||
le,
|
le,
|
||||||
lt,
|
lt,
|
||||||
// lang items
|
// lang items
|
||||||
not,
|
add_assign,
|
||||||
neg,
|
add,
|
||||||
|
bitand_assign,
|
||||||
|
bitand,
|
||||||
|
bitor_assign,
|
||||||
|
bitor,
|
||||||
|
bitxor_assign,
|
||||||
|
bitxor,
|
||||||
|
deref_mut,
|
||||||
|
deref,
|
||||||
|
div_assign,
|
||||||
|
div,
|
||||||
|
fn_mut,
|
||||||
|
fn_once,
|
||||||
future_trait,
|
future_trait,
|
||||||
owned_box,
|
|
||||||
index,
|
index,
|
||||||
partial_ord
|
index_mut,
|
||||||
|
mul_assign,
|
||||||
|
mul,
|
||||||
|
neg,
|
||||||
|
not,
|
||||||
|
owned_box,
|
||||||
|
partial_ord,
|
||||||
|
r#fn,
|
||||||
|
rem_assign,
|
||||||
|
rem,
|
||||||
|
shl_assign,
|
||||||
|
shl,
|
||||||
|
shr_assign,
|
||||||
|
shr,
|
||||||
|
sub_assign,
|
||||||
|
sub,
|
||||||
);
|
);
|
||||||
|
|
||||||
// self/Self cannot be used as an identifier
|
// self/Self cannot be used as an identifier
|
||||||
|
|
|
@ -3,13 +3,14 @@
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use base_db::SourceDatabaseExt;
|
use base_db::SourceDatabaseExt;
|
||||||
use hir::{Local, Name, ScopeDef, Semantics, SemanticsScope, Type, TypeInfo};
|
use hir::{known, Local, Name, ScopeDef, Semantics, SemanticsScope, Type, TypeInfo};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
active_parameter::ActiveParameter,
|
active_parameter::ActiveParameter,
|
||||||
base_db::{FilePosition, SourceDatabase},
|
base_db::{FilePosition, SourceDatabase},
|
||||||
helpers::FamousDefs,
|
helpers::FamousDefs,
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
};
|
};
|
||||||
|
use rustc_hash::FxHashSet;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
algo::find_node_at_offset,
|
algo::find_node_at_offset,
|
||||||
ast::{self, HasName, NameOrNameRef},
|
ast::{self, HasName, NameOrNameRef},
|
||||||
|
@ -85,6 +86,7 @@ pub(crate) enum ParamKind {
|
||||||
Function,
|
Function,
|
||||||
Closure,
|
Closure,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `CompletionContext` is created early during completion to figure out, where
|
/// `CompletionContext` is created early during completion to figure out, where
|
||||||
/// exactly is the cursor, syntax-wise.
|
/// exactly is the cursor, syntax-wise.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -120,7 +122,10 @@ pub(crate) struct CompletionContext<'a> {
|
||||||
pub(super) lifetime_ctx: Option<LifetimeContext>,
|
pub(super) lifetime_ctx: Option<LifetimeContext>,
|
||||||
pub(super) pattern_ctx: Option<PatternContext>,
|
pub(super) pattern_ctx: Option<PatternContext>,
|
||||||
pub(super) path_context: Option<PathCompletionContext>,
|
pub(super) path_context: Option<PathCompletionContext>,
|
||||||
|
|
||||||
pub(super) locals: Vec<(Name, Local)>,
|
pub(super) locals: Vec<(Name, Local)>,
|
||||||
|
/// Operator traits defined in the project
|
||||||
|
pub(super) ops_traits: FxHashSet<hir::Trait>,
|
||||||
|
|
||||||
no_completion_required: bool,
|
no_completion_required: bool,
|
||||||
}
|
}
|
||||||
|
@ -308,6 +313,11 @@ impl<'a> CompletionContext<'a> {
|
||||||
self.token.kind() == BANG && self.token.parent().map_or(false, |it| it.kind() == MACRO_CALL)
|
self.token.kind() == BANG && self.token.parent().map_or(false, |it| it.kind() == MACRO_CALL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether the given trait is an operator trait or not.
|
||||||
|
pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool {
|
||||||
|
self.ops_traits.contains(&trait_)
|
||||||
|
}
|
||||||
|
|
||||||
/// A version of [`SemanticsScope::process_all_names`] that filters out `#[doc(hidden)]` items.
|
/// A version of [`SemanticsScope::process_all_names`] that filters out `#[doc(hidden)]` items.
|
||||||
pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
|
pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
|
||||||
let _p = profile::span("CompletionContext::process_all_names");
|
let _p = profile::span("CompletionContext::process_all_names");
|
||||||
|
@ -388,6 +398,17 @@ impl<'a> CompletionContext<'a> {
|
||||||
locals.push((name, local));
|
locals.push((name, local));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
let mut ops_traits =
|
||||||
|
FxHashSet::with_capacity_and_hasher(OP_TRAIT_LANG_NAMES.len(), Default::default());
|
||||||
|
if let Some(krate) = krate {
|
||||||
|
let _p = profile::span("CompletionContext::new ops");
|
||||||
|
for trait_ in
|
||||||
|
OP_TRAIT_LANG_NAMES.iter().filter_map(|item| hir::Trait::lang(db, krate, item))
|
||||||
|
{
|
||||||
|
ops_traits.insert(trait_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut ctx = CompletionContext {
|
let mut ctx = CompletionContext {
|
||||||
sema,
|
sema,
|
||||||
scope,
|
scope,
|
||||||
|
@ -413,6 +434,7 @@ impl<'a> CompletionContext<'a> {
|
||||||
locals,
|
locals,
|
||||||
incomplete_let: false,
|
incomplete_let: false,
|
||||||
no_completion_required: false,
|
no_completion_required: false,
|
||||||
|
ops_traits,
|
||||||
};
|
};
|
||||||
ctx.expand_and_fill(
|
ctx.expand_and_fill(
|
||||||
original_file.syntax().clone(),
|
original_file.syntax().clone(),
|
||||||
|
@ -889,6 +911,7 @@ fn pattern_context_for(pat: ast::Pat) -> PatternContext {
|
||||||
});
|
});
|
||||||
PatternContext { refutability, is_param, has_type_ascription }
|
PatternContext { refutability, is_param, has_type_ascription }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> {
|
fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> {
|
||||||
syntax.covering_element(range).ancestors().find_map(N::cast)
|
syntax.covering_element(range).ancestors().find_map(N::cast)
|
||||||
}
|
}
|
||||||
|
@ -915,6 +938,37 @@ fn has_ref(token: &SyntaxToken) -> bool {
|
||||||
token.kind() == T![&]
|
token.kind() == T![&]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const OP_TRAIT_LANG_NAMES: &[hir::Name] = &[
|
||||||
|
known::add_assign,
|
||||||
|
known::add,
|
||||||
|
known::bitand_assign,
|
||||||
|
known::bitand,
|
||||||
|
known::bitor_assign,
|
||||||
|
known::bitor,
|
||||||
|
known::bitxor_assign,
|
||||||
|
known::bitxor,
|
||||||
|
known::deref_mut,
|
||||||
|
known::deref,
|
||||||
|
known::div_assign,
|
||||||
|
known::div,
|
||||||
|
known::fn_mut,
|
||||||
|
known::fn_once,
|
||||||
|
known::r#fn,
|
||||||
|
known::index_mut,
|
||||||
|
known::index,
|
||||||
|
known::mul_assign,
|
||||||
|
known::mul,
|
||||||
|
known::neg,
|
||||||
|
known::not,
|
||||||
|
known::rem_assign,
|
||||||
|
known::rem,
|
||||||
|
known::shl_assign,
|
||||||
|
known::shl,
|
||||||
|
known::shr_assign,
|
||||||
|
known::shr,
|
||||||
|
known::sub,
|
||||||
|
known::sub,
|
||||||
|
];
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use expect_test::{expect, Expect};
|
use expect_test::{expect, Expect};
|
||||||
|
|
|
@ -139,6 +139,8 @@ pub struct CompletionRelevance {
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub is_local: bool,
|
pub is_local: bool,
|
||||||
|
/// Set for method completions of the `core::ops` family.
|
||||||
|
pub is_op_method: bool,
|
||||||
/// This is set in cases like these:
|
/// This is set in cases like these:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -198,6 +200,9 @@ impl CompletionRelevance {
|
||||||
if self.is_local {
|
if self.is_local {
|
||||||
score += 1;
|
score += 1;
|
||||||
}
|
}
|
||||||
|
if self.is_op_method {
|
||||||
|
score -= 1;
|
||||||
|
}
|
||||||
if self.exact_postfix_snippet_match {
|
if self.exact_postfix_snippet_match {
|
||||||
score += 100;
|
score += 100;
|
||||||
}
|
}
|
||||||
|
@ -588,10 +593,8 @@ mod tests {
|
||||||
..CompletionRelevance::default()
|
..CompletionRelevance::default()
|
||||||
}],
|
}],
|
||||||
vec![CompletionRelevance {
|
vec![CompletionRelevance {
|
||||||
exact_name_match: false,
|
|
||||||
type_match: None,
|
|
||||||
is_local: false,
|
|
||||||
exact_postfix_snippet_match: true,
|
exact_postfix_snippet_match: true,
|
||||||
|
..CompletionRelevance::default()
|
||||||
}],
|
}],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,13 @@ fn render(
|
||||||
item.set_relevance(CompletionRelevance {
|
item.set_relevance(CompletionRelevance {
|
||||||
type_match: compute_type_match(completion, &ret_type),
|
type_match: compute_type_match(completion, &ret_type),
|
||||||
exact_name_match: compute_exact_name_match(completion, &call),
|
exact_name_match: compute_exact_name_match(completion, &call),
|
||||||
|
is_op_method: match func_type {
|
||||||
|
FuncType::Method(_) => func
|
||||||
|
.as_assoc_item(ctx.db())
|
||||||
|
.and_then(|trait_| trait_.containing_trait_or_trait_impl(ctx.db()))
|
||||||
|
.map_or(false, |trait_| completion.is_ops_trait(trait_)),
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
..CompletionRelevance::default()
|
..CompletionRelevance::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue