Skip to content

Commit 5ab502c

Browse files
committed
Auto merge of rust-lang#93376 - flip1995:clippyup, r=Manishearth
Update Clippy r? `@Manishearth`
2 parents 1b41093 + cce9231 commit 5ab502c

File tree

102 files changed

+1841
-997
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+1841
-997
lines changed

src/tools/clippy/CHANGELOG.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -981,7 +981,7 @@ Released 2021-03-25
981981
[#6532](https://github.com/rust-lang/rust-clippy/pull/6532)
982982
* [`single_match`] Suggest `if` over `if let` when possible
983983
[#6574](https://github.com/rust-lang/rust-clippy/pull/6574)
984-
* [`ref_in_deref`] Use parentheses correctly in suggestion
984+
* `ref_in_deref` Use parentheses correctly in suggestion
985985
[#6609](https://github.com/rust-lang/rust-clippy/pull/6609)
986986
* [`stable_sort_primitive`] Clarify error message
987987
[#6611](https://github.com/rust-lang/rust-clippy/pull/6611)
@@ -3227,7 +3227,6 @@ Released 2018-09-13
32273227
[`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing
32283228
[`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
32293229
[`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference
3230-
[`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
32313230
[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
32323231
[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
32333232
[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once

src/tools/clippy/clippy_dev/src/bless.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,14 @@ use walkdir::WalkDir;
99

1010
use crate::clippy_project_root;
1111

12+
#[cfg(not(windows))]
13+
static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
14+
#[cfg(windows)]
15+
static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
16+
1217
static CLIPPY_BUILD_TIME: SyncLazy<Option<std::time::SystemTime>> = SyncLazy::new(|| {
1318
let mut path = std::env::current_exe().unwrap();
14-
path.set_file_name("cargo-clippy");
19+
path.set_file_name(CARGO_CLIPPY_EXE);
1520
fs::metadata(path).ok()?.modified().ok()
1621
});
1722

src/tools/clippy/clippy_dev/src/lint.rs

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ pub fn run(filename: &str) {
77
.args(["-Z", "no-codegen"])
88
.args(["--edition", "2021"])
99
.arg(filename)
10-
.env("__CLIPPY_INTERNAL_TESTS", "true")
1110
.status()
1211
.expect("failed to run cargo")
1312
.code();

src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs

+2
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,6 @@ impl<'tcx> LateLintPass<'tcx> for BorrowAsPtr {
9494
}
9595
}
9696
}
97+
98+
extract_msrv_attr!(LateContext);
9799
}

src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs

+3-8
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,14 @@ pub(super) fn check(
2323

2424
if_chain! {
2525
if let LitKind::Int(n, _) = lit.node;
26-
if let Some(src) = snippet_opt(cx, lit.span);
26+
if let Some(src) = snippet_opt(cx, cast_expr.span);
2727
if cast_to.is_floating_point();
2828
if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node);
2929
let from_nbits = 128 - n.leading_zeros();
3030
let to_nbits = fp_ty_mantissa_nbits(cast_to);
3131
if from_nbits != 0 && to_nbits != 0 && from_nbits <= to_nbits && num_lit.is_decimal();
3232
then {
33-
let literal_str = if is_unary_neg(cast_expr) { format!("-{}", num_lit.integer) } else { num_lit.integer.into() };
34-
lint_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
33+
lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to);
3534
return true
3635
}
3736
}
@@ -48,7 +47,7 @@ pub(super) fn check(
4847
| LitKind::Float(_, LitFloatType::Suffixed(_))
4948
if cast_from.kind() == cast_to.kind() =>
5049
{
51-
if let Some(src) = snippet_opt(cx, lit.span) {
50+
if let Some(src) = snippet_opt(cx, cast_expr.span) {
5251
if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) {
5352
lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to);
5453
}
@@ -113,7 +112,3 @@ fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 {
113112
_ => 0,
114113
}
115114
}
116-
117-
fn is_unary_neg(expr: &Expr<'_>) -> bool {
118-
matches!(expr.kind, ExprKind::Unary(UnOp::Neg, _))
119-
}

src/tools/clippy/clippy_lints/src/dereference.rs

+144-55
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
22
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
3+
use clippy_utils::sugg::has_enclosing_paren;
34
use clippy_utils::ty::peel_mid_ty_refs;
45
use clippy_utils::{get_parent_expr, get_parent_node, is_lint_allowed, path_to_local};
56
use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
@@ -10,11 +11,10 @@ use rustc_hir::{
1011
Pat, PatKind, UnOp,
1112
};
1213
use rustc_lint::{LateContext, LateLintPass};
13-
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
14+
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
1415
use rustc_middle::ty::{self, Ty, TyCtxt, TyS, TypeckResults};
1516
use rustc_session::{declare_tool_lint, impl_lint_pass};
1617
use rustc_span::{symbol::sym, Span};
17-
use std::iter;
1818

1919
declare_clippy_lint! {
2020
/// ### What it does
@@ -131,8 +131,6 @@ pub struct Dereferencing {
131131
struct StateData {
132132
/// Span of the top level expression
133133
span: Span,
134-
/// The required mutability
135-
target_mut: Mutability,
136134
}
137135

138136
enum State {
@@ -141,9 +139,13 @@ enum State {
141139
// The number of calls in a sequence which changed the referenced type
142140
ty_changed_count: usize,
143141
is_final_ufcs: bool,
142+
/// The required mutability
143+
target_mut: Mutability,
144144
},
145145
DerefedBorrow {
146-
count: u32,
146+
count: usize,
147+
required_precedence: i8,
148+
msg: &'static str,
147149
},
148150
}
149151

@@ -214,59 +216,98 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
214216
1
215217
},
216218
is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
217-
},
218-
StateData {
219-
span: expr.span,
220219
target_mut,
221220
},
221+
StateData { span: expr.span },
222222
));
223223
},
224224
RefOp::AddrOf => {
225225
// Find the number of times the borrow is auto-derefed.
226226
let mut iter = find_adjustments(cx.tcx, typeck, expr).iter();
227-
if let Some((i, adjust)) = iter.by_ref().enumerate().find_map(|(i, adjust)| {
228-
if !matches!(adjust.kind, Adjust::Deref(_)) {
229-
Some((i, adjust))
230-
} else if !adjust.target.is_ref() {
231-
// Add one to the number of references found.
232-
Some((i + 1, adjust))
227+
let mut deref_count = 0usize;
228+
let next_adjust = loop {
229+
match iter.next() {
230+
Some(adjust) => {
231+
if !matches!(adjust.kind, Adjust::Deref(_)) {
232+
break Some(adjust);
233+
} else if !adjust.target.is_ref() {
234+
deref_count += 1;
235+
break iter.next();
236+
}
237+
deref_count += 1;
238+
},
239+
None => break None,
240+
};
241+
};
242+
243+
// Determine the required number of references before any can be removed. In all cases the
244+
// reference made by the current expression will be removed. After that there are four cases to
245+
// handle.
246+
//
247+
// 1. Auto-borrow will trigger in the current position, so no further references are required.
248+
// 2. Auto-deref ends at a reference, or the underlying type, so one extra needs to be left to
249+
// handle the automatically inserted re-borrow.
250+
// 3. Auto-deref hits a user-defined `Deref` impl, so at least one reference needs to exist to
251+
// start auto-deref.
252+
// 4. If the chain of non-user-defined derefs ends with a mutable re-borrow, and re-borrow
253+
// adjustments will not be inserted automatically, then leave one further reference to avoid
254+
// moving a mutable borrow.
255+
// e.g.
256+
// fn foo<T>(x: &mut Option<&mut T>, y: &mut T) {
257+
// let x = match x {
258+
// // Removing the borrow will cause `x` to be moved
259+
// Some(x) => &mut *x,
260+
// None => y
261+
// };
262+
// }
263+
let deref_msg =
264+
"this expression creates a reference which is immediately dereferenced by the compiler";
265+
let borrow_msg = "this expression borrows a value the compiler would automatically borrow";
266+
267+
let (required_refs, required_precedence, msg) = if is_auto_borrow_position(parent, expr.hir_id)
268+
{
269+
(1, PREC_POSTFIX, if deref_count == 1 { borrow_msg } else { deref_msg })
270+
} else if let Some(&Adjust::Borrow(AutoBorrow::Ref(_, mutability))) =
271+
next_adjust.map(|a| &a.kind)
272+
{
273+
if matches!(mutability, AutoBorrowMutability::Mut { .. })
274+
&& !is_auto_reborrow_position(parent)
275+
{
276+
(3, 0, deref_msg)
233277
} else {
234-
None
235-
}
236-
}) {
237-
// Found two consecutive derefs. At least one can be removed.
238-
if i > 1 {
239-
let target_mut = iter::once(adjust)
240-
.chain(iter)
241-
.find_map(|adjust| match adjust.kind {
242-
Adjust::Borrow(AutoBorrow::Ref(_, m)) => Some(m.into()),
243-
_ => None,
244-
})
245-
// This default should never happen. Auto-deref always reborrows.
246-
.unwrap_or(Mutability::Not);
247-
self.state = Some((
248-
// Subtract one for the current borrow expression, and one to cover the last
249-
// reference which can't be removed (it's either reborrowed, or needed for
250-
// auto-deref to happen).
251-
State::DerefedBorrow {
252-
count:
253-
// Truncation here would require more than a `u32::MAX` level reference. The compiler
254-
// does not support this.
255-
#[allow(clippy::cast_possible_truncation)]
256-
{ i as u32 - 2 }
257-
},
258-
StateData {
259-
span: expr.span,
260-
target_mut,
261-
},
262-
));
278+
(2, 0, deref_msg)
263279
}
280+
} else {
281+
(2, 0, deref_msg)
282+
};
283+
284+
if deref_count >= required_refs {
285+
self.state = Some((
286+
State::DerefedBorrow {
287+
// One of the required refs is for the current borrow expression, the remaining ones
288+
// can't be removed without breaking the code. See earlier comment.
289+
count: deref_count - required_refs,
290+
required_precedence,
291+
msg,
292+
},
293+
StateData { span: expr.span },
294+
));
264295
}
265296
},
266297
_ => (),
267298
}
268299
},
269-
(Some((State::DerefMethod { ty_changed_count, .. }, data)), RefOp::Method(_)) => {
300+
(
301+
Some((
302+
State::DerefMethod {
303+
target_mut,
304+
ty_changed_count,
305+
..
306+
},
307+
data,
308+
)),
309+
RefOp::Method(_),
310+
) => {
270311
self.state = Some((
271312
State::DerefMethod {
272313
ty_changed_count: if deref_method_same_type(typeck.expr_ty(expr), typeck.expr_ty(sub_expr)) {
@@ -275,12 +316,30 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
275316
ty_changed_count + 1
276317
},
277318
is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
319+
target_mut,
278320
},
279321
data,
280322
));
281323
},
282-
(Some((State::DerefedBorrow { count }, data)), RefOp::AddrOf) if count != 0 => {
283-
self.state = Some((State::DerefedBorrow { count: count - 1 }, data));
324+
(
325+
Some((
326+
State::DerefedBorrow {
327+
count,
328+
required_precedence,
329+
msg,
330+
},
331+
data,
332+
)),
333+
RefOp::AddrOf,
334+
) if count != 0 => {
335+
self.state = Some((
336+
State::DerefedBorrow {
337+
count: count - 1,
338+
required_precedence,
339+
msg,
340+
},
341+
data,
342+
));
284343
},
285344

286345
(Some((state, data)), _) => report(cx, expr, state, data),
@@ -455,6 +514,30 @@ fn is_linted_explicit_deref_position(parent: Option<Node<'_>>, child_id: HirId,
455514
}
456515
}
457516

517+
/// Checks if the given expression is in a position which can be auto-reborrowed.
518+
/// Note: This is only correct assuming auto-deref is already occurring.
519+
fn is_auto_reborrow_position(parent: Option<Node<'_>>) -> bool {
520+
match parent {
521+
Some(Node::Expr(parent)) => matches!(parent.kind, ExprKind::MethodCall(..) | ExprKind::Call(..)),
522+
Some(Node::Local(_)) => true,
523+
_ => false,
524+
}
525+
}
526+
527+
/// Checks if the given expression is a position which can auto-borrow.
528+
fn is_auto_borrow_position(parent: Option<Node<'_>>, child_id: HirId) -> bool {
529+
if let Some(Node::Expr(parent)) = parent {
530+
match parent.kind {
531+
ExprKind::MethodCall(_, [self_arg, ..], _) => self_arg.hir_id == child_id,
532+
ExprKind::Field(..) => true,
533+
ExprKind::Call(f, _) => f.hir_id == child_id,
534+
_ => false,
535+
}
536+
} else {
537+
false
538+
}
539+
}
540+
458541
/// Adjustments are sometimes made in the parent block rather than the expression itself.
459542
fn find_adjustments<'tcx>(
460543
tcx: TyCtxt<'tcx>,
@@ -503,6 +586,7 @@ fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData)
503586
State::DerefMethod {
504587
ty_changed_count,
505588
is_final_ufcs,
589+
target_mut,
506590
} => {
507591
let mut app = Applicability::MachineApplicable;
508592
let (expr_str, expr_is_macro_call) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
@@ -517,12 +601,12 @@ fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData)
517601
};
518602
let addr_of_str = if ty_changed_count < ref_count {
519603
// Check if a reborrow from &mut T -> &T is required.
520-
if data.target_mut == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
604+
if target_mut == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
521605
"&*"
522606
} else {
523607
""
524608
}
525-
} else if data.target_mut == Mutability::Mut {
609+
} else if target_mut == Mutability::Mut {
526610
"&mut "
527611
} else {
528612
"&"
@@ -538,7 +622,7 @@ fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData)
538622
cx,
539623
EXPLICIT_DEREF_METHODS,
540624
data.span,
541-
match data.target_mut {
625+
match target_mut {
542626
Mutability::Not => "explicit `deref` method call",
543627
Mutability::Mut => "explicit `deref_mut` method call",
544628
},
@@ -547,19 +631,24 @@ fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData)
547631
app,
548632
);
549633
},
550-
State::DerefedBorrow { .. } => {
634+
State::DerefedBorrow {
635+
required_precedence,
636+
msg,
637+
..
638+
} => {
551639
let mut app = Applicability::MachineApplicable;
552640
let snip = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app).0;
553641
span_lint_and_sugg(
554642
cx,
555643
NEEDLESS_BORROW,
556644
data.span,
557-
&format!(
558-
"this expression borrows a reference (`{}`) that is immediately dereferenced by the compiler",
559-
cx.typeck_results().expr_ty(expr),
560-
),
645+
msg,
561646
"change this to",
562-
snip.into(),
647+
if required_precedence > expr.precedence().order() && !has_enclosing_paren(&snip) {
648+
format!("({})", snip)
649+
} else {
650+
snip.into()
651+
},
563652
app,
564653
);
565654
},

0 commit comments

Comments
 (0)