From 4f2134cc33f07c09fe166cec42971828843bc0ef Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 2 May 2020 01:18:19 +0200 Subject: Introduce EffectExpr --- crates/ra_ide/src/completion/completion_context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/ra_ide/src/completion') diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index 118fceb2e..c529752d4 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs @@ -344,7 +344,7 @@ impl<'a> CompletionContext<'a> { stmt.syntax().text_range() == name_ref.syntax().text_range(), ); } - if let Some(block) = ast::Block::cast(node) { + if let Some(block) = ast::BlockExpr::cast(node) { return Some( block.expr().map(|e| e.syntax().text_range()) == Some(name_ref.syntax().text_range()), -- cgit v1.2.3 From 767bff89ededdff875b042bb37397b972e3a82f1 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Fri, 1 May 2020 03:46:17 +0300 Subject: Complete standard derives --- crates/ra_ide/src/completion/complete_attribute.rs | 255 +++++++++++++++++++-- crates/ra_ide/src/completion/completion_context.rs | 6 +- 2 files changed, 245 insertions(+), 16 deletions(-) (limited to 'crates/ra_ide/src/completion') diff --git a/crates/ra_ide/src/completion/complete_attribute.rs b/crates/ra_ide/src/completion/complete_attribute.rs index 8bf952798..8934b45fe 100644 --- a/crates/ra_ide/src/completion/complete_attribute.rs +++ b/crates/ra_ide/src/completion/complete_attribute.rs @@ -5,23 +5,26 @@ use super::completion_context::CompletionContext; use super::completion_item::{CompletionItem, CompletionItemKind, CompletionKind, Completions}; +use ast::AttrInput; use ra_syntax::{ - ast::{Attr, AttrKind}, - AstNode, + ast::{self, AttrKind}, + AstNode, SyntaxKind, }; +use rustc_hash::FxHashSet; -pub(super) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) { - if !ctx.is_attribute { - return; - } +pub(super) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { + let attribute = ctx.attribute_under_caret.as_ref()?; - let is_inner = ctx - .original_token - .ancestors() - .find_map(Attr::cast) - .map(|attr| attr.kind() == AttrKind::Inner) - .unwrap_or(false); + match (attribute.path(), attribute.input()) { + (Some(path), Some(AttrInput::TokenTree(token_tree))) if path.to_string() == "derive" => { + complete_derive(acc, ctx, token_tree) + } + _ => complete_attribute_start(acc, ctx, attribute), + } + Some(()) +} +fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attribute: &ast::Attr) { for attr_completion in ATTRIBUTES { let mut item = CompletionItem::new( CompletionKind::Attribute, @@ -37,7 +40,7 @@ pub(super) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) _ => {} } - if is_inner || !attr_completion.should_be_inner { + if attribute.kind() == AttrKind::Inner || !attr_completion.should_be_inner { acc.add(item); } } @@ -126,6 +129,68 @@ const ATTRIBUTES: &[AttrCompletion] = &[ }, ]; +fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input: ast::TokenTree) { + // TODO kb autodetect derive macros + // https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0/topic/Find.20all.20possible.20derive.20macro.20values.3F/near/195955580 + + if let Ok(existing_derives) = parse_derive_input(derive_input) { + for derive_completion in DERIVE_COMPLETIONS + .into_iter() + .filter(|completion| !existing_derives.contains(completion.label)) + { + let mut label = derive_completion.label.to_owned(); + for dependency in derive_completion + .dependencies + .into_iter() + .filter(|&&dependency| !existing_derives.contains(dependency)) + { + label.push_str(", "); + label.push_str(dependency); + } + let item = CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label) + .kind(CompletionItemKind::Attribute); + acc.add(item); + } + } +} + +fn parse_derive_input(derive_input: ast::TokenTree) -> Result, ()> { + match (derive_input.left_delimiter_token(), derive_input.right_delimiter_token()) { + (Some(left_paren), Some(right_paren)) + if left_paren.kind() == SyntaxKind::L_PAREN + && right_paren.kind() == SyntaxKind::R_PAREN => + { + Ok(derive_input + .syntax() + .children_with_tokens() + .filter_map(|child| child.into_token()) + .skip_while(|child| child != &left_paren) + .take_while(|child| child != &right_paren) + .filter(|child| child.kind() == SyntaxKind::IDENT) + .map(|child| child.to_string()) + .collect()) + } + _ => Err(()), + } +} + +struct DeriveCompletion { + label: &'static str, + dependencies: &'static [&'static str], +} + +const DERIVE_COMPLETIONS: &[DeriveCompletion] = &[ + DeriveCompletion { label: "Clone", dependencies: &[] }, + DeriveCompletion { label: "Copy", dependencies: &["Clone"] }, + DeriveCompletion { label: "Debug", dependencies: &[] }, + DeriveCompletion { label: "Default", dependencies: &[] }, + DeriveCompletion { label: "Hash", dependencies: &[] }, + DeriveCompletion { label: "PartialEq", dependencies: &[] }, + DeriveCompletion { label: "Eq", dependencies: &["PartialEq"] }, + DeriveCompletion { label: "PartialOrd", dependencies: &["PartialEq"] }, + DeriveCompletion { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] }, +]; + #[cfg(test)] mod tests { use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; @@ -135,6 +200,170 @@ mod tests { do_completion(code, CompletionKind::Attribute) } + #[test] + fn empty_derive_completion() { + assert_debug_snapshot!( + do_attr_completion( + r" + #[derive(<|>)] + struct Test {} + ", + ), + @r###" + [ + CompletionItem { + label: "Clone", + source_range: 30..30, + delete: 30..30, + insert: "Clone", + kind: Attribute, + }, + CompletionItem { + label: "Copy, Clone", + source_range: 30..30, + delete: 30..30, + insert: "Copy, Clone", + kind: Attribute, + }, + CompletionItem { + label: "Debug", + source_range: 30..30, + delete: 30..30, + insert: "Debug", + kind: Attribute, + }, + CompletionItem { + label: "Default", + source_range: 30..30, + delete: 30..30, + insert: "Default", + kind: Attribute, + }, + CompletionItem { + label: "Eq, PartialEq", + source_range: 30..30, + delete: 30..30, + insert: "Eq, PartialEq", + kind: Attribute, + }, + CompletionItem { + label: "Hash", + source_range: 30..30, + delete: 30..30, + insert: "Hash", + kind: Attribute, + }, + CompletionItem { + label: "Ord, PartialOrd, Eq, PartialEq", + source_range: 30..30, + delete: 30..30, + insert: "Ord, PartialOrd, Eq, PartialEq", + kind: Attribute, + }, + CompletionItem { + label: "PartialEq", + source_range: 30..30, + delete: 30..30, + insert: "PartialEq", + kind: Attribute, + }, + CompletionItem { + label: "PartialOrd, PartialEq", + source_range: 30..30, + delete: 30..30, + insert: "PartialOrd, PartialEq", + kind: Attribute, + }, + ] + "### + ); + } + + #[test] + fn no_completion_for_incorrect_derive() { + assert_debug_snapshot!( + do_attr_completion( + r" + #[derive{<|>)] + struct Test {} + ", + ), + @"[]" + ); + } + + #[test] + fn derive_with_input_completion() { + assert_debug_snapshot!( + do_attr_completion( + r" + #[derive(Whatever, PartialEq, <|>)] + struct Test {} + ", + ), + @r###" + [ + CompletionItem { + label: "Clone", + source_range: 51..51, + delete: 51..51, + insert: "Clone", + kind: Attribute, + }, + CompletionItem { + label: "Copy, Clone", + source_range: 51..51, + delete: 51..51, + insert: "Copy, Clone", + kind: Attribute, + }, + CompletionItem { + label: "Debug", + source_range: 51..51, + delete: 51..51, + insert: "Debug", + kind: Attribute, + }, + CompletionItem { + label: "Default", + source_range: 51..51, + delete: 51..51, + insert: "Default", + kind: Attribute, + }, + CompletionItem { + label: "Eq", + source_range: 51..51, + delete: 51..51, + insert: "Eq", + kind: Attribute, + }, + CompletionItem { + label: "Hash", + source_range: 51..51, + delete: 51..51, + insert: "Hash", + kind: Attribute, + }, + CompletionItem { + label: "Ord, PartialOrd, Eq", + source_range: 51..51, + delete: 51..51, + insert: "Ord, PartialOrd, Eq", + kind: Attribute, + }, + CompletionItem { + label: "PartialOrd", + source_range: 51..51, + delete: 51..51, + insert: "PartialOrd", + kind: Attribute, + }, + ] + "### + ); + } + #[test] fn test_attribute_completion() { assert_debug_snapshot!( diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index c529752d4..dd87bd119 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs @@ -58,7 +58,7 @@ pub(crate) struct CompletionContext<'a> { pub(super) is_macro_call: bool, pub(super) is_path_type: bool, pub(super) has_type_args: bool, - pub(super) is_attribute: bool, + pub(super) attribute_under_caret: Option, } impl<'a> CompletionContext<'a> { @@ -116,7 +116,7 @@ impl<'a> CompletionContext<'a> { is_path_type: false, has_type_args: false, dot_receiver_is_ambiguous_float_literal: false, - is_attribute: false, + attribute_under_caret: None, }; let mut original_file = original_file.syntax().clone(); @@ -200,6 +200,7 @@ impl<'a> CompletionContext<'a> { Some(ty) }) .flatten(); + self.attribute_under_caret = find_node_at_offset(&file_with_fake_ident, offset); // First, let's try to complete a reference to some declaration. if let Some(name_ref) = find_node_at_offset::(&file_with_fake_ident, offset) { @@ -318,7 +319,6 @@ impl<'a> CompletionContext<'a> { .and_then(|it| it.syntax().parent().and_then(ast::CallExpr::cast)) .is_some(); self.is_macro_call = path.syntax().parent().and_then(ast::MacroCall::cast).is_some(); - self.is_attribute = path.syntax().parent().and_then(ast::Attr::cast).is_some(); self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); self.has_type_args = segment.type_arg_list().is_some(); -- cgit v1.2.3 From fee74851b02fb69c32291f3051438901faaf667f Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sat, 2 May 2020 22:24:27 +0300 Subject: Propose custom derives in completion --- crates/ra_ide/src/completion/complete_attribute.rs | 40 +++++++++++++++++----- 1 file changed, 32 insertions(+), 8 deletions(-) (limited to 'crates/ra_ide/src/completion') diff --git a/crates/ra_ide/src/completion/complete_attribute.rs b/crates/ra_ide/src/completion/complete_attribute.rs index 8934b45fe..346ba9e7a 100644 --- a/crates/ra_ide/src/completion/complete_attribute.rs +++ b/crates/ra_ide/src/completion/complete_attribute.rs @@ -130,11 +130,8 @@ const ATTRIBUTES: &[AttrCompletion] = &[ ]; fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input: ast::TokenTree) { - // TODO kb autodetect derive macros - // https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0/topic/Find.20all.20possible.20derive.20macro.20values.3F/near/195955580 - if let Ok(existing_derives) = parse_derive_input(derive_input) { - for derive_completion in DERIVE_COMPLETIONS + for derive_completion in DEFAULT_DERIVE_COMPLETIONS .into_iter() .filter(|completion| !existing_derives.contains(completion.label)) { @@ -147,9 +144,21 @@ fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input: label.push_str(", "); label.push_str(dependency); } - let item = CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label) - .kind(CompletionItemKind::Attribute); - acc.add(item); + acc.add( + CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label) + .kind(CompletionItemKind::Attribute), + ); + } + + for custom_derive_name in get_derive_names_in_scope(ctx).difference(&existing_derives) { + acc.add( + CompletionItem::new( + CompletionKind::Attribute, + ctx.source_range(), + custom_derive_name, + ) + .kind(CompletionItemKind::Attribute), + ); } } } @@ -174,12 +183,27 @@ fn parse_derive_input(derive_input: ast::TokenTree) -> Result, } } +fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet { + let mut result = FxHashSet::default(); + ctx.scope().process_all_names(&mut |name, scope_def| { + if let hir::ScopeDef::MacroDef(mac) = scope_def { + if mac.is_derive_macro() { + let name_string = name.to_string(); + result.insert(name_string); + } + } + }); + result +} + struct DeriveCompletion { label: &'static str, dependencies: &'static [&'static str], } -const DERIVE_COMPLETIONS: &[DeriveCompletion] = &[ +/// Standard Rust derives and the information about their dependencies +/// (the dependencies are needed so that the main derive don't break the compilation when added) +const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[ DeriveCompletion { label: "Clone", dependencies: &[] }, DeriveCompletion { label: "Copy", dependencies: &["Clone"] }, DeriveCompletion { label: "Debug", dependencies: &[] }, -- cgit v1.2.3 From 2fd054f276e6fd75237b476622d03eef2f18430a Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sat, 2 May 2020 23:45:44 +0300 Subject: Fix derive argument parsing --- crates/ra_ide/src/completion/complete_attribute.rs | 66 +++++++++++++--------- 1 file changed, 40 insertions(+), 26 deletions(-) (limited to 'crates/ra_ide/src/completion') diff --git a/crates/ra_ide/src/completion/complete_attribute.rs b/crates/ra_ide/src/completion/complete_attribute.rs index 346ba9e7a..20e6edc17 100644 --- a/crates/ra_ide/src/completion/complete_attribute.rs +++ b/crates/ra_ide/src/completion/complete_attribute.rs @@ -169,15 +169,30 @@ fn parse_derive_input(derive_input: ast::TokenTree) -> Result, if left_paren.kind() == SyntaxKind::L_PAREN && right_paren.kind() == SyntaxKind::R_PAREN => { - Ok(derive_input + let mut input_derives = FxHashSet::default(); + let mut current_derive = String::new(); + for token in derive_input .syntax() .children_with_tokens() - .filter_map(|child| child.into_token()) - .skip_while(|child| child != &left_paren) - .take_while(|child| child != &right_paren) - .filter(|child| child.kind() == SyntaxKind::IDENT) - .map(|child| child.to_string()) - .collect()) + .filter_map(|token| token.into_token()) + .skip_while(|token| token != &left_paren) + .skip(1) + .take_while(|token| token != &right_paren) + { + if SyntaxKind::COMMA == token.kind() { + if !current_derive.is_empty() { + input_derives.insert(current_derive); + current_derive = String::new(); + } + } else { + current_derive.push_str(token.to_string().trim()); + } + } + + if !current_derive.is_empty() { + input_derives.insert(current_derive); + } + Ok(input_derives) } _ => Err(()), } @@ -188,8 +203,7 @@ fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet { ctx.scope().process_all_names(&mut |name, scope_def| { if let hir::ScopeDef::MacroDef(mac) = scope_def { if mac.is_derive_macro() { - let name_string = name.to_string(); - result.insert(name_string); + result.insert(name.to_string()); } } }); @@ -321,7 +335,7 @@ mod tests { assert_debug_snapshot!( do_attr_completion( r" - #[derive(Whatever, PartialEq, <|>)] + #[derive(serde::Serialize, PartialEq, <|>)] struct Test {} ", ), @@ -329,57 +343,57 @@ mod tests { [ CompletionItem { label: "Clone", - source_range: 51..51, - delete: 51..51, + source_range: 59..59, + delete: 59..59, insert: "Clone", kind: Attribute, }, CompletionItem { label: "Copy, Clone", - source_range: 51..51, - delete: 51..51, + source_range: 59..59, + delete: 59..59, insert: "Copy, Clone", kind: Attribute, }, CompletionItem { label: "Debug", - source_range: 51..51, - delete: 51..51, + source_range: 59..59, + delete: 59..59, insert: "Debug", kind: Attribute, }, CompletionItem { label: "Default", - source_range: 51..51, - delete: 51..51, + source_range: 59..59, + delete: 59..59, insert: "Default", kind: Attribute, }, CompletionItem { label: "Eq", - source_range: 51..51, - delete: 51..51, + source_range: 59..59, + delete: 59..59, insert: "Eq", kind: Attribute, }, CompletionItem { label: "Hash", - source_range: 51..51, - delete: 51..51, + source_range: 59..59, + delete: 59..59, insert: "Hash", kind: Attribute, }, CompletionItem { label: "Ord, PartialOrd, Eq", - source_range: 51..51, - delete: 51..51, + source_range: 59..59, + delete: 59..59, insert: "Ord, PartialOrd, Eq", kind: Attribute, }, CompletionItem { label: "PartialOrd", - source_range: 51..51, - delete: 51..51, + source_range: 59..59, + delete: 59..59, insert: "PartialOrd", kind: Attribute, }, -- cgit v1.2.3 From e9643ab74ca2559d38085a38f7d351991c896abb Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 4 May 2020 15:07:51 +0200 Subject: Cleanup imports --- crates/ra_ide/src/completion/complete_attribute.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'crates/ra_ide/src/completion') diff --git a/crates/ra_ide/src/completion/complete_attribute.rs b/crates/ra_ide/src/completion/complete_attribute.rs index 20e6edc17..4eaaa0b6f 100644 --- a/crates/ra_ide/src/completion/complete_attribute.rs +++ b/crates/ra_ide/src/completion/complete_attribute.rs @@ -3,15 +3,17 @@ //! This module uses a bit of static metadata to provide completions //! for built-in attributes. -use super::completion_context::CompletionContext; -use super::completion_item::{CompletionItem, CompletionItemKind, CompletionKind, Completions}; -use ast::AttrInput; use ra_syntax::{ - ast::{self, AttrKind}, + ast::{self, AttrInput, AttrKind}, AstNode, SyntaxKind, }; use rustc_hash::FxHashSet; +use crate::completion::{ + completion_context::CompletionContext, + completion_item::{CompletionItem, CompletionItemKind, CompletionKind, Completions}, +}; + pub(super) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { let attribute = ctx.attribute_under_caret.as_ref()?; -- cgit v1.2.3 From 8f4478390e29f34c5530a25bd0338b689218677f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 4 May 2020 15:08:51 +0200 Subject: Qualify ast types --- crates/ra_ide/src/completion/complete_attribute.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'crates/ra_ide/src/completion') diff --git a/crates/ra_ide/src/completion/complete_attribute.rs b/crates/ra_ide/src/completion/complete_attribute.rs index 4eaaa0b6f..f17266221 100644 --- a/crates/ra_ide/src/completion/complete_attribute.rs +++ b/crates/ra_ide/src/completion/complete_attribute.rs @@ -3,10 +3,7 @@ //! This module uses a bit of static metadata to provide completions //! for built-in attributes. -use ra_syntax::{ - ast::{self, AttrInput, AttrKind}, - AstNode, SyntaxKind, -}; +use ra_syntax::{ast, AstNode, SyntaxKind}; use rustc_hash::FxHashSet; use crate::completion::{ @@ -18,7 +15,9 @@ pub(super) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) let attribute = ctx.attribute_under_caret.as_ref()?; match (attribute.path(), attribute.input()) { - (Some(path), Some(AttrInput::TokenTree(token_tree))) if path.to_string() == "derive" => { + (Some(path), Some(ast::AttrInput::TokenTree(token_tree))) + if path.to_string() == "derive" => + { complete_derive(acc, ctx, token_tree) } _ => complete_attribute_start(acc, ctx, attribute), @@ -42,7 +41,7 @@ fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attr _ => {} } - if attribute.kind() == AttrKind::Inner || !attr_completion.should_be_inner { + if attribute.kind() == ast::AttrKind::Inner || !attr_completion.should_be_inner { acc.add(item); } } -- cgit v1.2.3 From b211c5814e994a411095e4392d804d692d58d43b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 4 May 2020 16:48:50 +0200 Subject: Remove false positive attr compleitons --- .../src/completion/complete_qualified_path.rs | 23 ++++++++++++++++++++-- .../src/completion/complete_unqualified_path.rs | 21 ++++++++++++++++++-- 2 files changed, 40 insertions(+), 4 deletions(-) (limited to 'crates/ra_ide/src/completion') diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs index aa56a5cd8..d9ea92ef8 100644 --- a/crates/ra_ide/src/completion/complete_qualified_path.rs +++ b/crates/ra_ide/src/completion/complete_qualified_path.rs @@ -2,16 +2,21 @@ use hir::{Adt, HasVisibility, PathResolution, ScopeDef}; use ra_syntax::AstNode; +use rustc_hash::FxHashSet; use test_utils::tested_by; use crate::completion::{CompletionContext, Completions}; -use rustc_hash::FxHashSet; pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) { let path = match &ctx.path_prefix { Some(path) => path.clone(), - _ => return, + None => return, }; + + if ctx.attribute_under_caret.is_some() { + return; + } + let scope = ctx.scope(); let context_module = scope.module(); @@ -1325,4 +1330,18 @@ mod tests { "### ); } + + #[test] + fn dont_complete_attr() { + assert_debug_snapshot!( + do_reference_completion( + r" + mod foo { pub struct Foo; } + #[foo::<|>] + fn f() {} + " + ), + @r###"[]"### + ) + } } diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs index a6a5568de..bd40af1cb 100644 --- a/crates/ra_ide/src/completion/complete_unqualified_path.rs +++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs @@ -8,9 +8,12 @@ use hir::{Adt, ModuleDef, Type}; use ra_syntax::AstNode; pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { - if (!ctx.is_trivial_path && !ctx.is_pat_binding_or_const) - || ctx.record_lit_syntax.is_some() + if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { + return; + } + if ctx.record_lit_syntax.is_some() || ctx.record_pat_syntax.is_some() + || ctx.attribute_under_caret.is_some() { return; } @@ -1369,4 +1372,18 @@ mod tests { "### ) } + + #[test] + fn dont_complete_attr() { + assert_debug_snapshot!( + do_reference_completion( + r" + struct Foo; + #[<|>] + fn f() {} + " + ), + @r###"[]"### + ) + } } -- cgit v1.2.3 From 92665358cd98913e3fef8294e1889cc0bb919e3f Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Tue, 5 May 2020 23:56:10 +0800 Subject: Rename ImplItem to AssocItem --- .../src/completion/complete_qualified_path.rs | 2 +- .../ra_ide/src/completion/complete_trait_impl.rs | 46 ++++++++++++---------- 2 files changed, 27 insertions(+), 21 deletions(-) (limited to 'crates/ra_ide/src/completion') diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs index d9ea92ef8..7fcd22525 100644 --- a/crates/ra_ide/src/completion/complete_qualified_path.rs +++ b/crates/ra_ide/src/completion/complete_qualified_path.rs @@ -84,7 +84,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon }); // Iterate assoc types separately - ty.iterate_impl_items(ctx.db, krate, |item| { + ty.iterate_assoc_items(ctx.db, krate, |item| { if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { return None; } diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index ee32d1ff6..039df03e0 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -32,7 +32,7 @@ //! ``` use hir::{self, Docs, HasSource}; -use ra_assists::utils::get_missing_impl_items; +use ra_assists::utils::get_missing_assoc_items; use ra_syntax::{ ast::{self, edit, ImplDef}, AstNode, SyntaxKind, SyntaxNode, TextRange, T, @@ -50,7 +50,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext if let Some((trigger, impl_def)) = completion_match(ctx) { match trigger.kind() { SyntaxKind::NAME_REF => { - get_missing_impl_items(&ctx.sema, &impl_def).iter().for_each(|item| match item { + get_missing_assoc_items(&ctx.sema, &impl_def).iter().for_each(|item| match item { hir::AssocItem::Function(fn_item) => { add_function_impl(&trigger, acc, ctx, &fn_item) } @@ -64,34 +64,40 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext } SyntaxKind::FN_DEF => { - for missing_fn in get_missing_impl_items(&ctx.sema, &impl_def).iter().filter_map( - |item| match item { - hir::AssocItem::Function(fn_item) => Some(fn_item), - _ => None, - }, - ) { + for missing_fn in + get_missing_assoc_items(&ctx.sema, &impl_def).iter().filter_map(|item| { + match item { + hir::AssocItem::Function(fn_item) => Some(fn_item), + _ => None, + } + }) + { add_function_impl(&trigger, acc, ctx, &missing_fn); } } SyntaxKind::TYPE_ALIAS_DEF => { - for missing_fn in get_missing_impl_items(&ctx.sema, &impl_def).iter().filter_map( - |item| match item { - hir::AssocItem::TypeAlias(type_item) => Some(type_item), - _ => None, - }, - ) { + for missing_fn in + get_missing_assoc_items(&ctx.sema, &impl_def).iter().filter_map(|item| { + match item { + hir::AssocItem::TypeAlias(type_item) => Some(type_item), + _ => None, + } + }) + { add_type_alias_impl(&trigger, acc, ctx, &missing_fn); } } SyntaxKind::CONST_DEF => { - for missing_fn in get_missing_impl_items(&ctx.sema, &impl_def).iter().filter_map( - |item| match item { - hir::AssocItem::Const(const_item) => Some(const_item), - _ => None, - }, - ) { + for missing_fn in + get_missing_assoc_items(&ctx.sema, &impl_def).iter().filter_map(|item| { + match item { + hir::AssocItem::Const(const_item) => Some(const_item), + _ => None, + } + }) + { add_const_impl(&trigger, acc, ctx, &missing_fn); } } -- cgit v1.2.3 From 4a6fa8f0dfcebbb4ea80394e5e4ca21f076f58f2 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 5 May 2020 23:15:49 +0200 Subject: Rename AtomTextEdit -> Indel --- crates/ra_ide/src/completion/completion_context.rs | 4 ++-- crates/ra_ide/src/completion/completion_item.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'crates/ra_ide/src/completion') diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index dd87bd119..b6b9627de 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs @@ -9,7 +9,7 @@ use ra_syntax::{ SyntaxKind::*, SyntaxNode, SyntaxToken, TextRange, TextSize, }; -use ra_text_edit::AtomTextEdit; +use ra_text_edit::Indel; use crate::{call_info::ActiveParameter, completion::CompletionConfig, FilePosition}; @@ -76,7 +76,7 @@ impl<'a> CompletionContext<'a> { // actual completion. let file_with_fake_ident = { let parse = db.parse(position.file_id); - let edit = AtomTextEdit::insert(position.offset, "intellijRulezz".to_string()); + let edit = Indel::insert(position.offset, "intellijRulezz".to_string()); parse.reparse(&edit).tree() }; let fake_ident_token = diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs index 5936fb8f7..383b23ac4 100644 --- a/crates/ra_ide/src/completion/completion_item.rs +++ b/crates/ra_ide/src/completion/completion_item.rs @@ -62,8 +62,8 @@ impl fmt::Debug for CompletionItem { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut s = f.debug_struct("CompletionItem"); s.field("label", &self.label()).field("source_range", &self.source_range()); - if self.text_edit().as_atoms().len() == 1 { - let atom = &self.text_edit().as_atoms()[0]; + if self.text_edit().as_indels().len() == 1 { + let atom = &self.text_edit().as_indels()[0]; s.field("delete", &atom.delete); s.field("insert", &atom.insert); } else { -- cgit v1.2.3 From 4d50709a96f92f3927b3ac59110d593b49c53008 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 6 May 2020 16:05:43 +0200 Subject: Minor --- crates/ra_ide/src/completion/completion_item.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'crates/ra_ide/src/completion') diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs index 383b23ac4..6021f7279 100644 --- a/crates/ra_ide/src/completion/completion_item.rs +++ b/crates/ra_ide/src/completion/completion_item.rs @@ -2,11 +2,12 @@ use std::fmt; -use super::completion_config::SnippetCap; use hir::Documentation; use ra_syntax::TextRange; use ra_text_edit::TextEdit; +use crate::completion::completion_config::SnippetCap; + /// `CompletionItem` describes a single completion variant in the editor pop-up. /// It is basically a POD with various properties. To construct a /// `CompletionItem`, use `new` method and the `Builder` struct. -- cgit v1.2.3 From 6203e9c4faee288f16d93dbb7dd0f1f8df487d83 Mon Sep 17 00:00:00 2001 From: Benjamin Coenen <5719034+bnjjj@users.noreply.github.com> Date: Thu, 7 May 2020 11:23:38 +0200 Subject: add if let and while let postfix for Option and Result #4348 Signed-off-by: Benjamin Coenen <5719034+bnjjj@users.noreply.github.com> --- crates/ra_ide/src/completion/complete_postfix.rs | 200 ++++++++++++++++++++++- 1 file changed, 199 insertions(+), 1 deletion(-) (limited to 'crates/ra_ide/src/completion') diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs index 6a0f0c72e..dc32bbee2 100644 --- a/crates/ra_ide/src/completion/complete_postfix.rs +++ b/crates/ra_ide/src/completion/complete_postfix.rs @@ -38,7 +38,47 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { None => return, }; - if receiver_ty.is_bool() || receiver_ty.is_unknown() { + if receiver_ty.is_option(ctx.db) { + postfix_snippet( + ctx, + cap, + &dot_receiver, + "ifl", + "if let Some {}", + &format!("if let Some($1) = {} {{\n $0\n}}", receiver_text), + ) + .add_to(acc); + + postfix_snippet( + ctx, + cap, + &dot_receiver, + "while", + "while let Some {}", + &format!("while let Some($1) = {} {{\n $0\n}}", receiver_text), + ) + .add_to(acc); + } else if receiver_ty.is_result(ctx.db) { + postfix_snippet( + ctx, + cap, + &dot_receiver, + "ifl", + "if let Ok {}", + &format!("if let Ok($1) = {} {{\n $0\n}}", receiver_text), + ) + .add_to(acc); + + postfix_snippet( + ctx, + cap, + &dot_receiver, + "while", + "while let Ok {}", + &format!("while let Ok($1) = {} {{\n $0\n}}", receiver_text), + ) + .add_to(acc); + } else if receiver_ty.is_bool() || receiver_ty.is_unknown() { postfix_snippet( ctx, cap, @@ -235,6 +275,164 @@ mod tests { ); } + #[test] + fn postfix_completion_works_for_option() { + assert_debug_snapshot!( + do_postfix_completion( + r#" + enum Option { + Some(T), + None, + } + + fn main() { + let bar = Option::Some(true); + bar.<|> + } + "#, + ), + @r###" + [ + CompletionItem { + label: "box", + source_range: 210..210, + delete: 206..210, + insert: "Box::new(bar)", + detail: "Box::new(expr)", + }, + CompletionItem { + label: "dbg", + source_range: 210..210, + delete: 206..210, + insert: "dbg!(bar)", + detail: "dbg!(expr)", + }, + CompletionItem { + label: "ifl", + source_range: 210..210, + delete: 206..210, + insert: "if let Some($1) = bar {\n $0\n}", + detail: "if let Some {}", + }, + CompletionItem { + label: "match", + source_range: 210..210, + delete: 206..210, + insert: "match bar {\n ${1:_} => {$0\\},\n}", + detail: "match expr {}", + }, + CompletionItem { + label: "not", + source_range: 210..210, + delete: 206..210, + insert: "!bar", + detail: "!expr", + }, + CompletionItem { + label: "ref", + source_range: 210..210, + delete: 206..210, + insert: "&bar", + detail: "&expr", + }, + CompletionItem { + label: "refm", + source_range: 210..210, + delete: 206..210, + insert: "&mut bar", + detail: "&mut expr", + }, + CompletionItem { + label: "while", + source_range: 210..210, + delete: 206..210, + insert: "while let Some($1) = bar {\n $0\n}", + detail: "while let Some {}", + }, + ] + "### + ); + } + + #[test] + fn postfix_completion_works_for_result() { + assert_debug_snapshot!( + do_postfix_completion( + r#" + enum Result { + Ok(T), + Err(E), + } + + fn main() { + let bar = Result::Ok(true); + bar.<|> + } + "#, + ), + @r###" + [ + CompletionItem { + label: "box", + source_range: 211..211, + delete: 207..211, + insert: "Box::new(bar)", + detail: "Box::new(expr)", + }, + CompletionItem { + label: "dbg", + source_range: 211..211, + delete: 207..211, + insert: "dbg!(bar)", + detail: "dbg!(expr)", + }, + CompletionItem { + label: "ifl", + source_range: 211..211, + delete: 207..211, + insert: "if let Ok($1) = bar {\n $0\n}", + detail: "if let Ok {}", + }, + CompletionItem { + label: "match", + source_range: 211..211, + delete: 207..211, + insert: "match bar {\n ${1:_} => {$0\\},\n}", + detail: "match expr {}", + }, + CompletionItem { + label: "not", + source_range: 211..211, + delete: 207..211, + insert: "!bar", + detail: "!expr", + }, + CompletionItem { + label: "ref", + source_range: 211..211, + delete: 207..211, + insert: "&bar", + detail: "&expr", + }, + CompletionItem { + label: "refm", + source_range: 211..211, + delete: 207..211, + insert: "&mut bar", + detail: "&mut expr", + }, + CompletionItem { + label: "while", + source_range: 211..211, + delete: 207..211, + insert: "while let Ok($1) = bar {\n $0\n}", + detail: "while let Ok {}", + }, + ] + "### + ); + } + #[test] fn some_postfix_completions_ignored() { assert_debug_snapshot!( -- cgit v1.2.3 From 92b2230fefe61322dbca8194c8721f848c5d1c2f Mon Sep 17 00:00:00 2001 From: Benjamin Coenen <5719034+bnjjj@users.noreply.github.com> Date: Sun, 10 May 2020 12:45:35 +0200 Subject: add if let and while let postfix for Option and Result Signed-off-by: Benjamin Coenen <5719034+bnjjj@users.noreply.github.com> --- crates/ra_ide/src/completion/complete_postfix.rs | 82 +++++++++++++----------- 1 file changed, 44 insertions(+), 38 deletions(-) (limited to 'crates/ra_ide/src/completion') diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs index dc32bbee2..c5c4426cc 100644 --- a/crates/ra_ide/src/completion/complete_postfix.rs +++ b/crates/ra_ide/src/completion/complete_postfix.rs @@ -14,6 +14,7 @@ use crate::{ }, CompletionItem, }; +use ra_assists::utils::TryEnum; pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { if !ctx.config.enable_postfix_completions { @@ -38,46 +39,51 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { None => return, }; - if receiver_ty.is_option(ctx.db) { - postfix_snippet( - ctx, - cap, - &dot_receiver, - "ifl", - "if let Some {}", - &format!("if let Some($1) = {} {{\n $0\n}}", receiver_text), - ) - .add_to(acc); + if let Some(try_enum) = TryEnum::from_ty(&ctx.sema, &receiver_ty) { + match try_enum { + TryEnum::Result => { + postfix_snippet( + ctx, + cap, + &dot_receiver, + "ifl", + "if let Ok {}", + &format!("if let Ok($1) = {} {{\n $0\n}}", receiver_text), + ) + .add_to(acc); - postfix_snippet( - ctx, - cap, - &dot_receiver, - "while", - "while let Some {}", - &format!("while let Some($1) = {} {{\n $0\n}}", receiver_text), - ) - .add_to(acc); - } else if receiver_ty.is_result(ctx.db) { - postfix_snippet( - ctx, - cap, - &dot_receiver, - "ifl", - "if let Ok {}", - &format!("if let Ok($1) = {} {{\n $0\n}}", receiver_text), - ) - .add_to(acc); + postfix_snippet( + ctx, + cap, + &dot_receiver, + "while", + "while let Ok {}", + &format!("while let Ok($1) = {} {{\n $0\n}}", receiver_text), + ) + .add_to(acc); + } + TryEnum::Option => { + postfix_snippet( + ctx, + cap, + &dot_receiver, + "ifl", + "if let Some {}", + &format!("if let Some($1) = {} {{\n $0\n}}", receiver_text), + ) + .add_to(acc); - postfix_snippet( - ctx, - cap, - &dot_receiver, - "while", - "while let Ok {}", - &format!("while let Ok($1) = {} {{\n $0\n}}", receiver_text), - ) - .add_to(acc); + postfix_snippet( + ctx, + cap, + &dot_receiver, + "while", + "while let Some {}", + &format!("while let Some($1) = {} {{\n $0\n}}", receiver_text), + ) + .add_to(acc); + } + } } else if receiver_ty.is_bool() || receiver_ty.is_unknown() { postfix_snippet( ctx, -- cgit v1.2.3 From 4e54b1ca4628e61c2534462b87f9620e2306dc59 Mon Sep 17 00:00:00 2001 From: Benjamin Coenen <5719034+bnjjj@users.noreply.github.com> Date: Mon, 11 May 2020 18:11:23 +0200 Subject: add tests module snippet Signed-off-by: Benjamin Coenen <5719034+bnjjj@users.noreply.github.com> --- crates/ra_ide/src/completion/complete_snippet.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'crates/ra_ide/src/completion') diff --git a/crates/ra_ide/src/completion/complete_snippet.rs b/crates/ra_ide/src/completion/complete_snippet.rs index a3f5d1b6a..be8fbea2a 100644 --- a/crates/ra_ide/src/completion/complete_snippet.rs +++ b/crates/ra_ide/src/completion/complete_snippet.rs @@ -33,6 +33,24 @@ pub(super) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionConte None => return, }; + snippet( + ctx, + cap, + "Test module", + "\ +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn ${1:test_name}() { + $0 + } +}", + ) + .lookup_by("tmod") + .add_to(acc); + snippet( ctx, cap, -- cgit v1.2.3 From 72e3d2260b90cf3ea62f5ecd4acaf2dc5b7675c7 Mon Sep 17 00:00:00 2001 From: Benjamin Coenen <5719034+bnjjj@users.noreply.github.com> Date: Mon, 11 May 2020 19:59:58 +0200 Subject: add tests module snippet Signed-off-by: Benjamin Coenen <5719034+bnjjj@users.noreply.github.com> --- crates/ra_ide/src/completion/complete_snippet.rs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'crates/ra_ide/src/completion') diff --git a/crates/ra_ide/src/completion/complete_snippet.rs b/crates/ra_ide/src/completion/complete_snippet.rs index be8fbea2a..0568d9ccf 100644 --- a/crates/ra_ide/src/completion/complete_snippet.rs +++ b/crates/ra_ide/src/completion/complete_snippet.rs @@ -135,6 +135,14 @@ mod tests { kind: Snippet, lookup: "tfn", }, + CompletionItem { + label: "Test module", + source_range: 78..78, + delete: 78..78, + insert: "#[cfg(test)]\nmod tests {\n use super::*;\n\n #[test]\n fn ${1:test_name}() {\n $0\n }\n}", + kind: Snippet, + lookup: "tmod", + }, CompletionItem { label: "macro_rules", source_range: 78..78, -- cgit v1.2.3 From df330224080fca5eafa3327f082d18857a839dfe Mon Sep 17 00:00:00 2001 From: Benjamin Coenen <5719034+bnjjj@users.noreply.github.com> Date: Tue, 12 May 2020 11:48:58 +0200 Subject: add more specific match postfix for Result and Option Signed-off-by: Benjamin Coenen <5719034+bnjjj@users.noreply.github.com> --- crates/ra_ide/src/completion/complete_postfix.rs | 58 ++++++++++++++++++------ 1 file changed, 43 insertions(+), 15 deletions(-) (limited to 'crates/ra_ide/src/completion') diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs index c5c4426cc..f2a52a407 100644 --- a/crates/ra_ide/src/completion/complete_postfix.rs +++ b/crates/ra_ide/src/completion/complete_postfix.rs @@ -38,8 +38,8 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { Some(it) => it, None => return, }; - - if let Some(try_enum) = TryEnum::from_ty(&ctx.sema, &receiver_ty) { + let try_enum = TryEnum::from_ty(&ctx.sema, &receiver_ty); + if let Some(try_enum) = &try_enum { match try_enum { TryEnum::Result => { postfix_snippet( @@ -104,7 +104,6 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { ) .add_to(acc); } - // !&&&42 is a compiler error, ergo process it before considering the references postfix_snippet(ctx, cap, &dot_receiver, "not", "!expr", &format!("!{}", receiver_text)) .add_to(acc); @@ -126,16 +125,45 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { let dot_receiver = include_references(dot_receiver); let receiver_text = get_receiver_text(&dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal); - - postfix_snippet( - ctx, - cap, - &dot_receiver, - "match", - "match expr {}", - &format!("match {} {{\n ${{1:_}} => {{$0\\}},\n}}", receiver_text), - ) - .add_to(acc); + match try_enum { + Some(try_enum) => { + match try_enum { + TryEnum::Result => { + postfix_snippet( + ctx, + cap, + &dot_receiver, + "match", + "match expr {}", + &format!("match {} {{\n Ok(${{1:_}}) => {{$2\\}},\n Err(${{3:_}}) => {{$0\\}},\n}}", receiver_text), + ) + .add_to(acc); + } + TryEnum::Option => { + postfix_snippet( + ctx, + cap, + &dot_receiver, + "match", + "match expr {}", + &format!("match {} {{\n Some(${{1:_}}) => {{$2\\}},\n None => {{$0\\}},\n}}", receiver_text), + ) + .add_to(acc); + } + } + } + None => { + postfix_snippet( + ctx, + cap, + &dot_receiver, + "match", + "match expr {}", + &format!("match {} {{\n ${{1:_}} => {{$0\\}},\n}}", receiver_text), + ) + .add_to(acc); + } + } postfix_snippet( ctx, @@ -324,7 +352,7 @@ mod tests { label: "match", source_range: 210..210, delete: 206..210, - insert: "match bar {\n ${1:_} => {$0\\},\n}", + insert: "match bar {\n Some(${1:_}) => {$2\\},\n None => {$0\\},\n}", detail: "match expr {}", }, CompletionItem { @@ -403,7 +431,7 @@ mod tests { label: "match", source_range: 211..211, delete: 207..211, - insert: "match bar {\n ${1:_} => {$0\\},\n}", + insert: "match bar {\n Ok(${1:_}) => {$2\\},\n Err(${3:_}) => {$0\\},\n}", detail: "match expr {}", }, CompletionItem { -- cgit v1.2.3 From 90c62bcee9d1950d0e4b642fc2bd3ae5374e40cb Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 14 May 2020 15:15:52 +0200 Subject: Prioritize locals with correct types --- crates/ra_ide/src/completion/completion_context.rs | 2 +- crates/ra_ide/src/completion/presentation.rs | 58 ++++++++++++++++++++-- 2 files changed, 55 insertions(+), 5 deletions(-) (limited to 'crates/ra_ide/src/completion') diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index b6b9627de..da336973c 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs @@ -34,7 +34,7 @@ pub(crate) struct CompletionContext<'a> { pub(super) record_pat_syntax: Option, pub(super) record_field_syntax: Option, pub(super) impl_def: Option, - /// FIXME: `ActiveParameter` is string-based, which is very wrong + /// FIXME: `ActiveParameter` is string-based, which is very very wrong pub(super) active_parameter: Option, pub(super) is_param: bool, /// If a name-binding or reference to a const in a pattern. diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 2edb130cf..077cf9647 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs @@ -17,12 +17,11 @@ use crate::{ impl Completions { pub(crate) fn add_field(&mut self, ctx: &CompletionContext, field: hir::Field, ty: &Type) { let is_deprecated = is_deprecated(field, ctx.db); - let ty = ty.display(ctx.db).to_string(); let name = field.name(ctx.db); let mut completion_item = CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) .kind(CompletionItemKind::Field) - .detail(ty.clone()) + .detail(ty.display(ctx.db).to_string()) .set_documentation(field.docs(ctx.db)) .set_deprecated(is_deprecated); @@ -107,6 +106,12 @@ impl Completions { } }; + 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); + } + } + // Add `<>` for generic types if ctx.is_path_type && !ctx.has_type_args && ctx.config.add_call_parenthesis { if let Some(cap) = ctx.config.snippet_cap { @@ -319,10 +324,11 @@ impl Completions { pub(crate) fn compute_score( ctx: &CompletionContext, - // FIXME: this definitely should be a `Type` - ty: &str, + ty: &Type, name: &str, ) -> Option { + // FIXME: this should not fall back to string equality. + let ty = &ty.display(ctx.db).to_string(); let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { tested_by!(test_struct_field_completion_in_record_lit); let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?; @@ -1405,4 +1411,48 @@ mod tests { "### ); } + + #[test] + fn prioritize_exact_ref_match() { + assert_debug_snapshot!( + do_reference_completion( + r" + struct WorldSnapshot { _f: () }; + fn go(world: &WorldSnapshot) { + go(w<|>) + } + ", + ), + @r###" + [ + CompletionItem { + label: "WorldSnapshot", + source_range: 132..133, + delete: 132..133, + insert: "WorldSnapshot", + kind: Struct, + }, + CompletionItem { + label: "go(…)", + source_range: 132..133, + delete: 132..133, + insert: "go(${1:world})$0", + kind: Function, + lookup: "go", + detail: "fn go(world: &WorldSnapshot)", + trigger_call_info: true, + }, + CompletionItem { + label: "world", + source_range: 132..133, + delete: 132..133, + insert: "world", + kind: Binding, + detail: "&WorldSnapshot", + score: TypeAndNameMatch, + }, + ] + "### + ); + } } -- cgit v1.2.3 From 001a86dc03104b75df732d69257d22526cf422b7 Mon Sep 17 00:00:00 2001 From: Hasan Ali Date: Fri, 15 May 2020 22:23:49 +0100 Subject: Fix completion and hover for module and function of same name --- .../src/completion/complete_qualified_path.rs | 30 +++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'crates/ra_ide/src/completion') diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs index 7fcd22525..db7430454 100644 --- a/crates/ra_ide/src/completion/complete_qualified_path.rs +++ b/crates/ra_ide/src/completion/complete_qualified_path.rs @@ -20,7 +20,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon let scope = ctx.scope(); let context_module = scope.module(); - let res = match scope.resolve_hir_path(&path) { + let res = match scope.resolve_hir_path_qualifier(&path) { Some(res) => res, None => return, }; @@ -225,6 +225,34 @@ mod tests { ); } + #[test] + fn completes_mod_with_same_name_as_function() { + assert_debug_snapshot!( + do_reference_completion( + r" + use self::my::<|>; + + mod my { + pub struct Bar; + } + + fn my() {} + " + ), + @r###" + [ + CompletionItem { + label: "Bar", + source_range: 31..31, + delete: 31..31, + insert: "Bar", + kind: Struct, + }, + ] + "### + ); + } + #[test] fn path_visibility() { assert_debug_snapshot!( -- cgit v1.2.3 From c847c079fd66d7ed09c64ff398baf05317b16500 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 17 May 2020 12:09:53 +0200 Subject: Add AssistConfig --- crates/ra_ide/src/completion/test_utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/ra_ide/src/completion') diff --git a/crates/ra_ide/src/completion/test_utils.rs b/crates/ra_ide/src/completion/test_utils.rs index eb90b5279..bf22452a2 100644 --- a/crates/ra_ide/src/completion/test_utils.rs +++ b/crates/ra_ide/src/completion/test_utils.rs @@ -20,7 +20,7 @@ pub(crate) fn do_completion_with_options( } else { single_file_with_position(code) }; - let completions = analysis.completions(position, options).unwrap().unwrap(); + let completions = analysis.completions(options, position).unwrap().unwrap(); let completion_items: Vec = completions.into(); let mut kind_completions: Vec = completion_items.into_iter().filter(|c| c.completion_kind == kind).collect(); -- cgit v1.2.3 From ecac5d7de2192873c24b7b06d4964d188d8abe6a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 20 May 2020 12:59:20 +0200 Subject: Switch to new magic marks --- .../src/completion/complete_qualified_path.rs | 8 ++++---- .../src/completion/complete_unqualified_path.rs | 8 ++++---- crates/ra_ide/src/completion/presentation.rs | 24 +++++++++++----------- 3 files changed, 20 insertions(+), 20 deletions(-) (limited to 'crates/ra_ide/src/completion') diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs index db7430454..02ac0166b 100644 --- a/crates/ra_ide/src/completion/complete_qualified_path.rs +++ b/crates/ra_ide/src/completion/complete_qualified_path.rs @@ -3,7 +3,7 @@ use hir::{Adt, HasVisibility, PathResolution, ScopeDef}; use ra_syntax::AstNode; use rustc_hash::FxHashSet; -use test_utils::tested_by; +use test_utils::mark; use crate::completion::{CompletionContext, Completions}; @@ -40,7 +40,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { if name_ref.syntax().text() == name.to_string().as_str() { // for `use self::foo<|>`, don't suggest `foo` as a completion - tested_by!(dont_complete_current_use); + mark::hit!(dont_complete_current_use); continue; } } @@ -147,7 +147,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon #[cfg(test)] mod tests { - use test_utils::covers; + use test_utils::mark; use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; use insta::assert_debug_snapshot; @@ -158,7 +158,7 @@ mod tests { #[test] fn dont_complete_current_use() { - covers!(dont_complete_current_use); + mark::check!(dont_complete_current_use); let completions = do_completion(r"use self::foo<|>;", CompletionKind::Reference); assert!(completions.is_empty()); } diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs index bd40af1cb..db791660a 100644 --- a/crates/ra_ide/src/completion/complete_unqualified_path.rs +++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs @@ -1,7 +1,7 @@ //! Completion of names from the current scope, e.g. locals and imported items. use hir::ScopeDef; -use test_utils::tested_by; +use test_utils::mark; use crate::completion::{CompletionContext, Completions}; use hir::{Adt, ModuleDef, Type}; @@ -30,7 +30,7 @@ pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC if ctx.use_item_syntax.is_some() { if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) { if name_ref.syntax().text() == name.to_string().as_str() { - tested_by!(self_fulfilling_completion); + mark::hit!(self_fulfilling_completion); return; } } @@ -66,7 +66,7 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T #[cfg(test)] mod tests { use insta::assert_debug_snapshot; - use test_utils::covers; + use test_utils::mark; use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; @@ -76,7 +76,7 @@ mod tests { #[test] fn self_fulfilling_completion() { - covers!(self_fulfilling_completion); + mark::check!(self_fulfilling_completion); assert_debug_snapshot!( do_reference_completion( r#" diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 077cf9647..440ffa31d 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs @@ -3,7 +3,7 @@ use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type}; use ra_syntax::ast::NameOwner; use stdx::SepBy; -use test_utils::tested_by; +use test_utils::mark; use crate::{ completion::{ @@ -121,7 +121,7 @@ impl Completions { _ => false, }; if has_non_default_type_params { - tested_by!(inserts_angle_brackets_for_generics); + mark::hit!(inserts_angle_brackets_for_generics); completion_item = completion_item .lookup_by(local_name.clone()) .label(format!("{}<…>", local_name)) @@ -176,7 +176,7 @@ impl Completions { } None if needs_bang => builder.insert_text(format!("{}!", name)), _ => { - tested_by!(dont_insert_macro_call_parens_unncessary); + mark::hit!(dont_insert_macro_call_parens_unncessary); builder.insert_text(name) } }; @@ -330,14 +330,14 @@ pub(crate) fn compute_score( // FIXME: this should not fall back to string equality. let ty = &ty.display(ctx.db).to_string(); let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { - tested_by!(test_struct_field_completion_in_record_lit); + mark::hit!(test_struct_field_completion_in_record_lit); let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?; ( struct_field.name(ctx.db).to_string(), struct_field.signature_ty(ctx.db).display(ctx.db).to_string(), ) } else if let Some(active_parameter) = &ctx.active_parameter { - tested_by!(test_struct_field_completion_in_func_call); + mark::hit!(test_struct_field_completion_in_func_call); (active_parameter.name.clone(), active_parameter.ty.clone()) } else { return None; @@ -398,7 +398,7 @@ impl Builder { None => return self, }; // If not an import, add parenthesis automatically. - tested_by!(inserts_parens_for_function_calls); + mark::hit!(inserts_parens_for_function_calls); let (snippet, label) = if params.is_empty() { (format!("{}()$0", name), format!("{}()", name)) @@ -457,7 +457,7 @@ fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static s #[cfg(test)] mod tests { use insta::assert_debug_snapshot; - use test_utils::covers; + use test_utils::mark; use crate::completion::{ test_utils::{do_completion, do_completion_with_options}, @@ -607,7 +607,7 @@ mod tests { #[test] fn inserts_parens_for_function_calls() { - covers!(inserts_parens_for_function_calls); + mark::check!(inserts_parens_for_function_calls); assert_debug_snapshot!( do_reference_completion( r" @@ -992,7 +992,7 @@ mod tests { #[test] fn inserts_angle_brackets_for_generics() { - covers!(inserts_angle_brackets_for_generics); + mark::check!(inserts_angle_brackets_for_generics); assert_debug_snapshot!( do_reference_completion( r" @@ -1115,7 +1115,7 @@ mod tests { #[test] fn dont_insert_macro_call_parens_unncessary() { - covers!(dont_insert_macro_call_parens_unncessary); + mark::check!(dont_insert_macro_call_parens_unncessary); assert_debug_snapshot!( do_reference_completion( r" @@ -1181,7 +1181,7 @@ mod tests { #[test] fn test_struct_field_completion_in_func_call() { - covers!(test_struct_field_completion_in_func_call); + mark::check!(test_struct_field_completion_in_func_call); assert_debug_snapshot!( do_reference_completion( r" @@ -1271,7 +1271,7 @@ mod tests { #[test] fn test_struct_field_completion_in_record_lit() { - covers!(test_struct_field_completion_in_record_lit); + mark::check!(test_struct_field_completion_in_record_lit); assert_debug_snapshot!( do_reference_completion( r" -- cgit v1.2.3 From 5f57491c981530103e1e26dcd280e1a2df10f853 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 21 May 2020 15:56:18 +0200 Subject: Cleanup TextEdit --- crates/ra_ide/src/completion/completion_item.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'crates/ra_ide/src/completion') diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs index 6021f7279..cfb7c1e38 100644 --- a/crates/ra_ide/src/completion/completion_item.rs +++ b/crates/ra_ide/src/completion/completion_item.rs @@ -63,8 +63,8 @@ impl fmt::Debug for CompletionItem { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut s = f.debug_struct("CompletionItem"); s.field("label", &self.label()).field("source_range", &self.source_range()); - if self.text_edit().as_indels().len() == 1 { - let atom = &self.text_edit().as_indels()[0]; + if self.text_edit().len() == 1 { + let atom = &self.text_edit().iter().next().unwrap(); s.field("delete", &atom.delete); s.field("insert", &atom.insert); } else { -- cgit v1.2.3