Skip to content

Commit f014e15

Browse files
committed
Refactor code according to reivews
1 parent dc70701 commit f014e15

File tree

1 file changed

+141
-83
lines changed

1 file changed

+141
-83
lines changed

clippy_lints/src/unnecessary_wrap.rs

Lines changed: 141 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::utils::{
44
};
55
use if_chain::if_chain;
66
use rustc_errors::Applicability;
7-
use rustc_hir::intravisit::{FnKind, NestedVisitorMap, Visitor};
7+
use rustc_hir::intravisit::{FnKind, Visitor};
88
use rustc_hir::*;
99
use rustc_lint::{LateContext, LateLintPass};
1010
use rustc_middle::{hir::map::Map, ty::subst::GenericArgKind};
@@ -71,57 +71,31 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap {
7171
}
7272
}
7373

74-
if let ExprKind::Block(ref block, ..) = body.value.kind {
75-
let path = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) {
76-
&paths::OPTION_SOME
77-
} else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) {
78-
&paths::RESULT_OK
79-
} else {
80-
return;
81-
};
82-
83-
let mut visitor = UnnecessaryWrapVisitor { result: Vec::new() };
84-
visitor.visit_block(block);
85-
let result = visitor.result;
86-
87-
if result.iter().any(|expr| {
88-
if_chain! {
89-
if let ExprKind::Call(ref func, ref args) = expr.kind;
90-
if let ExprKind::Path(ref qpath) = func.kind;
91-
if match_qpath(qpath, path);
92-
if args.len() == 1;
93-
then {
94-
false
95-
} else {
96-
true
97-
}
74+
let path = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) {
75+
&paths::OPTION_SOME
76+
} else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) {
77+
&paths::RESULT_OK
78+
} else {
79+
return;
80+
};
81+
82+
let mut suggs = Vec::new();
83+
let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| {
84+
if_chain! {
85+
if let ExprKind::Call(ref func, ref args) = ret_expr.kind;
86+
if let ExprKind::Path(ref qpath) = func.kind;
87+
if match_qpath(qpath, path);
88+
if args.len() == 1;
89+
then {
90+
suggs.push((ret_expr.span, snippet(cx, args[0].span.source_callsite(), "..").to_string()));
91+
true
92+
} else {
93+
false
9894
}
99-
}) {
100-
return;
10195
}
96+
});
10297

103-
let suggs = result
104-
.iter()
105-
.filter_map(|expr| {
106-
let snippet = if let ExprKind::Call(_, ref args) = expr.kind {
107-
Some(snippet(cx, args[0].span, "..").to_string())
108-
} else {
109-
None
110-
};
111-
snippet.map(|snip| (expr.span, snip))
112-
})
113-
.chain({
114-
let inner_ty = return_ty(cx, hir_id)
115-
.walk()
116-
.skip(1) // skip `std::option::Option` or `std::result::Result`
117-
.take(1) // first outermost inner type is needed
118-
.filter_map(|inner| match inner.unpack() {
119-
GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()),
120-
_ => None,
121-
});
122-
inner_ty.map(|inner_ty| (fn_decl.output.span(), inner_ty))
123-
});
124-
98+
if can_sugg {
12599
span_lint_and_then(
126100
cx,
127101
UNNECESSARY_WRAP,
@@ -132,59 +106,143 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap {
132106
diag,
133107
"factor this out to",
134108
Applicability::MachineApplicable,
135-
suggs,
109+
suggs.into_iter().chain({
110+
let inner_ty = return_ty(cx, hir_id)
111+
.walk()
112+
.skip(1) // skip `std::option::Option` or `std::result::Result`
113+
.take(1) // take the first outermost inner type
114+
.filter_map(|inner| match inner.unpack() {
115+
GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()),
116+
_ => None,
117+
});
118+
inner_ty.map(|inner_ty| (fn_decl.output.span(), inner_ty))
119+
}),
136120
);
137121
},
138122
);
139123
}
140124
}
141125
}
142126

143-
struct UnnecessaryWrapVisitor<'tcx> {
144-
result: Vec<&'tcx Expr<'tcx>>,
145-
}
127+
// code below is copied from `bind_instead_of_map`
128+
129+
fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir Expr<'hir>, callback: F) -> bool
130+
where
131+
F: FnMut(&'hir Expr<'hir>) -> bool,
132+
{
133+
struct RetFinder<F> {
134+
in_stmt: bool,
135+
failed: bool,
136+
cb: F,
137+
}
138+
139+
struct WithStmtGuarg<'a, F> {
140+
val: &'a mut RetFinder<F>,
141+
prev_in_stmt: bool,
142+
}
146143

147-
impl<'tcx> Visitor<'tcx> for UnnecessaryWrapVisitor<'tcx> {
148-
type Map = Map<'tcx>;
144+
impl<F> RetFinder<F> {
145+
fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> {
146+
let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt);
147+
WithStmtGuarg {
148+
val: self,
149+
prev_in_stmt,
150+
}
151+
}
152+
}
149153

150-
fn visit_block(&mut self, block: &'tcx Block<'tcx>) {
151-
for stmt in block.stmts {
152-
self.visit_stmt(stmt);
154+
impl<F> std::ops::Deref for WithStmtGuarg<'_, F> {
155+
type Target = RetFinder<F>;
156+
157+
fn deref(&self) -> &Self::Target {
158+
self.val
153159
}
154-
if let Some(expr) = block.expr {
155-
self.visit_expr(expr)
160+
}
161+
162+
impl<F> std::ops::DerefMut for WithStmtGuarg<'_, F> {
163+
fn deref_mut(&mut self) -> &mut Self::Target {
164+
self.val
156165
}
157166
}
158167

159-
fn visit_stmt(&mut self, stmt: &'tcx Stmt<'tcx>) {
160-
match stmt.kind {
161-
StmtKind::Semi(ref expr) => {
162-
if let ExprKind::Ret(Some(value)) = expr.kind {
163-
self.result.push(value);
164-
}
165-
},
166-
StmtKind::Expr(ref expr) => self.visit_expr(expr),
167-
_ => (),
168+
impl<F> Drop for WithStmtGuarg<'_, F> {
169+
fn drop(&mut self) {
170+
self.val.in_stmt = self.prev_in_stmt;
168171
}
169172
}
170173

171-
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
172-
match expr.kind {
173-
ExprKind::Ret(Some(value)) => self.result.push(value),
174-
ExprKind::Call(..) | ExprKind::Path(..) => self.result.push(expr),
175-
ExprKind::Block(ref block, _) | ExprKind::Loop(ref block, ..) => {
176-
self.visit_block(block);
177-
},
178-
ExprKind::Match(_, arms, _) => {
179-
for arm in arms {
180-
self.visit_expr(arm.body);
174+
impl<'hir, F: FnMut(&'hir Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder<F> {
175+
type Map = Map<'hir>;
176+
177+
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
178+
intravisit::NestedVisitorMap::None
179+
}
180+
181+
fn visit_stmt(&mut self, stmt: &'hir Stmt<'_>) {
182+
intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt)
183+
}
184+
185+
fn visit_expr(&mut self, expr: &'hir Expr<'_>) {
186+
if self.failed {
187+
return;
188+
}
189+
if self.in_stmt {
190+
match expr.kind {
191+
ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr),
192+
_ => intravisit::walk_expr(self, expr),
193+
}
194+
} else {
195+
match expr.kind {
196+
ExprKind::Match(cond, arms, _) => {
197+
self.inside_stmt(true).visit_expr(cond);
198+
for arm in arms {
199+
self.visit_expr(arm.body);
200+
}
201+
},
202+
ExprKind::Block(..) => intravisit::walk_expr(self, expr),
203+
ExprKind::Ret(Some(expr)) => self.visit_expr(expr),
204+
_ => self.failed |= !(self.cb)(expr),
181205
}
182-
},
183-
_ => intravisit::walk_expr(self, expr),
206+
}
184207
}
185208
}
186209

187-
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
188-
NestedVisitorMap::None
210+
!contains_try(expr) && {
211+
let mut ret_finder = RetFinder {
212+
in_stmt: false,
213+
failed: false,
214+
cb: callback,
215+
};
216+
ret_finder.visit_expr(expr);
217+
!ret_finder.failed
218+
}
219+
}
220+
221+
/// returns `true` if expr contains match expr desugared from try
222+
fn contains_try(expr: &Expr<'_>) -> bool {
223+
struct TryFinder {
224+
found: bool,
225+
}
226+
227+
impl<'hir> intravisit::Visitor<'hir> for TryFinder {
228+
type Map = Map<'hir>;
229+
230+
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
231+
intravisit::NestedVisitorMap::None
232+
}
233+
234+
fn visit_expr(&mut self, expr: &'hir Expr<'hir>) {
235+
if self.found {
236+
return;
237+
}
238+
match expr.kind {
239+
ExprKind::Match(_, _, MatchSource::TryDesugar) => self.found = true,
240+
_ => intravisit::walk_expr(self, expr),
241+
}
242+
}
189243
}
244+
245+
let mut visitor = TryFinder { found: false };
246+
visitor.visit_expr(expr);
247+
visitor.found
190248
}

0 commit comments

Comments
 (0)