From 3b75bc154f75cb97ff2debee9f6594d6fc4f4053 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 17 Apr 2020 11:55:06 +0200 Subject: Better snippet when completing trait method --- crates/ra_ide/src/completion/complete_trait_impl.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'crates/ra_ide') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index fab02945c..2ec0e7ce9 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -142,11 +142,11 @@ fn add_function_impl( CompletionItemKind::Function }; - let snippet = format!("{} {{}}", display); + let snippet = format!("{} {{\n $0\n}}", display); let range = TextRange::from_to(fn_def_node.text_range().start(), ctx.source_range().end()); - builder.text_edit(TextEdit::replace(range, snippet)).kind(completion_kind).add_to(acc); + builder.snippet_edit(TextEdit::replace(range, snippet)).kind(completion_kind).add_to(acc); } fn add_type_alias_impl( @@ -217,9 +217,10 @@ fn make_const_compl_syntax(const_: &ast::ConstDef) -> String { #[cfg(test)] mod tests { - use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; use insta::assert_debug_snapshot; + use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; + fn complete(code: &str) -> Vec { do_completion(code, CompletionKind::Magic) } @@ -255,7 +256,7 @@ mod tests { label: "fn test()", source_range: [209; 210), delete: [209; 210), - insert: "fn test() {}", + insert: "fn test() {\n $0\n}", kind: Function, lookup: "test", }, @@ -313,7 +314,7 @@ mod tests { label: "fn test()", source_range: [139; 140), delete: [139; 140), - insert: "fn test() {}", + insert: "fn test() {\n $0\n}", kind: Function, lookup: "test", }, @@ -342,7 +343,7 @@ mod tests { label: "fn foo()", source_range: [141; 142), delete: [138; 142), - insert: "fn foo() {}", + insert: "fn foo() {\n $0\n}", kind: Function, lookup: "foo", }, @@ -374,7 +375,7 @@ mod tests { label: "fn foo_bar()", source_range: [200; 201), delete: [197; 201), - insert: "fn foo_bar() {}", + insert: "fn foo_bar() {\n $0\n}", kind: Function, lookup: "foo_bar", }, @@ -425,7 +426,7 @@ mod tests { label: "fn foo()", source_range: [144; 145), delete: [141; 145), - insert: "fn foo() {}", + insert: "fn foo() {\n $0\n}", kind: Function, lookup: "foo", }, @@ -454,7 +455,7 @@ mod tests { label: "fn foo()", source_range: [166; 167), delete: [163; 167), - insert: "fn foo()\nwhere T: Into {}", + insert: "fn foo()\nwhere T: Into {\n $0\n}", kind: Function, lookup: "foo", }, -- cgit v1.2.3 From a8196ffe8466aa60dec56e77c2da717793c0debe Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 17 Apr 2020 13:06:02 +0200 Subject: Correctly highlight ranges of diagnostics from macros closes #2799 --- crates/ra_ide/src/diagnostics.rs | 72 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 6 deletions(-) (limited to 'crates/ra_ide') diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index 901ad104c..e7e201709 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs @@ -1,4 +1,8 @@ -//! FIXME: write short doc here +//! Collects diagnostics & fixits for a single file. +//! +//! The tricky bit here is that diagnostics are produced by hir in terms of +//! macro-expanded files, but we need to present them to the users in terms of +//! original files. So we need to map the ranges. use std::cell::RefCell; @@ -46,7 +50,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec let mut sink = DiagnosticSink::new(|d| { res.borrow_mut().push(Diagnostic { message: d.message(), - range: d.highlight_range(), + range: sema.diagnostics_range(d).range, severity: Severity::Error, fix: None, }) @@ -62,7 +66,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec let create_file = FileSystemEdit::CreateFile { source_root, path }; let fix = SourceChange::file_system_edit("create module", create_file); res.borrow_mut().push(Diagnostic { - range: d.highlight_range(), + range: sema.diagnostics_range(d).range, message: d.message(), severity: Severity::Error, fix: Some(fix), @@ -95,7 +99,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec }; res.borrow_mut().push(Diagnostic { - range: d.highlight_range(), + range: sema.diagnostics_range(d).range, message: d.message(), severity: Severity::Error, fix, @@ -103,7 +107,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec }) .on::(|d| { res.borrow_mut().push(Diagnostic { - range: d.highlight_range(), + range: sema.diagnostics_range(d).range, message: d.message(), severity: Severity::Error, fix: None, @@ -115,7 +119,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec let edit = TextEdit::replace(node.syntax().text_range(), replacement); let fix = SourceChange::source_file_edit_from("wrap with ok", file_id, edit); res.borrow_mut().push(Diagnostic { - range: d.highlight_range(), + range: sema.diagnostics_range(d).range, message: d.message(), severity: Severity::Error, fix: Some(fix), @@ -621,6 +625,62 @@ mod tests { "###); } + #[test] + fn range_mapping_out_of_macros() { + let (analysis, file_id) = single_file( + r" + fn some() {} + fn items() {} + fn here() {} + + macro_rules! id { + ($($tt:tt)*) => { $($tt)*}; + } + + fn main() { + let _x = id![Foo { a: 42 }]; + } + + pub struct Foo { + pub a: i32, + pub b: i32, + } + ", + ); + let diagnostics = analysis.diagnostics(file_id).unwrap(); + assert_debug_snapshot!(diagnostics, @r###" + [ + Diagnostic { + message: "Missing structure fields:\n- b", + range: [224; 233), + fix: Some( + SourceChange { + label: "fill struct fields", + source_file_edits: [ + SourceFileEdit { + file_id: FileId( + 1, + ), + edit: TextEdit { + atoms: [ + AtomTextEdit { + delete: [3; 9), + insert: "{a:42, b: ()}", + }, + ], + }, + }, + ], + file_system_edits: [], + cursor_position: None, + }, + ), + severity: Error, + }, + ] + "###); + } + #[test] fn test_check_unnecessary_braces_in_use_statement() { check_not_applicable( -- cgit v1.2.3 From 028f1e2e3add764956911a0f2663107cb945c0ec Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 17 Apr 2020 14:28:20 +0200 Subject: Don\t suggest import itself as a completion for import --- .../src/completion/complete_unqualified_path.rs | 40 +++++++++++++++++++++- crates/ra_ide/src/marks.rs | 1 + 2 files changed, 40 insertions(+), 1 deletion(-) (limited to 'crates/ra_ide') diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs index 2d8e0776c..ad5fdcc4e 100644 --- a/crates/ra_ide/src/completion/complete_unqualified_path.rs +++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs @@ -1,6 +1,10 @@ //! Completion of names from the current scope, e.g. locals and imported items. +use hir::ScopeDef; +use test_utils::tested_by; + use crate::completion::{CompletionContext, Completions}; +use ra_syntax::AstNode; pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { if !ctx.is_trivial_path { @@ -14,12 +18,23 @@ pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC return; } - ctx.scope().process_all_names(&mut |name, res| acc.add_resolution(ctx, name.to_string(), &res)); + ctx.scope().process_all_names(&mut |name, res| { + 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); + return; + } + } + } + acc.add_resolution(ctx, name.to_string(), &res) + }); } #[cfg(test)] mod tests { use insta::assert_debug_snapshot; + use test_utils::covers; use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; @@ -27,6 +42,29 @@ mod tests { do_completion(ra_fixture, CompletionKind::Reference) } + #[test] + fn self_fulfilling_completion() { + covers!(self_fulfilling_completion); + assert_debug_snapshot!( + do_reference_completion( + r#" + use foo<|> + use std::collections; + "#, + ), + @r###" + [ + CompletionItem { + label: "collections", + source_range: [21; 24), + delete: [21; 24), + insert: "collections", + }, + ] + "### + ); + } + #[test] fn bind_pat_and_path_ignore_at() { assert_debug_snapshot!( diff --git a/crates/ra_ide/src/marks.rs b/crates/ra_ide/src/marks.rs index 5e1f135c5..eee44e886 100644 --- a/crates/ra_ide/src/marks.rs +++ b/crates/ra_ide/src/marks.rs @@ -8,4 +8,5 @@ test_utils::marks!( test_resolve_parent_module_on_module_decl search_filters_by_range dont_insert_macro_call_parens_unncessary + self_fulfilling_completion ); -- cgit v1.2.3 From 2e2c03ee2d7ef20fd6e20151507d26a4407c835e Mon Sep 17 00:00:00 2001 From: Leander Tentrup Date: Fri, 17 Apr 2020 22:23:23 +0200 Subject: Fix incorrect order of syntax highlight ranges --- crates/ra_ide/src/syntax_highlighting.rs | 3 ++- crates/ra_ide/src/syntax_highlighting/tests.rs | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'crates/ra_ide') diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 83d161f45..7b15b82bd 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -174,7 +174,8 @@ pub(crate) fn highlight( } assert_eq!(res.len(), 1, "after DFS traversal, the stack should only contain a single element"); - let res = res.pop().unwrap(); + let mut res = res.pop().unwrap(); + res.sort_by_key(|range| range.range.start()); // Check that ranges are sorted and disjoint assert!(res .iter() diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs index 110887c2a..73611e23a 100644 --- a/crates/ra_ide/src/syntax_highlighting/tests.rs +++ b/crates/ra_ide/src/syntax_highlighting/tests.rs @@ -156,3 +156,15 @@ fn main() { fs::write(dst_file, &actual_html).unwrap(); assert_eq_text!(expected_html, actual_html); } + +#[test] +fn ranges_sorted() { + let (analysis, file_id) = single_file( + r#" +#[foo(bar = "bar")] +macro_rules! test {} +}"# + .trim(), + ); + let _ = analysis.highlight(file_id).unwrap(); +} -- cgit v1.2.3 From 8a51a74556c77d7f228867dd64cd6244bed82be6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sat, 18 Apr 2020 10:53:48 +0300 Subject: Omit more parameter hints in the presence of underscores --- crates/ra_ide/src/inlay_hints.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'crates/ra_ide') diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs index 45b9f7802..0774fa0a1 100644 --- a/crates/ra_ide/src/inlay_hints.rs +++ b/crates/ra_ide/src/inlay_hints.rs @@ -237,7 +237,8 @@ fn should_show_param_hint( ) -> bool { if param_name.is_empty() || is_argument_similar_to_param(argument, param_name) - || Some(param_name) == fn_signature.name.as_ref().map(String::as_str) + || Some(param_name.trim_start_matches('_')) + == fn_signature.name.as_ref().map(|s| s.trim_start_matches('_')) { return false; } @@ -255,6 +256,8 @@ fn should_show_param_hint( fn is_argument_similar_to_param(argument: &ast::Expr, param_name: &str) -> bool { let argument_string = remove_ref(argument.clone()).syntax().to_string(); + let param_name = param_name.trim_start_matches('_'); + let argument_string = argument_string.trim_start_matches('_'); argument_string.starts_with(¶m_name) || argument_string.ends_with(¶m_name) } @@ -1094,8 +1097,10 @@ struct Param {} fn different_order(param: &Param) {} fn different_order_mut(param: &mut Param) {} +fn has_underscore(_param: bool) {} fn twiddle(twiddle: bool) {} +fn doo(_doo: bool) {} fn main() { let container: TestVarContainer = TestVarContainer { test_var: 42 }; @@ -1112,11 +1117,15 @@ fn main() { test_processed.frob(false); twiddle(true); + doo(true); let param_begin: Param = Param {}; different_order(¶m_begin); different_order(&mut param_begin); + let param: bool = true; + has_underscore(param); + let a: f64 = 7.0; let b: f64 = 4.0; let _: f64 = a.div_euclid(b); -- cgit v1.2.3