aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src')
-rw-r--r--crates/ra_assists/src/assist_context.rs27
-rw-r--r--crates/ra_assists/src/handlers/add_explicit_type.rs18
-rw-r--r--crates/ra_assists/src/handlers/add_from_impl_for_enum.rs14
-rw-r--r--crates/ra_assists/src/handlers/add_turbo_fish.rs12
-rw-r--r--crates/ra_assists/src/handlers/apply_demorgan.rs8
-rw-r--r--crates/ra_assists/src/handlers/auto_import.rs22
-rw-r--r--crates/ra_assists/src/handlers/change_visibility.rs548
-rw-r--r--crates/ra_assists/src/handlers/early_return.rs18
-rw-r--r--crates/ra_assists/src/handlers/fill_match_arms.rs202
-rw-r--r--crates/ra_assists/src/handlers/fix_visibility.rs559
-rw-r--r--crates/ra_assists/src/handlers/flip_binexpr.rs14
-rw-r--r--crates/ra_assists/src/handlers/flip_comma.rs2
-rw-r--r--crates/ra_assists/src/handlers/flip_trait_bound.rs14
-rw-r--r--crates/ra_assists/src/handlers/inline_local_variable.rs63
-rw-r--r--crates/ra_assists/src/handlers/introduce_variable.rs128
-rw-r--r--crates/ra_assists/src/handlers/invert_if.rs6
-rw-r--r--crates/ra_assists/src/handlers/merge_imports.rs22
-rw-r--r--crates/ra_assists/src/handlers/merge_match_arms.rs25
-rw-r--r--crates/ra_assists/src/handlers/move_bounds.rs8
-rw-r--r--crates/ra_assists/src/handlers/move_guard.rs33
-rw-r--r--crates/ra_assists/src/handlers/raw_string.rs26
-rw-r--r--crates/ra_assists/src/handlers/remove_dbg.rs39
-rw-r--r--crates/ra_assists/src/handlers/remove_mut.rs5
-rw-r--r--crates/ra_assists/src/handlers/reorder_fields.rs8
-rw-r--r--crates/ra_assists/src/handlers/replace_if_let_with_match.rs29
-rw-r--r--crates/ra_assists/src/handlers/replace_let_with_if_let.rs5
-rw-r--r--crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs38
-rw-r--r--crates/ra_assists/src/handlers/replace_unwrap_with_match.rs41
-rw-r--r--crates/ra_assists/src/handlers/split_import.rs6
-rw-r--r--crates/ra_assists/src/handlers/unwrap_block.rs34
-rw-r--r--crates/ra_assists/src/lib.rs3
-rw-r--r--crates/ra_assists/src/marks.rs15
-rw-r--r--crates/ra_assists/src/tests.rs18
-rw-r--r--crates/ra_assists/src/tests/generated.rs29
34 files changed, 994 insertions, 1045 deletions
diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs
index 005c17776..5b1a4680b 100644
--- a/crates/ra_assists/src/assist_context.rs
+++ b/crates/ra_assists/src/assist_context.rs
@@ -5,7 +5,7 @@ use hir::Semantics;
5use ra_db::{FileId, FileRange}; 5use ra_db::{FileId, FileRange};
6use ra_fmt::{leading_indent, reindent}; 6use ra_fmt::{leading_indent, reindent};
7use ra_ide_db::{ 7use ra_ide_db::{
8 source_change::{SingleFileChange, SourceChange}, 8 source_change::{SourceChange, SourceFileEdit},
9 RootDatabase, 9 RootDatabase,
10}; 10};
11use ra_syntax::{ 11use ra_syntax::{
@@ -150,11 +150,10 @@ impl Assists {
150 self.add_impl(label, f) 150 self.add_impl(label, f)
151 } 151 }
152 fn add_impl(&mut self, label: Assist, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> { 152 fn add_impl(&mut self, label: Assist, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> {
153 let change_label = label.label.clone();
154 let source_change = if self.resolve { 153 let source_change = if self.resolve {
155 let mut builder = AssistBuilder::new(self.file); 154 let mut builder = AssistBuilder::new(self.file);
156 f(&mut builder); 155 f(&mut builder);
157 Some(builder.finish(change_label)) 156 Some(builder.finish())
158 } else { 157 } else {
159 None 158 None
160 }; 159 };
@@ -171,19 +170,13 @@ impl Assists {
171 170
172pub(crate) struct AssistBuilder { 171pub(crate) struct AssistBuilder {
173 edit: TextEditBuilder, 172 edit: TextEditBuilder,
174 cursor_position: Option<TextSize>,
175 file: FileId, 173 file: FileId,
176 is_snippet: bool, 174 is_snippet: bool,
177} 175}
178 176
179impl AssistBuilder { 177impl AssistBuilder {
180 pub(crate) fn new(file: FileId) -> AssistBuilder { 178 pub(crate) fn new(file: FileId) -> AssistBuilder {
181 AssistBuilder { 179 AssistBuilder { edit: TextEditBuilder::default(), file, is_snippet: false }
182 edit: TextEditBuilder::default(),
183 cursor_position: None,
184 file,
185 is_snippet: false,
186 }
187 } 180 }
188 181
189 /// Remove specified `range` of text. 182 /// Remove specified `range` of text.
@@ -241,10 +234,6 @@ impl AssistBuilder {
241 algo::diff(&node, &new).into_text_edit(&mut self.edit) 234 algo::diff(&node, &new).into_text_edit(&mut self.edit)
242 } 235 }
243 236
244 /// Specify desired position of the cursor after the assist is applied.
245 pub(crate) fn set_cursor(&mut self, offset: TextSize) {
246 self.cursor_position = Some(offset)
247 }
248 // FIXME: better API 237 // FIXME: better API
249 pub(crate) fn set_file(&mut self, assist_file: FileId) { 238 pub(crate) fn set_file(&mut self, assist_file: FileId) {
250 self.file = assist_file; 239 self.file = assist_file;
@@ -256,14 +245,10 @@ impl AssistBuilder {
256 &mut self.edit 245 &mut self.edit
257 } 246 }
258 247
259 fn finish(self, change_label: String) -> SourceChange { 248 fn finish(self) -> SourceChange {
260 let edit = self.edit.finish(); 249 let edit = self.edit.finish();
261 if edit.is_empty() && self.cursor_position.is_none() { 250 let source_file_edit = SourceFileEdit { file_id: self.file, edit };
262 panic!("Only call `add_assist` if the assist can be applied") 251 let mut res: SourceChange = source_file_edit.into();
263 }
264 let mut res =
265 SingleFileChange { label: change_label, edit, cursor_position: self.cursor_position }
266 .into_source_change(self.file);
267 if self.is_snippet { 252 if self.is_snippet {
268 res.is_snippet = true; 253 res.is_snippet = true;
269 } 254 }
diff --git a/crates/ra_assists/src/handlers/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs
index 770049212..ab20c6649 100644
--- a/crates/ra_assists/src/handlers/add_explicit_type.rs
+++ b/crates/ra_assists/src/handlers/add_explicit_type.rs
@@ -86,11 +86,7 @@ mod tests {
86 86
87 #[test] 87 #[test]
88 fn add_explicit_type_works_for_simple_expr() { 88 fn add_explicit_type_works_for_simple_expr() {
89 check_assist( 89 check_assist(add_explicit_type, "fn f() { let a<|> = 1; }", "fn f() { let a: i32 = 1; }");
90 add_explicit_type,
91 "fn f() { let a<|> = 1; }",
92 "fn f() { let a<|>: i32 = 1; }",
93 );
94 } 90 }
95 91
96 #[test] 92 #[test]
@@ -98,7 +94,7 @@ mod tests {
98 check_assist( 94 check_assist(
99 add_explicit_type, 95 add_explicit_type,
100 "fn f() { let a<|>: _ = 1; }", 96 "fn f() { let a<|>: _ = 1; }",
101 "fn f() { let a<|>: i32 = 1; }", 97 "fn f() { let a: i32 = 1; }",
102 ); 98 );
103 } 99 }
104 100
@@ -122,7 +118,7 @@ mod tests {
122 } 118 }
123 119
124 fn f() { 120 fn f() {
125 let a<|>: Option<i32> = Option::Some(1); 121 let a: Option<i32> = Option::Some(1);
126 }"#, 122 }"#,
127 ); 123 );
128 } 124 }
@@ -132,7 +128,7 @@ mod tests {
132 check_assist( 128 check_assist(
133 add_explicit_type, 129 add_explicit_type,
134 r"macro_rules! v { () => {0u64} } fn f() { let a<|> = v!(); }", 130 r"macro_rules! v { () => {0u64} } fn f() { let a<|> = v!(); }",
135 r"macro_rules! v { () => {0u64} } fn f() { let a<|>: u64 = v!(); }", 131 r"macro_rules! v { () => {0u64} } fn f() { let a: u64 = v!(); }",
136 ); 132 );
137 } 133 }
138 134
@@ -140,8 +136,8 @@ mod tests {
140 fn add_explicit_type_works_for_macro_call_recursive() { 136 fn add_explicit_type_works_for_macro_call_recursive() {
141 check_assist( 137 check_assist(
142 add_explicit_type, 138 add_explicit_type,
143 "macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a<|> = v!(); }", 139 r#"macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a<|> = v!(); }"#,
144 "macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a<|>: u64 = v!(); }", 140 r#"macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a: u64 = v!(); }"#,
145 ); 141 );
146 } 142 }
147 143
@@ -208,7 +204,7 @@ struct Test<K, T = u8> {
208} 204}
209 205
210fn main() { 206fn main() {
211 let test<|>: Test<i32> = Test { t: 23, k: 33 }; 207 let test: Test<i32> = Test { t: 23, k: 33 };
212}"#, 208}"#,
213 ); 209 );
214 } 210 }
diff --git a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
index eb57b7231..6a675e812 100644
--- a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
+++ b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
@@ -1,6 +1,6 @@
1use ra_ide_db::RootDatabase; 1use ra_ide_db::RootDatabase;
2use ra_syntax::ast::{self, AstNode, NameOwner}; 2use ra_syntax::ast::{self, AstNode, NameOwner};
3use test_utils::tested_by; 3use test_utils::mark;
4 4
5use crate::{utils::FamousDefs, AssistContext, AssistId, Assists}; 5use crate::{utils::FamousDefs, AssistContext, AssistId, Assists};
6 6
@@ -39,7 +39,7 @@ pub(crate) fn add_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) ->
39 }; 39 };
40 40
41 if existing_from_impl(&ctx.sema, &variant).is_some() { 41 if existing_from_impl(&ctx.sema, &variant).is_some() {
42 tested_by!(test_add_from_impl_already_exists); 42 mark::hit!(test_add_from_impl_already_exists);
43 return None; 43 return None;
44 } 44 }
45 45
@@ -90,7 +90,7 @@ fn existing_from_impl(
90 90
91#[cfg(test)] 91#[cfg(test)]
92mod tests { 92mod tests {
93 use test_utils::covers; 93 use test_utils::mark;
94 94
95 use crate::tests::{check_assist, check_assist_not_applicable}; 95 use crate::tests::{check_assist, check_assist_not_applicable};
96 96
@@ -101,7 +101,7 @@ mod tests {
101 check_assist( 101 check_assist(
102 add_from_impl_for_enum, 102 add_from_impl_for_enum,
103 "enum A { <|>One(u32) }", 103 "enum A { <|>One(u32) }",
104 r#"enum A { <|>One(u32) } 104 r#"enum A { One(u32) }
105 105
106impl From<u32> for A { 106impl From<u32> for A {
107 fn from(v: u32) -> Self { 107 fn from(v: u32) -> Self {
@@ -116,7 +116,7 @@ impl From<u32> for A {
116 check_assist( 116 check_assist(
117 add_from_impl_for_enum, 117 add_from_impl_for_enum,
118 r#"enum A { <|>One(foo::bar::baz::Boo) }"#, 118 r#"enum A { <|>One(foo::bar::baz::Boo) }"#,
119 r#"enum A { <|>One(foo::bar::baz::Boo) } 119 r#"enum A { One(foo::bar::baz::Boo) }
120 120
121impl From<foo::bar::baz::Boo> for A { 121impl From<foo::bar::baz::Boo> for A {
122 fn from(v: foo::bar::baz::Boo) -> Self { 122 fn from(v: foo::bar::baz::Boo) -> Self {
@@ -149,7 +149,7 @@ impl From<foo::bar::baz::Boo> for A {
149 149
150 #[test] 150 #[test]
151 fn test_add_from_impl_already_exists() { 151 fn test_add_from_impl_already_exists() {
152 covers!(test_add_from_impl_already_exists); 152 mark::check!(test_add_from_impl_already_exists);
153 check_not_applicable( 153 check_not_applicable(
154 r#" 154 r#"
155enum A { <|>One(u32), } 155enum A { <|>One(u32), }
@@ -178,7 +178,7 @@ impl From<String> for A {
178pub trait From<T> { 178pub trait From<T> {
179 fn from(T) -> Self; 179 fn from(T) -> Self;
180}"#, 180}"#,
181 r#"enum A { <|>One(u32), Two(String), } 181 r#"enum A { One(u32), Two(String), }
182 182
183impl From<u32> for A { 183impl From<u32> for A {
184 fn from(v: u32) -> Self { 184 fn from(v: u32) -> Self {
diff --git a/crates/ra_assists/src/handlers/add_turbo_fish.rs b/crates/ra_assists/src/handlers/add_turbo_fish.rs
index a0363bc78..26acf81f2 100644
--- a/crates/ra_assists/src/handlers/add_turbo_fish.rs
+++ b/crates/ra_assists/src/handlers/add_turbo_fish.rs
@@ -1,11 +1,11 @@
1use ra_ide_db::defs::{classify_name_ref, Definition, NameRefClass}; 1use ra_ide_db::defs::{classify_name_ref, Definition, NameRefClass};
2use ra_syntax::{ast, AstNode, SyntaxKind, T}; 2use ra_syntax::{ast, AstNode, SyntaxKind, T};
3use test_utils::mark;
3 4
4use crate::{ 5use crate::{
5 assist_context::{AssistContext, Assists}, 6 assist_context::{AssistContext, Assists},
6 AssistId, 7 AssistId,
7}; 8};
8use test_utils::tested_by;
9 9
10// Assist: add_turbo_fish 10// Assist: add_turbo_fish
11// 11//
@@ -28,7 +28,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
28 let ident = ctx.find_token_at_offset(SyntaxKind::IDENT)?; 28 let ident = ctx.find_token_at_offset(SyntaxKind::IDENT)?;
29 let next_token = ident.next_token()?; 29 let next_token = ident.next_token()?;
30 if next_token.kind() == T![::] { 30 if next_token.kind() == T![::] {
31 tested_by!(add_turbo_fish_one_fish_is_enough); 31 mark::hit!(add_turbo_fish_one_fish_is_enough);
32 return None; 32 return None;
33 } 33 }
34 let name_ref = ast::NameRef::cast(ident.parent())?; 34 let name_ref = ast::NameRef::cast(ident.parent())?;
@@ -42,7 +42,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
42 }; 42 };
43 let generics = hir::GenericDef::Function(fun).params(ctx.sema.db); 43 let generics = hir::GenericDef::Function(fun).params(ctx.sema.db);
44 if generics.is_empty() { 44 if generics.is_empty() {
45 tested_by!(add_turbo_fish_non_generic); 45 mark::hit!(add_turbo_fish_non_generic);
46 return None; 46 return None;
47 } 47 }
48 acc.add(AssistId("add_turbo_fish"), "Add `::<>`", ident.text_range(), |builder| { 48 acc.add(AssistId("add_turbo_fish"), "Add `::<>`", ident.text_range(), |builder| {
@@ -58,7 +58,7 @@ mod tests {
58 use crate::tests::{check_assist, check_assist_not_applicable}; 58 use crate::tests::{check_assist, check_assist_not_applicable};
59 59
60 use super::*; 60 use super::*;
61 use test_utils::covers; 61 use test_utils::mark;
62 62
63 #[test] 63 #[test]
64 fn add_turbo_fish_function() { 64 fn add_turbo_fish_function() {
@@ -106,7 +106,7 @@ fn main() {
106 106
107 #[test] 107 #[test]
108 fn add_turbo_fish_one_fish_is_enough() { 108 fn add_turbo_fish_one_fish_is_enough() {
109 covers!(add_turbo_fish_one_fish_is_enough); 109 mark::check!(add_turbo_fish_one_fish_is_enough);
110 check_assist_not_applicable( 110 check_assist_not_applicable(
111 add_turbo_fish, 111 add_turbo_fish,
112 r#" 112 r#"
@@ -120,7 +120,7 @@ fn main() {
120 120
121 #[test] 121 #[test]
122 fn add_turbo_fish_non_generic() { 122 fn add_turbo_fish_non_generic() {
123 covers!(add_turbo_fish_non_generic); 123 mark::check!(add_turbo_fish_non_generic);
124 check_assist_not_applicable( 124 check_assist_not_applicable(
125 add_turbo_fish, 125 add_turbo_fish,
126 r#" 126 r#"
diff --git a/crates/ra_assists/src/handlers/apply_demorgan.rs b/crates/ra_assists/src/handlers/apply_demorgan.rs
index 0feba5e11..233e8fb8e 100644
--- a/crates/ra_assists/src/handlers/apply_demorgan.rs
+++ b/crates/ra_assists/src/handlers/apply_demorgan.rs
@@ -63,22 +63,22 @@ mod tests {
63 63
64 #[test] 64 #[test]
65 fn demorgan_turns_and_into_or() { 65 fn demorgan_turns_and_into_or() {
66 check_assist(apply_demorgan, "fn f() { !x &&<|> !x }", "fn f() { !(x ||<|> x) }") 66 check_assist(apply_demorgan, "fn f() { !x &&<|> !x }", "fn f() { !(x || x) }")
67 } 67 }
68 68
69 #[test] 69 #[test]
70 fn demorgan_turns_or_into_and() { 70 fn demorgan_turns_or_into_and() {
71 check_assist(apply_demorgan, "fn f() { !x ||<|> !x }", "fn f() { !(x &&<|> x) }") 71 check_assist(apply_demorgan, "fn f() { !x ||<|> !x }", "fn f() { !(x && x) }")
72 } 72 }
73 73
74 #[test] 74 #[test]
75 fn demorgan_removes_inequality() { 75 fn demorgan_removes_inequality() {
76 check_assist(apply_demorgan, "fn f() { x != x ||<|> !x }", "fn f() { !(x == x &&<|> x) }") 76 check_assist(apply_demorgan, "fn f() { x != x ||<|> !x }", "fn f() { !(x == x && x) }")
77 } 77 }
78 78
79 #[test] 79 #[test]
80 fn demorgan_general_case() { 80 fn demorgan_general_case() {
81 check_assist(apply_demorgan, "fn f() { x ||<|> x }", "fn f() { !(!x &&<|> !x) }") 81 check_assist(apply_demorgan, "fn f() { x ||<|> x }", "fn f() { !(!x && !x) }")
82 } 82 }
83 83
84 #[test] 84 #[test]
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs
index f6d25579e..edf96d50e 100644
--- a/crates/ra_assists/src/handlers/auto_import.rs
+++ b/crates/ra_assists/src/handlers/auto_import.rs
@@ -298,7 +298,7 @@ mod tests {
298 } 298 }
299 ", 299 ",
300 r" 300 r"
301 <|>use PubMod::PubStruct; 301 use PubMod::PubStruct;
302 302
303 PubStruct 303 PubStruct
304 304
@@ -329,7 +329,7 @@ mod tests {
329 macro_rules! foo { 329 macro_rules! foo {
330 ($i:ident) => { fn foo(a: $i) {} } 330 ($i:ident) => { fn foo(a: $i) {} }
331 } 331 }
332 foo!(Pub<|>Struct); 332 foo!(PubStruct);
333 333
334 pub mod PubMod { 334 pub mod PubMod {
335 pub struct PubStruct; 335 pub struct PubStruct;
@@ -360,7 +360,7 @@ mod tests {
360 use PubMod::{PubStruct2, PubStruct1}; 360 use PubMod::{PubStruct2, PubStruct1};
361 361
362 struct Test { 362 struct Test {
363 test: Pub<|>Struct2<u8>, 363 test: PubStruct2<u8>,
364 } 364 }
365 365
366 pub mod PubMod { 366 pub mod PubMod {
@@ -393,7 +393,7 @@ mod tests {
393 r" 393 r"
394 use PubMod3::PubStruct; 394 use PubMod3::PubStruct;
395 395
396 PubSt<|>ruct 396 PubStruct
397 397
398 pub mod PubMod1 { 398 pub mod PubMod1 {
399 pub struct PubStruct; 399 pub struct PubStruct;
@@ -474,7 +474,7 @@ mod tests {
474 r" 474 r"
475 use PubMod::test_function; 475 use PubMod::test_function;
476 476
477 test_function<|> 477 test_function
478 478
479 pub mod PubMod { 479 pub mod PubMod {
480 pub fn test_function() {}; 480 pub fn test_function() {};
@@ -501,7 +501,7 @@ mod tests {
501 r"use crate_with_macro::foo; 501 r"use crate_with_macro::foo;
502 502
503fn main() { 503fn main() {
504 foo<|> 504 foo
505} 505}
506", 506",
507 ); 507 );
@@ -587,7 +587,7 @@ fn main() {
587 } 587 }
588 588
589 fn main() { 589 fn main() {
590 TestStruct::test_function<|> 590 TestStruct::test_function
591 } 591 }
592 ", 592 ",
593 ); 593 );
@@ -620,7 +620,7 @@ fn main() {
620 } 620 }
621 621
622 fn main() { 622 fn main() {
623 TestStruct::TEST_CONST<|> 623 TestStruct::TEST_CONST
624 } 624 }
625 ", 625 ",
626 ); 626 );
@@ -659,7 +659,7 @@ fn main() {
659 } 659 }
660 660
661 fn main() { 661 fn main() {
662 test_mod::TestStruct::test_function<|> 662 test_mod::TestStruct::test_function
663 } 663 }
664 ", 664 ",
665 ); 665 );
@@ -730,7 +730,7 @@ fn main() {
730 } 730 }
731 731
732 fn main() { 732 fn main() {
733 test_mod::TestStruct::TEST_CONST<|> 733 test_mod::TestStruct::TEST_CONST
734 } 734 }
735 ", 735 ",
736 ); 736 );
@@ -803,7 +803,7 @@ fn main() {
803 803
804 fn main() { 804 fn main() {
805 let test_struct = test_mod::TestStruct {}; 805 let test_struct = test_mod::TestStruct {};
806 test_struct.test_meth<|>od() 806 test_struct.test_method()
807 } 807 }
808 ", 808 ",
809 ); 809 );
diff --git a/crates/ra_assists/src/handlers/change_visibility.rs b/crates/ra_assists/src/handlers/change_visibility.rs
index 40cf4b422..c21d75be0 100644
--- a/crates/ra_assists/src/handlers/change_visibility.rs
+++ b/crates/ra_assists/src/handlers/change_visibility.rs
@@ -5,14 +5,11 @@ use ra_syntax::{
5 ATTR, COMMENT, CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY, 5 ATTR, COMMENT, CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY,
6 WHITESPACE, 6 WHITESPACE,
7 }, 7 },
8 SyntaxNode, TextRange, TextSize, T, 8 SyntaxNode, TextSize, T,
9}; 9};
10 10use test_utils::mark;
11use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution};
12use test_utils::tested_by;
13 11
14use crate::{AssistContext, AssistId, Assists}; 12use crate::{AssistContext, AssistId, Assists};
15use ra_db::FileId;
16 13
17// Assist: change_visibility 14// Assist: change_visibility
18// 15//
@@ -30,8 +27,6 @@ pub(crate) fn change_visibility(acc: &mut Assists, ctx: &AssistContext) -> Optio
30 return change_vis(acc, vis); 27 return change_vis(acc, vis);
31 } 28 }
32 add_vis(acc, ctx) 29 add_vis(acc, ctx)
33 .or_else(|| add_vis_to_referenced_module_def(acc, ctx))
34 .or_else(|| add_vis_to_referenced_record_field(acc, ctx))
35} 30}
36 31
37fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 32fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
@@ -55,7 +50,7 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
55 } else if let Some(field_name) = ctx.find_node_at_offset::<ast::Name>() { 50 } else if let Some(field_name) = ctx.find_node_at_offset::<ast::Name>() {
56 let field = field_name.syntax().ancestors().find_map(ast::RecordFieldDef::cast)?; 51 let field = field_name.syntax().ancestors().find_map(ast::RecordFieldDef::cast)?;
57 if field.name()? != field_name { 52 if field.name()? != field_name {
58 tested_by!(change_visibility_field_false_positive); 53 mark::hit!(change_visibility_field_false_positive);
59 return None; 54 return None;
60 } 55 }
61 if field.visibility().is_some() { 56 if field.visibility().is_some() {
@@ -73,147 +68,9 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
73 68
74 acc.add(AssistId("change_visibility"), "Change visibility to pub(crate)", target, |edit| { 69 acc.add(AssistId("change_visibility"), "Change visibility to pub(crate)", target, |edit| {
75 edit.insert(offset, "pub(crate) "); 70 edit.insert(offset, "pub(crate) ");
76 edit.set_cursor(offset);
77 })
78}
79
80fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
81 let path: ast::Path = ctx.find_node_at_offset()?;
82 let path_res = ctx.sema.resolve_path(&path)?;
83 let def = match path_res {
84 PathResolution::Def(def) => def,
85 _ => return None,
86 };
87
88 let current_module = ctx.sema.scope(&path.syntax()).module()?;
89 let target_module = def.module(ctx.db)?;
90
91 let vis = target_module.visibility_of(ctx.db, &def)?;
92 if vis.is_visible_from(ctx.db, current_module.into()) {
93 return None;
94 };
95
96 let (offset, target, target_file, target_name) = target_data_for_def(ctx.db, def)?;
97
98 let missing_visibility =
99 if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" };
100
101 let assist_label = match target_name {
102 None => format!("Change visibility to {}", missing_visibility),
103 Some(name) => format!("Change visibility of {} to {}", name, missing_visibility),
104 };
105
106 acc.add(AssistId("change_visibility"), assist_label, target, |edit| {
107 edit.set_file(target_file);
108 edit.insert(offset, format!("{} ", missing_visibility));
109 edit.set_cursor(offset);
110 })
111}
112
113fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
114 let record_field: ast::RecordField = ctx.find_node_at_offset()?;
115 let (record_field_def, _) = ctx.sema.resolve_record_field(&record_field)?;
116
117 let current_module = ctx.sema.scope(record_field.syntax()).module()?;
118 let visibility = record_field_def.visibility(ctx.db);
119 if visibility.is_visible_from(ctx.db, current_module.into()) {
120 return None;
121 }
122
123 let parent = record_field_def.parent_def(ctx.db);
124 let parent_name = parent.name(ctx.db);
125 let target_module = parent.module(ctx.db);
126
127 let in_file_source = record_field_def.source(ctx.db);
128 let (offset, target) = match in_file_source.value {
129 hir::FieldSource::Named(it) => {
130 let s = it.syntax();
131 (vis_offset(s), s.text_range())
132 }
133 hir::FieldSource::Pos(it) => {
134 let s = it.syntax();
135 (vis_offset(s), s.text_range())
136 }
137 };
138
139 let missing_visibility =
140 if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" };
141 let target_file = in_file_source.file_id.original_file(ctx.db);
142
143 let target_name = record_field_def.name(ctx.db);
144 let assist_label =
145 format!("Change visibility of {}.{} to {}", parent_name, target_name, missing_visibility);
146
147 acc.add(AssistId("change_visibility"), assist_label, target, |edit| {
148 edit.set_file(target_file);
149 edit.insert(offset, format!("{} ", missing_visibility));
150 edit.set_cursor(offset)
151 }) 71 })
152} 72}
153 73
154fn target_data_for_def(
155 db: &dyn HirDatabase,
156 def: hir::ModuleDef,
157) -> Option<(TextSize, TextRange, FileId, Option<hir::Name>)> {
158 fn offset_target_and_file_id<S, Ast>(
159 db: &dyn HirDatabase,
160 x: S,
161 ) -> (TextSize, TextRange, FileId)
162 where
163 S: HasSource<Ast = Ast>,
164 Ast: AstNode,
165 {
166 let source = x.source(db);
167 let in_file_syntax = source.syntax();
168 let file_id = in_file_syntax.file_id;
169 let syntax = in_file_syntax.value;
170 (vis_offset(syntax), syntax.text_range(), file_id.original_file(db.upcast()))
171 }
172
173 let target_name;
174 let (offset, target, target_file) = match def {
175 hir::ModuleDef::Function(f) => {
176 target_name = Some(f.name(db));
177 offset_target_and_file_id(db, f)
178 }
179 hir::ModuleDef::Adt(adt) => {
180 target_name = Some(adt.name(db));
181 match adt {
182 hir::Adt::Struct(s) => offset_target_and_file_id(db, s),
183 hir::Adt::Union(u) => offset_target_and_file_id(db, u),
184 hir::Adt::Enum(e) => offset_target_and_file_id(db, e),
185 }
186 }
187 hir::ModuleDef::Const(c) => {
188 target_name = c.name(db);
189 offset_target_and_file_id(db, c)
190 }
191 hir::ModuleDef::Static(s) => {
192 target_name = s.name(db);
193 offset_target_and_file_id(db, s)
194 }
195 hir::ModuleDef::Trait(t) => {
196 target_name = Some(t.name(db));
197 offset_target_and_file_id(db, t)
198 }
199 hir::ModuleDef::TypeAlias(t) => {
200 target_name = Some(t.name(db));
201 offset_target_and_file_id(db, t)
202 }
203 hir::ModuleDef::Module(m) => {
204 target_name = m.name(db);
205 let in_file_source = m.declaration_source(db)?;
206 let file_id = in_file_source.file_id.original_file(db.upcast());
207 let syntax = in_file_source.value.syntax();
208 (vis_offset(syntax), syntax.text_range(), file_id)
209 }
210 // Enum variants can't be private, we can't modify builtin types
211 hir::ModuleDef::EnumVariant(_) | hir::ModuleDef::BuiltinType(_) => return None,
212 };
213
214 Some((offset, target, target_file, target_name))
215}
216
217fn vis_offset(node: &SyntaxNode) -> TextSize { 74fn vis_offset(node: &SyntaxNode) -> TextSize {
218 node.children_with_tokens() 75 node.children_with_tokens()
219 .skip_while(|it| match it.kind() { 76 .skip_while(|it| match it.kind() {
@@ -234,7 +91,6 @@ fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
234 target, 91 target,
235 |edit| { 92 |edit| {
236 edit.replace(vis.syntax().text_range(), "pub(crate)"); 93 edit.replace(vis.syntax().text_range(), "pub(crate)");
237 edit.set_cursor(vis.syntax().text_range().start())
238 }, 94 },
239 ); 95 );
240 } 96 }
@@ -246,7 +102,6 @@ fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
246 target, 102 target,
247 |edit| { 103 |edit| {
248 edit.replace(vis.syntax().text_range(), "pub"); 104 edit.replace(vis.syntax().text_range(), "pub");
249 edit.set_cursor(vis.syntax().text_range().start());
250 }, 105 },
251 ); 106 );
252 } 107 }
@@ -255,7 +110,7 @@ fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
255 110
256#[cfg(test)] 111#[cfg(test)]
257mod tests { 112mod tests {
258 use test_utils::covers; 113 use test_utils::mark;
259 114
260 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; 115 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
261 116
@@ -263,17 +118,13 @@ mod tests {
263 118
264 #[test] 119 #[test]
265 fn change_visibility_adds_pub_crate_to_items() { 120 fn change_visibility_adds_pub_crate_to_items() {
266 check_assist(change_visibility, "<|>fn foo() {}", "<|>pub(crate) fn foo() {}"); 121 check_assist(change_visibility, "<|>fn foo() {}", "pub(crate) fn foo() {}");
267 check_assist(change_visibility, "f<|>n foo() {}", "<|>pub(crate) fn foo() {}"); 122 check_assist(change_visibility, "f<|>n foo() {}", "pub(crate) fn foo() {}");
268 check_assist(change_visibility, "<|>struct Foo {}", "<|>pub(crate) struct Foo {}"); 123 check_assist(change_visibility, "<|>struct Foo {}", "pub(crate) struct Foo {}");
269 check_assist(change_visibility, "<|>mod foo {}", "<|>pub(crate) mod foo {}"); 124 check_assist(change_visibility, "<|>mod foo {}", "pub(crate) mod foo {}");
270 check_assist(change_visibility, "<|>trait Foo {}", "<|>pub(crate) trait Foo {}"); 125 check_assist(change_visibility, "<|>trait Foo {}", "pub(crate) trait Foo {}");
271 check_assist(change_visibility, "m<|>od {}", "<|>pub(crate) mod {}"); 126 check_assist(change_visibility, "m<|>od {}", "pub(crate) mod {}");
272 check_assist( 127 check_assist(change_visibility, "unsafe f<|>n foo() {}", "pub(crate) unsafe fn foo() {}");
273 change_visibility,
274 "unsafe f<|>n foo() {}",
275 "<|>pub(crate) unsafe fn foo() {}",
276 );
277 } 128 }
278 129
279 #[test] 130 #[test]
@@ -281,14 +132,14 @@ mod tests {
281 check_assist( 132 check_assist(
282 change_visibility, 133 change_visibility,
283 r"struct S { <|>field: u32 }", 134 r"struct S { <|>field: u32 }",
284 r"struct S { <|>pub(crate) field: u32 }", 135 r"struct S { pub(crate) field: u32 }",
285 ); 136 );
286 check_assist(change_visibility, r"struct S ( <|>u32 )", r"struct S ( <|>pub(crate) u32 )"); 137 check_assist(change_visibility, r"struct S ( <|>u32 )", r"struct S ( pub(crate) u32 )");
287 } 138 }
288 139
289 #[test] 140 #[test]
290 fn change_visibility_field_false_positive() { 141 fn change_visibility_field_false_positive() {
291 covers!(change_visibility_field_false_positive); 142 mark::check!(change_visibility_field_false_positive);
292 check_assist_not_applicable( 143 check_assist_not_applicable(
293 change_visibility, 144 change_visibility,
294 r"struct S { field: [(); { let <|>x = ();}] }", 145 r"struct S { field: [(); { let <|>x = ();}] }",
@@ -297,17 +148,17 @@ mod tests {
297 148
298 #[test] 149 #[test]
299 fn change_visibility_pub_to_pub_crate() { 150 fn change_visibility_pub_to_pub_crate() {
300 check_assist(change_visibility, "<|>pub fn foo() {}", "<|>pub(crate) fn foo() {}") 151 check_assist(change_visibility, "<|>pub fn foo() {}", "pub(crate) fn foo() {}")
301 } 152 }
302 153
303 #[test] 154 #[test]
304 fn change_visibility_pub_crate_to_pub() { 155 fn change_visibility_pub_crate_to_pub() {
305 check_assist(change_visibility, "<|>pub(crate) fn foo() {}", "<|>pub fn foo() {}") 156 check_assist(change_visibility, "<|>pub(crate) fn foo() {}", "pub fn foo() {}")
306 } 157 }
307 158
308 #[test] 159 #[test]
309 fn change_visibility_const() { 160 fn change_visibility_const() {
310 check_assist(change_visibility, "<|>const FOO = 3u8;", "<|>pub(crate) const FOO = 3u8;"); 161 check_assist(change_visibility, "<|>const FOO = 3u8;", "pub(crate) const FOO = 3u8;");
311 } 162 }
312 163
313 #[test] 164 #[test]
@@ -328,199 +179,12 @@ mod tests {
328 // comments 179 // comments
329 180
330 #[derive(Debug)] 181 #[derive(Debug)]
331 <|>pub(crate) struct Foo; 182 pub(crate) struct Foo;
332 ", 183 ",
333 ) 184 )
334 } 185 }
335 186
336 #[test] 187 #[test]
337 fn change_visibility_of_fn_via_path() {
338 check_assist(
339 change_visibility,
340 r"mod foo { fn foo() {} }
341 fn main() { foo::foo<|>() } ",
342 r"mod foo { <|>pub(crate) fn foo() {} }
343 fn main() { foo::foo() } ",
344 );
345 check_assist_not_applicable(
346 change_visibility,
347 r"mod foo { pub fn foo() {} }
348 fn main() { foo::foo<|>() } ",
349 )
350 }
351
352 #[test]
353 fn change_visibility_of_adt_in_submodule_via_path() {
354 check_assist(
355 change_visibility,
356 r"mod foo { struct Foo; }
357 fn main() { foo::Foo<|> } ",
358 r"mod foo { <|>pub(crate) struct Foo; }
359 fn main() { foo::Foo } ",
360 );
361 check_assist_not_applicable(
362 change_visibility,
363 r"mod foo { pub struct Foo; }
364 fn main() { foo::Foo<|> } ",
365 );
366 check_assist(
367 change_visibility,
368 r"mod foo { enum Foo; }
369 fn main() { foo::Foo<|> } ",
370 r"mod foo { <|>pub(crate) enum Foo; }
371 fn main() { foo::Foo } ",
372 );
373 check_assist_not_applicable(
374 change_visibility,
375 r"mod foo { pub enum Foo; }
376 fn main() { foo::Foo<|> } ",
377 );
378 check_assist(
379 change_visibility,
380 r"mod foo { union Foo; }
381 fn main() { foo::Foo<|> } ",
382 r"mod foo { <|>pub(crate) union Foo; }
383 fn main() { foo::Foo } ",
384 );
385 check_assist_not_applicable(
386 change_visibility,
387 r"mod foo { pub union Foo; }
388 fn main() { foo::Foo<|> } ",
389 );
390 }
391
392 #[test]
393 fn change_visibility_of_adt_in_other_file_via_path() {
394 check_assist(
395 change_visibility,
396 r"
397 //- /main.rs
398 mod foo;
399 fn main() { foo::Foo<|> }
400
401 //- /foo.rs
402 struct Foo;
403 ",
404 r"<|>pub(crate) struct Foo;
405
406",
407 );
408 }
409
410 #[test]
411 fn change_visibility_of_struct_field_via_path() {
412 check_assist(
413 change_visibility,
414 r"mod foo { pub struct Foo { bar: (), } }
415 fn main() { foo::Foo { <|>bar: () }; } ",
416 r"mod foo { pub struct Foo { <|>pub(crate) bar: (), } }
417 fn main() { foo::Foo { bar: () }; } ",
418 );
419 check_assist(
420 change_visibility,
421 r"//- /lib.rs
422 mod foo;
423 fn main() { foo::Foo { <|>bar: () }; }
424 //- /foo.rs
425 pub struct Foo { bar: () }
426 ",
427 r"pub struct Foo { <|>pub(crate) bar: () }
428
429",
430 );
431 check_assist_not_applicable(
432 change_visibility,
433 r"mod foo { pub struct Foo { pub bar: (), } }
434 fn main() { foo::Foo { <|>bar: () }; } ",
435 );
436 check_assist_not_applicable(
437 change_visibility,
438 r"//- /lib.rs
439 mod foo;
440 fn main() { foo::Foo { <|>bar: () }; }
441 //- /foo.rs
442 pub struct Foo { pub bar: () }
443 ",
444 );
445 }
446
447 #[test]
448 fn change_visibility_of_enum_variant_field_via_path() {
449 check_assist(
450 change_visibility,
451 r"mod foo { pub enum Foo { Bar { bar: () } } }
452 fn main() { foo::Foo::Bar { <|>bar: () }; } ",
453 r"mod foo { pub enum Foo { Bar { <|>pub(crate) bar: () } } }
454 fn main() { foo::Foo::Bar { bar: () }; } ",
455 );
456 check_assist(
457 change_visibility,
458 r"//- /lib.rs
459 mod foo;
460 fn main() { foo::Foo::Bar { <|>bar: () }; }
461 //- /foo.rs
462 pub enum Foo { Bar { bar: () } }
463 ",
464 r"pub enum Foo { Bar { <|>pub(crate) bar: () } }
465
466",
467 );
468 check_assist_not_applicable(
469 change_visibility,
470 r"mod foo { pub struct Foo { pub bar: (), } }
471 fn main() { foo::Foo { <|>bar: () }; } ",
472 );
473 check_assist_not_applicable(
474 change_visibility,
475 r"//- /lib.rs
476 mod foo;
477 fn main() { foo::Foo { <|>bar: () }; }
478 //- /foo.rs
479 pub struct Foo { pub bar: () }
480 ",
481 );
482 }
483
484 #[test]
485 #[ignore]
486 // FIXME reenable this test when `Semantics::resolve_record_field` works with union fields
487 fn change_visibility_of_union_field_via_path() {
488 check_assist(
489 change_visibility,
490 r"mod foo { pub union Foo { bar: (), } }
491 fn main() { foo::Foo { <|>bar: () }; } ",
492 r"mod foo { pub union Foo { <|>pub(crate) bar: (), } }
493 fn main() { foo::Foo { bar: () }; } ",
494 );
495 check_assist(
496 change_visibility,
497 r"//- /lib.rs
498 mod foo;
499 fn main() { foo::Foo { <|>bar: () }; }
500 //- /foo.rs
501 pub union Foo { bar: () }
502 ",
503 r"pub union Foo { <|>pub(crate) bar: () }
504
505",
506 );
507 check_assist_not_applicable(
508 change_visibility,
509 r"mod foo { pub union Foo { pub bar: (), } }
510 fn main() { foo::Foo { <|>bar: () }; } ",
511 );
512 check_assist_not_applicable(
513 change_visibility,
514 r"//- /lib.rs
515 mod foo;
516 fn main() { foo::Foo { <|>bar: () }; }
517 //- /foo.rs
518 pub union Foo { pub bar: () }
519 ",
520 );
521 }
522
523 #[test]
524 fn not_applicable_for_enum_variants() { 188 fn not_applicable_for_enum_variants() {
525 check_assist_not_applicable( 189 check_assist_not_applicable(
526 change_visibility, 190 change_visibility,
@@ -530,182 +194,6 @@ mod tests {
530 } 194 }
531 195
532 #[test] 196 #[test]
533 fn change_visibility_of_const_via_path() {
534 check_assist(
535 change_visibility,
536 r"mod foo { const FOO: () = (); }
537 fn main() { foo::FOO<|> } ",
538 r"mod foo { <|>pub(crate) const FOO: () = (); }
539 fn main() { foo::FOO } ",
540 );
541 check_assist_not_applicable(
542 change_visibility,
543 r"mod foo { pub const FOO: () = (); }
544 fn main() { foo::FOO<|> } ",
545 );
546 }
547
548 #[test]
549 fn change_visibility_of_static_via_path() {
550 check_assist(
551 change_visibility,
552 r"mod foo { static FOO: () = (); }
553 fn main() { foo::FOO<|> } ",
554 r"mod foo { <|>pub(crate) static FOO: () = (); }
555 fn main() { foo::FOO } ",
556 );
557 check_assist_not_applicable(
558 change_visibility,
559 r"mod foo { pub static FOO: () = (); }
560 fn main() { foo::FOO<|> } ",
561 );
562 }
563
564 #[test]
565 fn change_visibility_of_trait_via_path() {
566 check_assist(
567 change_visibility,
568 r"mod foo { trait Foo { fn foo(&self) {} } }
569 fn main() { let x: &dyn foo::<|>Foo; } ",
570 r"mod foo { <|>pub(crate) trait Foo { fn foo(&self) {} } }
571 fn main() { let x: &dyn foo::Foo; } ",
572 );
573 check_assist_not_applicable(
574 change_visibility,
575 r"mod foo { pub trait Foo { fn foo(&self) {} } }
576 fn main() { let x: &dyn foo::Foo<|>; } ",
577 );
578 }
579
580 #[test]
581 fn change_visibility_of_type_alias_via_path() {
582 check_assist(
583 change_visibility,
584 r"mod foo { type Foo = (); }
585 fn main() { let x: foo::Foo<|>; } ",
586 r"mod foo { <|>pub(crate) type Foo = (); }
587 fn main() { let x: foo::Foo; } ",
588 );
589 check_assist_not_applicable(
590 change_visibility,
591 r"mod foo { pub type Foo = (); }
592 fn main() { let x: foo::Foo<|>; } ",
593 );
594 }
595
596 #[test]
597 fn change_visibility_of_module_via_path() {
598 check_assist(
599 change_visibility,
600 r"mod foo { mod bar { fn bar() {} } }
601 fn main() { foo::bar<|>::bar(); } ",
602 r"mod foo { <|>pub(crate) mod bar { fn bar() {} } }
603 fn main() { foo::bar::bar(); } ",
604 );
605
606 check_assist(
607 change_visibility,
608 r"
609 //- /main.rs
610 mod foo;
611 fn main() { foo::bar<|>::baz(); }
612
613 //- /foo.rs
614 mod bar {
615 pub fn baz() {}
616 }
617 ",
618 r"<|>pub(crate) mod bar {
619 pub fn baz() {}
620}
621
622",
623 );
624
625 check_assist_not_applicable(
626 change_visibility,
627 r"mod foo { pub mod bar { pub fn bar() {} } }
628 fn main() { foo::bar<|>::bar(); } ",
629 );
630 }
631
632 #[test]
633 fn change_visibility_of_inline_module_in_other_file_via_path() {
634 check_assist(
635 change_visibility,
636 r"
637 //- /main.rs
638 mod foo;
639 fn main() { foo::bar<|>::baz(); }
640
641 //- /foo.rs
642 mod bar;
643
644 //- /foo/bar.rs
645 pub fn baz() {}
646 }
647 ",
648 r"<|>pub(crate) mod bar;
649",
650 );
651 }
652
653 #[test]
654 fn change_visibility_of_module_declaration_in_other_file_via_path() {
655 check_assist(
656 change_visibility,
657 r"//- /main.rs
658 mod foo;
659 fn main() { foo::bar<|>>::baz(); }
660
661 //- /foo.rs
662 mod bar {
663 pub fn baz() {}
664 }",
665 r"<|>pub(crate) mod bar {
666 pub fn baz() {}
667}
668",
669 );
670 }
671
672 #[test]
673 #[ignore]
674 // FIXME handle reexports properly
675 fn change_visibility_of_reexport() {
676 check_assist(
677 change_visibility,
678 r"
679 mod foo {
680 use bar::Baz;
681 mod bar { pub(super) struct Baz; }
682 }
683 foo::Baz<|>
684 ",
685 r"
686 mod foo {
687 <|>pub(crate) use bar::Baz;
688 mod bar { pub(super) struct Baz; }
689 }
690 foo::Baz
691 ",
692 )
693 }
694
695 #[test]
696 fn adds_pub_when_target_is_in_another_crate() {
697 check_assist(
698 change_visibility,
699 r"//- /main.rs crate:a deps:foo
700 foo::Bar<|>
701 //- /lib.rs crate:foo
702 struct Bar;",
703 r"<|>pub struct Bar;
704",
705 )
706 }
707
708 #[test]
709 fn change_visibility_target() { 197 fn change_visibility_target() {
710 check_assist_target(change_visibility, "<|>fn foo() {}", "fn"); 198 check_assist_target(change_visibility, "<|>fn foo() {}", "fn");
711 check_assist_target(change_visibility, "pub(crate)<|> fn foo() {}", "pub(crate)"); 199 check_assist_target(change_visibility, "pub(crate)<|> fn foo() {}", "pub(crate)");
diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs
index 66b296081..4cc75a7ce 100644
--- a/crates/ra_assists/src/handlers/early_return.rs
+++ b/crates/ra_assists/src/handlers/early_return.rs
@@ -97,7 +97,6 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
97 } 97 }
98 98
99 then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; 99 then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?;
100 let cursor_position = ctx.offset();
101 100
102 let target = if_expr.syntax().text_range(); 101 let target = if_expr.syntax().text_range();
103 acc.add(AssistId("convert_to_guarded_return"), "Convert to guarded return", target, |edit| { 102 acc.add(AssistId("convert_to_guarded_return"), "Convert to guarded return", target, |edit| {
@@ -148,7 +147,6 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
148 } 147 }
149 }; 148 };
150 edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap()); 149 edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap());
151 edit.set_cursor(cursor_position);
152 150
153 fn replace( 151 fn replace(
154 new_expr: &SyntaxNode, 152 new_expr: &SyntaxNode,
@@ -207,7 +205,7 @@ mod tests {
207 r#" 205 r#"
208 fn main() { 206 fn main() {
209 bar(); 207 bar();
210 if<|> !true { 208 if !true {
211 return; 209 return;
212 } 210 }
213 foo(); 211 foo();
@@ -237,7 +235,7 @@ mod tests {
237 r#" 235 r#"
238 fn main(n: Option<String>) { 236 fn main(n: Option<String>) {
239 bar(); 237 bar();
240 le<|>t n = match n { 238 let n = match n {
241 Some(it) => it, 239 Some(it) => it,
242 _ => return, 240 _ => return,
243 }; 241 };
@@ -263,7 +261,7 @@ mod tests {
263 "#, 261 "#,
264 r#" 262 r#"
265 fn main() { 263 fn main() {
266 le<|>t x = match Err(92) { 264 let x = match Err(92) {
267 Ok(it) => it, 265 Ok(it) => it,
268 _ => return, 266 _ => return,
269 }; 267 };
@@ -291,7 +289,7 @@ mod tests {
291 r#" 289 r#"
292 fn main(n: Option<String>) { 290 fn main(n: Option<String>) {
293 bar(); 291 bar();
294 le<|>t n = match n { 292 let n = match n {
295 Ok(it) => it, 293 Ok(it) => it,
296 _ => return, 294 _ => return,
297 }; 295 };
@@ -321,7 +319,7 @@ mod tests {
321 r#" 319 r#"
322 fn main() { 320 fn main() {
323 while true { 321 while true {
324 if<|> !true { 322 if !true {
325 continue; 323 continue;
326 } 324 }
327 foo(); 325 foo();
@@ -349,7 +347,7 @@ mod tests {
349 r#" 347 r#"
350 fn main() { 348 fn main() {
351 while true { 349 while true {
352 le<|>t n = match n { 350 let n = match n {
353 Some(it) => it, 351 Some(it) => it,
354 _ => continue, 352 _ => continue,
355 }; 353 };
@@ -378,7 +376,7 @@ mod tests {
378 r#" 376 r#"
379 fn main() { 377 fn main() {
380 loop { 378 loop {
381 if<|> !true { 379 if !true {
382 continue; 380 continue;
383 } 381 }
384 foo(); 382 foo();
@@ -406,7 +404,7 @@ mod tests {
406 r#" 404 r#"
407 fn main() { 405 fn main() {
408 loop { 406 loop {
409 le<|>t n = match n { 407 let n = match n {
410 Some(it) => it, 408 Some(it) => it,
411 _ => continue, 409 _ => continue,
412 }; 410 };
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs
index b57ff75ae..cc303285b 100644
--- a/crates/ra_assists/src/handlers/fill_match_arms.rs
+++ b/crates/ra_assists/src/handlers/fill_match_arms.rs
@@ -4,9 +4,12 @@ use hir::{Adt, HasSource, ModuleDef, Semantics};
4use itertools::Itertools; 4use itertools::Itertools;
5use ra_ide_db::RootDatabase; 5use ra_ide_db::RootDatabase;
6use ra_syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat}; 6use ra_syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat};
7use test_utils::tested_by; 7use test_utils::mark;
8 8
9use crate::{utils::FamousDefs, AssistContext, AssistId, Assists}; 9use crate::{
10 utils::{render_snippet, Cursor, FamousDefs},
11 AssistContext, AssistId, Assists,
12};
10 13
11// Assist: fill_match_arms 14// Assist: fill_match_arms
12// 15//
@@ -27,7 +30,7 @@ use crate::{utils::FamousDefs, AssistContext, AssistId, Assists};
27// 30//
28// fn handle(action: Action) { 31// fn handle(action: Action) {
29// match action { 32// match action {
30// Action::Move { distance } => {} 33// $0Action::Move { distance } => {}
31// Action::Stop => {} 34// Action::Stop => {}
32// } 35// }
33// } 36// }
@@ -58,7 +61,7 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
58 .collect::<Vec<_>>(); 61 .collect::<Vec<_>>();
59 if Some(enum_def) == FamousDefs(&ctx.sema, module.krate()).core_option_Option() { 62 if Some(enum_def) == FamousDefs(&ctx.sema, module.krate()).core_option_Option() {
60 // Match `Some` variant first. 63 // Match `Some` variant first.
61 tested_by!(option_order); 64 mark::hit!(option_order);
62 variants.reverse() 65 variants.reverse()
63 } 66 }
64 variants 67 variants
@@ -100,10 +103,23 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
100 } 103 }
101 104
102 let target = match_expr.syntax().text_range(); 105 let target = match_expr.syntax().text_range();
103 acc.add(AssistId("fill_match_arms"), "Fill match arms", target, |edit| { 106 acc.add(AssistId("fill_match_arms"), "Fill match arms", target, |builder| {
104 let new_arm_list = match_arm_list.remove_placeholder().append_arms(missing_arms); 107 let new_arm_list = match_arm_list.remove_placeholder();
105 edit.set_cursor(expr.syntax().text_range().start()); 108 let n_old_arms = new_arm_list.arms().count();
106 edit.replace_ast(match_arm_list, new_arm_list); 109 let new_arm_list = new_arm_list.append_arms(missing_arms);
110 let first_new_arm = new_arm_list.arms().nth(n_old_arms);
111 let old_range = match_arm_list.syntax().text_range();
112 match (first_new_arm, ctx.config.snippet_cap) {
113 (Some(first_new_arm), Some(cap)) => {
114 let snippet = render_snippet(
115 cap,
116 new_arm_list.syntax(),
117 Cursor::Before(first_new_arm.syntax()),
118 );
119 builder.replace_snippet(cap, old_range, snippet);
120 }
121 _ => builder.replace(old_range, new_arm_list.to_string()),
122 }
107 }) 123 })
108} 124}
109 125
@@ -174,13 +190,14 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> O
174 190
175#[cfg(test)] 191#[cfg(test)]
176mod tests { 192mod tests {
193 use test_utils::mark;
194
177 use crate::{ 195 use crate::{
178 tests::{check_assist, check_assist_not_applicable, check_assist_target}, 196 tests::{check_assist, check_assist_not_applicable, check_assist_target},
179 utils::FamousDefs, 197 utils::FamousDefs,
180 }; 198 };
181 199
182 use super::fill_match_arms; 200 use super::fill_match_arms;
183 use test_utils::covers;
184 201
185 #[test] 202 #[test]
186 fn all_match_arms_provided() { 203 fn all_match_arms_provided() {
@@ -225,12 +242,12 @@ mod tests {
225 r#" 242 r#"
226 enum A { 243 enum A {
227 As, 244 As,
228 Bs{x:i32, y:Option<i32>}, 245 Bs { x: i32, y: Option<i32> },
229 Cs(i32, Option<i32>), 246 Cs(i32, Option<i32>),
230 } 247 }
231 fn main() { 248 fn main() {
232 match A::As<|> { 249 match A::As<|> {
233 A::Bs{x,y:Some(_)} => {} 250 A::Bs { x, y: Some(_) } => {}
234 A::Cs(_, Some(_)) => {} 251 A::Cs(_, Some(_)) => {}
235 } 252 }
236 } 253 }
@@ -238,14 +255,14 @@ mod tests {
238 r#" 255 r#"
239 enum A { 256 enum A {
240 As, 257 As,
241 Bs{x:i32, y:Option<i32>}, 258 Bs { x: i32, y: Option<i32> },
242 Cs(i32, Option<i32>), 259 Cs(i32, Option<i32>),
243 } 260 }
244 fn main() { 261 fn main() {
245 match <|>A::As { 262 match A::As {
246 A::Bs{x,y:Some(_)} => {} 263 A::Bs { x, y: Some(_) } => {}
247 A::Cs(_, Some(_)) => {} 264 A::Cs(_, Some(_)) => {}
248 A::As => {} 265 $0A::As => {}
249 } 266 }
250 } 267 }
251 "#, 268 "#,
@@ -275,9 +292,9 @@ mod tests {
275 Cs(Option<i32>), 292 Cs(Option<i32>),
276 } 293 }
277 fn main() { 294 fn main() {
278 match <|>A::As { 295 match A::As {
279 A::Cs(_) | A::Bs => {} 296 A::Cs(_) | A::Bs => {}
280 A::As => {} 297 $0A::As => {}
281 } 298 }
282 } 299 }
283 "#, 300 "#,
@@ -321,11 +338,11 @@ mod tests {
321 Ys, 338 Ys,
322 } 339 }
323 fn main() { 340 fn main() {
324 match <|>A::As { 341 match A::As {
325 A::Bs if 0 < 1 => {} 342 A::Bs if 0 < 1 => {}
326 A::Ds(_value) => { let x = 1; } 343 A::Ds(_value) => { let x = 1; }
327 A::Es(B::Xs) => (), 344 A::Es(B::Xs) => (),
328 A::As => {} 345 $0A::As => {}
329 A::Cs => {} 346 A::Cs => {}
330 } 347 }
331 } 348 }
@@ -343,7 +360,7 @@ mod tests {
343 Bs, 360 Bs,
344 Cs(String), 361 Cs(String),
345 Ds(String, String), 362 Ds(String, String),
346 Es{ x: usize, y: usize } 363 Es { x: usize, y: usize }
347 } 364 }
348 365
349 fn main() { 366 fn main() {
@@ -357,13 +374,13 @@ mod tests {
357 Bs, 374 Bs,
358 Cs(String), 375 Cs(String),
359 Ds(String, String), 376 Ds(String, String),
360 Es{ x: usize, y: usize } 377 Es { x: usize, y: usize }
361 } 378 }
362 379
363 fn main() { 380 fn main() {
364 let a = A::As; 381 let a = A::As;
365 match <|>a { 382 match a {
366 A::As => {} 383 $0A::As => {}
367 A::Bs => {} 384 A::Bs => {}
368 A::Cs(_) => {} 385 A::Cs(_) => {}
369 A::Ds(_, _) => {} 386 A::Ds(_, _) => {}
@@ -379,14 +396,8 @@ mod tests {
379 check_assist( 396 check_assist(
380 fill_match_arms, 397 fill_match_arms,
381 r#" 398 r#"
382 enum A { 399 enum A { One, Two }
383 One, 400 enum B { One, Two }
384 Two,
385 }
386 enum B {
387 One,
388 Two,
389 }
390 401
391 fn main() { 402 fn main() {
392 let a = A::One; 403 let a = A::One;
@@ -395,20 +406,14 @@ mod tests {
395 } 406 }
396 "#, 407 "#,
397 r#" 408 r#"
398 enum A { 409 enum A { One, Two }
399 One, 410 enum B { One, Two }
400 Two,
401 }
402 enum B {
403 One,
404 Two,
405 }
406 411
407 fn main() { 412 fn main() {
408 let a = A::One; 413 let a = A::One;
409 let b = B::One; 414 let b = B::One;
410 match <|>(a, b) { 415 match (a, b) {
411 (A::One, B::One) => {} 416 $0(A::One, B::One) => {}
412 (A::One, B::Two) => {} 417 (A::One, B::Two) => {}
413 (A::Two, B::One) => {} 418 (A::Two, B::One) => {}
414 (A::Two, B::Two) => {} 419 (A::Two, B::Two) => {}
@@ -423,14 +428,8 @@ mod tests {
423 check_assist( 428 check_assist(
424 fill_match_arms, 429 fill_match_arms,
425 r#" 430 r#"
426 enum A { 431 enum A { One, Two }
427 One, 432 enum B { One, Two }
428 Two,
429 }
430 enum B {
431 One,
432 Two,
433 }
434 433
435 fn main() { 434 fn main() {
436 let a = A::One; 435 let a = A::One;
@@ -439,20 +438,14 @@ mod tests {
439 } 438 }
440 "#, 439 "#,
441 r#" 440 r#"
442 enum A { 441 enum A { One, Two }
443 One, 442 enum B { One, Two }
444 Two,
445 }
446 enum B {
447 One,
448 Two,
449 }
450 443
451 fn main() { 444 fn main() {
452 let a = A::One; 445 let a = A::One;
453 let b = B::One; 446 let b = B::One;
454 match <|>(&a, &b) { 447 match (&a, &b) {
455 (A::One, B::One) => {} 448 $0(A::One, B::One) => {}
456 (A::One, B::Two) => {} 449 (A::One, B::Two) => {}
457 (A::Two, B::One) => {} 450 (A::Two, B::One) => {}
458 (A::Two, B::Two) => {} 451 (A::Two, B::Two) => {}
@@ -467,14 +460,8 @@ mod tests {
467 check_assist_not_applicable( 460 check_assist_not_applicable(
468 fill_match_arms, 461 fill_match_arms,
469 r#" 462 r#"
470 enum A { 463 enum A { One, Two }
471 One, 464 enum B { One, Two }
472 Two,
473 }
474 enum B {
475 One,
476 Two,
477 }
478 465
479 fn main() { 466 fn main() {
480 let a = A::One; 467 let a = A::One;
@@ -492,14 +479,8 @@ mod tests {
492 check_assist_not_applicable( 479 check_assist_not_applicable(
493 fill_match_arms, 480 fill_match_arms,
494 r#" 481 r#"
495 enum A { 482 enum A { One, Two }
496 One, 483 enum B { One, Two }
497 Two,
498 }
499 enum B {
500 One,
501 Two,
502 }
503 484
504 fn main() { 485 fn main() {
505 let a = A::One; 486 let a = A::One;
@@ -523,10 +504,7 @@ mod tests {
523 check_assist_not_applicable( 504 check_assist_not_applicable(
524 fill_match_arms, 505 fill_match_arms,
525 r#" 506 r#"
526 enum A { 507 enum A { One, Two }
527 One,
528 Two,
529 }
530 508
531 fn main() { 509 fn main() {
532 let a = A::One; 510 let a = A::One;
@@ -542,9 +520,7 @@ mod tests {
542 check_assist( 520 check_assist(
543 fill_match_arms, 521 fill_match_arms,
544 r#" 522 r#"
545 enum A { 523 enum A { As }
546 As,
547 }
548 524
549 fn foo(a: &A) { 525 fn foo(a: &A) {
550 match a<|> { 526 match a<|> {
@@ -552,13 +528,11 @@ mod tests {
552 } 528 }
553 "#, 529 "#,
554 r#" 530 r#"
555 enum A { 531 enum A { As }
556 As,
557 }
558 532
559 fn foo(a: &A) { 533 fn foo(a: &A) {
560 match <|>a { 534 match a {
561 A::As => {} 535 $0A::As => {}
562 } 536 }
563 } 537 }
564 "#, 538 "#,
@@ -568,7 +542,7 @@ mod tests {
568 fill_match_arms, 542 fill_match_arms,
569 r#" 543 r#"
570 enum A { 544 enum A {
571 Es{ x: usize, y: usize } 545 Es { x: usize, y: usize }
572 } 546 }
573 547
574 fn foo(a: &mut A) { 548 fn foo(a: &mut A) {
@@ -578,12 +552,12 @@ mod tests {
578 "#, 552 "#,
579 r#" 553 r#"
580 enum A { 554 enum A {
581 Es{ x: usize, y: usize } 555 Es { x: usize, y: usize }
582 } 556 }
583 557
584 fn foo(a: &mut A) { 558 fn foo(a: &mut A) {
585 match <|>a { 559 match a {
586 A::Es { x, y } => {} 560 $0A::Es { x, y } => {}
587 } 561 }
588 } 562 }
589 "#, 563 "#,
@@ -622,8 +596,8 @@ mod tests {
622 enum E { X, Y } 596 enum E { X, Y }
623 597
624 fn main() { 598 fn main() {
625 match <|>E::X { 599 match E::X {
626 E::X => {} 600 $0E::X => {}
627 E::Y => {} 601 E::Y => {}
628 } 602 }
629 } 603 }
@@ -650,8 +624,8 @@ mod tests {
650 use foo::E::X; 624 use foo::E::X;
651 625
652 fn main() { 626 fn main() {
653 match <|>X { 627 match X {
654 X => {} 628 $0X => {}
655 foo::E::Y => {} 629 foo::E::Y => {}
656 } 630 }
657 } 631 }
@@ -664,10 +638,7 @@ mod tests {
664 check_assist( 638 check_assist(
665 fill_match_arms, 639 fill_match_arms,
666 r#" 640 r#"
667 enum A { 641 enum A { One, Two }
668 One,
669 Two,
670 }
671 fn foo(a: A) { 642 fn foo(a: A) {
672 match a { 643 match a {
673 // foo bar baz<|> 644 // foo bar baz<|>
@@ -677,16 +648,13 @@ mod tests {
677 } 648 }
678 "#, 649 "#,
679 r#" 650 r#"
680 enum A { 651 enum A { One, Two }
681 One,
682 Two,
683 }
684 fn foo(a: A) { 652 fn foo(a: A) {
685 match <|>a { 653 match a {
686 // foo bar baz 654 // foo bar baz
687 A::One => {} 655 A::One => {}
688 // This is where the rest should be 656 // This is where the rest should be
689 A::Two => {} 657 $0A::Two => {}
690 } 658 }
691 } 659 }
692 "#, 660 "#,
@@ -698,10 +666,7 @@ mod tests {
698 check_assist( 666 check_assist(
699 fill_match_arms, 667 fill_match_arms,
700 r#" 668 r#"
701 enum A { 669 enum A { One, Two }
702 One,
703 Two,
704 }
705 fn foo(a: A) { 670 fn foo(a: A) {
706 match a { 671 match a {
707 // foo bar baz<|> 672 // foo bar baz<|>
@@ -709,14 +674,11 @@ mod tests {
709 } 674 }
710 "#, 675 "#,
711 r#" 676 r#"
712 enum A { 677 enum A { One, Two }
713 One,
714 Two,
715 }
716 fn foo(a: A) { 678 fn foo(a: A) {
717 match <|>a { 679 match a {
718 // foo bar baz 680 // foo bar baz
719 A::One => {} 681 $0A::One => {}
720 A::Two => {} 682 A::Two => {}
721 } 683 }
722 } 684 }
@@ -739,8 +701,8 @@ mod tests {
739 r#" 701 r#"
740 enum A { One, Two, } 702 enum A { One, Two, }
741 fn foo(a: A) { 703 fn foo(a: A) {
742 match <|>a { 704 match a {
743 A::One => {} 705 $0A::One => {}
744 A::Two => {} 706 A::Two => {}
745 } 707 }
746 } 708 }
@@ -750,7 +712,7 @@ mod tests {
750 712
751 #[test] 713 #[test]
752 fn option_order() { 714 fn option_order() {
753 covers!(option_order); 715 mark::check!(option_order);
754 let before = r#" 716 let before = r#"
755fn foo(opt: Option<i32>) { 717fn foo(opt: Option<i32>) {
756 match opt<|> { 718 match opt<|> {
@@ -764,8 +726,8 @@ fn foo(opt: Option<i32>) {
764 before, 726 before,
765 r#" 727 r#"
766fn foo(opt: Option<i32>) { 728fn foo(opt: Option<i32>) {
767 match <|>opt { 729 match opt {
768 Some(_) => {} 730 $0Some(_) => {}
769 None => {} 731 None => {}
770 } 732 }
771} 733}
diff --git a/crates/ra_assists/src/handlers/fix_visibility.rs b/crates/ra_assists/src/handlers/fix_visibility.rs
new file mode 100644
index 000000000..9ec42f568
--- /dev/null
+++ b/crates/ra_assists/src/handlers/fix_visibility.rs
@@ -0,0 +1,559 @@
1use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution};
2use ra_db::FileId;
3use ra_syntax::{
4 ast, AstNode,
5 SyntaxKind::{ATTR, COMMENT, WHITESPACE},
6 SyntaxNode, TextRange, TextSize,
7};
8
9use crate::{AssistContext, AssistId, Assists};
10
11// FIXME: this really should be a fix for diagnostic, rather than an assist.
12
13// Assist: fix_visibility
14//
15// Makes inaccessible item public.
16//
17// ```
18// mod m {
19// fn frobnicate() {}
20// }
21// fn main() {
22// m::frobnicate<|>() {}
23// }
24// ```
25// ->
26// ```
27// mod m {
28// $0pub(crate) fn frobnicate() {}
29// }
30// fn main() {
31// m::frobnicate() {}
32// }
33// ```
34pub(crate) fn fix_visibility(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
35 add_vis_to_referenced_module_def(acc, ctx)
36 .or_else(|| add_vis_to_referenced_record_field(acc, ctx))
37}
38
39fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
40 let path: ast::Path = ctx.find_node_at_offset()?;
41 let path_res = ctx.sema.resolve_path(&path)?;
42 let def = match path_res {
43 PathResolution::Def(def) => def,
44 _ => return None,
45 };
46
47 let current_module = ctx.sema.scope(&path.syntax()).module()?;
48 let target_module = def.module(ctx.db)?;
49
50 let vis = target_module.visibility_of(ctx.db, &def)?;
51 if vis.is_visible_from(ctx.db, current_module.into()) {
52 return None;
53 };
54
55 let (offset, target, target_file, target_name) = target_data_for_def(ctx.db, def)?;
56
57 let missing_visibility =
58 if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" };
59
60 let assist_label = match target_name {
61 None => format!("Change visibility to {}", missing_visibility),
62 Some(name) => format!("Change visibility of {} to {}", name, missing_visibility),
63 };
64
65 acc.add(AssistId("fix_visibility"), assist_label, target, |builder| {
66 builder.set_file(target_file);
67 match ctx.config.snippet_cap {
68 Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)),
69 None => builder.insert(offset, format!("{} ", missing_visibility)),
70 }
71 })
72}
73
74fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
75 let record_field: ast::RecordField = ctx.find_node_at_offset()?;
76 let (record_field_def, _) = ctx.sema.resolve_record_field(&record_field)?;
77
78 let current_module = ctx.sema.scope(record_field.syntax()).module()?;
79 let visibility = record_field_def.visibility(ctx.db);
80 if visibility.is_visible_from(ctx.db, current_module.into()) {
81 return None;
82 }
83
84 let parent = record_field_def.parent_def(ctx.db);
85 let parent_name = parent.name(ctx.db);
86 let target_module = parent.module(ctx.db);
87
88 let in_file_source = record_field_def.source(ctx.db);
89 let (offset, target) = match in_file_source.value {
90 hir::FieldSource::Named(it) => {
91 let s = it.syntax();
92 (vis_offset(s), s.text_range())
93 }
94 hir::FieldSource::Pos(it) => {
95 let s = it.syntax();
96 (vis_offset(s), s.text_range())
97 }
98 };
99
100 let missing_visibility =
101 if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" };
102 let target_file = in_file_source.file_id.original_file(ctx.db);
103
104 let target_name = record_field_def.name(ctx.db);
105 let assist_label =
106 format!("Change visibility of {}.{} to {}", parent_name, target_name, missing_visibility);
107
108 acc.add(AssistId("fix_visibility"), assist_label, target, |builder| {
109 builder.set_file(target_file);
110 match ctx.config.snippet_cap {
111 Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)),
112 None => builder.insert(offset, format!("{} ", missing_visibility)),
113 }
114 })
115}
116
117fn target_data_for_def(
118 db: &dyn HirDatabase,
119 def: hir::ModuleDef,
120) -> Option<(TextSize, TextRange, FileId, Option<hir::Name>)> {
121 fn offset_target_and_file_id<S, Ast>(
122 db: &dyn HirDatabase,
123 x: S,
124 ) -> (TextSize, TextRange, FileId)
125 where
126 S: HasSource<Ast = Ast>,
127 Ast: AstNode,
128 {
129 let source = x.source(db);
130 let in_file_syntax = source.syntax();
131 let file_id = in_file_syntax.file_id;
132 let syntax = in_file_syntax.value;
133 (vis_offset(syntax), syntax.text_range(), file_id.original_file(db.upcast()))
134 }
135
136 let target_name;
137 let (offset, target, target_file) = match def {
138 hir::ModuleDef::Function(f) => {
139 target_name = Some(f.name(db));
140 offset_target_and_file_id(db, f)
141 }
142 hir::ModuleDef::Adt(adt) => {
143 target_name = Some(adt.name(db));
144 match adt {
145 hir::Adt::Struct(s) => offset_target_and_file_id(db, s),
146 hir::Adt::Union(u) => offset_target_and_file_id(db, u),
147 hir::Adt::Enum(e) => offset_target_and_file_id(db, e),
148 }
149 }
150 hir::ModuleDef::Const(c) => {
151 target_name = c.name(db);
152 offset_target_and_file_id(db, c)
153 }
154 hir::ModuleDef::Static(s) => {
155 target_name = s.name(db);
156 offset_target_and_file_id(db, s)
157 }
158 hir::ModuleDef::Trait(t) => {
159 target_name = Some(t.name(db));
160 offset_target_and_file_id(db, t)
161 }
162 hir::ModuleDef::TypeAlias(t) => {
163 target_name = Some(t.name(db));
164 offset_target_and_file_id(db, t)
165 }
166 hir::ModuleDef::Module(m) => {
167 target_name = m.name(db);
168 let in_file_source = m.declaration_source(db)?;
169 let file_id = in_file_source.file_id.original_file(db.upcast());
170 let syntax = in_file_source.value.syntax();
171 (vis_offset(syntax), syntax.text_range(), file_id)
172 }
173 // Enum variants can't be private, we can't modify builtin types
174 hir::ModuleDef::EnumVariant(_) | hir::ModuleDef::BuiltinType(_) => return None,
175 };
176
177 Some((offset, target, target_file, target_name))
178}
179
180fn vis_offset(node: &SyntaxNode) -> TextSize {
181 node.children_with_tokens()
182 .skip_while(|it| match it.kind() {
183 WHITESPACE | COMMENT | ATTR => true,
184 _ => false,
185 })
186 .next()
187 .map(|it| it.text_range().start())
188 .unwrap_or_else(|| node.text_range().start())
189}
190
191#[cfg(test)]
192mod tests {
193 use crate::tests::{check_assist, check_assist_not_applicable};
194
195 use super::*;
196
197 #[test]
198 fn fix_visibility_of_fn() {
199 check_assist(
200 fix_visibility,
201 r"mod foo { fn foo() {} }
202 fn main() { foo::foo<|>() } ",
203 r"mod foo { $0pub(crate) fn foo() {} }
204 fn main() { foo::foo() } ",
205 );
206 check_assist_not_applicable(
207 fix_visibility,
208 r"mod foo { pub fn foo() {} }
209 fn main() { foo::foo<|>() } ",
210 )
211 }
212
213 #[test]
214 fn fix_visibility_of_adt_in_submodule() {
215 check_assist(
216 fix_visibility,
217 r"mod foo { struct Foo; }
218 fn main() { foo::Foo<|> } ",
219 r"mod foo { $0pub(crate) struct Foo; }
220 fn main() { foo::Foo } ",
221 );
222 check_assist_not_applicable(
223 fix_visibility,
224 r"mod foo { pub struct Foo; }
225 fn main() { foo::Foo<|> } ",
226 );
227 check_assist(
228 fix_visibility,
229 r"mod foo { enum Foo; }
230 fn main() { foo::Foo<|> } ",
231 r"mod foo { $0pub(crate) enum Foo; }
232 fn main() { foo::Foo } ",
233 );
234 check_assist_not_applicable(
235 fix_visibility,
236 r"mod foo { pub enum Foo; }
237 fn main() { foo::Foo<|> } ",
238 );
239 check_assist(
240 fix_visibility,
241 r"mod foo { union Foo; }
242 fn main() { foo::Foo<|> } ",
243 r"mod foo { $0pub(crate) union Foo; }
244 fn main() { foo::Foo } ",
245 );
246 check_assist_not_applicable(
247 fix_visibility,
248 r"mod foo { pub union Foo; }
249 fn main() { foo::Foo<|> } ",
250 );
251 }
252
253 #[test]
254 fn fix_visibility_of_adt_in_other_file() {
255 check_assist(
256 fix_visibility,
257 r"
258 //- /main.rs
259 mod foo;
260 fn main() { foo::Foo<|> }
261
262 //- /foo.rs
263 struct Foo;
264 ",
265 r"$0pub(crate) struct Foo;
266
267",
268 );
269 }
270
271 #[test]
272 fn fix_visibility_of_struct_field() {
273 check_assist(
274 fix_visibility,
275 r"mod foo { pub struct Foo { bar: (), } }
276 fn main() { foo::Foo { <|>bar: () }; } ",
277 r"mod foo { pub struct Foo { $0pub(crate) bar: (), } }
278 fn main() { foo::Foo { bar: () }; } ",
279 );
280 check_assist(
281 fix_visibility,
282 r"//- /lib.rs
283 mod foo;
284 fn main() { foo::Foo { <|>bar: () }; }
285 //- /foo.rs
286 pub struct Foo { bar: () }
287 ",
288 r"pub struct Foo { $0pub(crate) bar: () }
289
290",
291 );
292 check_assist_not_applicable(
293 fix_visibility,
294 r"mod foo { pub struct Foo { pub bar: (), } }
295 fn main() { foo::Foo { <|>bar: () }; } ",
296 );
297 check_assist_not_applicable(
298 fix_visibility,
299 r"//- /lib.rs
300 mod foo;
301 fn main() { foo::Foo { <|>bar: () }; }
302 //- /foo.rs
303 pub struct Foo { pub bar: () }
304 ",
305 );
306 }
307
308 #[test]
309 fn fix_visibility_of_enum_variant_field() {
310 check_assist(
311 fix_visibility,
312 r"mod foo { pub enum Foo { Bar { bar: () } } }
313 fn main() { foo::Foo::Bar { <|>bar: () }; } ",
314 r"mod foo { pub enum Foo { Bar { $0pub(crate) bar: () } } }
315 fn main() { foo::Foo::Bar { bar: () }; } ",
316 );
317 check_assist(
318 fix_visibility,
319 r"//- /lib.rs
320 mod foo;
321 fn main() { foo::Foo::Bar { <|>bar: () }; }
322 //- /foo.rs
323 pub enum Foo { Bar { bar: () } }
324 ",
325 r"pub enum Foo { Bar { $0pub(crate) bar: () } }
326
327",
328 );
329 check_assist_not_applicable(
330 fix_visibility,
331 r"mod foo { pub struct Foo { pub bar: (), } }
332 fn main() { foo::Foo { <|>bar: () }; } ",
333 );
334 check_assist_not_applicable(
335 fix_visibility,
336 r"//- /lib.rs
337 mod foo;
338 fn main() { foo::Foo { <|>bar: () }; }
339 //- /foo.rs
340 pub struct Foo { pub bar: () }
341 ",
342 );
343 }
344
345 #[test]
346 #[ignore]
347 // FIXME reenable this test when `Semantics::resolve_record_field` works with union fields
348 fn fix_visibility_of_union_field() {
349 check_assist(
350 fix_visibility,
351 r"mod foo { pub union Foo { bar: (), } }
352 fn main() { foo::Foo { <|>bar: () }; } ",
353 r"mod foo { pub union Foo { $0pub(crate) bar: (), } }
354 fn main() { foo::Foo { bar: () }; } ",
355 );
356 check_assist(
357 fix_visibility,
358 r"//- /lib.rs
359 mod foo;
360 fn main() { foo::Foo { <|>bar: () }; }
361 //- /foo.rs
362 pub union Foo { bar: () }
363 ",
364 r"pub union Foo { $0pub(crate) bar: () }
365
366",
367 );
368 check_assist_not_applicable(
369 fix_visibility,
370 r"mod foo { pub union Foo { pub bar: (), } }
371 fn main() { foo::Foo { <|>bar: () }; } ",
372 );
373 check_assist_not_applicable(
374 fix_visibility,
375 r"//- /lib.rs
376 mod foo;
377 fn main() { foo::Foo { <|>bar: () }; }
378 //- /foo.rs
379 pub union Foo { pub bar: () }
380 ",
381 );
382 }
383
384 #[test]
385 fn fix_visibility_of_const() {
386 check_assist(
387 fix_visibility,
388 r"mod foo { const FOO: () = (); }
389 fn main() { foo::FOO<|> } ",
390 r"mod foo { $0pub(crate) const FOO: () = (); }
391 fn main() { foo::FOO } ",
392 );
393 check_assist_not_applicable(
394 fix_visibility,
395 r"mod foo { pub const FOO: () = (); }
396 fn main() { foo::FOO<|> } ",
397 );
398 }
399
400 #[test]
401 fn fix_visibility_of_static() {
402 check_assist(
403 fix_visibility,
404 r"mod foo { static FOO: () = (); }
405 fn main() { foo::FOO<|> } ",
406 r"mod foo { $0pub(crate) static FOO: () = (); }
407 fn main() { foo::FOO } ",
408 );
409 check_assist_not_applicable(
410 fix_visibility,
411 r"mod foo { pub static FOO: () = (); }
412 fn main() { foo::FOO<|> } ",
413 );
414 }
415
416 #[test]
417 fn fix_visibility_of_trait() {
418 check_assist(
419 fix_visibility,
420 r"mod foo { trait Foo { fn foo(&self) {} } }
421 fn main() { let x: &dyn foo::<|>Foo; } ",
422 r"mod foo { $0pub(crate) trait Foo { fn foo(&self) {} } }
423 fn main() { let x: &dyn foo::Foo; } ",
424 );
425 check_assist_not_applicable(
426 fix_visibility,
427 r"mod foo { pub trait Foo { fn foo(&self) {} } }
428 fn main() { let x: &dyn foo::Foo<|>; } ",
429 );
430 }
431
432 #[test]
433 fn fix_visibility_of_type_alias() {
434 check_assist(
435 fix_visibility,
436 r"mod foo { type Foo = (); }
437 fn main() { let x: foo::Foo<|>; } ",
438 r"mod foo { $0pub(crate) type Foo = (); }
439 fn main() { let x: foo::Foo; } ",
440 );
441 check_assist_not_applicable(
442 fix_visibility,
443 r"mod foo { pub type Foo = (); }
444 fn main() { let x: foo::Foo<|>; } ",
445 );
446 }
447
448 #[test]
449 fn fix_visibility_of_module() {
450 check_assist(
451 fix_visibility,
452 r"mod foo { mod bar { fn bar() {} } }
453 fn main() { foo::bar<|>::bar(); } ",
454 r"mod foo { $0pub(crate) mod bar { fn bar() {} } }
455 fn main() { foo::bar::bar(); } ",
456 );
457
458 check_assist(
459 fix_visibility,
460 r"
461 //- /main.rs
462 mod foo;
463 fn main() { foo::bar<|>::baz(); }
464
465 //- /foo.rs
466 mod bar {
467 pub fn baz() {}
468 }
469 ",
470 r"$0pub(crate) mod bar {
471 pub fn baz() {}
472}
473
474",
475 );
476
477 check_assist_not_applicable(
478 fix_visibility,
479 r"mod foo { pub mod bar { pub fn bar() {} } }
480 fn main() { foo::bar<|>::bar(); } ",
481 );
482 }
483
484 #[test]
485 fn fix_visibility_of_inline_module_in_other_file() {
486 check_assist(
487 fix_visibility,
488 r"
489 //- /main.rs
490 mod foo;
491 fn main() { foo::bar<|>::baz(); }
492
493 //- /foo.rs
494 mod bar;
495
496 //- /foo/bar.rs
497 pub fn baz() {}
498 }
499 ",
500 r"$0pub(crate) mod bar;
501",
502 );
503 }
504
505 #[test]
506 fn fix_visibility_of_module_declaration_in_other_file() {
507 check_assist(
508 fix_visibility,
509 r"//- /main.rs
510 mod foo;
511 fn main() { foo::bar<|>>::baz(); }
512
513 //- /foo.rs
514 mod bar {
515 pub fn baz() {}
516 }",
517 r"$0pub(crate) mod bar {
518 pub fn baz() {}
519}
520",
521 );
522 }
523
524 #[test]
525 fn adds_pub_when_target_is_in_another_crate() {
526 check_assist(
527 fix_visibility,
528 r"//- /main.rs crate:a deps:foo
529 foo::Bar<|>
530 //- /lib.rs crate:foo
531 struct Bar;",
532 r"$0pub struct Bar;
533",
534 )
535 }
536
537 #[test]
538 #[ignore]
539 // FIXME handle reexports properly
540 fn fix_visibility_of_reexport() {
541 check_assist(
542 fix_visibility,
543 r"
544 mod foo {
545 use bar::Baz;
546 mod bar { pub(super) struct Baz; }
547 }
548 foo::Baz<|>
549 ",
550 r"
551 mod foo {
552 $0pub(crate) use bar::Baz;
553 mod bar { pub(super) struct Baz; }
554 }
555 foo::Baz
556 ",
557 )
558 }
559}
diff --git a/crates/ra_assists/src/handlers/flip_binexpr.rs b/crates/ra_assists/src/handlers/flip_binexpr.rs
index 692ba4895..573196576 100644
--- a/crates/ra_assists/src/handlers/flip_binexpr.rs
+++ b/crates/ra_assists/src/handlers/flip_binexpr.rs
@@ -85,17 +85,13 @@ mod tests {
85 check_assist( 85 check_assist(
86 flip_binexpr, 86 flip_binexpr,
87 "fn f() { let res = 1 ==<|> 2; }", 87 "fn f() { let res = 1 ==<|> 2; }",
88 "fn f() { let res = 2 ==<|> 1; }", 88 "fn f() { let res = 2 == 1; }",
89 ) 89 )
90 } 90 }
91 91
92 #[test] 92 #[test]
93 fn flip_binexpr_works_for_gt() { 93 fn flip_binexpr_works_for_gt() {
94 check_assist( 94 check_assist(flip_binexpr, "fn f() { let res = 1 ><|> 2; }", "fn f() { let res = 2 < 1; }")
95 flip_binexpr,
96 "fn f() { let res = 1 ><|> 2; }",
97 "fn f() { let res = 2 <<|> 1; }",
98 )
99 } 95 }
100 96
101 #[test] 97 #[test]
@@ -103,7 +99,7 @@ mod tests {
103 check_assist( 99 check_assist(
104 flip_binexpr, 100 flip_binexpr,
105 "fn f() { let res = 1 <=<|> 2; }", 101 "fn f() { let res = 1 <=<|> 2; }",
106 "fn f() { let res = 2 >=<|> 1; }", 102 "fn f() { let res = 2 >= 1; }",
107 ) 103 )
108 } 104 }
109 105
@@ -112,7 +108,7 @@ mod tests {
112 check_assist( 108 check_assist(
113 flip_binexpr, 109 flip_binexpr,
114 "fn f() { let res = (1 + 1) ==<|> (2 + 2); }", 110 "fn f() { let res = (1 + 1) ==<|> (2 + 2); }",
115 "fn f() { let res = (2 + 2) ==<|> (1 + 1); }", 111 "fn f() { let res = (2 + 2) == (1 + 1); }",
116 ) 112 )
117 } 113 }
118 114
@@ -132,7 +128,7 @@ mod tests {
132 fn dyn_eq(&self, other: &dyn Diagnostic) -> bool { 128 fn dyn_eq(&self, other: &dyn Diagnostic) -> bool {
133 match other.downcast_ref::<Self>() { 129 match other.downcast_ref::<Self>() {
134 None => false, 130 None => false,
135 Some(it) => self ==<|> it, 131 Some(it) => self == it,
136 } 132 }
137 } 133 }
138 "#, 134 "#,
diff --git a/crates/ra_assists/src/handlers/flip_comma.rs b/crates/ra_assists/src/handlers/flip_comma.rs
index dfe2a7fed..a57a1c463 100644
--- a/crates/ra_assists/src/handlers/flip_comma.rs
+++ b/crates/ra_assists/src/handlers/flip_comma.rs
@@ -45,7 +45,7 @@ mod tests {
45 check_assist( 45 check_assist(
46 flip_comma, 46 flip_comma,
47 "fn foo(x: i32,<|> y: Result<(), ()>) {}", 47 "fn foo(x: i32,<|> y: Result<(), ()>) {}",
48 "fn foo(y: Result<(), ()>,<|> x: i32) {}", 48 "fn foo(y: Result<(), ()>, x: i32) {}",
49 ) 49 )
50 } 50 }
51 51
diff --git a/crates/ra_assists/src/handlers/flip_trait_bound.rs b/crates/ra_assists/src/handlers/flip_trait_bound.rs
index 8a08702ab..0115adc8b 100644
--- a/crates/ra_assists/src/handlers/flip_trait_bound.rs
+++ b/crates/ra_assists/src/handlers/flip_trait_bound.rs
@@ -60,7 +60,7 @@ mod tests {
60 check_assist( 60 check_assist(
61 flip_trait_bound, 61 flip_trait_bound,
62 "struct S<T> where T: A <|>+ B { }", 62 "struct S<T> where T: A <|>+ B { }",
63 "struct S<T> where T: B <|>+ A { }", 63 "struct S<T> where T: B + A { }",
64 ) 64 )
65 } 65 }
66 66
@@ -69,13 +69,13 @@ mod tests {
69 check_assist( 69 check_assist(
70 flip_trait_bound, 70 flip_trait_bound,
71 "impl X for S<T> where T: A +<|> B { }", 71 "impl X for S<T> where T: A +<|> B { }",
72 "impl X for S<T> where T: B +<|> A { }", 72 "impl X for S<T> where T: B + A { }",
73 ) 73 )
74 } 74 }
75 75
76 #[test] 76 #[test]
77 fn flip_trait_bound_works_for_fn() { 77 fn flip_trait_bound_works_for_fn() {
78 check_assist(flip_trait_bound, "fn f<T: A <|>+ B>(t: T) { }", "fn f<T: B <|>+ A>(t: T) { }") 78 check_assist(flip_trait_bound, "fn f<T: A <|>+ B>(t: T) { }", "fn f<T: B + A>(t: T) { }")
79 } 79 }
80 80
81 #[test] 81 #[test]
@@ -83,7 +83,7 @@ mod tests {
83 check_assist( 83 check_assist(
84 flip_trait_bound, 84 flip_trait_bound,
85 "fn f<T>(t: T) where T: A +<|> B { }", 85 "fn f<T>(t: T) where T: A +<|> B { }",
86 "fn f<T>(t: T) where T: B +<|> A { }", 86 "fn f<T>(t: T) where T: B + A { }",
87 ) 87 )
88 } 88 }
89 89
@@ -92,7 +92,7 @@ mod tests {
92 check_assist( 92 check_assist(
93 flip_trait_bound, 93 flip_trait_bound,
94 "fn f<T>(t: T) where T: A <|>+ 'static { }", 94 "fn f<T>(t: T) where T: A <|>+ 'static { }",
95 "fn f<T>(t: T) where T: 'static <|>+ A { }", 95 "fn f<T>(t: T) where T: 'static + A { }",
96 ) 96 )
97 } 97 }
98 98
@@ -101,7 +101,7 @@ mod tests {
101 check_assist( 101 check_assist(
102 flip_trait_bound, 102 flip_trait_bound,
103 "struct S<T> where T: A<T> <|>+ b_mod::B<T> + C<T> { }", 103 "struct S<T> where T: A<T> <|>+ b_mod::B<T> + C<T> { }",
104 "struct S<T> where T: b_mod::B<T> <|>+ A<T> + C<T> { }", 104 "struct S<T> where T: b_mod::B<T> + A<T> + C<T> { }",
105 ) 105 )
106 } 106 }
107 107
@@ -110,7 +110,7 @@ mod tests {
110 check_assist( 110 check_assist(
111 flip_trait_bound, 111 flip_trait_bound,
112 "struct S<T> where T: A + B + C + D + E + F +<|> G + H + I + J { }", 112 "struct S<T> where T: A + B + C + D + E + F +<|> G + H + I + J { }",
113 "struct S<T> where T: A + B + C + D + E + G +<|> F + H + I + J { }", 113 "struct S<T> where T: A + B + C + D + E + G + F + H + I + J { }",
114 ) 114 )
115 } 115 }
116} 116}
diff --git a/crates/ra_assists/src/handlers/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs
index 5b26814d3..d26e68847 100644
--- a/crates/ra_assists/src/handlers/inline_local_variable.rs
+++ b/crates/ra_assists/src/handlers/inline_local_variable.rs
@@ -3,7 +3,7 @@ use ra_syntax::{
3 ast::{self, AstNode, AstToken}, 3 ast::{self, AstNode, AstToken},
4 TextRange, 4 TextRange,
5}; 5};
6use test_utils::tested_by; 6use test_utils::mark;
7 7
8use crate::{ 8use crate::{
9 assist_context::{AssistContext, Assists}, 9 assist_context::{AssistContext, Assists},
@@ -33,11 +33,11 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
33 _ => return None, 33 _ => return None,
34 }; 34 };
35 if bind_pat.mut_token().is_some() { 35 if bind_pat.mut_token().is_some() {
36 tested_by!(test_not_inline_mut_variable); 36 mark::hit!(test_not_inline_mut_variable);
37 return None; 37 return None;
38 } 38 }
39 if !bind_pat.syntax().text_range().contains_inclusive(ctx.offset()) { 39 if !bind_pat.syntax().text_range().contains_inclusive(ctx.offset()) {
40 tested_by!(not_applicable_outside_of_bind_pat); 40 mark::hit!(not_applicable_outside_of_bind_pat);
41 return None; 41 return None;
42 } 42 }
43 let initializer_expr = let_stmt.initializer()?; 43 let initializer_expr = let_stmt.initializer()?;
@@ -46,7 +46,7 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
46 let def = Definition::Local(def); 46 let def = Definition::Local(def);
47 let refs = def.find_usages(ctx.db, None); 47 let refs = def.find_usages(ctx.db, None);
48 if refs.is_empty() { 48 if refs.is_empty() {
49 tested_by!(test_not_applicable_if_variable_unused); 49 mark::hit!(test_not_applicable_if_variable_unused);
50 return None; 50 return None;
51 }; 51 };
52 52
@@ -116,13 +116,12 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
116 let replacement = if should_wrap { init_in_paren.clone() } else { init_str.clone() }; 116 let replacement = if should_wrap { init_in_paren.clone() } else { init_str.clone() };
117 builder.replace(desc.file_range.range, replacement) 117 builder.replace(desc.file_range.range, replacement)
118 } 118 }
119 builder.set_cursor(delete_range.start())
120 }) 119 })
121} 120}
122 121
123#[cfg(test)] 122#[cfg(test)]
124mod tests { 123mod tests {
125 use test_utils::covers; 124 use test_utils::mark;
126 125
127 use crate::tests::{check_assist, check_assist_not_applicable}; 126 use crate::tests::{check_assist, check_assist_not_applicable};
128 127
@@ -149,7 +148,7 @@ fn foo() {
149 r" 148 r"
150fn bar(a: usize) {} 149fn bar(a: usize) {}
151fn foo() { 150fn foo() {
152 <|>1 + 1; 151 1 + 1;
153 if 1 > 10 { 152 if 1 > 10 {
154 } 153 }
155 154
@@ -183,7 +182,7 @@ fn foo() {
183 r" 182 r"
184fn bar(a: usize) {} 183fn bar(a: usize) {}
185fn foo() { 184fn foo() {
186 <|>(1 + 1) + 1; 185 (1 + 1) + 1;
187 if (1 + 1) > 10 { 186 if (1 + 1) > 10 {
188 } 187 }
189 188
@@ -217,7 +216,7 @@ fn foo() {
217 r" 216 r"
218fn bar(a: usize) {} 217fn bar(a: usize) {}
219fn foo() { 218fn foo() {
220 <|>bar(1) + 1; 219 bar(1) + 1;
221 if bar(1) > 10 { 220 if bar(1) > 10 {
222 } 221 }
223 222
@@ -251,7 +250,7 @@ fn foo() {
251 r" 250 r"
252fn bar(a: usize): usize { a } 251fn bar(a: usize): usize { a }
253fn foo() { 252fn foo() {
254 <|>(bar(1) as u64) + 1; 253 (bar(1) as u64) + 1;
255 if (bar(1) as u64) > 10 { 254 if (bar(1) as u64) > 10 {
256 } 255 }
257 256
@@ -283,7 +282,7 @@ fn foo() {
283}", 282}",
284 r" 283 r"
285fn foo() { 284fn foo() {
286 <|>{ 10 + 1 } + 1; 285 { 10 + 1 } + 1;
287 if { 10 + 1 } > 10 { 286 if { 10 + 1 } > 10 {
288 } 287 }
289 288
@@ -315,7 +314,7 @@ fn foo() {
315}", 314}",
316 r" 315 r"
317fn foo() { 316fn foo() {
318 <|>( 10 + 1 ) + 1; 317 ( 10 + 1 ) + 1;
319 if ( 10 + 1 ) > 10 { 318 if ( 10 + 1 ) > 10 {
320 } 319 }
321 320
@@ -330,7 +329,7 @@ fn foo() {
330 329
331 #[test] 330 #[test]
332 fn test_not_inline_mut_variable() { 331 fn test_not_inline_mut_variable() {
333 covers!(test_not_inline_mut_variable); 332 mark::check!(test_not_inline_mut_variable);
334 check_assist_not_applicable( 333 check_assist_not_applicable(
335 inline_local_variable, 334 inline_local_variable,
336 r" 335 r"
@@ -353,7 +352,7 @@ fn foo() {
353}", 352}",
354 r" 353 r"
355fn foo() { 354fn foo() {
356 <|>let b = bar(10 + 1) * 10; 355 let b = bar(10 + 1) * 10;
357 let c = bar(10 + 1) as usize; 356 let c = bar(10 + 1) as usize;
358}", 357}",
359 ); 358 );
@@ -373,7 +372,7 @@ fn foo() {
373 r" 372 r"
374fn foo() { 373fn foo() {
375 let x = vec![1, 2, 3]; 374 let x = vec![1, 2, 3];
376 <|>let b = x[0] * 10; 375 let b = x[0] * 10;
377 let c = x[0] as usize; 376 let c = x[0] as usize;
378}", 377}",
379 ); 378 );
@@ -393,7 +392,7 @@ fn foo() {
393 r" 392 r"
394fn foo() { 393fn foo() {
395 let bar = vec![1]; 394 let bar = vec![1];
396 <|>let b = bar.len() * 10; 395 let b = bar.len() * 10;
397 let c = bar.len() as usize; 396 let c = bar.len() as usize;
398}", 397}",
399 ); 398 );
@@ -421,7 +420,7 @@ struct Bar {
421 420
422fn foo() { 421fn foo() {
423 let bar = Bar { foo: 1 }; 422 let bar = Bar { foo: 1 };
424 <|>let b = bar.foo * 10; 423 let b = bar.foo * 10;
425 let c = bar.foo as usize; 424 let c = bar.foo as usize;
426}", 425}",
427 ); 426 );
@@ -442,7 +441,7 @@ fn foo() -> Option<usize> {
442 r" 441 r"
443fn foo() -> Option<usize> { 442fn foo() -> Option<usize> {
444 let bar = Some(1); 443 let bar = Some(1);
445 <|>let b = bar? * 10; 444 let b = bar? * 10;
446 let c = bar? as usize; 445 let c = bar? as usize;
447 None 446 None
448}", 447}",
@@ -462,7 +461,7 @@ fn foo() {
462 r" 461 r"
463fn foo() { 462fn foo() {
464 let bar = 10; 463 let bar = 10;
465 <|>let b = &bar * 10; 464 let b = &bar * 10;
466}", 465}",
467 ); 466 );
468 } 467 }
@@ -478,7 +477,7 @@ fn foo() {
478}", 477}",
479 r" 478 r"
480fn foo() { 479fn foo() {
481 <|>let b = (10, 20)[0]; 480 let b = (10, 20)[0];
482}", 481}",
483 ); 482 );
484 } 483 }
@@ -494,7 +493,7 @@ fn foo() {
494}", 493}",
495 r" 494 r"
496fn foo() { 495fn foo() {
497 <|>let b = [1, 2, 3].len(); 496 let b = [1, 2, 3].len();
498}", 497}",
499 ); 498 );
500 } 499 }
@@ -511,7 +510,7 @@ fn foo() {
511}", 510}",
512 r" 511 r"
513fn foo() { 512fn foo() {
514 <|>let b = (10 + 20) * 10; 513 let b = (10 + 20) * 10;
515 let c = (10 + 20) as usize; 514 let c = (10 + 20) as usize;
516}", 515}",
517 ); 516 );
@@ -531,7 +530,7 @@ fn foo() {
531 r" 530 r"
532fn foo() { 531fn foo() {
533 let d = 10; 532 let d = 10;
534 <|>let b = d * 10; 533 let b = d * 10;
535 let c = d as usize; 534 let c = d as usize;
536}", 535}",
537 ); 536 );
@@ -549,7 +548,7 @@ fn foo() {
549}", 548}",
550 r" 549 r"
551fn foo() { 550fn foo() {
552 <|>let b = { 10 } * 10; 551 let b = { 10 } * 10;
553 let c = { 10 } as usize; 552 let c = { 10 } as usize;
554}", 553}",
555 ); 554 );
@@ -569,7 +568,7 @@ fn foo() {
569}", 568}",
570 r" 569 r"
571fn foo() { 570fn foo() {
572 <|>let b = (10 + 20) * 10; 571 let b = (10 + 20) * 10;
573 let c = (10 + 20, 20); 572 let c = (10 + 20, 20);
574 let d = [10 + 20, 10]; 573 let d = [10 + 20, 10];
575 let e = (10 + 20); 574 let e = (10 + 20);
@@ -588,7 +587,7 @@ fn foo() {
588}", 587}",
589 r" 588 r"
590fn foo() { 589fn foo() {
591 <|>for i in vec![10, 20] {} 590 for i in vec![10, 20] {}
592}", 591}",
593 ); 592 );
594 } 593 }
@@ -604,7 +603,7 @@ fn foo() {
604}", 603}",
605 r" 604 r"
606fn foo() { 605fn foo() {
607 <|>while 1 > 0 {} 606 while 1 > 0 {}
608}", 607}",
609 ); 608 );
610 } 609 }
@@ -622,7 +621,7 @@ fn foo() {
622}", 621}",
623 r" 622 r"
624fn foo() { 623fn foo() {
625 <|>loop { 624 loop {
626 break 1 + 1; 625 break 1 + 1;
627 } 626 }
628}", 627}",
@@ -640,7 +639,7 @@ fn foo() {
640}", 639}",
641 r" 640 r"
642fn foo() { 641fn foo() {
643 <|>return 1 > 0; 642 return 1 > 0;
644}", 643}",
645 ); 644 );
646 } 645 }
@@ -656,14 +655,14 @@ fn foo() {
656}", 655}",
657 r" 656 r"
658fn foo() { 657fn foo() {
659 <|>match 1 > 0 {} 658 match 1 > 0 {}
660}", 659}",
661 ); 660 );
662 } 661 }
663 662
664 #[test] 663 #[test]
665 fn test_not_applicable_if_variable_unused() { 664 fn test_not_applicable_if_variable_unused() {
666 covers!(test_not_applicable_if_variable_unused); 665 mark::check!(test_not_applicable_if_variable_unused);
667 check_assist_not_applicable( 666 check_assist_not_applicable(
668 inline_local_variable, 667 inline_local_variable,
669 r" 668 r"
@@ -676,7 +675,7 @@ fn foo() {
676 675
677 #[test] 676 #[test]
678 fn not_applicable_outside_of_bind_pat() { 677 fn not_applicable_outside_of_bind_pat() {
679 covers!(not_applicable_outside_of_bind_pat); 678 mark::check!(not_applicable_outside_of_bind_pat);
680 check_assist_not_applicable( 679 check_assist_not_applicable(
681 inline_local_variable, 680 inline_local_variable,
682 r" 681 r"
diff --git a/crates/ra_assists/src/handlers/introduce_variable.rs b/crates/ra_assists/src/handlers/introduce_variable.rs
index fdf3ada0d..31d6539f7 100644
--- a/crates/ra_assists/src/handlers/introduce_variable.rs
+++ b/crates/ra_assists/src/handlers/introduce_variable.rs
@@ -4,10 +4,10 @@ use ra_syntax::{
4 BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR, 4 BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR,
5 WHITESPACE, 5 WHITESPACE,
6 }, 6 },
7 SyntaxNode, TextSize, 7 SyntaxNode,
8}; 8};
9use stdx::format_to; 9use stdx::format_to;
10use test_utils::tested_by; 10use test_utils::mark;
11 11
12use crate::{AssistContext, AssistId, Assists}; 12use crate::{AssistContext, AssistId, Assists};
13 13
@@ -23,7 +23,7 @@ use crate::{AssistContext, AssistId, Assists};
23// -> 23// ->
24// ``` 24// ```
25// fn main() { 25// fn main() {
26// let var_name = (1 + 2); 26// let $0var_name = (1 + 2);
27// var_name * 4; 27// var_name * 4;
28// } 28// }
29// ``` 29// ```
@@ -33,7 +33,7 @@ pub(crate) fn introduce_variable(acc: &mut Assists, ctx: &AssistContext) -> Opti
33 } 33 }
34 let node = ctx.covering_element(); 34 let node = ctx.covering_element();
35 if node.kind() == COMMENT { 35 if node.kind() == COMMENT {
36 tested_by!(introduce_var_in_comment_is_not_applicable); 36 mark::hit!(introduce_var_in_comment_is_not_applicable);
37 return None; 37 return None;
38 } 38 }
39 let expr = node.ancestors().find_map(valid_target_expr)?; 39 let expr = node.ancestors().find_map(valid_target_expr)?;
@@ -46,14 +46,13 @@ pub(crate) fn introduce_variable(acc: &mut Assists, ctx: &AssistContext) -> Opti
46 acc.add(AssistId("introduce_variable"), "Extract into variable", target, move |edit| { 46 acc.add(AssistId("introduce_variable"), "Extract into variable", target, move |edit| {
47 let mut buf = String::new(); 47 let mut buf = String::new();
48 48
49 let cursor_offset = if wrap_in_block { 49 if wrap_in_block {
50 buf.push_str("{ let var_name = "); 50 buf.push_str("{ let var_name = ");
51 TextSize::of("{ let ")
52 } else { 51 } else {
53 buf.push_str("let var_name = "); 52 buf.push_str("let var_name = ");
54 TextSize::of("let ")
55 }; 53 };
56 format_to!(buf, "{}", expr.syntax()); 54 format_to!(buf, "{}", expr.syntax());
55
57 let full_stmt = ast::ExprStmt::cast(anchor_stmt.clone()); 56 let full_stmt = ast::ExprStmt::cast(anchor_stmt.clone());
58 let is_full_stmt = if let Some(expr_stmt) = &full_stmt { 57 let is_full_stmt = if let Some(expr_stmt) = &full_stmt {
59 Some(expr.syntax().clone()) == expr_stmt.expr().map(|e| e.syntax().clone()) 58 Some(expr.syntax().clone()) == expr_stmt.expr().map(|e| e.syntax().clone())
@@ -61,32 +60,47 @@ pub(crate) fn introduce_variable(acc: &mut Assists, ctx: &AssistContext) -> Opti
61 false 60 false
62 }; 61 };
63 if is_full_stmt { 62 if is_full_stmt {
64 tested_by!(test_introduce_var_expr_stmt); 63 mark::hit!(test_introduce_var_expr_stmt);
65 if full_stmt.unwrap().semicolon_token().is_none() { 64 if full_stmt.unwrap().semicolon_token().is_none() {
66 buf.push_str(";"); 65 buf.push_str(";");
67 } 66 }
68 edit.replace(expr.syntax().text_range(), buf); 67 let offset = expr.syntax().text_range();
69 } else { 68 match ctx.config.snippet_cap {
70 buf.push_str(";"); 69 Some(cap) => {
71 70 let snip = buf.replace("let var_name", "let $0var_name");
72 // We want to maintain the indent level, 71 edit.replace_snippet(cap, offset, snip)
73 // but we do not want to duplicate possible 72 }
74 // extra newlines in the indent block 73 None => edit.replace(offset, buf),
75 let text = indent.text();
76 if text.starts_with('\n') {
77 buf.push_str("\n");
78 buf.push_str(text.trim_start_matches('\n'));
79 } else {
80 buf.push_str(text);
81 } 74 }
75 return;
76 }
82 77
83 edit.replace(expr.syntax().text_range(), "var_name".to_string()); 78 buf.push_str(";");
84 edit.insert(anchor_stmt.text_range().start(), buf); 79
85 if wrap_in_block { 80 // We want to maintain the indent level,
86 edit.insert(anchor_stmt.text_range().end(), " }"); 81 // but we do not want to duplicate possible
82 // extra newlines in the indent block
83 let text = indent.text();
84 if text.starts_with('\n') {
85 buf.push_str("\n");
86 buf.push_str(text.trim_start_matches('\n'));
87 } else {
88 buf.push_str(text);
89 }
90
91 edit.replace(expr.syntax().text_range(), "var_name".to_string());
92 let offset = anchor_stmt.text_range().start();
93 match ctx.config.snippet_cap {
94 Some(cap) => {
95 let snip = buf.replace("let var_name", "let $0var_name");
96 edit.insert_snippet(cap, offset, snip)
87 } 97 }
98 None => edit.insert(offset, buf),
99 }
100
101 if wrap_in_block {
102 edit.insert(anchor_stmt.text_range().end(), " }");
88 } 103 }
89 edit.set_cursor(anchor_stmt.text_range().start() + cursor_offset);
90 }) 104 })
91} 105}
92 106
@@ -113,7 +127,7 @@ fn anchor_stmt(expr: ast::Expr) -> Option<(SyntaxNode, bool)> {
113 expr.syntax().ancestors().find_map(|node| { 127 expr.syntax().ancestors().find_map(|node| {
114 if let Some(expr) = node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.expr()) { 128 if let Some(expr) = node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.expr()) {
115 if expr.syntax() == &node { 129 if expr.syntax() == &node {
116 tested_by!(test_introduce_var_last_expr); 130 mark::hit!(test_introduce_var_last_expr);
117 return Some((node, false)); 131 return Some((node, false));
118 } 132 }
119 } 133 }
@@ -134,7 +148,7 @@ fn anchor_stmt(expr: ast::Expr) -> Option<(SyntaxNode, bool)> {
134 148
135#[cfg(test)] 149#[cfg(test)]
136mod tests { 150mod tests {
137 use test_utils::covers; 151 use test_utils::mark;
138 152
139 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; 153 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
140 154
@@ -144,37 +158,37 @@ mod tests {
144 fn test_introduce_var_simple() { 158 fn test_introduce_var_simple() {
145 check_assist( 159 check_assist(
146 introduce_variable, 160 introduce_variable,
147 " 161 r#"
148fn foo() { 162fn foo() {
149 foo(<|>1 + 1<|>); 163 foo(<|>1 + 1<|>);
150}", 164}"#,
151 " 165 r#"
152fn foo() { 166fn foo() {
153 let <|>var_name = 1 + 1; 167 let $0var_name = 1 + 1;
154 foo(var_name); 168 foo(var_name);
155}", 169}"#,
156 ); 170 );
157 } 171 }
158 172
159 #[test] 173 #[test]
160 fn introduce_var_in_comment_is_not_applicable() { 174 fn introduce_var_in_comment_is_not_applicable() {
161 covers!(introduce_var_in_comment_is_not_applicable); 175 mark::check!(introduce_var_in_comment_is_not_applicable);
162 check_assist_not_applicable(introduce_variable, "fn main() { 1 + /* <|>comment<|> */ 1; }"); 176 check_assist_not_applicable(introduce_variable, "fn main() { 1 + /* <|>comment<|> */ 1; }");
163 } 177 }
164 178
165 #[test] 179 #[test]
166 fn test_introduce_var_expr_stmt() { 180 fn test_introduce_var_expr_stmt() {
167 covers!(test_introduce_var_expr_stmt); 181 mark::check!(test_introduce_var_expr_stmt);
168 check_assist( 182 check_assist(
169 introduce_variable, 183 introduce_variable,
170 " 184 r#"
171fn foo() { 185fn foo() {
172 <|>1 + 1<|>; 186 <|>1 + 1<|>;
173}", 187}"#,
174 " 188 r#"
175fn foo() { 189fn foo() {
176 let <|>var_name = 1 + 1; 190 let $0var_name = 1 + 1;
177}", 191}"#,
178 ); 192 );
179 check_assist( 193 check_assist(
180 introduce_variable, 194 introduce_variable,
@@ -185,7 +199,7 @@ fn foo() {
185}", 199}",
186 " 200 "
187fn foo() { 201fn foo() {
188 let <|>var_name = { let x = 0; x }; 202 let $0var_name = { let x = 0; x };
189 something_else(); 203 something_else();
190}", 204}",
191 ); 205 );
@@ -201,7 +215,7 @@ fn foo() {
201}", 215}",
202 " 216 "
203fn foo() { 217fn foo() {
204 let <|>var_name = 1; 218 let $0var_name = 1;
205 var_name + 1; 219 var_name + 1;
206}", 220}",
207 ); 221 );
@@ -209,7 +223,7 @@ fn foo() {
209 223
210 #[test] 224 #[test]
211 fn test_introduce_var_last_expr() { 225 fn test_introduce_var_last_expr() {
212 covers!(test_introduce_var_last_expr); 226 mark::check!(test_introduce_var_last_expr);
213 check_assist( 227 check_assist(
214 introduce_variable, 228 introduce_variable,
215 " 229 "
@@ -218,7 +232,7 @@ fn foo() {
218}", 232}",
219 " 233 "
220fn foo() { 234fn foo() {
221 let <|>var_name = 1 + 1; 235 let $0var_name = 1 + 1;
222 bar(var_name) 236 bar(var_name)
223}", 237}",
224 ); 238 );
@@ -230,7 +244,7 @@ fn foo() {
230}", 244}",
231 " 245 "
232fn foo() { 246fn foo() {
233 let <|>var_name = bar(1 + 1); 247 let $0var_name = bar(1 + 1);
234 var_name 248 var_name
235}", 249}",
236 ) 250 )
@@ -253,7 +267,7 @@ fn main() {
253fn main() { 267fn main() {
254 let x = true; 268 let x = true;
255 let tuple = match x { 269 let tuple = match x {
256 true => { let <|>var_name = 2 + 2; (var_name, true) } 270 true => { let $0var_name = 2 + 2; (var_name, true) }
257 _ => (0, false) 271 _ => (0, false)
258 }; 272 };
259} 273}
@@ -283,7 +297,7 @@ fn main() {
283 let tuple = match x { 297 let tuple = match x {
284 true => { 298 true => {
285 let y = 1; 299 let y = 1;
286 let <|>var_name = 2 + y; 300 let $0var_name = 2 + y;
287 (var_name, true) 301 (var_name, true)
288 } 302 }
289 _ => (0, false) 303 _ => (0, false)
@@ -304,7 +318,7 @@ fn main() {
304", 318",
305 " 319 "
306fn main() { 320fn main() {
307 let lambda = |x: u32| { let <|>var_name = x * 2; var_name }; 321 let lambda = |x: u32| { let $0var_name = x * 2; var_name };
308} 322}
309", 323",
310 ); 324 );
@@ -321,7 +335,7 @@ fn main() {
321", 335",
322 " 336 "
323fn main() { 337fn main() {
324 let lambda = |x: u32| { let <|>var_name = x * 2; var_name }; 338 let lambda = |x: u32| { let $0var_name = x * 2; var_name };
325} 339}
326", 340",
327 ); 341 );
@@ -338,7 +352,7 @@ fn main() {
338", 352",
339 " 353 "
340fn main() { 354fn main() {
341 let <|>var_name = Some(true); 355 let $0var_name = Some(true);
342 let o = var_name; 356 let o = var_name;
343} 357}
344", 358",
@@ -356,7 +370,7 @@ fn main() {
356", 370",
357 " 371 "
358fn main() { 372fn main() {
359 let <|>var_name = bar.foo(); 373 let $0var_name = bar.foo();
360 let v = var_name; 374 let v = var_name;
361} 375}
362", 376",
@@ -374,7 +388,7 @@ fn foo() -> u32 {
374", 388",
375 " 389 "
376fn foo() -> u32 { 390fn foo() -> u32 {
377 let <|>var_name = 2 + 2; 391 let $0var_name = 2 + 2;
378 return var_name; 392 return var_name;
379} 393}
380", 394",
@@ -396,7 +410,7 @@ fn foo() -> u32 {
396fn foo() -> u32 { 410fn foo() -> u32 {
397 411
398 412
399 let <|>var_name = 2 + 2; 413 let $0var_name = 2 + 2;
400 return var_name; 414 return var_name;
401} 415}
402", 416",
@@ -413,7 +427,7 @@ fn foo() -> u32 {
413 " 427 "
414fn foo() -> u32 { 428fn foo() -> u32 {
415 429
416 let <|>var_name = 2 + 2; 430 let $0var_name = 2 + 2;
417 return var_name; 431 return var_name;
418} 432}
419", 433",
@@ -438,7 +452,7 @@ fn foo() -> u32 {
438 // bar 452 // bar
439 453
440 454
441 let <|>var_name = 2 + 2; 455 let $0var_name = 2 + 2;
442 return var_name; 456 return var_name;
443} 457}
444", 458",
@@ -459,7 +473,7 @@ fn main() {
459 " 473 "
460fn main() { 474fn main() {
461 let result = loop { 475 let result = loop {
462 let <|>var_name = 2 + 2; 476 let $0var_name = 2 + 2;
463 break var_name; 477 break var_name;
464 }; 478 };
465} 479}
@@ -478,7 +492,7 @@ fn main() {
478", 492",
479 " 493 "
480fn main() { 494fn main() {
481 let <|>var_name = 0f32 as u32; 495 let $0var_name = 0f32 as u32;
482 let v = var_name; 496 let v = var_name;
483} 497}
484", 498",
diff --git a/crates/ra_assists/src/handlers/invert_if.rs b/crates/ra_assists/src/handlers/invert_if.rs
index 527c7caef..59d278eb9 100644
--- a/crates/ra_assists/src/handlers/invert_if.rs
+++ b/crates/ra_assists/src/handlers/invert_if.rs
@@ -72,7 +72,7 @@ mod tests {
72 check_assist( 72 check_assist(
73 invert_if, 73 invert_if,
74 "fn f() { i<|>f x != 3 { 1 } else { 3 + 2 } }", 74 "fn f() { i<|>f x != 3 { 1 } else { 3 + 2 } }",
75 "fn f() { i<|>f x == 3 { 3 + 2 } else { 1 } }", 75 "fn f() { if x == 3 { 3 + 2 } else { 1 } }",
76 ) 76 )
77 } 77 }
78 78
@@ -81,7 +81,7 @@ mod tests {
81 check_assist( 81 check_assist(
82 invert_if, 82 invert_if,
83 "fn f() { <|>if !cond { 3 * 2 } else { 1 } }", 83 "fn f() { <|>if !cond { 3 * 2 } else { 1 } }",
84 "fn f() { <|>if cond { 1 } else { 3 * 2 } }", 84 "fn f() { if cond { 1 } else { 3 * 2 } }",
85 ) 85 )
86 } 86 }
87 87
@@ -90,7 +90,7 @@ mod tests {
90 check_assist( 90 check_assist(
91 invert_if, 91 invert_if,
92 "fn f() { i<|>f cond { 3 * 2 } else { 1 } }", 92 "fn f() { i<|>f cond { 3 * 2 } else { 1 } }",
93 "fn f() { i<|>f !cond { 1 } else { 3 * 2 } }", 93 "fn f() { if !cond { 1 } else { 3 * 2 } }",
94 ) 94 )
95 } 95 }
96 96
diff --git a/crates/ra_assists/src/handlers/merge_imports.rs b/crates/ra_assists/src/handlers/merge_imports.rs
index ac3e53c27..972d16241 100644
--- a/crates/ra_assists/src/handlers/merge_imports.rs
+++ b/crates/ra_assists/src/handlers/merge_imports.rs
@@ -58,8 +58,6 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<()
58 let target = tree.syntax().text_range(); 58 let target = tree.syntax().text_range();
59 acc.add(AssistId("merge_imports"), "Merge imports", target, |builder| { 59 acc.add(AssistId("merge_imports"), "Merge imports", target, |builder| {
60 builder.rewrite(rewriter); 60 builder.rewrite(rewriter);
61 // FIXME: we only need because our diff is imprecise
62 builder.set_cursor(offset);
63 }) 61 })
64} 62}
65 63
@@ -142,7 +140,7 @@ use std::fmt<|>::Debug;
142use std::fmt::Display; 140use std::fmt::Display;
143", 141",
144 r" 142 r"
145use std::fmt<|>::{Debug, Display}; 143use std::fmt::{Debug, Display};
146", 144",
147 ) 145 )
148 } 146 }
@@ -156,7 +154,7 @@ use std::fmt::Debug;
156use std::fmt<|>::Display; 154use std::fmt<|>::Display;
157", 155",
158 r" 156 r"
159use std::fmt:<|>:{Display, Debug}; 157use std::fmt::{Display, Debug};
160", 158",
161 ); 159 );
162 } 160 }
@@ -169,7 +167,7 @@ use std::fmt:<|>:{Display, Debug};
169use std::{fmt<|>::Debug, fmt::Display}; 167use std::{fmt<|>::Debug, fmt::Display};
170", 168",
171 r" 169 r"
172use std::{fmt<|>::{Debug, Display}}; 170use std::{fmt::{Debug, Display}};
173", 171",
174 ); 172 );
175 check_assist( 173 check_assist(
@@ -178,7 +176,7 @@ use std::{fmt<|>::{Debug, Display}};
178use std::{fmt::Debug, fmt<|>::Display}; 176use std::{fmt::Debug, fmt<|>::Display};
179", 177",
180 r" 178 r"
181use std::{fmt::<|>{Display, Debug}}; 179use std::{fmt::{Display, Debug}};
182", 180",
183 ); 181 );
184 } 182 }
@@ -192,7 +190,7 @@ use std<|>::cell::*;
192use std::str; 190use std::str;
193", 191",
194 r" 192 r"
195use std<|>::{cell::*, str}; 193use std::{cell::*, str};
196", 194",
197 ) 195 )
198 } 196 }
@@ -206,7 +204,7 @@ use std<|>::cell::*;
206use std::str::*; 204use std::str::*;
207", 205",
208 r" 206 r"
209use std<|>::{cell::*, str::*}; 207use std::{cell::*, str::*};
210", 208",
211 ) 209 )
212 } 210 }
@@ -222,7 +220,7 @@ use foo::baz;
222/// Doc comment 220/// Doc comment
223", 221",
224 r" 222 r"
225use foo<|>::{bar, baz}; 223use foo::{bar, baz};
226 224
227/// Doc comment 225/// Doc comment
228", 226",
@@ -241,7 +239,7 @@ use {
241", 239",
242 r" 240 r"
243use { 241use {
244 foo<|>::{bar, baz}, 242 foo::{bar, baz},
245}; 243};
246", 244",
247 ); 245 );
@@ -255,7 +253,7 @@ use {
255", 253",
256 r" 254 r"
257use { 255use {
258 foo::{bar<|>, baz}, 256 foo::{bar, baz},
259}; 257};
260", 258",
261 ); 259 );
@@ -272,7 +270,7 @@ use foo::<|>{
272}; 270};
273", 271",
274 r" 272 r"
275use foo::{<|> 273use foo::{
276 FooBar, 274 FooBar,
277bar::baz}; 275bar::baz};
278", 276",
diff --git a/crates/ra_assists/src/handlers/merge_match_arms.rs b/crates/ra_assists/src/handlers/merge_match_arms.rs
index d4e38aa6a..ca04ec671 100644
--- a/crates/ra_assists/src/handlers/merge_match_arms.rs
+++ b/crates/ra_assists/src/handlers/merge_match_arms.rs
@@ -3,7 +3,7 @@ use std::iter::successors;
3use ra_syntax::{ 3use ra_syntax::{
4 algo::neighbor, 4 algo::neighbor,
5 ast::{self, AstNode}, 5 ast::{self, AstNode},
6 Direction, TextSize, 6 Direction,
7}; 7};
8 8
9use crate::{AssistContext, AssistId, Assists, TextRange}; 9use crate::{AssistContext, AssistId, Assists, TextRange};
@@ -41,17 +41,6 @@ pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option
41 let current_expr = current_arm.expr()?; 41 let current_expr = current_arm.expr()?;
42 let current_text_range = current_arm.syntax().text_range(); 42 let current_text_range = current_arm.syntax().text_range();
43 43
44 enum CursorPos {
45 InExpr(TextSize),
46 InPat(TextSize),
47 }
48 let cursor_pos = ctx.offset();
49 let cursor_pos = if current_expr.syntax().text_range().contains(cursor_pos) {
50 CursorPos::InExpr(current_text_range.end() - cursor_pos)
51 } else {
52 CursorPos::InPat(cursor_pos)
53 };
54
55 // We check if the following match arms match this one. We could, but don't, 44 // We check if the following match arms match this one. We could, but don't,
56 // compare to the previous match arm as well. 45 // compare to the previous match arm as well.
57 let arms_to_merge = successors(Some(current_arm), |it| neighbor(it, Direction::Next)) 46 let arms_to_merge = successors(Some(current_arm), |it| neighbor(it, Direction::Next))
@@ -87,10 +76,6 @@ pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option
87 let start = arms_to_merge.first().unwrap().syntax().text_range().start(); 76 let start = arms_to_merge.first().unwrap().syntax().text_range().start();
88 let end = arms_to_merge.last().unwrap().syntax().text_range().end(); 77 let end = arms_to_merge.last().unwrap().syntax().text_range().end();
89 78
90 edit.set_cursor(match cursor_pos {
91 CursorPos::InExpr(back_offset) => start + TextSize::of(&arm) - back_offset,
92 CursorPos::InPat(offset) => offset,
93 });
94 edit.replace(TextRange::new(start, end), arm); 79 edit.replace(TextRange::new(start, end), arm);
95 }) 80 })
96} 81}
@@ -132,7 +117,7 @@ mod tests {
132 fn main() { 117 fn main() {
133 let x = X::A; 118 let x = X::A;
134 let y = match x { 119 let y = match x {
135 X::A | X::B => { 1i32<|> } 120 X::A | X::B => { 1i32 }
136 X::C => { 2i32 } 121 X::C => { 2i32 }
137 } 122 }
138 } 123 }
@@ -164,7 +149,7 @@ mod tests {
164 fn main() { 149 fn main() {
165 let x = X::A; 150 let x = X::A;
166 let y = match x { 151 let y = match x {
167 X::A | X::B | X::C | X::D => {<|> 1i32 }, 152 X::A | X::B | X::C | X::D => { 1i32 },
168 X::E => { 2i32 }, 153 X::E => { 2i32 },
169 } 154 }
170 } 155 }
@@ -197,7 +182,7 @@ mod tests {
197 let x = X::A; 182 let x = X::A;
198 let y = match x { 183 let y = match x {
199 X::A => { 1i32 }, 184 X::A => { 1i32 },
200 _ => { 2i<|>32 } 185 _ => { 2i32 }
201 } 186 }
202 } 187 }
203 "#, 188 "#,
@@ -226,7 +211,7 @@ mod tests {
226 211
227 fn main() { 212 fn main() {
228 match X::A { 213 match X::A {
229 X::A<|> | X::B | X::C => 92, 214 X::A | X::B | X::C => 92,
230 X::D => 62, 215 X::D => 62,
231 _ => panic!(), 216 _ => panic!(),
232 } 217 }
diff --git a/crates/ra_assists/src/handlers/move_bounds.rs b/crates/ra_assists/src/handlers/move_bounds.rs
index a41aacfc3..be2a7eddc 100644
--- a/crates/ra_assists/src/handlers/move_bounds.rs
+++ b/crates/ra_assists/src/handlers/move_bounds.rs
@@ -99,7 +99,7 @@ mod tests {
99 fn foo<T: u32, <|>F: FnOnce(T) -> T>() {} 99 fn foo<T: u32, <|>F: FnOnce(T) -> T>() {}
100 "#, 100 "#,
101 r#" 101 r#"
102 fn foo<T, <|>F>() where T: u32, F: FnOnce(T) -> T {} 102 fn foo<T, F>() where T: u32, F: FnOnce(T) -> T {}
103 "#, 103 "#,
104 ); 104 );
105 } 105 }
@@ -112,7 +112,7 @@ mod tests {
112 impl<U: u32, <|>T> A<U, T> {} 112 impl<U: u32, <|>T> A<U, T> {}
113 "#, 113 "#,
114 r#" 114 r#"
115 impl<U, <|>T> A<U, T> where U: u32 {} 115 impl<U, T> A<U, T> where U: u32 {}
116 "#, 116 "#,
117 ); 117 );
118 } 118 }
@@ -125,7 +125,7 @@ mod tests {
125 struct A<<|>T: Iterator<Item = u32>> {} 125 struct A<<|>T: Iterator<Item = u32>> {}
126 "#, 126 "#,
127 r#" 127 r#"
128 struct A<<|>T> where T: Iterator<Item = u32> {} 128 struct A<T> where T: Iterator<Item = u32> {}
129 "#, 129 "#,
130 ); 130 );
131 } 131 }
@@ -138,7 +138,7 @@ mod tests {
138 struct Pair<<|>T: u32>(T, T); 138 struct Pair<<|>T: u32>(T, T);
139 "#, 139 "#,
140 r#" 140 r#"
141 struct Pair<<|>T>(T, T) where T: u32; 141 struct Pair<T>(T, T) where T: u32;
142 "#, 142 "#,
143 ); 143 );
144 } 144 }
diff --git a/crates/ra_assists/src/handlers/move_guard.rs b/crates/ra_assists/src/handlers/move_guard.rs
index fc0335b57..7edcf0748 100644
--- a/crates/ra_assists/src/handlers/move_guard.rs
+++ b/crates/ra_assists/src/handlers/move_guard.rs
@@ -1,7 +1,6 @@
1use ra_syntax::{ 1use ra_syntax::{
2 ast, 2 ast::{AstNode, IfExpr, MatchArm},
3 ast::{AstNode, AstToken, IfExpr, MatchArm}, 3 SyntaxKind::WHITESPACE,
4 TextSize,
5}; 4};
6 5
7use crate::{AssistContext, AssistId, Assists}; 6use crate::{AssistContext, AssistId, Assists};
@@ -42,24 +41,15 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext) ->
42 41
43 let target = guard.syntax().text_range(); 42 let target = guard.syntax().text_range();
44 acc.add(AssistId("move_guard_to_arm_body"), "Move guard to arm body", target, |edit| { 43 acc.add(AssistId("move_guard_to_arm_body"), "Move guard to arm body", target, |edit| {
45 let offseting_amount = match space_before_guard.and_then(|it| it.into_token()) { 44 match space_before_guard {
46 Some(tok) => { 45 Some(element) if element.kind() == WHITESPACE => {
47 if ast::Whitespace::cast(tok.clone()).is_some() { 46 edit.delete(element.text_range());
48 let ele = tok.text_range();
49 edit.delete(ele);
50 ele.len()
51 } else {
52 TextSize::from(0)
53 }
54 } 47 }
55 _ => TextSize::from(0), 48 _ => (),
56 }; 49 };
57 50
58 edit.delete(guard.syntax().text_range()); 51 edit.delete(guard.syntax().text_range());
59 edit.replace_node_and_indent(arm_expr.syntax(), buf); 52 edit.replace_node_and_indent(arm_expr.syntax(), buf);
60 edit.set_cursor(
61 arm_expr.syntax().text_range().start() + TextSize::from(3) - offseting_amount,
62 );
63 }) 53 })
64} 54}
65 55
@@ -124,7 +114,6 @@ pub(crate) fn move_arm_cond_to_match_guard(acc: &mut Assists, ctx: &AssistContex
124 } 114 }
125 115
126 edit.insert(match_pat.syntax().text_range().end(), buf); 116 edit.insert(match_pat.syntax().text_range().end(), buf);
127 edit.set_cursor(match_pat.syntax().text_range().end() + TextSize::from(1));
128 }, 117 },
129 ) 118 )
130} 119}
@@ -172,7 +161,7 @@ mod tests {
172 let t = 'a'; 161 let t = 'a';
173 let chars = "abcd"; 162 let chars = "abcd";
174 match t { 163 match t {
175 '\r' => if chars.clone().next() == Some('\n') { <|>false }, 164 '\r' => if chars.clone().next() == Some('\n') { false },
176 _ => true 165 _ => true
177 } 166 }
178 } 167 }
@@ -195,7 +184,7 @@ mod tests {
195 r#" 184 r#"
196 fn f() { 185 fn f() {
197 match x { 186 match x {
198 y @ 4 | y @ 5 => if y > 5 { <|>true }, 187 y @ 4 | y @ 5 => if y > 5 { true },
199 _ => false 188 _ => false
200 } 189 }
201 } 190 }
@@ -222,7 +211,7 @@ mod tests {
222 let t = 'a'; 211 let t = 'a';
223 let chars = "abcd"; 212 let chars = "abcd";
224 match t { 213 match t {
225 '\r' <|>if chars.clone().next() == Some('\n') => false, 214 '\r' if chars.clone().next() == Some('\n') => false,
226 _ => true 215 _ => true
227 } 216 }
228 } 217 }
@@ -266,7 +255,7 @@ mod tests {
266 let t = 'a'; 255 let t = 'a';
267 let chars = "abcd"; 256 let chars = "abcd";
268 match t { 257 match t {
269 '\r' <|>if chars.clone().next().is_some() => { }, 258 '\r' if chars.clone().next().is_some() => { },
270 _ => true 259 _ => true
271 } 260 }
272 } 261 }
@@ -296,7 +285,7 @@ mod tests {
296 let mut t = 'a'; 285 let mut t = 'a';
297 let chars = "abcd"; 286 let chars = "abcd";
298 match t { 287 match t {
299 '\r' <|>if chars.clone().next().is_some() => { 288 '\r' if chars.clone().next().is_some() => {
300 t = 'e'; 289 t = 'e';
301 false 290 false
302 }, 291 },
diff --git a/crates/ra_assists/src/handlers/raw_string.rs b/crates/ra_assists/src/handlers/raw_string.rs
index c20ffe0b3..16002d2ac 100644
--- a/crates/ra_assists/src/handlers/raw_string.rs
+++ b/crates/ra_assists/src/handlers/raw_string.rs
@@ -164,7 +164,7 @@ mod test {
164 "#, 164 "#,
165 r##" 165 r##"
166 fn f() { 166 fn f() {
167 let s = <|>r#"random 167 let s = r#"random
168string"#; 168string"#;
169 } 169 }
170 "##, 170 "##,
@@ -182,7 +182,7 @@ string"#;
182 "#, 182 "#,
183 r##" 183 r##"
184 fn f() { 184 fn f() {
185 format!(<|>r#"x = {}"#, 92) 185 format!(r#"x = {}"#, 92)
186 } 186 }
187 "##, 187 "##,
188 ) 188 )
@@ -199,7 +199,7 @@ string"#;
199 "###, 199 "###,
200 r####" 200 r####"
201 fn f() { 201 fn f() {
202 let s = <|>r#"#random## 202 let s = r#"#random##
203string"#; 203string"#;
204 } 204 }
205 "####, 205 "####,
@@ -217,7 +217,7 @@ string"#;
217 "###, 217 "###,
218 r####" 218 r####"
219 fn f() { 219 fn f() {
220 let s = <|>r###"#random"## 220 let s = r###"#random"##
221string"###; 221string"###;
222 } 222 }
223 "####, 223 "####,
@@ -235,7 +235,7 @@ string"###;
235 "#, 235 "#,
236 r##" 236 r##"
237 fn f() { 237 fn f() {
238 let s = <|>r#"random string"#; 238 let s = r#"random string"#;
239 } 239 }
240 "##, 240 "##,
241 ) 241 )
@@ -289,7 +289,7 @@ string"###;
289 "#, 289 "#,
290 r##" 290 r##"
291 fn f() { 291 fn f() {
292 let s = <|>r#"random string"#; 292 let s = r#"random string"#;
293 } 293 }
294 "##, 294 "##,
295 ) 295 )
@@ -306,7 +306,7 @@ string"###;
306 "##, 306 "##,
307 r###" 307 r###"
308 fn f() { 308 fn f() {
309 let s = <|>r##"random"string"##; 309 let s = r##"random"string"##;
310 } 310 }
311 "###, 311 "###,
312 ) 312 )
@@ -348,7 +348,7 @@ string"###;
348 "##, 348 "##,
349 r#" 349 r#"
350 fn f() { 350 fn f() {
351 let s = <|>r"random string"; 351 let s = r"random string";
352 } 352 }
353 "#, 353 "#,
354 ) 354 )
@@ -365,7 +365,7 @@ string"###;
365 "##, 365 "##,
366 r#" 366 r#"
367 fn f() { 367 fn f() {
368 let s = <|>r"random\"str\"ing"; 368 let s = r"random\"str\"ing";
369 } 369 }
370 "#, 370 "#,
371 ) 371 )
@@ -382,7 +382,7 @@ string"###;
382 "###, 382 "###,
383 r##" 383 r##"
384 fn f() { 384 fn f() {
385 let s = <|>r#"random string"#; 385 let s = r#"random string"#;
386 } 386 }
387 "##, 387 "##,
388 ) 388 )
@@ -436,7 +436,7 @@ string"###;
436 "##, 436 "##,
437 r#" 437 r#"
438 fn f() { 438 fn f() {
439 let s = <|>"random string"; 439 let s = "random string";
440 } 440 }
441 "#, 441 "#,
442 ) 442 )
@@ -453,7 +453,7 @@ string"###;
453 "##, 453 "##,
454 r#" 454 r#"
455 fn f() { 455 fn f() {
456 let s = <|>"random\"str\"ing"; 456 let s = "random\"str\"ing";
457 } 457 }
458 "#, 458 "#,
459 ) 459 )
@@ -470,7 +470,7 @@ string"###;
470 "###, 470 "###,
471 r##" 471 r##"
472 fn f() { 472 fn f() {
473 let s = <|>"random string"; 473 let s = "random string";
474 } 474 }
475 "##, 475 "##,
476 ) 476 )
diff --git a/crates/ra_assists/src/handlers/remove_dbg.rs b/crates/ra_assists/src/handlers/remove_dbg.rs
index 8eef578cf..961ee1731 100644
--- a/crates/ra_assists/src/handlers/remove_dbg.rs
+++ b/crates/ra_assists/src/handlers/remove_dbg.rs
@@ -29,26 +29,6 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
29 29
30 let macro_range = macro_call.syntax().text_range(); 30 let macro_range = macro_call.syntax().text_range();
31 31
32 // If the cursor is inside the macro call, we'll try to maintain the cursor
33 // position by subtracting the length of dbg!( from the start of the file
34 // range, otherwise we'll default to using the start of the macro call
35 let cursor_pos = {
36 let file_range = ctx.frange.range;
37
38 let offset_start = file_range
39 .start()
40 .checked_sub(macro_range.start())
41 .unwrap_or_else(|| TextSize::from(0));
42
43 let dbg_size = TextSize::of("dbg!(");
44
45 if offset_start > dbg_size {
46 file_range.start() - dbg_size
47 } else {
48 macro_range.start()
49 }
50 };
51
52 let macro_content = { 32 let macro_content = {
53 let macro_args = macro_call.token_tree()?.syntax().clone(); 33 let macro_args = macro_call.token_tree()?.syntax().clone();
54 34
@@ -58,9 +38,8 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
58 }; 38 };
59 39
60 let target = macro_call.syntax().text_range(); 40 let target = macro_call.syntax().text_range();
61 acc.add(AssistId("remove_dbg"), "Remove dbg!()", target, |edit| { 41 acc.add(AssistId("remove_dbg"), "Remove dbg!()", target, |builder| {
62 edit.replace(macro_range, macro_content); 42 builder.replace(macro_range, macro_content);
63 edit.set_cursor(cursor_pos);
64 }) 43 })
65} 44}
66 45
@@ -94,13 +73,13 @@ mod tests {
94 73
95 #[test] 74 #[test]
96 fn test_remove_dbg() { 75 fn test_remove_dbg() {
97 check_assist(remove_dbg, "<|>dbg!(1 + 1)", "<|>1 + 1"); 76 check_assist(remove_dbg, "<|>dbg!(1 + 1)", "1 + 1");
98 77
99 check_assist(remove_dbg, "dbg!<|>((1 + 1))", "<|>(1 + 1)"); 78 check_assist(remove_dbg, "dbg!<|>((1 + 1))", "(1 + 1)");
100 79
101 check_assist(remove_dbg, "dbg!(1 <|>+ 1)", "1 <|>+ 1"); 80 check_assist(remove_dbg, "dbg!(1 <|>+ 1)", "1 + 1");
102 81
103 check_assist(remove_dbg, "let _ = <|>dbg!(1 + 1)", "let _ = <|>1 + 1"); 82 check_assist(remove_dbg, "let _ = <|>dbg!(1 + 1)", "let _ = 1 + 1");
104 83
105 check_assist( 84 check_assist(
106 remove_dbg, 85 remove_dbg,
@@ -113,7 +92,7 @@ fn foo(n: usize) {
113", 92",
114 " 93 "
115fn foo(n: usize) { 94fn foo(n: usize) {
116 if let Some(_) = n.<|>checked_sub(4) { 95 if let Some(_) = n.checked_sub(4) {
117 // ... 96 // ...
118 } 97 }
119} 98}
@@ -122,8 +101,8 @@ fn foo(n: usize) {
122 } 101 }
123 #[test] 102 #[test]
124 fn test_remove_dbg_with_brackets_and_braces() { 103 fn test_remove_dbg_with_brackets_and_braces() {
125 check_assist(remove_dbg, "dbg![<|>1 + 1]", "<|>1 + 1"); 104 check_assist(remove_dbg, "dbg![<|>1 + 1]", "1 + 1");
126 check_assist(remove_dbg, "dbg!{<|>1 + 1}", "<|>1 + 1"); 105 check_assist(remove_dbg, "dbg!{<|>1 + 1}", "1 + 1");
127 } 106 }
128 107
129 #[test] 108 #[test]
diff --git a/crates/ra_assists/src/handlers/remove_mut.rs b/crates/ra_assists/src/handlers/remove_mut.rs
index dce546db7..fe4eada03 100644
--- a/crates/ra_assists/src/handlers/remove_mut.rs
+++ b/crates/ra_assists/src/handlers/remove_mut.rs
@@ -26,8 +26,7 @@ pub(crate) fn remove_mut(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
26 }; 26 };
27 27
28 let target = mut_token.text_range(); 28 let target = mut_token.text_range();
29 acc.add(AssistId("remove_mut"), "Remove `mut` keyword", target, |edit| { 29 acc.add(AssistId("remove_mut"), "Remove `mut` keyword", target, |builder| {
30 edit.set_cursor(delete_from); 30 builder.delete(TextRange::new(delete_from, delete_to));
31 edit.delete(TextRange::new(delete_from, delete_to));
32 }) 31 })
33} 32}
diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs
index 757f6406e..897da2832 100644
--- a/crates/ra_assists/src/handlers/reorder_fields.rs
+++ b/crates/ra_assists/src/handlers/reorder_fields.rs
@@ -23,7 +23,7 @@ use crate::{AssistContext, AssistId, Assists};
23// ``` 23// ```
24// 24//
25pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 25pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
26 reorder::<ast::RecordLit>(acc, ctx.clone()).or_else(|| reorder::<ast::RecordPat>(acc, ctx)) 26 reorder::<ast::RecordLit>(acc, ctx).or_else(|| reorder::<ast::RecordPat>(acc, ctx))
27} 27}
28 28
29fn reorder<R: AstNode>(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 29fn reorder<R: AstNode>(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
@@ -140,7 +140,7 @@ mod tests {
140 "#, 140 "#,
141 r#" 141 r#"
142 struct Foo {foo: i32, bar: i32}; 142 struct Foo {foo: i32, bar: i32};
143 const test: Foo = <|>Foo {foo: 1, bar: 0} 143 const test: Foo = Foo {foo: 1, bar: 0}
144 "#, 144 "#,
145 ) 145 )
146 } 146 }
@@ -164,7 +164,7 @@ mod tests {
164 164
165 fn f(f: Foo) -> { 165 fn f(f: Foo) -> {
166 match f { 166 match f {
167 <|>Foo { ref mut bar, baz: 0, .. } => (), 167 Foo { ref mut bar, baz: 0, .. } => (),
168 _ => () 168 _ => ()
169 } 169 }
170 } 170 }
@@ -202,7 +202,7 @@ mod tests {
202 impl Foo { 202 impl Foo {
203 fn new() -> Foo { 203 fn new() -> Foo {
204 let foo = String::new(); 204 let foo = String::new();
205 <|>Foo { 205 Foo {
206 foo, 206 foo,
207 bar: foo.clone(), 207 bar: foo.clone(),
208 extra: "Extra field", 208 extra: "Extra field",
diff --git a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
index 65f5fc6ab..e016f51c3 100644
--- a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
+++ b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
@@ -68,7 +68,6 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext)
68 .indent(IndentLevel::from_node(if_expr.syntax())) 68 .indent(IndentLevel::from_node(if_expr.syntax()))
69 }; 69 };
70 70
71 edit.set_cursor(if_expr.syntax().text_range().start());
72 edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr); 71 edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr);
73 }) 72 })
74} 73}
@@ -83,7 +82,7 @@ mod tests {
83 fn test_replace_if_let_with_match_unwraps_simple_expressions() { 82 fn test_replace_if_let_with_match_unwraps_simple_expressions() {
84 check_assist( 83 check_assist(
85 replace_if_let_with_match, 84 replace_if_let_with_match,
86 " 85 r#"
87impl VariantData { 86impl VariantData {
88 pub fn is_struct(&self) -> bool { 87 pub fn is_struct(&self) -> bool {
89 if <|>let VariantData::Struct(..) = *self { 88 if <|>let VariantData::Struct(..) = *self {
@@ -92,16 +91,16 @@ impl VariantData {
92 false 91 false
93 } 92 }
94 } 93 }
95} ", 94} "#,
96 " 95 r#"
97impl VariantData { 96impl VariantData {
98 pub fn is_struct(&self) -> bool { 97 pub fn is_struct(&self) -> bool {
99 <|>match *self { 98 match *self {
100 VariantData::Struct(..) => true, 99 VariantData::Struct(..) => true,
101 _ => false, 100 _ => false,
102 } 101 }
103 } 102 }
104} ", 103} "#,
105 ) 104 )
106 } 105 }
107 106
@@ -109,7 +108,7 @@ impl VariantData {
109 fn test_replace_if_let_with_match_doesnt_unwrap_multiline_expressions() { 108 fn test_replace_if_let_with_match_doesnt_unwrap_multiline_expressions() {
110 check_assist( 109 check_assist(
111 replace_if_let_with_match, 110 replace_if_let_with_match,
112 " 111 r#"
113fn foo() { 112fn foo() {
114 if <|>let VariantData::Struct(..) = a { 113 if <|>let VariantData::Struct(..) = a {
115 bar( 114 bar(
@@ -118,10 +117,10 @@ fn foo() {
118 } else { 117 } else {
119 false 118 false
120 } 119 }
121} ", 120} "#,
122 " 121 r#"
123fn foo() { 122fn foo() {
124 <|>match a { 123 match a {
125 VariantData::Struct(..) => { 124 VariantData::Struct(..) => {
126 bar( 125 bar(
127 123 126 123
@@ -129,7 +128,7 @@ fn foo() {
129 } 128 }
130 _ => false, 129 _ => false,
131 } 130 }
132} ", 131} "#,
133 ) 132 )
134 } 133 }
135 134
@@ -137,7 +136,7 @@ fn foo() {
137 fn replace_if_let_with_match_target() { 136 fn replace_if_let_with_match_target() {
138 check_assist_target( 137 check_assist_target(
139 replace_if_let_with_match, 138 replace_if_let_with_match,
140 " 139 r#"
141impl VariantData { 140impl VariantData {
142 pub fn is_struct(&self) -> bool { 141 pub fn is_struct(&self) -> bool {
143 if <|>let VariantData::Struct(..) = *self { 142 if <|>let VariantData::Struct(..) = *self {
@@ -146,7 +145,7 @@ impl VariantData {
146 false 145 false
147 } 146 }
148 } 147 }
149} ", 148} "#,
150 "if let VariantData::Struct(..) = *self { 149 "if let VariantData::Struct(..) = *self {
151 true 150 true
152 } else { 151 } else {
@@ -176,7 +175,7 @@ enum Option<T> { Some(T), None }
176use Option::*; 175use Option::*;
177 176
178fn foo(x: Option<i32>) { 177fn foo(x: Option<i32>) {
179 <|>match x { 178 match x {
180 Some(x) => println!("{}", x), 179 Some(x) => println!("{}", x),
181 None => println!("none"), 180 None => println!("none"),
182 } 181 }
@@ -206,7 +205,7 @@ enum Result<T, E> { Ok(T), Err(E) }
206use Result::*; 205use Result::*;
207 206
208fn foo(x: Result<i32, ()>) { 207fn foo(x: Result<i32, ()>) {
209 <|>match x { 208 match x {
210 Ok(x) => println!("{}", x), 209 Ok(x) => println!("{}", x),
211 Err(_) => println!("none"), 210 Err(_) => println!("none"),
212 } 211 }
diff --git a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs
index 482957dc6..761557ac0 100644
--- a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs
+++ b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs
@@ -58,12 +58,9 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext) ->
58 let stmt = make::expr_stmt(if_); 58 let stmt = make::expr_stmt(if_);
59 59
60 let placeholder = stmt.syntax().descendants().find_map(ast::PlaceholderPat::cast).unwrap(); 60 let placeholder = stmt.syntax().descendants().find_map(ast::PlaceholderPat::cast).unwrap();
61 let target_offset =
62 let_stmt.syntax().text_range().start() + placeholder.syntax().text_range().start();
63 let stmt = stmt.replace_descendant(placeholder.into(), original_pat); 61 let stmt = stmt.replace_descendant(placeholder.into(), original_pat);
64 62
65 edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt)); 63 edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt));
66 edit.set_cursor(target_offset);
67 }) 64 })
68} 65}
69 66
@@ -88,7 +85,7 @@ fn main() {
88enum E<T> { X(T), Y(T) } 85enum E<T> { X(T), Y(T) }
89 86
90fn main() { 87fn main() {
91 if let <|>x = E::X(92) { 88 if let x = E::X(92) {
92 } 89 }
93} 90}
94 ", 91 ",
diff --git a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
index d9f84208d..0197a8cf0 100644
--- a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
@@ -89,7 +89,7 @@ std::fmt::Debug<|>
89 " 89 "
90use std::fmt::Debug; 90use std::fmt::Debug;
91 91
92Debug<|> 92Debug
93 ", 93 ",
94 ); 94 );
95 } 95 }
@@ -106,7 +106,7 @@ fn main() {
106 " 106 "
107use std::fmt::Debug; 107use std::fmt::Debug;
108 108
109Debug<|> 109Debug
110 110
111fn main() { 111fn main() {
112} 112}
@@ -130,7 +130,7 @@ use std::fmt::Debug;
130fn main() { 130fn main() {
131} 131}
132 132
133Debug<|> 133Debug
134 ", 134 ",
135 ); 135 );
136 } 136 }
@@ -145,7 +145,7 @@ std::fmt<|>::Debug
145 " 145 "
146use std::fmt; 146use std::fmt;
147 147
148fmt<|>::Debug 148fmt::Debug
149 ", 149 ",
150 ); 150 );
151 } 151 }
@@ -164,7 +164,7 @@ impl std::fmt::Debug<|> for Foo {
164use stdx; 164use stdx;
165use std::fmt::Debug; 165use std::fmt::Debug;
166 166
167impl Debug<|> for Foo { 167impl Debug for Foo {
168} 168}
169 ", 169 ",
170 ); 170 );
@@ -181,7 +181,7 @@ impl std::fmt::Debug<|> for Foo {
181 " 181 "
182use std::fmt::Debug; 182use std::fmt::Debug;
183 183
184impl Debug<|> for Foo { 184impl Debug for Foo {
185} 185}
186 ", 186 ",
187 ); 187 );
@@ -198,7 +198,7 @@ impl Debug<|> for Foo {
198 " 198 "
199 use std::fmt::Debug; 199 use std::fmt::Debug;
200 200
201 impl Debug<|> for Foo { 201 impl Debug for Foo {
202 } 202 }
203 ", 203 ",
204 ); 204 );
@@ -217,7 +217,7 @@ impl std::io<|> for Foo {
217 " 217 "
218use std::{io, fmt}; 218use std::{io, fmt};
219 219
220impl io<|> for Foo { 220impl io for Foo {
221} 221}
222 ", 222 ",
223 ); 223 );
@@ -236,7 +236,7 @@ impl std::fmt::Debug<|> for Foo {
236 " 236 "
237use std::fmt::{self, Debug, }; 237use std::fmt::{self, Debug, };
238 238
239impl Debug<|> for Foo { 239impl Debug for Foo {
240} 240}
241 ", 241 ",
242 ); 242 );
@@ -255,7 +255,7 @@ impl std::fmt<|> for Foo {
255 " 255 "
256use std::fmt::{self, Debug}; 256use std::fmt::{self, Debug};
257 257
258impl fmt<|> for Foo { 258impl fmt for Foo {
259} 259}
260 ", 260 ",
261 ); 261 );
@@ -274,7 +274,7 @@ impl std::fmt::nested<|> for Foo {
274 " 274 "
275use std::fmt::{Debug, nested::{Display, self}}; 275use std::fmt::{Debug, nested::{Display, self}};
276 276
277impl nested<|> for Foo { 277impl nested for Foo {
278} 278}
279", 279",
280 ); 280 );
@@ -293,7 +293,7 @@ impl std::fmt::nested<|> for Foo {
293 " 293 "
294use std::fmt::{Debug, nested::{self, Display}}; 294use std::fmt::{Debug, nested::{self, Display}};
295 295
296impl nested<|> for Foo { 296impl nested for Foo {
297} 297}
298", 298",
299 ); 299 );
@@ -312,7 +312,7 @@ impl std::fmt::nested::Debug<|> for Foo {
312 " 312 "
313use std::fmt::{Debug, nested::{Display, Debug}}; 313use std::fmt::{Debug, nested::{Display, Debug}};
314 314
315impl Debug<|> for Foo { 315impl Debug for Foo {
316} 316}
317", 317",
318 ); 318 );
@@ -331,7 +331,7 @@ impl std::fmt::nested::Display<|> for Foo {
331 " 331 "
332use std::fmt::{nested::Display, Debug}; 332use std::fmt::{nested::Display, Debug};
333 333
334impl Display<|> for Foo { 334impl Display for Foo {
335} 335}
336", 336",
337 ); 337 );
@@ -350,7 +350,7 @@ impl std::fmt::Display<|> for Foo {
350 " 350 "
351use std::fmt::{Display, nested::Debug}; 351use std::fmt::{Display, nested::Debug};
352 352
353impl Display<|> for Foo { 353impl Display for Foo {
354} 354}
355", 355",
356 ); 356 );
@@ -374,7 +374,7 @@ use crate::{
374 AssocItem, 374 AssocItem,
375}; 375};
376 376
377fn foo() { lower<|>::trait_env() } 377fn foo() { lower::trait_env() }
378", 378",
379 ); 379 );
380 } 380 }
@@ -392,7 +392,7 @@ impl foo::Debug<|> for Foo {
392 " 392 "
393use std::fmt as foo; 393use std::fmt as foo;
394 394
395impl Debug<|> for Foo { 395impl Debug for Foo {
396} 396}
397", 397",
398 ); 398 );
@@ -435,7 +435,7 @@ mod foo {
435 mod bar { 435 mod bar {
436 use std::fmt::Debug; 436 use std::fmt::Debug;
437 437
438 Debug<|> 438 Debug
439 } 439 }
440} 440}
441 ", 441 ",
@@ -458,7 +458,7 @@ fn main() {
458use std::fmt::Debug; 458use std::fmt::Debug;
459 459
460fn main() { 460fn main() {
461 Debug<|> 461 Debug
462} 462}
463 ", 463 ",
464 ); 464 );
diff --git a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
index b379b55a8..cff7dfb81 100644
--- a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
+++ b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
@@ -9,7 +9,10 @@ use ra_syntax::{
9 AstNode, 9 AstNode,
10}; 10};
11 11
12use crate::{utils::TryEnum, AssistContext, AssistId, Assists}; 12use crate::{
13 utils::{render_snippet, Cursor, TryEnum},
14 AssistContext, AssistId, Assists,
15};
13 16
14// Assist: replace_unwrap_with_match 17// Assist: replace_unwrap_with_match
15// 18//
@@ -29,7 +32,7 @@ use crate::{utils::TryEnum, AssistContext, AssistId, Assists};
29// let x: Result<i32, i32> = Result::Ok(92); 32// let x: Result<i32, i32> = Result::Ok(92);
30// let y = match x { 33// let y = match x {
31// Ok(a) => a, 34// Ok(a) => a,
32// _ => unreachable!(), 35// $0_ => unreachable!(),
33// }; 36// };
34// } 37// }
35// ``` 38// ```
@@ -43,7 +46,7 @@ pub(crate) fn replace_unwrap_with_match(acc: &mut Assists, ctx: &AssistContext)
43 let ty = ctx.sema.type_of_expr(&caller)?; 46 let ty = ctx.sema.type_of_expr(&caller)?;
44 let happy_variant = TryEnum::from_ty(&ctx.sema, &ty)?.happy_case(); 47 let happy_variant = TryEnum::from_ty(&ctx.sema, &ty)?.happy_case();
45 let target = method_call.syntax().text_range(); 48 let target = method_call.syntax().text_range();
46 acc.add(AssistId("replace_unwrap_with_match"), "Replace unwrap with match", target, |edit| { 49 acc.add(AssistId("replace_unwrap_with_match"), "Replace unwrap with match", target, |builder| {
47 let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant))); 50 let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant)));
48 let it = make::bind_pat(make::name("a")).into(); 51 let it = make::bind_pat(make::name("a")).into();
49 let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); 52 let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into();
@@ -58,16 +61,30 @@ pub(crate) fn replace_unwrap_with_match(acc: &mut Assists, ctx: &AssistContext)
58 let match_expr = make::expr_match(caller.clone(), match_arm_list) 61 let match_expr = make::expr_match(caller.clone(), match_arm_list)
59 .indent(IndentLevel::from_node(method_call.syntax())); 62 .indent(IndentLevel::from_node(method_call.syntax()));
60 63
61 edit.set_cursor(caller.syntax().text_range().start()); 64 let range = method_call.syntax().text_range();
62 edit.replace_ast::<ast::Expr>(method_call.into(), match_expr); 65 match ctx.config.snippet_cap {
66 Some(cap) => {
67 let err_arm = match_expr
68 .syntax()
69 .descendants()
70 .filter_map(ast::MatchArm::cast)
71 .last()
72 .unwrap();
73 let snippet =
74 render_snippet(cap, match_expr.syntax(), Cursor::Before(err_arm.syntax()));
75 builder.replace_snippet(cap, range, snippet)
76 }
77 None => builder.replace(range, match_expr.to_string()),
78 }
63 }) 79 })
64} 80}
65 81
66#[cfg(test)] 82#[cfg(test)]
67mod tests { 83mod tests {
68 use super::*;
69 use crate::tests::{check_assist, check_assist_target}; 84 use crate::tests::{check_assist, check_assist_target};
70 85
86 use super::*;
87
71 #[test] 88 #[test]
72 fn test_replace_result_unwrap_with_match() { 89 fn test_replace_result_unwrap_with_match() {
73 check_assist( 90 check_assist(
@@ -85,9 +102,9 @@ enum Result<T, E> { Ok(T), Err(E) }
85fn i<T>(a: T) -> T { a } 102fn i<T>(a: T) -> T { a }
86fn main() { 103fn main() {
87 let x: Result<i32, i32> = Result::Ok(92); 104 let x: Result<i32, i32> = Result::Ok(92);
88 let y = <|>match i(x) { 105 let y = match i(x) {
89 Ok(a) => a, 106 Ok(a) => a,
90 _ => unreachable!(), 107 $0_ => unreachable!(),
91 }; 108 };
92} 109}
93 ", 110 ",
@@ -111,9 +128,9 @@ enum Option<T> { Some(T), None }
111fn i<T>(a: T) -> T { a } 128fn i<T>(a: T) -> T { a }
112fn main() { 129fn main() {
113 let x = Option::Some(92); 130 let x = Option::Some(92);
114 let y = <|>match i(x) { 131 let y = match i(x) {
115 Some(a) => a, 132 Some(a) => a,
116 _ => unreachable!(), 133 $0_ => unreachable!(),
117 }; 134 };
118} 135}
119 ", 136 ",
@@ -137,9 +154,9 @@ enum Result<T, E> { Ok(T), Err(E) }
137fn i<T>(a: T) -> T { a } 154fn i<T>(a: T) -> T { a }
138fn main() { 155fn main() {
139 let x: Result<i32, i32> = Result::Ok(92); 156 let x: Result<i32, i32> = Result::Ok(92);
140 let y = <|>match i(x) { 157 let y = match i(x) {
141 Ok(a) => a, 158 Ok(a) => a,
142 _ => unreachable!(), 159 $0_ => unreachable!(),
143 }.count_zeroes(); 160 }.count_zeroes();
144} 161}
145 ", 162 ",
diff --git a/crates/ra_assists/src/handlers/split_import.rs b/crates/ra_assists/src/handlers/split_import.rs
index b2757e50c..c7a874480 100644
--- a/crates/ra_assists/src/handlers/split_import.rs
+++ b/crates/ra_assists/src/handlers/split_import.rs
@@ -26,12 +26,10 @@ pub(crate) fn split_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
26 if new_tree == use_tree { 26 if new_tree == use_tree {
27 return None; 27 return None;
28 } 28 }
29 let cursor = ctx.offset();
30 29
31 let target = colon_colon.text_range(); 30 let target = colon_colon.text_range();
32 acc.add(AssistId("split_import"), "Split import", target, |edit| { 31 acc.add(AssistId("split_import"), "Split import", target, |edit| {
33 edit.replace_ast(use_tree, new_tree); 32 edit.replace_ast(use_tree, new_tree);
34 edit.set_cursor(cursor);
35 }) 33 })
36} 34}
37 35
@@ -46,7 +44,7 @@ mod tests {
46 check_assist( 44 check_assist(
47 split_import, 45 split_import,
48 "use crate::<|>db::RootDatabase;", 46 "use crate::<|>db::RootDatabase;",
49 "use crate::<|>{db::RootDatabase};", 47 "use crate::{db::RootDatabase};",
50 ) 48 )
51 } 49 }
52 50
@@ -55,7 +53,7 @@ mod tests {
55 check_assist( 53 check_assist(
56 split_import, 54 split_import,
57 "use crate:<|>:db::{RootDatabase, FileSymbol}", 55 "use crate:<|>:db::{RootDatabase, FileSymbol}",
58 "use crate:<|>:{db::{RootDatabase, FileSymbol}}", 56 "use crate::{db::{RootDatabase, FileSymbol}}",
59 ) 57 )
60 } 58 }
61 59
diff --git a/crates/ra_assists/src/handlers/unwrap_block.rs b/crates/ra_assists/src/handlers/unwrap_block.rs
index e52ec557e..8440c7d0f 100644
--- a/crates/ra_assists/src/handlers/unwrap_block.rs
+++ b/crates/ra_assists/src/handlers/unwrap_block.rs
@@ -1,8 +1,10 @@
1use crate::{AssistContext, AssistId, Assists};
2
3use ast::{ElseBranch, Expr, LoopBodyOwner};
4use ra_fmt::unwrap_trivial_block; 1use ra_fmt::unwrap_trivial_block;
5use ra_syntax::{ast, match_ast, AstNode, TextRange, T}; 2use ra_syntax::{
3 ast::{self, ElseBranch, Expr, LoopBodyOwner},
4 match_ast, AstNode, TextRange, T,
5};
6
7use crate::{AssistContext, AssistId, Assists};
6 8
7// Assist: unwrap_block 9// Assist: unwrap_block
8// 10//
@@ -60,7 +62,6 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
60 let range_to_del_else_if = TextRange::new(ancestor_then_branch.syntax().text_range().end(), l_curly_token.text_range().start()); 62 let range_to_del_else_if = TextRange::new(ancestor_then_branch.syntax().text_range().end(), l_curly_token.text_range().start());
61 let range_to_del_rest = TextRange::new(then_branch.syntax().text_range().end(), if_expr.syntax().text_range().end()); 63 let range_to_del_rest = TextRange::new(then_branch.syntax().text_range().end(), if_expr.syntax().text_range().end());
62 64
63 edit.set_cursor(ancestor_then_branch.syntax().text_range().end());
64 edit.delete(range_to_del_rest); 65 edit.delete(range_to_del_rest);
65 edit.delete(range_to_del_else_if); 66 edit.delete(range_to_del_else_if);
66 edit.replace(target, update_expr_string(then_branch.to_string(), &[' ', '{'])); 67 edit.replace(target, update_expr_string(then_branch.to_string(), &[' ', '{']));
@@ -77,7 +78,6 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
77 return acc.add(assist_id, assist_label, target, |edit| { 78 return acc.add(assist_id, assist_label, target, |edit| {
78 let range_to_del = TextRange::new(then_branch.syntax().text_range().end(), l_curly_token.text_range().start()); 79 let range_to_del = TextRange::new(then_branch.syntax().text_range().end(), l_curly_token.text_range().start());
79 80
80 edit.set_cursor(then_branch.syntax().text_range().end());
81 edit.delete(range_to_del); 81 edit.delete(range_to_del);
82 edit.replace(target, update_expr_string(else_block.to_string(), &[' ', '{'])); 82 edit.replace(target, update_expr_string(else_block.to_string(), &[' ', '{']));
83 }); 83 });
@@ -95,8 +95,6 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
95 95
96 let target = expr_to_unwrap.syntax().text_range(); 96 let target = expr_to_unwrap.syntax().text_range();
97 acc.add(assist_id, assist_label, target, |edit| { 97 acc.add(assist_id, assist_label, target, |edit| {
98 edit.set_cursor(expr.syntax().text_range().start());
99
100 edit.replace( 98 edit.replace(
101 expr.syntax().text_range(), 99 expr.syntax().text_range(),
102 update_expr_string(expr_to_unwrap.to_string(), &[' ', '{', '\n']), 100 update_expr_string(expr_to_unwrap.to_string(), &[' ', '{', '\n']),
@@ -152,7 +150,7 @@ mod tests {
152 r#" 150 r#"
153 fn main() { 151 fn main() {
154 bar(); 152 bar();
155 <|>foo(); 153 foo();
156 154
157 //comment 155 //comment
158 bar(); 156 bar();
@@ -186,7 +184,7 @@ mod tests {
186 184
187 //comment 185 //comment
188 bar(); 186 bar();
189 }<|> 187 }
190 println!("bar"); 188 println!("bar");
191 } 189 }
192 "#, 190 "#,
@@ -220,7 +218,7 @@ mod tests {
220 218
221 //comment 219 //comment
222 //bar(); 220 //bar();
223 }<|> 221 }
224 println!("bar"); 222 println!("bar");
225 } 223 }
226 "#, 224 "#,
@@ -256,7 +254,7 @@ mod tests {
256 //bar(); 254 //bar();
257 } else if false { 255 } else if false {
258 println!("bar"); 256 println!("bar");
259 }<|> 257 }
260 println!("foo"); 258 println!("foo");
261 } 259 }
262 "#, 260 "#,
@@ -296,7 +294,7 @@ mod tests {
296 println!("bar"); 294 println!("bar");
297 } else if true { 295 } else if true {
298 println!("foo"); 296 println!("foo");
299 }<|> 297 }
300 println!("else"); 298 println!("else");
301 } 299 }
302 "#, 300 "#,
@@ -334,7 +332,7 @@ mod tests {
334 //bar(); 332 //bar();
335 } else if false { 333 } else if false {
336 println!("bar"); 334 println!("bar");
337 }<|> 335 }
338 println!("foo"); 336 println!("foo");
339 } 337 }
340 "#, 338 "#,
@@ -381,7 +379,7 @@ mod tests {
381 "#, 379 "#,
382 r#" 380 r#"
383 fn main() { 381 fn main() {
384 <|>if true { 382 if true {
385 foo(); 383 foo();
386 384
387 //comment 385 //comment
@@ -415,7 +413,7 @@ mod tests {
415 r#" 413 r#"
416 fn main() { 414 fn main() {
417 for i in 0..5 { 415 for i in 0..5 {
418 <|>foo(); 416 foo();
419 417
420 //comment 418 //comment
421 bar(); 419 bar();
@@ -445,7 +443,7 @@ mod tests {
445 "#, 443 "#,
446 r#" 444 r#"
447 fn main() { 445 fn main() {
448 <|>if true { 446 if true {
449 foo(); 447 foo();
450 448
451 //comment 449 //comment
@@ -478,7 +476,7 @@ mod tests {
478 "#, 476 "#,
479 r#" 477 r#"
480 fn main() { 478 fn main() {
481 <|>if true { 479 if true {
482 foo(); 480 foo();
483 481
484 //comment 482 //comment
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 339f24100..464bc03dd 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -12,7 +12,6 @@ macro_rules! eprintln {
12 12
13mod assist_config; 13mod assist_config;
14mod assist_context; 14mod assist_context;
15mod marks;
16#[cfg(test)] 15#[cfg(test)]
17mod tests; 16mod tests;
18pub mod utils; 17pub mod utils;
@@ -117,6 +116,7 @@ mod handlers {
117 mod change_visibility; 116 mod change_visibility;
118 mod early_return; 117 mod early_return;
119 mod fill_match_arms; 118 mod fill_match_arms;
119 mod fix_visibility;
120 mod flip_binexpr; 120 mod flip_binexpr;
121 mod flip_comma; 121 mod flip_comma;
122 mod flip_trait_bound; 122 mod flip_trait_bound;
@@ -155,6 +155,7 @@ mod handlers {
155 change_visibility::change_visibility, 155 change_visibility::change_visibility,
156 early_return::convert_to_guarded_return, 156 early_return::convert_to_guarded_return,
157 fill_match_arms::fill_match_arms, 157 fill_match_arms::fill_match_arms,
158 fix_visibility::fix_visibility,
158 flip_binexpr::flip_binexpr, 159 flip_binexpr::flip_binexpr,
159 flip_comma::flip_comma, 160 flip_comma::flip_comma,
160 flip_trait_bound::flip_trait_bound, 161 flip_trait_bound::flip_trait_bound,
diff --git a/crates/ra_assists/src/marks.rs b/crates/ra_assists/src/marks.rs
deleted file mode 100644
index 722f3c6a4..000000000
--- a/crates/ra_assists/src/marks.rs
+++ /dev/null
@@ -1,15 +0,0 @@
1//! See test_utils/src/marks.rs
2
3test_utils::marks![
4 option_order
5 introduce_var_in_comment_is_not_applicable
6 test_introduce_var_expr_stmt
7 test_introduce_var_last_expr
8 not_applicable_outside_of_bind_pat
9 test_not_inline_mut_variable
10 test_not_applicable_if_variable_unused
11 change_visibility_field_false_positive
12 test_add_from_impl_already_exists
13 add_turbo_fish_one_fish_is_enough
14 add_turbo_fish_non_generic
15];
diff --git a/crates/ra_assists/src/tests.rs b/crates/ra_assists/src/tests.rs
index 9ba3da786..62dd3547f 100644
--- a/crates/ra_assists/src/tests.rs
+++ b/crates/ra_assists/src/tests.rs
@@ -7,8 +7,7 @@ use ra_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
7use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase}; 7use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase};
8use ra_syntax::TextRange; 8use ra_syntax::TextRange;
9use test_utils::{ 9use test_utils::{
10 add_cursor, assert_eq_text, extract_offset, extract_range, extract_range_or_offset, 10 assert_eq_text, extract_offset, extract_range, extract_range_or_offset, RangeOrOffset,
11 RangeOrOffset,
12}; 11};
13 12
14use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, Assists}; 13use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, Assists};
@@ -103,21 +102,6 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult) {
103 102
104 let mut actual = db.file_text(change.file_id).as_ref().to_owned(); 103 let mut actual = db.file_text(change.file_id).as_ref().to_owned();
105 change.edit.apply(&mut actual); 104 change.edit.apply(&mut actual);
106
107 if !source_change.is_snippet {
108 match source_change.cursor_position {
109 None => {
110 if let RangeOrOffset::Offset(before_cursor_pos) = range_or_offset {
111 let off = change
112 .edit
113 .apply_to_offset(before_cursor_pos)
114 .expect("cursor position is affected by the edit");
115 actual = add_cursor(&actual, off)
116 }
117 }
118 Some(off) => actual = add_cursor(&actual, off.offset),
119 };
120 }
121 assert_eq_text!(after, &actual); 105 assert_eq_text!(after, &actual);
122 } 106 }
123 (Some(assist), ExpectedResult::Target(target)) => { 107 (Some(assist), ExpectedResult::Target(target)) => {
diff --git a/crates/ra_assists/src/tests/generated.rs b/crates/ra_assists/src/tests/generated.rs
index cd6129dc5..250e56a69 100644
--- a/crates/ra_assists/src/tests/generated.rs
+++ b/crates/ra_assists/src/tests/generated.rs
@@ -336,7 +336,7 @@ enum Action { Move { distance: u32 }, Stop }
336 336
337fn handle(action: Action) { 337fn handle(action: Action) {
338 match action { 338 match action {
339 Action::Move { distance } => {} 339 $0Action::Move { distance } => {}
340 Action::Stop => {} 340 Action::Stop => {}
341 } 341 }
342} 342}
@@ -345,6 +345,29 @@ fn handle(action: Action) {
345} 345}
346 346
347#[test] 347#[test]
348fn doctest_fix_visibility() {
349 check_doc_test(
350 "fix_visibility",
351 r#####"
352mod m {
353 fn frobnicate() {}
354}
355fn main() {
356 m::frobnicate<|>() {}
357}
358"#####,
359 r#####"
360mod m {
361 $0pub(crate) fn frobnicate() {}
362}
363fn main() {
364 m::frobnicate() {}
365}
366"#####,
367 )
368}
369
370#[test]
348fn doctest_flip_binexpr() { 371fn doctest_flip_binexpr() {
349 check_doc_test( 372 check_doc_test(
350 "flip_binexpr", 373 "flip_binexpr",
@@ -420,7 +443,7 @@ fn main() {
420"#####, 443"#####,
421 r#####" 444 r#####"
422fn main() { 445fn main() {
423 let var_name = (1 + 2); 446 let $0var_name = (1 + 2);
424 var_name * 4; 447 var_name * 4;
425} 448}
426"#####, 449"#####,
@@ -741,7 +764,7 @@ fn main() {
741 let x: Result<i32, i32> = Result::Ok(92); 764 let x: Result<i32, i32> = Result::Ok(92);
742 let y = match x { 765 let y = match x {
743 Ok(a) => a, 766 Ok(a) => a,
744 _ => unreachable!(), 767 $0_ => unreachable!(),
745 }; 768 };
746} 769}
747"#####, 770"#####,