Skip to content

Commit 88ec537

Browse files
committed
rustfix and rustfmt
1 parent 7a0adc4 commit 88ec537

File tree

4 files changed

+151
-155
lines changed

4 files changed

+151
-155
lines changed
Lines changed: 138 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
// noise reduction, remove before committing!
22
#![allow(unused_variables)]
33

4+
use clippy_utils::diagnostics::span_lint_and_sugg;
5+
use clippy_utils::source::snippet_with_applicability;
6+
use clippy_utils::{fn_def_id, match_def_path};
47
use rustc_errors::Applicability;
5-
use rustc_hir::*;
68
use rustc_hir::def::Res;
9+
use rustc_hir::*;
710
use rustc_lint::{LateContext, LateLintPass};
811
use rustc_session::declare_lint_pass;
912
use rustc_span::Span;
10-
use clippy_utils::{match_def_path, fn_def_id};
11-
use clippy_utils::diagnostics::span_lint_and_sugg;
12-
use clippy_utils::source::snippet_with_applicability;
1313

1414
declare_clippy_lint! {
1515
/// ### What it does
1616
/// Detects usage of `Option::and_then` and `bool::then_some` that could
17-
/// be replaced with `Option::filter`.
18-
///
17+
/// be replaced with `Option::filter`.
18+
///
1919
/// ### Why is this bad?
20-
/// Needless complexity, uses recent and uncommon stdlib funtions instead of
21-
/// one older function.
20+
/// Needless complexity, uses recent and uncommon stdlib funtions instead of
21+
/// one older function.
2222
///
2323
/// ### Example
2424
/// ```no_run
@@ -39,146 +39,150 @@ declare_clippy_lint! {
3939
declare_lint_pass!(AndThenThenSome => [AND_THEN_THEN_SOME]);
4040

4141
impl<'tcx> LateLintPass<'tcx> for AndThenThenSome {
42-
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
43-
match expr.kind {
44-
ExprKind::MethodCall(method_name, selfarg, [ arg ], _span) => {
45-
//(expr);
46-
//let option_id = cx.tcx.get_diagnostic_item(sym::Option);
47-
// TODO: check if type of reciever is diagnostic item Option.
48-
//let tckr = cx.typeck_results();
49-
//let def_id = tckr.type_dependent_def_id(expr.hir_id).unwrap();
50-
//(method_name, selfarg, arg);
51-
if is_and_then(cx, expr)
52-
{
53-
if let Some((closure_args, predicate)) = (then_some_closure_arg(cx, arg)) {
54-
//(predicate);
55-
show_sugg(cx, expr.span, selfarg, closure_args, predicate);
56-
}
57-
}
58-
}
59-
ExprKind::Call(_func, [ selfarg, arg ]) => {
60-
if (is_and_then(cx, expr)) {
61-
if let Some((closure_args, predicate)) = (then_some_closure_arg(cx, arg)) {
62-
//(predicate);
63-
show_sugg(cx, expr.span, selfarg, closure_args, predicate);
64-
}
65-
}
66-
}
67-
// TODO: check for call as associated function
68-
_ => {},
69-
}
70-
}
42+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
43+
match expr.kind {
44+
ExprKind::MethodCall(method_name, selfarg, [arg], _span) => {
45+
//let option_id = cx.tcx.get_diagnostic_item(sym::Option);
46+
// TODO: check if type of reciever is diagnostic item Option.
47+
//let tckr = cx.typeck_results();
48+
//let def_id = tckr.type_dependent_def_id(expr.hir_id).unwrap();
49+
//(method_name, selfarg, arg);
50+
if is_and_then(cx, expr) {
51+
if let Some((closure_args, predicate)) = then_some_closure_arg(cx, arg) {
52+
//(predicate);
53+
show_sugg(cx, expr.span, selfarg, closure_args, predicate);
54+
}
55+
}
56+
},
57+
ExprKind::Call(_func, [selfarg, arg]) => {
58+
if is_and_then(cx, expr) {
59+
if let Some((closure_args, predicate)) = then_some_closure_arg(cx, arg) {
60+
//(predicate);
61+
show_sugg(cx, expr.span, selfarg, closure_args, predicate);
62+
}
63+
}
64+
},
65+
// TODO: check for call as associated function
66+
_ => {},
67+
}
68+
}
7169
}
7270

7371
// `|v| X.then_some(v)` -> Some((span"|v|", X))
74-
fn then_some_closure_arg<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>)
75-
-> Option<(Span, &'tcx Expr<'tcx>)>
76-
{
77-
(expr);
78-
match expr.kind {
79-
ExprKind::Closure(Closure{
80-
fn_decl: FnDecl{ inputs: [ Ty{ hir_id: arg_id, ..} ], .. },
81-
body,
82-
..
83-
}) => {
84-
if let Node::Expr(expr) = (cx.tcx.hir_node(body.hir_id)) {
85-
//(arg_id);
86-
if let Some(body) = (peel_closure_body(cx, expr, *arg_id)) {
87-
Some((cx.tcx.hir().span(*arg_id), body))
88-
} else {
89-
None
90-
}
91-
} else {
92-
None
93-
}
94-
},
95-
_ => None,
96-
}
72+
fn then_some_closure_arg<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<(Span, &'tcx Expr<'tcx>)> {
73+
match expr.kind {
74+
ExprKind::Closure(Closure {
75+
fn_decl: FnDecl {
76+
inputs: [Ty { hir_id: arg_id, .. }],
77+
..
78+
},
79+
body,
80+
..
81+
}) => {
82+
if let Node::Expr(expr) = cx.tcx.hir_node(body.hir_id) {
83+
//(arg_id);
84+
(peel_closure_body(cx, expr, *arg_id)).map(|body| (cx.tcx.hir().span(*arg_id), body))
85+
} else {
86+
None
87+
}
88+
},
89+
_ => None,
90+
}
9791
}
9892

99-
fn peel_closure_body<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, closure_arg_id: HirId) -> Option<&'tcx Expr<'tcx>> {
100-
101-
match expr.kind {
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-
}
106-
ExprKind::MethodCall(_path, selfarg, [ arg ], _span) => {
107-
if is_then_some(cx, expr) &&
108-
is_local_defined_at(cx, arg, closure_arg_id)
109-
{
110-
// the argument to then_some is the same as that given to the closure
111-
Some(selfarg)
112-
} else {
113-
None
114-
}
115-
}
116-
ExprKind::Call(func, [ pred, arg ]) => {
117-
if (is_then_some(cx, expr)) && (is_local_defined_at(cx, arg, closure_arg_id)) {
118-
Some(pred)
119-
120-
} else {
121-
None
122-
}
123-
}
124-
_ => {
125-
None
126-
}
127-
}
93+
fn peel_closure_body<'tcx>(
94+
cx: &LateContext<'tcx>,
95+
expr: &'tcx Expr<'tcx>,
96+
closure_arg_id: HirId,
97+
) -> Option<&'tcx Expr<'tcx>> {
98+
match expr.kind {
99+
// it would be nice if we could lift { x; y.a() } into { x; y }.a()
100+
ExprKind::Block(
101+
Block {
102+
stmts: [],
103+
expr: Some(wrapped_expr),
104+
..
105+
},
106+
_,
107+
) => peel_closure_body(cx, wrapped_expr, closure_arg_id),
108+
ExprKind::MethodCall(_path, selfarg, [arg], _span) => {
109+
if is_then_some(cx, expr) && is_local_defined_at(cx, arg, closure_arg_id) {
110+
// the argument to then_some is the same as that given to the closure
111+
Some(selfarg)
112+
} else {
113+
None
114+
}
115+
},
116+
ExprKind::Call(func, [pred, arg]) => {
117+
if (is_then_some(cx, expr)) && (is_local_defined_at(cx, arg, closure_arg_id)) {
118+
Some(pred)
119+
} else {
120+
None
121+
}
122+
},
123+
_ => None,
124+
}
128125
}
129126

130-
fn is_local_defined_at<'tcx>(cx: &LateContext<'tcx>, local: &Expr<'_>, arg_hid: HirId) -> bool {
131-
match local.kind {
132-
ExprKind::Path(QPath::Resolved(_, Path{ res: Res::Local(local_hid), .. })) => {
133-
// FIXME: this is the best way i could find to compare if
134-
// a local refers to a specific closure argument.
135-
//
136-
// it breaks if the closure argument has an explicitly declared type,
137-
// since the spans only align for TyKind::Infer
138-
if let Node::Pat(Pat{ span: local_span, .. }) = (cx.tcx.hir_node(*local_hid)) &&
139-
let Node::Ty(Ty{ span: arg_span, .. }) = (cx.tcx.hir_node(arg_hid)) &&
140-
local_span == arg_span
141-
{
142-
true
143-
} else {
144-
false
145-
}
146-
}
147-
// is not local at all, so definitly isn't a local defined at the given position
148-
_ => false,
149-
}
127+
fn is_local_defined_at(cx: &LateContext<'_>, local: &Expr<'_>, arg_hid: HirId) -> bool {
128+
match local.kind {
129+
ExprKind::Path(QPath::Resolved(
130+
_,
131+
Path {
132+
res: Res::Local(local_hid),
133+
..
134+
},
135+
)) => {
136+
// FIXME: this is the best way i could find to compare if
137+
// a local refers to a specific closure argument.
138+
//
139+
// it breaks if the closure argument has an explicitly declared type,
140+
// since the spans only align for TyKind::Infer
141+
if let Node::Pat(Pat { span: local_span, .. }) = (cx.tcx.hir_node(*local_hid))
142+
&& let Node::Ty(Ty { span: arg_span, .. }) = (cx.tcx.hir_node(arg_hid))
143+
&& local_span == arg_span
144+
{
145+
true
146+
} else {
147+
false
148+
}
149+
},
150+
// is not local at all, so definitly isn't a local defined at the given position
151+
_ => false,
152+
}
150153
}
151154

152155
fn show_sugg(cx: &LateContext<'_>, span: Span, selfarg: &Expr<'_>, closure_args: Span, predicate: &Expr<'_>) {
153-
let mut appl = Applicability::MachineApplicable;
154-
let sugg = format!(
155-
"{}.filter(|{}| {})",
156-
snippet_with_applicability(cx, selfarg.span, "<OPTION>", &mut appl),
157-
snippet_with_applicability(cx, closure_args, "<ARGS>", &mut appl),
158-
snippet_with_applicability(cx, predicate.span, "<PREDICATE>", &mut appl));
159-
span_lint_and_sugg(cx, AND_THEN_THEN_SOME, span,
160-
"use of `and_then` + `then_some` is equivelent to `filter`",
161-
"use `Option::filter` instead",
162-
sugg, appl);
156+
let mut appl = Applicability::MachineApplicable;
157+
let sugg = format!(
158+
"{}.filter(|{}| {})",
159+
snippet_with_applicability(cx, selfarg.span, "<OPTION>", &mut appl),
160+
snippet_with_applicability(cx, closure_args, "<ARGS>", &mut appl),
161+
snippet_with_applicability(cx, predicate.span, "<PREDICATE>", &mut appl)
162+
);
163+
span_lint_and_sugg(
164+
cx,
165+
AND_THEN_THEN_SOME,
166+
span,
167+
"use of `and_then` + `then_some` is equivelent to `filter`",
168+
"use `Option::filter` instead",
169+
sugg,
170+
appl,
171+
);
163172
}
164173

165174
fn is_then_some(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
166-
if let Some(def_id) = fn_def_id(cx, expr) {
167-
(match_def_path(
168-
cx, (def_id),
169-
&["core", "bool", "<impl bool>", "then_some"]))
170-
} else {
171-
(expr);
172-
false
173-
}
175+
if let Some(def_id) = fn_def_id(cx, expr) {
176+
match_def_path(cx, def_id, &["core", "bool", "<impl bool>", "then_some"])
177+
} else {
178+
false
179+
}
174180
}
175181

176182
fn is_and_then(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
177-
if let Some(def_id) = fn_def_id(cx, expr) {
178-
(match_def_path(
179-
cx, (def_id),
180-
&["core", "option", "Option", "and_then"]))
181-
} else {
182-
false
183-
}
183+
if let Some(def_id) = fn_def_id(cx, expr) {
184+
match_def_path(cx, def_id, &["core", "option", "Option", "and_then"])
185+
} else {
186+
false
187+
}
184188
}

tests/ui/and_then_then_some.fixed

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
#![warn(clippy::and_then_then_some)]
22

33
fn main() {
4-
let x = Some("foo".to_string());
4+
let x = Some("foo".to_string());
55

66
let _y = x.clone().filter(|v| v.starts_with('f'));
77

8-
let _z = x.clone().filter(|v| v.starts_with('f'));
9-
let _w = x.filter(|v| v.starts_with('f'));
8+
let _z = x.clone().filter(|v| v.starts_with('f'));
9+
let _w = x.filter(|v| v.starts_with('f'));
1010
}

tests/ui/and_then_then_some.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
#![warn(clippy::and_then_then_some)]
22

33
fn main() {
4-
let x = Some("foo".to_string());
4+
let x = Some("foo".to_string());
55

6-
let _y = x.clone().and_then(|v| v.starts_with('f')
7-
.then_some(v));
6+
let _y = x.clone().and_then(|v| v.starts_with('f').then_some(v));
87

9-
let _z = x.clone().and_then(|v| bool::then_some(v.starts_with('f'), v));
10-
let _w = Option::and_then(x, |v| {
11-
bool::then_some(v.starts_with('f'), v)
12-
});
8+
let _z = x.clone().and_then(|v| bool::then_some(v.starts_with('f'), v));
9+
let _w = Option::and_then(x, |v| bool::then_some(v.starts_with('f'), v));
1310
}

tests/ui/and_then_then_some.stderr

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,23 @@
11
error: use of `and_then` + `then_some` is equivelent to `filter`
22
--> tests/ui/and_then_then_some.rs:6:14
33
|
4-
LL | let _y = x.clone().and_then(|v| v.starts_with('f')
5-
| ______________^
6-
LL | | .then_some(v));
7-
| |______________________^ help: use `Option::filter` instead: `x.clone().filter(|v| v.starts_with('f'))`
4+
LL | let _y = x.clone().and_then(|v| v.starts_with('f').then_some(v));
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `Option::filter` instead: `x.clone().filter(|v| v.starts_with('f'))`
86
|
97
= note: `-D clippy::and-then-then-some` implied by `-D warnings`
108
= help: to override `-D warnings` add `#[allow(clippy::and_then_then_some)]`
119

1210
error: use of `and_then` + `then_some` is equivelent to `filter`
13-
--> tests/ui/and_then_then_some.rs:9:11
11+
--> tests/ui/and_then_then_some.rs:8:14
1412
|
1513
LL | let _z = x.clone().and_then(|v| bool::then_some(v.starts_with('f'), v));
1614
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `Option::filter` instead: `x.clone().filter(|v| v.starts_with('f'))`
1715

1816
error: use of `and_then` + `then_some` is equivelent to `filter`
19-
--> tests/ui/and_then_then_some.rs:10:11
17+
--> tests/ui/and_then_then_some.rs:9:14
2018
|
21-
LL | let _w = Option::and_then(x, |v| {
22-
| ______________^
23-
LL | | bool::then_some(v.starts_with('f'), v)
24-
LL | | });
25-
| |______^ help: use `Option::filter` instead: `x.filter(|v| v.starts_with('f'))`
19+
LL | let _w = Option::and_then(x, |v| bool::then_some(v.starts_with('f'), v));
20+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `Option::filter` instead: `x.filter(|v| v.starts_with('f'))`
2621

2722
error: aborting due to 3 previous errors
2823

0 commit comments

Comments
 (0)