Skip to content

Commit 37e7058

Browse files
committed
i think i have everything working
1 parent 5b520b6 commit 37e7058

File tree

2 files changed

+31
-15
lines changed

2 files changed

+31
-15
lines changed

clippy_lints/src/and_then_then_some.rs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ declare_lint_pass!(AndThenThenSome => [AND_THEN_THEN_SOME]);
4141
impl<'tcx> LateLintPass<'tcx> for AndThenThenSome {
4242
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
4343
match expr.kind {
44-
ExprKind::MethodCall(method_name, selfarg, [ arg ], span) => {
44+
ExprKind::MethodCall(method_name, selfarg, [ arg ], _span) => {
4545
//(expr);
4646
//let option_id = cx.tcx.get_diagnostic_item(sym::Option);
4747
// TODO: check if type of reciever is diagnostic item Option.
@@ -56,6 +56,14 @@ impl<'tcx> LateLintPass<'tcx> for AndThenThenSome {
5656
}
5757
}
5858
}
59+
ExprKind::Call(_func, [ selfarg, arg ]) => {
60+
if dbg!(is_and_then(cx, expr)) {
61+
if let Some((closure_args, predicate)) = dbg!(then_some_closure_arg(cx, arg)) {
62+
//dbg!(predicate);
63+
show_sugg(cx, expr.span, selfarg, closure_args, predicate);
64+
}
65+
}
66+
}
5967
// TODO: check for call as associated function
6068
_ => {},
6169
}
@@ -66,15 +74,16 @@ impl<'tcx> LateLintPass<'tcx> for AndThenThenSome {
6674
fn then_some_closure_arg<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>)
6775
-> Option<(Span, &'tcx Expr<'tcx>)>
6876
{
77+
dbg!(expr);
6978
match expr.kind {
7079
ExprKind::Closure(Closure{
7180
fn_decl: FnDecl{ inputs: [ Ty{ hir_id: arg_id, ..} ], .. },
7281
body,
7382
..
7483
}) => {
75-
if let Node::Expr(expr) = cx.tcx.hir_node(body.hir_id) {
84+
if let Node::Expr(expr) = dbg!(cx.tcx.hir_node(body.hir_id)) {
7685
//dbg!(arg_id);
77-
if let Some(body) = peel_closure_body(cx, expr, *arg_id) {
86+
if let Some(body) = dbg!(peel_closure_body(cx, expr, *arg_id)) {
7887
Some((cx.tcx.hir().span(*arg_id), body))
7988
} else {
8089
None
@@ -89,11 +98,11 @@ fn then_some_closure_arg<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>)
8998

9099
fn peel_closure_body<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, closure_arg_id: HirId) -> Option<&'tcx Expr<'tcx>> {
91100

92-
//dbg!(cx.tcx.hir_node(closure_arg_id));
93101
match expr.kind {
94-
ExprKind::Block(_block, _) =>
95-
// recurse somehow, maybe lift { x; y.a() } into { x; y }.a()
96-
todo!(),
102+
// it would be nice if we could lift { x; y.a() } into { x; y }.a()
103+
ExprKind::Block(Block{ stmts: [], expr: Some(wrapped_expr), ..}, _) => {
104+
peel_closure_body(cx, wrapped_expr, closure_arg_id)
105+
}
97106
ExprKind::MethodCall(_path, selfarg, [ arg ], _span) => {
98107
if is_then_some(cx, expr) &&
99108
is_local_defined_at(cx, arg, closure_arg_id)
@@ -116,17 +125,24 @@ fn peel_closure_body<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, closu
116125
None
117126
}
118127
}
119-
_ => None,
128+
_ => {
129+
eprintln!("cannot peel {expr:#?}");
130+
None
131+
}
120132
}
121133
}
122134

123135
fn is_local_defined_at<'tcx>(cx: &LateContext<'tcx>, local: &Expr<'_>, arg_hid: HirId) -> bool {
124-
//dbg!(local);
136+
dbg!(local);
125137
match local.kind {
126138
ExprKind::Path(QPath::Resolved(_, Path{ res: Res::Local(local_hid), .. })) => {
127-
// XXX" this is the best way i could find to compare if a local refers to a specific closure argument.
128-
if let Node::Pat(Pat{ span: local_span, .. }) = cx.tcx.hir_node(*local_hid) &&
129-
let Node::Ty(Ty{ span: arg_span, .. }) = cx.tcx.hir_node(arg_hid) &&
139+
// FIXME: this is the best way i could find to compare if
140+
// a local refers to a specific closure argument.
141+
//
142+
// it breaks if the closure argument has an explicitly declared type,
143+
// since the spans only align for TyKind::Infer
144+
if let Node::Pat(Pat{ span: local_span, .. }) = dbg!(cx.tcx.hir_node(*local_hid)) &&
145+
let Node::Ty(Ty{ span: arg_span, .. }) = dbg!(cx.tcx.hir_node(arg_hid)) &&
130146
local_span == arg_span
131147
{
132148
true

tests/ui/and_then_then_some.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
fn main() {
44
let x = Some("foo".to_string());
55

6-
let _y = x.clone().and_then(|v| v.starts_with('f')
6+
/*let _y = x.clone().and_then(|v| v.starts_with('f')
77
.then_some(v));
88
9-
let _z = x.clone().and_then(|v| bool::then_some(v.starts_with('f'), v));
10-
let _w = Option::and_then(x, |v: String| {
9+
let _z = x.clone().and_then(|v| bool::then_some(v.starts_with('f'), v));*/
10+
let _w = Option::and_then(x, |v| {
1111
bool::then_some(v.starts_with('f'), v)
1212
});
1313
}

0 commit comments

Comments
 (0)