Skip to content

Commit efdc739

Browse files
author
Michael Wright
committed
Move unnecessary_filter_map to a submodule
1 parent db5c63b commit efdc739

File tree

2 files changed

+148
-140
lines changed

2 files changed

+148
-140
lines changed

clippy_lints/src/methods.rs renamed to clippy_lints/src/methods/mod.rs

Lines changed: 2 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::rustc::hir;
22
use crate::rustc::hir::def::Def;
3-
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
43
use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, Lint, LintArray, LintContext, LintPass};
54
use crate::rustc::ty::{self, Ty};
65
use crate::rustc::{declare_tool_lint, lint_array};
@@ -9,7 +8,6 @@ use crate::syntax::ast;
98
use crate::syntax::source_map::{BytePos, Span};
109
use crate::utils::paths;
1110
use crate::utils::sugg;
12-
use crate::utils::usage::mutated_variables;
1311
use crate::utils::{
1412
get_arg_name, get_trait_def_id, implements_trait, in_macro, is_copy, is_expn_of, is_self, is_self_ty,
1513
iter_input_pats, last_path_segment, match_def_path, match_path, match_qpath, match_trait_method, match_type,
@@ -22,6 +20,8 @@ use std::borrow::Cow;
2220
use std::fmt;
2321
use std::iter;
2422

23+
mod unnecessary_filter_map;
24+
2525
#[derive(Clone)]
2626
pub struct Pass;
2727

@@ -1424,144 +1424,6 @@ fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr, fold_args:
14241424
};
14251425
}
14261426

1427-
mod unnecessary_filter_map {
1428-
use super::*;
1429-
1430-
pub(super) fn lint(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) {
1431-
1432-
if !match_trait_method(cx, expr, &paths::ITERATOR) {
1433-
return;
1434-
}
1435-
1436-
if let hir::ExprKind::Closure(_, _, body_id, ..) = args[1].node {
1437-
1438-
let body = cx.tcx.hir.body(body_id);
1439-
let arg_id = body.arguments[0].pat.id;
1440-
let mutates_arg = match mutated_variables(&body.value, cx) {
1441-
Some(used_mutably) => used_mutably.contains(&arg_id),
1442-
None => true,
1443-
};
1444-
1445-
let (mut found_mapping, mut found_filtering) = check_expression(&cx, arg_id, &body.value);
1446-
1447-
let mut return_visitor = ReturnVisitor::new(&cx, arg_id);
1448-
return_visitor.visit_expr(&body.value);
1449-
found_mapping |= return_visitor.found_mapping;
1450-
found_filtering |= return_visitor.found_filtering;
1451-
1452-
if !found_filtering {
1453-
span_lint(
1454-
cx,
1455-
UNNECESSARY_FILTER_MAP,
1456-
expr.span,
1457-
"this `.filter_map` can be written more simply using `.map`",
1458-
);
1459-
return;
1460-
}
1461-
1462-
if !found_mapping && !mutates_arg {
1463-
span_lint(
1464-
cx,
1465-
UNNECESSARY_FILTER_MAP,
1466-
expr.span,
1467-
"this `.filter_map` can be written more simply using `.filter`",
1468-
);
1469-
return;
1470-
}
1471-
}
1472-
}
1473-
1474-
// returns (found_mapping, found_filtering)
1475-
fn check_expression<'a, 'tcx: 'a>(cx: &'a LateContext<'a, 'tcx>, arg_id: ast::NodeId, expr: &'tcx hir::Expr) -> (bool, bool) {
1476-
match &expr.node {
1477-
hir::ExprKind::Call(ref func, ref args) => {
1478-
if_chain! {
1479-
if let hir::ExprKind::Path(ref path) = func.node;
1480-
then {
1481-
if match_qpath(path, &paths::OPTION_SOME) {
1482-
if_chain! {
1483-
if let hir::ExprKind::Path(path) = &args[0].node;
1484-
if let Def::Local(ref local) = cx.tables.qpath_def(path, args[0].hir_id);
1485-
then {
1486-
if arg_id == *local {
1487-
return (false, false)
1488-
}
1489-
}
1490-
}
1491-
return (true, false);
1492-
} else {
1493-
// We don't know. It might do anything.
1494-
return (true, true);
1495-
}
1496-
}
1497-
}
1498-
(true, true)
1499-
},
1500-
hir::ExprKind::Block(ref block, _) => {
1501-
if let Some(expr) = &block.expr {
1502-
check_expression(cx, arg_id, &expr)
1503-
} else {
1504-
(false, false)
1505-
}
1506-
},
1507-
// There must be an else_arm or there will be a type error
1508-
hir::ExprKind::If(_, ref if_arm, Some(ref else_arm)) => {
1509-
let if_check = check_expression(cx, arg_id, if_arm);
1510-
let else_check = check_expression(cx, arg_id, else_arm);
1511-
(if_check.0 | else_check.0, if_check.1 | else_check.1)
1512-
},
1513-
hir::ExprKind::Match(_, ref arms, _) => {
1514-
let mut found_mapping = false;
1515-
let mut found_filtering = false;
1516-
for arm in arms {
1517-
let (m, f) = check_expression(cx, arg_id, &arm.body);
1518-
found_mapping |= m;
1519-
found_filtering |= f;
1520-
}
1521-
(found_mapping, found_filtering)
1522-
},
1523-
hir::ExprKind::Path(path) if match_qpath(path, &paths::OPTION_NONE) => (false, true),
1524-
_ => (true, true)
1525-
}
1526-
}
1527-
1528-
struct ReturnVisitor<'a, 'tcx: 'a> {
1529-
cx: &'a LateContext<'a, 'tcx>,
1530-
arg_id: ast::NodeId,
1531-
// Found a non-None return that isn't Some(input)
1532-
found_mapping: bool,
1533-
// Found a return that isn't Some
1534-
found_filtering: bool,
1535-
}
1536-
1537-
impl<'a, 'tcx: 'a> ReturnVisitor<'a, 'tcx> {
1538-
fn new(cx: &'a LateContext<'a, 'tcx>, arg_id: ast::NodeId) -> ReturnVisitor<'a, 'tcx> {
1539-
ReturnVisitor {
1540-
cx,
1541-
arg_id,
1542-
found_mapping: false,
1543-
found_filtering: false,
1544-
}
1545-
}
1546-
}
1547-
1548-
impl<'a, 'tcx> Visitor<'tcx> for ReturnVisitor<'a, 'tcx> {
1549-
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
1550-
if let hir::ExprKind::Ret(Some(expr)) = &expr.node {
1551-
let (found_mapping, found_filtering) = check_expression(self.cx, self.arg_id, expr);
1552-
self.found_mapping |= found_mapping;
1553-
self.found_filtering |= found_filtering;
1554-
} else {
1555-
walk_expr(self, expr);
1556-
}
1557-
}
1558-
1559-
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
1560-
NestedVisitorMap::None
1561-
}
1562-
}
1563-
}
1564-
15651427
fn lint_iter_nth(cx: &LateContext<'_, '_>, expr: &hir::Expr, iter_args: &[hir::Expr], is_mut: bool) {
15661428
let mut_str = if is_mut { "_mut" } else { "" };
15671429
let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some() {
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
2+
use crate::rustc::lint::LateContext;
3+
use crate::rustc::hir;
4+
use crate::rustc::hir::def::Def;
5+
use crate::syntax::ast;
6+
use crate::utils::{match_qpath, match_trait_method, span_lint};
7+
use crate::utils::paths;
8+
use crate::utils::usage::mutated_variables;
9+
10+
use if_chain::if_chain;
11+
12+
use super::UNNECESSARY_FILTER_MAP;
13+
14+
pub(super) fn lint(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) {
15+
16+
if !match_trait_method(cx, expr, &paths::ITERATOR) {
17+
return;
18+
}
19+
20+
if let hir::ExprKind::Closure(_, _, body_id, ..) = args[1].node {
21+
22+
let body = cx.tcx.hir.body(body_id);
23+
let arg_id = body.arguments[0].pat.id;
24+
let mutates_arg = match mutated_variables(&body.value, cx) {
25+
Some(used_mutably) => used_mutably.contains(&arg_id),
26+
None => true,
27+
};
28+
29+
let (mut found_mapping, mut found_filtering) = check_expression(&cx, arg_id, &body.value);
30+
31+
let mut return_visitor = ReturnVisitor::new(&cx, arg_id);
32+
return_visitor.visit_expr(&body.value);
33+
found_mapping |= return_visitor.found_mapping;
34+
found_filtering |= return_visitor.found_filtering;
35+
36+
if !found_filtering {
37+
span_lint(
38+
cx,
39+
UNNECESSARY_FILTER_MAP,
40+
expr.span,
41+
"this `.filter_map` can be written more simply using `.map`",
42+
);
43+
return;
44+
}
45+
46+
if !found_mapping && !mutates_arg {
47+
span_lint(
48+
cx,
49+
UNNECESSARY_FILTER_MAP,
50+
expr.span,
51+
"this `.filter_map` can be written more simply using `.filter`",
52+
);
53+
return;
54+
}
55+
}
56+
}
57+
58+
// returns (found_mapping, found_filtering)
59+
fn check_expression<'a, 'tcx: 'a>(cx: &'a LateContext<'a, 'tcx>, arg_id: ast::NodeId, expr: &'tcx hir::Expr) -> (bool, bool) {
60+
match &expr.node {
61+
hir::ExprKind::Call(ref func, ref args) => {
62+
if_chain! {
63+
if let hir::ExprKind::Path(ref path) = func.node;
64+
then {
65+
if match_qpath(path, &paths::OPTION_SOME) {
66+
if_chain! {
67+
if let hir::ExprKind::Path(path) = &args[0].node;
68+
if let Def::Local(ref local) = cx.tables.qpath_def(path, args[0].hir_id);
69+
then {
70+
if arg_id == *local {
71+
return (false, false)
72+
}
73+
}
74+
}
75+
return (true, false);
76+
} else {
77+
// We don't know. It might do anything.
78+
return (true, true);
79+
}
80+
}
81+
}
82+
(true, true)
83+
},
84+
hir::ExprKind::Block(ref block, _) => {
85+
if let Some(expr) = &block.expr {
86+
check_expression(cx, arg_id, &expr)
87+
} else {
88+
(false, false)
89+
}
90+
},
91+
// There must be an else_arm or there will be a type error
92+
hir::ExprKind::If(_, ref if_arm, Some(ref else_arm)) => {
93+
let if_check = check_expression(cx, arg_id, if_arm);
94+
let else_check = check_expression(cx, arg_id, else_arm);
95+
(if_check.0 | else_check.0, if_check.1 | else_check.1)
96+
},
97+
hir::ExprKind::Match(_, ref arms, _) => {
98+
let mut found_mapping = false;
99+
let mut found_filtering = false;
100+
for arm in arms {
101+
let (m, f) = check_expression(cx, arg_id, &arm.body);
102+
found_mapping |= m;
103+
found_filtering |= f;
104+
}
105+
(found_mapping, found_filtering)
106+
},
107+
hir::ExprKind::Path(path) if match_qpath(path, &paths::OPTION_NONE) => (false, true),
108+
_ => (true, true)
109+
}
110+
}
111+
112+
struct ReturnVisitor<'a, 'tcx: 'a> {
113+
cx: &'a LateContext<'a, 'tcx>,
114+
arg_id: ast::NodeId,
115+
// Found a non-None return that isn't Some(input)
116+
found_mapping: bool,
117+
// Found a return that isn't Some
118+
found_filtering: bool,
119+
}
120+
121+
impl<'a, 'tcx: 'a> ReturnVisitor<'a, 'tcx> {
122+
fn new(cx: &'a LateContext<'a, 'tcx>, arg_id: ast::NodeId) -> ReturnVisitor<'a, 'tcx> {
123+
ReturnVisitor {
124+
cx,
125+
arg_id,
126+
found_mapping: false,
127+
found_filtering: false,
128+
}
129+
}
130+
}
131+
132+
impl<'a, 'tcx> Visitor<'tcx> for ReturnVisitor<'a, 'tcx> {
133+
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
134+
if let hir::ExprKind::Ret(Some(expr)) = &expr.node {
135+
let (found_mapping, found_filtering) = check_expression(self.cx, self.arg_id, expr);
136+
self.found_mapping |= found_mapping;
137+
self.found_filtering |= found_filtering;
138+
} else {
139+
walk_expr(self, expr);
140+
}
141+
}
142+
143+
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
144+
NestedVisitorMap::None
145+
}
146+
}

0 commit comments

Comments
 (0)