From 6e0c456ec4a05ebacf23039af797dbcfff49086c Mon Sep 17 00:00:00 2001
From: Peter Jaszkowiak
Date: Fri, 15 Sep 2023 21:56:10 -0600
Subject: [PATCH 01/43] triagebot no-merges: exclude "Rustup"s, add labels
---
triagebot.toml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/triagebot.toml b/triagebot.toml
index 6856bb0ab3759..419b3c30deb0a 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -11,6 +11,8 @@ allow-unauthenticated = [
# Have rustbot inform users about the *No Merge Policy*
[no-merges]
+exclude_titles = ["Rustup"] # exclude syncs from rust-lang/rust
+labels = ["has-merge-commits", "S-waiting-on-author"]
[autolabel."S-waiting-on-review"]
new_pr = true
From 77c121e8172377ca5a978a2f107735847dea33ed Mon Sep 17 00:00:00 2001
From: Taiki Endo
Date: Wed, 20 Sep 2023 19:05:51 +0900
Subject: [PATCH 02/43] Warn missing_enforced_import_renames by default
---
clippy_lints/src/missing_enforced_import_rename.rs | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs
index 96d83e114a410..fc088710e4295 100644
--- a/clippy_lints/src/missing_enforced_import_rename.rs
+++ b/clippy_lints/src/missing_enforced_import_rename.rs
@@ -17,6 +17,9 @@ declare_clippy_lint! {
/// Checks for imports that do not rename the item as specified
/// in the `enforce-import-renames` config option.
///
+ /// Note: Even though this lint is warn-by-default, it will only trigger if
+ /// import renames are defined in the clippy.toml file.
+ ///
/// ### Why is this bad?
/// Consistency is important, if a project has defined import
/// renames they should be followed. More practically, some item names are too
@@ -38,7 +41,7 @@ declare_clippy_lint! {
/// ```
#[clippy::version = "1.55.0"]
pub MISSING_ENFORCED_IMPORT_RENAMES,
- restriction,
+ style,
"enforce import renames"
}
From faacd55741785b17d6bdbe3f3319ee6e3079ccab Mon Sep 17 00:00:00 2001
From: Ikko Eltociear Ashimine
Date: Thu, 5 Oct 2023 00:03:04 +0900
Subject: [PATCH 03/43] Fix typo in attrs.rs
documenation -> documentation
---
clippy_lints/src/attrs.rs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs
index 0546807bac4fb..db01ddbde04e3 100644
--- a/clippy_lints/src/attrs.rs
+++ b/clippy_lints/src/attrs.rs
@@ -183,7 +183,7 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
- /// Checks for empty lines after documenation comments.
+ /// Checks for empty lines after documentation comments.
///
/// ### Why is this bad?
/// The documentation comment was most likely meant to be an inner attribute or regular comment.
@@ -795,7 +795,7 @@ impl EarlyLintPass for EarlyAttributes {
/// Check for empty lines after outer attributes.
///
-/// Attributes and documenation comments are both considered outer attributes
+/// Attributes and documentation comments are both considered outer attributes
/// by the AST. However, the average user likely considers them to be different.
/// Checking for empty lines after each of these attributes is split into two different
/// lints but can share the same logic.
From 31fd282732e15811e916d216d5badd0a56361dd3 Mon Sep 17 00:00:00 2001
From: y21 <30553356+y21@users.noreply.github.com>
Date: Wed, 4 Oct 2023 18:07:54 +0200
Subject: [PATCH 04/43] [`get_first`]: lint on non-primitive types
---
clippy_lints/src/methods/get_first.rs | 2 --
tests/ui/get_first.fixed | 13 ++++++++++---
tests/ui/get_first.rs | 13 ++++++++++---
tests/ui/get_first.stderr | 18 ++++++++++++------
4 files changed, 32 insertions(+), 14 deletions(-)
diff --git a/clippy_lints/src/methods/get_first.rs b/clippy_lints/src/methods/get_first.rs
index ee063adac64af..e7b4564c651ef 100644
--- a/clippy_lints/src/methods/get_first.rs
+++ b/clippy_lints/src/methods/get_first.rs
@@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_slice_of_primitives;
use clippy_utils::source::snippet_with_applicability;
use if_chain::if_chain;
use rustc_ast::LitKind;
@@ -20,7 +19,6 @@ pub(super) fn check<'tcx>(
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
if cx.tcx.type_of(impl_id).instantiate_identity().is_slice();
- if let Some(_) = is_slice_of_primitives(cx, recv);
if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind;
then {
let mut app = Applicability::MachineApplicable;
diff --git a/tests/ui/get_first.fixed b/tests/ui/get_first.fixed
index b1a597fc4dd5b..a7cdd2a93baca 100644
--- a/tests/ui/get_first.fixed
+++ b/tests/ui/get_first.fixed
@@ -14,17 +14,20 @@ impl Bar {
fn main() {
let x = vec![2, 3, 5];
- let _ = x.first(); // Use x.first()
+ let _ = x.first();
+ //~^ ERROR: accessing first element with `x.get(0)`
let _ = x.get(1);
let _ = x[0];
let y = [2, 3, 5];
- let _ = y.first(); // Use y.first()
+ let _ = y.first();
+ //~^ ERROR: accessing first element with `y.get(0)`
let _ = y.get(1);
let _ = y[0];
let z = &[2, 3, 5];
- let _ = z.first(); // Use z.first()
+ let _ = z.first();
+ //~^ ERROR: accessing first element with `z.get(0)`
let _ = z.get(1);
let _ = z[0];
@@ -37,4 +40,8 @@ fn main() {
let bar = Bar { arr: [0, 1, 2] };
let _ = bar.get(0); // Do not lint, because Bar is struct.
+
+ let non_primitives = [vec![1, 2], vec![3, 4]];
+ let _ = non_primitives.first();
+ //~^ ERROR: accessing first element with `non_primitives.get(0)`
}
diff --git a/tests/ui/get_first.rs b/tests/ui/get_first.rs
index e27ee4be8c087..cca743c4bf5e0 100644
--- a/tests/ui/get_first.rs
+++ b/tests/ui/get_first.rs
@@ -14,17 +14,20 @@ impl Bar {
fn main() {
let x = vec![2, 3, 5];
- let _ = x.get(0); // Use x.first()
+ let _ = x.get(0);
+ //~^ ERROR: accessing first element with `x.get(0)`
let _ = x.get(1);
let _ = x[0];
let y = [2, 3, 5];
- let _ = y.get(0); // Use y.first()
+ let _ = y.get(0);
+ //~^ ERROR: accessing first element with `y.get(0)`
let _ = y.get(1);
let _ = y[0];
let z = &[2, 3, 5];
- let _ = z.get(0); // Use z.first()
+ let _ = z.get(0);
+ //~^ ERROR: accessing first element with `z.get(0)`
let _ = z.get(1);
let _ = z[0];
@@ -37,4 +40,8 @@ fn main() {
let bar = Bar { arr: [0, 1, 2] };
let _ = bar.get(0); // Do not lint, because Bar is struct.
+
+ let non_primitives = [vec![1, 2], vec![3, 4]];
+ let _ = non_primitives.get(0);
+ //~^ ERROR: accessing first element with `non_primitives.get(0)`
}
diff --git a/tests/ui/get_first.stderr b/tests/ui/get_first.stderr
index 56b4c29a31353..8ee66e33cc813 100644
--- a/tests/ui/get_first.stderr
+++ b/tests/ui/get_first.stderr
@@ -1,23 +1,29 @@
error: accessing first element with `x.get(0)`
--> $DIR/get_first.rs:17:13
|
-LL | let _ = x.get(0); // Use x.first()
+LL | let _ = x.get(0);
| ^^^^^^^^ help: try: `x.first()`
|
= note: `-D clippy::get-first` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::get_first)]`
error: accessing first element with `y.get(0)`
- --> $DIR/get_first.rs:22:13
+ --> $DIR/get_first.rs:23:13
|
-LL | let _ = y.get(0); // Use y.first()
+LL | let _ = y.get(0);
| ^^^^^^^^ help: try: `y.first()`
error: accessing first element with `z.get(0)`
- --> $DIR/get_first.rs:27:13
+ --> $DIR/get_first.rs:29:13
|
-LL | let _ = z.get(0); // Use z.first()
+LL | let _ = z.get(0);
| ^^^^^^^^ help: try: `z.first()`
-error: aborting due to 3 previous errors
+error: accessing first element with `non_primitives.get(0)`
+ --> $DIR/get_first.rs:45:13
+ |
+LL | let _ = non_primitives.get(0);
+ | ^^^^^^^^^^^^^^^^^^^^^ help: try: `non_primitives.first()`
+
+error: aborting due to 4 previous errors
From e6f29f1900002d980dd06778a29e73637539d928 Mon Sep 17 00:00:00 2001
From: y21 <30553356+y21@users.noreply.github.com>
Date: Wed, 4 Oct 2023 18:08:30 +0200
Subject: [PATCH 05/43] dogfood
---
clippy_lints/src/loops/same_item_push.rs | 2 +-
clippy_lints/src/manual_bits.rs | 4 ++--
clippy_lints/src/methods/search_is_some.rs | 2 +-
clippy_lints/src/missing_doc.rs | 2 +-
clippy_lints/src/needless_continue.rs | 4 ++--
clippy_lints/src/slow_vector_initialization.rs | 2 +-
clippy_lints/src/uninit_vec.rs | 2 +-
clippy_lints/src/unnecessary_map_on_constructor.rs | 4 ++--
clippy_utils/src/consts.rs | 2 +-
clippy_utils/src/higher.rs | 2 +-
10 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs
index f7b3b2358a0bd..5fffb27cda2f1 100644
--- a/clippy_lints/src/loops/same_item_push.rs
+++ b/clippy_lints/src/loops/same_item_push.rs
@@ -185,7 +185,7 @@ fn get_vec_push<'tcx>(
if let StmtKind::Semi(semi_stmt) = &stmt.kind;
if let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind;
// Figure out the parameters for the method call
- if let Some(pushed_item) = args.get(0);
+ if let Some(pushed_item) = args.first();
// Check that the method being called is push() on a Vec
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec);
if path.ident.name.as_str() == "push";
diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs
index 6c7c57ba1d6b6..552c57d5e0253 100644
--- a/clippy_lints/src/manual_bits.rs
+++ b/clippy_lints/src/manual_bits.rs
@@ -103,9 +103,9 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<
if let ExprKind::Path(ref count_func_qpath) = count_func.kind;
if let QPath::Resolved(_, count_func_path) = count_func_qpath;
- if let Some(segment_zero) = count_func_path.segments.get(0);
+ if let Some(segment_zero) = count_func_path.segments.first();
if let Some(args) = segment_zero.args;
- if let Some(GenericArg::Type(real_ty)) = args.args.get(0);
+ if let Some(GenericArg::Type(real_ty)) = args.args.first();
if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id();
if cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id);
diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs
index afdb8ce94ac43..04ddaaa2f4617 100644
--- a/clippy_lints/src/methods/search_is_some.rs
+++ b/clippy_lints/src/methods/search_is_some.rs
@@ -39,7 +39,7 @@ pub(super) fn check<'tcx>(
if search_method == "find";
if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind;
let closure_body = cx.tcx.hir().body(body);
- if let Some(closure_arg) = closure_body.params.get(0);
+ if let Some(closure_arg) = closure_body.params.first();
then {
if let hir::PatKind::Ref(..) = closure_arg.pat.kind {
Some(search_snippet.replacen('&', "", 1))
diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs
index f2773cad400cc..0629dee4f722f 100644
--- a/clippy_lints/src/missing_doc.rs
+++ b/clippy_lints/src/missing_doc.rs
@@ -67,7 +67,7 @@ impl MissingDoc {
if_chain! {
if let Some(meta) = meta;
if let MetaItemKind::List(list) = meta.kind;
- if let Some(meta) = list.get(0);
+ if let Some(meta) = list.first();
if let Some(name) = meta.ident();
then {
name.name == sym::include
diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs
index 38a75034cd314..377cbef7b99e3 100644
--- a/clippy_lints/src/needless_continue.rs
+++ b/clippy_lints/src/needless_continue.rs
@@ -189,7 +189,7 @@ fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>)
}
fn is_first_block_stmt_continue(block: &ast::Block, label: Option<&ast::Label>) -> bool {
- block.stmts.get(0).map_or(false, |stmt| match stmt.kind {
+ block.stmts.first().map_or(false, |stmt| match stmt.kind {
ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => {
if let ast::ExprKind::Continue(ref l) = e.kind {
compare_labels(label, l.as_ref())
@@ -434,7 +434,7 @@ fn erode_from_back(s: &str) -> String {
}
fn span_of_first_expr_in_block(block: &ast::Block) -> Option {
- block.stmts.get(0).map(|stmt| stmt.span)
+ block.stmts.first().map(|stmt| stmt.span)
}
#[cfg(test)]
diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs
index 9db18c2976c22..2278e41be3758 100644
--- a/clippy_lints/src/slow_vector_initialization.rs
+++ b/clippy_lints/src/slow_vector_initialization.rs
@@ -335,7 +335,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> {
fn visit_block(&mut self, block: &'tcx Block<'_>) {
if self.initialization_found {
- if let Some(s) = block.stmts.get(0) {
+ if let Some(s) = block.stmts.first() {
self.visit_stmt(s);
}
diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs
index 6756df8e716ca..72569e10f0581 100644
--- a/clippy_lints/src/uninit_vec.rs
+++ b/clippy_lints/src/uninit_vec.rs
@@ -201,7 +201,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt
let expr = peel_hir_expr_while(expr, |e| {
if let ExprKind::Block(block, _) = e.kind {
// Extract the first statement/expression
- match (block.stmts.get(0).map(|stmt| &stmt.kind), block.expr) {
+ match (block.stmts.first().map(|stmt| &stmt.kind), block.expr) {
(None, Some(expr)) => Some(expr),
(Some(StmtKind::Expr(expr) | StmtKind::Semi(expr)), _) => Some(expr),
_ => None,
diff --git a/clippy_lints/src/unnecessary_map_on_constructor.rs b/clippy_lints/src/unnecessary_map_on_constructor.rs
index 5aa057580e9d9..894de0d85c1ef 100644
--- a/clippy_lints/src/unnecessary_map_on_constructor.rs
+++ b/clippy_lints/src/unnecessary_map_on_constructor.rs
@@ -40,7 +40,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor {
let (constructor_path, constructor_item) =
if let hir::ExprKind::Call(constructor, constructor_args) = recv.kind
&& let hir::ExprKind::Path(constructor_path) = constructor.kind
- && let Some(arg) = constructor_args.get(0)
+ && let Some(arg) = constructor_args.first()
{
if constructor.span.from_expansion() || arg.span.from_expansion() {
return;
@@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor {
_ => return,
}
- if let Some(map_arg) = args.get(0)
+ if let Some(map_arg) = args.first()
&& let hir::ExprKind::Path(fun) = map_arg.kind
{
if map_arg.span.from_expansion() {
diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs
index 0bae7056c4fb8..79c04c7c7f4a3 100644
--- a/clippy_utils/src/consts.rs
+++ b/clippy_utils/src/consts.rs
@@ -504,7 +504,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
},
(Some(Constant::Vec(vec)), _) => {
if !vec.is_empty() && vec.iter().all(|x| *x == vec[0]) {
- match vec.get(0) {
+ match vec.first() {
Some(Constant::F32(x)) => Some(Constant::F32(*x)),
Some(Constant::F64(x)) => Some(Constant::F64(*x)),
_ => None,
diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs
index 802adbd4d2d56..7c1be625bd3a5 100644
--- a/clippy_utils/src/higher.rs
+++ b/clippy_utils/src/higher.rs
@@ -449,7 +449,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -
} else if name.ident.name == symbol::kw::Default {
return Some(VecInitKind::Default);
} else if name.ident.name.as_str() == "with_capacity" {
- let arg = args.get(0)?;
+ let arg = args.first()?;
return match constant_simple(cx, cx.typeck_results(), arg) {
Some(Constant::Int(num)) => Some(VecInitKind::WithConstCapacity(num)),
_ => Some(VecInitKind::WithExprCapacity(arg.hir_id)),
From 010a9b1e6056970ad9b50618f485568f49cf962b Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote
Date: Thu, 5 Oct 2023 16:08:07 +1100
Subject: [PATCH 06/43] Rename `Features::active_features`.
The word "active" is currently used in two different and confusing ways:
- `ACTIVE_FEATURES` actually means "available unstable features"
- `Features::active_features` actually means "features declared in the
crate's code", which can include feature within `ACTIVE_FEATURES` but
also others.
(This is also distinct from "enabled" features which includes declared
features but also some edition-specific features automatically enabled
depending on the edition in use.)
This commit changes the `Features::active_features` to
`Features::declared_features` which actually matches its meaning.
Likewise, `Features::active` becomes `Features::declared`.
---
clippy_lints/src/manual_float_methods.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs
index 88db7ae6aece0..15c8417e70284 100644
--- a/clippy_lints/src/manual_float_methods.rs
+++ b/clippy_lints/src/manual_float_methods.rs
@@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
if !in_external_macro(cx.sess(), expr.span)
&& (
matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst)
- || cx.tcx.features().active(sym!(const_float_classify))
+ || cx.tcx.features().declared(sym!(const_float_classify))
) && let ExprKind::Binary(kind, lhs, rhs) = expr.kind
&& let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind
&& let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind
From 9de3e6c9281e284f81515345330fb74b0c4ad312 Mon Sep 17 00:00:00 2001
From: Jason Newcomb
Date: Tue, 26 Sep 2023 23:56:38 -0400
Subject: [PATCH 07/43] Add more diagnostic items for clippy
---
clippy_lints/src/await_holding_invalid.rs | 2 +-
clippy_lints/src/box_default.rs | 14 +--
clippy_lints/src/casts/cast_ptr_alignment.rs | 19 ++--
.../src/casts/cast_slice_from_raw_parts.rs | 12 +--
clippy_lints/src/create_dir.rs | 4 +-
clippy_lints/src/default.rs | 10 +-
.../src/default_constructed_unit_structs.rs | 5 +-
.../src/default_instead_of_iter_empty.rs | 6 +-
clippy_lints/src/exit.rs | 5 +-
clippy_lints/src/explicit_write.rs | 28 +++---
clippy_lints/src/from_raw_with_void_ptr.rs | 4 +-
clippy_lints/src/instant_subtraction.rs | 6 +-
clippy_lints/src/lines_filter_map_ok.rs | 4 +-
clippy_lints/src/manual_retain.rs | 2 +-
clippy_lints/src/methods/bytecount.rs | 8 +-
clippy_lints/src/methods/clone_on_ref_ptr.rs | 19 ++--
.../methods/from_iter_instead_of_collect.rs | 4 +-
.../src/methods/inefficient_to_string.rs | 3 +-
.../src/methods/iter_out_of_bounds.rs | 10 +-
clippy_lints/src/methods/open_options.rs | 8 +-
.../src/methods/option_as_ref_deref.rs | 5 +-
clippy_lints/src/methods/seek_from_current.rs | 5 +-
.../seek_to_start_instead_of_rewind.rs | 6 +-
.../methods/suspicious_command_arg_space.rs | 7 +-
clippy_lints/src/missing_fields_in_debug.rs | 12 ++-
clippy_lints/src/needless_pass_by_value.rs | 4 +-
clippy_lints/src/non_canonical_impls.rs | 7 +-
.../src/non_octal_unix_permissions.rs | 10 +-
.../src/non_send_fields_in_send_ty.rs | 4 +-
clippy_lints/src/operators/cmp_owned.rs | 4 +-
.../src/permissions_set_readonly_false.rs | 6 +-
clippy_lints/src/ptr.rs | 94 ++++++++-----------
clippy_lints/src/rc_clone_in_vec_init.rs | 9 +-
clippy_lints/src/redundant_clone.rs | 4 +-
clippy_lints/src/size_of_in_element_count.rs | 22 ++---
clippy_lints/src/swap_ptr_to_ref.rs | 6 +-
clippy_lints/src/unnamed_address.rs | 4 +-
clippy_lints/src/unused_peekable.rs | 10 +-
clippy_lints/src/useless_conversion.rs | 4 +-
clippy_utils/src/higher.rs | 2 +-
clippy_utils/src/lib.rs | 2 +-
clippy_utils/src/paths.rs | 48 ----------
clippy_utils/src/ty.rs | 6 +-
.../unnecessary_def_path_hardcoded_path.rs | 4 +-
...unnecessary_def_path_hardcoded_path.stderr | 4 +-
45 files changed, 191 insertions(+), 271 deletions(-)
diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs
index 7dd808a7b3b73..accff9b0a34c6 100644
--- a/clippy_lints/src/await_holding_invalid.rs
+++ b/clippy_lints/src/await_holding_invalid.rs
@@ -287,5 +287,5 @@ fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool {
}
fn is_refcell_ref(cx: &LateContext<'_>, def_id: DefId) -> bool {
- match_def_path(cx, def_id, &paths::REFCELL_REF) || match_def_path(cx, def_id, &paths::REFCELL_REFMUT)
+ matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::RefCellRef | sym::RefCellRefMut))
}
diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs
index fa9c525fc08d9..3f1ff66b8cf60 100644
--- a/clippy_lints/src/box_default.rs
+++ b/clippy_lints/src/box_default.rs
@@ -1,10 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::macros::macro_backtrace;
use clippy_utils::ty::expr_sig;
-use clippy_utils::{get_parent_node, is_default_equivalent, match_path, path_def_id, paths};
+use clippy_utils::{get_parent_node, is_default_equivalent, path_def_id};
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_ty, Visitor};
-use rustc_hir::{Block, Expr, ExprKind, Local, Node, QPath, TyKind};
+use rustc_hir::{def::Res, Block, Expr, ExprKind, Local, Node, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::print::with_forced_trimmed_paths;
@@ -55,7 +55,7 @@ impl LateLintPass<'_> for BoxDefault {
expr.span,
"`Box::new(_)` of default value",
"try",
- if is_plain_default(arg_path) || given_type(cx, expr) {
+ 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) {
with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()"))
@@ -68,11 +68,13 @@ impl LateLintPass<'_> for BoxDefault {
}
}
-fn is_plain_default(arg_path: &Expr<'_>) -> bool {
+fn is_plain_default(cx: &LateContext<'_>, arg_path: &Expr<'_>) -> bool {
// we need to match the actual path so we don't match e.g. "u8::default"
- if let ExprKind::Path(QPath::Resolved(None, path)) = &arg_path.kind {
+ if let ExprKind::Path(QPath::Resolved(None, path)) = &arg_path.kind
+ && let Res::Def(_, def_id) = path.res
+ {
// avoid generic parameters
- match_path(path, &paths::DEFAULT_TRAIT_METHOD) && path.segments.iter().all(|seg| seg.args.is_none())
+ cx.tcx.is_diagnostic_item(sym::default_fn, def_id) && path.segments.iter().all(|seg| seg.args.is_none())
} else {
false
}
diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs
index 1de69122101c5..9e8ef28253741 100644
--- a/clippy_lints/src/casts/cast_ptr_alignment.rs
+++ b/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::is_c_void;
-use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, match_any_def_paths, paths};
+use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant};
use rustc_hir::{Expr, ExprKind, GenericArg};
use rustc_lint::LateContext;
use rustc_middle::ty::layout::LayoutOf;
@@ -75,16 +75,17 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
}
},
ExprKind::Call(func, [arg, ..]) if arg.hir_id == e.hir_id => {
- static PATHS: &[&[&str]] = &[
- paths::PTR_READ_UNALIGNED.as_slice(),
- paths::PTR_UNALIGNED_VOLATILE_LOAD.as_slice(),
- paths::PTR_UNALIGNED_VOLATILE_STORE.as_slice(),
- ];
-
if let ExprKind::Path(path) = &func.kind
&& let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id()
- && (match_any_def_paths(cx, def_id, PATHS).is_some()
- || cx.tcx.is_diagnostic_item(sym::ptr_write_unaligned, def_id))
+ && matches!(
+ cx.tcx.get_diagnostic_name(def_id),
+ Some(
+ sym::ptr_write_unaligned
+ | sym::ptr_read_unaligned
+ | sym::intrinsics_unaligned_volatile_load
+ | sym::intrinsics_unaligned_volatile_store
+ )
+ )
{
true
} else {
diff --git a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
index 5e0123842b041..eb0f75b2f605b 100644
--- a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
+++ b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
@@ -1,13 +1,13 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_context;
-use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
+use rustc_span::sym;
use super::CAST_SLICE_FROM_RAW_PARTS;
@@ -17,12 +17,10 @@ enum RawPartsKind {
}
fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option {
- if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS) {
- Some(RawPartsKind::Immutable)
- } else if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS_MUT) {
- Some(RawPartsKind::Mutable)
- } else {
- None
+ match cx.tcx.get_diagnostic_name(did)? {
+ sym::slice_from_raw_parts => Some(RawPartsKind::Immutable),
+ sym::slice_from_raw_parts_mut => Some(RawPartsKind::Mutable),
+ _ => None,
}
}
diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs
index 878248a6bdc8c..2bca695c43b15 100644
--- a/clippy_lints/src/create_dir.rs
+++ b/clippy_lints/src/create_dir.rs
@@ -1,11 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
-use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@@ -37,7 +37,7 @@ impl LateLintPass<'_> for CreateDir {
if let ExprKind::Call(func, [arg, ..]) = expr.kind;
if let ExprKind::Path(ref path) = func.kind;
if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id();
- if match_def_path(cx, def_id, &paths::STD_FS_CREATE_DIR);
+ if cx.tcx.is_diagnostic_item(sym::fs_create_dir, def_id);
then {
span_lint_and_sugg(
cx,
diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs
index 763ad0264ad91..5787f19cc6cb1 100644
--- a/clippy_lints/src/default.rs
+++ b/clippy_lints/src/default.rs
@@ -1,9 +1,7 @@
use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::{has_drop, is_copy};
-use clippy_utils::{
- any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro, match_def_path, paths,
-};
+use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
@@ -14,7 +12,7 @@ use rustc_middle::ty;
use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::{Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
declare_clippy_lint! {
/// ### What it does
@@ -91,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id);
if let ExprKind::Path(ref qpath) = path.kind;
if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
- if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
+ if cx.tcx.is_diagnostic_item(sym::default_fn, def_id);
if !is_update_syntax_base(cx, expr);
// Detect and ignore ::default() because these calls do explicitly name the type.
if let QPath::Resolved(None, _path) = qpath;
@@ -268,7 +266,7 @@ fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool
if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id);
then {
// right hand side of assignment is `Default::default`
- match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD)
+ cx.tcx.is_diagnostic_item(sym::default_fn, def_id)
} else {
false
}
diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs
index a294c69378774..0676777e79681 100644
--- a/clippy_lints/src/default_constructed_unit_structs.rs
+++ b/clippy_lints/src/default_constructed_unit_structs.rs
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{is_ty_alias, match_def_path, paths};
+use clippy_utils::is_ty_alias;
use hir::def::Res;
use hir::ExprKind;
use rustc_errors::Applicability;
@@ -7,6 +7,7 @@ use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@@ -63,7 +64,7 @@ impl LateLintPass<'_> for DefaultConstructedUnitStructs {
// `::Assoc` cannot be used as a constructor
if !is_alias(*base);
if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id);
- if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
+ if cx.tcx.is_diagnostic_item(sym::default_fn, def_id);
// make sure we have a struct with no fields (unit struct)
if let ty::Adt(def, ..) = cx.typeck_results().expr_ty(expr).kind();
if def.is_struct();
diff --git a/clippy_lints/src/default_instead_of_iter_empty.rs b/clippy_lints/src/default_instead_of_iter_empty.rs
index 572990aaba109..3d6d257e386b5 100644
--- a/clippy_lints/src/default_instead_of_iter_empty.rs
+++ b/clippy_lints/src/default_instead_of_iter_empty.rs
@@ -1,11 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_context;
-use clippy_utils::{last_path_segment, match_def_path, paths};
+use clippy_utils::last_path_segment;
use rustc_errors::Applicability;
use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::SyntaxContext;
+use rustc_span::{sym, SyntaxContext};
declare_clippy_lint! {
/// ### What it does
@@ -37,7 +37,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty {
&& let TyKind::Path(ty_path) = &ty.kind
&& let QPath::Resolved(None, path) = ty_path
&& let def::Res::Def(_, def_id) = &path.res
- && match_def_path(cx, *def_id, &paths::ITER_EMPTY)
+ && cx.tcx.is_diagnostic_item(sym::IterEmpty, *def_id)
&& let ctxt = expr.span.ctxt()
&& ty.span.ctxt() == ctxt
{
diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs
index 8ba6a9e48763f..5de79133c7dcc 100644
--- a/clippy_lints/src/exit.rs
+++ b/clippy_lints/src/exit.rs
@@ -1,9 +1,10 @@
use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{is_entrypoint_fn, match_def_path, paths};
+use clippy_utils::{is_entrypoint_fn};
use if_chain::if_chain;
use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@@ -45,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for Exit {
if let ExprKind::Call(path_expr, _args) = e.kind;
if let ExprKind::Path(ref path) = path_expr.kind;
if let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id();
- if match_def_path(cx, def_id, &paths::EXIT);
+ if cx.tcx.is_diagnostic_item(sym::process_exit, def_id);
let parent = cx.tcx.hir().get_parent_item(e.hir_id).def_id;
if let Some(Node::Item(Item{kind: ItemKind::Fn(..), ..})) = cx.tcx.hir().find_by_def_id(parent);
// If the next item up is a function we check if it is an entry point
diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs
index b612cc00bf97e..6f6177340f487 100644
--- a/clippy_lints/src/explicit_write.rs
+++ b/clippy_lints/src/explicit_write.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::macros::{find_format_args, format_args_inputs_span};
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_expn_of, match_function_call, paths};
+use clippy_utils::{is_expn_of, path_def_id};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
@@ -47,18 +47,19 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind
&& unwrap_fun.ident.name == sym::unwrap
// match call to write_fmt
- && let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind)
+ && let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = *look_in_block(cx, &write_call.kind)
+ && let ExprKind::Call(write_recv_path, _) = write_recv.kind
&& write_fun.ident.name == sym!(write_fmt)
- // match calls to std::io::stdout() / std::io::stderr ()
- && let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() {
- Some("stdout")
- } else if match_function_call(cx, write_recv, &paths::STDERR).is_some() {
- Some("stderr")
- } else {
- None
- }
- && let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root())
+ && let Some(def_id) = path_def_id(cx, write_recv_path)
{
+ // match calls to std::io::stdout() / std::io::stderr ()
+ let (dest_name, prefix) = match cx.tcx.get_diagnostic_name(def_id) {
+ Some(sym::io_stdout) => ("stdout", ""),
+ Some(sym::io_stderr) => ("stderr", "e"),
+ _ => return,
+ };
+ let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root()) else { return; };
+
// ordering is important here, since `writeln!` uses `write!` internally
let calling_macro = if is_expn_of(write_call.span, "writeln").is_some() {
Some("writeln")
@@ -67,11 +68,6 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
} else {
None
};
- let prefix = if dest_name == "stderr" {
- "e"
- } else {
- ""
- };
// We need to remove the last trailing newline from the string because the
// underlying `fmt::write` function doesn't know whether `println!` or `print!` was
diff --git a/clippy_lints/src/from_raw_with_void_ptr.rs b/clippy_lints/src/from_raw_with_void_ptr.rs
index 5e859d97c6242..d82ea6d2fc80e 100644
--- a/clippy_lints/src/from_raw_with_void_ptr.rs
+++ b/clippy_lints/src/from_raw_with_void_ptr.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::is_c_void;
-use clippy_utils::{match_def_path, path_def_id, paths};
+use clippy_utils::path_def_id;
use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
@@ -68,7 +68,7 @@ fn def_id_matches_type(cx: &LateContext<'_>, def_id: DefId) -> Option<&'static s
}
}
- if match_def_path(cx, def_id, &paths::WEAK_RC) || match_def_path(cx, def_id, &paths::WEAK_ARC) {
+ if matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::RcWeak | sym::ArcWeak)) {
Some("Weak")
} else {
None
diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs
index 8df7dfb8b9e5a..a1a115f6d79f6 100644
--- a/clippy_lints/src/instant_subtraction.rs
+++ b/clippy_lints/src/instant_subtraction.rs
@@ -130,11 +130,7 @@ fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool {
fn is_an_instant(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let expr_ty = cx.typeck_results().expr_ty(expr);
-
- match expr_ty.kind() {
- rustc_middle::ty::Adt(def, _) => clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT),
- _ => false,
- }
+ ty::is_type_diagnostic_item(cx, expr_ty, sym::Instant)
}
fn is_a_duration(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs
index 49425ff0a8e05..ac949b6726095 100644
--- a/clippy_lints/src/lines_filter_map_ok.rs
+++ b/clippy_lints/src/lines_filter_map_ok.rs
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::ty::match_type;
+use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{is_diag_item_method, is_trait_method, match_def_path, path_to_local_id, paths};
use rustc_errors::Applicability;
use rustc_hir::{Body, Closure, Expr, ExprKind};
@@ -62,7 +62,7 @@ impl LateLintPass<'_> for LinesFilterMapOk {
if let ExprKind::MethodCall(fm_method, fm_receiver, [fm_arg], fm_span) = expr.kind &&
is_trait_method(cx, expr, sym::Iterator) &&
(fm_method.ident.as_str() == "filter_map" || fm_method.ident.as_str() == "flat_map") &&
- match_type(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), &paths::STD_IO_LINES)
+ is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines)
{
let lint = match &fm_arg.kind {
// Detect `Result::ok`
diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs
index 1a69a48c582b0..f923413f4348b 100644
--- a/clippy_lints/src/manual_retain.rs
+++ b/clippy_lints/src/manual_retain.rs
@@ -135,7 +135,7 @@ fn check_to_owned(
if msrv.meets(msrvs::STRING_RETAIN)
&& let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
&& let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
- && match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD)
+ && cx.tcx.is_diagnostic_item(sym::to_owned_method, to_owned_def_id)
&& let hir::ExprKind::MethodCall(_, chars_expr, [_], _) = &filter_expr.kind
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
diff --git a/clippy_lints/src/methods/bytecount.rs b/clippy_lints/src/methods/bytecount.rs
index f490a71755407..35370355f8340 100644
--- a/clippy_lints/src/methods/bytecount.rs
+++ b/clippy_lints/src/methods/bytecount.rs
@@ -1,8 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::match_type;
+use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::is_local_used;
-use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs};
+use clippy_utils::{path_to_local_id, peel_blocks, peel_ref_operators, strip_pat_refs};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind};
@@ -25,9 +25,9 @@ pub(super) fn check<'tcx>(
if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind;
if let ExprKind::Binary(ref op, l, r) = body.value.kind;
if op.node == BinOpKind::Eq;
- if match_type(cx,
+ if is_type_diagnostic_item(cx,
cx.typeck_results().expr_ty(filter_recv).peel_refs(),
- &paths::SLICE_ITER);
+ sym::SliceIter);
let operand_is_arg = |expr| {
let expr = peel_ref_operators(cx, peel_blocks(expr));
path_to_local_id(expr, arg_id)
diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs
index ddf3c9f27df29..926bd06bacbd2 100644
--- a/clippy_lints/src/methods/clone_on_ref_ptr.rs
+++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs
@@ -1,7 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::paths;
use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::{is_type_diagnostic_item, match_type};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -22,15 +20,14 @@ pub(super) fn check(
}
let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
- if let ty::Adt(_, subst) = obj_ty.kind() {
- let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) {
- "Rc"
- } else if is_type_diagnostic_item(cx, obj_ty, sym::Arc) {
- "Arc"
- } else if match_type(cx, obj_ty, &paths::WEAK_RC) || match_type(cx, obj_ty, &paths::WEAK_ARC) {
- "Weak"
- } else {
- return;
+ if let ty::Adt(adt, subst) = obj_ty.kind()
+ && let Some(name) = cx.tcx.get_diagnostic_name(adt.did())
+ {
+ let caller_type = match name {
+ sym::Rc => "Rc",
+ sym::Arc => "Arc",
+ sym::RcWeak | sym::ArcWeak => "Weak",
+ _ => return,
};
// Sometimes unnecessary ::<_> after Rc/Arc/Weak
diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs
index 66dfce3682b59..4040d3a5fe13b 100644
--- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs
+++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::implements_trait;
-use clippy_utils::{is_expr_path_def_path, paths, sugg};
+use clippy_utils::{is_path_diagnostic_item, sugg};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -13,7 +13,7 @@ use super::FROM_ITER_INSTEAD_OF_COLLECT;
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>], func: &hir::Expr<'_>) {
if_chain! {
- if is_expr_path_def_path(cx, func, &paths::FROM_ITERATOR_METHOD);
+ if is_path_diagnostic_item(cx, func, sym::from_iter_fn);
let ty = cx.typeck_results().expr_ty(expr);
let arg_ty = cx.typeck_results().expr_ty(&args[0]);
if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs
index 631741d9290c8..6686d42c95f83 100644
--- a/clippy_lints/src/methods/inefficient_to_string.rs
+++ b/clippy_lints/src/methods/inefficient_to_string.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::{is_type_lang_item, walk_ptrs_ty_depth};
-use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -22,7 +21,7 @@ pub fn check(
if_chain! {
if args.is_empty() && method_name == sym::to_string;
if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD);
+ if cx.tcx.is_diagnostic_item(sym::to_string_method, to_string_meth_did);
if let Some(args) = cx.typeck_results().node_args_opt(expr.hir_id);
let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver);
let self_ty = args.type_at(0);
diff --git a/clippy_lints/src/methods/iter_out_of_bounds.rs b/clippy_lints/src/methods/iter_out_of_bounds.rs
index 79c6d63254b28..99ea7f03df4e7 100644
--- a/clippy_lints/src/methods/iter_out_of_bounds.rs
+++ b/clippy_lints/src/methods/iter_out_of_bounds.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_note;
use clippy_utils::higher::VecArgs;
-use clippy_utils::{expr_or_init, is_trait_method, match_def_path, paths};
+use clippy_utils::{expr_or_init, is_trait_method};
use rustc_ast::LitKind;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
@@ -26,14 +26,14 @@ fn get_iterator_length<'tcx>(cx: &LateContext<'tcx>, iter: &'tcx Expr<'tcx>) ->
};
let did = adt.did();
- if match_def_path(cx, did, &paths::ARRAY_INTO_ITER) {
+ if cx.tcx.is_diagnostic_item(sym::ArrayIntoIter, did) {
// For array::IntoIter, the length is the second generic
// parameter.
substs
.const_at(1)
.try_eval_target_usize(cx.tcx, cx.param_env)
.map(u128::from)
- } else if match_def_path(cx, did, &paths::SLICE_ITER)
+ } else if cx.tcx.is_diagnostic_item(sym::SliceIter, did)
&& let ExprKind::MethodCall(_, recv, ..) = iter.kind
{
if let ty::Array(_, len) = cx.typeck_results().expr_ty(recv).peel_refs().kind() {
@@ -47,9 +47,9 @@ fn get_iterator_length<'tcx>(cx: &LateContext<'tcx>, iter: &'tcx Expr<'tcx>) ->
} else {
None
}
- } else if match_def_path(cx, did, &paths::ITER_EMPTY) {
+ } else if cx.tcx.is_diagnostic_item(sym::IterEmpty, did) {
Some(0)
- } else if match_def_path(cx, did, &paths::ITER_ONCE) {
+ } else if cx.tcx.is_diagnostic_item(sym::IterOnce, did) {
Some(1)
} else {
None
diff --git a/clippy_lints/src/methods/open_options.rs b/clippy_lints/src/methods/open_options.rs
index 1c664e76d74f5..c0f5a27994515 100644
--- a/clippy_lints/src/methods/open_options.rs
+++ b/clippy_lints/src/methods/open_options.rs
@@ -1,17 +1,17 @@
use clippy_utils::diagnostics::span_lint;
-use clippy_utils::paths;
-use clippy_utils::ty::match_type;
+use clippy_utils::ty::is_type_diagnostic_item;
use rustc_ast::ast::LitKind;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_span::source_map::{Span, Spanned};
+use rustc_span::sym;
use super::NONSENSICAL_OPEN_OPTIONS;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
&& let Some(impl_id) = cx.tcx.impl_of_method(method_id)
- && match_type(cx, cx.tcx.type_of(impl_id).instantiate_identity(), &paths::OPEN_OPTIONS)
+ && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::FsOpenOptions)
{
let mut options = Vec::new();
get_open_options(cx, recv, &mut options);
@@ -40,7 +40,7 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec
let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
// Only proceed if this is a call on some object of type std::fs::OpenOptions
- if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && !arguments.is_empty() {
+ if is_type_diagnostic_item(cx, obj_ty, sym::FsOpenOptions) && !arguments.is_empty() {
let argument_option = match arguments[0].kind {
ExprKind::Lit(span) => {
if let Spanned {
diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs
index 3e33f9193374e..d0c27f9631f7a 100644
--- a/clippy_lints/src/methods/option_as_ref_deref.rs
+++ b/clippy_lints/src/methods/option_as_ref_deref.rs
@@ -32,8 +32,7 @@ pub(super) fn check(
return;
}
- let deref_aliases: [&[&str]; 8] = [
- &paths::DEREF_MUT_TRAIT_METHOD,
+ let deref_aliases: [&[&str]; 7] = [
&paths::CSTRING_AS_C_STR,
&paths::OS_STRING_AS_OS_STR,
&paths::PATH_BUF_AS_PATH,
@@ -49,6 +48,7 @@ pub(super) fn check(
.opt_def_id()
.map_or(false, |fun_def_id| {
cx.tcx.is_diagnostic_item(sym::deref_method, fun_def_id)
+ || cx.tcx.is_diagnostic_item(sym::deref_mut_method, fun_def_id)
|| deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path))
})
},
@@ -70,6 +70,7 @@ pub(super) fn check(
then {
let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap();
cx.tcx.is_diagnostic_item(sym::deref_method, method_did)
+ || cx.tcx.is_diagnostic_item(sym::deref_mut_method, method_did)
|| deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
} else {
false
diff --git a/clippy_lints/src/methods/seek_from_current.rs b/clippy_lints/src/methods/seek_from_current.rs
index f3d6a15ede01b..4ea87027a9e6f 100644
--- a/clippy_lints/src/methods/seek_from_current.rs
+++ b/clippy_lints/src/methods/seek_from_current.rs
@@ -2,18 +2,19 @@ use rustc_ast::ast::{LitIntType, LitKind};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
+use rustc_span::sym;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_trait_def_id, match_def_path, paths};
+use clippy_utils::{match_def_path, paths};
use super::SEEK_FROM_CURRENT;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) {
let ty = cx.typeck_results().expr_ty(recv);
- if let Some(def_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) {
+ if let Some(def_id) = cx.tcx.get_diagnostic_item(sym::IoSeek) {
if implements_trait(cx, ty, def_id, &[]) && arg_is_seek_from_current(cx, arg) {
let mut applicability = Applicability::MachineApplicable;
let snip = snippet_with_applicability(cx, recv.span, "..", &mut applicability);
diff --git a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
index 787e9e0ebd245..50d4de7a68007 100644
--- a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
+++ b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
@@ -1,11 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_trait_def_id, is_expr_used_or_unified, match_def_path, paths};
+use clippy_utils::{is_expr_used_or_unified, match_def_path, paths};
use rustc_ast::ast::{LitIntType, LitKind};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
-use rustc_span::Span;
+use rustc_span::{sym, Span};
use super::SEEK_TO_START_INSTEAD_OF_REWIND;
@@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(
return;
}
- if let Some(seek_trait_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) &&
+ if let Some(seek_trait_id) = cx.tcx.get_diagnostic_item(sym::IoSeek) &&
implements_trait(cx, ty, seek_trait_id, &[]) &&
let ExprKind::Call(func, args1) = arg.kind &&
let ExprKind::Path(ref path) = func.kind &&
diff --git a/clippy_lints/src/methods/suspicious_command_arg_space.rs b/clippy_lints/src/methods/suspicious_command_arg_space.rs
index bc8f017676415..8959e2c1d75f7 100644
--- a/clippy_lints/src/methods/suspicious_command_arg_space.rs
+++ b/clippy_lints/src/methods/suspicious_command_arg_space.rs
@@ -1,9 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::paths;
-use clippy_utils::ty::match_type;
+use clippy_utils::ty::is_type_diagnostic_item;
use rustc_errors::{Applicability, Diagnostic};
use rustc_lint::LateContext;
-use rustc_span::Span;
+use rustc_span::{sym, Span};
use {rustc_ast as ast, rustc_hir as hir};
use super::SUSPICIOUS_COMMAND_ARG_SPACE;
@@ -11,7 +10,7 @@ use super::SUSPICIOUS_COMMAND_ARG_SPACE;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, span: Span) {
let ty = cx.typeck_results().expr_ty(recv).peel_refs();
- if match_type(cx, ty, &paths::STD_PROCESS_COMMAND)
+ if is_type_diagnostic_item(cx, ty, sym::Command)
&& let hir::ExprKind::Lit(lit) = &arg.kind
&& let ast::LitKind::Str(s, _) = &lit.node
&& let Some((arg1, arg2)) = s.as_str().split_once(' ')
diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs
index 2f63b9b9f0b8e..f0b865be8042d 100644
--- a/clippy_lints/src/missing_fields_in_debug.rs
+++ b/clippy_lints/src/missing_fields_in_debug.rs
@@ -1,9 +1,9 @@
use std::ops::ControlFlow;
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::ty::match_type;
+use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::{for_each_expr, Visitable};
-use clippy_utils::{is_path_lang_item, paths};
+use clippy_utils::is_path_lang_item;
use rustc_ast::LitKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::{DefKind, Res};
@@ -114,9 +114,11 @@ fn should_lint<'tcx>(
if let ExprKind::MethodCall(path, recv, ..) = &expr.kind {
let recv_ty = typeck_results.expr_ty(recv).peel_refs();
- if path.ident.name == sym::debug_struct && match_type(cx, recv_ty, &paths::FORMATTER) {
+ if path.ident.name == sym::debug_struct && is_type_diagnostic_item(cx, recv_ty, sym::Formatter) {
has_debug_struct = true;
- } else if path.ident.name == sym!(finish_non_exhaustive) && match_type(cx, recv_ty, &paths::DEBUG_STRUCT) {
+ } else if path.ident.name == sym!(finish_non_exhaustive)
+ && is_type_diagnostic_item(cx, recv_ty, sym::DebugStruct)
+ {
has_finish_non_exhaustive = true;
}
}
@@ -137,7 +139,7 @@ fn as_field_call<'tcx>(
) -> Option {
if let ExprKind::MethodCall(path, recv, [debug_field, _], _) = &expr.kind
&& let recv_ty = typeck_results.expr_ty(recv).peel_refs()
- && match_type(cx, recv_ty, &paths::DEBUG_STRUCT)
+ && is_type_diagnostic_item(cx, recv_ty, sym::DebugStruct)
&& path.ident.name == sym::field
&& let ExprKind::Lit(lit) = &debug_field.kind
&& let LitKind::Str(sym, ..) = lit.node
diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs
index 5ee26966fa716..6d7df2eac6291 100644
--- a/clippy_lints/src/needless_pass_by_value.rs
+++ b/clippy_lints/src/needless_pass_by_value.rs
@@ -4,7 +4,7 @@ use clippy_utils::source::{snippet, snippet_opt};
use clippy_utils::ty::{
implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item,
};
-use clippy_utils::{get_trait_def_id, is_self, paths};
+use clippy_utils::is_self;
use if_chain::if_chain;
use rustc_ast::ast::Attribute;
use rustc_errors::{Applicability, Diagnostic};
@@ -115,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
need!(cx.tcx.lang_items().fn_trait()),
need!(cx.tcx.lang_items().fn_once_trait()),
need!(cx.tcx.lang_items().fn_mut_trait()),
- need!(get_trait_def_id(cx, &paths::RANGE_ARGUMENT_TRAIT)),
+ need!(cx.tcx.get_diagnostic_item(sym::RangeBounds)),
];
let sized_trait = need!(cx.tcx.lang_items().sized_trait());
diff --git a/clippy_lints/src/non_canonical_impls.rs b/clippy_lints/src/non_canonical_impls.rs
index 20b4b4f03ed47..4be140647fcc4 100644
--- a/clippy_lints/src/non_canonical_impls.rs
+++ b/clippy_lints/src/non_canonical_impls.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::paths::ORD_CMP;
use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_parent_node, is_res_lang_ctor, last_path_segment, match_def_path, path_res, std_or_core};
+use clippy_utils::{get_parent_node, is_res_lang_ctor, last_path_segment, path_res, std_or_core};
use rustc_errors::Applicability;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, LangItem, Node, UnOp};
@@ -261,7 +260,7 @@ fn self_cmp_call<'tcx>(
match cmp_expr.kind {
ExprKind::Call(path, [_self, _other]) => path_res(cx, path)
.opt_def_id()
- .is_some_and(|def_id| match_def_path(cx, def_id, &ORD_CMP)),
+ .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::ord_cmp_method, def_id)),
ExprKind::MethodCall(_, _, [_other], ..) => {
// We can set this to true here no matter what as if it's a `MethodCall` and goes to the
// `else` branch, it must be a method named `cmp` that isn't `Ord::cmp`
@@ -273,7 +272,7 @@ fn self_cmp_call<'tcx>(
cx.tcx
.typeck(def_id)
.type_dependent_def_id(cmp_expr.hir_id)
- .is_some_and(|def_id| match_def_path(cx, def_id, &ORD_CMP))
+ .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::ord_cmp_method, def_id))
},
_ => false,
}
diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs
index e1de494eb41c0..d47728f190ab9 100644
--- a/clippy_lints/src/non_octal_unix_permissions.rs
+++ b/clippy_lints/src/non_octal_unix_permissions.rs
@@ -1,6 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
-use clippy_utils::ty::{is_type_diagnostic_item, match_type};
use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
@@ -45,13 +44,12 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
match &expr.kind {
ExprKind::MethodCall(path, func, [param], _) => {
- let obj_ty = cx.typeck_results().expr_ty(func).peel_refs();
-
if_chain! {
+ if let Some(adt) = cx.typeck_results().expr_ty(func).peel_refs().ty_adt_def();
if (path.ident.name == sym!(mode)
- && (match_type(cx, obj_ty, &paths::OPEN_OPTIONS)
- || is_type_diagnostic_item(cx, obj_ty, sym::DirBuilder)))
- || (path.ident.name == sym!(set_mode) && match_type(cx, obj_ty, &paths::PERMISSIONS));
+ && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::FsOpenOptions | sym::DirBuilder)))
+ || (path.ident.name == sym!(set_mode)
+ && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did()));
if let ExprKind::Lit(_) = param.kind;
if param.span.ctxt() == expr.span.ctxt();
diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs
index c5e777c207028..d388dfc08f3b7 100644
--- a/clippy_lints/src/non_send_fields_in_send_ty.rs
+++ b/clippy_lints/src/non_send_fields_in_send_ty.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use clippy_utils::ty::{implements_trait, is_copy};
-use clippy_utils::{is_lint_allowed, match_def_path, paths};
+use clippy_utils::is_lint_allowed;
use rustc_ast::ImplPolarity;
use rustc_hir::def_id::DefId;
use rustc_hir::{FieldDef, Item, ItemKind, Node};
@@ -233,7 +233,7 @@ fn contains_pointer_like<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> b
return true;
},
ty::Adt(adt_def, _) => {
- if match_def_path(cx, adt_def.did(), &paths::PTR_NON_NULL) {
+ if cx.tcx.is_diagnostic_item(sym::NonNull, adt_def.did()) {
return true;
}
},
diff --git a/clippy_lints/src/operators/cmp_owned.rs b/clippy_lints/src/operators/cmp_owned.rs
index d3de9699fe9d9..136642d69dcaa 100644
--- a/clippy_lints/src/operators/cmp_owned.rs
+++ b/clippy_lints/src/operators/cmp_owned.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use clippy_utils::ty::{implements_trait, is_copy};
-use clippy_utils::{match_def_path, path_def_id, paths};
+use clippy_utils::path_def_id;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_lint::LateContext;
@@ -50,7 +50,7 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool)
},
ExprKind::Call(path, [arg])
if path_def_id(cx, path).map_or(false, |did| {
- if match_def_path(cx, did, &paths::FROM_STR_METHOD) {
+ if cx.tcx.is_diagnostic_item(sym::from_str_method, did) {
true
} else if cx.tcx.is_diagnostic_item(sym::from_fn, did) {
!is_copy(cx, typeck.expr_ty(expr))
diff --git a/clippy_lints/src/permissions_set_readonly_false.rs b/clippy_lints/src/permissions_set_readonly_false.rs
index 664d44d6504dc..f3089d716ff1c 100644
--- a/clippy_lints/src/permissions_set_readonly_false.rs
+++ b/clippy_lints/src/permissions_set_readonly_false.rs
@@ -1,10 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::paths;
-use clippy_utils::ty::match_type;
+use clippy_utils::ty::is_type_diagnostic_item;
use rustc_ast::ast::LitKind;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@@ -31,7 +31,7 @@ declare_lint_pass!(PermissionsSetReadonlyFalse => [PERMISSIONS_SET_READONLY_FALS
impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if let ExprKind::MethodCall(path, receiver, [arg], _) = &expr.kind
- && match_type(cx, cx.typeck_results().expr_ty(receiver), &paths::PERMISSIONS)
+ && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::FsPermissions)
&& path.ident.name == sym!(set_readonly)
&& let ExprKind::Lit(lit) = &arg.kind
&& LitKind::Bool(false) == lit.node
diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs
index 7dabdcd58ec2c..310051efc5088 100644
--- a/clippy_lints/src/ptr.rs
+++ b/clippy_lints/src/ptr.rs
@@ -4,9 +4,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::expr_sig;
use clippy_utils::visitors::contains_unsafe_block;
-use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, paths};
+use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local};
use hir::LifetimeName;
-use if_chain::if_chain;
use rustc_errors::{Applicability, MultiSpan};
use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::HirIdMap;
@@ -271,60 +270,43 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
}
fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- // (fn_path, arg_indices) - `arg_indices` are the `arg` positions where null would cause U.B.
- const INVALID_NULL_PTR_USAGE_TABLE: [(&[&str], &[usize]); 13] = [
- (&paths::SLICE_FROM_RAW_PARTS, &[0]),
- (&paths::SLICE_FROM_RAW_PARTS_MUT, &[0]),
- (&paths::PTR_COPY, &[0, 1]),
- (&paths::PTR_COPY_NONOVERLAPPING, &[0, 1]),
- (&paths::PTR_READ, &[0]),
- (&paths::PTR_READ_UNALIGNED, &[0]),
- (&paths::PTR_READ_VOLATILE, &[0]),
- (&paths::PTR_REPLACE, &[0]),
- (&paths::PTR_SLICE_FROM_RAW_PARTS, &[0]),
- (&paths::PTR_SLICE_FROM_RAW_PARTS_MUT, &[0]),
- (&paths::PTR_SWAP, &[0, 1]),
- (&paths::PTR_SWAP_NONOVERLAPPING, &[0, 1]),
- (&paths::PTR_WRITE_BYTES, &[0]),
- ];
- let invalid_null_ptr_usage_table_diag_items: [(Option, &[usize]); 3] = [
- (cx.tcx.get_diagnostic_item(sym::ptr_write), &[0]),
- (cx.tcx.get_diagnostic_item(sym::ptr_write_unaligned), &[0]),
- (cx.tcx.get_diagnostic_item(sym::ptr_write_volatile), &[0]),
- ];
-
- if_chain! {
- if let ExprKind::Call(fun, args) = expr.kind;
- if let ExprKind::Path(ref qpath) = fun.kind;
- if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
- let fun_def_path = cx.get_def_path(fun_def_id).into_iter().map(Symbol::to_ident_string).collect::>();
- if let Some(arg_indices) = INVALID_NULL_PTR_USAGE_TABLE
- .iter()
- .find_map(|&(fn_path, indices)| if fn_path == fun_def_path { Some(indices) } else { None })
- .or_else(|| {
- invalid_null_ptr_usage_table_diag_items
- .iter()
- .find_map(|&(def_id, indices)| {
- if def_id == Some(fun_def_id) {
- Some(indices)
- } else {
- None
- }
- })
- });
- then {
- for &arg_idx in arg_indices {
- if let Some(arg) = args.get(arg_idx).filter(|arg| is_null_path(cx, arg)) {
- span_lint_and_sugg(
- cx,
- INVALID_NULL_PTR_USAGE,
- arg.span,
- "pointer must be non-null",
- "change this to",
- "core::ptr::NonNull::dangling().as_ptr()".to_string(),
- Applicability::MachineApplicable,
- );
- }
+ if let ExprKind::Call(fun, args) = expr.kind
+ && let ExprKind::Path(ref qpath) = fun.kind
+ && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id()
+ && let Some(name) = cx.tcx.get_diagnostic_name(fun_def_id)
+ {
+ // `arg` positions where null would cause U.B.
+ let arg_indices: &[_] = match name {
+ sym::ptr_read
+ | sym::ptr_read_unaligned
+ | sym::ptr_read_volatile
+ | sym::ptr_replace
+ | sym::ptr_slice_from_raw_parts
+ | sym::ptr_slice_from_raw_parts_mut
+ | sym::ptr_write
+ | sym::ptr_write_bytes
+ | sym::ptr_write_unaligned
+ | sym::ptr_write_volatile
+ | sym::slice_from_raw_parts
+ | sym::slice_from_raw_parts_mut => &[0],
+ sym::ptr_copy
+ | sym::ptr_copy_nonoverlapping
+ | sym::ptr_swap
+ | sym::ptr_swap_nonoverlapping => &[0, 1],
+ _ => return,
+ };
+
+ for &arg_idx in arg_indices {
+ if let Some(arg) = args.get(arg_idx).filter(|arg| is_null_path(cx, arg)) {
+ span_lint_and_sugg(
+ cx,
+ INVALID_NULL_PTR_USAGE,
+ arg.span,
+ "pointer must be non-null",
+ "change this to",
+ "core::ptr::NonNull::dangling().as_ptr()".to_string(),
+ Applicability::MachineApplicable,
+ );
}
}
}
diff --git a/clippy_lints/src/rc_clone_in_vec_init.rs b/clippy_lints/src/rc_clone_in_vec_init.rs
index 8e85c55e7563f..1a127c2bcf68e 100644
--- a/clippy_lints/src/rc_clone_in_vec_init.rs
+++ b/clippy_lints/src/rc_clone_in_vec_init.rs
@@ -2,11 +2,11 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::VecArgs;
use clippy_utils::macros::root_macro_call_first_node;
use clippy_utils::source::{indent_of, snippet};
-use clippy_utils::ty::match_type;
-use clippy_utils::{last_path_segment, paths};
+use clippy_utils::last_path_segment;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, Span, Symbol};
@@ -133,8 +133,9 @@ fn ref_init(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(Symbol, Span)> {
return Some((symbol, func.span));
}
- let ty_path = cx.typeck_results().expr_ty(expr);
- if match_type(cx, ty_path, &paths::WEAK_RC) || match_type(cx, ty_path, &paths::WEAK_ARC) {
+ if let ty::Adt(adt, _) = *cx.typeck_results().expr_ty(expr).kind()
+ && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::RcWeak | sym::ArcWeak))
+ {
return Some((Symbol::intern("Weak"), func.span));
}
}
diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs
index e36adef555e65..2c0086b09813c 100644
--- a/clippy_lints/src/redundant_clone.rs
+++ b/clippy_lints/src/redundant_clone.rs
@@ -99,8 +99,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
unwrap_or_continue!(is_call_with_ref_arg(cx, mir, &terminator.kind));
let from_borrow = match_def_path(cx, fn_def_id, &paths::CLONE_TRAIT_METHOD)
- || match_def_path(cx, fn_def_id, &paths::TO_OWNED_METHOD)
- || (match_def_path(cx, fn_def_id, &paths::TO_STRING_METHOD)
+ || cx.tcx.is_diagnostic_item(sym::to_owned_method, fn_def_id)
+ || (cx.tcx.is_diagnostic_item(sym::to_string_method, fn_def_id)
&& is_type_lang_item(cx, arg_ty, LangItem::String));
let from_deref = !from_borrow
diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs
index bd783b4e00541..b940cac6047be 100644
--- a/clippy_lints/src/size_of_in_element_count.rs
+++ b/clippy_lints/src/size_of_in_element_count.rs
@@ -2,7 +2,6 @@
//! expecting a count of T
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -67,16 +66,6 @@ fn get_pointee_ty_and_count_expr<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'_>,
) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> {
- const FUNCTIONS: [&[&str]; 8] = [
- &paths::PTR_COPY_NONOVERLAPPING,
- &paths::PTR_COPY,
- &paths::PTR_WRITE_BYTES,
- &paths::PTR_SWAP_NONOVERLAPPING,
- &paths::PTR_SLICE_FROM_RAW_PARTS,
- &paths::PTR_SLICE_FROM_RAW_PARTS_MUT,
- &paths::SLICE_FROM_RAW_PARTS,
- &paths::SLICE_FROM_RAW_PARTS_MUT,
- ];
const METHODS: [&str; 11] = [
"write_bytes",
"copy_to",
@@ -97,7 +86,16 @@ fn get_pointee_ty_and_count_expr<'tcx>(
if let ExprKind::Call(func, [.., count]) = expr.kind;
if let ExprKind::Path(ref func_qpath) = func.kind;
if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
- if FUNCTIONS.iter().any(|func_path| match_def_path(cx, def_id, func_path));
+ if matches!(cx.tcx.get_diagnostic_name(def_id), Some(
+ sym::ptr_copy
+ | sym::ptr_copy_nonoverlapping
+ | sym::ptr_slice_from_raw_parts
+ | sym::ptr_slice_from_raw_parts_mut
+ | sym::ptr_swap_nonoverlapping
+ | sym::ptr_write_bytes
+ | sym::slice_from_raw_parts
+ | sym::slice_from_raw_parts_mut
+ ));
// Get the pointee type
if let Some(pointee_ty) = cx.typeck_results().node_args(func.hir_id).types().next();
diff --git a/clippy_lints/src/swap_ptr_to_ref.rs b/clippy_lints/src/swap_ptr_to_ref.rs
index d085dda3582be..3685432a25399 100644
--- a/clippy_lints/src/swap_ptr_to_ref.rs
+++ b/clippy_lints/src/swap_ptr_to_ref.rs
@@ -1,11 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_with_context;
-use clippy_utils::{match_def_path, path_def_id, paths};
+use clippy_utils::path_def_id;
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{Span, SyntaxContext};
+use rustc_span::{sym, Span, SyntaxContext};
declare_clippy_lint! {
/// ### What it does
@@ -42,7 +42,7 @@ impl LateLintPass<'_> for SwapPtrToRef {
fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
if let ExprKind::Call(fn_expr, [arg1, arg2]) = e.kind
&& let Some(fn_id) = path_def_id(cx, fn_expr)
- && match_def_path(cx, fn_id, &paths::MEM_SWAP)
+ && cx.tcx.is_diagnostic_item(sym::mem_swap, fn_id)
&& let ctxt = e.span.ctxt()
&& let (from_ptr1, arg1_span) = is_ptr_to_ref(cx, arg1, ctxt)
&& let (from_ptr2, arg2_span) = is_ptr_to_ref(cx, arg2, ctxt)
diff --git a/clippy_lints/src/unnamed_address.rs b/clippy_lints/src/unnamed_address.rs
index dea8a1e35bbba..996e7edf5573d 100644
--- a/clippy_lints/src/unnamed_address.rs
+++ b/clippy_lints/src/unnamed_address.rs
@@ -1,10 +1,10 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
-use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@@ -96,7 +96,7 @@ impl LateLintPass<'_> for UnnamedAddress {
if let ExprKind::Call(func, [ref _left, ref _right]) = expr.kind;
if let ExprKind::Path(ref func_qpath) = func.kind;
if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
- if match_def_path(cx, def_id, &paths::PTR_EQ);
+ if cx.tcx.is_diagnostic_item(sym::ptr_eq, def_id);
let ty_param = cx.typeck_results().node_args(func.hir_id).type_at(0);
if ty_param.is_trait();
then {
diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs
index 4ee16d9a5e4ad..db91beec0efa7 100644
--- a/clippy_lints/src/unused_peekable.rs
+++ b/clippy_lints/src/unused_peekable.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::{match_type, peel_mid_ty_refs_is_mutable};
-use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, paths, peel_ref_operators};
+use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable};
+use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators};
use rustc_ast::Mutability;
use rustc_hir::intravisit::{walk_expr, Visitor};
use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind};
@@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable {
// Don't lint `Peekable`s returned from a block
if let Some(expr) = block.expr
&& let Some(ty) = cx.typeck_results().expr_ty_opt(peel_ref_operators(cx, expr))
- && match_type(cx, ty, &paths::PEEKABLE)
+ && is_type_diagnostic_item(cx, ty, sym::IterPeekable)
{
return;
}
@@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable {
&& !init.span.from_expansion()
&& let Some(ty) = cx.typeck_results().expr_ty_opt(init)
&& let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty)
- && match_type(cx, ty, &paths::PEEKABLE)
+ && is_type_diagnostic_item(cx, ty, sym::IterPeekable)
{
let mut vis = PeekableVisitor::new(cx, binding);
@@ -222,7 +222,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
fn arg_is_mut_peekable(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool {
if let Some(ty) = cx.typeck_results().expr_ty_opt(arg)
&& let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty)
- && match_type(cx, ty, &paths::PEEKABLE)
+ && is_type_diagnostic_item(cx, ty, sym::IterPeekable)
{
true
} else {
diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs
index f32e7edad6cb6..3cc91838c0004 100644
--- a/clippy_lints/src/useless_conversion.rs
+++ b/clippy_lints/src/useless_conversion.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lin
use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts};
-use clippy_utils::{get_parent_expr, is_trait_method, is_ty_alias, match_def_path, path_to_local, paths};
+use clippy_utils::{get_parent_expr, is_trait_method, is_ty_alias, path_to_local};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def::DefKind;
@@ -331,7 +331,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
let a = cx.typeck_results().expr_ty(e);
let b = cx.typeck_results().expr_ty(arg);
if_chain! {
- if match_def_path(cx, def_id, &paths::TRY_FROM);
+ if cx.tcx.is_diagnostic_item(sym::try_from_fn, def_id);
if is_type_diagnostic_item(cx, a, sym::Result);
if let ty::Adt(_, args) = a.kind();
if let Some(a_type) = args.types().next();
diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs
index 802adbd4d2d56..741f9f54883d6 100644
--- a/clippy_utils/src/higher.rs
+++ b/clippy_utils/src/higher.rs
@@ -457,7 +457,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -
};
},
ExprKind::Path(QPath::Resolved(_, path))
- if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD)
+ if cx.tcx.is_diagnostic_item(sym::default_fn, path.res.opt_def_id()?)
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) =>
{
return Some(VecInitKind::Default);
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index 13da79fba7e8e..64ca2ff787363 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -2076,7 +2076,7 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool
match expr.kind {
ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir().body(body)),
- _ => path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, &paths::CONVERT_IDENTITY)),
+ _ => path_def_id(cx, expr).map_or(false, |id| cx.tcx.is_diagnostic_item(sym::convert_identity, id)),
}
}
diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs
index 2fb24b5c7ed9d..1f2bb16f459fc 100644
--- a/clippy_utils/src/paths.rs
+++ b/clippy_utils/src/paths.rs
@@ -25,17 +25,12 @@ pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "
pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"];
pub const CORE_RESULT_OK_METHOD: [&str; 4] = ["core", "result", "Result", "ok"];
pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"];
-pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"];
-pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"];
#[cfg(feature = "internal")]
pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"];
#[cfg(feature = "internal")]
pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"];
-pub const EXIT: [&str; 3] = ["std", "process", "exit"];
pub const F32_EPSILON: [&str; 4] = ["core", "f32", "", "EPSILON"];
pub const F64_EPSILON: [&str; 4] = ["core", "f64", "", "EPSILON"];
-pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"];
-pub const FROM_STR_METHOD: [&str; 5] = ["core", "str", "traits", "FromStr", "from_str"];
#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"];
#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
@@ -48,8 +43,6 @@ pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"];
#[cfg(feature = "internal")]
pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"];
pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"];
-pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"];
-pub const ITER_ONCE: [&str; 5] = ["core", "iter", "sources", "once", "Once"];
pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"];
#[cfg(feature = "internal")]
pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
@@ -59,10 +52,8 @@ pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"];
pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"];
#[cfg(feature = "internal")]
pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"];
-pub const MEM_SWAP: [&str; 3] = ["core", "mem", "swap"];
#[cfg(feature = "internal")]
pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"];
-pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"];
pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"];
pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"];
pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"];
@@ -71,28 +62,9 @@ pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "Rw
pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
pub const PATH_MAIN_SEPARATOR: [&str; 3] = ["std", "path", "MAIN_SEPARATOR"];
pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
-pub const PEEKABLE: [&str; 5] = ["core", "iter", "adapters", "peekable", "Peekable"];
-pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"];
#[cfg_attr(not(unix), allow(clippy::invalid_paths))]
pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "PermissionsExt", "from_mode"];
-pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"];
-pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"];
-pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
-pub const PTR_SLICE_FROM_RAW_PARTS: [&str; 3] = ["core", "ptr", "slice_from_raw_parts"];
-pub const PTR_SLICE_FROM_RAW_PARTS_MUT: [&str; 3] = ["core", "ptr", "slice_from_raw_parts_mut"];
-pub const PTR_SWAP_NONOVERLAPPING: [&str; 3] = ["core", "ptr", "swap_nonoverlapping"];
-pub const PTR_READ: [&str; 3] = ["core", "ptr", "read"];
-pub const PTR_READ_UNALIGNED: [&str; 3] = ["core", "ptr", "read_unaligned"];
-pub const PTR_READ_VOLATILE: [&str; 3] = ["core", "ptr", "read_volatile"];
-pub const PTR_REPLACE: [&str; 3] = ["core", "ptr", "replace"];
-pub const PTR_SWAP: [&str; 3] = ["core", "ptr", "swap"];
-pub const PTR_UNALIGNED_VOLATILE_LOAD: [&str; 3] = ["core", "intrinsics", "unaligned_volatile_load"];
-pub const PTR_UNALIGNED_VOLATILE_STORE: [&str; 3] = ["core", "intrinsics", "unaligned_volatile_store"];
-pub const PTR_WRITE_BYTES: [&str; 3] = ["core", "intrinsics", "write_bytes"];
pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"];
-pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
-pub const REFCELL_REF: [&str; 3] = ["core", "cell", "Ref"];
-pub const REFCELL_REFMUT: [&str; 3] = ["core", "cell", "RefMut"];
pub const REGEX_BUILDER_NEW: [&str; 3] = ["regex", "RegexBuilder", "new"];
pub const REGEX_BYTES_BUILDER_NEW: [&str; 4] = ["regex", "bytes", "RegexBuilder", "new"];
pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "bytes", "Regex", "new"];
@@ -101,21 +73,11 @@ pub const REGEX_NEW: [&str; 3] = ["regex", "Regex", "new"];
pub const REGEX_SET_NEW: [&str; 3] = ["regex", "RegexSet", "new"];
pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"];
pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
-pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"];
-pub const SLICE_FROM_RAW_PARTS_MUT: [&str; 4] = ["core", "slice", "raw", "from_raw_parts_mut"];
pub const SLICE_GET: [&str; 4] = ["core", "slice", "", "get"];
pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "", "into_vec"];
pub const SLICE_INTO: [&str; 4] = ["core", "slice", "", "iter"];
-pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"];
-pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"];
-pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"];
-pub const CONVERT_IDENTITY: [&str; 3] = ["core", "convert", "identity"];
-pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"];
-pub const STD_IO_LINES: [&str; 3] = ["std", "io", "Lines"];
-pub const STD_IO_SEEK: [&str; 3] = ["std", "io", "Seek"];
pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"];
pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"];
-pub const STD_PROCESS_COMMAND: [&str; 3] = ["std", "process", "Command"];
pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"];
pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"];
@@ -136,13 +98,11 @@ pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol",
pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"];
#[cfg(feature = "internal")]
pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
-pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"];
pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const TOKIO_IO_ASYNCREADEXT: [&str; 5] = ["tokio", "io", "util", "async_read_ext", "AsyncReadExt"];
#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const TOKIO_IO_ASYNCWRITEEXT: [&str; 5] = ["tokio", "io", "util", "async_write_ext", "AsyncWriteExt"];
-pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"];
pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"];
pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"];
pub const VEC_DEQUE_ITER: [&str; 5] = ["alloc", "collections", "vec_deque", "VecDeque", "iter"];
@@ -150,18 +110,10 @@ pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"];
pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"];
pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"];
pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
-pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
-pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
-pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"];
pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"];
-pub const INSTANT: [&str; 3] = ["std", "time", "Instant"];
pub const VEC_IS_EMPTY: [&str; 4] = ["alloc", "vec", "Vec", "is_empty"];
pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"];
pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"];
pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"];
-pub const FORMATTER: [&str; 3] = ["core", "fmt", "Formatter"];
-pub const DEBUG_STRUCT: [&str; 4] = ["core", "fmt", "builders", "DebugStruct"];
-pub const ORD_CMP: [&str; 4] = ["core", "cmp", "Ord", "cmp"];
#[expect(clippy::invalid_paths)] // not sure why it thinks this, it works so
pub const BOOL_THEN: [&str; 4] = ["core", "bool", "", "then"];
-pub const ARRAY_INTO_ITER: [&str; 4] = ["core", "array", "iter", "IntoIter"];
diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs
index 604dc76912e65..2d305a63eca12 100644
--- a/clippy_utils/src/ty.rs
+++ b/clippy_utils/src/ty.rs
@@ -31,7 +31,7 @@ use rustc_trait_selection::traits::{Obligation, ObligationCause};
use std::assert_matches::debug_assert_matches;
use std::iter;
-use crate::{match_def_path, path_res, paths};
+use crate::{match_def_path, path_res};
mod type_certainty;
pub use type_certainty::expr_type_is_certain;
@@ -461,10 +461,8 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
else if is_type_lang_item(cx, ty, LangItem::OwnedBox)
|| matches!(
get_type_diagnostic_name(cx, ty),
- Some(sym::HashSet | sym::Rc | sym::Arc | sym::cstring_type)
+ Some(sym::HashSet | sym::Rc | sym::Arc | sym::cstring_type | sym::RcWeak | sym::ArcWeak)
)
- || match_type(cx, ty, &paths::WEAK_RC)
- || match_type(cx, ty, &paths::WEAK_ARC)
{
// Check all of the generic arguments.
if let ty::Adt(_, subs) = ty.kind() {
diff --git a/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs b/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs
index b5ff3a5420561..60be297881341 100644
--- a/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs
+++ b/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs
@@ -11,6 +11,6 @@ fn main() {
const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"];
const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
- // Don't lint, not yet a diagnostic or language item
- const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"];
+ // Don't lint, not a diagnostic or language item
+ const OPS_MOD: [&str; 5] = ["core", "ops"];
}
diff --git a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
index 58b1fd92b5dc9..076786329cd9f 100644
--- a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
+++ b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
@@ -19,8 +19,8 @@ LL | const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"]
error: hardcoded path to a diagnostic item
--> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
|
-LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | const OPS_MOD: [&str; 5] = ["core", "ops"];
+ | ^^^^^^^^^^^^^^^
|
= help: convert all references to use `sym::deref_method`
From ddd1564e5d723c7c380ab0656c91857d99391a5f Mon Sep 17 00:00:00 2001
From: Guillaume Gomez
Date: Fri, 6 Oct 2023 11:18:34 +0200
Subject: [PATCH 08/43] Add regression test for #11610 about mutable usage of
argument in async function for the `needless_pass_by_ref_mut` lint
---
tests/ui/needless_pass_by_ref_mut.rs | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/tests/ui/needless_pass_by_ref_mut.rs b/tests/ui/needless_pass_by_ref_mut.rs
index 39d76f9990022..93f94b384af22 100644
--- a/tests/ui/needless_pass_by_ref_mut.rs
+++ b/tests/ui/needless_pass_by_ref_mut.rs
@@ -270,6 +270,12 @@ pub async fn closure4(n: &mut usize) {
})();
}
+// Should not warn.
+async fn _f(v: &mut Vec<()>) {
+ let x = || v.pop();
+ _ = || || x;
+}
+
fn main() {
let mut u = 0;
let mut v = vec![0];
From 8ebed4cc1a2e21844c58f3b0bfbad1a069bb09b6 Mon Sep 17 00:00:00 2001
From: Philipp Krones
Date: Fri, 6 Oct 2023 17:35:45 +0200
Subject: [PATCH 09/43] Merge commit 'b105fb4c39bc1a010807a6c076193cef8d93c109'
into clippyup
---
CHANGELOG.md | 97 ++++++-
Cargo.toml | 4 +-
book/src/development/adding_lints.md | 2 +-
book/src/lint_configuration.md | 1 +
clippy_dev/src/new_lint.rs | 63 ++++-
clippy_lints/Cargo.toml | 5 +-
clippy_lints/src/allow_attributes.rs | 2 +-
clippy_lints/src/declared_lints.rs | 3 +
clippy_lints/src/enum_clike.rs | 4 +-
clippy_lints/src/error_impl_error.rs | 2 +-
clippy_lints/src/four_forward_slashes.rs | 2 +-
clippy_lints/src/ignored_unit_patterns.rs | 4 +
clippy_lints/src/implicit_hasher.rs | 5 +-
clippy_lints/src/items_after_test_module.rs | 108 +++++---
clippy_lints/src/iter_without_into_iter.rs | 249 ++++++++++++++++++
clippy_lints/src/lib.rs | 4 +
clippy_lints/src/manual_float_methods.rs | 4 +-
clippy_lints/src/manual_hash_one.rs | 133 ++++++++++
clippy_lints/src/manual_let_else.rs | 4 +-
clippy_lints/src/manual_non_exhaustive.rs | 22 +-
clippy_lints/src/matches/mod.rs | 2 +-
clippy_lints/src/matches/overlapping_arms.rs | 6 +-
clippy_lints/src/methods/mod.rs | 13 +-
.../src/methods/unnecessary_literal_unwrap.rs | 11 +-
clippy_lints/src/missing_assert_message.rs | 4 +
.../src/mixed_read_write_in_expression.rs | 7 +-
clippy_lints/src/needless_pass_by_ref_mut.rs | 4 +-
clippy_lints/src/non_canonical_impls.rs | 2 +-
clippy_lints/src/operators/mod.rs | 4 +-
clippy_lints/src/raw_strings.rs | 30 +--
clippy_lints/src/redundant_locals.rs | 36 +--
clippy_lints/src/std_instead_of_core.rs | 6 +-
clippy_lints/src/utils/conf.rs | 43 ++-
clippy_lints/src/wildcard_imports.rs | 1 +
clippy_lints/src/write.rs | 142 +++++++---
clippy_utils/Cargo.toml | 2 +-
clippy_utils/src/consts.rs | 69 +++--
clippy_utils/src/lib.rs | 31 ++-
clippy_utils/src/msrvs.rs | 2 +-
clippy_utils/src/visitors.rs | 44 ++++
declare_clippy_lint/Cargo.toml | 2 +-
rust-toolchain | 2 +-
src/driver.rs | 55 ++--
src/main.rs | 63 +++--
tests/ui/auxiliary/proc_macro_derive.rs | 28 ++
tests/ui/ignored_unit_patterns.fixed | 15 ++
tests/ui/ignored_unit_patterns.rs | 15 ++
tests/ui/ignored_unit_patterns.stderr | 24 +-
tests/ui/infinite_loop.rs | 2 -
tests/ui/infinite_loop.stderr | 33 +--
tests/ui/into_iter_without_iter.rs | 124 +++++++++
tests/ui/into_iter_without_iter.stderr | 114 ++++++++
.../after_proc_macros.rs | 11 +
.../auxiliary/submodule.rs | 4 +
.../block_module.stderr | 2 -
.../items_after_test_module/in_submodule.rs | 8 +
.../in_submodule.stderr | 14 +
.../multiple_modules.rs | 11 +
.../{block_module.rs => root_module.fixed} | 15 +-
.../ui/items_after_test_module/root_module.rs | 22 ++
.../root_module.stderr | 20 ++
tests/ui/iter_without_into_iter.rs | 120 +++++++++
tests/ui/iter_without_into_iter.stderr | 150 +++++++++++
tests/ui/let_underscore_future.rs | 2 -
tests/ui/let_underscore_future.stderr | 17 +-
tests/ui/manual_hash_one.fixed | 89 +++++++
tests/ui/manual_hash_one.rs | 89 +++++++
tests/ui/manual_hash_one.stderr | 56 ++++
tests/ui/manual_let_else_match.fixed | 4 +
tests/ui/manual_let_else_match.rs | 8 +
tests/ui/manual_let_else_match.stderr | 12 +-
tests/ui/manual_non_exhaustive_enum.rs | 3 +-
tests/ui/manual_non_exhaustive_enum.stderr | 20 +-
tests/ui/mut_key.rs | 2 -
tests/ui/mut_key.stderr | 41 ++-
tests/ui/mut_reference.rs | 2 -
tests/ui/mut_reference.stderr | 17 +-
tests/ui/needless_pass_by_ref_mut.rs | 1 +
tests/ui/needless_pass_by_ref_mut.stderr | 42 +--
tests/ui/needless_raw_string.fixed | 4 +
tests/ui/needless_raw_string.rs | 4 +
tests/ui/needless_raw_string.stderr | 46 +++-
tests/ui/needless_raw_string_hashes.stderr | 30 +--
tests/ui/print_literal.fixed | 18 +-
tests/ui/print_literal.rs | 18 +-
tests/ui/print_literal.stderr | 124 ++++++---
tests/ui/redundant_locals.rs | 37 +++
tests/ui/redundant_locals.stderr | 139 ++++++----
tests/ui/should_impl_trait/method_list_2.rs | 2 -
.../ui/should_impl_trait/method_list_2.stderr | 36 +--
tests/ui/slow_vector_initialization.rs | 2 -
tests/ui/slow_vector_initialization.stderr | 11 +-
tests/ui/std_instead_of_core.fixed | 11 +
tests/ui/std_instead_of_core.rs | 11 +
tests/ui/std_instead_of_core.stderr | 22 +-
tests/ui/wildcard_imports.fixed | 28 ++
tests/ui/wildcard_imports.rs | 28 ++
tests/ui/wildcard_imports.stderr | 38 +--
.../wildcard_imports_2021.edition2018.fixed | 28 ++
.../wildcard_imports_2021.edition2018.stderr | 38 +--
.../wildcard_imports_2021.edition2021.fixed | 28 ++
.../wildcard_imports_2021.edition2021.stderr | 38 +--
tests/ui/wildcard_imports_2021.rs | 28 ++
tests/ui/write_literal.fixed | 14 +-
tests/ui/write_literal.rs | 14 +-
tests/ui/write_literal.stderr | 74 +++---
tests/ui/write_literal_2.rs | 16 +-
tests/ui/write_literal_2.stderr | 82 ++----
108 files changed, 2637 insertions(+), 768 deletions(-)
create mode 100644 clippy_lints/src/iter_without_into_iter.rs
create mode 100644 clippy_lints/src/manual_hash_one.rs
create mode 100644 tests/ui/into_iter_without_iter.rs
create mode 100644 tests/ui/into_iter_without_iter.stderr
create mode 100644 tests/ui/items_after_test_module/after_proc_macros.rs
create mode 100644 tests/ui/items_after_test_module/auxiliary/submodule.rs
delete mode 100644 tests/ui/items_after_test_module/block_module.stderr
create mode 100644 tests/ui/items_after_test_module/in_submodule.rs
create mode 100644 tests/ui/items_after_test_module/in_submodule.stderr
create mode 100644 tests/ui/items_after_test_module/multiple_modules.rs
rename tests/ui/items_after_test_module/{block_module.rs => root_module.fixed} (86%)
create mode 100644 tests/ui/items_after_test_module/root_module.rs
create mode 100644 tests/ui/items_after_test_module/root_module.stderr
create mode 100644 tests/ui/iter_without_into_iter.rs
create mode 100644 tests/ui/iter_without_into_iter.stderr
create mode 100644 tests/ui/manual_hash_one.fixed
create mode 100644 tests/ui/manual_hash_one.rs
create mode 100644 tests/ui/manual_hash_one.stderr
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8c9ab1e2402ca..fef25ad8635ae 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,11 +6,101 @@ document.
## Unreleased / Beta / In Rust Nightly
-[37f4c172...master](https://github.com/rust-lang/rust-clippy/compare/37f4c172...master)
+[1e8fdf49...master](https://github.com/rust-lang/rust-clippy/compare/1e8fdf49...master)
+
+## Rust 1.73
+
+Current stable, released 2023-10-05
+
+[View all 103 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-07-02T12%3A24%3A40Z..2023-08-11T11%3A09%3A56Z+base%3Amaster)
+
+### New Lints
+
+* [`impossible_comparisons`]
+ [#10843](https://github.com/rust-lang/rust-clippy/pull/10843)
+* [`redundant_comparisons`]
+ [#10843](https://github.com/rust-lang/rust-clippy/pull/10843)
+* [`ignored_unit_patterns`]
+ [#11242](https://github.com/rust-lang/rust-clippy/pull/11242)
+* [`readonly_write_lock`]
+ [#11210](https://github.com/rust-lang/rust-clippy/pull/11210)
+* [`filter_map_bool_then`]
+ [#11115](https://github.com/rust-lang/rust-clippy/pull/11115)
+* [`needless_return_with_question_mark`]
+ [#11031](https://github.com/rust-lang/rust-clippy/pull/11031)
+* [`redundant_guards`]
+ [#10955](https://github.com/rust-lang/rust-clippy/pull/10955)
+* [`redundant_locals`]
+ [#10885](https://github.com/rust-lang/rust-clippy/pull/10885)
+* [`absolute_paths`]
+ [#11003](https://github.com/rust-lang/rust-clippy/pull/11003)
+* [`error_impl_error`]
+ [#11107](https://github.com/rust-lang/rust-clippy/pull/11107)
+* [`iter_skip_zero`]
+ [#11046](https://github.com/rust-lang/rust-clippy/pull/11046)
+* [`string_lit_chars_any`]
+ [#11052](https://github.com/rust-lang/rust-clippy/pull/11052)
+* [`four_forward_slashes`]
+ [#11140](https://github.com/rust-lang/rust-clippy/pull/11140)
+* [`format_collect`]
+ [#11116](https://github.com/rust-lang/rust-clippy/pull/11116)
+* [`needless_pass_by_ref_mut`]
+ [#10900](https://github.com/rust-lang/rust-clippy/pull/10900)
+* [`manual_is_infinite`]
+ [#11049](https://github.com/rust-lang/rust-clippy/pull/11049)
+* [`manual_is_finite`]
+ [#11049](https://github.com/rust-lang/rust-clippy/pull/11049)
+* [`incorrect_partial_ord_impl_on_ord_type`]
+ [#10788](https://github.com/rust-lang/rust-clippy/pull/10788)
+* [`read_line_without_trim`]
+ [#10970](https://github.com/rust-lang/rust-clippy/pull/10970)
+* [`type_id_on_box`]
+ [#10987](https://github.com/rust-lang/rust-clippy/pull/10987)
+
+### Moves and Deprecations
+
+* Renamed `unwrap_or_else_default` to [`unwrap_or_default`]
+ [#10120](https://github.com/rust-lang/rust-clippy/pull/10120)
+* Moved [`tuple_array_conversions`] to `pedantic` (Now allow-by-default)
+ [#11146](https://github.com/rust-lang/rust-clippy/pull/11146)
+* Moved [`arc_with_non_send_sync`] to `suspicious` (Now warn-by-default)
+ [#11104](https://github.com/rust-lang/rust-clippy/pull/11104)
+* Moved [`needless_raw_string_hashes`] to `pedantic` (Now allow-by-default)
+ [#11415](https://github.com/rust-lang/rust-clippy/pull/11415)
+
+### Enhancements
+
+* [`unwrap_used`]: No longer lints on the never-type or never-like enums
+ [#11252](https://github.com/rust-lang/rust-clippy/pull/11252)
+* [`expect_used`]: No longer lints on the never-type or never-like enums
+ [#11252](https://github.com/rust-lang/rust-clippy/pull/11252)
+
+### False Positive Fixes
+
+* [`panic_in_result_fn`]: No longer triggers on `todo!`, `unimplemented!`, `unreachable!`
+ [#11123](https://github.com/rust-lang/rust-clippy/pull/11123)
+
+### Suggestion Fixes/Improvements
+
+* [`semicolon_if_nothing_returned`]: The suggestion is now machine-applicable with rustfix
+ [#11083](https://github.com/rust-lang/rust-clippy/pull/11083)
+
+### ICE Fixes
+
+* [`filter_map_bool_then`]: No longer crashes on late-bound regions
+ [#11318](https://github.com/rust-lang/rust-clippy/pull/11318)
+* [`unwrap_or_default`]: No longer crashes on alias types for local items
+ [#11258](https://github.com/rust-lang/rust-clippy/pull/11258)
+* [`unnecessary_literal_unwrap`]: No longer crashes on `None.unwrap_or_default()`
+ [#11106](https://github.com/rust-lang/rust-clippy/pull/11106)
+* Fixed MIR-related ICE
+ [#11130](https://github.com/rust-lang/rust-clippy/pull/11130)
+* [`missing_fields_in_debug`]: No longer crashes on non-ADT self types
+ [#11069](https://github.com/rust-lang/rust-clippy/pull/11069)
## Rust 1.72
-Current stable, released 2023-08-24
+Released 2023-08-24
[View all 131 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-05-22T14%3A53%3A59Z..2023-07-01T22%3A57%3A20Z+base%3Amaster)
@@ -5011,6 +5101,7 @@ Released 2018-09-13
[`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division
[`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array
[`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
+[`into_iter_without_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_without_iter
[`invalid_atomic_ordering`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_atomic_ordering
[`invalid_null_ptr_usage`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_null_ptr_usage
[`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref
@@ -5036,6 +5127,7 @@ Released 2018-09-13
[`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
[`iter_skip_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_zero
[`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain
+[`iter_without_into_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_without_into_iter
[`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero
[`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
[`large_const_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays
@@ -5072,6 +5164,7 @@ Released 2018-09-13
[`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find
[`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
[`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten
+[`manual_hash_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one
[`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed
[`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check
[`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite
diff --git a/Cargo.toml b/Cargo.toml
index 66786004f6e72..cbcb42dad79b2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clippy"
-version = "0.1.74"
+version = "0.1.75"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
@@ -25,6 +25,8 @@ clippy_lints = { path = "clippy_lints" }
rustc_tools_util = "0.3.0"
tempfile = { version = "3.2", optional = true }
termize = "0.1"
+color-print = "0.3.4" # Sync version with Cargo
+anstream = "0.5.0"
[dev-dependencies]
ui_test = "0.20"
diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md
index f6f0c95c72933..e001197842bdc 100644
--- a/book/src/development/adding_lints.md
+++ b/book/src/development/adding_lints.md
@@ -261,7 +261,7 @@ impl EarlyLintPass for FooFunctions {}
[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60
[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
-[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110
+[category_level_mapping]: ../index.html
## Lint registration
diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md
index b980083f1f52a..2c958ccbbc246 100644
--- a/book/src/lint_configuration.md
+++ b/book/src/lint_configuration.md
@@ -151,6 +151,7 @@ The minimum rust version that the project supports
* [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds)
* [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions)
* [`manual_try_fold`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold)
+* [`manual_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one)
## `cognitive-complexity-threshold`
diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs
index e64cf2c874968..be2386bb1d24b 100644
--- a/clippy_dev/src/new_lint.rs
+++ b/clippy_dev/src/new_lint.rs
@@ -58,7 +58,7 @@ pub fn create(
};
create_lint(&lint, msrv).context("Unable to create lint implementation")?;
- create_test(&lint).context("Unable to create a test for the new lint")?;
+ create_test(&lint, msrv).context("Unable to create a test for the new lint")?;
if lint.ty.is_none() {
add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs")?;
@@ -88,15 +88,21 @@ fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
}
}
-fn create_test(lint: &LintData<'_>) -> io::Result<()> {
- fn create_project_layout>(lint_name: &str, location: P, case: &str, hint: &str) -> io::Result<()> {
+fn create_test(lint: &LintData<'_>, msrv: bool) -> io::Result<()> {
+ fn create_project_layout>(
+ lint_name: &str,
+ location: P,
+ case: &str,
+ hint: &str,
+ msrv: bool,
+ ) -> io::Result<()> {
let mut path = location.into().join(case);
fs::create_dir(&path)?;
write_file(path.join("Cargo.toml"), get_manifest_contents(lint_name, hint))?;
path.push("src");
fs::create_dir(&path)?;
- write_file(path.join("main.rs"), get_test_file_contents(lint_name))?;
+ write_file(path.join("main.rs"), get_test_file_contents(lint_name, msrv))?;
Ok(())
}
@@ -106,13 +112,25 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> {
let test_dir = lint.project_root.join(&relative_test_dir);
fs::create_dir(&test_dir)?;
- create_project_layout(lint.name, &test_dir, "fail", "Content that triggers the lint goes here")?;
- create_project_layout(lint.name, &test_dir, "pass", "This file should not trigger the lint")?;
+ create_project_layout(
+ lint.name,
+ &test_dir,
+ "fail",
+ "Content that triggers the lint goes here",
+ msrv,
+ )?;
+ create_project_layout(
+ lint.name,
+ &test_dir,
+ "pass",
+ "This file should not trigger the lint",
+ false,
+ )?;
println!("Generated test directories: `{relative_test_dir}/pass`, `{relative_test_dir}/fail`");
} else {
let test_path = format!("tests/ui/{}.rs", lint.name);
- let test_contents = get_test_file_contents(lint.name);
+ let test_contents = get_test_file_contents(lint.name, msrv);
write_file(lint.project_root.join(&test_path), test_contents)?;
println!("Generated test file: `{test_path}`");
@@ -194,8 +212,8 @@ pub(crate) fn get_stabilization_version() -> String {
parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`")
}
-fn get_test_file_contents(lint_name: &str) -> String {
- formatdoc!(
+fn get_test_file_contents(lint_name: &str, msrv: bool) -> String {
+ let mut test = formatdoc!(
r#"
#![warn(clippy::{lint_name})]
@@ -203,7 +221,29 @@ fn get_test_file_contents(lint_name: &str) -> String {
// test code goes here
}}
"#
- )
+ );
+
+ if msrv {
+ let _ = writedoc!(
+ test,
+ r#"
+
+ // TODO: set xx to the version one below the MSRV used by the lint, and yy to
+ // the version used by the lint
+ #[clippy::msrv = "1.xx"]
+ fn msrv_1_xx() {{
+ // a simple example that would trigger the lint if the MSRV were met
+ }}
+
+ #[clippy::msrv = "1.yy"]
+ fn msrv_1_yy() {{
+ // the same example as above
+ }}
+ "#
+ );
+ }
+
+ test
}
fn get_manifest_contents(lint_name: &str, hint: &str) -> String {
@@ -258,7 +298,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
)
});
- let _: fmt::Result = write!(result, "{}", get_lint_declaration(&name_upper, category));
+ let _: fmt::Result = writeln!(result, "{}", get_lint_declaration(&name_upper, category));
result.push_str(&if enable_msrv {
formatdoc!(
@@ -281,7 +321,6 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
}}
// TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed.
- // TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`.
// TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs`
"#
)
diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml
index dcd9a4adcbd46..4d5b3bf8a948d 100644
--- a/clippy_lints/Cargo.toml
+++ b/clippy_lints/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clippy_lints"
-version = "0.1.74"
+version = "0.1.75"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
@@ -28,6 +28,9 @@ semver = "1.0"
rustc-semver = "1.1"
url = "2.2"
+[dev-dependencies]
+walkdir = "2.3"
+
[features]
deny-warnings = ["clippy_utils/deny-warnings"]
# build clippy with internal lints enabled, off by default
diff --git a/clippy_lints/src/allow_attributes.rs b/clippy_lints/src/allow_attributes.rs
index e1ef514edfd18..e3f4cf79d315c 100644
--- a/clippy_lints/src/allow_attributes.rs
+++ b/clippy_lints/src/allow_attributes.rs
@@ -8,6 +8,7 @@ use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
+ /// ### What it does
/// Checks for usage of the `#[allow]` attribute and suggests replacing it with
/// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html))
///
@@ -19,7 +20,6 @@ declare_clippy_lint! {
/// (`#![allow]`) are usually used to enable or disable lints on a global scale.
///
/// ### Why is this bad?
- ///
/// `#[expect]` attributes suppress the lint emission, but emit a warning, if
/// the expectation is unfulfilled. This can be useful to be notified when the
/// lint is no longer triggered.
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 4d1281ec1e7c7..481c44031cf72 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -229,6 +229,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::items_after_statements::ITEMS_AFTER_STATEMENTS_INFO,
crate::items_after_test_module::ITEMS_AFTER_TEST_MODULE_INFO,
crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO,
+ crate::iter_without_into_iter::INTO_ITER_WITHOUT_ITER_INFO,
+ crate::iter_without_into_iter::ITER_WITHOUT_INTO_ITER_INFO,
crate::large_const_arrays::LARGE_CONST_ARRAYS_INFO,
crate::large_enum_variant::LARGE_ENUM_VARIANT_INFO,
crate::large_futures::LARGE_FUTURES_INFO,
@@ -280,6 +282,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::manual_clamp::MANUAL_CLAMP_INFO,
crate::manual_float_methods::MANUAL_IS_FINITE_INFO,
crate::manual_float_methods::MANUAL_IS_INFINITE_INFO,
+ crate::manual_hash_one::MANUAL_HASH_ONE_INFO,
crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO,
crate::manual_let_else::MANUAL_LET_ELSE_INFO,
crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO,
diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs
index 3f60e5a7c4d64..646767868e2cf 100644
--- a/clippy_lints/src/enum_clike.rs
+++ b/clippy_lints/src/enum_clike.rs
@@ -1,7 +1,7 @@
//! lint on C-like enums that are `repr(isize/usize)` and have values that
//! don't fit into an `i32`
-use clippy_utils::consts::{miri_to_const, Constant};
+use clippy_utils::consts::{mir_to_const, Constant};
use clippy_utils::diagnostics::span_lint;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
.const_eval_poly(def_id.to_def_id())
.ok()
.map(|val| rustc_middle::mir::Const::from_value(val, ty));
- if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx, c)) {
+ if let Some(Constant::Int(val)) = constant.and_then(|c| mir_to_const(cx, c)) {
if let ty::Adt(adt, _) = ty.kind() {
if adt.is_enum() {
ty = adt.repr().discr_type().to_ty(cx.tcx);
diff --git a/clippy_lints/src/error_impl_error.rs b/clippy_lints/src/error_impl_error.rs
index f24577c738229..6d429fbd03538 100644
--- a/clippy_lints/src/error_impl_error.rs
+++ b/clippy_lints/src/error_impl_error.rs
@@ -27,7 +27,7 @@ declare_clippy_lint! {
///
/// impl std::error::Error for Error { ... }
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub ERROR_IMPL_ERROR,
restriction,
"exported types named `Error` that implement `Error`"
diff --git a/clippy_lints/src/four_forward_slashes.rs b/clippy_lints/src/four_forward_slashes.rs
index 419c77343441c..0ec52f89e7166 100644
--- a/clippy_lints/src/four_forward_slashes.rs
+++ b/clippy_lints/src/four_forward_slashes.rs
@@ -28,7 +28,7 @@ declare_clippy_lint! {
/// // ...
/// }
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub FOUR_FORWARD_SLASHES,
suspicious,
"comments with 4 forward slashes (`////`) likely intended to be doc comments (`///`)"
diff --git a/clippy_lints/src/ignored_unit_patterns.rs b/clippy_lints/src/ignored_unit_patterns.rs
index d8ead1c9d9f68..ef2a66d4a209a 100644
--- a/clippy_lints/src/ignored_unit_patterns.rs
+++ b/clippy_lints/src/ignored_unit_patterns.rs
@@ -37,6 +37,10 @@ declare_lint_pass!(IgnoredUnitPatterns => [IGNORED_UNIT_PATTERNS]);
impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns {
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx hir::Pat<'tcx>) {
+ if pat.span.from_expansion() {
+ return;
+ }
+
match cx.tcx.hir().get_parent(pat.hir_id) {
Node::Param(param) if matches!(cx.tcx.hir().get_parent(param.hir_id), Node::Item(_)) => {
// Ignore function parameters
diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs
index 64a4a3fa741bc..2b2ea156cd4d3 100644
--- a/clippy_lints/src/implicit_hasher.rs
+++ b/clippy_lints/src/implicit_hasher.rs
@@ -6,9 +6,8 @@ use rustc_hir as hir;
use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor};
use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind};
use rustc_hir_analysis::hir_ty_to_ty;
-use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
-use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{Ty, TypeckResults};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
@@ -162,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
vis.visit_ty(ty);
for target in &vis.found {
- if in_external_macro(cx.sess(), generics.span) {
+ if generics.span.from_expansion() {
continue;
}
let generics_suggestion_span = generics.span.substitute_dummy({
diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs
index 55a43e9156282..41477242bcc0b 100644
--- a/clippy_lints/src/items_after_test_module.rs
+++ b/clippy_lints/src/items_after_test_module.rs
@@ -1,10 +1,12 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::{is_from_proc_macro, is_in_cfg_test};
-use rustc_hir::{HirId, ItemId, ItemKind, Mod};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
+use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro};
+use rustc_errors::{Applicability, SuggestionStyle};
+use rustc_hir::{HirId, Item, ItemKind, Mod};
+use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{sym, Span};
+use rustc_span::hygiene::AstPass;
+use rustc_span::{sym, ExpnKind};
declare_clippy_lint! {
/// ### What it does
@@ -41,46 +43,72 @@ declare_clippy_lint! {
declare_lint_pass!(ItemsAfterTestModule => [ITEMS_AFTER_TEST_MODULE]);
-impl LateLintPass<'_> for ItemsAfterTestModule {
- fn check_mod(&mut self, cx: &LateContext<'_>, _: &Mod<'_>, _: HirId) {
- let mut was_test_mod_visited = false;
- let mut test_mod_span: Option = None;
+fn cfg_test_module<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool {
+ if let ItemKind::Mod(test_mod) = item.kind
+ && item.span.hi() == test_mod.spans.inner_span.hi()
+ && is_cfg_test(cx.tcx, item.hir_id())
+ && !item.span.from_expansion()
+ && !is_from_proc_macro(cx, item)
+ {
+ true
+ } else {
+ false
+ }
+}
- let hir = cx.tcx.hir();
- let items = hir.items().collect::>();
+impl LateLintPass<'_> for ItemsAfterTestModule {
+ fn check_mod(&mut self, cx: &LateContext<'_>, module: &Mod<'_>, _: HirId) {
+ let mut items = module.item_ids.iter().map(|&id| cx.tcx.hir().item(id));
- for (i, itid) in items.iter().enumerate() {
- let item = hir.item(*itid);
+ let Some((mod_pos, test_mod)) = items.by_ref().enumerate().find(|(_, item)| cfg_test_module(cx, item)) else {
+ return;
+ };
- if_chain! {
- if was_test_mod_visited;
- if i == (items.len() - 3 /* Weird magic number (HIR-translation behaviour) */);
- if cx.sess().source_map().lookup_char_pos(item.span.lo()).file.name_hash
- == cx.sess().source_map().lookup_char_pos(test_mod_span.unwrap().lo()).file.name_hash; // Will never fail
- if !matches!(item.kind, ItemKind::Mod(_));
- if !is_in_cfg_test(cx.tcx, itid.hir_id()); // The item isn't in the testing module itself
- if !in_external_macro(cx.sess(), item.span);
- if !is_from_proc_macro(cx, item);
+ let after: Vec<_> = items
+ .filter(|item| {
+ // Ignore the generated test main function
+ !(item.ident.name == sym::main
+ && item.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::TestHarness))
+ })
+ .collect();
- then {
- span_lint_and_help(cx, ITEMS_AFTER_TEST_MODULE, test_mod_span.unwrap().with_hi(item.span.hi()), "items were found after the testing module", None, "move the items to before the testing module was defined");
- }};
+ if let Some(last) = after.last()
+ && after.iter().all(|&item| {
+ !matches!(item.kind, ItemKind::Mod(_))
+ && !item.span.from_expansion()
+ && !is_from_proc_macro(cx, item)
+ })
+ && !fulfill_or_allowed(cx, ITEMS_AFTER_TEST_MODULE, after.iter().map(|item| item.hir_id()))
+ {
+ let def_spans: Vec<_> = std::iter::once(test_mod.owner_id)
+ .chain(after.iter().map(|item| item.owner_id))
+ .map(|id| cx.tcx.def_span(id))
+ .collect();
- if let ItemKind::Mod(module) = item.kind && item.span.hi() == module.spans.inner_span.hi() {
- // Check that it works the same way, the only I way I've found for #10713
- for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) {
- if_chain! {
- if attr.has_name(sym::cfg);
- if let Some(mitems) = attr.meta_item_list();
- if let [mitem] = &*mitems;
- if mitem.has_name(sym::test);
- then {
- was_test_mod_visited = true;
- test_mod_span = Some(item.span);
- }
+ span_lint_hir_and_then(
+ cx,
+ ITEMS_AFTER_TEST_MODULE,
+ test_mod.hir_id(),
+ def_spans,
+ "items after a test module",
+ |diag| {
+ if let Some(prev) = mod_pos.checked_sub(1)
+ && let prev = cx.tcx.hir().item(module.item_ids[prev])
+ && let items_span = last.span.with_lo(test_mod.span.hi())
+ && let Some(items) = snippet_opt(cx, items_span)
+ {
+ diag.multipart_suggestion_with_style(
+ "move the items to before the test module was defined",
+ vec![
+ (prev.span.shrink_to_hi(), items),
+ (items_span, String::new())
+ ],
+ Applicability::MachineApplicable,
+ SuggestionStyle::HideCodeAlways,
+ );
}
- }
- }
+ },
+ );
}
}
}
diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs
new file mode 100644
index 0000000000000..43e1b92c9b9a7
--- /dev/null
+++ b/clippy_lints/src/iter_without_into_iter.rs
@@ -0,0 +1,249 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::get_parent_as_impl;
+use clippy_utils::source::snippet;
+use clippy_utils::ty::{implements_trait, make_normalized_projection};
+use rustc_ast::Mutability;
+use rustc_errors::Applicability;
+use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::{self, Ty};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{sym, Symbol};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Looks for `iter` and `iter_mut` methods without an associated `IntoIterator for (&|&mut) Type` implementation.
+ ///
+ /// ### Why is this bad?
+ /// It's not bad, but having them is idiomatic and allows the type to be used in for loops directly
+ /// (`for val in &iter {}`), without having to first call `iter()` or `iter_mut()`.
+ ///
+ /// ### Example
+ /// ```rust
+ /// struct MySlice<'a>(&'a [u8]);
+ /// impl<'a> MySlice<'a> {
+ /// pub fn iter(&self) -> std::slice::Iter<'a, u8> {
+ /// self.0.iter()
+ /// }
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// struct MySlice<'a>(&'a [u8]);
+ /// impl<'a> MySlice<'a> {
+ /// pub fn iter(&self) -> std::slice::Iter<'a, u8> {
+ /// self.0.iter()
+ /// }
+ /// }
+ /// impl<'a> IntoIterator for &MySlice<'a> {
+ /// type Item = &'a u8;
+ /// type IntoIter = std::slice::Iter<'a, u8>;
+ /// fn into_iter(self) -> Self::IntoIter {
+ /// self.iter()
+ /// }
+ /// }
+ /// ```
+ #[clippy::version = "1.74.0"]
+ pub ITER_WITHOUT_INTO_ITER,
+ pedantic,
+ "implementing `iter(_mut)` without an associated `IntoIterator for (&|&mut) Type` impl"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// This is the opposite of the `iter_without_into_iter` lint.
+ /// It looks for `IntoIterator for (&|&mut) Type` implementations without an inherent `iter` or `iter_mut` method.
+ ///
+ /// ### Why is this bad?
+ /// It's not bad, but having them is idiomatic and allows the type to be used in iterator chains
+ /// by just calling `.iter()`, instead of the more awkward `<&Type>::into_iter` or `(&val).iter()` syntax
+ /// in case of ambiguity with another `Intoiterator` impl.
+ ///
+ /// ### Example
+ /// ```rust
+ /// struct MySlice<'a>(&'a [u8]);
+ /// impl<'a> IntoIterator for &MySlice<'a> {
+ /// type Item = &'a u8;
+ /// type IntoIter = std::slice::Iter<'a, u8>;
+ /// fn into_iter(self) -> Self::IntoIter {
+ /// self.0.iter()
+ /// }
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// struct MySlice<'a>(&'a [u8]);
+ /// impl<'a> MySlice<'a> {
+ /// pub fn iter(&self) -> std::slice::Iter<'a, u8> {
+ /// self.into_iter()
+ /// }
+ /// }
+ /// impl<'a> IntoIterator for &MySlice<'a> {
+ /// type Item = &'a u8;
+ /// type IntoIter = std::slice::Iter<'a, u8>;
+ /// fn into_iter(self) -> Self::IntoIter {
+ /// self.0.iter()
+ /// }
+ /// }
+ /// ```
+ #[clippy::version = "1.74.0"]
+ pub INTO_ITER_WITHOUT_ITER,
+ pedantic,
+ "implementing `IntoIterator for (&|&mut) Type` without an inherent `iter(_mut)` method"
+}
+
+declare_lint_pass!(IterWithoutIntoIter => [ITER_WITHOUT_INTO_ITER, INTO_ITER_WITHOUT_ITER]);
+
+/// Checks if a given type is nameable in a trait (impl).
+/// RPIT is stable, but impl Trait in traits is not (yet), so when we have
+/// a function such as `fn iter(&self) -> impl IntoIterator`, we can't
+/// suggest `type IntoIter = impl IntoIterator`.
+fn is_nameable_in_impl_trait(ty: &rustc_hir::Ty<'_>) -> bool {
+ !matches!(ty.kind, TyKind::OpaqueDef(..))
+}
+
+fn type_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool {
+ if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) {
+ cx.tcx.inherent_impls(ty_did).iter().any(|&did| {
+ cx.tcx
+ .associated_items(did)
+ .filter_by_name_unhygienic(method_name)
+ .next()
+ .is_some_and(|item| item.kind == ty::AssocKind::Fn)
+ })
+ } else {
+ false
+ }
+}
+
+impl LateLintPass<'_> for IterWithoutIntoIter {
+ fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
+ if let ItemKind::Impl(imp) = item.kind
+ && let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind
+ && let Some(trait_ref) = imp.of_trait
+ && trait_ref.trait_def_id().is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did))
+ && let &ty::Ref(_, ty, mtbl) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind()
+ && let expected_method_name = match mtbl {
+ Mutability::Mut => sym::iter_mut,
+ Mutability::Not => sym::iter,
+ }
+ && !type_has_inherent_method(cx, ty, expected_method_name)
+ && let Some(iter_assoc_span) = imp.items.iter().find_map(|item| {
+ if item.ident.name == sym!(IntoIter) {
+ Some(cx.tcx.hir().impl_item(item.id).expect_type().span)
+ } else {
+ None
+ }
+ })
+ {
+ span_lint_and_then(
+ cx,
+ INTO_ITER_WITHOUT_ITER,
+ item.span,
+ &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
+ // that we don't want to call.
+ let sugg = format!(
+"
+impl {self_ty_without_ref} {{
+ fn {expected_method_name}({ref_self}self) -> {iter_ty} {{
+ <{ref_self}Self as IntoIterator>::into_iter(self)
+ }}
+}}
+",
+ self_ty_without_ref = snippet(cx, self_ty_without_ref.ty.span, ".."),
+ ref_self = mtbl.ref_prefix_str(),
+ iter_ty = snippet(cx, iter_assoc_span, ".."),
+ );
+
+ diag.span_suggestion_verbose(
+ item.span.shrink_to_lo(),
+ format!("consider implementing `{expected_method_name}`"),
+ sugg,
+ // Just like iter_without_into_iter, this suggestion is on a best effort basis
+ // and requires potentially adding lifetimes or moving them around.
+ Applicability::Unspecified
+ );
+ }
+ );
+ }
+ }
+
+ fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) {
+ let item_did = item.owner_id.to_def_id();
+ let (borrow_prefix, expected_implicit_self) = match item.ident.name {
+ sym::iter => ("&", ImplicitSelfKind::ImmRef),
+ sym::iter_mut => ("&mut ", ImplicitSelfKind::MutRef),
+ _ => return,
+ };
+
+ if let ImplItemKind::Fn(sig, _) = item.kind
+ && let FnRetTy::Return(ret) = sig.decl.output
+ && is_nameable_in_impl_trait(ret)
+ && cx.tcx.generics_of(item_did).params.is_empty()
+ && sig.decl.implicit_self == expected_implicit_self
+ && sig.decl.inputs.len() == 1
+ && let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id())
+ && imp.of_trait.is_none()
+ && let sig = cx.tcx.liberate_late_bound_regions(
+ item_did,
+ cx.tcx.fn_sig(item_did).instantiate_identity()
+ )
+ && let ref_ty = sig.inputs()[0]
+ && let Some(into_iter_did) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
+ && let Some(iterator_did) = cx.tcx.get_diagnostic_item(sym::Iterator)
+ && let ret_ty = sig.output()
+ // Order is important here, we need to check that the `fn iter` return type actually implements `IntoIterator`
+ // *before* normalizing `<_ as IntoIterator>::Item` (otherwise make_normalized_projection ICEs)
+ && implements_trait(cx, ret_ty, iterator_did, &[])
+ && let Some(iter_ty) = make_normalized_projection(
+ cx.tcx,
+ cx.param_env,
+ iterator_did,
+ sym!(Item),
+ [ret_ty],
+ )
+ // Only lint if the `IntoIterator` impl doesn't actually exist
+ && !implements_trait(cx, ref_ty, into_iter_did, &[])
+ {
+ let self_ty_snippet = format!("{borrow_prefix}{}", snippet(cx, imp.self_ty.span, ".."));
+
+ span_lint_and_then(
+ cx,
+ ITER_WITHOUT_INTO_ITER,
+ item.span,
+ &format!("`{}` method without an `IntoIterator` impl for `{self_ty_snippet}`", item.ident),
+ |diag| {
+ // Get the lower span of the `impl` block, and insert the suggestion right before it:
+ // impl X {
+ // ^ fn iter(&self) -> impl IntoIterator { ... }
+ // }
+ let span_behind_impl = cx.tcx
+ .def_span(cx.tcx.hir().parent_id(item.hir_id()).owner.def_id)
+ .shrink_to_lo();
+
+ let sugg = format!(
+"
+impl IntoIterator for {self_ty_snippet} {{
+ type IntoIter = {ret_ty};
+ type Iter = {iter_ty};
+ fn into_iter() -> Self::IntoIter {{
+ self.iter()
+ }}
+}}
+"
+ );
+ diag.span_suggestion_verbose(
+ span_behind_impl,
+ format!("consider implementing `IntoIterator` for `{self_ty_snippet}`"),
+ sugg,
+ // Suggestion is on a best effort basis, might need some adjustments by the user
+ // such as adding some lifetimes in the associated types, or importing types.
+ Applicability::Unspecified,
+ );
+ });
+ }
+ }
+}
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 1271be2fd9368..0f35ec2766574 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -169,6 +169,7 @@ mod invalid_upcast_comparisons;
mod items_after_statements;
mod items_after_test_module;
mod iter_not_returning_iterator;
+mod iter_without_into_iter;
mod large_const_arrays;
mod large_enum_variant;
mod large_futures;
@@ -190,6 +191,7 @@ mod manual_async_fn;
mod manual_bits;
mod manual_clamp;
mod manual_float_methods;
+mod manual_hash_one;
mod manual_is_ascii_check;
mod manual_let_else;
mod manual_main_separator_str;
@@ -1119,6 +1121,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
msrv(),
))
});
+ store.register_late_pass(move |_| Box::new(manual_hash_one::ManualHashOne::new(msrv())));
+ store.register_late_pass(|_| Box::new(iter_without_into_iter::IterWithoutIntoIter));
// add lints here, do not remove this comment, it's used in `new_lint`
}
diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs
index 88db7ae6aece0..ed9189a180495 100644
--- a/clippy_lints/src/manual_float_methods.rs
+++ b/clippy_lints/src/manual_float_methods.rs
@@ -26,7 +26,7 @@ declare_clippy_lint! {
/// # let x = 1.0f32;
/// if x.is_infinite() {}
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub MANUAL_IS_INFINITE,
style,
"use dedicated method to check if a float is infinite"
@@ -51,7 +51,7 @@ declare_clippy_lint! {
/// if x.is_finite() {}
/// if x.is_finite() {}
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub MANUAL_IS_FINITE,
style,
"use dedicated method to check if a float is finite"
diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs
new file mode 100644
index 0000000000000..ea91133545044
--- /dev/null
+++ b/clippy_lints/src/manual_hash_one.rs
@@ -0,0 +1,133 @@
+use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::source::snippet_opt;
+use clippy_utils::visitors::{is_local_used, local_used_once};
+use clippy_utils::{is_trait_method, path_to_local_id};
+use rustc_errors::Applicability;
+use rustc_hir::{BindingAnnotation, ExprKind, Local, Node, PatKind, StmtKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for cases where [`BuildHasher::hash_one`] can be used.
+ ///
+ /// [`BuildHasher::hash_one`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html#method.hash_one
+ ///
+ /// ### Why is this bad?
+ /// It is more concise to use the `hash_one` method.
+ ///
+ /// ### Example
+ /// ```rust
+ /// use std::hash::{BuildHasher, Hash, Hasher};
+ /// use std::collections::hash_map::RandomState;
+ ///
+ /// let s = RandomState::new();
+ /// let value = vec![1, 2, 3];
+ ///
+ /// let mut hasher = s.build_hasher();
+ /// value.hash(&mut hasher);
+ /// let hash = hasher.finish();
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// use std::hash::BuildHasher;
+ /// use std::collections::hash_map::RandomState;
+ ///
+ /// let s = RandomState::new();
+ /// let value = vec![1, 2, 3];
+ ///
+ /// let hash = s.hash_one(&value);
+ /// ```
+ #[clippy::version = "1.74.0"]
+ pub MANUAL_HASH_ONE,
+ complexity,
+ "manual implementations of `BuildHasher::hash_one`"
+}
+
+pub struct ManualHashOne {
+ msrv: Msrv,
+}
+
+impl ManualHashOne {
+ #[must_use]
+ pub fn new(msrv: Msrv) -> Self {
+ Self { msrv }
+ }
+}
+
+impl_lint_pass!(ManualHashOne => [MANUAL_HASH_ONE]);
+
+impl LateLintPass<'_> for ManualHashOne {
+ fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
+ // `let mut hasher = seg.build_hasher();`
+ if let PatKind::Binding(BindingAnnotation::MUT, hasher, _, None) = local.pat.kind
+ && let Some(init) = local.init
+ && !init.span.from_expansion()
+ && let ExprKind::MethodCall(seg, build_hasher, [], _) = init.kind
+ && seg.ident.name == sym!(build_hasher)
+
+ && let Node::Stmt(local_stmt) = cx.tcx.hir().get_parent(local.hir_id)
+ && let Node::Block(block) = cx.tcx.hir().get_parent(local_stmt.hir_id)
+
+ && let mut stmts = block.stmts.iter()
+ .skip_while(|stmt| stmt.hir_id != local_stmt.hir_id)
+ .skip(1)
+ .filter(|&stmt| is_local_used(cx, stmt, hasher))
+
+ // `hashed_value.hash(&mut hasher);`
+ && let Some(hash_stmt) = stmts.next()
+ && let StmtKind::Semi(hash_expr) = hash_stmt.kind
+ && !hash_expr.span.from_expansion()
+ && let ExprKind::MethodCall(seg, hashed_value, [ref_to_hasher], _) = hash_expr.kind
+ && seg.ident.name == sym::hash
+ && is_trait_method(cx, hash_expr, sym::Hash)
+ && path_to_local_id(ref_to_hasher.peel_borrows(), hasher)
+
+ && let maybe_finish_stmt = stmts.next()
+ // There should be no more statements referencing `hasher`
+ && stmts.next().is_none()
+
+ // `hasher.finish()`, may be anywhere in a statement or the trailing expr of the block
+ && let Some(path_expr) = local_used_once(cx, (maybe_finish_stmt, block.expr), hasher)
+ && let Node::Expr(finish_expr) = cx.tcx.hir().get_parent(path_expr.hir_id)
+ && !finish_expr.span.from_expansion()
+ && let ExprKind::MethodCall(seg, _, [], _) = finish_expr.kind
+ && seg.ident.name == sym!(finish)
+
+ && self.msrv.meets(msrvs::BUILD_HASHER_HASH_ONE)
+ {
+ span_lint_hir_and_then(
+ cx,
+ MANUAL_HASH_ONE,
+ finish_expr.hir_id,
+ finish_expr.span,
+ "manual implementation of `BuildHasher::hash_one`",
+ |diag| {
+ if let Some(build_hasher) = snippet_opt(cx, build_hasher.span)
+ && let Some(hashed_value) = snippet_opt(cx, hashed_value.span)
+ {
+ diag.multipart_suggestion(
+ "try",
+ vec![
+ (local_stmt.span, String::new()),
+ (hash_stmt.span, String::new()),
+ (
+ finish_expr.span,
+ // `needless_borrows_for_generic_args` will take care of
+ // removing the `&` when it isn't needed
+ format!("{build_hasher}.hash_one(&{hashed_value})")
+ )
+ ],
+ Applicability::MachineApplicable,
+ );
+
+ }
+ },
+ );
+ }
+ }
+
+ extract_msrv_attr!(LateContext);
+}
diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs
index c531137b785e8..2117308cd4009 100644
--- a/clippy_lints/src/manual_let_else.rs
+++ b/clippy_lints/src/manual_let_else.rs
@@ -136,9 +136,9 @@ fn emit_manual_let_else(
// for this to be machine applicable.
let mut app = Applicability::HasPlaceholders;
let (sn_expr, _) = snippet_with_context(cx, expr.span, span.ctxt(), "", &mut app);
- let (sn_else, _) = snippet_with_context(cx, else_body.span, span.ctxt(), "", &mut app);
+ let (sn_else, else_is_mac_call) = snippet_with_context(cx, else_body.span, span.ctxt(), "", &mut app);
- let else_bl = if matches!(else_body.kind, ExprKind::Block(..)) {
+ let else_bl = if matches!(else_body.kind, ExprKind::Block(..)) && !else_is_mac_call {
sn_else.into_owned()
} else {
format!("{{ {sn_else} }}")
diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs
index 0e22485db2c59..c12727c4a28cc 100644
--- a/clippy_lints/src/manual_non_exhaustive.rs
+++ b/clippy_lints/src/manual_non_exhaustive.rs
@@ -3,6 +3,7 @@ use clippy_utils::is_doc_hidden;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_opt;
use rustc_ast::ast::{self, VisibilityKind};
+use rustc_ast::attr;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
@@ -158,7 +159,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
let mut iter = def.variants.iter().filter_map(|v| {
(matches!(v.data, hir::VariantData::Unit(_, _))
&& v.ident.as_str().starts_with('_')
- && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id)))
+ && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id))
+ && !attr::contains_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive))
.then_some((v.def_id, v.span))
});
if let Some((id, span)) = iter.next()
@@ -198,16 +200,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
enum_span,
"this seems like a manual implementation of the non-exhaustive pattern",
|diag| {
- if !cx.tcx.adt_def(enum_id).is_variant_list_non_exhaustive()
- && let header_span = cx.sess().source_map().span_until_char(enum_span, '{')
- && let Some(snippet) = snippet_opt(cx, header_span)
- {
- diag.span_suggestion(
- header_span,
- "add the attribute",
- format!("#[non_exhaustive] {snippet}"),
- Applicability::Unspecified,
- );
+ let header_span = cx.sess().source_map().span_until_char(enum_span, '{');
+ if let Some(snippet) = snippet_opt(cx, header_span) {
+ diag.span_suggestion(
+ header_span,
+ "add the attribute",
+ format!("#[non_exhaustive] {snippet}"),
+ Applicability::Unspecified,
+ );
}
diag.span_help(variant_span, "remove this variant");
},
diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs
index 930386a60aa02..a23000e5fe15c 100644
--- a/clippy_lints/src/matches/mod.rs
+++ b/clippy_lints/src/matches/mod.rs
@@ -961,7 +961,7 @@ declare_clippy_lint! {
/// _ => todo!(),
/// }
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub REDUNDANT_GUARDS,
complexity,
"checks for unnecessary guards in match expressions"
diff --git a/clippy_lints/src/matches/overlapping_arms.rs b/clippy_lints/src/matches/overlapping_arms.rs
index 7c0485914b83b..8f0083f812cc2 100644
--- a/clippy_lints/src/matches/overlapping_arms.rs
+++ b/clippy_lints/src/matches/overlapping_arms.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt};
+use clippy_utils::consts::{constant, constant_full_int, mir_to_const, FullInt};
use clippy_utils::diagnostics::span_lint_and_note;
use core::cmp::Ordering;
use rustc_hir::{Arm, Expr, PatKind, RangeEnd};
@@ -37,14 +37,14 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
Some(lhs) => constant(cx, cx.typeck_results(), lhs)?,
None => {
let min_val_const = ty.numeric_min_val(cx.tcx)?;
- miri_to_const(cx, mir::Const::from_ty_const(min_val_const, cx.tcx))?
+ mir_to_const(cx, mir::Const::from_ty_const(min_val_const, cx.tcx))?
},
};
let rhs_const = match rhs {
Some(rhs) => constant(cx, cx.typeck_results(), rhs)?,
None => {
let max_val_const = ty.numeric_max_val(cx.tcx)?;
- miri_to_const(cx, mir::Const::from_ty_const(max_val_const, cx.tcx))?
+ mir_to_const(cx, mir::Const::from_ty_const(max_val_const, cx.tcx))?
},
};
let lhs_val = lhs_const.int_value(cx, ty)?;
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index e7fcef9e9de27..a935aea5075d7 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -2970,7 +2970,7 @@ declare_clippy_lint! {
/// assert_eq!((*any_box).type_id(), TypeId::of::());
/// // ^ dereference first, to call `type_id` on `dyn Any`
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub TYPE_ID_ON_BOX,
suspicious,
"calling `.type_id()` on `Box`"
@@ -3368,6 +3368,7 @@ declare_clippy_lint! {
}
declare_clippy_lint! {
+ /// ### What it does
/// Looks for calls to [`Stdin::read_line`] to read a line from the standard input
/// into a string, then later attempting to parse this string into a type without first trimming it, which will
/// always fail because the string has a trailing newline in it.
@@ -3390,7 +3391,7 @@ declare_clippy_lint! {
/// // ^^^^^^^^^^^ remove the trailing newline
/// assert_eq!(num, 42);
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub READ_LINE_WITHOUT_TRIM,
correctness,
"calling `Stdin::read_line`, then trying to parse it without first trimming"
@@ -3418,7 +3419,7 @@ declare_clippy_lint! {
/// # let c = 'c';
/// matches!(c, '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub STRING_LIT_CHARS_ANY,
restriction,
"checks for `.chars().any(|i| i == c)`"
@@ -3453,7 +3454,7 @@ declare_clippy_lint! {
/// })
/// }
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub FORMAT_COLLECT,
perf,
"`format!`ing every element in a collection, then collecting the strings into a new `String`"
@@ -3474,7 +3475,7 @@ declare_clippy_lint! {
/// let y = v.iter().collect::>();
/// assert_eq!(x, y);
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub ITER_SKIP_ZERO,
correctness,
"disallows `.skip(0)`"
@@ -3505,7 +3506,7 @@ declare_clippy_lint! {
/// # let v = vec![];
/// _ = v.into_iter().filter(|i| i % 2 == 0).map(|i| really_expensive_fn(i));
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub FILTER_MAP_BOOL_THEN,
style,
"checks for usage of `bool::then` in `Iterator::filter_map`"
diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
index 24c0ea3f60a99..3e19d72ec912a 100644
--- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
+++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
@@ -24,7 +24,6 @@ fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) -
}
}
-#[expect(clippy::too_many_lines)]
pub(super) fn check(
cx: &LateContext<'_>,
expr: &hir::Expr<'_>,
@@ -101,11 +100,11 @@ pub(super) fn check(
(expr.span.with_lo(args[0].span.hi()), String::new()),
]),
("None", "unwrap_or_else", _) => match args[0].kind {
- hir::ExprKind::Closure(hir::Closure {
- body,
- ..
- }) => Some(vec![
- (expr.span.with_hi(cx.tcx.hir().body(*body).value.span.lo()), String::new()),
+ hir::ExprKind::Closure(hir::Closure { body, .. }) => Some(vec![
+ (
+ expr.span.with_hi(cx.tcx.hir().body(*body).value.span.lo()),
+ String::new(),
+ ),
(expr.span.with_lo(args[0].span.hi()), String::new()),
]),
_ => None,
diff --git a/clippy_lints/src/missing_assert_message.rs b/clippy_lints/src/missing_assert_message.rs
index c17f00c427515..136947a2c8cd3 100644
--- a/clippy_lints/src/missing_assert_message.rs
+++ b/clippy_lints/src/missing_assert_message.rs
@@ -15,6 +15,10 @@ declare_clippy_lint! {
/// A good custom message should be more about why the failure of the assertion is problematic
/// and not what is failed because the assertion already conveys that.
///
+ /// Although the same reasoning applies to testing functions, this lint ignores them as they would be too noisy.
+ /// Also, in most cases understanding the test failure would be easier
+ /// compared to understanding a complex invariant distributed around the codebase.
+ ///
/// ### Known problems
/// This lint cannot check the quality of the custom panic messages.
/// Hence, you can suppress this lint simply by adding placeholder messages
diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs
index ea6a9bc5657da..e87aea263d48e 100644
--- a/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -135,10 +135,7 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
}
fn stmt_might_diverge(stmt: &Stmt<'_>) -> bool {
- match stmt.kind {
- StmtKind::Item(..) => false,
- _ => true,
- }
+ !matches!(stmt.kind, StmtKind::Item(..))
}
impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
@@ -148,7 +145,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
ExprKind::Block(block, ..) => match (block.stmts, block.expr) {
(stmts, Some(e)) => {
if stmts.iter().all(|stmt| !stmt_might_diverge(stmt)) {
- self.visit_expr(e)
+ self.visit_expr(e);
}
},
([first @ .., stmt], None) => {
diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs
index 57652e5ff546b..212d6234bdb3c 100644
--- a/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -47,9 +47,9 @@ declare_clippy_lint! {
/// 12 + *y
/// }
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub NEEDLESS_PASS_BY_REF_MUT,
- suspicious,
+ nursery,
"using a `&mut` argument when it's not mutated"
}
diff --git a/clippy_lints/src/non_canonical_impls.rs b/clippy_lints/src/non_canonical_impls.rs
index 4be140647fcc4..0e4b6aa1b7d23 100644
--- a/clippy_lints/src/non_canonical_impls.rs
+++ b/clippy_lints/src/non_canonical_impls.rs
@@ -102,7 +102,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub NON_CANONICAL_PARTIAL_ORD_IMPL,
suspicious,
"non-canonical implementation of `PartialOrd` on an `Ord` type"
diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs
index 4635e1164cd31..6b247cf5f6ae1 100644
--- a/clippy_lints/src/operators/mod.rs
+++ b/clippy_lints/src/operators/mod.rs
@@ -312,7 +312,7 @@ declare_clippy_lint! {
/// # let status_code = 200;
/// if status_code <= 400 && status_code > 500 {}
/// ```
- #[clippy::version = "1.71.0"]
+ #[clippy::version = "1.73.0"]
pub IMPOSSIBLE_COMPARISONS,
correctness,
"double comparisons that will never evaluate to `true`"
@@ -332,7 +332,7 @@ declare_clippy_lint! {
/// # let status_code = 200;
/// if status_code <= 400 && status_code < 500 {}
/// ```
- #[clippy::version = "1.71.0"]
+ #[clippy::version = "1.73.0"]
pub REDUNDANT_COMPARISONS,
correctness,
"double comparisons where one of them can be removed"
diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs
index 8a7e487466610..c951d9a4a09d5 100644
--- a/clippy_lints/src/raw_strings.rs
+++ b/clippy_lints/src/raw_strings.rs
@@ -75,6 +75,7 @@ impl EarlyLintPass for RawStrings {
if !snippet(cx, expr.span, prefix).trim().starts_with(prefix) {
return;
}
+ let descr = lit.kind.descr();
if !str.contains(['\\', '"']) {
span_lint_and_then(
@@ -89,20 +90,17 @@ impl EarlyLintPass for RawStrings {
let r_pos = expr.span.lo() + BytePos::from_usize(prefix.len() - 1);
let start = start.with_lo(r_pos);
- if end.is_empty() {
- diag.span_suggestion(
- start,
- "use a string literal instead",
- format!("\"{str}\""),
- Applicability::MachineApplicable,
- );
- } else {
- diag.multipart_suggestion(
- "try",
- vec![(start, String::new()), (end, String::new())],
- Applicability::MachineApplicable,
- );
+ let mut remove = vec![(start, String::new())];
+ // avoid debug ICE from empty suggestions
+ if !end.is_empty() {
+ remove.push((end, String::new()));
}
+
+ diag.multipart_suggestion_verbose(
+ format!("use a plain {descr} literal instead"),
+ remove,
+ Applicability::MachineApplicable,
+ );
},
);
if !matches!(cx.get_lint_level(NEEDLESS_RAW_STRINGS), rustc_lint::Allow) {
@@ -149,9 +147,9 @@ impl EarlyLintPass for RawStrings {
let (start, end) = hash_spans(expr.span, prefix, req, max);
let message = match max - req {
- _ if req == 0 => "remove all the hashes around the literal".to_string(),
- 1 => "remove one hash from both sides of the literal".to_string(),
- n => format!("remove {n} hashes from both sides of the literal"),
+ _ if req == 0 => format!("remove all the hashes around the {descr} literal"),
+ 1 => format!("remove one hash from both sides of the {descr} literal"),
+ n => format!("remove {n} hashes from both sides of the {descr} literal"),
};
diag.multipart_suggestion(
diff --git a/clippy_lints/src/redundant_locals.rs b/clippy_lints/src/redundant_locals.rs
index 0c89c7ee47d36..197742b5dd41d 100644
--- a/clippy_lints/src/redundant_locals.rs
+++ b/clippy_lints/src/redundant_locals.rs
@@ -3,11 +3,9 @@ use clippy_utils::is_from_proc_macro;
use clippy_utils::ty::needs_ordered_drop;
use rustc_ast::Mutability;
use rustc_hir::def::Res;
-use rustc_hir::{
- BindingAnnotation, ByRef, Expr, ExprKind, HirId, Local, Node, Pat, PatKind, QPath,
-};
+use rustc_hir::{BindingAnnotation, ByRef, ExprKind, HirId, Local, Node, Pat, PatKind, QPath};
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::{in_external_macro, is_from_async_await};
+use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::Ident;
use rustc_span::DesugaringKind;
@@ -39,7 +37,7 @@ declare_clippy_lint! {
/// // no redefinition with the same name
/// }
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub REDUNDANT_LOCALS,
correctness,
"redundant redefinition of a local binding"
@@ -68,21 +66,18 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
// the local does not change the effect of assignments to the binding. see #11290
if !affects_assignments(cx, mutability, binding_id, local.hir_id);
// the local does not affect the code's drop behavior
- if !affects_drop_behavior(cx, binding_id, local.hir_id, expr);
+ if !needs_ordered_drop(cx, cx.typeck_results().expr_ty(expr));
// the local is user-controlled
if !in_external_macro(cx.sess(), local.span);
if !is_from_proc_macro(cx, expr);
- // Async function parameters are lowered into the closure body, so we can't lint them.
- // see `lower_maybe_async_body` in `rust_ast_lowering`
- if !is_from_async_await(local.span);
then {
span_lint_and_help(
cx,
REDUNDANT_LOCALS,
- vec![binding_pat.span, local.span],
- "redundant redefinition of a binding",
- None,
- &format!("remove the redefinition of `{ident}`"),
+ local.span,
+ &format!("redundant redefinition of a binding `{ident}`"),
+ Some(binding_pat.span),
+ &format!("`{ident}` is initially defined here"),
);
}
}
@@ -109,18 +104,3 @@ fn affects_assignments(cx: &LateContext<'_>, mutability: Mutability, bind: HirId
// the binding is mutable and the rebinding is in a different scope than the original binding
mutability == Mutability::Mut && hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind)
}
-
-/// Check if a rebinding of a local affects the code's drop behavior.
-fn affects_drop_behavior<'tcx>(
- cx: &LateContext<'tcx>,
- bind: HirId,
- rebind: HirId,
- rebind_expr: &Expr<'tcx>,
-) -> bool {
- let hir = cx.tcx.hir();
-
- // the rebinding is in a different scope than the original binding
- // and the type of the binding cares about drop order
- hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind)
- && needs_ordered_drop(cx, cx.typeck_results().expr_ty(rebind_expr))
-}
diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs
index 5f54a10d1c41d..b7396535eedff 100644
--- a/clippy_lints/src/std_instead_of_core.rs
+++ b/clippy_lints/src/std_instead_of_core.rs
@@ -1,9 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_from_proc_macro;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
use rustc_hir::{HirId, Path, PathSegment};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::kw;
use rustc_span::{sym, Span};
@@ -99,6 +101,8 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
if let Res::Def(_, def_id) = path.res
&& let Some(first_segment) = get_first_segment(path)
&& is_stable(cx, def_id)
+ && !in_external_macro(cx.sess(), path.span)
+ && !is_from_proc_macro(cx, &first_segment.ident)
{
let (lint, used_mod, replace_with) = match first_segment.ident.name {
sym::std => match cx.tcx.crate_name(def_id.krate) {
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 75c3c7a958a21..23da1de77303e 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -294,7 +294,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.
+ /// 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.
///
/// The minimum rust version that the project supports
(msrv: Option = None),
@@ -744,3 +744,44 @@ fn calculate_dimensions(fields: &[&str]) -> (usize, Vec) {
(rows, column_widths)
}
+
+#[cfg(test)]
+mod tests {
+ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+ use serde::de::IgnoredAny;
+ use std::fs;
+ use walkdir::WalkDir;
+
+ #[test]
+ fn configs_are_tested() {
+ let mut names: FxHashSet = super::metadata::get_configuration_metadata()
+ .into_iter()
+ .map(|meta| meta.name.replace('_', "-"))
+ .collect();
+
+ let toml_files = WalkDir::new("../tests")
+ .into_iter()
+ .map(Result::unwrap)
+ .filter(|entry| entry.file_name() == "clippy.toml");
+
+ for entry in toml_files {
+ let file = fs::read_to_string(entry.path()).unwrap();
+ #[allow(clippy::zero_sized_map_values)]
+ if let Ok(map) = toml::from_str::>(&file) {
+ for name in map.keys() {
+ names.remove(name.as_str());
+ }
+ }
+ }
+
+ 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`"
+ );
+ }
+}
diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs
index d09d02a7dfda9..70b83149ce1a6 100644
--- a/clippy_lints/src/wildcard_imports.rs
+++ b/clippy_lints/src/wildcard_imports.rs
@@ -132,6 +132,7 @@ impl LateLintPass<'_> for WildcardImports {
if self.warn_on_all || !self.check_exceptions(item, use_path.segments);
let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id);
if !used_imports.is_empty(); // Already handled by `unused_imports`
+ if !used_imports.contains(&kw::Underscore);
then {
let mut applicability = Applicability::MachineApplicable;
let import_source_snippet = snippet_with_applicability(cx, use_path.span, "..", &mut applicability);
diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs
index da083fb14aae1..855aefa70cb15 100644
--- a/clippy_lints/src/write.rs
+++ b/clippy_lints/src/write.rs
@@ -3,12 +3,15 @@ use clippy_utils::macros::{find_format_args, format_arg_removal_span, root_macro
use clippy_utils::source::{expand_past_previous_comma, snippet_opt};
use clippy_utils::{is_in_cfg_test, is_in_test_function};
use rustc_ast::token::LitKind;
-use rustc_ast::{FormatArgPosition, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, FormatTrait};
+use rustc_ast::{
+ FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder,
+ FormatTrait,
+};
use rustc_errors::Applicability;
use rustc_hir::{Expr, Impl, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{sym, BytePos};
+use rustc_span::{sym, BytePos, Span};
declare_clippy_lint! {
/// ### What it does
@@ -450,6 +453,12 @@ fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call
fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
let arg_index = |argument: &FormatArgPosition| argument.index.unwrap_or_else(|pos| pos);
+ let lint_name = if name.starts_with("write") {
+ WRITE_LITERAL
+ } else {
+ PRINT_LITERAL
+ };
+
let mut counts = vec![0u32; format_args.arguments.all_args().len()];
for piece in &format_args.template {
if let FormatArgsPiece::Placeholder(placeholder) = piece {
@@ -457,6 +466,12 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
}
}
+ let mut suggestion: Vec<(Span, String)> = vec![];
+ // holds index of replaced positional arguments; used to decrement the index of the remaining
+ // positional arguments.
+ let mut replaced_position: Vec = vec![];
+ let mut sug_span: Option = None;
+
for piece in &format_args.template {
if let FormatArgsPiece::Placeholder(FormatPlaceholder {
argument,
@@ -471,9 +486,9 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
&& let rustc_ast::ExprKind::Lit(lit) = &arg.expr.kind
&& !arg.expr.span.from_expansion()
&& let Some(value_string) = snippet_opt(cx, arg.expr.span)
- {
+ {
let (replacement, replace_raw) = match lit.kind {
- LitKind::Str | LitKind::StrRaw(_) => match extract_str_literal(&value_string) {
+ LitKind::Str | LitKind::StrRaw(_) => match extract_str_literal(&value_string) {
Some(extracted) => extracted,
None => return,
},
@@ -493,12 +508,6 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
_ => continue,
};
- let lint = if name.starts_with("write") {
- WRITE_LITERAL
- } else {
- PRINT_LITERAL
- };
-
let Some(format_string_snippet) = snippet_opt(cx, format_args.span) else { continue };
let format_string_is_raw = format_string_snippet.starts_with('r');
@@ -519,29 +528,58 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
},
};
- span_lint_and_then(
- cx,
- lint,
- arg.expr.span,
- "literal with an empty format string",
- |diag| {
- if let Some(replacement) = replacement
- // `format!("{}", "a")`, `format!("{named}", named = "b")
- // ~~~~~ ~~~~~~~~~~~~~
- && let Some(removal_span) = format_arg_removal_span(format_args, index)
- {
- let replacement = replacement.replace('{', "{{").replace('}', "}}");
- diag.multipart_suggestion(
- "try",
- vec![(*placeholder_span, replacement), (removal_span, String::new())],
- Applicability::MachineApplicable,
- );
- }
- },
- );
+ sug_span = Some(sug_span.unwrap_or(arg.expr.span).to(arg.expr.span));
+
+ if let Some((_, index)) = positional_arg_piece_span(piece) {
+ replaced_position.push(index);
+ }
+
+ if let Some(replacement) = replacement
+ // `format!("{}", "a")`, `format!("{named}", named = "b")
+ // ~~~~~ ~~~~~~~~~~~~~
+ && let Some(removal_span) = format_arg_removal_span(format_args, index) {
+ let replacement = escape_braces(&replacement, !format_string_is_raw && !replace_raw);
+ suggestion.push((*placeholder_span, replacement));
+ suggestion.push((removal_span, String::new()));
+ }
+ }
+ }
+ // Decrement the index of the remaining by the number of replaced positional arguments
+ if !suggestion.is_empty() {
+ for piece in &format_args.template {
+ if let Some((span, index)) = positional_arg_piece_span(piece)
+ && suggestion.iter().all(|(s, _)| *s != span) {
+ let decrement = replaced_position.iter().filter(|i| **i < index).count();
+ suggestion.push((span, format!("{{{}}}", index.saturating_sub(decrement))));
+ }
}
}
+
+ if let Some(span) = sug_span {
+ span_lint_and_then(cx, lint_name, span, "literal with an empty format string", |diag| {
+ if !suggestion.is_empty() {
+ diag.multipart_suggestion("try", suggestion, Applicability::MachineApplicable);
+ }
+ });
+ }
+}
+
+/// Extract Span and its index from the given `piece`, iff it's positional argument.
+fn positional_arg_piece_span(piece: &FormatArgsPiece) -> Option<(Span, usize)> {
+ match piece {
+ FormatArgsPiece::Placeholder(FormatPlaceholder {
+ argument:
+ FormatArgPosition {
+ index: Ok(index),
+ kind: FormatArgPositionKind::Number,
+ ..
+ },
+ span: Some(span),
+ ..
+ }) => Some((*span, *index)),
+ _ => None,
+ }
}
/// Removes the raw marker, `#`s and quotes from a str, and returns if the literal is raw
@@ -593,3 +631,47 @@ fn conservative_unescape(literal: &str) -> Result {
if err { Err(UnescapeErr::Lint) } else { Ok(unescaped) }
}
+
+/// Replaces `{` with `{{` and `}` with `}}`. If `preserve_unicode_escapes` is `true` the braces in
+/// `\u{xxxx}` are left unmodified
+#[expect(clippy::match_same_arms)]
+fn escape_braces(literal: &str, preserve_unicode_escapes: bool) -> String {
+ #[derive(Clone, Copy)]
+ enum State {
+ Normal,
+ Backslash,
+ UnicodeEscape,
+ }
+
+ let mut escaped = String::with_capacity(literal.len());
+ let mut state = State::Normal;
+
+ for ch in literal.chars() {
+ state = match (ch, state) {
+ // Escape braces outside of unicode escapes by doubling them up
+ ('{' | '}', State::Normal) => {
+ escaped.push(ch);
+ State::Normal
+ },
+ // If `preserve_unicode_escapes` isn't enabled stay in `State::Normal`, otherwise:
+ //
+ // \u{aaaa} \\ \x01
+ // ^ ^ ^
+ ('\\', State::Normal) if preserve_unicode_escapes => State::Backslash,
+ // \u{aaaa}
+ // ^
+ ('u', State::Backslash) => State::UnicodeEscape,
+ // \xAA \\
+ // ^ ^
+ (_, State::Backslash) => State::Normal,
+ // \u{aaaa}
+ // ^
+ ('}', State::UnicodeEscape) => State::Normal,
+ _ => state,
+ };
+
+ escaped.push(ch);
+ }
+
+ escaped
+}
diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml
index 1596bb773976a..8522493f67b3a 100644
--- a/clippy_utils/Cargo.toml
+++ b/clippy_utils/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clippy_utils"
-version = "0.1.74"
+version = "0.1.75"
edition = "2021"
publish = false
diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs
index d596eed4b7c4d..0bae7056c4fb8 100644
--- a/clippy_utils/src/consts.rs
+++ b/clippy_utils/src/consts.rs
@@ -9,11 +9,12 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp};
use rustc_lexer::tokenize;
use rustc_lint::LateContext;
-use rustc_middle::mir::interpret::Scalar;
+use rustc_middle::mir::interpret::{alloc_range, Scalar};
use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, List, ScalarInt, Ty, TyCtxt};
use rustc_middle::{bug, mir, span_bug};
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::SyntaxContext;
+use rustc_target::abi::Size;
use std::cmp::Ordering::{self, Equal};
use std::hash::{Hash, Hasher};
use std::iter;
@@ -403,7 +404,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
&& adt_def.is_struct()
&& let Some(desired_field) = field_of_struct(*adt_def, self.lcx, *constant, field)
{
- miri_to_const(self.lcx, desired_field)
+ mir_to_const(self.lcx, desired_field)
}
else {
result
@@ -483,7 +484,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
.const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), None)
.ok()
.map(|val| rustc_middle::mir::Const::from_value(val, ty))?;
- let result = miri_to_const(self.lcx, result)?;
+ let result = mir_to_const(self.lcx, result)?;
self.source = ConstantSource::Constant;
Some(result)
},
@@ -655,10 +656,14 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
}
}
-pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option> {
+pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option> {
use rustc_middle::mir::ConstValue;
- match result {
- mir::Const::Val(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() {
+ let mir::Const::Val(val, _) = result else {
+ // We only work on evaluated consts.
+ return None;
+ };
+ match (val, result.ty().kind()) {
+ (ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() {
ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))),
@@ -671,42 +676,28 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) ->
ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))),
_ => None,
},
- mir::Const::Val(cv, _) if matches!(result.ty().kind(), ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Str)) =>
- {
- let data = cv.try_get_slice_bytes_for_diagnostics(lcx.tcx)?;
+ (_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Str) => {
+ let data = val.try_get_slice_bytes_for_diagnostics(lcx.tcx)?;
String::from_utf8(data.to_owned()).ok().map(Constant::Str)
},
- mir::Const::Val(ConstValue::Indirect { alloc_id, offset: _ }, _) => {
- let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory();
- match result.ty().kind() {
- ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
- ty::Array(sub_type, len) => match sub_type.kind() {
- ty::Float(FloatTy::F32) => match len.try_to_target_usize(lcx.tcx) {
- Some(len) => alloc
- .inner()
- .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len).unwrap()))
- .to_owned()
- .array_chunks::<4>()
- .map(|&chunk| Some(Constant::F32(f32::from_le_bytes(chunk))))
- .collect::