aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_assists/src')
-rw-r--r--crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs121
-rw-r--r--crates/ide_assists/src/handlers/fill_match_arms.rs34
-rw-r--r--crates/ide_assists/src/handlers/generate_deref.rs27
-rw-r--r--crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs173
4 files changed, 158 insertions, 197 deletions
diff --git a/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs b/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs
index 4e75a7b14..7fd73d4c7 100644
--- a/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs
+++ b/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs
@@ -77,9 +77,11 @@ fn validate_method_call_expr(
77 expr: ast::MethodCallExpr, 77 expr: ast::MethodCallExpr,
78) -> Option<(ast::Expr, ast::Expr)> { 78) -> Option<(ast::Expr, ast::Expr)> {
79 let name_ref = expr.name_ref()?; 79 let name_ref = expr.name_ref()?;
80 if name_ref.syntax().text_range().intersect(ctx.frange.range).is_none() 80 if name_ref.syntax().text_range().intersect(ctx.frange.range).is_none() {
81 || name_ref.text() != "for_each" 81 cov_mark::hit!(test_for_each_not_applicable_invalid_cursor_pos);
82 { 82 return None;
83 }
84 if name_ref.text() != "for_each" {
83 return None; 85 return None;
84 } 86 }
85 87
@@ -98,59 +100,27 @@ fn validate_method_call_expr(
98 100
99#[cfg(test)] 101#[cfg(test)]
100mod tests { 102mod tests {
101 use crate::tests::{self, check_assist}; 103 use crate::tests::{check_assist, check_assist_not_applicable};
102 104
103 use super::*; 105 use super::*;
104 106
105 const EMPTY_ITER_FIXTURE: &'static str = r"
106//- /lib.rs deps:core crate:empty_iter
107pub struct EmptyIter;
108impl Iterator for EmptyIter {
109 type Item = usize;
110 fn next(&mut self) -> Option<Self::Item> { None }
111}
112pub struct Empty;
113impl Empty {
114 pub fn iter(&self) -> EmptyIter { EmptyIter }
115}
116";
117
118 fn check_assist_with_fixtures(before: &str, after: &str) {
119 let before = &format!(
120 "//- /main.rs crate:main deps:core,empty_iter{}{}{}",
121 before,
122 EMPTY_ITER_FIXTURE,
123 FamousDefs::FIXTURE,
124 );
125 check_assist(convert_iter_for_each_to_for, before, after);
126 }
127
128 fn check_assist_not_applicable(before: &str) {
129 let before = &format!(
130 "//- /main.rs crate:main deps:core,empty_iter{}{}{}",
131 before,
132 EMPTY_ITER_FIXTURE,
133 FamousDefs::FIXTURE,
134 );
135 tests::check_assist_not_applicable(convert_iter_for_each_to_for, before);
136 }
137
138 #[test] 107 #[test]
139 fn test_for_each_in_method_stmt() { 108 fn test_for_each_in_method_stmt() {
140 check_assist_with_fixtures( 109 check_assist(
110 convert_iter_for_each_to_for,
141 r#" 111 r#"
142use empty_iter::*; 112//- minicore: iterators
143fn main() { 113fn main() {
144 let x = Empty; 114 let it = core::iter::repeat(92);
145 x.iter().$0for_each(|(x, y)| { 115 it.$0for_each(|(x, y)| {
146 println!("x: {}, y: {}", x, y); 116 println!("x: {}, y: {}", x, y);
147 }); 117 });
148}"#, 118}
119"#,
149 r#" 120 r#"
150use empty_iter::*;
151fn main() { 121fn main() {
152 let x = Empty; 122 let it = core::iter::repeat(92);
153 for (x, y) in x.iter() { 123 for (x, y) in it {
154 println!("x: {}, y: {}", x, y); 124 println!("x: {}, y: {}", x, y);
155 } 125 }
156} 126}
@@ -160,43 +130,21 @@ fn main() {
160 130
161 #[test] 131 #[test]
162 fn test_for_each_in_method() { 132 fn test_for_each_in_method() {
163 check_assist_with_fixtures( 133 check_assist(
134 convert_iter_for_each_to_for,
164 r#" 135 r#"
165use empty_iter::*; 136//- minicore: iterators
166fn main() { 137fn main() {
167 let x = Empty; 138 let it = core::iter::repeat(92);
168 x.iter().$0for_each(|(x, y)| { 139 it.$0for_each(|(x, y)| {
169 println!("x: {}, y: {}", x, y); 140 println!("x: {}, y: {}", x, y);
170 }) 141 })
171}"#,
172 r#"
173use empty_iter::*;
174fn main() {
175 let x = Empty;
176 for (x, y) in x.iter() {
177 println!("x: {}, y: {}", x, y);
178 }
179} 142}
180"#, 143"#,
181 )
182 }
183
184 #[test]
185 fn test_for_each_in_iter_stmt() {
186 check_assist_with_fixtures(
187 r#"
188use empty_iter::*;
189fn main() {
190 let x = Empty.iter();
191 x.$0for_each(|(x, y)| {
192 println!("x: {}, y: {}", x, y);
193 });
194}"#,
195 r#" 144 r#"
196use empty_iter::*;
197fn main() { 145fn main() {
198 let x = Empty.iter(); 146 let it = core::iter::repeat(92);
199 for (x, y) in x { 147 for (x, y) in it {
200 println!("x: {}, y: {}", x, y); 148 println!("x: {}, y: {}", x, y);
201 } 149 }
202} 150}
@@ -206,18 +154,19 @@ fn main() {
206 154
207 #[test] 155 #[test]
208 fn test_for_each_without_braces_stmt() { 156 fn test_for_each_without_braces_stmt() {
209 check_assist_with_fixtures( 157 check_assist(
158 convert_iter_for_each_to_for,
210 r#" 159 r#"
211use empty_iter::*; 160//- minicore: iterators
212fn main() { 161fn main() {
213 let x = Empty; 162 let it = core::iter::repeat(92);
214 x.iter().$0for_each(|(x, y)| println!("x: {}, y: {}", x, y)); 163 it.$0for_each(|(x, y)| println!("x: {}, y: {}", x, y));
215}"#, 164}
165"#,
216 r#" 166 r#"
217use empty_iter::*;
218fn main() { 167fn main() {
219 let x = Empty; 168 let it = core::iter::repeat(92);
220 for (x, y) in x.iter() { 169 for (x, y) in it {
221 println!("x: {}, y: {}", x, y) 170 println!("x: {}, y: {}", x, y)
222 } 171 }
223} 172}
@@ -228,7 +177,9 @@ fn main() {
228 #[test] 177 #[test]
229 fn test_for_each_not_applicable() { 178 fn test_for_each_not_applicable() {
230 check_assist_not_applicable( 179 check_assist_not_applicable(
180 convert_iter_for_each_to_for,
231 r#" 181 r#"
182//- minicore: iterators
232fn main() { 183fn main() {
233 ().$0for_each(|x| println!("{}", x)); 184 ().$0for_each(|x| println!("{}", x));
234}"#, 185}"#,
@@ -237,11 +188,13 @@ fn main() {
237 188
238 #[test] 189 #[test]
239 fn test_for_each_not_applicable_invalid_cursor_pos() { 190 fn test_for_each_not_applicable_invalid_cursor_pos() {
191 cov_mark::check!(test_for_each_not_applicable_invalid_cursor_pos);
240 check_assist_not_applicable( 192 check_assist_not_applicable(
193 convert_iter_for_each_to_for,
241 r#" 194 r#"
242use empty_iter::*; 195//- minicore: iterators
243fn main() { 196fn main() {
244 Empty.iter().for_each(|(x, y)| $0println!("x: {}, y: {}", x, y)); 197 core::iter::repeat(92).for_each(|(x, y)| $0println!("x: {}, y: {}", x, y));
245}"#, 198}"#,
246 ) 199 )
247 } 200 }
diff --git a/crates/ide_assists/src/handlers/fill_match_arms.rs b/crates/ide_assists/src/handlers/fill_match_arms.rs
index 5a43bdd6f..cd0f6dba9 100644
--- a/crates/ide_assists/src/handlers/fill_match_arms.rs
+++ b/crates/ide_assists/src/handlers/fill_match_arms.rs
@@ -278,8 +278,6 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: ExtendedVariant) -> Op
278 278
279#[cfg(test)] 279#[cfg(test)]
280mod tests { 280mod tests {
281 use ide_db::helpers::FamousDefs;
282
283 use crate::tests::{ 281 use crate::tests::{
284 check_assist, check_assist_not_applicable, check_assist_target, check_assist_unresolved, 282 check_assist, check_assist_not_applicable, check_assist_target, check_assist_unresolved,
285 }; 283 };
@@ -716,7 +714,10 @@ fn main() {
716 714
717 #[test] 715 #[test]
718 fn fill_match_arms_tuple_of_enum_partial_with_wildcards() { 716 fn fill_match_arms_tuple_of_enum_partial_with_wildcards() {
719 let ra_fixture = r#" 717 check_assist(
718 fill_match_arms,
719 r#"
720//- minicore: option
720fn main() { 721fn main() {
721 let a = Some(1); 722 let a = Some(1);
722 let b = Some(()); 723 let b = Some(());
@@ -725,10 +726,7 @@ fn main() {
725 (None, Some(_)) => {} 726 (None, Some(_)) => {}
726 } 727 }
727} 728}
728"#; 729"#,
729 check_assist(
730 fill_match_arms,
731 &format!("//- /main.rs crate:main deps:core{}{}", ra_fixture, FamousDefs::FIXTURE),
732 r#" 730 r#"
733fn main() { 731fn main() {
734 let a = Some(1); 732 let a = Some(1);
@@ -746,17 +744,17 @@ fn main() {
746 #[test] 744 #[test]
747 fn fill_match_arms_partial_with_deep_pattern() { 745 fn fill_match_arms_partial_with_deep_pattern() {
748 // Fixme: cannot handle deep patterns 746 // Fixme: cannot handle deep patterns
749 let ra_fixture = r#" 747 check_assist_not_applicable(
748 fill_match_arms,
749 r#"
750//- minicore: option
750fn main() { 751fn main() {
751 match $0Some(true) { 752 match $0Some(true) {
752 Some(true) => {} 753 Some(true) => {}
753 None => {} 754 None => {}
754 } 755 }
755} 756}
756"#; 757"#,
757 check_assist_not_applicable(
758 fill_match_arms,
759 &format!("//- /main.rs crate:main deps:core{}{}", ra_fixture, FamousDefs::FIXTURE),
760 ); 758 );
761 } 759 }
762 760
@@ -1007,17 +1005,15 @@ fn foo(a: A) {
1007 #[test] 1005 #[test]
1008 fn option_order() { 1006 fn option_order() {
1009 cov_mark::check!(option_order); 1007 cov_mark::check!(option_order);
1010 let before = r#" 1008 check_assist(
1009 fill_match_arms,
1010 r#"
1011//- minicore: option
1011fn foo(opt: Option<i32>) { 1012fn foo(opt: Option<i32>) {
1012 match opt$0 { 1013 match opt$0 {
1013 } 1014 }
1014} 1015}
1015"#; 1016"#,
1016 let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE);
1017
1018 check_assist(
1019 fill_match_arms,
1020 before,
1021 r#" 1017 r#"
1022fn foo(opt: Option<i32>) { 1018fn foo(opt: Option<i32>) {
1023 match opt { 1019 match opt {
diff --git a/crates/ide_assists/src/handlers/generate_deref.rs b/crates/ide_assists/src/handlers/generate_deref.rs
index 4998ff7a4..4e10fdb85 100644
--- a/crates/ide_assists/src/handlers/generate_deref.rs
+++ b/crates/ide_assists/src/handlers/generate_deref.rs
@@ -182,23 +182,17 @@ impl std::ops::Deref for B {
182 ); 182 );
183 } 183 }
184 184
185 fn check_not_applicable(ra_fixture: &str) {
186 let fixture = format!(
187 "//- /main.rs crate:main deps:core,std\n{}\n{}",
188 ra_fixture,
189 FamousDefs::FIXTURE
190 );
191 check_assist_not_applicable(generate_deref, &fixture)
192 }
193
194 #[test] 185 #[test]
195 fn test_generate_record_deref_not_applicable_if_already_impl() { 186 fn test_generate_record_deref_not_applicable_if_already_impl() {
196 cov_mark::check!(test_add_record_deref_impl_already_exists); 187 cov_mark::check!(test_add_record_deref_impl_already_exists);
197 check_not_applicable( 188 check_assist_not_applicable(
198 r#"struct A { } 189 generate_deref,
190 r#"
191//- minicore: deref
192struct A { }
199struct B { $0a: A } 193struct B { $0a: A }
200 194
201impl std::ops::Deref for B { 195impl core::ops::Deref for B {
202 type Target = A; 196 type Target = A;
203 197
204 fn deref(&self) -> &Self::Target { 198 fn deref(&self) -> &Self::Target {
@@ -211,11 +205,14 @@ impl std::ops::Deref for B {
211 #[test] 205 #[test]
212 fn test_generate_field_deref_not_applicable_if_already_impl() { 206 fn test_generate_field_deref_not_applicable_if_already_impl() {
213 cov_mark::check!(test_add_field_deref_impl_already_exists); 207 cov_mark::check!(test_add_field_deref_impl_already_exists);
214 check_not_applicable( 208 check_assist_not_applicable(
215 r#"struct A { } 209 generate_deref,
210 r#"
211//- minicore: deref
212struct A { }
216struct B($0A) 213struct B($0A)
217 214
218impl std::ops::Deref for B { 215impl core::ops::Deref for B {
219 type Target = A; 216 type Target = A;
220 217
221 fn deref(&self) -> &Self::Target { 218 fn deref(&self) -> &Self::Target {
diff --git a/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs b/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs
index 50b05ab0b..5f2aa016f 100644
--- a/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs
+++ b/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs
@@ -85,38 +85,48 @@ fn is_ref_and_impls_iter_method(
85 let krate = scope.module()?.krate(); 85 let krate = scope.module()?.krate();
86 let traits_in_scope = scope.traits_in_scope(); 86 let traits_in_scope = scope.traits_in_scope();
87 let iter_trait = FamousDefs(sema, Some(krate)).core_iter_Iterator()?; 87 let iter_trait = FamousDefs(sema, Some(krate)).core_iter_Iterator()?;
88 let has_wanted_method = typ.iterate_method_candidates( 88
89 sema.db, 89 let has_wanted_method = typ
90 krate, 90 .iterate_method_candidates(
91 &traits_in_scope, 91 sema.db,
92 Some(&wanted_method), 92 krate,
93 |_, func| { 93 &traits_in_scope,
94 if func.ret_type(sema.db).impls_trait(sema.db, iter_trait, &[]) { 94 Some(&wanted_method),
95 return Some(()); 95 |_, func| {
96 } 96 if func.ret_type(sema.db).impls_trait(sema.db, iter_trait, &[]) {
97 None 97 return Some(());
98 }, 98 }
99 ); 99 None
100 has_wanted_method.and(Some((expr_behind_ref, wanted_method))) 100 },
101 )
102 .is_some();
103 if !has_wanted_method {
104 return None;
105 }
106
107 Some((expr_behind_ref, wanted_method))
101} 108}
102 109
103/// Whether iterable implements core::Iterator 110/// Whether iterable implements core::Iterator
104fn impls_core_iter(sema: &hir::Semantics<ide_db::RootDatabase>, iterable: &ast::Expr) -> bool { 111fn impls_core_iter(sema: &hir::Semantics<ide_db::RootDatabase>, iterable: &ast::Expr) -> bool {
105 let it_typ = if let Some(i) = sema.type_of_expr(iterable) { 112 let it_typ = match sema.type_of_expr(iterable) {
106 i 113 Some(it) => it,
107 } else { 114 None => return false,
108 return false;
109 }; 115 };
110 let module = if let Some(m) = sema.scope(iterable.syntax()).module() { 116
111 m 117 let module = match sema.scope(iterable.syntax()).module() {
112 } else { 118 Some(it) => it,
113 return false; 119 None => return false,
114 }; 120 };
121
115 let krate = module.krate(); 122 let krate = module.krate();
116 if let Some(iter_trait) = FamousDefs(sema, Some(krate)).core_iter_Iterator() { 123 match FamousDefs(sema, Some(krate)).core_iter_Iterator() {
117 return it_typ.impls_trait(sema.db, iter_trait, &[]); 124 Some(iter_trait) => {
125 cov_mark::hit!(test_already_impls_iterator);
126 it_typ.impls_trait(sema.db, iter_trait, &[])
127 }
128 None => false,
118 } 129 }
119 false
120} 130}
121 131
122#[cfg(test)] 132#[cfg(test)]
@@ -125,33 +135,6 @@ mod tests {
125 135
126 use super::*; 136 use super::*;
127 137
128 const EMPTY_ITER_FIXTURE: &'static str = r"
129//- /lib.rs deps:core crate:empty_iter
130pub struct EmptyIter;
131impl Iterator for EmptyIter {
132 type Item = usize;
133 fn next(&mut self) -> Option<Self::Item> { None }
134}
135
136pub struct Empty;
137impl Empty {
138 pub fn iter(&self) -> EmptyIter { EmptyIter }
139 pub fn iter_mut(&self) -> EmptyIter { EmptyIter }
140}
141
142pub struct NoIterMethod;
143";
144
145 fn check_assist_with_fixtures(before: &str, after: &str) {
146 let before = &format!(
147 "//- /main.rs crate:main deps:core,empty_iter{}{}{}",
148 before,
149 FamousDefs::FIXTURE,
150 EMPTY_ITER_FIXTURE
151 );
152 check_assist(replace_for_loop_with_for_each, before, after);
153 }
154
155 #[test] 138 #[test]
156 fn test_not_for() { 139 fn test_not_for() {
157 check_assist_not_applicable( 140 check_assist_not_applicable(
@@ -201,33 +184,50 @@ fn main() {
201 184
202 #[test] 185 #[test]
203 fn test_for_borrowed() { 186 fn test_for_borrowed() {
204 check_assist_with_fixtures( 187 check_assist(
205 r" 188 replace_for_loop_with_for_each,
206use empty_iter::*; 189 r#"
190//- minicore: iterators
191use core::iter::{Repeat, repeat};
192
193struct S;
194impl S {
195 fn iter(&self) -> Repeat<i32> { repeat(92) }
196 fn iter_mut(&mut self) -> Repeat<i32> { repeat(92) }
197}
198
207fn main() { 199fn main() {
208 let x = Empty; 200 let x = S;
209 for $0v in &x { 201 for $0v in &x {
210 let a = v * 2; 202 let a = v * 2;
211 } 203 }
212} 204}
213", 205"#,
214 r" 206 r#"
215use empty_iter::*; 207use core::iter::{Repeat, repeat};
208
209struct S;
210impl S {
211 fn iter(&self) -> Repeat<i32> { repeat(92) }
212 fn iter_mut(&mut self) -> Repeat<i32> { repeat(92) }
213}
214
216fn main() { 215fn main() {
217 let x = Empty; 216 let x = S;
218 x.iter().for_each(|v| { 217 x.iter().for_each(|v| {
219 let a = v * 2; 218 let a = v * 2;
220 }); 219 });
221} 220}
222", 221"#,
223 ) 222 )
224 } 223 }
225 224
226 #[test] 225 #[test]
227 fn test_for_borrowed_no_iter_method() { 226 fn test_for_borrowed_no_iter_method() {
228 check_assist_with_fixtures( 227 check_assist(
228 replace_for_loop_with_for_each,
229 r" 229 r"
230use empty_iter::*; 230struct NoIterMethod;
231fn main() { 231fn main() {
232 let x = NoIterMethod; 232 let x = NoIterMethod;
233 for $0v in &x { 233 for $0v in &x {
@@ -236,7 +236,7 @@ fn main() {
236} 236}
237", 237",
238 r" 238 r"
239use empty_iter::*; 239struct NoIterMethod;
240fn main() { 240fn main() {
241 let x = NoIterMethod; 241 let x = NoIterMethod;
242 (&x).into_iter().for_each(|v| { 242 (&x).into_iter().for_each(|v| {
@@ -249,25 +249,41 @@ fn main() {
249 249
250 #[test] 250 #[test]
251 fn test_for_borrowed_mut() { 251 fn test_for_borrowed_mut() {
252 check_assist_with_fixtures( 252 check_assist(
253 r" 253 replace_for_loop_with_for_each,
254use empty_iter::*; 254 r#"
255//- minicore: iterators
256use core::iter::{Repeat, repeat};
257
258struct S;
259impl S {
260 fn iter(&self) -> Repeat<i32> { repeat(92) }
261 fn iter_mut(&mut self) -> Repeat<i32> { repeat(92) }
262}
263
255fn main() { 264fn main() {
256 let x = Empty; 265 let x = S;
257 for $0v in &mut x { 266 for $0v in &mut x {
258 let a = v * 2; 267 let a = v * 2;
259 } 268 }
260} 269}
261", 270"#,
262 r" 271 r#"
263use empty_iter::*; 272use core::iter::{Repeat, repeat};
273
274struct S;
275impl S {
276 fn iter(&self) -> Repeat<i32> { repeat(92) }
277 fn iter_mut(&mut self) -> Repeat<i32> { repeat(92) }
278}
279
264fn main() { 280fn main() {
265 let x = Empty; 281 let x = S;
266 x.iter_mut().for_each(|v| { 282 x.iter_mut().for_each(|v| {
267 let a = v * 2; 283 let a = v * 2;
268 }); 284 });
269} 285}
270", 286"#,
271 ) 287 )
272 } 288 }
273 289
@@ -296,21 +312,20 @@ fn main() {
296 312
297 #[test] 313 #[test]
298 fn test_already_impls_iterator() { 314 fn test_already_impls_iterator() {
299 check_assist_with_fixtures( 315 cov_mark::check!(test_already_impls_iterator);
316 check_assist(
317 replace_for_loop_with_for_each,
300 r#" 318 r#"
301use empty_iter::*; 319//- minicore: iterators
302fn main() { 320fn main() {
303 let x = Empty; 321 for$0 a in core::iter::repeat(92).take(1) {
304 for$0 a in x.iter().take(1) {
305 println!("{}", a); 322 println!("{}", a);
306 } 323 }
307} 324}
308"#, 325"#,
309 r#" 326 r#"
310use empty_iter::*;
311fn main() { 327fn main() {
312 let x = Empty; 328 core::iter::repeat(92).take(1).for_each(|a| {
313 x.iter().take(1).for_each(|a| {
314 println!("{}", a); 329 println!("{}", a);
315 }); 330 });
316} 331}