aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists/src/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_assists/src/handlers')
-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.rs185
3 files changed, 141 insertions, 105 deletions
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..8e571723d 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,20 +184,44 @@ 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(
188 replace_for_loop_with_for_each,
205 r" 189 r"
206use empty_iter::*; 190//- minicore: iterator
191struct Iter;
192impl Iterator for Iter {
193 type Item = usize;
194 fn next(&mut self) -> Option<Self::Item> { None }
195}
196
197struct S;
198impl S {
199 fn iter(&self) -> Iter { Iter }
200 fn iter_mut(&mut self) -> Iter { Iter }
201}
202
207fn main() { 203fn main() {
208 let x = Empty; 204 let x = S;
209 for $0v in &x { 205 for $0v in &x {
210 let a = v * 2; 206 let a = v * 2;
211 } 207 }
212} 208}
213", 209",
214 r" 210 r"
215use empty_iter::*; 211struct Iter;
212impl Iterator for Iter {
213 type Item = usize;
214 fn next(&mut self) -> Option<Self::Item> { None }
215}
216
217struct S;
218impl S {
219 fn iter(&self) -> Iter { Iter }
220 fn iter_mut(&mut self) -> Iter { Iter }
221}
222
216fn main() { 223fn main() {
217 let x = Empty; 224 let x = S;
218 x.iter().for_each(|v| { 225 x.iter().for_each(|v| {
219 let a = v * 2; 226 let a = v * 2;
220 }); 227 });
@@ -225,9 +232,10 @@ fn main() {
225 232
226 #[test] 233 #[test]
227 fn test_for_borrowed_no_iter_method() { 234 fn test_for_borrowed_no_iter_method() {
228 check_assist_with_fixtures( 235 check_assist(
236 replace_for_loop_with_for_each,
229 r" 237 r"
230use empty_iter::*; 238struct NoIterMethod;
231fn main() { 239fn main() {
232 let x = NoIterMethod; 240 let x = NoIterMethod;
233 for $0v in &x { 241 for $0v in &x {
@@ -236,7 +244,7 @@ fn main() {
236} 244}
237", 245",
238 r" 246 r"
239use empty_iter::*; 247struct NoIterMethod;
240fn main() { 248fn main() {
241 let x = NoIterMethod; 249 let x = NoIterMethod;
242 (&x).into_iter().for_each(|v| { 250 (&x).into_iter().for_each(|v| {
@@ -249,20 +257,44 @@ fn main() {
249 257
250 #[test] 258 #[test]
251 fn test_for_borrowed_mut() { 259 fn test_for_borrowed_mut() {
252 check_assist_with_fixtures( 260 check_assist(
261 replace_for_loop_with_for_each,
253 r" 262 r"
254use empty_iter::*; 263//- minicore: iterator
264struct Iter;
265impl Iterator for Iter {
266 type Item = usize;
267 fn next(&mut self) -> Option<Self::Item> { None }
268}
269
270struct S;
271impl S {
272 fn iter(&self) -> Iter { Iter }
273 fn iter_mut(&mut self) -> Iter { Iter }
274}
275
255fn main() { 276fn main() {
256 let x = Empty; 277 let x = S;
257 for $0v in &mut x { 278 for $0v in &mut x {
258 let a = v * 2; 279 let a = v * 2;
259 } 280 }
260} 281}
261", 282",
262 r" 283 r"
263use empty_iter::*; 284struct Iter;
285impl Iterator for Iter {
286 type Item = usize;
287 fn next(&mut self) -> Option<Self::Item> { None }
288}
289
290struct S;
291impl S {
292 fn iter(&self) -> Iter { Iter }
293 fn iter_mut(&mut self) -> Iter { Iter }
294}
295
264fn main() { 296fn main() {
265 let x = Empty; 297 let x = S;
266 x.iter_mut().for_each(|v| { 298 x.iter_mut().for_each(|v| {
267 let a = v * 2; 299 let a = v * 2;
268 }); 300 });
@@ -296,21 +328,32 @@ fn main() {
296 328
297 #[test] 329 #[test]
298 fn test_already_impls_iterator() { 330 fn test_already_impls_iterator() {
299 check_assist_with_fixtures( 331 cov_mark::check!(test_already_impls_iterator);
332 check_assist(
333 replace_for_loop_with_for_each,
300 r#" 334 r#"
301use empty_iter::*; 335//- minicore: iterator
336struct Iter;
337impl Iterator for Iter {
338 type Item = usize;
339 fn next(&mut self) -> Option<Self::Item> { None }
340}
341
302fn main() { 342fn main() {
303 let x = Empty; 343 for$0 a in Iter.take(1) {
304 for$0 a in x.iter().take(1) {
305 println!("{}", a); 344 println!("{}", a);
306 } 345 }
307} 346}
308"#, 347"#,
309 r#" 348 r#"
310use empty_iter::*; 349struct Iter;
350impl Iterator for Iter {
351 type Item = usize;
352 fn next(&mut self) -> Option<Self::Item> { None }
353}
354
311fn main() { 355fn main() {
312 let x = Empty; 356 Iter.take(1).for_each(|a| {
313 x.iter().take(1).for_each(|a| {
314 println!("{}", a); 357 println!("{}", a);
315 }); 358 });
316} 359}