Merge commit '9725c4a162502a02c1c67fdca6b797fe09b2b73c' into clippy-subtree-update

This commit is contained in:
Philipp Krones 2024-04-04 19:52:55 +02:00
parent 53e31dc45c
commit 0ae4a048c6
444 changed files with 5289 additions and 1934 deletions

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
# Generated by ui-test
rustc-ice-*
# Used by CI to be able to push:
/.github/deploy_key
out

View File

@ -5379,6 +5379,7 @@ Released 2018-09-13
[`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays
[`large_stack_frames`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_frames
[`large_types_passed_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value
[`legacy_numeric_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#legacy_numeric_constants
[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return
@ -5481,6 +5482,7 @@ Released 2018-09-13
[`missing_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc
[`missing_spin_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_spin_loop
[`missing_trait_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_trait_methods
[`missing_transmute_annotations`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_transmute_annotations
[`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes
[`mixed_attributes_style`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_attributes_style
[`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals

View File

@ -31,7 +31,6 @@ anstream = "0.6.0"
[dev-dependencies]
ui_test = "0.22.2"
tester = "0.9"
regex = "1.5.5"
toml = "0.7.3"
walkdir = "2.3"

View File

@ -32,3 +32,4 @@
- [Proposals](development/proposals/README.md)
- [Roadmap 2021](development/proposals/roadmap-2021.md)
- [Syntax Tree Patterns](development/proposals/syntax-tree-patterns.md)
- [The Team](development/the_team.md)

View File

@ -62,9 +62,8 @@ $ cargo dev new_lint --name=lint_name --pass=late --category=pedantic
There are two things to note here:
1. `--pass`: We set `--pass=late` in this command to do a late lint pass. The
alternative is an `early` lint pass. We will discuss this difference in a
later chapter.
<!-- FIXME: Link that "later chapter" when lint_passes.md is merged -->
alternative is an `early` lint pass. We will discuss this difference in the
[Lint Passes] chapter.
2. `--category`: If not provided, the `category` of this new lint will default
to `nursery`.
@ -194,8 +193,7 @@ store.register_late_pass(|_| Box::new(foo_functions::FooFunctions));
As you might have guessed, where there's something late, there is something
early: in Clippy there is a `register_early_pass` method as well. More on early
vs. late passes in a later chapter.
<!-- FIXME: Link that "later chapter" when lint_passes.md is merged -->
vs. late passes in the [Lint Passes] chapter.
Without a call to one of `register_early_pass` or `register_late_pass`, the lint
pass in question will not be run.
@ -203,3 +201,4 @@ pass in question will not be run.
[all_lints]: https://rust-lang.github.io/rust-clippy/master/
[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
[Lint Passes]: lint_passes.md

View File

@ -50,7 +50,7 @@ questions already, but the parser is okay with it. This is what we
mean when we say `EarlyLintPass` deals with only syntax on the AST level.
Alternatively, think of the `foo_functions` lint we mentioned in
define new lints <!-- FIXME: add link --> chapter.
the [Define New Lints](defining_lints.md) chapter.
We want the `foo_functions` lint to detect functions with `foo` as their name.
Writing a lint that only checks for the name of a function means that we only

View File

@ -0,0 +1,130 @@
# The team
Everyone who contributes to Clippy makes the project what it is. Collaboration
and discussions are the lifeblood of every open-source project. Clippy has a
very flat hierarchy. The teams mainly have additional access rights to the repo.
This document outlines the onboarding process, as well as duties, and access
rights for members of a group.
All regular events mentioned in this chapter are tracked in the [calendar repository].
The calendar file is also available for download: [clippy.ics]
## Everyone
Everyone, including you, is welcome to join discussions and contribute in other
ways, like PRs.
You also have some triage rights, using `@rustbot` to add labels and claim
issues. See [labeling with @rustbot].
A rule for everyone should be to keep a healthy work-life balance. Take a break
when you need one.
## Clippy-Contributors
This is a group of regular contributors to Clippy to help with triaging.
### Duties
This team exists to make contributing easier for regular members. It doesn't
carry any duties that need to be done. However, we want to encourage members of
this group to help with triaging, which can include:
1. **Labeling issues**
For the `good-first-issue` label, it can still be good to use `@rustbot` to
subscribe to the issue and help interested parties, if they post questions
in the comments.
2. **Closing duplicate or resolved issues**
When you manually close an issue, it's often a good idea, to add a short
comment explaining the reason.
3. **Ping people after two weeks of inactivity**
We try to keep issue assignments and PRs fairly up-to-date. After two weeks,
it can be good to send a friendly ping to the delaying party.
You might close a PR with the `I-inactive-closed` label if the author is
busy or wants to abandon it. If the reviewer is busy, the PR can be
reassigned to someone else.
Checkout: https://triage.rust-lang.org/triage/rust-lang/rust-clippy to
monitor PRs.
While not part of their duties, contributors are encouraged to review PRs
and help on Zulip. The team always appreciates help!
### Membership
If you have been contributing to Clippy for some time, we'll probably ask you if
you want to join this team. Members of this team are also welcome to suggest
people who they think would make a great addition to this group.
For this group, there is no direct onboarding process. You're welcome to just
continue what you've been doing. If you like, you can ask for someone to mentor
you, either in the Clippy stream on Zulip or privately via a PM.
If you have been inactive in Clippy for over three months, we'll probably move
you to the alumni group. You're always welcome to come back.
## The Clippy Team
[The Clippy team](https://www.rust-lang.org/governance/teams/dev-tools#Clippy%20team)
is responsible for maintaining Clippy.
### Duties
1. **Respond to PRs in a timely manner**
It's totally fine, if you don't have the time for reviews right now.
You can reassign the PR to a random member by commenting `r? clippy`.
2. **Take a break when you need one**
You are valuable! Clippy wouldn't be what it is without you. So take a break
early and recharge some energy when you need to.
3. **Be responsive on Zulip**
This means in a reasonable time frame, so responding within one or two days
is totally fine.
It's also good, if you answer threads on Zulip and take part in our Clippy
meetings, every two weeks. The meeting dates are tracked in the [calendar repository].
4. **Sync Clippy with the rust-lang/rust repo**
This is done every two weeks, usually by @flip1995.
5. **Update the changelog**
This needs to be done for every release, every six weeks. This is usually
done by @xFrednet.
### Membership
If you have been active for some time, we'll probably reach out and ask
if you want to help with reviews and eventually join the Clippy team.
During the onboarding process, you'll be assigned pull requests to review.
You'll also have an active team member as a mentor who'll stay in contact via
Zulip DMs to provide advice and feedback. If you have questions, you're always
welcome to ask, that is the best way to learn. Once you're done with the review,
you can ping your mentor for a full review and to r+ the PR in both of your names.
When your mentor is confident that you can handle reviews on your own, they'll
start an informal vote among the active team members to officially add you to
the team. This vote is usually accepted unanimously. Then you'll be added to
the team once you've confirmed that you're still interested in joining. The
onboarding phase typically takes a couple of weeks to a few months.
If you have been inactive in Clippy for over three months, we'll probably move
you to the alumni group. You're always welcome to come back.
[calendar repository]: https://github.com/rust-lang/calendar/blob/main/clippy.toml
[clippy.ics]: https://rust-lang.github.io/calendar/clippy.ics
[labeling with @rustbot]: https://forge.rust-lang.org/triagebot/labeling.html

View File

@ -616,6 +616,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
* [`if_then_some_else_none`](https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none)
* [`index_refutable_slice`](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice)
* [`iter_kv_map`](https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map)
* [`legacy_numeric_constants`](https://rust-lang.github.io/rust-clippy/master/index.html#legacy_numeric_constants)
* [`manual_bits`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits)
* [`manual_c_str_literals`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals)
* [`manual_clamp`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp)

View File

@ -262,7 +262,7 @@ define_Conf! {
///
/// Suppress lints whenever the suggested change would cause breakage for other crates.
(avoid_breaking_exported_api: bool = true),
/// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES.
/// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS.
///
/// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml`
#[default_text = ""]
@ -856,11 +856,6 @@ mod tests {
}
}
assert!(
names.remove("allow-one-hash-in-raw-strings"),
"remove this when #11481 is fixed"
);
assert!(
names.is_empty(),
"Configuration variable lacks test: {names:?}\nAdd a test to `tests/ui-toml`"

View File

@ -1,6 +1,12 @@
#![feature(rustc_private, let_chains)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(rust_2018_idioms, unused_lifetimes)]
#![warn(
trivial_casts,
trivial_numeric_casts,
rust_2018_idioms,
unused_lifetimes,
unused_qualifications
)]
#![allow(
clippy::must_use_candidate,
clippy::missing_panics_doc,

View File

@ -36,7 +36,7 @@ msrv_aliases! {
1,47,0 { TAU, IS_ASCII_DIGIT_CONST, ARRAY_IMPL_ANY_LEN }
1,46,0 { CONST_IF_MATCH }
1,45,0 { STR_STRIP_PREFIX }
1,43,0 { LOG2_10, LOG10_2 }
1,43,0 { LOG2_10, LOG10_2, NUMERIC_ASSOCIATED_CONSTANTS }
1,42,0 { MATCHES_MACRO, SLICE_PATTERNS, PTR_SLICE_RAW_PARTS }
1,41,0 { RE_REBALANCING_COHERENCE, RESULT_MAP_OR_ELSE }
1,40,0 { MEM_TAKE, NON_EXHAUSTIVE, OPTION_AS_DEREF }

View File

@ -2,8 +2,13 @@
#![feature(let_chains)]
#![feature(rustc_private)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
// warn on lints, that are included in `rust-lang/rust`s bootstrap
#![warn(rust_2018_idioms, unused_lifetimes)]
#![warn(
trivial_casts,
trivial_numeric_casts,
rust_2018_idioms,
unused_lifetimes,
unused_qualifications
)]
// The `rustc_driver` crate seems to be required in order to use the `rust_lexer` crate.
#[allow(unused_extern_crates)]

View File

@ -20,6 +20,8 @@ pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a String>) {
.args(["--edition", "2021"])
.arg(path)
.args(args)
// Prevent rustc from creating `rustc-ice-*` files the console output is enough.
.env("RUSTC_ICE", "0")
.status(),
);
} else {
@ -32,6 +34,8 @@ pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a String>) {
let status = Command::new(cargo_clippy_path())
.arg("clippy")
.args(args)
// Prevent rustc from creating `rustc-ice-*` files the console output is enough.
.env("RUSTC_ICE", "0")
.current_dir(path)
.status();

View File

@ -992,7 +992,7 @@ fn replace_region_in_text<'a>(
}
fn try_rename_file(old_name: &Path, new_name: &Path) -> bool {
match fs::OpenOptions::new().create_new(true).write(true).open(new_name) {
match OpenOptions::new().create_new(true).write(true).open(new_name) {
Ok(file) => drop(file),
Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false,
Err(e) => panic_file(e, new_name, "create"),
@ -1016,7 +1016,7 @@ fn panic_file(error: io::Error, name: &Path, action: &str) -> ! {
}
fn rewrite_file(path: &Path, f: impl FnOnce(&str) -> Option<String>) {
let mut file = fs::OpenOptions::new()
let mut file = OpenOptions::new()
.write(true)
.read(true)
.open(path)

View File

@ -95,7 +95,7 @@ impl ApproxConstant {
cx,
APPROX_CONSTANT,
e.span,
&format!("approximate value of `{module}::consts::{}` found", &name),
format!("approximate value of `{module}::consts::{}` found", &name),
None,
"consider using the constant directly",
);

View File

@ -53,9 +53,9 @@ fn check_asm_syntax(
cx,
lint,
span,
&format!("{style} x86 assembly syntax used"),
format!("{style} x86 assembly syntax used"),
None,
&format!("use {} x86 assembly syntax", !style),
format!("use {} x86 assembly syntax", !style),
);
}
}

View File

@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
cx,
ASSERTIONS_ON_CONSTANTS,
macro_call.span,
&format!(
format!(
"`{}!(true)` will be optimized out by the compiler",
cx.tcx.item_name(macro_call.def_id)
),
@ -74,9 +74,9 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
cx,
ASSERTIONS_ON_CONSTANTS,
macro_call.span,
&format!("`assert!(false{assert_arg})` should probably be replaced"),
format!("`assert!(false{assert_arg})` should probably be replaced"),
None,
&format!("use `panic!({panic_arg})` or `unreachable!({panic_arg})`"),
format!("use `panic!({panic_arg})` or `unreachable!({panic_arg})`"),
);
}
}

View File

@ -65,7 +65,7 @@ impl AssigningClones {
impl_lint_pass!(AssigningClones => [ASSIGNING_CLONES]);
impl<'tcx> LateLintPass<'tcx> for AssigningClones {
fn check_expr(&mut self, cx: &LateContext<'tcx>, assign_expr: &'tcx hir::Expr<'_>) {
fn check_expr(&mut self, cx: &LateContext<'tcx>, assign_expr: &'tcx Expr<'_>) {
// Do not fire the lint in macros
let expn_data = assign_expr.span().ctxt().outer_expn_data();
match expn_data.kind {
@ -181,6 +181,23 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC
return false;
}
// If the call expression is inside an impl block that contains the method invoked by the
// call expression, we bail out to avoid suggesting something that could result in endless
// recursion.
if let Some(local_block_id) = impl_block.as_local()
&& let Some(block) = cx.tcx.hir_node_by_def_id(local_block_id).as_owner()
{
let impl_block_owner = block.def_id();
if cx
.tcx
.hir()
.parent_id_iter(lhs.hir_id)
.any(|parent| parent.owner == impl_block_owner)
{
return false;
}
}
// Find the function for which we want to check that it is implemented.
let provided_fn = match call.target {
TargetTrait::Clone => cx.tcx.get_diagnostic_item(sym::Clone).and_then(|clone| {
@ -205,14 +222,9 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC
implemented_fns.contains_key(&provided_fn.def_id)
}
fn suggest<'tcx>(
cx: &LateContext<'tcx>,
assign_expr: &hir::Expr<'tcx>,
lhs: &hir::Expr<'tcx>,
call: &CallCandidate<'tcx>,
) {
fn suggest<'tcx>(cx: &LateContext<'tcx>, assign_expr: &Expr<'tcx>, lhs: &Expr<'tcx>, call: &CallCandidate<'tcx>) {
span_lint_and_then(cx, ASSIGNING_CLONES, assign_expr.span, call.message(), |diag| {
let mut applicability = Applicability::MachineApplicable;
let mut applicability = Applicability::Unspecified;
diag.span_suggestion(
assign_expr.span,
@ -263,7 +275,7 @@ impl<'tcx> CallCandidate<'tcx> {
fn suggested_replacement(
&self,
cx: &LateContext<'tcx>,
lhs: &hir::Expr<'tcx>,
lhs: &Expr<'tcx>,
applicability: &mut Applicability,
) -> String {
match self.target {

View File

@ -30,7 +30,7 @@ pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMet
cx,
ALLOW_ATTRIBUTES_WITHOUT_REASON,
attr.span,
&format!("`{}` attribute without specifying a reason", name.as_str()),
format!("`{}` attribute without specifying a reason", name.as_str()),
None,
"try adding a reason at the end with `, reason = \"..\"`",
);

View File

@ -31,6 +31,9 @@ fn check_duplicated_attr(
attr_paths: &mut FxHashMap<String, Span>,
parent: &mut Vec<String>,
) {
if attr.span.from_expansion() {
return;
}
let Some(ident) = attr.ident() else { return };
let name = ident.name;
if name == sym::doc || name == sym::cfg_attr {
@ -38,6 +41,14 @@ fn check_duplicated_attr(
// conditions are the same.
return;
}
if let Some(direct_parent) = parent.last()
&& ["cfg", "cfg_attr"].contains(&direct_parent.as_str())
&& [sym::all, sym::not, sym::any].contains(&name)
{
// FIXME: We don't correctly check `cfg`s for now, so if it's more complex than just a one
// level `cfg`, we leave.
return;
}
if let Some(value) = attr.value_str() {
emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}={value}", parent.join(":")));
} else if let Some(sub_attrs) = attr.meta_item_list() {

View File

@ -21,7 +21,7 @@ pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Att
cx,
INLINE_ALWAYS,
attr.span,
&format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"),
format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"),
);
}
}

View File

@ -40,7 +40,7 @@ fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) {
cx,
MAYBE_MISUSED_CFG,
meta.span,
&format!("'test' may be misspelled as '{}'", ident.name.as_str()),
format!("'test' may be misspelled as '{}'", ident.name.as_str()),
"did you mean",
"test".to_string(),
Applicability::MaybeIncorrect,

View File

@ -1,30 +1,85 @@
use super::MIXED_ATTRIBUTES_STYLE;
use clippy_utils::diagnostics::span_lint;
use rustc_ast::AttrStyle;
use rustc_lint::EarlyContext;
use rustc_ast::{AttrKind, AttrStyle, Attribute};
use rustc_data_structures::fx::FxHashSet;
use rustc_lint::{LateContext, LintContext};
use rustc_span::source_map::SourceMap;
use rustc_span::{SourceFile, Span, Symbol};
use std::sync::Arc;
pub(super) fn check(cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
let mut has_outer = false;
let mut has_inner = false;
#[derive(Hash, PartialEq, Eq)]
enum SimpleAttrKind {
Doc,
/// A normal attribute, with its name symbols.
Normal(Vec<Symbol>),
}
for attr in &item.attrs {
if attr.span.from_expansion() {
impl From<&AttrKind> for SimpleAttrKind {
fn from(value: &AttrKind) -> Self {
match value {
AttrKind::Normal(attr) => {
let path_symbols = attr
.item
.path
.segments
.iter()
.map(|seg| seg.ident.name)
.collect::<Vec<_>>();
Self::Normal(path_symbols)
},
AttrKind::DocComment(..) => Self::Doc,
}
}
}
pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute]) {
let mut inner_attr_kind: FxHashSet<SimpleAttrKind> = FxHashSet::default();
let mut outer_attr_kind: FxHashSet<SimpleAttrKind> = FxHashSet::default();
let source_map = cx.sess().source_map();
let item_src = source_map.lookup_source_file(item_span.lo());
for attr in attrs {
if attr.span.from_expansion() || !attr_in_same_src_as_item(source_map, &item_src, attr.span) {
continue;
}
let kind: SimpleAttrKind = (&attr.kind).into();
match attr.style {
AttrStyle::Inner => has_inner = true,
AttrStyle::Outer => has_outer = true,
}
AttrStyle::Inner => {
if outer_attr_kind.contains(&kind) {
lint_mixed_attrs(cx, attrs);
return;
}
inner_attr_kind.insert(kind);
},
AttrStyle::Outer => {
if inner_attr_kind.contains(&kind) {
lint_mixed_attrs(cx, attrs);
return;
}
outer_attr_kind.insert(kind);
},
};
}
if !has_outer || !has_inner {
}
fn lint_mixed_attrs(cx: &LateContext<'_>, attrs: &[Attribute]) {
let mut attrs_iter = attrs.iter().filter(|attr| !attr.span.from_expansion());
let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.last()) {
first.span.with_hi(last.span.hi())
} else {
return;
}
let mut attrs_iter = item.attrs.iter().filter(|attr| !attr.span.from_expansion());
let span = attrs_iter.next().unwrap().span;
};
span_lint(
cx,
MIXED_ATTRIBUTES_STYLE,
span.with_hi(attrs_iter.last().unwrap().span.hi()),
span,
"item has both inner and outer attributes",
);
}
fn attr_in_same_src_as_item(source_map: &SourceMap, item_src: &Arc<SourceFile>, attr_span: Span) -> bool {
let attr_src = source_map.lookup_source_file(attr_span.lo());
Arc::ptr_eq(item_src, &attr_src)
}

View File

@ -465,10 +465,20 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
/// Checks that an item has only one kind of attributes.
/// Checks for items that have the same kind of attributes with mixed styles (inner/outer).
///
/// ### Why is this bad?
/// Having both kinds of attributes makes it more complicated to read code.
/// Having both style of said attributes makes it more complicated to read code.
///
/// ### Known problems
/// This lint currently has false-negatives when mixing same attributes
/// but they have different path symbols, for example:
/// ```ignore
/// #[custom_attribute]
/// pub fn foo() {
/// #![my_crate::custom_attribute]
/// }
/// ```
///
/// ### Example
/// ```no_run
@ -486,7 +496,7 @@ declare_clippy_lint! {
/// ```
#[clippy::version = "1.78.0"]
pub MIXED_ATTRIBUTES_STYLE,
suspicious,
style,
"item has both inner and outer attributes"
}
@ -523,6 +533,7 @@ declare_lint_pass!(Attributes => [
USELESS_ATTRIBUTE,
BLANKET_CLIPPY_RESTRICTION_LINTS,
SHOULD_PANIC_WITHOUT_EXPECT,
MIXED_ATTRIBUTES_STYLE,
]);
impl<'tcx> LateLintPass<'tcx> for Attributes {
@ -566,6 +577,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
ItemKind::ExternCrate(..) | ItemKind::Use(..) => useless_attribute::check(cx, item, attrs),
_ => {},
}
mixed_attributes_style::check(cx, item.span, attrs);
}
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
@ -594,7 +606,6 @@ impl_lint_pass!(EarlyAttributes => [
MAYBE_MISUSED_CFG,
DEPRECATED_CLIPPY_CFG_ATTR,
UNNECESSARY_CLIPPY_CFG,
MIXED_ATTRIBUTES_STYLE,
DUPLICATED_ATTRIBUTES,
]);
@ -605,7 +616,6 @@ impl EarlyLintPass for EarlyAttributes {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
empty_line_after::check(cx, item);
mixed_attributes_style::check(cx, item);
duplicated_attributes::check(cx, &item.attrs);
}

View File

@ -58,7 +58,7 @@ pub(super) fn check(
clippy_lints,
"no need to put clippy lints behind a `clippy` cfg",
None,
&format!(
format!(
"write instead: `#{}[{}({})]`",
if attr.style == AttrStyle::Inner { "!" } else { "" },
ident.name,

View File

@ -267,7 +267,7 @@ fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPa
cx,
AWAIT_HOLDING_INVALID_TYPE,
span,
&format!(
format!(
"`{}` may not be held across an `await` point per `clippy.toml`",
disallowed.path()
),

View File

@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInConditions {
else {
return;
};
let complex_block_message = &format!(
let complex_block_message = format!(
"in {desc}, avoid complex blocks or closures with blocks; \
instead, move the block or closure higher and bind it with a `let`",
);
@ -141,7 +141,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInConditions {
let ex = &body.value;
if let ExprKind::Block(block, _) = ex.kind {
if !body.value.span.from_expansion() && !block.stmts.is_empty() {
span_lint(cx, BLOCKS_IN_CONDITIONS, ex.span, complex_block_message);
span_lint(cx, BLOCKS_IN_CONDITIONS, ex.span, complex_block_message.clone());
return ControlFlow::Continue(Descend::No);
}
}

View File

@ -121,7 +121,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
cx,
BOOL_ASSERT_COMPARISON,
macro_call.span,
&format!("used `{macro_name}!` with a literal bool"),
format!("used `{macro_name}!` with a literal bool"),
|diag| {
// assert_eq!(...)
// ^^^^^^^^^

View File

@ -392,13 +392,13 @@ fn simple_negate(b: Bool) -> Bool {
t @ Term(_) => Not(Box::new(t)),
And(mut v) => {
for el in &mut v {
*el = simple_negate(::std::mem::replace(el, True));
*el = simple_negate(std::mem::replace(el, True));
}
Or(v)
},
Or(mut v) => {
for el in &mut v {
*el = simple_negate(::std::mem::replace(el, True));
*el = simple_negate(std::mem::replace(el, True));
}
And(v)
},

View File

@ -1,6 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::macros::macro_backtrace;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::expr_sig;
use clippy_utils::{is_default_equivalent, path_def_id};
use rustc_errors::Applicability;
@ -9,20 +8,16 @@ use rustc_hir::intravisit::{walk_ty, Visitor};
use rustc_hir::{Block, Expr, ExprKind, LetStmt, Node, QPath, Ty, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::IsSuggestable;
use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
/// checks for `Box::new(T::default())`, which is better written as
/// `Box::<T>::default()`.
/// checks for `Box::new(Default::default())`, which can be written as
/// `Box::default()`.
///
/// ### Why is this bad?
/// First, it's more complex, involving two calls instead of one.
/// Second, `Box::default()` can be faster
/// [in certain cases](https://nnethercote.github.io/perf-book/standard-library-types.html#box).
/// `Box::default()` is equivalent and more concise.
///
/// ### Example
/// ```no_run
@ -34,7 +29,7 @@ declare_clippy_lint! {
/// ```
#[clippy::version = "1.66.0"]
pub BOX_DEFAULT,
perf,
style,
"Using Box::new(T::default()) instead of Box::default()"
}
@ -53,14 +48,14 @@ impl LateLintPass<'_> for BoxDefault {
&& path_def_id(cx, ty).map_or(false, |id| Some(id) == cx.tcx.lang_items().owned_box())
// And the single argument to the call is another function call
// This is the `T::default()` of `Box::new(T::default())`
&& let ExprKind::Call(arg_path, inner_call_args) = arg.kind
&& let ExprKind::Call(arg_path, _) = arg.kind
// And we are not in a foreign crate's macro
&& !in_external_macro(cx.sess(), expr.span)
// And the argument expression has the same context as the outer call expression
// or that we are inside a `vec!` macro expansion
&& (expr.span.eq_ctxt(arg.span) || is_local_vec_expn(cx, arg, expr))
// And the argument is equivalent to `Default::default()`
&& is_default_equivalent(cx, arg)
// And the argument is `Default::default()` or the type is specified
&& (is_plain_default(cx, arg_path) || (given_type(cx, expr) && is_default_equivalent(cx, arg)))
{
span_lint_and_sugg(
cx,
@ -68,25 +63,7 @@ impl LateLintPass<'_> for BoxDefault {
expr.span,
"`Box::new(_)` of default value",
"try",
if is_plain_default(cx, arg_path) || given_type(cx, expr) {
"Box::default()".into()
} else if let Some(arg_ty) =
cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true, None)
{
// Check if we can copy from the source expression in the replacement.
// We need the call to have no argument (see `explicit_default_type`).
if inner_call_args.is_empty()
&& let Some(ty) = explicit_default_type(arg_path)
&& let Some(s) = snippet_opt(cx, ty.span)
{
format!("Box::<{s}>::default()")
} else {
// Otherwise, use the inferred type's formatting.
with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()"))
}
} else {
return;
},
"Box::default()".into(),
Applicability::MachineApplicable,
);
}
@ -105,20 +82,6 @@ fn is_plain_default(cx: &LateContext<'_>, arg_path: &Expr<'_>) -> bool {
}
}
// Checks whether the call is of the form `A::B::f()`. Returns `A::B` if it is.
//
// In the event we have this kind of construct, it's easy to use `A::B` as a replacement in the
// quickfix. `f` must however have no parameter. Should `f` have some, then some of the type of
// `A::B` may be inferred from the arguments. This would be the case for `Vec::from([0; false])`,
// where the argument to `from` allows inferring this is a `Vec<bool>`
fn explicit_default_type<'a>(arg_path: &'a Expr<'_>) -> Option<&'a Ty<'a>> {
if let ExprKind::Path(QPath::TypeRelative(ty, _)) = &arg_path.kind {
Some(ty)
} else {
None
}
}
fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>) -> bool {
macro_backtrace(expr.span).next().map_or(false, |call| {
cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id) && call.span.eq_ctxt(ref_expr.span)
@ -129,7 +92,7 @@ fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>)
struct InferVisitor(bool);
impl<'tcx> Visitor<'tcx> for InferVisitor {
fn visit_ty(&mut self, t: &rustc_hir::Ty<'_>) {
fn visit_ty(&mut self, t: &Ty<'_>) {
self.0 |= matches!(t.kind, TyKind::Infer | TyKind::OpaqueDef(..) | TyKind::TraitObject(..));
if !self.0 {
walk_ty(self, t);

View File

@ -41,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, ignore_publish: b
fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, field: &str) {
let message = format!("package `{}` is missing `{field}` metadata", package.name);
span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, &message);
span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, message);
}
fn is_empty_str<T: AsRef<std::ffi::OsStr>>(value: &Option<T>) -> bool {

View File

@ -56,13 +56,13 @@ fn lint(cx: &LateContext<'_>, feature: &str, substring: &str, is_prefix: bool) {
REDUNDANT_FEATURE_NAMES
},
DUMMY_SP,
&format!(
format!(
"the \"{substring}\" {} in the feature name \"{feature}\" is {}",
if is_prefix { "prefix" } else { "suffix" },
if is_negative { "negative" } else { "redundant" }
),
None,
&format!(
format!(
"consider renaming the feature to \"{}\"{}",
if is_prefix {
feature.strip_prefix(substring)

View File

@ -102,7 +102,7 @@ fn check_table(cx: &LateContext<'_>, table: LintTable, groups: &FxHashSet<&str>,
cx,
LINT_GROUPS_PRIORITY,
toml_span(group.span(), file),
&format!(
format!(
"lint group `{}` has the same priority ({priority}) as a lint",
group.as_ref()
),

View File

@ -241,7 +241,7 @@ impl LateLintPass<'_> for Cargo {
},
Err(e) => {
for lint in NO_DEPS_LINTS {
span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {e}"));
span_lint(cx, lint, DUMMY_SP, format!("could not read cargo metadata: {e}"));
}
},
}
@ -257,7 +257,7 @@ impl LateLintPass<'_> for Cargo {
},
Err(e) => {
for lint in WITH_DEPS_LINTS {
span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {e}"));
span_lint(cx, lint, DUMMY_SP, format!("could not read cargo metadata: {e}"));
}
},
}

View File

@ -52,7 +52,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, allowed_duplicate
cx,
MULTIPLE_CRATE_VERSIONS,
DUMMY_SP,
&format!("multiple versions for dependency `{name}`: {versions}"),
format!("multiple versions for dependency `{name}`: {versions}"),
);
}
}

View File

@ -17,7 +17,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) {
cx,
WILDCARD_DEPENDENCIES,
DUMMY_SP,
&format!("wildcard dependency for `{}`", dep.name),
format!("wildcard dependency for `{}`", dep.name),
);
}
}

View File

@ -28,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
cx,
AS_PTR_CAST_MUT,
expr.span,
&format!("casting the result of `as_ptr` to *mut {ptrty}"),
format!("casting the result of `as_ptr` to *mut {ptrty}"),
"replace with",
format!("{recv}.as_mut_ptr()"),
applicability,

View File

@ -34,7 +34,7 @@ pub(super) fn check(
cx,
CAST_ABS_TO_UNSIGNED,
span,
&format!("casting the result of `{cast_from}::abs()` to {cast_to}"),
format!("casting the result of `{cast_from}::abs()` to {cast_to}"),
"replace with",
format!("{}.unsigned_abs()", Sugg::hir(cx, receiver, "..").maybe_par()),
Applicability::MachineApplicable,

View File

@ -68,7 +68,7 @@ pub(super) fn check(
cx,
CAST_LOSSLESS,
expr.span,
&message,
message,
"try",
format!("{cast_to_fmt}::from({sugg})"),
app,

View File

@ -12,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
cx,
CAST_NAN_TO_INT,
expr.span,
&format!("casting a known NaN to {to_ty}"),
format!("casting a known NaN to {to_ty}"),
None,
"this always evaluates to 0",
);

View File

@ -41,7 +41,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
})
},
BinOpKind::Rem | BinOpKind::BitAnd => get_constant_bits(cx, right)
.unwrap_or(u64::max_value())
.unwrap_or(u64::MAX)
.min(apply_reductions(cx, nbits, left, signed)),
BinOpKind::Shr => apply_reductions(cx, nbits, left, signed)
.saturating_sub(constant_int(cx, right).map_or(0, |s| u64::try_from(s).unwrap_or_default())),
@ -56,7 +56,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
} else {
None
};
apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value()))
apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::MAX))
},
ExprKind::MethodCall(method, _, [lo, hi], _) => {
if method.ident.as_str() == "clamp" {
@ -142,7 +142,7 @@ pub(super) fn check(
cx,
CAST_ENUM_TRUNCATION,
expr.span,
&format!(
format!(
"casting `{cast_from}::{}` to `{cast_to}` will truncate the value{suffix}",
variant.name,
),
@ -163,7 +163,7 @@ pub(super) fn check(
_ => return,
};
span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg, |diag| {
span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, msg, |diag| {
diag.help("if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...");
if !cast_from.is_floating_point() {
offer_suggestion(cx, expr, cast_expr, cast_to_span, diag);

View File

@ -79,7 +79,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca
),
};
span_lint_and_then(cx, CAST_POSSIBLE_WRAP, expr.span, &message, |diag| {
span_lint_and_then(cx, CAST_POSSIBLE_WRAP, expr.span, message, |diag| {
if let EmitState::LintOnPtrSize(16) = should_lint {
diag
.note("`usize` and `isize` may be as small as 16 bits on some platforms")

View File

@ -38,7 +38,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca
cx,
CAST_PRECISION_LOSS,
expr.span,
&format!(
format!(
"casting `{0}` to `{1}` causes a loss of precision {2}(`{0}` is {3} bits wide, \
but `{1}`'s mantissa is only {4} bits wide)",
cast_from,

View File

@ -48,7 +48,7 @@ fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_f
cx,
CAST_PTR_ALIGNMENT,
expr.span,
&format!(
format!(
"casting from `{cast_from}` to a more-strictly-aligned pointer (`{cast_to}`) ({} < {} bytes)",
from_layout.align.abi.bytes(),
to_layout.align.abi.bytes(),

View File

@ -47,7 +47,7 @@ pub(super) fn check<'cx>(
cx,
CAST_SIGN_LOSS,
expr.span,
&format!("casting `{cast_from}` to `{cast_to}` may lose the sign of the value"),
format!("casting `{cast_from}` to `{cast_to}` may lose the sign of the value"),
);
}
}
@ -118,7 +118,7 @@ enum Sign {
Uncertain,
}
fn expr_sign<'cx>(cx: &LateContext<'cx>, expr: &Expr<'_>, ty: impl Into<Option<Ty<'cx>>>) -> Sign {
fn expr_sign<'cx, 'tcx>(cx: &LateContext<'cx>, mut expr: &'tcx Expr<'tcx>, ty: impl Into<Option<Ty<'cx>>>) -> Sign {
// Try evaluate this expr first to see if it's positive
if let Some(val) = get_const_signed_int_eval(cx, expr, ty) {
return if val >= 0 { Sign::ZeroOrPositive } else { Sign::Negative };
@ -134,11 +134,12 @@ fn expr_sign<'cx>(cx: &LateContext<'cx>, expr: &Expr<'_>, ty: impl Into<Option<T
// Peel unwrap(), expect(), etc.
while let Some(&found_name) = METHODS_UNWRAP.iter().find(|&name| &method_name == name)
&& let Some(arglist) = method_chain_args(expr, &[found_name])
&& let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind
&& let ExprKind::MethodCall(inner_path, recv, ..) = &arglist[0].0.kind
{
// The original type has changed, but we can't use `ty` here anyway, because it has been
// moved.
method_name = inner_path.ident.name.as_str();
expr = recv;
}
if METHODS_POW.iter().any(|&name| method_name == name)

View File

@ -35,7 +35,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv
cx,
CAST_SLICE_DIFFERENT_SIZES,
expr.span,
&format!(
format!(
"casting between raw pointers to `[{}]` (element size {from_size}) and `[{}]` (element size {to_size}) does not adjust the count",
start_ty.ty, end_ty.ty,
),

View File

@ -46,7 +46,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
cx,
CAST_SLICE_FROM_RAW_PARTS,
span,
&format!("casting the result of `{func}` to {cast_to}"),
format!("casting the result of `{func}` to {cast_to}"),
"replace with",
format!("core::ptr::slice_{func}({ptr}, {len})"),
applicability,

View File

@ -25,7 +25,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
cx,
FN_TO_NUMERIC_CAST,
expr.span,
&format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
"try",
format!("{from_snippet} as usize"),
applicability,

View File

@ -23,7 +23,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
cx,
FN_TO_NUMERIC_CAST_ANY,
expr.span,
&format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
"did you mean to invoke the function?",
format!("{from_snippet}() as {cast_to}"),
applicability,

View File

@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
cx,
FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
expr.span,
&format!("casting function pointer `{from_snippet}` to `{cast_to}`, which truncates the value"),
format!("casting function pointer `{from_snippet}` to `{cast_to}`, which truncates the value"),
"try",
format!("{from_snippet} as usize"),
applicability,

View File

@ -62,8 +62,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
// we omit following `cast`:
let omit_cast = if let ExprKind::Call(func, []) = cast_expr.kind
&& let ExprKind::Path(ref qpath @ QPath::Resolved(None, path)) = func.kind
&& let Some(method_defid) = path.res.opt_def_id()
{
let method_defid = path.res.def_id();
if cx.tcx.is_diagnostic_item(sym::ptr_null, method_defid) {
OmitFollowedCastReason::Null(qpath)
} else if cx.tcx.is_diagnostic_item(sym::ptr_null_mut, method_defid) {

View File

@ -36,7 +36,7 @@ pub(super) fn check<'tcx>(
PTR_CAST_CONSTNESS,
expr.span,
"`as` casting between raw pointers while changing only its constness",
&format!("try `pointer::cast_{constness}`, a safer alternative"),
format!("try `pointer::cast_{constness}`, a safer alternative"),
format!("{}.cast_{constness}()", sugg.maybe_par()),
Applicability::MachineApplicable,
);

View File

@ -51,7 +51,7 @@ pub(super) fn check<'tcx>(
cx,
UNNECESSARY_CAST,
expr.span,
&format!(
format!(
"casting raw pointers to the same type and constness is unnecessary (`{cast_from}` -> `{cast_to}`)"
),
"try",
@ -166,7 +166,7 @@ pub(super) fn check<'tcx>(
cx,
UNNECESSARY_CAST,
expr.span,
&format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"),
format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"),
"try",
if needs_block {
format!("{{ {cast_str} }}")
@ -209,7 +209,7 @@ fn lint_unnecessary_cast(
cx,
UNNECESSARY_CAST,
expr.span,
&format!("casting {literal_kind_name} literal to `{cast_to}` is unnecessary"),
format!("casting {literal_kind_name} literal to `{cast_to}` is unnecessary"),
"try",
sugg,
Applicability::MachineApplicable,

View File

@ -121,7 +121,7 @@ impl CognitiveComplexity {
cx,
COGNITIVE_COMPLEXITY,
fn_span,
&format!(
format!(
"the function has a cognitive complexity of ({cc}/{})",
self.limit.limit()
),

View File

@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead {
}
}
fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>, collections: &[rustc_span::Symbol]) -> bool {
fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>, collections: &[Symbol]) -> bool {
let ty = cx.typeck_results().pat_ty(local.pat);
collections.iter().any(|&sym| is_type_diagnostic_item(cx, ty, sym))
// String type is a lang item but not a diagnostic item for now so we need a separate check

View File

@ -254,6 +254,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::large_include_file::LARGE_INCLUDE_FILE_INFO,
crate::large_stack_arrays::LARGE_STACK_ARRAYS_INFO,
crate::large_stack_frames::LARGE_STACK_FRAMES_INFO,
crate::legacy_numeric_constants::LEGACY_NUMERIC_CONSTANTS_INFO,
crate::len_zero::COMPARISON_TO_EMPTY_INFO,
crate::len_zero::LEN_WITHOUT_IS_EMPTY_INFO,
crate::len_zero::LEN_ZERO_INFO,
@ -678,6 +679,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::trait_bounds::TYPE_REPETITION_IN_BOUNDS_INFO,
crate::transmute::CROSSPOINTER_TRANSMUTE_INFO,
crate::transmute::EAGER_TRANSMUTE_INFO,
crate::transmute::MISSING_TRANSMUTE_ANNOTATIONS_INFO,
crate::transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS_INFO,
crate::transmute::TRANSMUTE_BYTES_TO_STR_INFO,
crate::transmute::TRANSMUTE_FLOAT_TO_INT_INFO,

View File

@ -100,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
cx,
DEFAULT_TRAIT_ACCESS,
expr.span,
&format!("calling `{replacement}` is more clear than this expression"),
format!("calling `{replacement}` is more clear than this expression"),
"try",
replacement,
Applicability::Unspecified, // First resolve the TODO above
@ -243,7 +243,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
first_assign.unwrap().span,
"field assignment outside of initializer for an instance created with Default::default()",
Some(local.span),
&format!("consider initializing the variable with `{sugg}` and removing relevant reassignments"),
format!("consider initializing the variable with `{sugg}` and removing relevant reassignments"),
);
self.reassigned_linted.insert(span);
}

View File

@ -56,7 +56,7 @@ fn is_alias(ty: hir::Ty<'_>) -> bool {
impl LateLintPass<'_> for DefaultConstructedUnitStructs {
fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
if let hir::ExprKind::Call(fn_expr, &[]) = expr.kind
if let ExprKind::Call(fn_expr, &[]) = expr.kind
// make sure we have a call to `Default::default`
&& let ExprKind::Path(ref qpath @ hir::QPath::TypeRelative(base, _)) = fn_expr.kind
// make sure this isn't a type alias:

View File

@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty {
cx,
DEFAULT_INSTEAD_OF_ITER_EMPTY,
expr.span,
&format!("`{path}()` is the more idiomatic way"),
format!("`{path}()` is the more idiomatic way"),
"try",
sugg,
applicability,
@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty {
fn make_sugg(
cx: &LateContext<'_>,
ty_path: &rustc_hir::QPath<'_>,
ty_path: &QPath<'_>,
ctxt: SyntaxContext,
applicability: &mut Applicability,
path: &str,

View File

@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultUnionRepresentation {
item.span,
"this union has the default representation",
None,
&format!(
format!(
"consider annotating `{}` with `#[repr(C)]` to explicitly specify memory layout",
cx.tcx.def_path_str(item.owner_id)
),

View File

@ -79,7 +79,7 @@ fn is_path_self(e: &Expr<'_>) -> bool {
fn contains_trait_object(ty: Ty<'_>) -> bool {
match ty.kind() {
ty::Ref(_, ty, _) => contains_trait_object(*ty),
ty::Adt(def, args) => def.is_box() && args[0].as_type().map_or(false, contains_trait_object),
Adt(def, args) => def.is_box() && args[0].as_type().map_or(false, contains_trait_object),
ty::Dynamic(..) => true,
_ => false,
}

View File

@ -11,8 +11,7 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_middle::traits::Reveal;
use rustc_middle::ty::{
self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, ToPredicate, TraitPredicate, Ty,
TyCtxt,
self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, ToPredicate, TraitPredicate, Ty, TyCtxt,
};
use rustc_session::declare_lint_pass;
use rustc_span::def_id::LocalDefId;

View File

@ -102,11 +102,11 @@ impl DisallowedMacros {
DISALLOWED_MACROS,
cx.tcx.local_def_id_to_hir_id(derive_src.def_id),
mac.span,
&msg,
msg,
add_note,
);
} else {
span_lint_and_then(cx, DISALLOWED_MACROS, mac.span, &msg, add_note);
span_lint_and_then(cx, DISALLOWED_MACROS, mac.span, msg, add_note);
}
}
}

View File

@ -99,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
None => return,
};
let msg = format!("use of a disallowed method `{}`", conf.path());
span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, &msg, |diag| {
span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, msg, |diag| {
if let Some(reason) = conf.reason() {
diag.note(reason);
}

View File

@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedNames {
cx,
DISALLOWED_NAMES,
ident.span,
&format!("use of a disallowed/placeholder name `{}`", ident.name),
format!("use of a disallowed/placeholder name `{}`", ident.name),
);
}
}

View File

@ -98,7 +98,7 @@ impl EarlyLintPass for DisallowedScriptIdents {
cx,
DISALLOWED_SCRIPT_IDENTS,
span,
&format!(
format!(
"identifier `{symbol_str}` has a Unicode script that is not allowed by configuration: {}",
script.full_name()
),

View File

@ -127,7 +127,7 @@ fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &DisallowedPath) {
cx,
DISALLOWED_TYPES,
span,
&format!("`{name}` is not allowed according to config"),
format!("`{name}` is not allowed according to config"),
|diag| {
if let Some(reason) = conf.reason() {
diag.note(reason);

View File

@ -129,9 +129,9 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
cx,
lint,
expr.span,
&msg,
msg,
note_span,
&format!("argument has type `{arg_ty}`"),
format!("argument has type `{arg_ty}`"),
);
}
}

View File

@ -119,7 +119,7 @@ impl EarlyLintPass for DuplicateMod {
cx,
DUPLICATE_MOD,
multi_span,
&format!("file is loaded as a module multiple times: `{}`", local_path.display()),
format!("file is loaded as a module multiple times: `{}`", local_path.display()),
None,
"replace all but one `mod` item with `use` items",
);

View File

@ -197,7 +197,7 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix
cx,
lint.as_lint(),
expr.span,
&format!(
format!(
"usage of the {}`{ty}::{}`{}",
if prefix == Prefix::From { "function " } else { "" },
lint.as_name(prefix),

View File

@ -186,7 +186,7 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
cx,
MAP_ENTRY,
expr.span,
&format!("usage of `contains_key` followed by `insert` on a `{}`", map_ty.name()),
format!("usage of `contains_key` followed by `insert` on a `{}`", map_ty.name()),
"try",
sugg,
app,

View File

@ -177,7 +177,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
}
}
fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
}
impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {

View File

@ -3,14 +3,14 @@ use clippy_utils::higher::VecArgs;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::type_diagnostic_name;
use clippy_utils::usage::{local_used_after_expr, local_used_in};
use clippy_utils::{get_path_from_caller_to_method_type, higher, is_adjusted, path_to_local, path_to_local_id};
use clippy_utils::{get_path_from_caller_to_method_type, is_adjusted, path_to_local, path_to_local_id};
use rustc_errors::Applicability;
use rustc_hir::{BindingAnnotation, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, TyKind, Unsafety};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{
self, Binder, ClosureArgs, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, RegionKind,
Ty, TypeVisitableExt, TypeckResults,
self, Binder, ClosureArgs, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, RegionKind, Ty,
TypeVisitableExt, TypeckResults,
};
use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
if body.value.span.from_expansion() {
if body.params.is_empty() {
if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, body.value) {
if let Some(VecArgs::Vec(&[])) = VecArgs::hir(cx, body.value) {
// replace `|| vec![]` with `Vec::new`
span_lint_and_sugg(
cx,

View File

@ -120,7 +120,7 @@ impl ExcessiveBools {
cx,
FN_PARAMS_EXCESSIVE_BOOLS,
span,
&format!("more than {} bools in function parameters", self.max_fn_params_bools),
format!("more than {} bools in function parameters", self.max_fn_params_bools),
None,
"consider refactoring bools into two-variant enums",
);
@ -145,7 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
cx,
STRUCT_EXCESSIVE_BOOLS,
item.span,
&format!("more than {} bools in a struct", self.max_struct_bools),
format!("more than {} bools in a struct", self.max_struct_bools),
None,
"consider using a state machine or refactoring bools into two-variant enums",
);

View File

@ -38,7 +38,7 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
/// Warns on any exported `structs`s that are not tagged `#[non_exhaustive]`
/// Warns on any exported `struct`s that are not tagged `#[non_exhaustive]`
///
/// ### Why is this bad?
/// Exhaustive structs are typically fine, but a project which does

View File

@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
cx,
EXPLICIT_WRITE,
expr.span,
&format!("use of `{used}.unwrap()`"),
format!("use of `{used}.unwrap()`"),
"try",
format!("{prefix}{sugg_mac}!({inputs_snippet})"),
applicability,

View File

@ -110,11 +110,11 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
.map_or(param.span, |bound_span| param.span.with_hi(bound_span.hi()))
}
fn emit_help(&self, spans: Vec<Span>, msg: &str, help: &'static str) {
fn emit_help(&self, spans: Vec<Span>, msg: String, help: &'static str) {
span_lint_and_help(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, spans, msg, None, help);
}
fn emit_sugg(&self, spans: Vec<Span>, msg: &str, help: &'static str) {
fn emit_sugg(&self, spans: Vec<Span>, msg: String, help: &'static str) {
let suggestions: Vec<(Span, String)> = spans.iter().copied().zip(std::iter::repeat(String::new())).collect();
span_lint_and_then(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, spans, msg, |diag| {
diag.multipart_suggestion(help, suggestions, Applicability::MachineApplicable);
@ -167,7 +167,7 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
.iter()
.map(|(_, param)| self.get_bound_span(param))
.collect::<Vec<_>>();
self.emit_help(spans, &msg, help);
self.emit_help(spans, msg, help);
} else {
let spans = if explicit_params.len() == extra_params.len() {
vec![self.generics.span] // Remove the entire list of generics
@ -196,7 +196,7 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
})
.collect()
};
self.emit_sugg(spans, &msg, help);
self.emit_sugg(spans, msg, help);
};
}
}

View File

@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
LitFloatType::Unsuffixed => None,
};
let (is_whole, is_inf, mut float_str) = match fty {
FloatTy::F16 => {
FloatTy::F16 | FloatTy::F128 => {
// FIXME(f16_f128): do a check like the others when parsing is available
return;
},
@ -97,10 +97,6 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
(value.fract() == 0.0, value.is_infinite(), formatter.format(value))
},
FloatTy::F128 => {
// FIXME(f16_f128): do a check like the others when parsing is available
return;
},
};
if is_inf {

View File

@ -552,9 +552,9 @@ fn is_testing_negative(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -
/// Returns true iff expr is some zero literal
fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
match constant_simple(cx, cx.typeck_results(), expr) {
Some(Constant::Int(i)) => i == 0,
Some(Constant::F32(f)) => f == 0.0,
Some(Constant::F64(f)) => f == 0.0,
Some(Int(i)) => i == 0,
Some(F32(f)) => f == 0.0,
Some(F64(f)) => f == 0.0,
_ => false,
}
}

View File

@ -401,7 +401,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> {
self.cx,
FORMAT_IN_FORMAT_ARGS,
self.macro_call.span,
&format!("`format!` in `{name}!` args"),
format!("`format!` in `{name}!` args"),
|diag| {
diag.help(format!(
"combine the `format!(..)` arguments with the outer `{name}!(..)` call"
@ -431,7 +431,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> {
cx,
TO_STRING_IN_FORMAT_ARGS,
to_string_span.with_lo(receiver.span.hi()),
&format!("`to_string` applied to a type that implements `Display` in `{name}!` args"),
format!("`to_string` applied to a type that implements `Display` in `{name}!` args"),
"remove this",
String::new(),
Applicability::MachineApplicable,
@ -441,7 +441,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> {
cx,
TO_STRING_IN_FORMAT_ARGS,
value.span,
&format!("`to_string` applied to a type that implements `Display` in `{name}!` args"),
format!("`to_string` applied to a type that implements `Display` in `{name}!` args"),
"use this",
format!(
"{}{:*>n_needed_derefs$}{receiver_snippet}",

View File

@ -214,7 +214,7 @@ impl<'a, 'tcx> FormatImplExpr<'a, 'tcx> {
self.cx,
RECURSIVE_FORMAT_IMPL,
self.expr.span,
&format!("using `self` as `{name}` in `impl {name}` will cause infinite recursion"),
format!("using `self` as `{name}` in `impl {name}` will cause infinite recursion"),
);
}
}
@ -235,7 +235,7 @@ impl<'a, 'tcx> FormatImplExpr<'a, 'tcx> {
self.cx,
PRINT_IN_FORMAT_IMPL,
macro_call.span,
&format!("use of `{name}!` in `{}` impl", self.format_trait_impl.name),
format!("use of `{name}!` in `{}` impl", self.format_trait_impl.name),
"replace with",
if let Some(formatter_name) = self.format_trait_impl.formatter_name {
format!("{replacement}!({formatter_name}, ..)")

View File

@ -151,12 +151,12 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) {
cx,
SUSPICIOUS_ASSIGNMENT_FORMATTING,
eqop_span,
&format!(
format!(
"this looks like you are trying to use `.. {op}= ..`, but you \
really are doing `.. = ({op} ..)`"
),
None,
&format!("to remove this lint, use either `{op}=` or `= {op}`"),
format!("to remove this lint, use either `{op}=` or `= {op}`"),
);
}
}
@ -187,12 +187,12 @@ fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) {
cx,
SUSPICIOUS_UNARY_OP_FORMATTING,
eqop_span,
&format!(
format!(
"by not having a space between `{binop_str}` and `{unop_str}` it looks like \
`{binop_str}{unop_str}` is a single operator"
),
None,
&format!("put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`"),
format!("put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`"),
);
}
}
@ -215,6 +215,7 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
// its bad when there is a \n after the “else”
&& let Some(else_snippet) = snippet_opt(cx, else_span)
&& let Some((pre_else, post_else)) = else_snippet.split_once("else")
&& !else_snippet.contains('/')
&& let Some((_, post_else_post_eol)) = post_else.split_once('\n')
{
// Allow allman style braces `} \n else \n {`
@ -238,9 +239,9 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
cx,
SUSPICIOUS_ELSE_FORMATTING,
else_span,
&format!("this is an `else {else_desc}` but the formatting might hide it"),
format!("this is an `else {else_desc}` but the formatting might hide it"),
None,
&format!(
format!(
"to remove this lint, remove the `else` or remove the new line between \
`else` and `{else_desc}`",
),
@ -308,9 +309,9 @@ fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) {
cx,
SUSPICIOUS_ELSE_FORMATTING,
else_span,
&format!("this looks like {looks_like} but the `else` is missing"),
format!("this looks like {looks_like} but the `else` is missing"),
None,
&format!("to remove this lint, add the missing `else` or add a new line before {next_thing}",),
format!("to remove this lint, add the missing `else` or add a new line before {next_thing}",),
);
}
}

View File

@ -4,7 +4,7 @@ use clippy_utils::ty::is_c_void;
use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{RawPtr};
use rustc_middle::ty::RawPtr;
use rustc_session::declare_lint_pass;
use rustc_span::sym;
@ -52,7 +52,7 @@ impl LateLintPass<'_> for FromRawWithVoidPtr {
cx,
FROM_RAW_WITH_VOID_PTR,
expr.span,
&msg,
msg,
Some(arg.span),
"cast this to a pointer of the appropriate type",
);

View File

@ -142,7 +142,7 @@ fn check_must_use_candidate<'tcx>(
item_span: Span,
item_id: hir::OwnerId,
fn_span: Span,
msg: &str,
msg: &'static str,
) {
if has_mutable_arg(cx, body)
|| mutates_static(cx, body)
@ -207,9 +207,7 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, tys: &mut DefIdSet)
},
ty::Tuple(args) => args.iter().any(|ty| is_mutable_ty(cx, ty, tys)),
ty::Array(ty, _) | ty::Slice(ty) => is_mutable_ty(cx, ty, tys),
ty::RawPtr(ty, mutbl) | ty::Ref(_, ty, mutbl) => {
mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, tys)
},
ty::RawPtr(ty, mutbl) | ty::Ref(_, ty, mutbl) => mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, tys),
// calling something constitutes a side effect, so return true on all callables
// also never calls need not be used, so return true for them, too
_ => true,

View File

@ -2,7 +2,7 @@ use rustc_errors::Diag;
use rustc_hir as hir;
use rustc_lint::{LateContext, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Adt, Ty};
use rustc_middle::ty::{Adt, Ty};
use rustc_span::{sym, Span};
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
@ -25,7 +25,7 @@ fn result_err_ty<'tcx>(
.tcx
.instantiate_bound_regions_with_erased(cx.tcx.fn_sig(id).instantiate_identity().output())
&& is_type_diagnostic_item(cx, ty, sym::Result)
&& let ty::Adt(_, args) = ty.kind()
&& let Adt(_, args) = ty.kind()
{
let err_ty = args.type_at(1);
Some((hir_ty, err_ty))

View File

@ -59,7 +59,7 @@ fn check_arg_number(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, fn_span: Span,
cx,
TOO_MANY_ARGUMENTS,
fn_span,
&format!("this function has too many arguments ({args}/{too_many_arguments_threshold})"),
format!("this function has too many arguments ({args}/{too_many_arguments_threshold})"),
);
}
}

View File

@ -77,7 +77,7 @@ pub(super) fn check_fn(
cx,
TOO_MANY_LINES,
span,
&format!("this function has too many lines ({line_count}/{too_many_lines_threshold})"),
format!("this function has too many lines ({line_count}/{too_many_lines_threshold})"),
);
}
}

View File

@ -117,9 +117,9 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
cx,
IF_THEN_SOME_ELSE_NONE,
expr.span,
&format!("this could be simplified with `bool::{method_name}`"),
format!("this could be simplified with `bool::{method_name}`"),
None,
&help,
help,
);
}
}

View File

@ -141,7 +141,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
cx,
IMPLICIT_HASHER,
target.span(),
&format!(
format!(
"impl for `{}` should be generalized over different hashers",
target.type_name()
),
@ -187,7 +187,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
cx,
IMPLICIT_HASHER,
target.span(),
&format!(
format!(
"parameter of type `{}` should be generalized over different hashers",
target.type_name()
),

View File

@ -56,7 +56,7 @@ fn emit_lint(
index: usize,
// The bindings that were implied, used for suggestion purposes since removing a bound with associated types
// means we might need to then move it to a different bound
implied_bindings: &[rustc_hir::TypeBinding<'_>],
implied_bindings: &[TypeBinding<'_>],
bound: &ImplTraitBound<'_>,
) {
let implied_by = snippet(cx, bound.span, "..");
@ -65,7 +65,7 @@ fn emit_lint(
cx,
IMPLIED_BOUNDS_IN_IMPLS,
poly_trait.span,
&format!("this bound is already specified as the supertrait of `{implied_by}`"),
format!("this bound is already specified as the supertrait of `{implied_by}`"),
|diag| {
// If we suggest removing a bound, we may also need to extend the span
// to include the `+` token that is ahead or behind,

View File

@ -33,7 +33,7 @@ declare_clippy_lint! {
///
/// To fix this problem, either increase your MSRV or use another item
/// available in your current MSRV.
#[clippy::version = "1.77.0"]
#[clippy::version = "1.78.0"]
pub INCOMPATIBLE_MSRV,
suspicious,
"ensures that all items used in the crate are available for the current MSRV"
@ -104,7 +104,7 @@ impl IncompatibleMsrv {
cx,
INCOMPATIBLE_MSRV,
span,
&format!(
format!(
"current MSRV (Minimum Supported Rust Version) is `{}` but this item is stable since `{version}`",
self.msrv
),

View File

@ -132,20 +132,20 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) {
cx,
INHERENT_TO_STRING_SHADOW_DISPLAY,
item.span,
&format!(
format!(
"type `{self_type}` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`"
),
None,
&format!("remove the inherent method from type `{self_type}`"),
format!("remove the inherent method from type `{self_type}`"),
);
} else {
span_lint_and_help(
cx,
INHERENT_TO_STRING,
item.span,
&format!("implementation of inherent method `to_string(&self) -> String` for type `{self_type}`"),
format!("implementation of inherent method `to_string(&self) -> String` for type `{self_type}`"),
None,
&format!("implement trait `Display` for type `{self_type}` instead"),
format!("implement trait `Display` for type `{self_type}` instead"),
);
}
}

View File

@ -51,7 +51,7 @@ fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) {
cx,
INLINE_FN_WITHOUT_BODY,
attr.span,
&format!("use of `#[inline]` on trait method `{name}` which has no body"),
format!("use of `#[inline]` on trait method `{name}` which has no body"),
|diag| {
diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable);
},

View File

@ -1,5 +1,5 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::{self, span_lint_and_sugg};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_context;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty;
@ -149,7 +149,7 @@ fn print_unchecked_duration_subtraction_sugg(
let left_expr = snippet_with_context(cx, left_expr.span, ctxt, "<instant>", &mut applicability).0;
let right_expr = snippet_with_context(cx, right_expr.span, ctxt, "<duration>", &mut applicability).0;
diagnostics::span_lint_and_sugg(
span_lint_and_sugg(
cx,
UNCHECKED_DURATION_SUBTRACTION,
expr.span,

View File

@ -43,7 +43,7 @@ impl LateLintPass<'_> for IntegerDivisionRemainderUsed {
cx,
INTEGER_DIVISION_REMAINDER_USED,
expr.span.source_callsite(),
&format!("use of {} has been disallowed in this context", op.node.as_str()),
format!("use of {} has been disallowed in this context", op.node.as_str()),
);
}
}

View File

@ -76,7 +76,7 @@ fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, alwa
cx,
INVALID_UPCAST_COMPARISONS,
span,
&format!(
format!(
"because of the numeric bounds on `{}` prior to casting, this expression is always {}",
snippet(cx, cast_val.span, "the expression"),
if always { "true" } else { "false" },
@ -88,7 +88,7 @@ fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, alwa
fn upcast_comparison_bounds_err<'tcx>(
cx: &LateContext<'tcx>,
span: Span,
rel: comparisons::Rel,
rel: Rel,
lhs_bounds: Option<(FullInt, FullInt)>,
lhs: &'tcx Expr<'_>,
rhs: &'tcx Expr<'_>,

View File

@ -240,9 +240,9 @@ fn check_fields(cx: &LateContext<'_>, threshold: u64, item: &Item<'_>, fields: &
cx,
STRUCT_FIELD_NAMES,
item.span,
&format!("all fields have the same {what}fix: `{value}`"),
format!("all fields have the same {what}fix: `{value}`"),
None,
&format!("remove the {what}fixes"),
format!("remove the {what}fixes"),
);
}
}
@ -370,9 +370,9 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n
cx,
ENUM_VARIANT_NAMES,
span,
&format!("all variants have the same {what}fix: `{value}`"),
format!("all variants have the same {what}fix: `{value}`"),
None,
&format!(
format!(
"remove the {what}fixes and use full paths to \
the variants instead of glob imports"
),

View File

@ -84,7 +84,7 @@ fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefI
cx,
ITER_NOT_RETURNING_ITERATOR,
sig.span,
&format!("this method is named `{name}` but its return type does not implement `Iterator`"),
format!("this method is named `{name}` but its return type does not implement `Iterator`"),
);
}
}

View File

@ -182,7 +182,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter {
cx,
INTO_ITER_WITHOUT_ITER,
item.span,
&format!("`IntoIterator` implemented for a reference type without an `{expected_method_name}` method"),
format!("`IntoIterator` implemented for a reference type without an `{expected_method_name}` method"),
|diag| {
// The suggestion forwards to the `IntoIterator` impl and uses a form of UFCS
// to avoid name ambiguities, as there might be an inherent into_iter method
@ -258,7 +258,7 @@ impl {self_ty_without_ref} {{
cx,
ITER_WITHOUT_INTO_ITER,
item.span,
&format!(
format!(
"`{}` method without an `IntoIterator` impl for `{self_ty_snippet}`",
item.ident
),

View File

@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeFuture {
cx,
LARGE_FUTURES,
expr.span,
&format!("large future with a size of {} bytes", size.bytes()),
format!("large future with a size of {} bytes", size.bytes()),
"consider `Box::pin` on it",
format!("Box::pin({})", snippet(cx, expr.span, "..")),
Applicability::Unspecified,

Some files were not shown because too many files have changed in this diff Show More