aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_ty/src/tests/regression.rs47
-rw-r--r--crates/hir_ty/src/tests/traits.rs16
-rw-r--r--crates/ide/src/inlay_hints.rs31
-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/move_module_to_file.rs65
-rw-r--r--crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs173
-rw-r--r--crates/ide_db/src/helpers/famous_defs_fixture.rs94
-rw-r--r--crates/syntax/src/ast/node_ext.rs8
-rw-r--r--crates/test_utils/src/fixture.rs2
-rw-r--r--crates/test_utils/src/minicore.rs101
12 files changed, 344 insertions, 375 deletions
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index 1edec1615..e0ad41fb9 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -418,48 +418,17 @@ fn issue_2705() {
418fn issue_2683_chars_impl() { 418fn issue_2683_chars_impl() {
419 check_types( 419 check_types(
420 r#" 420 r#"
421//- /main.rs crate:main deps:std 421//- minicore: iterator
422pub struct Chars<'a> {}
423impl<'a> Iterator for Chars<'a> {
424 type Item = char;
425 fn next(&mut self) -> Option<char> {}
426}
427
422fn test() { 428fn test() {
423 let chars: std::str::Chars<'_>; 429 let chars: Chars<'_>;
424 (chars.next(), chars.nth(1)); 430 (chars.next(), chars.nth(1));
425} //^ (Option<char>, Option<char>) 431} //^ (Option<char>, Option<char>)
426
427//- /std.rs crate:std
428#[prelude_import]
429use self::prelude::rust_2018::*;
430pub mod prelude {
431 pub mod rust_2018 {
432 pub use crate::iter::Iterator;
433 pub use crate::option::Option;
434 }
435}
436
437pub mod iter {
438 pub use self::traits::Iterator;
439 pub mod traits {
440 pub use self::iterator::Iterator;
441
442 pub mod iterator {
443 pub trait Iterator {
444 type Item;
445 fn next(&mut self) -> Option<Self::Item>;
446 fn nth(&mut self, n: usize) -> Option<Self::Item> {}
447 }
448 }
449 }
450}
451
452pub mod option {
453 pub enum Option<T> {}
454}
455
456pub mod str {
457 pub struct Chars<'a> {}
458 impl<'a> Iterator for Chars<'a> {
459 type Item = char;
460 fn next(&mut self) -> Option<char> {}
461 }
462}
463"#, 432"#,
464 ); 433 );
465} 434}
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 065cca74f..22e0bfc49 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -1492,7 +1492,7 @@ fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
1492fn impl_trait_assoc_binding_projection_bug() { 1492fn impl_trait_assoc_binding_projection_bug() {
1493 check_types( 1493 check_types(
1494 r#" 1494 r#"
1495//- /main.rs crate:main deps:std 1495//- minicore: iterator
1496pub trait Language { 1496pub trait Language {
1497 type Kind; 1497 type Kind;
1498} 1498}
@@ -1512,20 +1512,6 @@ fn api_walkthrough() {
1512 node.clone(); 1512 node.clone();
1513 } //^ {unknown} 1513 } //^ {unknown}
1514} 1514}
1515
1516//- /std.rs crate:std
1517#[prelude_import] use iter::*;
1518mod iter {
1519 trait IntoIterator {
1520 type Item;
1521 }
1522 trait Iterator {
1523 type Item;
1524 }
1525 impl<T: Iterator> IntoIterator for T {
1526 type Item = <T as Iterator>::Item;
1527 }
1528}
1529"#, 1515"#,
1530 ); 1516 );
1531} 1517}
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 9cd33d0e4..335d57a0d 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -434,7 +434,6 @@ fn get_callable(
434#[cfg(test)] 434#[cfg(test)]
435mod tests { 435mod tests {
436 use expect_test::{expect, Expect}; 436 use expect_test::{expect, Expect};
437 use ide_db::helpers::FamousDefs;
438 use test_utils::extract_annotations; 437 use test_utils::extract_annotations;
439 438
440 use crate::{fixture, inlay_hints::InlayHintsConfig}; 439 use crate::{fixture, inlay_hints::InlayHintsConfig};
@@ -487,8 +486,6 @@ mod tests {
487 } 486 }
488 487
489 fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) { 488 fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) {
490 let ra_fixture =
491 format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
492 let (analysis, file_id) = fixture::file(&ra_fixture); 489 let (analysis, file_id) = fixture::file(&ra_fixture);
493 let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); 490 let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
494 let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); 491 let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap();
@@ -498,8 +495,6 @@ mod tests {
498 } 495 }
499 496
500 fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) { 497 fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) {
501 let ra_fixture =
502 format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
503 let (analysis, file_id) = fixture::file(&ra_fixture); 498 let (analysis, file_id) = fixture::file(&ra_fixture);
504 let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); 499 let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap();
505 expect.assert_debug_eq(&inlay_hints) 500 expect.assert_debug_eq(&inlay_hints)
@@ -823,6 +818,7 @@ fn main() {
823 fn shorten_iterators_in_associated_params() { 818 fn shorten_iterators_in_associated_params() {
824 check_types( 819 check_types(
825 r#" 820 r#"
821//- minicore: iterators
826use core::iter; 822use core::iter;
827 823
828pub struct SomeIter<T> {} 824pub struct SomeIter<T> {}
@@ -875,7 +871,7 @@ fn main() {
875 fn fn_hints() { 871 fn fn_hints() {
876 check_types( 872 check_types(
877 r#" 873 r#"
878trait Sized {} 874//- minicore: fn, sized
879 875
880fn foo() -> impl Fn() { loop {} } 876fn foo() -> impl Fn() { loop {} }
881fn foo1() -> impl Fn(f64) { loop {} } 877fn foo1() -> impl Fn(f64) { loop {} }
@@ -1073,6 +1069,7 @@ fn main() {
1073 fn complete_for_hint() { 1069 fn complete_for_hint() {
1074 check_types( 1070 check_types(
1075 r#" 1071 r#"
1072//- minicore: iterator
1076pub struct Vec<T> {} 1073pub struct Vec<T> {}
1077 1074
1078impl<T> Vec<T> { 1075impl<T> Vec<T> {
@@ -1129,6 +1126,7 @@ fn main() {
1129 fn shorten_iterator_hints() { 1126 fn shorten_iterator_hints() {
1130 check_types( 1127 check_types(
1131 r#" 1128 r#"
1129//- minicore: iterators
1132use core::iter; 1130use core::iter;
1133 1131
1134struct MyIter; 1132struct MyIter;
@@ -1230,12 +1228,12 @@ fn main() {
1230 expect![[r#" 1228 expect![[r#"
1231 [ 1229 [
1232 InlayHint { 1230 InlayHint {
1233 range: 148..173, 1231 range: 147..172,
1234 kind: ChainingHint, 1232 kind: ChainingHint,
1235 label: "B", 1233 label: "B",
1236 }, 1234 },
1237 InlayHint { 1235 InlayHint {
1238 range: 148..155, 1236 range: 147..154,
1239 kind: ChainingHint, 1237 kind: ChainingHint,
1240 label: "A", 1238 label: "A",
1241 }, 1239 },
@@ -1290,12 +1288,12 @@ fn main() {
1290 expect![[r#" 1288 expect![[r#"
1291 [ 1289 [
1292 InlayHint { 1290 InlayHint {
1293 range: 144..191, 1291 range: 143..190,
1294 kind: ChainingHint, 1292 kind: ChainingHint,
1295 label: "C", 1293 label: "C",
1296 }, 1294 },
1297 InlayHint { 1295 InlayHint {
1298 range: 144..180, 1296 range: 143..179,
1299 kind: ChainingHint, 1297 kind: ChainingHint,
1300 label: "B", 1298 label: "B",
1301 }, 1299 },
@@ -1335,12 +1333,12 @@ fn main() {
1335 expect![[r#" 1333 expect![[r#"
1336 [ 1334 [
1337 InlayHint { 1335 InlayHint {
1338 range: 247..284, 1336 range: 246..283,
1339 kind: ChainingHint, 1337 kind: ChainingHint,
1340 label: "B<X<i32, bool>>", 1338 label: "B<X<i32, bool>>",
1341 }, 1339 },
1342 InlayHint { 1340 InlayHint {
1343 range: 247..266, 1341 range: 246..265,
1344 kind: ChainingHint, 1342 kind: ChainingHint,
1345 label: "A<X<i32, bool>>", 1343 label: "A<X<i32, bool>>",
1346 }, 1344 },
@@ -1359,6 +1357,7 @@ fn main() {
1359 max_length: None, 1357 max_length: None,
1360 }, 1358 },
1361 r#" 1359 r#"
1360//- minicore: iterators
1362use core::iter; 1361use core::iter;
1363 1362
1364struct MyIter; 1363struct MyIter;
@@ -1381,22 +1380,22 @@ fn main() {
1381 expect![[r#" 1380 expect![[r#"
1382 [ 1381 [
1383 InlayHint { 1382 InlayHint {
1384 range: 175..242, 1383 range: 174..241,
1385 kind: ChainingHint, 1384 kind: ChainingHint,
1386 label: "impl Iterator<Item = ()>", 1385 label: "impl Iterator<Item = ()>",
1387 }, 1386 },
1388 InlayHint { 1387 InlayHint {
1389 range: 175..225, 1388 range: 174..224,
1390 kind: ChainingHint, 1389 kind: ChainingHint,
1391 label: "impl Iterator<Item = ()>", 1390 label: "impl Iterator<Item = ()>",
1392 }, 1391 },
1393 InlayHint { 1392 InlayHint {
1394 range: 175..207, 1393 range: 174..206,
1395 kind: ChainingHint, 1394 kind: ChainingHint,
1396 label: "impl Iterator<Item = ()>", 1395 label: "impl Iterator<Item = ()>",
1397 }, 1396 },
1398 InlayHint { 1397 InlayHint {
1399 range: 175..190, 1398 range: 174..189,
1400 kind: ChainingHint, 1399 kind: ChainingHint,
1401 label: "&mut MyIter", 1400 label: "&mut MyIter",
1402 }, 1401 },
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/move_module_to_file.rs b/crates/ide_assists/src/handlers/move_module_to_file.rs
index 93f702c55..cfc54be8d 100644
--- a/crates/ide_assists/src/handlers/move_module_to_file.rs
+++ b/crates/ide_assists/src/handlers/move_module_to_file.rs
@@ -1,5 +1,8 @@
1use std::iter;
2
1use ast::edit::IndentLevel; 3use ast::edit::IndentLevel;
2use ide_db::base_db::AnchoredPathBuf; 4use ide_db::base_db::AnchoredPathBuf;
5use itertools::Itertools;
3use stdx::format_to; 6use stdx::format_to;
4use syntax::{ 7use syntax::{
5 ast::{self, edit::AstNodeEdit, NameOwner}, 8 ast::{self, edit::AstNodeEdit, NameOwner},
@@ -34,7 +37,10 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Opt
34 37
35 let module_name = module_ast.name()?; 38 let module_name = module_ast.name()?;
36 39
37 let module_def = ctx.sema.to_def(&module_ast)?; 40 // get to the outermost module syntax so we can grab the module of file we are in
41 let outermost_mod_decl =
42 iter::successors(Some(module_ast.clone()), |module| module.parent()).last()?;
43 let module_def = ctx.sema.to_def(&outermost_mod_decl)?;
38 let parent_module = module_def.parent(ctx.db())?; 44 let parent_module = module_def.parent(ctx.db())?;
39 45
40 acc.add( 46 acc.add(
@@ -43,11 +49,19 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Opt
43 target, 49 target,
44 |builder| { 50 |builder| {
45 let path = { 51 let path = {
46 let dir = match parent_module.name(ctx.db()) { 52 let mut buf = String::from("./");
47 Some(name) if !parent_module.is_mod_rs(ctx.db()) => format!("{}/", name), 53 match parent_module.name(ctx.db()) {
48 _ => String::new(), 54 Some(name) if !parent_module.is_mod_rs(ctx.db()) => {
49 }; 55 format_to!(buf, "{}/", name)
50 format!("./{}{}.rs", dir, module_name) 56 }
57 _ => (),
58 }
59 let segments = iter::successors(Some(module_ast.clone()), |module| module.parent())
60 .filter_map(|it| it.name())
61 .collect::<Vec<_>>();
62 format_to!(buf, "{}", segments.into_iter().rev().format("/"));
63 format_to!(buf, ".rs");
64 buf
51 }; 65 };
52 let contents = { 66 let contents = {
53 let items = module_items.dedent(IndentLevel(1)).to_string(); 67 let items = module_items.dedent(IndentLevel(1)).to_string();
@@ -59,14 +73,13 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Opt
59 items 73 items
60 }; 74 };
61 75
62 let mut buf = String::new(); 76 let buf = format!("mod {};", module_name);
63 format_to!(buf, "mod {};", module_name);
64 77
65 let replacement_start = if let Some(mod_token) = module_ast.mod_token() { 78 let replacement_start = match module_ast.mod_token() {
66 mod_token.text_range().start() 79 Some(mod_token) => mod_token.text_range(),
67 } else { 80 None => module_ast.syntax().text_range(),
68 module_ast.syntax().text_range().start() 81 }
69 }; 82 .start();
70 83
71 builder.replace( 84 builder.replace(
72 TextRange::new(replacement_start, module_ast.syntax().text_range().end()), 85 TextRange::new(replacement_start, module_ast.syntax().text_range().end()),
@@ -212,4 +225,30 @@ mod tests;
212"#, 225"#,
213 ); 226 );
214 } 227 }
228
229 #[test]
230 fn extract_nested() {
231 check_assist(
232 move_module_to_file,
233 r#"
234//- /lib.rs
235mod foo;
236//- /foo.rs
237mod bar {
238 mod baz {
239 mod qux$0 {}
240 }
241}
242"#,
243 r#"
244//- /foo.rs
245mod bar {
246 mod baz {
247 mod qux;
248 }
249}
250//- /foo/bar/baz/qux.rs
251"#,
252 );
253 }
215} 254}
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}
diff --git a/crates/ide_db/src/helpers/famous_defs_fixture.rs b/crates/ide_db/src/helpers/famous_defs_fixture.rs
index 312851966..551203936 100644
--- a/crates/ide_db/src/helpers/famous_defs_fixture.rs
+++ b/crates/ide_db/src/helpers/famous_defs_fixture.rs
@@ -26,100 +26,6 @@ pub mod default {
26 } 26 }
27} 27}
28 28
29pub mod iter {
30 pub use self::traits::{collect::IntoIterator, iterator::Iterator};
31 mod traits {
32 pub(crate) mod iterator {
33 use crate::option::Option;
34 pub trait Iterator {
35 type Item;
36 fn next(&mut self) -> Option<Self::Item>;
37 fn by_ref(&mut self) -> &mut Self {
38 self
39 }
40 fn take(self, n: usize) -> crate::iter::Take<Self> {
41 crate::iter::Take { inner: self }
42 }
43 }
44
45 impl<I: Iterator> Iterator for &mut I {
46 type Item = I::Item;
47 fn next(&mut self) -> Option<I::Item> {
48 (**self).next()
49 }
50 }
51 }
52 pub(crate) mod collect {
53 pub trait IntoIterator {
54 type Item;
55 }
56 }
57 }
58
59 pub use self::sources::*;
60 pub(crate) mod sources {
61 use super::Iterator;
62 use crate::option::Option::{self, *};
63 pub struct Repeat<A> {
64 element: A,
65 }
66
67 pub fn repeat<T>(elt: T) -> Repeat<T> {
68 Repeat { element: elt }
69 }
70
71 impl<A> Iterator for Repeat<A> {
72 type Item = A;
73
74 fn next(&mut self) -> Option<A> {
75 None
76 }
77 }
78 }
79
80 pub use self::adapters::*;
81 pub(crate) mod adapters {
82 use super::Iterator;
83 use crate::option::Option::{self, *};
84 pub struct Take<I> {
85 pub(crate) inner: I,
86 }
87 impl<I> Iterator for Take<I>
88 where
89 I: Iterator,
90 {
91 type Item = <I as Iterator>::Item;
92 fn next(&mut self) -> Option<<I as Iterator>::Item> {
93 None
94 }
95 }
96 }
97}
98
99pub mod ops {
100 #[lang = "fn"]
101 pub trait Fn<Args>: FnMut<Args> {
102 extern "rust-call" fn call(&self, args: Args) -> Self::Output;
103 }
104
105 #[lang = "fn_mut"]
106 pub trait FnMut<Args>: FnOnce<Args> {
107 extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
108 }
109 #[lang = "fn_once"]
110 pub trait FnOnce<Args> {
111 #[lang = "fn_once_output"]
112 type Output;
113 extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
114 }
115
116 #[lang = "deref"]
117 pub trait Deref {
118 type Target: ?Sized;
119 fn deref(&self) -> &Self::Target;
120 }
121}
122
123pub mod option { 29pub mod option {
124 pub enum Option<T> { 30 pub enum Option<T> {
125 None, 31 None,
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 2bd9ad867..b057e6624 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -675,6 +675,14 @@ impl ast::LifetimeParam {
675 } 675 }
676} 676}
677 677
678impl ast::Module {
679 /// Returns the parent ast::Module, this is different than the semantic parent in that this only
680 /// considers parent declarations in the AST
681 pub fn parent(&self) -> Option<ast::Module> {
682 self.syntax().ancestors().nth(2).and_then(ast::Module::cast)
683 }
684}
685
678impl ast::RangePat { 686impl ast::RangePat {
679 pub fn start(&self) -> Option<ast::Pat> { 687 pub fn start(&self) -> Option<ast::Pat> {
680 self.syntax() 688 self.syntax()
diff --git a/crates/test_utils/src/fixture.rs b/crates/test_utils/src/fixture.rs
index 005a5c092..8d8f3b560 100644
--- a/crates/test_utils/src/fixture.rs
+++ b/crates/test_utils/src/fixture.rs
@@ -154,7 +154,7 @@ impl Fixture {
154 let components = meta.split_ascii_whitespace().collect::<Vec<_>>(); 154 let components = meta.split_ascii_whitespace().collect::<Vec<_>>();
155 155
156 let path = components[0].to_string(); 156 let path = components[0].to_string();
157 assert!(path.starts_with('/')); 157 assert!(path.starts_with('/'), "fixture path does not start with `/`: {:?}", path);
158 158
159 let mut krate = None; 159 let mut krate = None;
160 let mut deps = Vec::new(); 160 let mut deps = Vec::new();
diff --git a/crates/test_utils/src/minicore.rs b/crates/test_utils/src/minicore.rs
index e04ca58d2..e6d2301c7 100644
--- a/crates/test_utils/src/minicore.rs
+++ b/crates/test_utils/src/minicore.rs
@@ -20,6 +20,8 @@
20//! future: pin 20//! future: pin
21//! option: 21//! option:
22//! result: 22//! result:
23//! iterator: option
24//! iterators: iterator
23 25
24pub mod marker { 26pub mod marker {
25 // region:sized 27 // region:sized
@@ -206,9 +208,108 @@ pub mod task {
206} 208}
207// endregion:future 209// endregion:future
208 210
211// region:iterator
212pub mod iter {
213 // region:iterators
214 mod adapters {
215 pub struct Take<I> {
216 iter: I,
217 n: usize,
218 }
219
220 impl<I> Iterator for Take<I>
221 where
222 I: Iterator,
223 {
224 type Item = <I as Iterator>::Item;
225
226 fn next(&mut self) -> Option<<I as Iterator>::Item> {
227 loop {}
228 }
229 }
230 }
231 pub use self::adapters::Take;
232
233 mod sources {
234 mod repeat {
235 pub fn repeat<T>(elt: T) -> Repeat<T> {
236 loop {}
237 }
238
239 pub struct Repeat<A> {
240 element: A,
241 }
242
243 impl<A> Iterator for Repeat<A> {
244 type Item = A;
245
246 fn next(&mut self) -> Option<A> {
247 loop {}
248 }
249 }
250 }
251 pub use self::repeat::{repeat, Repeat};
252 }
253 pub use self::sources::{repeat, Repeat};
254 // endregion:iterators
255
256 mod traits {
257 mod iterator {
258 use super::super::Take;
259
260 pub trait Iterator {
261 type Item;
262 #[lang = "next"]
263 fn next(&mut self) -> Option<Self::Item>;
264 fn nth(&mut self, n: usize) -> Option<Self::Item> {
265 loop {}
266 }
267 fn by_ref(&mut self) -> &mut Self
268 where
269 Self: Sized,
270 {
271 self
272 }
273 // region:iterators
274 fn take(self, n: usize) -> crate::iter::Take<Self> {
275 loop {}
276 }
277 // endregion:iterators
278 }
279 impl<I: Iterator + ?Sized> Iterator for &mut I {
280 type Item = I::Item;
281 fn next(&mut self) -> Option<I::Item> {
282 (**self).next()
283 }
284 }
285 }
286 pub use self::iterator::Iterator;
287
288 mod collect {
289 pub trait IntoIterator {
290 type Item;
291 type IntoIter: Iterator<Item = Self::Item>;
292 #[lang = "into_iter"]
293 fn into_iter(self) -> Self::IntoIter;
294 }
295 impl<I: Iterator> IntoIterator for I {
296 type Item = I::Item;
297 type IntoIter = I;
298 fn into_iter(self) -> I {
299 self
300 }
301 }
302 }
303 pub use self::collect::IntoIterator;
304 }
305 pub use self::traits::{IntoIterator, Iterator};
306}
307// endregion:iterator
308
209pub mod prelude { 309pub mod prelude {
210 pub mod v1 { 310 pub mod v1 {
211 pub use crate::{ 311 pub use crate::{
312 iter::{IntoIterator, Iterator}, // :iterator
212 marker::Sized, // :sized 313 marker::Sized, // :sized
213 ops::{Fn, FnMut, FnOnce}, // :fn 314 ops::{Fn, FnMut, FnOnce}, // :fn
214 option::Option::{self, None, Some}, // :option 315 option::Option::{self, None, Some}, // :option