Fix convert_iter_for_each_to_for doctest

This commit is contained in:
Lukas Wirth 2021-03-12 15:41:08 +01:00
parent e505752442
commit 6d35c67b6e
2 changed files with 56 additions and 15 deletions

View file

@ -11,37 +11,45 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
// Converts an Iterator::for_each function into a for loop. // Converts an Iterator::for_each function into a for loop.
// //
// ``` // ```
// # //- /lib.rs crate:core
// # pub mod iter { pub mod traits { pub mod iterator { pub trait Iterator {} } } }
// # pub struct SomeIter;
// # impl self::iter::traits::iterator::Iterator for SomeIter {}
// # //- /lib.rs crate:main deps:core
// # use core::SomeIter;
// fn main() { // fn main() {
// let vec = vec![(1, 2), (2, 3), (3, 4)]; // let iter = SomeIter;
// x.iter().for_each(|(x, y)| { // iter.for_each$0(|(x, y)| {
// println!("x: {}, y: {}", x, y); // println!("x: {}, y: {}", x, y);
// }); // });
// } // }
// ``` // ```
// -> // ->
// ``` // ```
// # use core::SomeIter;
// fn main() { // fn main() {
// let vec = vec![(1, 2), (2, 3), (3, 4)]; // let iter = SomeIter;
// for (x, y) in x.iter() { // for (x, y) in iter {
// println!("x: {}, y: {}", x, y); // println!("x: {}, y: {}", x, y);
// } // }
// } // }
// ``` // ```
pub(crate) fn convert_iter_for_each_to_for(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { pub(crate) fn convert_iter_for_each_to_for(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
let method = ctx.find_node_at_offset::<ast::MethodCallExpr>()?; let method = ctx.find_node_at_offset::<ast::MethodCallExpr>()?;
let stmt = method.syntax().parent().and_then(ast::ExprStmt::cast);
let closure = match method.arg_list()?.args().next()? { let closure = match method.arg_list()?.args().next()? {
ast::Expr::ClosureExpr(expr) => expr, ast::Expr::ClosureExpr(expr) => expr,
_ => return None, _ => return None,
}; };
let (method, receiver) = validate_method_call_expr(&ctx.sema, method)?; let (method, receiver) = validate_method_call_expr(ctx, method)?;
let param_list = closure.param_list()?; let param_list = closure.param_list()?;
let param = param_list.params().next()?.pat()?; let param = param_list.params().next()?.pat()?;
let body = closure.body()?; let body = closure.body()?;
let stmt = method.syntax().parent().and_then(ast::ExprStmt::cast);
let syntax = stmt.as_ref().map_or(method.syntax(), |stmt| stmt.syntax()); let syntax = stmt.as_ref().map_or(method.syntax(), |stmt| stmt.syntax());
acc.add( acc.add(
@ -65,13 +73,18 @@ pub(crate) fn convert_iter_for_each_to_for(acc: &mut Assists, ctx: &AssistContex
} }
fn validate_method_call_expr( fn validate_method_call_expr(
sema: &hir::Semantics<ide_db::RootDatabase>, ctx: &AssistContext,
expr: ast::MethodCallExpr, expr: ast::MethodCallExpr,
) -> Option<(ast::Expr, ast::Expr)> { ) -> Option<(ast::Expr, ast::Expr)> {
if expr.name_ref()?.text() != "for_each" { let name_ref = expr.name_ref()?;
if name_ref.syntax().text_range().intersect(ctx.frange.range).is_none()
|| name_ref.text() != "for_each"
{
return None; return None;
} }
let sema = &ctx.sema;
let receiver = expr.receiver()?; let receiver = expr.receiver()?;
let expr = ast::Expr::MethodCallExpr(expr); let expr = ast::Expr::MethodCallExpr(expr);
@ -85,7 +98,7 @@ fn validate_method_call_expr(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::tests::{check_assist, check_assist_not_applicable}; use crate::tests::{self, check_assist};
use super::*; use super::*;
@ -112,6 +125,16 @@ impl Empty {
check_assist(convert_iter_for_each_to_for, before, after); check_assist(convert_iter_for_each_to_for, before, after);
} }
fn check_assist_not_applicable(before: &str) {
let before = &format!(
"//- /main.rs crate:main deps:core,empty_iter{}{}{}",
before,
EMPTY_ITER_FIXTURE,
FamousDefs::FIXTURE,
);
tests::check_assist_not_applicable(convert_iter_for_each_to_for, before);
}
#[test] #[test]
fn test_for_each_in_method_stmt() { fn test_for_each_in_method_stmt() {
check_assist_with_fixtures( check_assist_with_fixtures(
@ -201,13 +224,24 @@ fn main() {
"#, "#,
) )
} }
#[test] #[test]
fn test_for_each_not_applicable() { fn test_for_each_not_applicable() {
check_assist_not_applicable( check_assist_not_applicable(
convert_iter_for_each_to_for,
r#" r#"
fn main() { fn main() {
value.$0for_each(|x| println!("{}", x)); ().$0for_each(|x| println!("{}", x));
}"#,
)
}
#[test]
fn test_for_each_not_applicable_invalid_cursor_pos() {
check_assist_not_applicable(
r#"
use empty_iter::*;
fn main() {
Empty.iter().for_each(|(x, y)| $0println!("x: {}, y: {}", x, y));
}"#, }"#,
) )
} }

View file

@ -210,17 +210,24 @@ fn doctest_convert_iter_for_each_to_for() {
check_doc_test( check_doc_test(
"convert_iter_for_each_to_for", "convert_iter_for_each_to_for",
r#####" r#####"
//- /lib.rs crate:core
pub mod iter { pub mod traits { pub mod iterator { pub trait Iterator {} } } }
pub struct SomeIter;
impl self::iter::traits::iterator::Iterator for SomeIter {}
//- /lib.rs crate:main deps:core
use core::SomeIter;
fn main() { fn main() {
let vec = vec![(1, 2), (2, 3), (3, 4)]; let iter = SomeIter;
x.iter().for_each(|(x, y)| { iter.for_each$0(|(x, y)| {
println!("x: {}, y: {}", x, y); println!("x: {}, y: {}", x, y);
}); });
} }
"#####, "#####,
r#####" r#####"
use core::SomeIter;
fn main() { fn main() {
let vec = vec![(1, 2), (2, 3), (3, 4)]; let iter = SomeIter;
for (x, y) in x.iter() { for (x, y) in iter {
println!("x: {}, y: {}", x, y); println!("x: {}, y: {}", x, y);
} }
} }