mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 22:31:43 +00:00
Remove redundant completions
This commit is contained in:
parent
59483c2176
commit
70157f07d9
3 changed files with 70 additions and 4 deletions
|
@ -112,6 +112,11 @@ pub(crate) fn completions(
|
||||||
) -> Option<Completions> {
|
) -> Option<Completions> {
|
||||||
let ctx = CompletionContext::new(db, position, config)?;
|
let ctx = CompletionContext::new(db, position, config)?;
|
||||||
|
|
||||||
|
if ctx.no_completion_required() {
|
||||||
|
// No work required here.
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let mut acc = Completions::default();
|
let mut acc = Completions::default();
|
||||||
complete_attribute::complete_attribute(&mut acc, &ctx);
|
complete_attribute::complete_attribute(&mut acc, &ctx);
|
||||||
complete_fn_param::complete_fn_param(&mut acc, &ctx);
|
complete_fn_param::complete_fn_param(&mut acc, &ctx);
|
||||||
|
@ -157,6 +162,23 @@ mod tests {
|
||||||
panic!("completion detail not found: {}", expected.detail)
|
panic!("completion detail not found: {}", expected.detail)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_no_completion(ra_fixture: &str) {
|
||||||
|
let (analysis, position) = fixture::position(ra_fixture);
|
||||||
|
let config = CompletionConfig::default();
|
||||||
|
analysis.completions(&config, position).unwrap();
|
||||||
|
|
||||||
|
let completions: Option<Vec<String>> = analysis
|
||||||
|
.completions(&config, position)
|
||||||
|
.unwrap()
|
||||||
|
.and_then(|completions| if completions.is_empty() { None } else { Some(completions) })
|
||||||
|
.map(|completions| {
|
||||||
|
completions.into_iter().map(|completion| format!("{:?}", completion)).collect()
|
||||||
|
});
|
||||||
|
|
||||||
|
// `assert_eq` instead of `assert!(completions.is_none())` to get the list of completions if test will panic.
|
||||||
|
assert_eq!(completions, None, "Completions were generated, but weren't expected");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_completion_detail_from_macro_generated_struct_fn_doc_attr() {
|
fn test_completion_detail_from_macro_generated_struct_fn_doc_attr() {
|
||||||
check_detail_and_documentation(
|
check_detail_and_documentation(
|
||||||
|
@ -208,4 +230,15 @@ mod tests {
|
||||||
DetailAndDocumentation { detail: "fn foo(&self)", documentation: " Do the foo" },
|
DetailAndDocumentation { detail: "fn foo(&self)", documentation: " Do the foo" },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_no_completions_required() {
|
||||||
|
check_no_completion(
|
||||||
|
r#"
|
||||||
|
fn foo() {
|
||||||
|
for i i<|>
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,10 @@ use crate::{
|
||||||
call_info::ActiveParameter,
|
call_info::ActiveParameter,
|
||||||
completion::{
|
completion::{
|
||||||
patterns::{
|
patterns::{
|
||||||
has_bind_pat_parent, has_block_expr_parent, has_field_list_parent,
|
fn_is_prev, for_is_prev2, has_bind_pat_parent, has_block_expr_parent,
|
||||||
has_impl_as_prev_sibling, has_impl_parent, has_item_list_or_source_file_parent,
|
has_field_list_parent, has_impl_as_prev_sibling, has_impl_parent,
|
||||||
has_ref_parent, has_trait_as_prev_sibling, has_trait_parent, if_is_prev,
|
has_item_list_or_source_file_parent, has_ref_parent, has_trait_as_prev_sibling,
|
||||||
is_in_loop_body, is_match_arm, unsafe_is_prev,
|
has_trait_parent, if_is_prev, is_in_loop_body, is_match_arm, unsafe_is_prev,
|
||||||
},
|
},
|
||||||
CompletionConfig,
|
CompletionConfig,
|
||||||
},
|
},
|
||||||
|
@ -91,6 +91,8 @@ pub(crate) struct CompletionContext<'a> {
|
||||||
pub(super) impl_as_prev_sibling: bool,
|
pub(super) impl_as_prev_sibling: bool,
|
||||||
pub(super) is_match_arm: bool,
|
pub(super) is_match_arm: bool,
|
||||||
pub(super) has_item_list_or_source_file_parent: bool,
|
pub(super) has_item_list_or_source_file_parent: bool,
|
||||||
|
pub(super) for_is_prev2: bool,
|
||||||
|
pub(super) fn_is_prev: bool,
|
||||||
pub(super) locals: Vec<(String, Local)>,
|
pub(super) locals: Vec<(String, Local)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,6 +176,8 @@ impl<'a> CompletionContext<'a> {
|
||||||
if_is_prev: false,
|
if_is_prev: false,
|
||||||
is_match_arm: false,
|
is_match_arm: false,
|
||||||
has_item_list_or_source_file_parent: false,
|
has_item_list_or_source_file_parent: false,
|
||||||
|
for_is_prev2: false,
|
||||||
|
fn_is_prev: false,
|
||||||
locals,
|
locals,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -221,6 +225,14 @@ impl<'a> CompletionContext<'a> {
|
||||||
Some(ctx)
|
Some(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks whether completions in that particular case don't make much sense.
|
||||||
|
/// Examples:
|
||||||
|
/// - `fn <|>` -- we expect function name, it's unlikely that "hint" will be helpful.
|
||||||
|
/// - `for _ i<|>` -- obviously, it'll be "in" keyword.
|
||||||
|
pub(crate) fn no_completion_required(&self) -> bool {
|
||||||
|
self.fn_is_prev || self.for_is_prev2
|
||||||
|
}
|
||||||
|
|
||||||
/// The range of the identifier that is being completed.
|
/// The range of the identifier that is being completed.
|
||||||
pub(crate) fn source_range(&self) -> TextRange {
|
pub(crate) fn source_range(&self) -> TextRange {
|
||||||
// check kind of macro-expanded token, but use range of original token
|
// check kind of macro-expanded token, but use range of original token
|
||||||
|
@ -253,6 +265,8 @@ impl<'a> CompletionContext<'a> {
|
||||||
self.mod_declaration_under_caret =
|
self.mod_declaration_under_caret =
|
||||||
find_node_at_offset::<ast::Module>(&file_with_fake_ident, offset)
|
find_node_at_offset::<ast::Module>(&file_with_fake_ident, offset)
|
||||||
.filter(|module| module.item_list().is_none());
|
.filter(|module| module.item_list().is_none());
|
||||||
|
self.for_is_prev2 = for_is_prev2(syntax_element.clone());
|
||||||
|
self.fn_is_prev = fn_is_prev(syntax_element.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fill(
|
fn fill(
|
||||||
|
|
|
@ -116,6 +116,25 @@ pub(crate) fn if_is_prev(element: SyntaxElement) -> bool {
|
||||||
.is_some()
|
.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn fn_is_prev(element: SyntaxElement) -> bool {
|
||||||
|
element
|
||||||
|
.into_token()
|
||||||
|
.and_then(|it| previous_non_trivia_token(it))
|
||||||
|
.filter(|it| it.kind() == FN_KW)
|
||||||
|
.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the token previous to the previous one is `for`.
|
||||||
|
/// For example, `for _ i<|>` => true.
|
||||||
|
pub(crate) fn for_is_prev2(element: SyntaxElement) -> bool {
|
||||||
|
element
|
||||||
|
.into_token()
|
||||||
|
.and_then(|it| previous_non_trivia_token(it))
|
||||||
|
.and_then(|it| previous_non_trivia_token(it))
|
||||||
|
.filter(|it| it.kind() == FOR_KW)
|
||||||
|
.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_if_is_prev() {
|
fn test_if_is_prev() {
|
||||||
check_pattern_is_applicable(r"if l<|>", if_is_prev);
|
check_pattern_is_applicable(r"if l<|>", if_is_prev);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue