Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Clippy #106259

Merged
merged 56 commits into from
Dec 29, 2022
Merged
Changes from 7 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
055f349
Avoid `match_wildcard_for_single_variants` on guarded wild matches
koka831 Dec 10, 2022
3b6bbf7
Fix match_single_binding suggestion introduced an extra semicolon
alex-semenyuk Nov 7, 2022
5b3a666
fix manual_filter false positive
ericwu17 Dec 16, 2022
3c14075
manual_filter: add a related test
ericwu17 Dec 16, 2022
033f1ec
Add 2018/2021 edition tests for wildcard_imports
chansuke Dec 12, 2022
1c42252
Merge commit '4bdfb0741dbcecd5279a2635c3280726db0604b5' into clippyup
flip1995 Dec 17, 2022
af39a8a
Identify more cases of useless `into_iter()` calls
samueltardieu Dec 1, 2022
6afe547
Add lint `transmute_null_to_fn`
Niki4tap Dec 17, 2022
3cc67d0
Relax clippy_utils::consts::miri_to_const pointer type restrictiveness
Niki4tap Dec 17, 2022
42106e0
Add lint `fn_null_check`
Niki4tap Dec 17, 2022
54a9168
Remove useless pattern matching
Niki4tap Dec 17, 2022
dae54fa
Doc codeblock fixup
Niki4tap Dec 18, 2022
ebb0759
Add a test for regular wildcard
koka831 Dec 11, 2022
b1ca307
Address some of the code style issues
Niki4tap Dec 18, 2022
910a97d
Auto merge of #10020 - samueltardieu:more-into-iter-removal, r=xFrednet
bors Dec 18, 2022
9b2fc8e
Make clippy happy
Niki4tap Dec 18, 2022
20f501a
Improve code style further
Niki4tap Dec 18, 2022
cc98574
Fix comments, use `constant` instead of raw `constant_context`
Niki4tap Dec 18, 2022
62061b8
Move manual_clamp to nursery
flip1995 Dec 19, 2022
8a6aca3
Auto merge of #10101 - flip1995:manual_clamp_nursery, r=xFrednet
bors Dec 19, 2022
691df70
Inline some `const`s
Niki4tap Dec 19, 2022
b3145fe
Auto merge of #10099 - Niki4tap:null_fn_lints, r=llogiq
bors Dec 19, 2022
d0ac6ba
Fix overflow ICE in large_stack/const_arrays
Niki4tap Dec 19, 2022
30e6e85
add [`permissions_set_readonly_false`] #9702
Oct 28, 2022
e1d3c1e
refactor: fix style
chansuke Dec 17, 2022
09cfcaf
Auto merge of #10103 - Niki4tap:overflow_ice, r=flip1995
bors Dec 19, 2022
2444494
Make Clippy test no longer unsound
compiler-errors Dec 16, 2022
1e68973
Auto merge of #10067 - chansuke:issue-7943, r=giraffate
bors Dec 20, 2022
cd3d38a
Use `rustc_mir_dataflow::impls::MaybeStorageLive`
smoelius Oct 11, 2022
c6477eb
Add tests
smoelius Oct 12, 2022
ed519ad
Improve `possible_borrower`
smoelius Oct 12, 2022
26df551
Fix adjacent code
smoelius Oct 12, 2022
c7dc961
Address review comments
smoelius Dec 13, 2022
4dbd8ad
Address https://github.com/rust-lang/rust/pull/105659
smoelius Dec 20, 2022
b21cc36
hotfix: add help dialog for `PermissionExt`
chansuke Dec 17, 2022
4a09068
Auto merge of #10063 - chansuke:issue-9702, r=Alexendoo
bors Dec 20, 2022
065c6f7
Auto merge of #10091 - EricWu2003:manual-filter-FP, r=llogiq
bors Dec 21, 2022
b6882f6
Fix FP in needless_return when using yeet
Niki4tap Dec 22, 2022
f0d331a
Auto merge of #10109 - Niki4tap:yeet_not_return, r=flip1995
bors Dec 22, 2022
8a6e6fd
Auto merge of #10056 - koka831:fix/9993, r=Jarcho
bors Dec 22, 2022
4fe3727
Auto merge of #9701 - smoelius:improve-possible-borrower, r=Jarcho
bors Dec 22, 2022
faebca3
Changelog fix
alex-semenyuk Dec 23, 2022
e2a687d
Auto merge of #10111 - alex-semenyuk:changelog_fix, r=flip1995
bors Dec 23, 2022
d7b9e19
Add size_of_ref lint
lukaslueg Dec 17, 2022
e8703a0
Auto merge of #10098 - lukaslueg:size_of_ref, r=Jarcho
bors Dec 24, 2022
12f2dea
`not_unsafe_ptr_arg_deref` update documentation
tgross35 Dec 25, 2022
4f1bae0
Auto merge of #10116 - tgross35:patch-1, r=llogiq
bors Dec 25, 2022
fae19a9
Place default values near its definitions
koka831 Dec 25, 2022
6bb6dd6
fix incorrect suggestion in `suboptimal_flops`
ericwu17 Dec 23, 2022
d98e714
Auto merge of #10113 - EricWu2003:suboptimal_flops_incorrect_suggesti…
bors Dec 26, 2022
266eef7
Auto merge of #10119 - koka831:doc/config-default-value, r=xFrednet
bors Dec 28, 2022
22af8fe
Auto merge of #10060 - alex-semenyuk:match_single_binding_fix, r=llogiq
bors Dec 29, 2022
0853540
Merge remote-tracking branch 'upstream/master' into rustup
flip1995 Dec 29, 2022
1f97186
Bump nightly version -> 2022-12-29
flip1995 Dec 29, 2022
4f3ab69
Auto merge of #10126 - flip1995:rustup, r=flip1995
bors Dec 29, 2022
56ab392
Merge commit '4f3ab69ea0a0908260944443c739426cc384ae1a' into clippyup
flip1995 Dec 29, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clippy_lints/src/casts/cast_slice_different_sizes.rs
Original file line number Diff line number Diff line change
@@ -54,7 +54,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv

diag.span_suggestion(
expr.span,
&format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"),
format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"),
sugg,
rustc_errors::Applicability::HasPlaceholders,
);
8 changes: 4 additions & 4 deletions clippy_lints/src/dereference.rs
Original file line number Diff line number Diff line change
@@ -1282,10 +1282,10 @@ fn referent_used_exactly_once<'tcx>(
possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir)));
}
let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1;
// If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is
// that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of
// itself. See the comment in that method for an explanation as to why.
possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location)
// If `place.local` were not included here, the `copyable_iterator::warn` test would fail. The
// reason is that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible
// borrower of itself. See the comment in that method for an explanation as to why.
possible_borrower.at_most_borrowers(cx, &[local, place.local], place.local, location)
&& used_exactly_once(mir, place.local).unwrap_or(false)
} else {
false
2 changes: 1 addition & 1 deletion clippy_lints/src/format_args.rs
Original file line number Diff line number Diff line change
@@ -377,7 +377,7 @@ fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symb
call_site,
&format!("`format!` in `{name}!` args"),
|diag| {
diag.help(&format!(
diag.help(format!(
"combine the `format!(..)` arguments with the outer `{name}!(..)` call"
));
diag.help("or consider changing `format!` to `format_args!`");
2 changes: 1 addition & 1 deletion clippy_lints/src/large_enum_variant.rs
Original file line number Diff line number Diff line change
@@ -111,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
);
diag.span_label(
def.variants[variants_size[1].ind].span,
&if variants_size[1].fields_size.is_empty() {
if variants_size[1].fields_size.is_empty() {
"the second-largest variant carries no data at all".to_owned()
} else {
format!(
2 changes: 1 addition & 1 deletion clippy_lints/src/len_zero.rs
Original file line number Diff line number Diff line change
@@ -361,7 +361,7 @@ fn check_for_is_empty<'tcx>(
db.span_note(span, "`is_empty` defined here");
}
if let Some(self_kind) = self_kind {
db.note(&output.expected_sig(self_kind));
db.note(output.expected_sig(self_kind));
}
});
}
2 changes: 1 addition & 1 deletion clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
@@ -336,7 +336,7 @@ pub fn read_conf(sess: &Session, path: &io::Result<Option<PathBuf>>) -> Conf {
Ok(Some(path)) => path,
Ok(None) => return Conf::default(),
Err(error) => {
sess.struct_err(&format!("error finding Clippy's configuration file: {error}"))
sess.struct_err(format!("error finding Clippy's configuration file: {error}"))
.emit();
return Conf::default();
},
2 changes: 1 addition & 1 deletion clippy_lints/src/loops/explicit_counter_loop.rs
Original file line number Diff line number Diff line change
@@ -77,7 +77,7 @@ pub(super) fn check<'tcx>(
applicability,
);

diag.note(&format!(
diag.note(format!(
"`{name}` is of type `{int_name}`, making it ineligible for `Iterator::enumerate`"
));
},
2 changes: 1 addition & 1 deletion clippy_lints/src/manual_async_fn.rs
Original file line number Diff line number Diff line change
@@ -76,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
let help = format!("make the function `async` and {ret_sugg}");
diag.span_suggestion(
header_span,
&help,
help,
format!("async {}{ret_snip}", &header_snip[..ret_pos]),
Applicability::MachineApplicable
);
2 changes: 1 addition & 1 deletion clippy_lints/src/manual_strip.rs
Original file line number Diff line number Diff line change
@@ -109,7 +109,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {

let test_span = expr.span.until(then.span);
span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {kind_word} manually"), |diag| {
diag.span_note(test_span, &format!("the {kind_word} was tested here"));
diag.span_note(test_span, format!("the {kind_word} was tested here"));
multispan_sugg(
diag,
&format!("try using the `strip_{kind_word}` method"),
2 changes: 1 addition & 1 deletion clippy_lints/src/methods/inefficient_to_string.rs
Original file line number Diff line number Diff line change
@@ -36,7 +36,7 @@ pub fn check(
expr.span,
&format!("calling `to_string` on `{arg_ty}`"),
|diag| {
diag.help(&format!(
diag.help(format!(
"`{self_ty}` implements `ToString` through a slower blanket impl, but `{deref_self_ty}` has a fast specialization of `ToString`"
));
let mut applicability = Applicability::MachineApplicable;
2 changes: 1 addition & 1 deletion clippy_lints/src/methods/iter_skip_next.rs
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
application = Applicability::Unspecified;
diag.span_help(
pat.span,
&format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")),
format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")),
);
}
}
2 changes: 1 addition & 1 deletion clippy_lints/src/methods/option_map_unwrap_or.rs
Original file line number Diff line number Diff line change
@@ -84,7 +84,7 @@ pub(super) fn check<'tcx>(
suggestion.push((map_arg_span.with_hi(map_arg_span.lo()), format!("{unwrap_snippet}, ")));
}

diag.multipart_suggestion(&format!("use `{suggest}` instead"), suggestion, applicability);
diag.multipart_suggestion(format!("use `{suggest}` instead"), suggestion, applicability);
});
}
}
2 changes: 1 addition & 1 deletion clippy_lints/src/methods/str_splitn.rs
Original file line number Diff line number Diff line change
@@ -167,7 +167,7 @@ fn check_manual_split_once_indirect(
};
diag.span_suggestion_verbose(
local.span,
&format!("try `{r}split_once`"),
format!("try `{r}split_once`"),
format!("let ({lhs}, {rhs}) = {self_snip}.{r}split_once({pat_snip}){unwrap};"),
app,
);
2 changes: 1 addition & 1 deletion clippy_lints/src/methods/unnecessary_lazy_eval.rs
Original file line number Diff line number Diff line change
@@ -62,7 +62,7 @@ pub(super) fn check<'tcx>(
span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| {
diag.span_suggestion(
span,
&format!("use `{simplify_using}(..)` instead"),
format!("use `{simplify_using}(..)` instead"),
format!("{simplify_using}({})", snippet(cx, body_expr.span, "..")),
applicability,
);
6 changes: 3 additions & 3 deletions clippy_lints/src/needless_late_init.rs
Original file line number Diff line number Diff line change
@@ -284,7 +284,7 @@ fn check<'tcx>(

diag.span_suggestion(
assign.lhs_span,
&format!("declare `{binding_name}` here"),
format!("declare `{binding_name}` here"),
let_snippet,
Applicability::MachineApplicable,
);
@@ -304,7 +304,7 @@ fn check<'tcx>(

diag.span_suggestion_verbose(
usage.stmt.span.shrink_to_lo(),
&format!("declare `{binding_name}` here"),
format!("declare `{binding_name}` here"),
format!("{let_snippet} = "),
applicability,
);
@@ -335,7 +335,7 @@ fn check<'tcx>(

diag.span_suggestion_verbose(
usage.stmt.span.shrink_to_lo(),
&format!("declare `{binding_name}` here"),
format!("declare `{binding_name}` here"),
format!("{let_snippet} = "),
applicability,
);
4 changes: 2 additions & 2 deletions clippy_lints/src/octal_escapes.rs
Original file line number Diff line number Diff line change
@@ -125,7 +125,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) {
if is_string { "string" } else { "byte string" }
),
|diag| {
diag.help(&format!(
diag.help(format!(
"octal escapes are not supported, `\\0` is always a null {}",
if is_string { "character" } else { "byte" }
));
@@ -139,7 +139,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) {
// suggestion 2: unambiguous null byte
diag.span_suggestion(
span,
&format!(
format!(
"if the null {} is intended, disambiguate using",
if is_string { "character" } else { "byte" }
),
2 changes: 1 addition & 1 deletion clippy_lints/src/operators/misrefactored_assign_op.rs
Original file line number Diff line number Diff line change
@@ -50,7 +50,7 @@ fn lint_misrefactored_assign_op(
let long = format!("{snip_a} = {}", sugg::make_binop(op.into(), a, r));
diag.span_suggestion(
expr.span,
&format!(
format!(
"did you mean `{snip_a} = {snip_a} {} {snip_r}` or `{long}`? Consider replacing it with",
op.as_str()
),
4 changes: 2 additions & 2 deletions clippy_lints/src/redundant_clone.rs
Original file line number Diff line number Diff line change
@@ -131,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
// `res = clone(arg)` can be turned into `res = move arg;`
// if `arg` is the only borrow of `cloned` at this point.

if cannot_move_out || !possible_borrower.only_borrowers(&[arg], cloned, loc) {
if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg], cloned, loc) {
continue;
}

@@ -178,7 +178,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
// StorageDead(pred_arg);
// res = to_path_buf(cloned);
// ```
if cannot_move_out || !possible_borrower.only_borrowers(&[arg, cloned], local, loc) {
if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg, cloned], local, loc) {
continue;
}

4 changes: 2 additions & 2 deletions clippy_lints/src/same_name_method.rs
Original file line number Diff line number Diff line change
@@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
|diag| {
diag.span_note(
trait_method_span,
&format!("existing `{method_name}` defined here"),
format!("existing `{method_name}` defined here"),
);
},
);
@@ -151,7 +151,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
// iterate on trait_spans?
diag.span_note(
trait_spans[0],
&format!("existing `{method_name}` defined here"),
format!("existing `{method_name}` defined here"),
);
},
);
4 changes: 2 additions & 2 deletions clippy_lints/src/swap.rs
Original file line number Diff line number Diff line change
@@ -132,7 +132,7 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa
applicability,
);
if !is_xor_based {
diag.note(&format!("or maybe you should use `{sugg}::mem::replace`?"));
diag.note(format!("or maybe you should use `{sugg}::mem::replace`?"));
}
},
);
@@ -214,7 +214,7 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
Applicability::MaybeIncorrect,
);
diag.note(
&format!("or maybe you should use `{sugg}::mem::replace`?")
format!("or maybe you should use `{sugg}::mem::replace`?")
);
}
});
14 changes: 7 additions & 7 deletions clippy_lints/src/transmute/transmute_undefined_repr.rs
Original file line number Diff line number Diff line change
@@ -77,7 +77,7 @@ pub(super) fn check<'tcx>(
&format!("transmute from `{from_ty_orig}` which has an undefined layout"),
|diag| {
if from_ty_orig.peel_refs() != from_ty.peel_refs() {
diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
diag.note(format!("the contained type `{from_ty}` has an undefined layout"));
}
},
);
@@ -91,7 +91,7 @@ pub(super) fn check<'tcx>(
&format!("transmute to `{to_ty_orig}` which has an undefined layout"),
|diag| {
if to_ty_orig.peel_refs() != to_ty.peel_refs() {
diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
diag.note(format!("the contained type `{to_ty}` has an undefined layout"));
}
},
);
@@ -119,16 +119,16 @@ pub(super) fn check<'tcx>(
),
|diag| {
if let Some(same_adt_did) = same_adt_did {
diag.note(&format!(
diag.note(format!(
"two instances of the same generic type (`{}`) may have different layouts",
cx.tcx.item_name(same_adt_did)
));
} else {
if from_ty_orig.peel_refs() != from_ty {
diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
diag.note(format!("the contained type `{from_ty}` has an undefined layout"));
}
if to_ty_orig.peel_refs() != to_ty {
diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
diag.note(format!("the contained type `{to_ty}` has an undefined layout"));
}
}
},
@@ -146,7 +146,7 @@ pub(super) fn check<'tcx>(
&format!("transmute from `{from_ty_orig}` which has an undefined layout"),
|diag| {
if from_ty_orig.peel_refs() != from_ty {
diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
diag.note(format!("the contained type `{from_ty}` has an undefined layout"));
}
},
);
@@ -163,7 +163,7 @@ pub(super) fn check<'tcx>(
&format!("transmute into `{to_ty_orig}` which has an undefined layout"),
|diag| {
if to_ty_orig.peel_refs() != to_ty {
diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
diag.note(format!("the contained type `{to_ty}` has an undefined layout"));
}
},
);
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(
&format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"),
|diag| {
if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
let sugg = arg.as_ty(&to_ty.to_string()).to_string();
let sugg = arg.as_ty(to_ty.to_string()).to_string();
diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable);
}
},
2 changes: 1 addition & 1 deletion clippy_lints/src/transmute/useless_transmute.rs
Original file line number Diff line number Diff line change
@@ -61,7 +61,7 @@ pub(super) fn check<'tcx>(
"transmute from an integer to a pointer",
|diag| {
if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
diag.span_suggestion(e.span, "try", arg.as_ty(&to_ty.to_string()), Applicability::Unspecified);
diag.span_suggestion(e.span, "try", arg.as_ty(to_ty.to_string()), Applicability::Unspecified);
}
},
);
8 changes: 4 additions & 4 deletions clippy_lints/src/types/redundant_allocation.rs
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
&format!("usage of `{outer_sym}<{generic_snippet}>`"),
|diag| {
diag.span_suggestion(hir_ty.span, "try", format!("{generic_snippet}"), applicability);
diag.note(&format!(
diag.note(format!(
"`{generic_snippet}` is already a pointer, `{outer_sym}<{generic_snippet}>` allocates a pointer on the heap"
));
},
@@ -78,7 +78,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
format!("{outer_sym}<{generic_snippet}>"),
applicability,
);
diag.note(&format!(
diag.note(format!(
"`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation"
));
},
@@ -91,10 +91,10 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
hir_ty.span,
&format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"),
|diag| {
diag.note(&format!(
diag.note(format!(
"`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation"
));
diag.help(&format!(
diag.help(format!(
"consider using just `{outer_sym}<{generic_snippet}>` or `{inner_sym}<{generic_snippet}>`"
));
},
4 changes: 2 additions & 2 deletions clippy_lints/src/unit_types/unit_arg.rs
Original file line number Diff line number Diff line change
@@ -129,7 +129,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp

if arg_snippets_without_empty_blocks.is_empty() {
db.multipart_suggestion(
&format!("use {singular}unit literal{plural} instead"),
format!("use {singular}unit literal{plural} instead"),
args_to_recover
.iter()
.map(|arg| (arg.span, "()".to_string()))
@@ -142,7 +142,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp
let it_or_them = if plural { "them" } else { "it" };
db.span_suggestion(
expr.span,
&format!(
format!(
"{or}move the expression{empty_or_s} in front of the call and replace {it_or_them} with the unit literal `()`"
),
sugg,
4 changes: 2 additions & 2 deletions clippy_lints/src/write.rs
Original file line number Diff line number Diff line change
@@ -377,7 +377,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_c
// print!("\n"), write!(f, "\n")

diag.multipart_suggestion(
&format!("use `{name}ln!` instead"),
format!("use `{name}ln!` instead"),
vec![(name_span, format!("{name}ln")), (format_string_span, String::new())],
Applicability::MachineApplicable,
);
@@ -388,7 +388,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_c
let newline_span = format_string_span.with_lo(hi - BytePos(3)).with_hi(hi - BytePos(1));

diag.multipart_suggestion(
&format!("use `{name}ln!` instead"),
format!("use `{name}ln!` instead"),
vec![(name_span, format!("{name}ln")), (newline_span, String::new())],
Applicability::MachineApplicable,
);
2 changes: 1 addition & 1 deletion clippy_utils/src/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ use std::env;
fn docs_link(diag: &mut Diagnostic, lint: &'static Lint) {
if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() {
if let Some(lint) = lint.name_lower().strip_prefix("clippy::") {
diag.help(&format!(
diag.help(format!(
"for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{lint}",
&option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| {
// extract just major + minor version and ignore patch versions
52 changes: 0 additions & 52 deletions clippy_utils/src/mir/maybe_storage_live.rs

This file was deleted.

2 changes: 0 additions & 2 deletions clippy_utils/src/mir/mod.rs
Original file line number Diff line number Diff line change
@@ -5,8 +5,6 @@ use rustc_middle::mir::{
};
use rustc_middle::ty::TyCtxt;

mod maybe_storage_live;

mod possible_borrower;
pub use possible_borrower::PossibleBorrowerMap;

274 changes: 172 additions & 102 deletions clippy_utils/src/mir/possible_borrower.rs
Original file line number Diff line number Diff line change
@@ -1,92 +1,137 @@
use super::{
maybe_storage_live::MaybeStorageLive, possible_origin::PossibleOriginVisitor,
transitive_relation::TransitiveRelation,
};
use super::possible_origin::PossibleOriginVisitor;
use crate::ty::is_copy;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_index::bit_set::{BitSet, HybridBitSet};
use rustc_lint::LateContext;
use rustc_middle::mir::{self, visit::Visitor as _, Mutability};
use rustc_middle::ty::{self, visit::TypeVisitor};
use rustc_mir_dataflow::{Analysis, ResultsCursor};
use rustc_middle::mir::{
self, visit::Visitor as _, BasicBlock, Local, Location, Mutability, Statement, StatementKind, Terminator,
};
use rustc_middle::ty::{self, visit::TypeVisitor, TyCtxt};
use rustc_mir_dataflow::{
fmt::DebugWithContext, impls::MaybeStorageLive, lattice::JoinSemiLattice, Analysis, AnalysisDomain,
CallReturnPlaces, ResultsCursor,
};
use std::borrow::Cow;
use std::ops::ControlFlow;

/// Collects the possible borrowers of each local.
/// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
/// possible borrowers of `a`.
#[allow(clippy::module_name_repetitions)]
struct PossibleBorrowerVisitor<'a, 'b, 'tcx> {
possible_borrower: TransitiveRelation,
struct PossibleBorrowerAnalysis<'b, 'tcx> {
tcx: TyCtxt<'tcx>,
body: &'b mir::Body<'tcx>,
cx: &'a LateContext<'tcx>,
possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
}

impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> {
fn new(
cx: &'a LateContext<'tcx>,
body: &'b mir::Body<'tcx>,
possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
) -> Self {
#[derive(Clone, Debug, Eq, PartialEq)]
struct PossibleBorrowerState {
map: FxIndexMap<Local, BitSet<Local>>,
domain_size: usize,
}

impl PossibleBorrowerState {
fn new(domain_size: usize) -> Self {
Self {
possible_borrower: TransitiveRelation::default(),
cx,
body,
possible_origin,
map: FxIndexMap::default(),
domain_size,
}
}

fn into_map(
self,
cx: &'a LateContext<'tcx>,
maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive>,
) -> PossibleBorrowerMap<'b, 'tcx> {
let mut map = FxHashMap::default();
for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) {
if is_copy(cx, self.body.local_decls[row].ty) {
continue;
}
#[allow(clippy::similar_names)]
fn add(&mut self, borrowed: Local, borrower: Local) {
self.map
.entry(borrowed)
.or_insert(BitSet::new_empty(self.domain_size))
.insert(borrower);
}
}

let mut borrowers = self.possible_borrower.reachable_from(row, self.body.local_decls.len());
borrowers.remove(mir::Local::from_usize(0));
impl<C> DebugWithContext<C> for PossibleBorrowerState {
fn fmt_with(&self, _ctxt: &C, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
<_ as std::fmt::Debug>::fmt(self, f)
}
fn fmt_diff_with(&self, _old: &Self, _ctxt: &C, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
unimplemented!()
}
}

impl JoinSemiLattice for PossibleBorrowerState {
fn join(&mut self, other: &Self) -> bool {
let mut changed = false;
for (&borrowed, borrowers) in other.map.iter() {
if !borrowers.is_empty() {
map.insert(row, borrowers);
changed |= self
.map
.entry(borrowed)
.or_insert(BitSet::new_empty(self.domain_size))
.union(borrowers);
}
}
changed
}
}

let bs = BitSet::new_empty(self.body.local_decls.len());
PossibleBorrowerMap {
map,
maybe_live,
bitset: (bs.clone(), bs),
impl<'b, 'tcx> AnalysisDomain<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> {
type Domain = PossibleBorrowerState;

const NAME: &'static str = "possible_borrower";

fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
PossibleBorrowerState::new(body.local_decls.len())
}

fn initialize_start_block(&self, _body: &mir::Body<'tcx>, _entry_set: &mut Self::Domain) {}
}

impl<'b, 'tcx> PossibleBorrowerAnalysis<'b, 'tcx> {
fn new(
tcx: TyCtxt<'tcx>,
body: &'b mir::Body<'tcx>,
possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
) -> Self {
Self {
tcx,
body,
possible_origin,
}
}
}

impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b, 'tcx> {
fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
let lhs = place.local;
match rvalue {
mir::Rvalue::Ref(_, _, borrowed) => {
self.possible_borrower.add(borrowed.local, lhs);
},
other => {
if ContainsRegion
.visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty)
.is_continue()
{
return;
}
rvalue_locals(other, |rhs| {
if lhs != rhs {
self.possible_borrower.add(rhs, lhs);
impl<'b, 'tcx> Analysis<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> {
fn apply_call_return_effect(
&self,
_state: &mut Self::Domain,
_block: BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
) {
}

fn apply_statement_effect(&self, state: &mut Self::Domain, statement: &Statement<'tcx>, _location: Location) {
if let StatementKind::Assign(box (place, rvalue)) = &statement.kind {
let lhs = place.local;
match rvalue {
mir::Rvalue::Ref(_, _, borrowed) => {
state.add(borrowed.local, lhs);
},
other => {
if ContainsRegion
.visit_ty(place.ty(&self.body.local_decls, self.tcx).ty)
.is_continue()
{
return;
}
});
},
rvalue_locals(other, |rhs| {
if lhs != rhs {
state.add(rhs, lhs);
}
});
},
}
}
}

fn visit_terminator(&mut self, terminator: &mir::Terminator<'_>, _loc: mir::Location) {
fn apply_terminator_effect(&self, state: &mut Self::Domain, terminator: &Terminator<'tcx>, _location: Location) {
if let mir::TerminatorKind::Call {
args,
destination: mir::Place { local: dest, .. },
@@ -126,10 +171,10 @@ impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b,

for y in mutable_variables {
for x in &immutable_borrowers {
self.possible_borrower.add(*x, y);
state.add(*x, y);
}
for x in &mutable_borrowers {
self.possible_borrower.add(*x, y);
state.add(*x, y);
}
}
}
@@ -165,73 +210,98 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
}
}

/// Result of `PossibleBorrowerVisitor`.
/// Result of `PossibleBorrowerAnalysis`.
#[allow(clippy::module_name_repetitions)]
pub struct PossibleBorrowerMap<'b, 'tcx> {
/// Mapping `Local -> its possible borrowers`
pub map: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive>,
// Caches to avoid allocation of `BitSet` on every query
pub bitset: (BitSet<mir::Local>, BitSet<mir::Local>),
body: &'b mir::Body<'tcx>,
possible_borrower: ResultsCursor<'b, 'tcx, PossibleBorrowerAnalysis<'b, 'tcx>>,
maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'b>>,
pushed: BitSet<Local>,
stack: Vec<Local>,
}

impl<'a, 'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
pub fn new(cx: &'a LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
pub fn new(cx: &LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
let possible_origin = {
let mut vis = PossibleOriginVisitor::new(mir);
vis.visit_body(mir);
vis.into_map(cx)
};
let maybe_storage_live_result = MaybeStorageLive
let possible_borrower = PossibleBorrowerAnalysis::new(cx.tcx, mir, possible_origin)
.into_engine(cx.tcx, mir)
.pass_name("redundant_clone")
.pass_name("possible_borrower")
.iterate_to_fixpoint()
.into_results_cursor(mir);
let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin);
vis.visit_body(mir);
vis.into_map(cx, maybe_storage_live_result)
}

/// Returns true if the set of borrowers of `borrowed` living at `at` matches with `borrowers`.
pub fn only_borrowers(&mut self, borrowers: &[mir::Local], borrowed: mir::Local, at: mir::Location) -> bool {
self.bounded_borrowers(borrowers, borrowers, borrowed, at)
let maybe_live = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len())))
.into_engine(cx.tcx, mir)
.pass_name("possible_borrower")
.iterate_to_fixpoint()
.into_results_cursor(mir);
PossibleBorrowerMap {
body: mir,
possible_borrower,
maybe_live,
pushed: BitSet::new_empty(mir.local_decls.len()),
stack: Vec::with_capacity(mir.local_decls.len()),
}
}

/// Returns true if the set of borrowers of `borrowed` living at `at` includes at least `below`
/// but no more than `above`.
pub fn bounded_borrowers(
/// Returns true if the set of borrowers of `borrowed` living at `at` includes no more than
/// `borrowers`.
/// Notes:
/// 1. It would be nice if `PossibleBorrowerMap` could store `cx` so that `at_most_borrowers`
/// would not require it to be passed in. But a `PossibleBorrowerMap` is stored in `LintPass`
/// `Dereferencing`, which outlives any `LateContext`.
/// 2. In all current uses of `at_most_borrowers`, `borrowers` is a slice of at most two
/// elements. Thus, `borrowers.contains(...)` is effectively a constant-time operation. If
/// `at_most_borrowers`'s uses were to expand beyond this, its implementation might have to be
/// adjusted.
pub fn at_most_borrowers(
&mut self,
below: &[mir::Local],
above: &[mir::Local],
cx: &LateContext<'tcx>,
borrowers: &[mir::Local],
borrowed: mir::Local,
at: mir::Location,
) -> bool {
self.maybe_live.seek_after_primary_effect(at);
if is_copy(cx, self.body.local_decls[borrowed].ty) {
return true;
}

self.bitset.0.clear();
let maybe_live = &mut self.maybe_live;
if let Some(bitset) = self.map.get(&borrowed) {
for b in bitset.iter().filter(move |b| maybe_live.contains(*b)) {
self.bitset.0.insert(b);
self.possible_borrower.seek_before_primary_effect(at);
self.maybe_live.seek_before_primary_effect(at);

let possible_borrower = &self.possible_borrower.get().map;
let maybe_live = &self.maybe_live;

self.pushed.clear();
self.stack.clear();

if let Some(borrowers) = possible_borrower.get(&borrowed) {
for b in borrowers.iter() {
if self.pushed.insert(b) {
self.stack.push(b);
}
}
} else {
return false;
// Nothing borrows `borrowed` at `at`.
return true;
}

self.bitset.1.clear();
for b in below {
self.bitset.1.insert(*b);
}

if !self.bitset.0.superset(&self.bitset.1) {
return false;
}
while let Some(borrower) = self.stack.pop() {
if maybe_live.contains(borrower) && !borrowers.contains(&borrower) {
return false;
}

for b in above {
self.bitset.0.remove(*b);
if let Some(borrowers) = possible_borrower.get(&borrower) {
for b in borrowers.iter() {
if self.pushed.insert(b) {
self.stack.push(b);
}
}
}
}

self.bitset.0.is_empty()
true
}

pub fn local_is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool {
2 changes: 1 addition & 1 deletion tests/ui/manual_retain.fixed
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// run-rustfix
#![warn(clippy::manual_retain)]
#![allow(unused)]
#![allow(unused, clippy::redundant_clone)]
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::collections::BinaryHeap;
2 changes: 1 addition & 1 deletion tests/ui/manual_retain.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// run-rustfix
#![warn(clippy::manual_retain)]
#![allow(unused)]
#![allow(unused, clippy::redundant_clone)]
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::collections::BinaryHeap;
13 changes: 12 additions & 1 deletion tests/ui/needless_borrow.fixed
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// run-rustfix
#![feature(lint_reasons)]
#![feature(custom_inner_attributes, lint_reasons, rustc_private)]
#![allow(
unused,
clippy::uninlined_format_args,
@@ -491,3 +491,14 @@ mod issue_9782_method_variant {
S.foo::<&[u8; 100]>(&a);
}
}

extern crate rustc_lint;
extern crate rustc_span;

#[allow(dead_code)]
mod span_lint {
use rustc_lint::{LateContext, Lint, LintContext};
fn foo(cx: &LateContext<'_>, lint: &'static Lint) {
cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(String::new()));
}
}
13 changes: 12 additions & 1 deletion tests/ui/needless_borrow.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// run-rustfix
#![feature(lint_reasons)]
#![feature(custom_inner_attributes, lint_reasons, rustc_private)]
#![allow(
unused,
clippy::uninlined_format_args,
@@ -491,3 +491,14 @@ mod issue_9782_method_variant {
S.foo::<&[u8; 100]>(&a);
}
}

extern crate rustc_lint;
extern crate rustc_span;

#[allow(dead_code)]
mod span_lint {
use rustc_lint::{LateContext, Lint, LintContext};
fn foo(cx: &LateContext<'_>, lint: &'static Lint) {
cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new()));
}
}
8 changes: 7 additions & 1 deletion tests/ui/needless_borrow.stderr
Original file line number Diff line number Diff line change
@@ -216,5 +216,11 @@ error: the borrowed expression implements the required traits
LL | foo(&a);
| ^^ help: change this to: `a`

error: aborting due to 36 previous errors
error: the borrowed expression implements the required traits
--> $DIR/needless_borrow.rs:502:85
|
LL | cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new()));
| ^^^^^^^^^^^^^^ help: change this to: `String::new()`

error: aborting due to 37 previous errors

6 changes: 6 additions & 0 deletions tests/ui/redundant_clone.fixed
Original file line number Diff line number Diff line change
@@ -239,3 +239,9 @@ fn false_negative_5707() {
let _z = x.clone(); // pr 7346 can't lint on `x`
drop(y);
}

#[allow(unused, clippy::manual_retain)]
fn possible_borrower_improvements() {
let mut s = String::from("foobar");
s = s.chars().filter(|&c| c != 'o').collect();
}
6 changes: 6 additions & 0 deletions tests/ui/redundant_clone.rs
Original file line number Diff line number Diff line change
@@ -239,3 +239,9 @@ fn false_negative_5707() {
let _z = x.clone(); // pr 7346 can't lint on `x`
drop(y);
}

#[allow(unused, clippy::manual_retain)]
fn possible_borrower_improvements() {
let mut s = String::from("foobar");
s = s.chars().filter(|&c| c != 'o').to_owned().collect();
}
14 changes: 13 additions & 1 deletion tests/ui/redundant_clone.stderr
Original file line number Diff line number Diff line change
@@ -179,5 +179,17 @@ note: this value is dropped without further use
LL | foo(&x.clone(), move || {
| ^

error: aborting due to 15 previous errors
error: redundant clone
--> $DIR/redundant_clone.rs:246:40
|
LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect();
| ^^^^^^^^^^^ help: remove this
|
note: this value is dropped without further use
--> $DIR/redundant_clone.rs:246:9
|
LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 16 previous errors