Skip to content

Commit 7a2cabb

Browse files
committed
Auto merge of #93001 - flip1995:clippyup, r=Manishearth
Out of cycle Clippy update I want to do an out-of-cycle sync for #8295, and possibly backport this to stable together with rust-lang/rust#92938. If this doesn't get backported to stable, then I at least want to backport it to beta. r? `@Manishearth`
2 parents 8f48116 + ddad101 commit 7a2cabb

Some content is hidden

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

43 files changed

+754
-100
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -3049,6 +3049,7 @@ Released 2018-09-13
30493049
[`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator
30503050
[`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth
30513051
[`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero
3052+
[`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned
30523053
[`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
30533054
[`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero
30543055
[`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits

COPYRIGHT

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright 2014-2021 The Rust Project Developers
1+
Copyright 2014-2022 The Rust Project Developers
22

33
Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
44
http://www.apache.org/licenses/LICENSE-2.0> or the MIT license

LICENSE-APACHE

+1-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work.
186186
same "printed page" as the copyright notice for easier
187187
identification within third-party archives.
188188

189-
Copyright 2014-2021 The Rust Project Developers
189+
Copyright 2014-2022 The Rust Project Developers
190190

191191
Licensed under the Apache License, Version 2.0 (the "License");
192192
you may not use this file except in compliance with the License.

LICENSE-MIT

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2014-2021 The Rust Project Developers
3+
Copyright (c) 2014-2022 The Rust Project Developers
44

55
Permission is hereby granted, free of charge, to any
66
person obtaining a copy of this software and associated

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT
238238

239239
## License
240240

241-
Copyright 2014-2021 The Rust Project Developers
241+
Copyright 2014-2022 The Rust Project Developers
242242

243243
Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
244244
[https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license

clippy_lints/src/bit_mask.rs

+12-12
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ declare_clippy_lint! {
1818
/// {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following
1919
/// table:
2020
///
21-
/// |Comparison |Bit Op|Example |is always|Formula |
22-
/// |------------|------|------------|---------|----------------------|
23-
/// |`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` |
24-
/// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` |
25-
/// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` |
26-
/// |`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` |
27-
/// |`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` |
28-
/// |`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` |
21+
/// |Comparison |Bit Op|Example |is always|Formula |
22+
/// |------------|------|-------------|---------|----------------------|
23+
/// |`==` or `!=`| `&` |`x & 2 == 3` |`false` |`c & m != c` |
24+
/// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` |
25+
/// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` |
26+
/// |`==` or `!=`| `\|` |`x \| 1 == 0`|`false` |`c \| m != c` |
27+
/// |`<` or `>=`| `\|` |`x \| 1 < 1` |`false` |`m >= c` |
28+
/// |`<=` or `>` | `\|` |`x \| 1 > 0` |`true` |`m > c` |
2929
///
3030
/// ### Why is this bad?
3131
/// If the bits that the comparison cares about are always
@@ -53,10 +53,10 @@ declare_clippy_lint! {
5353
/// without changing the outcome. The basic structure can be seen in the
5454
/// following table:
5555
///
56-
/// |Comparison| Bit Op |Example |equals |
57-
/// |----------|---------|-----------|-------|
58-
/// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`|
59-
/// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`|
56+
/// |Comparison| Bit Op |Example |equals |
57+
/// |----------|----------|------------|-------|
58+
/// |`>` / `<=`|`\|` / `^`|`x \| 2 > 3`|`x > 3`|
59+
/// |`<` / `>=`|`\|` / `^`|`x ^ 1 < 4` |`x < 4`|
6060
///
6161
/// ### Why is this bad?
6262
/// Not equally evil as [`bad_bit_mask`](#bad_bit_mask),

clippy_lints/src/copies.rs

+17-12
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ impl<'tcx> LateLintPass<'tcx> for CopyAndPaste {
183183
lint_same_cond(cx, &conds);
184184
lint_same_fns_in_if_cond(cx, &conds);
185185
// Block duplication
186-
lint_same_then_else(cx, &blocks, conds.len() == blocks.len(), expr);
186+
lint_same_then_else(cx, &conds, &blocks, conds.len() == blocks.len(), expr);
187187
}
188188
}
189189
}
@@ -192,6 +192,7 @@ impl<'tcx> LateLintPass<'tcx> for CopyAndPaste {
192192
/// Implementation of `BRANCHES_SHARING_CODE` and `IF_SAME_THEN_ELSE` if the blocks are equal.
193193
fn lint_same_then_else<'tcx>(
194194
cx: &LateContext<'tcx>,
195+
conds: &[&'tcx Expr<'_>],
195196
blocks: &[&Block<'tcx>],
196197
has_conditional_else: bool,
197198
expr: &'tcx Expr<'_>,
@@ -204,7 +205,7 @@ fn lint_same_then_else<'tcx>(
204205
// Check if each block has shared code
205206
let has_expr = blocks[0].expr.is_some();
206207

207-
let (start_eq, mut end_eq, expr_eq) = if let Some(block_eq) = scan_block_for_eq(cx, blocks) {
208+
let (start_eq, mut end_eq, expr_eq) = if let Some(block_eq) = scan_block_for_eq(cx, conds, blocks) {
208209
(block_eq.start_eq, block_eq.end_eq, block_eq.expr_eq)
209210
} else {
210211
return;
@@ -316,14 +317,14 @@ struct BlockEqual {
316317

317318
/// This function can also trigger the `IF_SAME_THEN_ELSE` in which case it'll return `None` to
318319
/// abort any further processing and avoid duplicate lint triggers.
319-
fn scan_block_for_eq(cx: &LateContext<'_>, blocks: &[&Block<'_>]) -> Option<BlockEqual> {
320+
fn scan_block_for_eq(cx: &LateContext<'_>, conds: &[&Expr<'_>], blocks: &[&Block<'_>]) -> Option<BlockEqual> {
320321
let mut start_eq = usize::MAX;
321322
let mut end_eq = usize::MAX;
322323
let mut expr_eq = true;
323-
let mut iter = blocks.windows(2);
324-
while let Some(&[win0, win1]) = iter.next() {
325-
let l_stmts = win0.stmts;
326-
let r_stmts = win1.stmts;
324+
let mut iter = blocks.windows(2).enumerate();
325+
while let Some((i, &[block0, block1])) = iter.next() {
326+
let l_stmts = block0.stmts;
327+
let r_stmts = block1.stmts;
327328

328329
// `SpanlessEq` now keeps track of the locals and is therefore context sensitive clippy#6752.
329330
// The comparison therefore needs to be done in a way that builds the correct context.
@@ -340,22 +341,26 @@ fn scan_block_for_eq(cx: &LateContext<'_>, blocks: &[&Block<'_>]) -> Option<Bloc
340341
it1.zip(it2)
341342
.fold(0, |acc, (l, r)| if evaluator.eq_stmt(l, r) { acc + 1 } else { 0 })
342343
};
343-
let block_expr_eq = both(&win0.expr, &win1.expr, |l, r| evaluator.eq_expr(l, r));
344+
let block_expr_eq = both(&block0.expr, &block1.expr, |l, r| evaluator.eq_expr(l, r));
344345

345346
// IF_SAME_THEN_ELSE
346347
if_chain! {
347348
if block_expr_eq;
348349
if l_stmts.len() == r_stmts.len();
349350
if l_stmts.len() == current_start_eq;
350-
if !is_lint_allowed(cx, IF_SAME_THEN_ELSE, win0.hir_id);
351-
if !is_lint_allowed(cx, IF_SAME_THEN_ELSE, win1.hir_id);
351+
// `conds` may have one last item than `blocks`.
352+
// Any `i` from `blocks.windows(2)` will exist in `conds`, but `i+1` may not exist on the last iteration.
353+
if !matches!(conds[i].kind, ExprKind::Let(..));
354+
if !matches!(conds.get(i + 1).map(|e| &e.kind), Some(ExprKind::Let(..)));
355+
if !is_lint_allowed(cx, IF_SAME_THEN_ELSE, block0.hir_id);
356+
if !is_lint_allowed(cx, IF_SAME_THEN_ELSE, block1.hir_id);
352357
then {
353358
span_lint_and_note(
354359
cx,
355360
IF_SAME_THEN_ELSE,
356-
win0.span,
361+
block0.span,
357362
"this `if` has identical blocks",
358-
Some(win1.span),
363+
Some(block1.span),
359364
"same as this",
360365
);
361366

clippy_lints/src/format.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_lint::{LateContext, LateLintPass};
99
use rustc_middle::ty;
1010
use rustc_session::{declare_lint_pass, declare_tool_lint};
1111
use rustc_span::symbol::kw;
12-
use rustc_span::{sym, Span};
12+
use rustc_span::{sym, BytePos, Span};
1313

1414
declare_clippy_lint! {
1515
/// ### What it does
@@ -84,7 +84,22 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
8484
ExprKind::MethodCall(path, ..) => path.ident.name.as_str() == "to_string",
8585
_ => false,
8686
};
87-
let sugg = if is_new_string {
87+
let sugg = if format_args.format_string_span.contains(value.span) {
88+
// Implicit argument. e.g. `format!("{x}")` span points to `{x}`
89+
let spdata = value.span.data();
90+
let span = Span::new(
91+
spdata.lo + BytePos(1),
92+
spdata.hi - BytePos(1),
93+
spdata.ctxt,
94+
spdata.parent
95+
);
96+
let snip = snippet_with_applicability(cx, span, "..", &mut applicability);
97+
if is_new_string {
98+
snip.into()
99+
} else {
100+
format!("{snip}.to_string()")
101+
}
102+
} else if is_new_string {
88103
snippet_with_applicability(cx, value.span, "..", &mut applicability).into_owned()
89104
} else {
90105
let sugg = Sugg::hir_with_applicability(cx, value, "<arg>", &mut applicability);

clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ fn check_raw_ptr<'tcx>(
4242
let expr = &body.value;
4343
if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(def_id) {
4444
let raw_ptrs = iter_input_pats(decl, body)
45-
.zip(decl.inputs.iter())
46-
.filter_map(|(arg, ty)| raw_ptr_arg(arg, ty))
45+
.filter_map(|arg| raw_ptr_arg(cx, arg))
4746
.collect::<HirIdSet>();
4847

4948
if !raw_ptrs.is_empty() {
@@ -59,8 +58,12 @@ fn check_raw_ptr<'tcx>(
5958
}
6059
}
6160

62-
fn raw_ptr_arg(arg: &hir::Param<'_>, ty: &hir::Ty<'_>) -> Option<hir::HirId> {
63-
if let (&hir::PatKind::Binding(_, id, _, _), &hir::TyKind::Ptr(_)) = (&arg.pat.kind, &ty.kind) {
61+
fn raw_ptr_arg(cx: &LateContext<'_>, arg: &hir::Param<'_>) -> Option<hir::HirId> {
62+
if let (&hir::PatKind::Binding(_, id, _, _), Some(&ty::RawPtr(_))) = (
63+
&arg.pat.kind,
64+
cx.maybe_typeck_results()
65+
.map(|typeck_results| typeck_results.pat_ty(arg.pat).kind()),
66+
) {
6467
Some(id)
6568
} else {
6669
None

clippy_lints/src/iter_not_returning_iterator.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator {
6666

6767
fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) {
6868
if sig.decl.implicit_self.has_implicit_self() {
69-
let ret_ty = cx.tcx.fn_sig(fn_id).skip_binder().output();
69+
let ret_ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(fn_id).output());
7070
let ret_ty = cx
7171
.tcx
7272
.try_normalize_erasing_regions(cx.param_env, ret_ty)

clippy_lints/src/lib.register_all.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
156156
LintId::of(methods::ITER_NEXT_SLICE),
157157
LintId::of(methods::ITER_NTH),
158158
LintId::of(methods::ITER_NTH_ZERO),
159+
LintId::of(methods::ITER_OVEREAGER_CLONED),
159160
LintId::of(methods::ITER_SKIP_NEXT),
160161
LintId::of(methods::MANUAL_FILTER_MAP),
161162
LintId::of(methods::MANUAL_FIND_MAP),
@@ -249,7 +250,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
249250
LintId::of(reference::REF_IN_DEREF),
250251
LintId::of(regex::INVALID_REGEX),
251252
LintId::of(repeat_once::REPEAT_ONCE),
252-
LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
253253
LintId::of(returns::LET_AND_RETURN),
254254
LintId::of(returns::NEEDLESS_RETURN),
255255
LintId::of(self_assignment::SELF_ASSIGNMENT),

clippy_lints/src/lib.register_lints.rs

+1
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ store.register_lints(&[
288288
methods::ITER_NEXT_SLICE,
289289
methods::ITER_NTH,
290290
methods::ITER_NTH_ZERO,
291+
methods::ITER_OVEREAGER_CLONED,
291292
methods::ITER_SKIP_NEXT,
292293
methods::MANUAL_FILTER_MAP,
293294
methods::MANUAL_FIND_MAP,

clippy_lints/src/lib.register_pedantic.rs

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
8181
LintId::of(ranges::RANGE_PLUS_ONE),
8282
LintId::of(redundant_else::REDUNDANT_ELSE),
8383
LintId::of(ref_option_ref::REF_OPTION_REF),
84+
LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
8485
LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
8586
LintId::of(strings::STRING_ADD_ASSIGN),
8687
LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),

clippy_lints/src/lib.register_perf.rs

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
1414
LintId::of(methods::EXPECT_FUN_CALL),
1515
LintId::of(methods::EXTEND_WITH_DRAIN),
1616
LintId::of(methods::ITER_NTH),
17+
LintId::of(methods::ITER_OVEREAGER_CLONED),
1718
LintId::of(methods::MANUAL_STR_REPEAT),
1819
LintId::of(methods::OR_FUN_CALL),
1920
LintId::of(methods::SINGLE_CHAR_PATTERN),

clippy_lints/src/lib.register_suspicious.rs

-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
1616
LintId::of(methods::SUSPICIOUS_MAP),
1717
LintId::of(mut_key::MUTABLE_KEY_TYPE),
1818
LintId::of(octal_escapes::OCTAL_ESCAPES),
19-
LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
2019
LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
2120
LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
2221
])

clippy_lints/src/methods/implicit_clone.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,40 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::source::snippet_with_context;
3+
use clippy_utils::ty::peel_mid_ty_refs;
24
use clippy_utils::{is_diag_item_method, is_diag_trait_item};
35
use if_chain::if_chain;
46
use rustc_errors::Applicability;
57
use rustc_hir as hir;
68
use rustc_lint::LateContext;
79
use rustc_middle::ty::TyS;
8-
use rustc_span::{sym, Span};
10+
use rustc_span::sym;
911

1012
use super::IMPLICIT_CLONE;
1113

12-
pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, span: Span) {
14+
pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
1315
if_chain! {
1416
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
1517
if is_clone_like(cx, method_name, method_def_id);
1618
let return_type = cx.typeck_results().expr_ty(expr);
17-
let input_type = cx.typeck_results().expr_ty(recv).peel_refs();
19+
let input_type = cx.typeck_results().expr_ty(recv);
20+
let (input_type, ref_count) = peel_mid_ty_refs(input_type);
1821
if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did));
1922
if TyS::same_type(return_type, input_type);
2023
then {
24+
let mut app = Applicability::MachineApplicable;
25+
let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0;
2126
span_lint_and_sugg(
2227
cx,
2328
IMPLICIT_CLONE,
24-
span,
29+
expr.span,
2530
&format!("implicitly cloning a `{}` by calling `{}` on its dereferenced type", ty_name, method_name),
2631
"consider using",
27-
"clone".to_string(),
28-
Applicability::MachineApplicable
32+
if ref_count > 1 {
33+
format!("({}{}).clone()", "*".repeat(ref_count - 1), recv_snip)
34+
} else {
35+
format!("{}.clone()", recv_snip)
36+
},
37+
app,
2938
);
3039
}
3140
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::source::snippet;
3+
use clippy_utils::ty::{get_iterator_item_ty, is_copy};
4+
use itertools::Itertools;
5+
use rustc_errors::Applicability;
6+
use rustc_hir as hir;
7+
use rustc_lint::LateContext;
8+
use rustc_middle::ty;
9+
use std::ops::Not;
10+
11+
use super::ITER_OVEREAGER_CLONED;
12+
use crate::redundant_clone::REDUNDANT_CLONE;
13+
14+
/// lint overeager use of `cloned()` for `Iterator`s
15+
pub(super) fn check<'tcx>(
16+
cx: &LateContext<'tcx>,
17+
expr: &'tcx hir::Expr<'_>,
18+
recv: &'tcx hir::Expr<'_>,
19+
name: &str,
20+
map_arg: &[hir::Expr<'_>],
21+
) {
22+
// Check if it's iterator and get type associated with `Item`.
23+
let inner_ty = match get_iterator_item_ty(cx, cx.typeck_results().expr_ty_adjusted(recv)) {
24+
Some(ty) => ty,
25+
_ => return,
26+
};
27+
28+
match inner_ty.kind() {
29+
ty::Ref(_, ty, _) if !is_copy(cx, ty) => {},
30+
_ => return,
31+
};
32+
33+
let (lint, preserve_cloned) = match name {
34+
"count" => (REDUNDANT_CLONE, false),
35+
_ => (ITER_OVEREAGER_CLONED, true),
36+
};
37+
let wildcard_params = map_arg.is_empty().not().then(|| "...").unwrap_or_default();
38+
let msg = format!(
39+
"called `cloned().{}({})` on an `Iterator`. It may be more efficient to call `{}({}){}` instead",
40+
name,
41+
wildcard_params,
42+
name,
43+
wildcard_params,
44+
preserve_cloned.then(|| ".cloned()").unwrap_or_default(),
45+
);
46+
47+
span_lint_and_sugg(
48+
cx,
49+
lint,
50+
expr.span,
51+
&msg,
52+
"try this",
53+
format!(
54+
"{}.{}({}){}",
55+
snippet(cx, recv.span, ".."),
56+
name,
57+
map_arg.iter().map(|a| snippet(cx, a.span, "..")).join(", "),
58+
preserve_cloned.then(|| ".cloned()").unwrap_or_default(),
59+
),
60+
Applicability::MachineApplicable,
61+
);
62+
}

0 commit comments

Comments
 (0)