aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_assists')
-rw-r--r--crates/ide_assists/Cargo.toml3
-rw-r--r--crates/ide_assists/src/handlers/add_turbo_fish.rs55
-rw-r--r--crates/ide_assists/src/handlers/apply_demorgan.rs10
-rw-r--r--crates/ide_assists/src/handlers/auto_import.rs51
-rw-r--r--crates/ide_assists/src/handlers/change_visibility.rs7
-rw-r--r--crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs248
-rw-r--r--crates/ide_assists/src/handlers/extract_function.rs21
-rw-r--r--crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs6
-rw-r--r--crates/ide_assists/src/handlers/extract_variable.rs15
-rw-r--r--crates/ide_assists/src/handlers/fill_match_arms.rs6
-rw-r--r--crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs11
-rw-r--r--crates/ide_assists/src/handlers/generate_default_from_new.rs17
-rw-r--r--crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs7
-rw-r--r--crates/ide_assists/src/handlers/generate_function.rs73
-rw-r--r--crates/ide_assists/src/handlers/infer_function_return_type.rs37
-rw-r--r--crates/ide_assists/src/handlers/inline_function.rs5
-rw-r--r--crates/ide_assists/src/handlers/inline_local_variable.rs19
-rw-r--r--crates/ide_assists/src/handlers/move_module_to_file.rs5
-rw-r--r--crates/ide_assists/src/handlers/pull_assignment_up.rs13
-rw-r--r--crates/ide_assists/src/handlers/qualify_path.rs57
-rw-r--r--crates/ide_assists/src/handlers/raw_string.rs7
-rw-r--r--crates/ide_assists/src/handlers/remove_unused_param.rs6
-rw-r--r--crates/ide_assists/src/handlers/reorder_fields.rs7
-rw-r--r--crates/ide_assists/src/handlers/reorder_impl.rs7
-rw-r--r--crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs33
-rw-r--r--crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs5
-rw-r--r--crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs7
-rw-r--r--crates/ide_assists/src/handlers/unmerge_use.rs5
-rw-r--r--crates/ide_assists/src/handlers/wrap_return_type_in_result.rs5
-rw-r--r--crates/ide_assists/src/lib.rs2
-rw-r--r--crates/ide_assists/src/tests.rs1
-rw-r--r--crates/ide_assists/src/tests/generated.rs30
32 files changed, 543 insertions, 238 deletions
diff --git a/crates/ide_assists/Cargo.toml b/crates/ide_assists/Cargo.toml
index a34bdd6c3..dd9aa27c6 100644
--- a/crates/ide_assists/Cargo.toml
+++ b/crates/ide_assists/Cargo.toml
@@ -10,6 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = "1.1"
13rustc-hash = "1.1.0" 14rustc-hash = "1.1.0"
14itertools = "0.10.0" 15itertools = "0.10.0"
15either = "1.6.1" 16either = "1.6.1"
@@ -20,7 +21,7 @@ text_edit = { path = "../text_edit", version = "0.0.0" }
20profile = { path = "../profile", version = "0.0.0" } 21profile = { path = "../profile", version = "0.0.0" }
21ide_db = { path = "../ide_db", version = "0.0.0" } 22ide_db = { path = "../ide_db", version = "0.0.0" }
22hir = { path = "../hir", version = "0.0.0" } 23hir = { path = "../hir", version = "0.0.0" }
23test_utils = { path = "../test_utils", version = "0.0.0" }
24 24
25[dev-dependencies] 25[dev-dependencies]
26test_utils = { path = "../test_utils" }
26expect-test = "1.1" 27expect-test = "1.1"
diff --git a/crates/ide_assists/src/handlers/add_turbo_fish.rs b/crates/ide_assists/src/handlers/add_turbo_fish.rs
index a08b55ebb..ee879c151 100644
--- a/crates/ide_assists/src/handlers/add_turbo_fish.rs
+++ b/crates/ide_assists/src/handlers/add_turbo_fish.rs
@@ -1,6 +1,5 @@
1use ide_db::defs::{Definition, NameRefClass}; 1use ide_db::defs::{Definition, NameRefClass};
2use syntax::{ast, AstNode, SyntaxKind, T}; 2use syntax::{ast, AstNode, SyntaxKind, T};
3use test_utils::mark;
4 3
5use crate::{ 4use crate::{
6 assist_context::{AssistContext, Assists}, 5 assist_context::{AssistContext, Assists},
@@ -30,13 +29,13 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
30 if arg_list.args().count() > 0 { 29 if arg_list.args().count() > 0 {
31 return None; 30 return None;
32 } 31 }
33 mark::hit!(add_turbo_fish_after_call); 32 cov_mark::hit!(add_turbo_fish_after_call);
34 mark::hit!(add_type_ascription_after_call); 33 cov_mark::hit!(add_type_ascription_after_call);
35 arg_list.l_paren_token()?.prev_token().filter(|it| it.kind() == SyntaxKind::IDENT) 34 arg_list.l_paren_token()?.prev_token().filter(|it| it.kind() == SyntaxKind::IDENT)
36 })?; 35 })?;
37 let next_token = ident.next_token()?; 36 let next_token = ident.next_token()?;
38 if next_token.kind() == T![::] { 37 if next_token.kind() == T![::] {
39 mark::hit!(add_turbo_fish_one_fish_is_enough); 38 cov_mark::hit!(add_turbo_fish_one_fish_is_enough);
40 return None; 39 return None;
41 } 40 }
42 let name_ref = ast::NameRef::cast(ident.parent())?; 41 let name_ref = ast::NameRef::cast(ident.parent())?;
@@ -50,24 +49,31 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
50 }; 49 };
51 let generics = hir::GenericDef::Function(fun).params(ctx.sema.db); 50 let generics = hir::GenericDef::Function(fun).params(ctx.sema.db);
52 if generics.is_empty() { 51 if generics.is_empty() {
53 mark::hit!(add_turbo_fish_non_generic); 52 cov_mark::hit!(add_turbo_fish_non_generic);
54 return None; 53 return None;
55 } 54 }
56 55
57 if let Some(let_stmt) = ctx.find_node_at_offset::<ast::LetStmt>() { 56 if let Some(let_stmt) = ctx.find_node_at_offset::<ast::LetStmt>() {
58 if let_stmt.colon_token().is_none() { 57 if let_stmt.colon_token().is_none() {
59 let type_pos = let_stmt.pat()?.syntax().last_token()?.text_range().end(); 58 let type_pos = let_stmt.pat()?.syntax().last_token()?.text_range().end();
59 let semi_pos = let_stmt.syntax().last_token()?.text_range().end();
60
60 acc.add( 61 acc.add(
61 AssistId("add_type_ascription", AssistKind::RefactorRewrite), 62 AssistId("add_type_ascription", AssistKind::RefactorRewrite),
62 "Add `: _` before assignment operator", 63 "Add `: _` before assignment operator",
63 ident.text_range(), 64 ident.text_range(),
64 |builder| match ctx.config.snippet_cap { 65 |builder| {
65 Some(cap) => builder.insert_snippet(cap, type_pos, ": ${0:_}"), 66 if let_stmt.semicolon_token().is_none() {
66 None => builder.insert(type_pos, ": _"), 67 builder.insert(semi_pos, ";");
68 }
69 match ctx.config.snippet_cap {
70 Some(cap) => builder.insert_snippet(cap, type_pos, ": ${0:_}"),
71 None => builder.insert(type_pos, ": _"),
72 }
67 }, 73 },
68 )? 74 )?
69 } else { 75 } else {
70 mark::hit!(add_type_ascription_already_typed); 76 cov_mark::hit!(add_type_ascription_already_typed);
71 } 77 }
72 } 78 }
73 79
@@ -87,7 +93,6 @@ mod tests {
87 use crate::tests::{check_assist, check_assist_by_label, check_assist_not_applicable}; 93 use crate::tests::{check_assist, check_assist_by_label, check_assist_not_applicable};
88 94
89 use super::*; 95 use super::*;
90 use test_utils::mark;
91 96
92 #[test] 97 #[test]
93 fn add_turbo_fish_function() { 98 fn add_turbo_fish_function() {
@@ -110,7 +115,7 @@ fn main() {
110 115
111 #[test] 116 #[test]
112 fn add_turbo_fish_after_call() { 117 fn add_turbo_fish_after_call() {
113 mark::check!(add_turbo_fish_after_call); 118 cov_mark::check!(add_turbo_fish_after_call);
114 check_assist( 119 check_assist(
115 add_turbo_fish, 120 add_turbo_fish,
116 r#" 121 r#"
@@ -155,7 +160,7 @@ fn main() {
155 160
156 #[test] 161 #[test]
157 fn add_turbo_fish_one_fish_is_enough() { 162 fn add_turbo_fish_one_fish_is_enough() {
158 mark::check!(add_turbo_fish_one_fish_is_enough); 163 cov_mark::check!(add_turbo_fish_one_fish_is_enough);
159 check_assist_not_applicable( 164 check_assist_not_applicable(
160 add_turbo_fish, 165 add_turbo_fish,
161 r#" 166 r#"
@@ -169,7 +174,7 @@ fn main() {
169 174
170 #[test] 175 #[test]
171 fn add_turbo_fish_non_generic() { 176 fn add_turbo_fish_non_generic() {
172 mark::check!(add_turbo_fish_non_generic); 177 cov_mark::check!(add_turbo_fish_non_generic);
173 check_assist_not_applicable( 178 check_assist_not_applicable(
174 add_turbo_fish, 179 add_turbo_fish,
175 r#" 180 r#"
@@ -203,7 +208,7 @@ fn main() {
203 208
204 #[test] 209 #[test]
205 fn add_type_ascription_after_call() { 210 fn add_type_ascription_after_call() {
206 mark::check!(add_type_ascription_after_call); 211 cov_mark::check!(add_type_ascription_after_call);
207 check_assist_by_label( 212 check_assist_by_label(
208 add_turbo_fish, 213 add_turbo_fish,
209 r#" 214 r#"
@@ -250,7 +255,7 @@ fn main() {
250 255
251 #[test] 256 #[test]
252 fn add_type_ascription_already_typed() { 257 fn add_type_ascription_already_typed() {
253 mark::check!(add_type_ascription_already_typed); 258 cov_mark::check!(add_type_ascription_already_typed);
254 check_assist( 259 check_assist(
255 add_turbo_fish, 260 add_turbo_fish,
256 r#" 261 r#"
@@ -267,4 +272,24 @@ fn main() {
267"#, 272"#,
268 ); 273 );
269 } 274 }
275
276 #[test]
277 fn add_type_ascription_append_semicolon() {
278 check_assist_by_label(
279 add_turbo_fish,
280 r#"
281fn make<T>() -> T {}
282fn main() {
283 let x = make$0()
284}
285"#,
286 r#"
287fn make<T>() -> T {}
288fn main() {
289 let x: ${0:_} = make();
290}
291"#,
292 "Add `: _` before assignment operator",
293 );
294 }
270} 295}
diff --git a/crates/ide_assists/src/handlers/apply_demorgan.rs b/crates/ide_assists/src/handlers/apply_demorgan.rs
index 128b1eb56..a1c339603 100644
--- a/crates/ide_assists/src/handlers/apply_demorgan.rs
+++ b/crates/ide_assists/src/handlers/apply_demorgan.rs
@@ -1,5 +1,4 @@
1use syntax::ast::{self, AstNode}; 1use syntax::ast::{self, AstNode};
2use test_utils::mark;
3 2
4use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKind, Assists}; 3use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKind, Assists};
5 4
@@ -64,10 +63,10 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext) -> Option<(
64 edit.replace(lhs_range, not_lhs.syntax().text()); 63 edit.replace(lhs_range, not_lhs.syntax().text());
65 edit.replace(rhs_range, not_rhs.syntax().text()); 64 edit.replace(rhs_range, not_rhs.syntax().text());
66 if let Some(neg_expr) = neg_expr { 65 if let Some(neg_expr) = neg_expr {
67 mark::hit!(demorgan_double_negation); 66 cov_mark::hit!(demorgan_double_negation);
68 edit.replace(neg_expr.op_token().unwrap().text_range(), ""); 67 edit.replace(neg_expr.op_token().unwrap().text_range(), "");
69 } else { 68 } else {
70 mark::hit!(demorgan_double_parens); 69 cov_mark::hit!(demorgan_double_parens);
71 edit.replace(paren_expr.l_paren_token().unwrap().text_range(), "!("); 70 edit.replace(paren_expr.l_paren_token().unwrap().text_range(), "!(");
72 } 71 }
73 } else { 72 } else {
@@ -90,7 +89,6 @@ fn opposite_logic_op(kind: ast::BinOp) -> Option<&'static str> {
90#[cfg(test)] 89#[cfg(test)]
91mod tests { 90mod tests {
92 use ide_db::helpers::FamousDefs; 91 use ide_db::helpers::FamousDefs;
93 use test_utils::mark;
94 92
95 use super::*; 93 use super::*;
96 94
@@ -188,13 +186,13 @@ fn f() {
188 186
189 #[test] 187 #[test]
190 fn demorgan_doesnt_double_negation() { 188 fn demorgan_doesnt_double_negation() {
191 mark::check!(demorgan_double_negation); 189 cov_mark::check!(demorgan_double_negation);
192 check_assist(apply_demorgan, "fn f() { !(x ||$0 x) }", "fn f() { (!x && !x) }") 190 check_assist(apply_demorgan, "fn f() { !(x ||$0 x) }", "fn f() { (!x && !x) }")
193 } 191 }
194 192
195 #[test] 193 #[test]
196 fn demorgan_doesnt_double_parens() { 194 fn demorgan_doesnt_double_parens() {
197 mark::check!(demorgan_double_parens); 195 cov_mark::check!(demorgan_double_parens);
198 check_assist(apply_demorgan, "fn f() { (x ||$0 x) }", "fn f() { !(!x && !x) }") 196 check_assist(apply_demorgan, "fn f() { (x ||$0 x) }", "fn f() { !(!x && !x) }")
199 } 197 }
200} 198}
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index dc38f90e9..7019039b9 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -90,17 +90,17 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
90 } 90 }
91 91
92 let range = ctx.sema.original_range(&syntax_under_caret).range; 92 let range = ctx.sema.original_range(&syntax_under_caret).range;
93 let group = import_group_message(import_assets.import_candidate()); 93 let group_label = group_label(import_assets.import_candidate());
94 let scope = ImportScope::find_insert_use_container(&syntax_under_caret, &ctx.sema)?; 94 let scope = ImportScope::find_insert_use_container(&syntax_under_caret, &ctx.sema)?;
95 for (import, _) in proposed_imports { 95 for import in proposed_imports {
96 acc.add_group( 96 acc.add_group(
97 &group, 97 &group_label,
98 AssistId("auto_import", AssistKind::QuickFix), 98 AssistId("auto_import", AssistKind::QuickFix),
99 format!("Import `{}`", &import), 99 format!("Import `{}`", import.import_path),
100 range, 100 range,
101 |builder| { 101 |builder| {
102 let rewriter = 102 let rewriter =
103 insert_use(&scope, mod_path_to_ast(&import), ctx.config.insert_use.merge); 103 insert_use(&scope, mod_path_to_ast(&import.import_path), ctx.config.insert_use);
104 builder.rewrite(rewriter); 104 builder.rewrite(rewriter);
105 }, 105 },
106 ); 106 );
@@ -122,14 +122,14 @@ pub(super) fn find_importable_node(ctx: &AssistContext) -> Option<(ImportAssets,
122 } 122 }
123} 123}
124 124
125fn import_group_message(import_candidate: &ImportCandidate) -> GroupLabel { 125fn group_label(import_candidate: &ImportCandidate) -> GroupLabel {
126 let name = match import_candidate { 126 let name = match import_candidate {
127 ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()), 127 ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()),
128 ImportCandidate::TraitAssocItem(candidate) => { 128 ImportCandidate::TraitAssocItem(candidate) => {
129 format!("Import a trait for item {}", candidate.name.text()) 129 format!("Import a trait for item {}", candidate.assoc_item_name.text())
130 } 130 }
131 ImportCandidate::TraitMethod(candidate) => { 131 ImportCandidate::TraitMethod(candidate) => {
132 format!("Import a trait for method {}", candidate.name.text()) 132 format!("Import a trait for method {}", candidate.assoc_item_name.text())
133 } 133 }
134 }; 134 };
135 GroupLabel(name) 135 GroupLabel(name)
@@ -222,41 +222,6 @@ mod tests {
222 } 222 }
223 223
224 #[test] 224 #[test]
225 fn auto_imports_are_merged() {
226 check_assist(
227 auto_import,
228 r"
229 use PubMod::PubStruct1;
230
231 struct Test {
232 test: Pub$0Struct2<u8>,
233 }
234
235 pub mod PubMod {
236 pub struct PubStruct1;
237 pub struct PubStruct2<T> {
238 _t: T,
239 }
240 }
241 ",
242 r"
243 use PubMod::{PubStruct1, PubStruct2};
244
245 struct Test {
246 test: PubStruct2<u8>,
247 }
248
249 pub mod PubMod {
250 pub struct PubStruct1;
251 pub struct PubStruct2<T> {
252 _t: T,
253 }
254 }
255 ",
256 );
257 }
258
259 #[test]
260 fn applicable_when_found_multiple_imports() { 225 fn applicable_when_found_multiple_imports() {
261 check_assist( 226 check_assist(
262 auto_import, 227 auto_import,
diff --git a/crates/ide_assists/src/handlers/change_visibility.rs b/crates/ide_assists/src/handlers/change_visibility.rs
index ac8c44124..ec99a5505 100644
--- a/crates/ide_assists/src/handlers/change_visibility.rs
+++ b/crates/ide_assists/src/handlers/change_visibility.rs
@@ -4,7 +4,6 @@ use syntax::{
4 SyntaxKind::{CONST, ENUM, FN, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, VISIBILITY}, 4 SyntaxKind::{CONST, ENUM, FN, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, VISIBILITY},
5 T, 5 T,
6}; 6};
7use test_utils::mark;
8 7
9use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists}; 8use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists};
10 9
@@ -56,7 +55,7 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
56 } else if let Some(field_name) = ctx.find_node_at_offset::<ast::Name>() { 55 } else if let Some(field_name) = ctx.find_node_at_offset::<ast::Name>() {
57 let field = field_name.syntax().ancestors().find_map(ast::RecordField::cast)?; 56 let field = field_name.syntax().ancestors().find_map(ast::RecordField::cast)?;
58 if field.name()? != field_name { 57 if field.name()? != field_name {
59 mark::hit!(change_visibility_field_false_positive); 58 cov_mark::hit!(change_visibility_field_false_positive);
60 return None; 59 return None;
61 } 60 }
62 if field.visibility().is_some() { 61 if field.visibility().is_some() {
@@ -110,8 +109,6 @@ fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
110 109
111#[cfg(test)] 110#[cfg(test)]
112mod tests { 111mod tests {
113 use test_utils::mark;
114
115 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; 112 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
116 113
117 use super::*; 114 use super::*;
@@ -139,7 +136,7 @@ mod tests {
139 136
140 #[test] 137 #[test]
141 fn change_visibility_field_false_positive() { 138 fn change_visibility_field_false_positive() {
142 mark::check!(change_visibility_field_false_positive); 139 cov_mark::check!(change_visibility_field_false_positive);
143 check_assist_not_applicable( 140 check_assist_not_applicable(
144 change_visibility, 141 change_visibility,
145 r"struct S { field: [(); { let $0x = ();}] }", 142 r"struct S { field: [(); { let $0x = ();}] }",
diff --git a/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs b/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs
new file mode 100644
index 000000000..4e75a7b14
--- /dev/null
+++ b/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs
@@ -0,0 +1,248 @@
1use ide_db::helpers::FamousDefs;
2use syntax::{
3 ast::{self, edit::AstNodeEdit, make, ArgListOwner},
4 AstNode,
5};
6
7use crate::{AssistContext, AssistId, AssistKind, Assists};
8
9// Assist: convert_iter_for_each_to_for
10//
11// Converts an Iterator::for_each function into a for loop.
12//
13// ```
14// # //- /lib.rs crate:core
15// # pub mod iter { pub mod traits { pub mod iterator { pub trait Iterator {} } } }
16// # pub struct SomeIter;
17// # impl self::iter::traits::iterator::Iterator for SomeIter {}
18// # //- /lib.rs crate:main deps:core
19// # use core::SomeIter;
20// fn main() {
21// let iter = SomeIter;
22// iter.for_each$0(|(x, y)| {
23// println!("x: {}, y: {}", x, y);
24// });
25// }
26// ```
27// ->
28// ```
29// # use core::SomeIter;
30// fn main() {
31// let iter = SomeIter;
32// for (x, y) in iter {
33// println!("x: {}, y: {}", x, y);
34// }
35// }
36// ```
37
38pub(crate) fn convert_iter_for_each_to_for(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
39 let method = ctx.find_node_at_offset::<ast::MethodCallExpr>()?;
40
41 let closure = match method.arg_list()?.args().next()? {
42 ast::Expr::ClosureExpr(expr) => expr,
43 _ => return None,
44 };
45
46 let (method, receiver) = validate_method_call_expr(ctx, method)?;
47
48 let param_list = closure.param_list()?;
49 let param = param_list.params().next()?.pat()?;
50 let body = closure.body()?;
51
52 let stmt = method.syntax().parent().and_then(ast::ExprStmt::cast);
53 let syntax = stmt.as_ref().map_or(method.syntax(), |stmt| stmt.syntax());
54
55 acc.add(
56 AssistId("convert_iter_for_each_to_for", AssistKind::RefactorRewrite),
57 "Replace this `Iterator::for_each` with a for loop",
58 syntax.text_range(),
59 |builder| {
60 let indent = stmt.as_ref().map_or(method.indent_level(), |stmt| stmt.indent_level());
61
62 let block = match body {
63 ast::Expr::BlockExpr(block) => block,
64 _ => make::block_expr(Vec::new(), Some(body)),
65 }
66 .reset_indent()
67 .indent(indent);
68
69 let expr_for_loop = make::expr_for_loop(param, receiver, block);
70 builder.replace(syntax.text_range(), expr_for_loop.syntax().text())
71 },
72 )
73}
74
75fn validate_method_call_expr(
76 ctx: &AssistContext,
77 expr: ast::MethodCallExpr,
78) -> Option<(ast::Expr, ast::Expr)> {
79 let name_ref = expr.name_ref()?;
80 if name_ref.syntax().text_range().intersect(ctx.frange.range).is_none()
81 || name_ref.text() != "for_each"
82 {
83 return None;
84 }
85
86 let sema = &ctx.sema;
87
88 let receiver = expr.receiver()?;
89 let expr = ast::Expr::MethodCallExpr(expr);
90
91 let it_type = sema.type_of_expr(&receiver)?;
92 let module = sema.scope(receiver.syntax()).module()?;
93 let krate = module.krate();
94
95 let iter_trait = FamousDefs(sema, Some(krate)).core_iter_Iterator()?;
96 it_type.impls_trait(sema.db, iter_trait, &[]).then(|| (expr, receiver))
97}
98
99#[cfg(test)]
100mod tests {
101 use crate::tests::{self, check_assist};
102
103 use super::*;
104
105 const EMPTY_ITER_FIXTURE: &'static str = r"
106//- /lib.rs deps:core crate:empty_iter
107pub struct EmptyIter;
108impl Iterator for EmptyIter {
109 type Item = usize;
110 fn next(&mut self) -> Option<Self::Item> { None }
111}
112pub struct Empty;
113impl Empty {
114 pub fn iter(&self) -> EmptyIter { EmptyIter }
115}
116";
117
118 fn check_assist_with_fixtures(before: &str, after: &str) {
119 let before = &format!(
120 "//- /main.rs crate:main deps:core,empty_iter{}{}{}",
121 before,
122 EMPTY_ITER_FIXTURE,
123 FamousDefs::FIXTURE,
124 );
125 check_assist(convert_iter_for_each_to_for, before, after);
126 }
127
128 fn check_assist_not_applicable(before: &str) {
129 let before = &format!(
130 "//- /main.rs crate:main deps:core,empty_iter{}{}{}",
131 before,
132 EMPTY_ITER_FIXTURE,
133 FamousDefs::FIXTURE,
134 );
135 tests::check_assist_not_applicable(convert_iter_for_each_to_for, before);
136 }
137
138 #[test]
139 fn test_for_each_in_method_stmt() {
140 check_assist_with_fixtures(
141 r#"
142use empty_iter::*;
143fn main() {
144 let x = Empty;
145 x.iter().$0for_each(|(x, y)| {
146 println!("x: {}, y: {}", x, y);
147 });
148}"#,
149 r#"
150use empty_iter::*;
151fn main() {
152 let x = Empty;
153 for (x, y) in x.iter() {
154 println!("x: {}, y: {}", x, y);
155 }
156}
157"#,
158 )
159 }
160
161 #[test]
162 fn test_for_each_in_method() {
163 check_assist_with_fixtures(
164 r#"
165use empty_iter::*;
166fn main() {
167 let x = Empty;
168 x.iter().$0for_each(|(x, y)| {
169 println!("x: {}, y: {}", x, y);
170 })
171}"#,
172 r#"
173use empty_iter::*;
174fn main() {
175 let x = Empty;
176 for (x, y) in x.iter() {
177 println!("x: {}, y: {}", x, y);
178 }
179}
180"#,
181 )
182 }
183
184 #[test]
185 fn test_for_each_in_iter_stmt() {
186 check_assist_with_fixtures(
187 r#"
188use empty_iter::*;
189fn main() {
190 let x = Empty.iter();
191 x.$0for_each(|(x, y)| {
192 println!("x: {}, y: {}", x, y);
193 });
194}"#,
195 r#"
196use empty_iter::*;
197fn main() {
198 let x = Empty.iter();
199 for (x, y) in x {
200 println!("x: {}, y: {}", x, y);
201 }
202}
203"#,
204 )
205 }
206
207 #[test]
208 fn test_for_each_without_braces_stmt() {
209 check_assist_with_fixtures(
210 r#"
211use empty_iter::*;
212fn main() {
213 let x = Empty;
214 x.iter().$0for_each(|(x, y)| println!("x: {}, y: {}", x, y));
215}"#,
216 r#"
217use empty_iter::*;
218fn main() {
219 let x = Empty;
220 for (x, y) in x.iter() {
221 println!("x: {}, y: {}", x, y)
222 }
223}
224"#,
225 )
226 }
227
228 #[test]
229 fn test_for_each_not_applicable() {
230 check_assist_not_applicable(
231 r#"
232fn main() {
233 ().$0for_each(|x| println!("{}", x));
234}"#,
235 )
236 }
237
238 #[test]
239 fn test_for_each_not_applicable_invalid_cursor_pos() {
240 check_assist_not_applicable(
241 r#"
242use empty_iter::*;
243fn main() {
244 Empty.iter().for_each(|(x, y)| $0println!("x: {}, y: {}", x, y));
245}"#,
246 )
247 }
248}
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs
index 8779d8bd1..dd4501709 100644
--- a/crates/ide_assists/src/handlers/extract_function.rs
+++ b/crates/ide_assists/src/handlers/extract_function.rs
@@ -20,7 +20,6 @@ use syntax::{
20 SyntaxKind::{self, BLOCK_EXPR, BREAK_EXPR, COMMENT, PATH_EXPR, RETURN_EXPR}, 20 SyntaxKind::{self, BLOCK_EXPR, BREAK_EXPR, COMMENT, PATH_EXPR, RETURN_EXPR},
21 SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T, 21 SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T,
22}; 22};
23use test_utils::mark;
24 23
25use crate::{ 24use crate::{
26 assist_context::{AssistContext, Assists}, 25 assist_context::{AssistContext, Assists},
@@ -59,7 +58,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option
59 58
60 let node = ctx.covering_element(); 59 let node = ctx.covering_element();
61 if node.kind() == COMMENT { 60 if node.kind() == COMMENT {
62 mark::hit!(extract_function_in_comment_is_not_applicable); 61 cov_mark::hit!(extract_function_in_comment_is_not_applicable);
63 return None; 62 return None;
64 } 63 }
65 64
@@ -197,14 +196,14 @@ fn external_control_flow(ctx: &AssistContext, body: &FunctionBody) -> Option<Con
197 if let Some(kind) = expr_err_kind(&expr, ctx) { 196 if let Some(kind) = expr_err_kind(&expr, ctx) {
198 Some(FlowKind::TryReturn { expr, kind }) 197 Some(FlowKind::TryReturn { expr, kind })
199 } else { 198 } else {
200 mark::hit!(external_control_flow_try_and_return_non_err); 199 cov_mark::hit!(external_control_flow_try_and_return_non_err);
201 return None; 200 return None;
202 } 201 }
203 } 202 }
204 None => return None, 203 None => return None,
205 }, 204 },
206 (Some(_), _, _, _) => { 205 (Some(_), _, _, _) => {
207 mark::hit!(external_control_flow_try_and_bc); 206 cov_mark::hit!(external_control_flow_try_and_bc);
208 return None; 207 return None;
209 } 208 }
210 (None, Some(r), None, None) => match r.expr() { 209 (None, Some(r), None, None) => match r.expr() {
@@ -212,11 +211,11 @@ fn external_control_flow(ctx: &AssistContext, body: &FunctionBody) -> Option<Con
212 None => Some(FlowKind::Return), 211 None => Some(FlowKind::Return),
213 }, 212 },
214 (None, Some(_), _, _) => { 213 (None, Some(_), _, _) => {
215 mark::hit!(external_control_flow_return_and_bc); 214 cov_mark::hit!(external_control_flow_return_and_bc);
216 return None; 215 return None;
217 } 216 }
218 (None, None, Some(_), Some(_)) => { 217 (None, None, Some(_), Some(_)) => {
219 mark::hit!(external_control_flow_break_and_continue); 218 cov_mark::hit!(external_control_flow_break_and_continue);
220 return None; 219 return None;
221 } 220 }
222 (None, None, Some(b), None) => match b.expr() { 221 (None, None, Some(b), None) => match b.expr() {
@@ -1837,7 +1836,7 @@ fn $0fun_name(n: u32) -> u32 {
1837 1836
1838 #[test] 1837 #[test]
1839 fn in_comment_is_not_applicable() { 1838 fn in_comment_is_not_applicable() {
1840 mark::check!(extract_function_in_comment_is_not_applicable); 1839 cov_mark::check!(extract_function_in_comment_is_not_applicable);
1841 check_assist_not_applicable(extract_function, r"fn main() { 1 + /* $0comment$0 */ 1; }"); 1840 check_assist_not_applicable(extract_function, r"fn main() { 1 + /* $0comment$0 */ 1; }");
1842 } 1841 }
1843 1842
@@ -2822,7 +2821,7 @@ fn $0fun_name(n: i32) -> Result<i32, i64> {
2822 2821
2823 #[test] 2822 #[test]
2824 fn break_and_continue() { 2823 fn break_and_continue() {
2825 mark::check!(external_control_flow_break_and_continue); 2824 cov_mark::check!(external_control_flow_break_and_continue);
2826 check_assist_not_applicable( 2825 check_assist_not_applicable(
2827 extract_function, 2826 extract_function,
2828 r##" 2827 r##"
@@ -2842,7 +2841,7 @@ fn foo() {
2842 2841
2843 #[test] 2842 #[test]
2844 fn return_and_break() { 2843 fn return_and_break() {
2845 mark::check!(external_control_flow_return_and_bc); 2844 cov_mark::check!(external_control_flow_return_and_bc);
2846 check_assist_not_applicable( 2845 check_assist_not_applicable(
2847 extract_function, 2846 extract_function,
2848 r##" 2847 r##"
@@ -3341,7 +3340,7 @@ fn $0fun_name() -> Result<i32, i64> {
3341 3340
3342 #[test] 3341 #[test]
3343 fn try_and_break() { 3342 fn try_and_break() {
3344 mark::check!(external_control_flow_try_and_bc); 3343 cov_mark::check!(external_control_flow_try_and_bc);
3345 check_assist_not_applicable( 3344 check_assist_not_applicable(
3346 extract_function, 3345 extract_function,
3347 r##" 3346 r##"
@@ -3363,7 +3362,7 @@ fn foo() -> Option<()> {
3363 3362
3364 #[test] 3363 #[test]
3365 fn try_and_return_ok() { 3364 fn try_and_return_ok() {
3366 mark::check!(external_control_flow_try_and_return_non_err); 3365 cov_mark::check!(external_control_flow_try_and_return_non_err);
3367 check_assist_not_applicable( 3366 check_assist_not_applicable(
3368 extract_function, 3367 extract_function,
3369 r##" 3368 r##"
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
index 5c7678b53..335e0ed95 100644
--- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -1,7 +1,7 @@
1use std::iter; 1use std::iter;
2 2
3use either::Either; 3use either::Either;
4use hir::{AsName, Module, ModuleDef, Name, Variant}; 4use hir::{Module, ModuleDef, Name, Variant};
5use ide_db::{ 5use ide_db::{
6 defs::Definition, 6 defs::Definition,
7 helpers::{ 7 helpers::{
@@ -133,7 +133,7 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Va
133 ), 133 ),
134 _ => false, 134 _ => false,
135 }) 135 })
136 .any(|(name, _)| name == variant_name.as_name()) 136 .any(|(name, _)| name.to_string() == variant_name.to_string())
137} 137}
138 138
139fn insert_import( 139fn insert_import(
@@ -154,7 +154,7 @@ fn insert_import(
154 mod_path.pop_segment(); 154 mod_path.pop_segment();
155 mod_path.push_segment(variant_hir_name.clone()); 155 mod_path.push_segment(variant_hir_name.clone());
156 let scope = ImportScope::find_insert_use_container(scope_node, &ctx.sema)?; 156 let scope = ImportScope::find_insert_use_container(scope_node, &ctx.sema)?;
157 *rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use.merge); 157 *rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use);
158 } 158 }
159 Some(()) 159 Some(())
160} 160}
diff --git a/crates/ide_assists/src/handlers/extract_variable.rs b/crates/ide_assists/src/handlers/extract_variable.rs
index 312ac7ac4..7a32483dc 100644
--- a/crates/ide_assists/src/handlers/extract_variable.rs
+++ b/crates/ide_assists/src/handlers/extract_variable.rs
@@ -6,7 +6,6 @@ use syntax::{
6 }, 6 },
7 SyntaxNode, 7 SyntaxNode,
8}; 8};
9use test_utils::mark;
10 9
11use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists}; 10use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists};
12 11
@@ -32,7 +31,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option
32 } 31 }
33 let node = ctx.covering_element(); 32 let node = ctx.covering_element();
34 if node.kind() == COMMENT { 33 if node.kind() == COMMENT {
35 mark::hit!(extract_var_in_comment_is_not_applicable); 34 cov_mark::hit!(extract_var_in_comment_is_not_applicable);
36 return None; 35 return None;
37 } 36 }
38 let to_extract = node.ancestors().find_map(valid_target_expr)?; 37 let to_extract = node.ancestors().find_map(valid_target_expr)?;
@@ -69,7 +68,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option
69 format_to!(buf, "{}", to_extract.syntax()); 68 format_to!(buf, "{}", to_extract.syntax());
70 69
71 if let Anchor::Replace(stmt) = anchor { 70 if let Anchor::Replace(stmt) = anchor {
72 mark::hit!(test_extract_var_expr_stmt); 71 cov_mark::hit!(test_extract_var_expr_stmt);
73 if stmt.semicolon_token().is_none() { 72 if stmt.semicolon_token().is_none() {
74 buf.push_str(";"); 73 buf.push_str(";");
75 } 74 }
@@ -142,7 +141,7 @@ impl Anchor {
142 node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.tail_expr()) 141 node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.tail_expr())
143 { 142 {
144 if expr.syntax() == &node { 143 if expr.syntax() == &node {
145 mark::hit!(test_extract_var_last_expr); 144 cov_mark::hit!(test_extract_var_last_expr);
146 return Some(Anchor::Before(node)); 145 return Some(Anchor::Before(node));
147 } 146 }
148 } 147 }
@@ -175,8 +174,6 @@ impl Anchor {
175 174
176#[cfg(test)] 175#[cfg(test)]
177mod tests { 176mod tests {
178 use test_utils::mark;
179
180 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; 177 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
181 178
182 use super::*; 179 use super::*;
@@ -199,13 +196,13 @@ fn foo() {
199 196
200 #[test] 197 #[test]
201 fn extract_var_in_comment_is_not_applicable() { 198 fn extract_var_in_comment_is_not_applicable() {
202 mark::check!(extract_var_in_comment_is_not_applicable); 199 cov_mark::check!(extract_var_in_comment_is_not_applicable);
203 check_assist_not_applicable(extract_variable, "fn main() { 1 + /* $0comment$0 */ 1; }"); 200 check_assist_not_applicable(extract_variable, "fn main() { 1 + /* $0comment$0 */ 1; }");
204 } 201 }
205 202
206 #[test] 203 #[test]
207 fn test_extract_var_expr_stmt() { 204 fn test_extract_var_expr_stmt() {
208 mark::check!(test_extract_var_expr_stmt); 205 cov_mark::check!(test_extract_var_expr_stmt);
209 check_assist( 206 check_assist(
210 extract_variable, 207 extract_variable,
211 r#" 208 r#"
@@ -250,7 +247,7 @@ fn foo() {
250 247
251 #[test] 248 #[test]
252 fn test_extract_var_last_expr() { 249 fn test_extract_var_last_expr() {
253 mark::check!(test_extract_var_last_expr); 250 cov_mark::check!(test_extract_var_last_expr);
254 check_assist( 251 check_assist(
255 extract_variable, 252 extract_variable,
256 r#" 253 r#"
diff --git a/crates/ide_assists/src/handlers/fill_match_arms.rs b/crates/ide_assists/src/handlers/fill_match_arms.rs
index 7086e47d2..878b3a3fa 100644
--- a/crates/ide_assists/src/handlers/fill_match_arms.rs
+++ b/crates/ide_assists/src/handlers/fill_match_arms.rs
@@ -5,7 +5,6 @@ use ide_db::helpers::{mod_path_to_ast, FamousDefs};
5use ide_db::RootDatabase; 5use ide_db::RootDatabase;
6use itertools::Itertools; 6use itertools::Itertools;
7use syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat}; 7use syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat};
8use test_utils::mark;
9 8
10use crate::{ 9use crate::{
11 utils::{does_pat_match_variant, render_snippet, Cursor}, 10 utils::{does_pat_match_variant, render_snippet, Cursor},
@@ -62,7 +61,7 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
62 .collect::<Vec<_>>(); 61 .collect::<Vec<_>>();
63 if Some(enum_def) == FamousDefs(&ctx.sema, Some(module.krate())).core_option_Option() { 62 if Some(enum_def) == FamousDefs(&ctx.sema, Some(module.krate())).core_option_Option() {
64 // Match `Some` variant first. 63 // Match `Some` variant first.
65 mark::hit!(option_order); 64 cov_mark::hit!(option_order);
66 variants.reverse() 65 variants.reverse()
67 } 66 }
68 variants 67 variants
@@ -195,7 +194,6 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::Variant) -> Optio
195#[cfg(test)] 194#[cfg(test)]
196mod tests { 195mod tests {
197 use ide_db::helpers::FamousDefs; 196 use ide_db::helpers::FamousDefs;
198 use test_utils::mark;
199 197
200 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; 198 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
201 199
@@ -730,7 +728,7 @@ fn main() {
730 728
731 #[test] 729 #[test]
732 fn option_order() { 730 fn option_order() {
733 mark::check!(option_order); 731 cov_mark::check!(option_order);
734 let before = r#" 732 let before = r#"
735fn foo(opt: Option<i32>) { 733fn foo(opt: Option<i32>) {
736 match opt$0 { 734 match opt$0 {
diff --git a/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs b/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs
index 6a2ab9596..588ee1350 100644
--- a/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs
@@ -1,7 +1,6 @@
1use ide_db::helpers::FamousDefs; 1use ide_db::helpers::FamousDefs;
2use ide_db::RootDatabase; 2use ide_db::RootDatabase;
3use syntax::ast::{self, AstNode, NameOwner}; 3use syntax::ast::{self, AstNode, NameOwner};
4use test_utils::mark;
5 4
6use crate::{AssistContext, AssistId, AssistKind, Assists}; 5use crate::{AssistContext, AssistId, AssistKind, Assists};
7 6
@@ -38,12 +37,12 @@ pub(crate) fn generate_default_from_enum_variant(
38 let variant_name = variant.name()?; 37 let variant_name = variant.name()?;
39 let enum_name = variant.parent_enum().name()?; 38 let enum_name = variant.parent_enum().name()?;
40 if !matches!(variant.kind(), ast::StructKind::Unit) { 39 if !matches!(variant.kind(), ast::StructKind::Unit) {
41 mark::hit!(test_gen_default_on_non_unit_variant_not_implemented); 40 cov_mark::hit!(test_gen_default_on_non_unit_variant_not_implemented);
42 return None; 41 return None;
43 } 42 }
44 43
45 if existing_default_impl(&ctx.sema, &variant).is_some() { 44 if existing_default_impl(&ctx.sema, &variant).is_some() {
46 mark::hit!(test_gen_default_impl_already_exists); 45 cov_mark::hit!(test_gen_default_impl_already_exists);
47 return None; 46 return None;
48 } 47 }
49 48
@@ -89,8 +88,6 @@ fn existing_default_impl(
89 88
90#[cfg(test)] 89#[cfg(test)]
91mod tests { 90mod tests {
92 use test_utils::mark;
93
94 use crate::tests::{check_assist, check_assist_not_applicable}; 91 use crate::tests::{check_assist, check_assist_not_applicable};
95 92
96 use super::*; 93 use super::*;
@@ -127,7 +124,7 @@ impl Default for Variant {
127 124
128 #[test] 125 #[test]
129 fn test_generate_default_already_implemented() { 126 fn test_generate_default_already_implemented() {
130 mark::check!(test_gen_default_impl_already_exists); 127 cov_mark::check!(test_gen_default_impl_already_exists);
131 check_not_applicable( 128 check_not_applicable(
132 r#" 129 r#"
133enum Variant { 130enum Variant {
@@ -146,7 +143,7 @@ impl Default for Variant {
146 143
147 #[test] 144 #[test]
148 fn test_add_from_impl_no_element() { 145 fn test_add_from_impl_no_element() {
149 mark::check!(test_gen_default_on_non_unit_variant_not_implemented); 146 cov_mark::check!(test_gen_default_on_non_unit_variant_not_implemented);
150 check_not_applicable( 147 check_not_applicable(
151 r#" 148 r#"
152enum Variant { 149enum Variant {
diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs
index fa1254579..81c54ba3e 100644
--- a/crates/ide_assists/src/handlers/generate_default_from_new.rs
+++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs
@@ -7,7 +7,6 @@ use syntax::{
7 ast::{self, Impl, NameOwner}, 7 ast::{self, Impl, NameOwner},
8 AstNode, 8 AstNode,
9}; 9};
10use test_utils::mark;
11 10
12// Assist: generate_default_from_new 11// Assist: generate_default_from_new
13// 12//
@@ -43,19 +42,19 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext)
43 let fn_name = fn_node.name()?; 42 let fn_name = fn_node.name()?;
44 43
45 if fn_name.text() != "new" { 44 if fn_name.text() != "new" {
46 mark::hit!(other_function_than_new); 45 cov_mark::hit!(other_function_than_new);
47 return None; 46 return None;
48 } 47 }
49 48
50 if fn_node.param_list()?.params().next().is_some() { 49 if fn_node.param_list()?.params().next().is_some() {
51 mark::hit!(new_function_with_parameters); 50 cov_mark::hit!(new_function_with_parameters);
52 return None; 51 return None;
53 } 52 }
54 53
55 let impl_ = fn_node.syntax().ancestors().into_iter().find_map(ast::Impl::cast)?; 54 let impl_ = fn_node.syntax().ancestors().into_iter().find_map(ast::Impl::cast)?;
56 if is_default_implemented(ctx, &impl_) { 55 if is_default_implemented(ctx, &impl_) {
57 mark::hit!(default_block_is_already_present); 56 cov_mark::hit!(default_block_is_already_present);
58 mark::hit!(struct_in_module_with_default); 57 cov_mark::hit!(struct_in_module_with_default);
59 return None; 58 return None;
60 } 59 }
61 60
@@ -178,7 +177,7 @@ impl Default for Test {
178 177
179 #[test] 178 #[test]
180 fn new_function_with_parameters() { 179 fn new_function_with_parameters() {
181 mark::check!(new_function_with_parameters); 180 cov_mark::check!(new_function_with_parameters);
182 check_not_applicable( 181 check_not_applicable(
183 r#" 182 r#"
184struct Example { _inner: () } 183struct Example { _inner: () }
@@ -194,7 +193,7 @@ impl Example {
194 193
195 #[test] 194 #[test]
196 fn other_function_than_new() { 195 fn other_function_than_new() {
197 mark::check!(other_function_than_new); 196 cov_mark::check!(other_function_than_new);
198 check_not_applicable( 197 check_not_applicable(
199 r#" 198 r#"
200struct Example { _inner: () } 199struct Example { _inner: () }
@@ -211,7 +210,7 @@ impl Example {
211 210
212 #[test] 211 #[test]
213 fn default_block_is_already_present() { 212 fn default_block_is_already_present() {
214 mark::check!(default_block_is_already_present); 213 cov_mark::check!(default_block_is_already_present);
215 check_not_applicable( 214 check_not_applicable(
216 r#" 215 r#"
217struct Example { _inner: () } 216struct Example { _inner: () }
@@ -340,7 +339,7 @@ impl Default for Example {
340 339
341 #[test] 340 #[test]
342 fn struct_in_module_with_default() { 341 fn struct_in_module_with_default() {
343 mark::check!(struct_in_module_with_default); 342 cov_mark::check!(struct_in_module_with_default);
344 check_not_applicable( 343 check_not_applicable(
345 r#" 344 r#"
346mod test { 345mod test {
diff --git a/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs b/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs
index d9388a737..c13c6eebe 100644
--- a/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs
+++ b/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs
@@ -1,7 +1,6 @@
1use ide_db::helpers::FamousDefs; 1use ide_db::helpers::FamousDefs;
2use ide_db::RootDatabase; 2use ide_db::RootDatabase;
3use syntax::ast::{self, AstNode, NameOwner}; 3use syntax::ast::{self, AstNode, NameOwner};
4use test_utils::mark;
5 4
6use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists}; 5use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists};
7 6
@@ -44,7 +43,7 @@ pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext
44 }; 43 };
45 44
46 if existing_from_impl(&ctx.sema, &variant).is_some() { 45 if existing_from_impl(&ctx.sema, &variant).is_some() {
47 mark::hit!(test_add_from_impl_already_exists); 46 cov_mark::hit!(test_add_from_impl_already_exists);
48 return None; 47 return None;
49 } 48 }
50 49
@@ -103,8 +102,6 @@ fn existing_from_impl(
103 102
104#[cfg(test)] 103#[cfg(test)]
105mod tests { 104mod tests {
106 use test_utils::mark;
107
108 use crate::tests::{check_assist, check_assist_not_applicable}; 105 use crate::tests::{check_assist, check_assist_not_applicable};
109 106
110 use super::*; 107 use super::*;
@@ -172,7 +169,7 @@ impl From<u32> for A {
172 169
173 #[test] 170 #[test]
174 fn test_add_from_impl_already_exists() { 171 fn test_add_from_impl_already_exists() {
175 mark::check!(test_add_from_impl_already_exists); 172 cov_mark::check!(test_add_from_impl_already_exists);
176 check_not_applicable( 173 check_not_applicable(
177 r#" 174 r#"
178enum A { $0One(u32), } 175enum A { $0One(u32), }
diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs
index 3870b7e75..6f95b1a07 100644
--- a/crates/ide_assists/src/handlers/generate_function.rs
+++ b/crates/ide_assists/src/handlers/generate_function.rs
@@ -83,17 +83,18 @@ struct FunctionTemplate {
83 leading_ws: String, 83 leading_ws: String,
84 fn_def: ast::Fn, 84 fn_def: ast::Fn,
85 ret_type: ast::RetType, 85 ret_type: ast::RetType,
86 should_render_snippet: bool,
86 trailing_ws: String, 87 trailing_ws: String,
87 file: FileId, 88 file: FileId,
88} 89}
89 90
90impl FunctionTemplate { 91impl FunctionTemplate {
91 fn to_string(&self, cap: Option<SnippetCap>) -> String { 92 fn to_string(&self, cap: Option<SnippetCap>) -> String {
92 let f = match cap { 93 let f = match (cap, self.should_render_snippet) {
93 Some(cap) => { 94 (Some(cap), true) => {
94 render_snippet(cap, self.fn_def.syntax(), Cursor::Replace(self.ret_type.syntax())) 95 render_snippet(cap, self.fn_def.syntax(), Cursor::Replace(self.ret_type.syntax()))
95 } 96 }
96 None => self.fn_def.to_string(), 97 _ => self.fn_def.to_string(),
97 }; 98 };
98 format!("{}{}{}", self.leading_ws, f, self.trailing_ws) 99 format!("{}{}{}", self.leading_ws, f, self.trailing_ws)
99 } 100 }
@@ -104,6 +105,8 @@ struct FunctionBuilder {
104 fn_name: ast::Name, 105 fn_name: ast::Name,
105 type_params: Option<ast::GenericParamList>, 106 type_params: Option<ast::GenericParamList>,
106 params: ast::ParamList, 107 params: ast::ParamList,
108 ret_type: ast::RetType,
109 should_render_snippet: bool,
107 file: FileId, 110 file: FileId,
108 needs_pub: bool, 111 needs_pub: bool,
109} 112}
@@ -132,7 +135,43 @@ impl FunctionBuilder {
132 let fn_name = fn_name(&path)?; 135 let fn_name = fn_name(&path)?;
133 let (type_params, params) = fn_args(ctx, target_module, &call)?; 136 let (type_params, params) = fn_args(ctx, target_module, &call)?;
134 137
135 Some(Self { target, fn_name, type_params, params, file, needs_pub }) 138 // should_render_snippet intends to express a rough level of confidence about
139 // the correctness of the return type.
140 //
141 // If we are able to infer some return type, and that return type is not unit, we
142 // don't want to render the snippet. The assumption here is in this situation the
143 // return type is just as likely to be correct as any other part of the generated
144 // function.
145 //
146 // In the case where the return type is inferred as unit it is likely that the
147 // user does in fact intend for this generated function to return some non unit
148 // type, but that the current state of their code doesn't allow that return type
149 // to be accurately inferred.
150 let (ret_ty, should_render_snippet) = {
151 match ctx.sema.type_of_expr(&ast::Expr::CallExpr(call.clone())) {
152 Some(ty) if ty.is_unknown() || ty.is_unit() => (make::ty_unit(), true),
153 Some(ty) => {
154 let rendered = ty.display_source_code(ctx.db(), target_module.into());
155 match rendered {
156 Ok(rendered) => (make::ty(&rendered), false),
157 Err(_) => (make::ty_unit(), true),
158 }
159 }
160 None => (make::ty_unit(), true),
161 }
162 };
163 let ret_type = make::ret_type(ret_ty);
164
165 Some(Self {
166 target,
167 fn_name,
168 type_params,
169 params,
170 ret_type,
171 should_render_snippet,
172 file,
173 needs_pub,
174 })
136 } 175 }
137 176
138 fn render(self) -> FunctionTemplate { 177 fn render(self) -> FunctionTemplate {
@@ -145,7 +184,7 @@ impl FunctionBuilder {
145 self.type_params, 184 self.type_params,
146 self.params, 185 self.params,
147 fn_body, 186 fn_body,
148 Some(make::ret_type(make::ty_unit())), 187 Some(self.ret_type),
149 ); 188 );
150 let leading_ws; 189 let leading_ws;
151 let trailing_ws; 190 let trailing_ws;
@@ -171,6 +210,7 @@ impl FunctionBuilder {
171 insert_offset, 210 insert_offset,
172 leading_ws, 211 leading_ws,
173 ret_type: fn_def.ret_type().unwrap(), 212 ret_type: fn_def.ret_type().unwrap(),
213 should_render_snippet: self.should_render_snippet,
174 fn_def, 214 fn_def,
175 trailing_ws, 215 trailing_ws,
176 file: self.file, 216 file: self.file,
@@ -546,7 +586,7 @@ impl Baz {
546 } 586 }
547} 587}
548 588
549fn bar(baz: Baz) ${0:-> ()} { 589fn bar(baz: Baz) -> Baz {
550 todo!() 590 todo!()
551} 591}
552", 592",
@@ -1060,6 +1100,27 @@ pub(crate) fn bar() ${0:-> ()} {
1060 } 1100 }
1061 1101
1062 #[test] 1102 #[test]
1103 fn add_function_with_return_type() {
1104 check_assist(
1105 generate_function,
1106 r"
1107fn main() {
1108 let x: u32 = foo$0();
1109}
1110",
1111 r"
1112fn main() {
1113 let x: u32 = foo();
1114}
1115
1116fn foo() -> u32 {
1117 todo!()
1118}
1119",
1120 )
1121 }
1122
1123 #[test]
1063 fn add_function_not_applicable_if_function_already_exists() { 1124 fn add_function_not_applicable_if_function_already_exists() {
1064 check_assist_not_applicable( 1125 check_assist_not_applicable(
1065 generate_function, 1126 generate_function,
diff --git a/crates/ide_assists/src/handlers/infer_function_return_type.rs b/crates/ide_assists/src/handlers/infer_function_return_type.rs
index 5279af1f3..66113751c 100644
--- a/crates/ide_assists/src/handlers/infer_function_return_type.rs
+++ b/crates/ide_assists/src/handlers/infer_function_return_type.rs
@@ -1,6 +1,5 @@
1use hir::HirDisplay; 1use hir::HirDisplay;
2use syntax::{ast, AstNode, TextRange, TextSize}; 2use syntax::{ast, AstNode, TextRange, TextSize};
3use test_utils::mark;
4 3
5use crate::{AssistContext, AssistId, AssistKind, Assists}; 4use crate::{AssistContext, AssistId, AssistKind, Assists};
6 5
@@ -42,7 +41,7 @@ pub(crate) fn infer_function_return_type(acc: &mut Assists, ctx: &AssistContext)
42 } 41 }
43 } 42 }
44 if let FnType::Closure { wrap_expr: true } = fn_type { 43 if let FnType::Closure { wrap_expr: true } = fn_type {
45 mark::hit!(wrap_closure_non_block_expr); 44 cov_mark::hit!(wrap_closure_non_block_expr);
46 // `|x| x` becomes `|x| -> T x` which is invalid, so wrap it in a block 45 // `|x| x` becomes `|x| -> T x` which is invalid, so wrap it in a block
47 builder.replace(tail_expr.syntax().text_range(), &format!("{{{}}}", tail_expr)); 46 builder.replace(tail_expr.syntax().text_range(), &format!("{{{}}}", tail_expr));
48 } 47 }
@@ -61,13 +60,13 @@ fn ret_ty_to_action(ret_ty: Option<ast::RetType>, insert_pos: TextSize) -> Optio
61 match ret_ty { 60 match ret_ty {
62 Some(ret_ty) => match ret_ty.ty() { 61 Some(ret_ty) => match ret_ty.ty() {
63 Some(ast::Type::InferType(_)) | None => { 62 Some(ast::Type::InferType(_)) | None => {
64 mark::hit!(existing_infer_ret_type); 63 cov_mark::hit!(existing_infer_ret_type);
65 mark::hit!(existing_infer_ret_type_closure); 64 cov_mark::hit!(existing_infer_ret_type_closure);
66 Some(InsertOrReplace::Replace(ret_ty.syntax().text_range())) 65 Some(InsertOrReplace::Replace(ret_ty.syntax().text_range()))
67 } 66 }
68 _ => { 67 _ => {
69 mark::hit!(existing_ret_type); 68 cov_mark::hit!(existing_ret_type);
70 mark::hit!(existing_ret_type_closure); 69 cov_mark::hit!(existing_ret_type_closure);
71 None 70 None
72 } 71 }
73 }, 72 },
@@ -109,11 +108,11 @@ fn extract_tail(ctx: &AssistContext) -> Option<(FnType, ast::Expr, InsertOrRepla
109 }; 108 };
110 let frange = ctx.frange.range; 109 let frange = ctx.frange.range;
111 if return_type_range.contains_range(frange) { 110 if return_type_range.contains_range(frange) {
112 mark::hit!(cursor_in_ret_position); 111 cov_mark::hit!(cursor_in_ret_position);
113 mark::hit!(cursor_in_ret_position_closure); 112 cov_mark::hit!(cursor_in_ret_position_closure);
114 } else if tail_expr.syntax().text_range().contains_range(frange) { 113 } else if tail_expr.syntax().text_range().contains_range(frange) {
115 mark::hit!(cursor_on_tail); 114 cov_mark::hit!(cursor_on_tail);
116 mark::hit!(cursor_on_tail_closure); 115 cov_mark::hit!(cursor_on_tail_closure);
117 } else { 116 } else {
118 return None; 117 return None;
119 } 118 }
@@ -128,7 +127,7 @@ mod tests {
128 127
129 #[test] 128 #[test]
130 fn infer_return_type_specified_inferred() { 129 fn infer_return_type_specified_inferred() {
131 mark::check!(existing_infer_ret_type); 130 cov_mark::check!(existing_infer_ret_type);
132 check_assist( 131 check_assist(
133 infer_function_return_type, 132 infer_function_return_type,
134 r#"fn foo() -> $0_ { 133 r#"fn foo() -> $0_ {
@@ -142,7 +141,7 @@ mod tests {
142 141
143 #[test] 142 #[test]
144 fn infer_return_type_specified_inferred_closure() { 143 fn infer_return_type_specified_inferred_closure() {
145 mark::check!(existing_infer_ret_type_closure); 144 cov_mark::check!(existing_infer_ret_type_closure);
146 check_assist( 145 check_assist(
147 infer_function_return_type, 146 infer_function_return_type,
148 r#"fn foo() { 147 r#"fn foo() {
@@ -156,7 +155,7 @@ mod tests {
156 155
157 #[test] 156 #[test]
158 fn infer_return_type_cursor_at_return_type_pos() { 157 fn infer_return_type_cursor_at_return_type_pos() {
159 mark::check!(cursor_in_ret_position); 158 cov_mark::check!(cursor_in_ret_position);
160 check_assist( 159 check_assist(
161 infer_function_return_type, 160 infer_function_return_type,
162 r#"fn foo() $0{ 161 r#"fn foo() $0{
@@ -170,7 +169,7 @@ mod tests {
170 169
171 #[test] 170 #[test]
172 fn infer_return_type_cursor_at_return_type_pos_closure() { 171 fn infer_return_type_cursor_at_return_type_pos_closure() {
173 mark::check!(cursor_in_ret_position_closure); 172 cov_mark::check!(cursor_in_ret_position_closure);
174 check_assist( 173 check_assist(
175 infer_function_return_type, 174 infer_function_return_type,
176 r#"fn foo() { 175 r#"fn foo() {
@@ -184,7 +183,7 @@ mod tests {
184 183
185 #[test] 184 #[test]
186 fn infer_return_type() { 185 fn infer_return_type() {
187 mark::check!(cursor_on_tail); 186 cov_mark::check!(cursor_on_tail);
188 check_assist( 187 check_assist(
189 infer_function_return_type, 188 infer_function_return_type,
190 r#"fn foo() { 189 r#"fn foo() {
@@ -219,7 +218,7 @@ mod tests {
219 218
220 #[test] 219 #[test]
221 fn not_applicable_ret_type_specified() { 220 fn not_applicable_ret_type_specified() {
222 mark::check!(existing_ret_type); 221 cov_mark::check!(existing_ret_type);
223 check_assist_not_applicable( 222 check_assist_not_applicable(
224 infer_function_return_type, 223 infer_function_return_type,
225 r#"fn foo() -> i32 { 224 r#"fn foo() -> i32 {
@@ -251,7 +250,7 @@ mod tests {
251 250
252 #[test] 251 #[test]
253 fn infer_return_type_closure_block() { 252 fn infer_return_type_closure_block() {
254 mark::check!(cursor_on_tail_closure); 253 cov_mark::check!(cursor_on_tail_closure);
255 check_assist( 254 check_assist(
256 infer_function_return_type, 255 infer_function_return_type,
257 r#"fn foo() { 256 r#"fn foo() {
@@ -282,7 +281,7 @@ mod tests {
282 281
283 #[test] 282 #[test]
284 fn infer_return_type_closure_wrap() { 283 fn infer_return_type_closure_wrap() {
285 mark::check!(wrap_closure_non_block_expr); 284 cov_mark::check!(wrap_closure_non_block_expr);
286 check_assist( 285 check_assist(
287 infer_function_return_type, 286 infer_function_return_type,
288 r#"fn foo() { 287 r#"fn foo() {
@@ -321,7 +320,7 @@ mod tests {
321 320
322 #[test] 321 #[test]
323 fn not_applicable_ret_type_specified_closure() { 322 fn not_applicable_ret_type_specified_closure() {
324 mark::check!(existing_ret_type_closure); 323 cov_mark::check!(existing_ret_type_closure);
325 check_assist_not_applicable( 324 check_assist_not_applicable(
326 infer_function_return_type, 325 infer_function_return_type,
327 r#"fn foo() { 326 r#"fn foo() {
diff --git a/crates/ide_assists/src/handlers/inline_function.rs b/crates/ide_assists/src/handlers/inline_function.rs
index 6ec99b09b..8e56029cb 100644
--- a/crates/ide_assists/src/handlers/inline_function.rs
+++ b/crates/ide_assists/src/handlers/inline_function.rs
@@ -4,7 +4,6 @@ use syntax::{
4 ast::{self, edit::AstNodeEdit, ArgListOwner}, 4 ast::{self, edit::AstNodeEdit, ArgListOwner},
5 AstNode, 5 AstNode,
6}; 6};
7use test_utils::mark;
8 7
9use crate::{ 8use crate::{
10 assist_context::{AssistContext, Assists}, 9 assist_context::{AssistContext, Assists},
@@ -49,7 +48,7 @@ pub(crate) fn inline_function(acc: &mut Assists, ctx: &AssistContext) -> Option<
49 if arguments.len() != parameters.len() { 48 if arguments.len() != parameters.len() {
50 // Can't inline the function because they've passed the wrong number of 49 // Can't inline the function because they've passed the wrong number of
51 // arguments to this function 50 // arguments to this function
52 mark::hit!(inline_function_incorrect_number_of_arguments); 51 cov_mark::hit!(inline_function_incorrect_number_of_arguments);
53 return None; 52 return None;
54 } 53 }
55 54
@@ -155,7 +154,7 @@ fn main() { Foo.bar$0(); }
155 154
156 #[test] 155 #[test]
157 fn not_applicable_when_incorrect_number_of_parameters_are_provided() { 156 fn not_applicable_when_incorrect_number_of_parameters_are_provided() {
158 mark::check!(inline_function_incorrect_number_of_arguments); 157 cov_mark::check!(inline_function_incorrect_number_of_arguments);
159 check_assist_not_applicable( 158 check_assist_not_applicable(
160 inline_function, 159 inline_function,
161 r#" 160 r#"
diff --git a/crates/ide_assists/src/handlers/inline_local_variable.rs b/crates/ide_assists/src/handlers/inline_local_variable.rs
index da5522670..ea1466dc8 100644
--- a/crates/ide_assists/src/handlers/inline_local_variable.rs
+++ b/crates/ide_assists/src/handlers/inline_local_variable.rs
@@ -4,7 +4,6 @@ use syntax::{
4 ast::{self, AstNode, AstToken}, 4 ast::{self, AstNode, AstToken},
5 TextRange, 5 TextRange,
6}; 6};
7use test_utils::mark;
8 7
9use crate::{ 8use crate::{
10 assist_context::{AssistContext, Assists}, 9 assist_context::{AssistContext, Assists},
@@ -34,11 +33,11 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
34 _ => return None, 33 _ => return None,
35 }; 34 };
36 if bind_pat.mut_token().is_some() { 35 if bind_pat.mut_token().is_some() {
37 mark::hit!(test_not_inline_mut_variable); 36 cov_mark::hit!(test_not_inline_mut_variable);
38 return None; 37 return None;
39 } 38 }
40 if !bind_pat.syntax().text_range().contains_inclusive(ctx.offset()) { 39 if !bind_pat.syntax().text_range().contains_inclusive(ctx.offset()) {
41 mark::hit!(not_applicable_outside_of_bind_pat); 40 cov_mark::hit!(not_applicable_outside_of_bind_pat);
42 return None; 41 return None;
43 } 42 }
44 let initializer_expr = let_stmt.initializer()?; 43 let initializer_expr = let_stmt.initializer()?;
@@ -47,7 +46,7 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
47 let def = Definition::Local(def); 46 let def = Definition::Local(def);
48 let usages = def.usages(&ctx.sema).all(); 47 let usages = def.usages(&ctx.sema).all();
49 if usages.is_empty() { 48 if usages.is_empty() {
50 mark::hit!(test_not_applicable_if_variable_unused); 49 cov_mark::hit!(test_not_applicable_if_variable_unused);
51 return None; 50 return None;
52 }; 51 };
53 52
@@ -130,7 +129,7 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
130 Some(name_ref) 129 Some(name_ref)
131 if ast::RecordExprField::for_field_name(name_ref).is_some() => 130 if ast::RecordExprField::for_field_name(name_ref).is_some() =>
132 { 131 {
133 mark::hit!(inline_field_shorthand); 132 cov_mark::hit!(inline_field_shorthand);
134 builder.insert(reference.range.end(), format!(": {}", replacement)); 133 builder.insert(reference.range.end(), format!(": {}", replacement));
135 } 134 }
136 _ => builder.replace(reference.range, replacement), 135 _ => builder.replace(reference.range, replacement),
@@ -143,8 +142,6 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
143 142
144#[cfg(test)] 143#[cfg(test)]
145mod tests { 144mod tests {
146 use test_utils::mark;
147
148 use crate::tests::{check_assist, check_assist_not_applicable}; 145 use crate::tests::{check_assist, check_assist_not_applicable};
149 146
150 use super::*; 147 use super::*;
@@ -351,7 +348,7 @@ fn foo() {
351 348
352 #[test] 349 #[test]
353 fn test_not_inline_mut_variable() { 350 fn test_not_inline_mut_variable() {
354 mark::check!(test_not_inline_mut_variable); 351 cov_mark::check!(test_not_inline_mut_variable);
355 check_assist_not_applicable( 352 check_assist_not_applicable(
356 inline_local_variable, 353 inline_local_variable,
357 r" 354 r"
@@ -684,7 +681,7 @@ fn foo() {
684 681
685 #[test] 682 #[test]
686 fn inline_field_shorthand() { 683 fn inline_field_shorthand() {
687 mark::check!(inline_field_shorthand); 684 cov_mark::check!(inline_field_shorthand);
688 check_assist( 685 check_assist(
689 inline_local_variable, 686 inline_local_variable,
690 r" 687 r"
@@ -705,7 +702,7 @@ fn main() {
705 702
706 #[test] 703 #[test]
707 fn test_not_applicable_if_variable_unused() { 704 fn test_not_applicable_if_variable_unused() {
708 mark::check!(test_not_applicable_if_variable_unused); 705 cov_mark::check!(test_not_applicable_if_variable_unused);
709 check_assist_not_applicable( 706 check_assist_not_applicable(
710 inline_local_variable, 707 inline_local_variable,
711 r" 708 r"
@@ -718,7 +715,7 @@ fn foo() {
718 715
719 #[test] 716 #[test]
720 fn not_applicable_outside_of_bind_pat() { 717 fn not_applicable_outside_of_bind_pat() {
721 mark::check!(not_applicable_outside_of_bind_pat); 718 cov_mark::check!(not_applicable_outside_of_bind_pat);
722 check_assist_not_applicable( 719 check_assist_not_applicable(
723 inline_local_variable, 720 inline_local_variable,
724 r" 721 r"
diff --git a/crates/ide_assists/src/handlers/move_module_to_file.rs b/crates/ide_assists/src/handlers/move_module_to_file.rs
index 91c395c1b..6e685b4b2 100644
--- a/crates/ide_assists/src/handlers/move_module_to_file.rs
+++ b/crates/ide_assists/src/handlers/move_module_to_file.rs
@@ -5,7 +5,6 @@ use syntax::{
5 ast::{self, edit::AstNodeEdit, NameOwner}, 5 ast::{self, edit::AstNodeEdit, NameOwner},
6 AstNode, TextRange, 6 AstNode, TextRange,
7}; 7};
8use test_utils::mark;
9 8
10use crate::{AssistContext, AssistId, AssistKind, Assists}; 9use crate::{AssistContext, AssistId, AssistKind, Assists};
11 10
@@ -28,7 +27,7 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Opt
28 27
29 let l_curly_offset = module_items.syntax().text_range().start(); 28 let l_curly_offset = module_items.syntax().text_range().start();
30 if l_curly_offset <= ctx.offset() { 29 if l_curly_offset <= ctx.offset() {
31 mark::hit!(available_before_curly); 30 cov_mark::hit!(available_before_curly);
32 return None; 31 return None;
33 } 32 }
34 let target = TextRange::new(module_ast.syntax().text_range().start(), l_curly_offset); 33 let target = TextRange::new(module_ast.syntax().text_range().start(), l_curly_offset);
@@ -182,7 +181,7 @@ pub(crate) mod tests;
182 181
183 #[test] 182 #[test]
184 fn available_before_curly() { 183 fn available_before_curly() {
185 mark::check!(available_before_curly); 184 cov_mark::check!(available_before_curly);
186 check_assist_not_applicable(move_module_to_file, r#"mod m { $0 }"#); 185 check_assist_not_applicable(move_module_to_file, r#"mod m { $0 }"#);
187 } 186 }
188} 187}
diff --git a/crates/ide_assists/src/handlers/pull_assignment_up.rs b/crates/ide_assists/src/handlers/pull_assignment_up.rs
index 377ed4f2f..04bae4e58 100644
--- a/crates/ide_assists/src/handlers/pull_assignment_up.rs
+++ b/crates/ide_assists/src/handlers/pull_assignment_up.rs
@@ -2,7 +2,6 @@ use syntax::{
2 ast::{self, edit::AstNodeEdit, make}, 2 ast::{self, edit::AstNodeEdit, make},
3 AstNode, 3 AstNode,
4}; 4};
5use test_utils::mark;
6 5
7use crate::{ 6use crate::{
8 assist_context::{AssistContext, Assists}, 7 assist_context::{AssistContext, Assists},
@@ -104,7 +103,7 @@ fn exprify_if(
104 ast::ElseBranch::Block(exprify_block(block, sema, name)?) 103 ast::ElseBranch::Block(exprify_block(block, sema, name)?)
105 } 104 }
106 ast::ElseBranch::IfExpr(expr) => { 105 ast::ElseBranch::IfExpr(expr) => {
107 mark::hit!(test_pull_assignment_up_chained_if); 106 cov_mark::hit!(test_pull_assignment_up_chained_if);
108 ast::ElseBranch::IfExpr(ast::IfExpr::cast( 107 ast::ElseBranch::IfExpr(ast::IfExpr::cast(
109 exprify_if(&expr, sema, name)?.syntax().to_owned(), 108 exprify_if(&expr, sema, name)?.syntax().to_owned(),
110 )?) 109 )?)
@@ -144,7 +143,7 @@ fn is_equivalent(
144) -> bool { 143) -> bool {
145 match (expr0, expr1) { 144 match (expr0, expr1) {
146 (ast::Expr::FieldExpr(field_expr0), ast::Expr::FieldExpr(field_expr1)) => { 145 (ast::Expr::FieldExpr(field_expr0), ast::Expr::FieldExpr(field_expr1)) => {
147 mark::hit!(test_pull_assignment_up_field_assignment); 146 cov_mark::hit!(test_pull_assignment_up_field_assignment);
148 sema.resolve_field(field_expr0) == sema.resolve_field(field_expr1) 147 sema.resolve_field(field_expr0) == sema.resolve_field(field_expr1)
149 } 148 }
150 (ast::Expr::PathExpr(path0), ast::Expr::PathExpr(path1)) => { 149 (ast::Expr::PathExpr(path0), ast::Expr::PathExpr(path1)) => {
@@ -160,7 +159,7 @@ fn is_equivalent(
160 if prefix0.op_kind() == Some(ast::PrefixOp::Deref) 159 if prefix0.op_kind() == Some(ast::PrefixOp::Deref)
161 && prefix1.op_kind() == Some(ast::PrefixOp::Deref) => 160 && prefix1.op_kind() == Some(ast::PrefixOp::Deref) =>
162 { 161 {
163 mark::hit!(test_pull_assignment_up_deref); 162 cov_mark::hit!(test_pull_assignment_up_deref);
164 if let (Some(prefix0), Some(prefix1)) = (prefix0.expr(), prefix1.expr()) { 163 if let (Some(prefix0), Some(prefix1)) = (prefix0.expr(), prefix1.expr()) {
165 is_equivalent(sema, &prefix0, &prefix1) 164 is_equivalent(sema, &prefix0, &prefix1)
166 } else { 165 } else {
@@ -263,7 +262,7 @@ fn foo() {
263 262
264 #[test] 263 #[test]
265 fn test_pull_assignment_up_chained_if() { 264 fn test_pull_assignment_up_chained_if() {
266 mark::check!(test_pull_assignment_up_chained_if); 265 cov_mark::check!(test_pull_assignment_up_chained_if);
267 check_assist( 266 check_assist(
268 pull_assignment_up, 267 pull_assignment_up,
269 r#" 268 r#"
@@ -379,7 +378,7 @@ fn foo() {
379 378
380 #[test] 379 #[test]
381 fn test_pull_assignment_up_field_assignment() { 380 fn test_pull_assignment_up_field_assignment() {
382 mark::check!(test_pull_assignment_up_field_assignment); 381 cov_mark::check!(test_pull_assignment_up_field_assignment);
383 check_assist( 382 check_assist(
384 pull_assignment_up, 383 pull_assignment_up,
385 r#" 384 r#"
@@ -411,7 +410,7 @@ fn foo() {
411 410
412 #[test] 411 #[test]
413 fn test_pull_assignment_up_deref() { 412 fn test_pull_assignment_up_deref() {
414 mark::check!(test_pull_assignment_up_deref); 413 cov_mark::check!(test_pull_assignment_up_deref);
415 check_assist( 414 check_assist(
416 pull_assignment_up, 415 pull_assignment_up,
417 r#" 416 r#"
diff --git a/crates/ide_assists/src/handlers/qualify_path.rs b/crates/ide_assists/src/handlers/qualify_path.rs
index b0b0d31b4..30b23da6c 100644
--- a/crates/ide_assists/src/handlers/qualify_path.rs
+++ b/crates/ide_assists/src/handlers/qualify_path.rs
@@ -1,14 +1,16 @@
1use std::iter; 1use std::iter;
2 2
3use hir::{AsAssocItem, AsName}; 3use hir::AsAssocItem;
4use ide_db::helpers::{import_assets::ImportCandidate, mod_path_to_ast}; 4use ide_db::helpers::{
5 import_assets::{ImportCandidate, LocatedImport},
6 mod_path_to_ast,
7};
5use ide_db::RootDatabase; 8use ide_db::RootDatabase;
6use syntax::{ 9use syntax::{
7 ast, 10 ast,
8 ast::{make, ArgListOwner}, 11 ast::{make, ArgListOwner},
9 AstNode, 12 AstNode,
10}; 13};
11use test_utils::mark;
12 14
13use crate::{ 15use crate::{
14 assist_context::{AssistContext, Assists}, 16 assist_context::{AssistContext, Assists},
@@ -47,32 +49,32 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
47 let qualify_candidate = match candidate { 49 let qualify_candidate = match candidate {
48 ImportCandidate::Path(candidate) => { 50 ImportCandidate::Path(candidate) => {
49 if candidate.qualifier.is_some() { 51 if candidate.qualifier.is_some() {
50 mark::hit!(qualify_path_qualifier_start); 52 cov_mark::hit!(qualify_path_qualifier_start);
51 let path = ast::Path::cast(syntax_under_caret)?; 53 let path = ast::Path::cast(syntax_under_caret)?;
52 let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?); 54 let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?);
53 QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list()) 55 QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list())
54 } else { 56 } else {
55 mark::hit!(qualify_path_unqualified_name); 57 cov_mark::hit!(qualify_path_unqualified_name);
56 let path = ast::Path::cast(syntax_under_caret)?; 58 let path = ast::Path::cast(syntax_under_caret)?;
57 let generics = path.segment()?.generic_arg_list(); 59 let generics = path.segment()?.generic_arg_list();
58 QualifyCandidate::UnqualifiedName(generics) 60 QualifyCandidate::UnqualifiedName(generics)
59 } 61 }
60 } 62 }
61 ImportCandidate::TraitAssocItem(_) => { 63 ImportCandidate::TraitAssocItem(_) => {
62 mark::hit!(qualify_path_trait_assoc_item); 64 cov_mark::hit!(qualify_path_trait_assoc_item);
63 let path = ast::Path::cast(syntax_under_caret)?; 65 let path = ast::Path::cast(syntax_under_caret)?;
64 let (qualifier, segment) = (path.qualifier()?, path.segment()?); 66 let (qualifier, segment) = (path.qualifier()?, path.segment()?);
65 QualifyCandidate::TraitAssocItem(qualifier, segment) 67 QualifyCandidate::TraitAssocItem(qualifier, segment)
66 } 68 }
67 ImportCandidate::TraitMethod(_) => { 69 ImportCandidate::TraitMethod(_) => {
68 mark::hit!(qualify_path_trait_method); 70 cov_mark::hit!(qualify_path_trait_method);
69 let mcall_expr = ast::MethodCallExpr::cast(syntax_under_caret)?; 71 let mcall_expr = ast::MethodCallExpr::cast(syntax_under_caret)?;
70 QualifyCandidate::TraitMethod(ctx.sema.db, mcall_expr) 72 QualifyCandidate::TraitMethod(ctx.sema.db, mcall_expr)
71 } 73 }
72 }; 74 };
73 75
74 let group_label = group_label(candidate); 76 let group_label = group_label(candidate);
75 for (import, item) in proposed_imports { 77 for import in proposed_imports {
76 acc.add_group( 78 acc.add_group(
77 &group_label, 79 &group_label,
78 AssistId("qualify_path", AssistKind::QuickFix), 80 AssistId("qualify_path", AssistKind::QuickFix),
@@ -81,8 +83,8 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
81 |builder| { 83 |builder| {
82 qualify_candidate.qualify( 84 qualify_candidate.qualify(
83 |replace_with: String| builder.replace(range, replace_with), 85 |replace_with: String| builder.replace(range, replace_with),
84 import, 86 &import.import_path,
85 item, 87 import.item_to_import,
86 ) 88 )
87 }, 89 },
88 ); 90 );
@@ -98,8 +100,13 @@ enum QualifyCandidate<'db> {
98} 100}
99 101
100impl QualifyCandidate<'_> { 102impl QualifyCandidate<'_> {
101 fn qualify(&self, mut replacer: impl FnMut(String), import: hir::ModPath, item: hir::ItemInNs) { 103 fn qualify(
102 let import = mod_path_to_ast(&import); 104 &self,
105 mut replacer: impl FnMut(String),
106 import: &hir::ModPath,
107 item: hir::ItemInNs,
108 ) {
109 let import = mod_path_to_ast(import);
103 match self { 110 match self {
104 QualifyCandidate::QualifierStart(segment, generics) => { 111 QualifyCandidate::QualifierStart(segment, generics) => {
105 let generics = generics.as_ref().map_or_else(String::new, ToString::to_string); 112 let generics = generics.as_ref().map_or_else(String::new, ToString::to_string);
@@ -160,7 +167,9 @@ fn find_trait_method(
160) -> Option<hir::Function> { 167) -> Option<hir::Function> {
161 if let Some(hir::AssocItem::Function(method)) = 168 if let Some(hir::AssocItem::Function(method)) =
162 trait_.items(db).into_iter().find(|item: &hir::AssocItem| { 169 trait_.items(db).into_iter().find(|item: &hir::AssocItem| {
163 item.name(db).map(|name| name == trait_method_name.as_name()).unwrap_or(false) 170 item.name(db)
171 .map(|name| name.to_string() == trait_method_name.to_string())
172 .unwrap_or(false)
164 }) 173 })
165 { 174 {
166 Some(method) 175 Some(method)
@@ -182,23 +191,25 @@ fn item_as_trait(db: &RootDatabase, item: hir::ItemInNs) -> Option<hir::Trait> {
182fn group_label(candidate: &ImportCandidate) -> GroupLabel { 191fn group_label(candidate: &ImportCandidate) -> GroupLabel {
183 let name = match candidate { 192 let name = match candidate {
184 ImportCandidate::Path(it) => &it.name, 193 ImportCandidate::Path(it) => &it.name,
185 ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => &it.name, 194 ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => {
195 &it.assoc_item_name
196 }
186 } 197 }
187 .text(); 198 .text();
188 GroupLabel(format!("Qualify {}", name)) 199 GroupLabel(format!("Qualify {}", name))
189} 200}
190 201
191fn label(candidate: &ImportCandidate, import: &hir::ModPath) -> String { 202fn label(candidate: &ImportCandidate, import: &LocatedImport) -> String {
192 match candidate { 203 match candidate {
193 ImportCandidate::Path(candidate) => { 204 ImportCandidate::Path(candidate) => {
194 if candidate.qualifier.is_some() { 205 if candidate.qualifier.is_some() {
195 format!("Qualify with `{}`", &import) 206 format!("Qualify with `{}`", import.import_path)
196 } else { 207 } else {
197 format!("Qualify as `{}`", &import) 208 format!("Qualify as `{}`", import.import_path)
198 } 209 }
199 } 210 }
200 ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", &import), 211 ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", import.import_path),
201 ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", &import), 212 ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", import.import_path),
202 } 213 }
203} 214}
204 215
@@ -210,7 +221,7 @@ mod tests {
210 221
211 #[test] 222 #[test]
212 fn applicable_when_found_an_import_partial() { 223 fn applicable_when_found_an_import_partial() {
213 mark::check!(qualify_path_unqualified_name); 224 cov_mark::check!(qualify_path_unqualified_name);
214 check_assist( 225 check_assist(
215 qualify_path, 226 qualify_path,
216 r" 227 r"
@@ -502,7 +513,7 @@ fn main() {
502 513
503 #[test] 514 #[test]
504 fn associated_struct_const() { 515 fn associated_struct_const() {
505 mark::check!(qualify_path_qualifier_start); 516 cov_mark::check!(qualify_path_qualifier_start);
506 check_assist( 517 check_assist(
507 qualify_path, 518 qualify_path,
508 r" 519 r"
@@ -603,7 +614,7 @@ fn main() {
603 614
604 #[test] 615 #[test]
605 fn associated_trait_const() { 616 fn associated_trait_const() {
606 mark::check!(qualify_path_trait_assoc_item); 617 cov_mark::check!(qualify_path_trait_assoc_item);
607 check_assist( 618 check_assist(
608 qualify_path, 619 qualify_path,
609 r" 620 r"
@@ -673,7 +684,7 @@ fn main() {
673 684
674 #[test] 685 #[test]
675 fn trait_method() { 686 fn trait_method() {
676 mark::check!(qualify_path_trait_method); 687 cov_mark::check!(qualify_path_trait_method);
677 check_assist( 688 check_assist(
678 qualify_path, 689 qualify_path,
679 r" 690 r"
diff --git a/crates/ide_assists/src/handlers/raw_string.rs b/crates/ide_assists/src/handlers/raw_string.rs
index d95267607..d0f1613f3 100644
--- a/crates/ide_assists/src/handlers/raw_string.rs
+++ b/crates/ide_assists/src/handlers/raw_string.rs
@@ -1,7 +1,6 @@
1use std::borrow::Cow; 1use std::borrow::Cow;
2 2
3use syntax::{ast, AstToken, TextRange, TextSize}; 3use syntax::{ast, AstToken, TextRange, TextSize};
4use test_utils::mark;
5 4
6use crate::{AssistContext, AssistId, AssistKind, Assists}; 5use crate::{AssistContext, AssistId, AssistKind, Assists};
7 6
@@ -149,7 +148,7 @@ pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
149 let internal_text = &text[token.text_range_between_quotes()? - text_range.start()]; 148 let internal_text = &text[token.text_range_between_quotes()? - text_range.start()];
150 149
151 if existing_hashes == required_hashes(internal_text) { 150 if existing_hashes == required_hashes(internal_text) {
152 mark::hit!(cant_remove_required_hash); 151 cov_mark::hit!(cant_remove_required_hash);
153 return None; 152 return None;
154 } 153 }
155 154
@@ -182,8 +181,6 @@ fn test_required_hashes() {
182 181
183#[cfg(test)] 182#[cfg(test)]
184mod tests { 183mod tests {
185 use test_utils::mark;
186
187 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; 184 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
188 185
189 use super::*; 186 use super::*;
@@ -396,7 +393,7 @@ string"###;
396 393
397 #[test] 394 #[test]
398 fn cant_remove_required_hash() { 395 fn cant_remove_required_hash() {
399 mark::check!(cant_remove_required_hash); 396 cov_mark::check!(cant_remove_required_hash);
400 check_assist_not_applicable( 397 check_assist_not_applicable(
401 remove_hash, 398 remove_hash,
402 r##" 399 r##"
diff --git a/crates/ide_assists/src/handlers/remove_unused_param.rs b/crates/ide_assists/src/handlers/remove_unused_param.rs
index c961680e2..2699d2861 100644
--- a/crates/ide_assists/src/handlers/remove_unused_param.rs
+++ b/crates/ide_assists/src/handlers/remove_unused_param.rs
@@ -4,7 +4,7 @@ use syntax::{
4 ast::{self, ArgListOwner}, 4 ast::{self, ArgListOwner},
5 AstNode, SourceFile, SyntaxKind, SyntaxNode, TextRange, T, 5 AstNode, SourceFile, SyntaxKind, SyntaxNode, TextRange, T,
6}; 6};
7use test_utils::mark; 7
8use SyntaxKind::WHITESPACE; 8use SyntaxKind::WHITESPACE;
9 9
10use crate::{ 10use crate::{
@@ -49,7 +49,7 @@ pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext) -> Opt
49 Definition::Local(local) 49 Definition::Local(local)
50 }; 50 };
51 if param_def.usages(&ctx.sema).at_least_one() { 51 if param_def.usages(&ctx.sema).at_least_one() {
52 mark::hit!(keep_used); 52 cov_mark::hit!(keep_used);
53 return None; 53 return None;
54 } 54 }
55 acc.add( 55 acc.add(
@@ -243,7 +243,7 @@ fn b2() { foo(9) }
243 243
244 #[test] 244 #[test]
245 fn keep_used() { 245 fn keep_used() {
246 mark::check!(keep_used); 246 cov_mark::check!(keep_used);
247 check_assist_not_applicable( 247 check_assist_not_applicable(
248 remove_unused_param, 248 remove_unused_param,
249 r#" 249 r#"
diff --git a/crates/ide_assists/src/handlers/reorder_fields.rs b/crates/ide_assists/src/handlers/reorder_fields.rs
index fba7d6ddb..794c89323 100644
--- a/crates/ide_assists/src/handlers/reorder_fields.rs
+++ b/crates/ide_assists/src/handlers/reorder_fields.rs
@@ -4,7 +4,6 @@ use rustc_hash::FxHashMap;
4use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct}; 4use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct};
5use ide_db::RootDatabase; 5use ide_db::RootDatabase;
6use syntax::{algo, ast, match_ast, AstNode, SyntaxKind, SyntaxKind::*, SyntaxNode}; 6use syntax::{algo, ast, match_ast, AstNode, SyntaxKind, SyntaxKind::*, SyntaxNode};
7use test_utils::mark;
8 7
9use crate::{AssistContext, AssistId, AssistKind, Assists}; 8use crate::{AssistContext, AssistId, AssistKind, Assists};
10 9
@@ -39,7 +38,7 @@ fn reorder<R: AstNode>(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
39 }); 38 });
40 39
41 if sorted_fields == fields { 40 if sorted_fields == fields {
42 mark::hit!(reorder_sorted_fields); 41 cov_mark::hit!(reorder_sorted_fields);
43 return None; 42 return None;
44 } 43 }
45 44
@@ -109,15 +108,13 @@ fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashM
109 108
110#[cfg(test)] 109#[cfg(test)]
111mod tests { 110mod tests {
112 use test_utils::mark;
113
114 use crate::tests::{check_assist, check_assist_not_applicable}; 111 use crate::tests::{check_assist, check_assist_not_applicable};
115 112
116 use super::*; 113 use super::*;
117 114
118 #[test] 115 #[test]
119 fn reorder_sorted_fields() { 116 fn reorder_sorted_fields() {
120 mark::check!(reorder_sorted_fields); 117 cov_mark::check!(reorder_sorted_fields);
121 check_assist_not_applicable( 118 check_assist_not_applicable(
122 reorder_fields, 119 reorder_fields,
123 r#" 120 r#"
diff --git a/crates/ide_assists/src/handlers/reorder_impl.rs b/crates/ide_assists/src/handlers/reorder_impl.rs
index 309f291c8..edf4b0bfe 100644
--- a/crates/ide_assists/src/handlers/reorder_impl.rs
+++ b/crates/ide_assists/src/handlers/reorder_impl.rs
@@ -8,7 +8,6 @@ use syntax::{
8 ast::{self, NameOwner}, 8 ast::{self, NameOwner},
9 AstNode, 9 AstNode,
10}; 10};
11use test_utils::mark;
12 11
13use crate::{AssistContext, AssistId, AssistKind, Assists}; 12use crate::{AssistContext, AssistId, AssistKind, Assists};
14 13
@@ -71,7 +70,7 @@ pub(crate) fn reorder_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
71 70
72 // Don't edit already sorted methods: 71 // Don't edit already sorted methods:
73 if methods == sorted { 72 if methods == sorted {
74 mark::hit!(not_applicable_if_sorted); 73 cov_mark::hit!(not_applicable_if_sorted);
75 return None; 74 return None;
76 } 75 }
77 76
@@ -121,15 +120,13 @@ fn get_methods(items: &ast::AssocItemList) -> Vec<ast::Fn> {
121 120
122#[cfg(test)] 121#[cfg(test)]
123mod tests { 122mod tests {
124 use test_utils::mark;
125
126 use crate::tests::{check_assist, check_assist_not_applicable}; 123 use crate::tests::{check_assist, check_assist_not_applicable};
127 124
128 use super::*; 125 use super::*;
129 126
130 #[test] 127 #[test]
131 fn not_applicable_if_sorted() { 128 fn not_applicable_if_sorted() {
132 mark::check!(not_applicable_if_sorted); 129 cov_mark::check!(not_applicable_if_sorted);
133 check_assist_not_applicable( 130 check_assist_not_applicable(
134 reorder_impl, 131 reorder_impl,
135 r#" 132 r#"
diff --git a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
index c69bc5cac..88fe2fe90 100644
--- a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -1,5 +1,6 @@
1use hir::ModuleDef;
1use ide_db::helpers::mod_path_to_ast; 2use ide_db::helpers::mod_path_to_ast;
2use ide_db::imports_locator; 3use ide_db::items_locator;
3use itertools::Itertools; 4use itertools::Itertools;
4use syntax::{ 5use syntax::{
5 ast::{self, make, AstNode, NameOwner}, 6 ast::{self, make, AstNode, NameOwner},
@@ -64,22 +65,20 @@ pub(crate) fn replace_derive_with_manual_impl(
64 let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; 65 let current_module = ctx.sema.scope(annotated_name.syntax()).module()?;
65 let current_crate = current_module.krate(); 66 let current_crate = current_module.krate();
66 67
67 let found_traits = imports_locator::find_exact_imports( 68 let found_traits =
68 &ctx.sema, 69 items_locator::with_exact_name(&ctx.sema, current_crate, trait_token.text().to_string())
69 current_crate, 70 .into_iter()
70 trait_token.text().to_string(), 71 .filter_map(|item| match ModuleDef::from(item.as_module_def_id()?) {
71 ) 72 ModuleDef::Trait(trait_) => Some(trait_),
72 .filter_map(|candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate { 73 _ => None,
73 either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_), 74 })
74 _ => None, 75 .flat_map(|trait_| {
75 }) 76 current_module
76 .flat_map(|trait_| { 77 .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_))
77 current_module 78 .as_ref()
78 .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_)) 79 .map(mod_path_to_ast)
79 .as_ref() 80 .zip(Some(trait_))
80 .map(mod_path_to_ast) 81 });
81 .zip(Some(trait_))
82 });
83 82
84 let mut no_traits_found = true; 83 let mut no_traits_found = true;
85 for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) { 84 for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {
diff --git a/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs b/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs
index 27da28bc0..50b05ab0b 100644
--- a/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs
+++ b/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs
@@ -3,7 +3,6 @@ use hir::known;
3use ide_db::helpers::FamousDefs; 3use ide_db::helpers::FamousDefs;
4use stdx::format_to; 4use stdx::format_to;
5use syntax::{ast, AstNode}; 5use syntax::{ast, AstNode};
6use test_utils::mark;
7 6
8use crate::{AssistContext, AssistId, AssistKind, Assists}; 7use crate::{AssistContext, AssistId, AssistKind, Assists};
9 8
@@ -34,7 +33,7 @@ pub(crate) fn replace_for_loop_with_for_each(acc: &mut Assists, ctx: &AssistCont
34 let pat = for_loop.pat()?; 33 let pat = for_loop.pat()?;
35 let body = for_loop.loop_body()?; 34 let body = for_loop.loop_body()?;
36 if body.syntax().text_range().start() < ctx.offset() { 35 if body.syntax().text_range().start() < ctx.offset() {
37 mark::hit!(not_available_in_body); 36 cov_mark::hit!(not_available_in_body);
38 return None; 37 return None;
39 } 38 }
40 39
@@ -187,7 +186,7 @@ fn main() {
187 186
188 #[test] 187 #[test]
189 fn not_available_in_body() { 188 fn not_available_in_body() {
190 mark::check!(not_available_in_body); 189 cov_mark::check!(not_available_in_body);
191 check_assist_not_applicable( 190 check_assist_not_applicable(
192 replace_for_loop_with_for_each, 191 replace_for_loop_with_for_each,
193 r" 192 r"
diff --git a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
index f3bc6cf39..36d2e0331 100644
--- a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
@@ -1,6 +1,5 @@
1use ide_db::helpers::insert_use::{insert_use, ImportScope}; 1use ide_db::helpers::insert_use::{insert_use, ImportScope};
2use syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SyntaxNode}; 2use syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SyntaxNode};
3use test_utils::mark;
4 3
5use crate::{AssistContext, AssistId, AssistKind, Assists}; 4use crate::{AssistContext, AssistId, AssistKind, Assists};
6 5
@@ -27,7 +26,7 @@ pub(crate) fn replace_qualified_name_with_use(
27 return None; 26 return None;
28 } 27 }
29 if path.qualifier().is_none() { 28 if path.qualifier().is_none() {
30 mark::hit!(dont_import_trivial_paths); 29 cov_mark::hit!(dont_import_trivial_paths);
31 return None; 30 return None;
32 } 31 }
33 32
@@ -44,7 +43,7 @@ pub(crate) fn replace_qualified_name_with_use(
44 let mut rewriter = SyntaxRewriter::default(); 43 let mut rewriter = SyntaxRewriter::default();
45 shorten_paths(&mut rewriter, syntax.clone(), &path); 44 shorten_paths(&mut rewriter, syntax.clone(), &path);
46 if let Some(ref import_scope) = ImportScope::from(syntax.clone()) { 45 if let Some(ref import_scope) = ImportScope::from(syntax.clone()) {
47 rewriter += insert_use(import_scope, path, ctx.config.insert_use.merge); 46 rewriter += insert_use(import_scope, path, ctx.config.insert_use);
48 builder.rewrite(rewriter); 47 builder.rewrite(rewriter);
49 } 48 }
50 }, 49 },
@@ -458,7 +457,7 @@ impl Debug for Foo {
458 457
459 #[test] 458 #[test]
460 fn dont_import_trivial_paths() { 459 fn dont_import_trivial_paths() {
461 mark::check!(dont_import_trivial_paths); 460 cov_mark::check!(dont_import_trivial_paths);
462 check_assist_not_applicable( 461 check_assist_not_applicable(
463 replace_qualified_name_with_use, 462 replace_qualified_name_with_use,
464 r" 463 r"
diff --git a/crates/ide_assists/src/handlers/unmerge_use.rs b/crates/ide_assists/src/handlers/unmerge_use.rs
index 3dbef8e51..616af7c2e 100644
--- a/crates/ide_assists/src/handlers/unmerge_use.rs
+++ b/crates/ide_assists/src/handlers/unmerge_use.rs
@@ -3,7 +3,6 @@ use syntax::{
3 ast::{self, edit::AstNodeEdit, VisibilityOwner}, 3 ast::{self, edit::AstNodeEdit, VisibilityOwner},
4 AstNode, SyntaxKind, 4 AstNode, SyntaxKind,
5}; 5};
6use test_utils::mark;
7 6
8use crate::{ 7use crate::{
9 assist_context::{AssistContext, Assists}, 8 assist_context::{AssistContext, Assists},
@@ -27,7 +26,7 @@ pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
27 26
28 let tree_list = tree.syntax().parent().and_then(ast::UseTreeList::cast)?; 27 let tree_list = tree.syntax().parent().and_then(ast::UseTreeList::cast)?;
29 if tree_list.use_trees().count() < 2 { 28 if tree_list.use_trees().count() < 2 {
30 mark::hit!(skip_single_use_item); 29 cov_mark::hit!(skip_single_use_item);
31 return None; 30 return None;
32 } 31 }
33 32
@@ -89,7 +88,7 @@ mod tests {
89 88
90 #[test] 89 #[test]
91 fn skip_single_use_item() { 90 fn skip_single_use_item() {
92 mark::check!(skip_single_use_item); 91 cov_mark::check!(skip_single_use_item);
93 check_assist_not_applicable( 92 check_assist_not_applicable(
94 unmerge_use, 93 unmerge_use,
95 r" 94 r"
diff --git a/crates/ide_assists/src/handlers/wrap_return_type_in_result.rs b/crates/ide_assists/src/handlers/wrap_return_type_in_result.rs
index fec16fc49..e838630ea 100644
--- a/crates/ide_assists/src/handlers/wrap_return_type_in_result.rs
+++ b/crates/ide_assists/src/handlers/wrap_return_type_in_result.rs
@@ -4,7 +4,6 @@ use syntax::{
4 ast::{self, make, BlockExpr, Expr, LoopBodyOwner}, 4 ast::{self, make, BlockExpr, Expr, LoopBodyOwner},
5 match_ast, AstNode, SyntaxNode, 5 match_ast, AstNode, SyntaxNode,
6}; 6};
7use test_utils::mark;
8 7
9use crate::{AssistContext, AssistId, AssistKind, Assists}; 8use crate::{AssistContext, AssistId, AssistKind, Assists};
10 9
@@ -39,7 +38,7 @@ pub(crate) fn wrap_return_type_in_result(acc: &mut Assists, ctx: &AssistContext)
39 let first_part_ret_type = ret_type_str.splitn(2, '<').next(); 38 let first_part_ret_type = ret_type_str.splitn(2, '<').next();
40 if let Some(ret_type_first_part) = first_part_ret_type { 39 if let Some(ret_type_first_part) = first_part_ret_type {
41 if ret_type_first_part.ends_with("Result") { 40 if ret_type_first_part.ends_with("Result") {
42 mark::hit!(wrap_return_type_in_result_simple_return_type_already_result); 41 cov_mark::hit!(wrap_return_type_in_result_simple_return_type_already_result);
43 return None; 42 return None;
44 } 43 }
45 } 44 }
@@ -367,7 +366,7 @@ fn foo() -> std::result::Result<i32$0, String> {
367 366
368 #[test] 367 #[test]
369 fn wrap_return_type_in_result_simple_return_type_already_result() { 368 fn wrap_return_type_in_result_simple_return_type_already_result() {
370 mark::check!(wrap_return_type_in_result_simple_return_type_already_result); 369 cov_mark::check!(wrap_return_type_in_result_simple_return_type_already_result);
371 check_assist_not_applicable( 370 check_assist_not_applicable(
372 wrap_return_type_in_result, 371 wrap_return_type_in_result,
373 r#" 372 r#"
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs
index ea62d5f5d..f1aab74d4 100644
--- a/crates/ide_assists/src/lib.rs
+++ b/crates/ide_assists/src/lib.rs
@@ -116,6 +116,7 @@ mod handlers {
116 mod change_visibility; 116 mod change_visibility;
117 mod convert_integer_literal; 117 mod convert_integer_literal;
118 mod convert_comment_block; 118 mod convert_comment_block;
119 mod convert_iter_for_each_to_for;
119 mod early_return; 120 mod early_return;
120 mod expand_glob_import; 121 mod expand_glob_import;
121 mod extract_function; 122 mod extract_function;
@@ -181,6 +182,7 @@ mod handlers {
181 change_visibility::change_visibility, 182 change_visibility::change_visibility,
182 convert_integer_literal::convert_integer_literal, 183 convert_integer_literal::convert_integer_literal,
183 convert_comment_block::convert_comment_block, 184 convert_comment_block::convert_comment_block,
185 convert_iter_for_each_to_for::convert_iter_for_each_to_for,
184 early_return::convert_to_guarded_return, 186 early_return::convert_to_guarded_return,
185 expand_glob_import::expand_glob_import, 187 expand_glob_import::expand_glob_import,
186 extract_struct_from_enum_variant::extract_struct_from_enum_variant, 188 extract_struct_from_enum_variant::extract_struct_from_enum_variant,
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs
index b7f616760..a7a923beb 100644
--- a/crates/ide_assists/src/tests.rs
+++ b/crates/ide_assists/src/tests.rs
@@ -23,6 +23,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
23 insert_use: InsertUseConfig { 23 insert_use: InsertUseConfig {
24 merge: Some(MergeBehavior::Full), 24 merge: Some(MergeBehavior::Full),
25 prefix_kind: hir::PrefixKind::Plain, 25 prefix_kind: hir::PrefixKind::Plain,
26 group: true,
26 }, 27 },
27}; 28};
28 29
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs
index 304b5798f..3f77edd8d 100644
--- a/crates/ide_assists/src/tests/generated.rs
+++ b/crates/ide_assists/src/tests/generated.rs
@@ -206,6 +206,36 @@ const _: i32 = 0b1010;
206} 206}
207 207
208#[test] 208#[test]
209fn doctest_convert_iter_for_each_to_for() {
210 check_doc_test(
211 "convert_iter_for_each_to_for",
212 r#####"
213//- /lib.rs crate:core
214pub mod iter { pub mod traits { pub mod iterator { pub trait Iterator {} } } }
215pub struct SomeIter;
216impl self::iter::traits::iterator::Iterator for SomeIter {}
217//- /lib.rs crate:main deps:core
218use core::SomeIter;
219fn main() {
220 let iter = SomeIter;
221 iter.for_each$0(|(x, y)| {
222 println!("x: {}, y: {}", x, y);
223 });
224}
225"#####,
226 r#####"
227use core::SomeIter;
228fn main() {
229 let iter = SomeIter;
230 for (x, y) in iter {
231 println!("x: {}, y: {}", x, y);
232 }
233}
234"#####,
235 )
236}
237
238#[test]
209fn doctest_convert_to_guarded_return() { 239fn doctest_convert_to_guarded_return() {
210 check_doc_test( 240 check_doc_test(
211 "convert_to_guarded_return", 241 "convert_to_guarded_return",