diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs index 9acff676d4f6b..8b8b42bbf7228 100644 --- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs +++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs @@ -3,14 +3,13 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; -use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local}; +use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local, sym}; use rustc_errors::Applicability; use rustc_hir::{self as hir, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir; use rustc_middle::ty::{self, Instance, Mutability}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::sym; use rustc_span::{Span, SyntaxContext}; declare_clippy_lint! { @@ -86,9 +85,9 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones { && ctxt.is_root() && let which_trait = match fn_name { sym::clone if is_diag_trait_item(cx, fn_id, sym::Clone) => CloneTrait::Clone, - _ if fn_name.as_str() == "to_owned" - && is_diag_trait_item(cx, fn_id, sym::ToOwned) - && self.msrv.meets(cx, msrvs::CLONE_INTO) => + sym::to_owned + if is_diag_trait_item(cx, fn_id, sym::ToOwned) + && self.msrv.meets(cx, msrvs::CLONE_INTO) => { CloneTrait::ToOwned }, @@ -112,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones { && resolved_assoc_items.in_definition_order().any(|assoc| match which_trait { CloneTrait::Clone => assoc.name() == sym::clone_from, - CloneTrait::ToOwned => assoc.name().as_str() == "clone_into", + CloneTrait::ToOwned => assoc.name() == sym::clone_into, } ) && !clone_source_borrows_from_dest(cx, lhs, rhs.span) diff --git a/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs b/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs index 457692ed5dc53..4d64eec25d273 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs @@ -1,17 +1,15 @@ use super::BLANKET_CLIPPY_RESTRICTION_LINTS; use super::utils::extract_clippy_lint; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; +use clippy_utils::sym; use rustc_ast::MetaItemInner; use rustc_lint::{EarlyContext, Level, LintContext}; +use rustc_span::DUMMY_SP; use rustc_span::symbol::Symbol; -use rustc_span::{DUMMY_SP, sym}; pub(super) fn check(cx: &EarlyContext<'_>, name: Symbol, items: &[MetaItemInner]) { for lint in items { - if let Some(lint_name) = extract_clippy_lint(lint) - && lint_name.as_str() == "restriction" - && name != sym::allow - { + if name != sym::allow && extract_clippy_lint(lint) == Some(sym::restriction) { span_lint_and_help( cx, BLANKET_CLIPPY_RESTRICTION_LINTS, diff --git a/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs b/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs index 7fab97d3ea146..0edb50be8c778 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs @@ -73,7 +73,7 @@ fn check_deprecated_cfg_recursively(cx: &EarlyContext<'_>, attr: &rustc_ast::Met } fn check_cargo_clippy_attr(cx: &EarlyContext<'_>, item: &rustc_ast::MetaItem) { - if item.has_name(sym::feature) && item.value_str().is_some_and(|v| v.as_str() == "cargo-clippy") { + if item.has_name(sym::feature) && item.value_str() == Some(sym::cargo_clippy) { span_lint_and_sugg( cx, DEPRECATED_CLIPPY_CFG_ATTR, diff --git a/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs b/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs index 50943b36809d2..bd6459d6f9dbc 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs @@ -1,5 +1,6 @@ use super::DEPRECATED_SEMVER; use clippy_utils::diagnostics::span_lint; +use clippy_utils::sym; use rustc_ast::{LitKind, MetaItemLit}; use rustc_lint::EarlyContext; use rustc_span::Span; @@ -7,7 +8,7 @@ use semver::Version; pub(super) fn check(cx: &EarlyContext<'_>, span: Span, lit: &MetaItemLit) { if let LitKind::Str(is, _) = lit.kind - && (is.as_str() == "TBD" || Version::parse(is.as_str()).is_ok()) + && (is == sym::TBD || Version::parse(is.as_str()).is_ok()) { return; } diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs index 164d3540253a0..ba31a51f738a6 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; +use clippy_utils::sym; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; @@ -19,7 +20,7 @@ pub(super) fn check( if let ty::Int(from) = cast_from.kind() && let ty::Uint(to) = cast_to.kind() && let ExprKind::MethodCall(method_path, receiver, [], _) = cast_expr.kind - && method_path.ident.name.as_str() == "abs" + && method_path.ident.name == sym::abs && msrv.meets(cx, msrvs::UNSIGNED_ABS) { let span = if from.bit_width() == to.bit_width() { diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs index 8742f5f1a0e0e..e92879b853d7b 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs @@ -1,9 +1,9 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::expr_or_init; use clippy_utils::source::snippet; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize}; +use clippy_utils::{expr_or_init, sym}; use rustc_abi::IntegerType; use rustc_errors::{Applicability, Diag}; use rustc_hir::def::{DefKind, Res}; @@ -73,7 +73,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b nbits }, ExprKind::MethodCall(method, _value, [], _) => { - if method.ident.name.as_str() == "signum" { + if method.ident.name == sym::signum { 0 // do not lint if cast comes from a `signum` function } else { nbits diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs index 3fca0f8970770..01020f3eee21e 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -1,11 +1,10 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_c_void; -use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant}; +use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, sym}; use rustc_hir::{Expr, ExprKind, GenericArg}; use rustc_lint::LateContext; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty}; -use rustc_span::sym; use super::CAST_PTR_ALIGNMENT; @@ -20,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { ); lint_cast_ptr_alignment(cx, expr, cast_from, cast_to); } else if let ExprKind::MethodCall(method_path, self_arg, [], _) = &expr.kind - && method_path.ident.name.as_str() == "cast" + && method_path.ident.name == sym::cast && let Some(generic_args) = method_path.args && let [GenericArg::Type(cast_to)] = generic_args.args // There probably is no obvious reason to do this, just to be consistent with `as` cases. diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs index ae994e94a32b5..8e8c55cf38329 100644 --- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs @@ -8,7 +8,9 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind, Lit, Node, Path, QPath, TyKind, UnOp}; use rustc_lint::{LateContext, LintContext}; +use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, FloatTy, InferTy, Ty}; +use rustc_span::{Symbol, sym}; use std::ops::ControlFlow; use super::UNNECESSARY_CAST; @@ -142,6 +144,33 @@ pub(super) fn check<'tcx>( } if cast_from.kind() == cast_to.kind() && !expr.span.in_external_macro(cx.sess().source_map()) { + enum MaybeParenOrBlock { + Paren, + Block, + Nothing, + } + + fn is_borrow_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + matches!(expr.kind, ExprKind::AddrOf(..)) + || cx + .typeck_results() + .expr_adjustments(expr) + .first() + .is_some_and(|adj| matches!(adj.kind, Adjust::Borrow(_))) + } + + fn is_in_allowed_macro(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + const ALLOWED_MACROS: &[Symbol] = &[ + sym::format_args_macro, + sym::assert_eq_macro, + sym::debug_assert_eq_macro, + sym::assert_ne_macro, + sym::debug_assert_ne_macro, + ]; + matches!(expr.span.ctxt().outer_expn_data().macro_def_id, Some(def_id) if + cx.tcx.get_diagnostic_name(def_id).is_some_and(|sym| ALLOWED_MACROS.contains(&sym))) + } + if let Some(id) = path_to_local(cast_expr) && !cx.tcx.hir_span(id).eq_ctxt(cast_expr.span) { @@ -150,15 +179,15 @@ pub(super) fn check<'tcx>( return false; } - // If the whole cast expression is a unary expression (`(*x as T)`) or an addressof - // expression (`(&x as T)`), then not surrounding the suggestion into a block risks us - // changing the precedence of operators if the cast expression is followed by an operation - // with higher precedence than the unary operator (`(*x as T).foo()` would become - // `*x.foo()`, which changes what the `*` applies on). - // The same is true if the expression encompassing the cast expression is a unary - // expression or an addressof expression. - let needs_block = matches!(cast_expr.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..)) - || get_parent_expr(cx, expr).is_some_and(|e| matches!(e.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..))); + // Changing `&(x as i32)` to `&x` would change the meaning of the code because the previous creates + // a reference to the temporary while the latter creates a reference to the original value. + let surrounding = match cx.tcx.parent_hir_node(expr.hir_id) { + Node::Expr(parent) if is_borrow_expr(cx, parent) && !is_in_allowed_macro(cx, parent) => { + MaybeParenOrBlock::Block + }, + Node::Expr(parent) if cast_expr.precedence() < parent.precedence() => MaybeParenOrBlock::Paren, + _ => MaybeParenOrBlock::Nothing, + }; span_lint_and_sugg( cx, @@ -166,10 +195,10 @@ pub(super) fn check<'tcx>( expr.span, format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"), "try", - if needs_block { - format!("{{ {cast_str} }}") - } else { - cast_str + match surrounding { + MaybeParenOrBlock::Paren => format!("({cast_str})"), + MaybeParenOrBlock::Block => format!("{{ {cast_str} }}"), + MaybeParenOrBlock::Nothing => cast_str, }, Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs index c2aac7ca090bb..19f62e8bf79c6 100644 --- a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs +++ b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs @@ -5,8 +5,8 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::Span; use rustc_span::symbol::sym; +use rustc_span::{Span, kw}; declare_clippy_lint! { /// ### What it does @@ -105,12 +105,11 @@ fn contains_unhygienic_crate_reference(tts: &TokenStream) -> Option { fn is_crate_keyword(tt: &TokenTree) -> Option { if let TokenTree::Token( Token { - kind: TokenKind::Ident(symbol, _), + kind: TokenKind::Ident(kw::Crate, _), span, }, _, ) = tt - && symbol.as_str() == "crate" { Some(*span) } else { diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs index 3afb687040f45..72f5eaf8a4bcc 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -68,6 +68,38 @@ fn is_structural_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: T } } +/// Check if the pattern has any type mismatch that would prevent it from being used in an equality +/// check. This can happen if the expr has a reference type and the corresponding pattern is a +/// literal. +fn contains_type_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { + let mut result = false; + pat.walk(|p| { + if result { + return false; + } + + if p.span.in_external_macro(cx.sess().source_map()) { + return true; + } + + let adjust_pat = match p.kind { + PatKind::Or([p, ..]) => p, + _ => p, + }; + + if let Some(adjustments) = cx.typeck_results().pat_adjustments().get(adjust_pat.hir_id) + && adjustments.first().is_some_and(|first| first.source.is_ref()) + { + result = true; + return false; + } + + true + }); + + result +} + impl<'tcx> LateLintPass<'tcx> for PatternEquality { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let ExprKind::Let(let_expr) = expr.kind @@ -78,7 +110,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality { let pat_ty = cx.typeck_results().pat_ty(let_expr.pat); let mut applicability = Applicability::MachineApplicable; - if is_structural_partial_eq(cx, exp_ty, pat_ty) { + if is_structural_partial_eq(cx, exp_ty, pat_ty) && !contains_type_mismatch(cx, let_expr.pat) { let pat_str = match let_expr.pat.kind { PatKind::Struct(..) => format!( "({})", diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs index d5f0659f8427f..553a00ed868d5 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs @@ -3,7 +3,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::{ eq_expr_value, get_parent_expr, higher, is_in_const_context, is_inherent_method_call, is_no_std_crate, - numeric_literal, peel_blocks, sugg, + numeric_literal, peel_blocks, sugg, sym, }; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp}; @@ -435,7 +435,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { rhs, ) = expr.kind && let ExprKind::MethodCall(path, self_arg, [], _) = &lhs.kind - && path.ident.name.as_str() == "exp" + && path.ident.name == sym::exp && cx.typeck_results().expr_ty(lhs).is_floating_point() && let Some(value) = ConstEvalCtxt::new(cx).eval(rhs) && (F32(1.0) == value || F64(1.0) == value) diff --git a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs index c8828c9361576..5e2e2c9dbf725 100644 --- a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs @@ -1,12 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::path_def_id; use clippy_utils::ty::is_c_void; +use clippy_utils::{path_def_id, sym}; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -41,7 +40,7 @@ impl LateLintPass<'_> for FromRawWithVoidPtr { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Call(box_from_raw, [arg]) = expr.kind && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind - && seg.ident.name.as_str() == "from_raw" + && seg.ident.name == sym::from_raw && let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id)) && let arg_kind = cx.typeck_results().expr_ty(arg).kind() && let ty::RawPtr(ty, _) = arg_kind diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs index 25b087e8484f2..b816963cc825b 100644 --- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs +++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs @@ -1,13 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; -use clippy_utils::{is_in_const_context, is_integer_literal}; +use clippy_utils::{is_in_const_context, is_integer_literal, sym}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, PrimTy, QPath, TyKind, def}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does @@ -53,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { // check if the second part of the path indeed calls the associated // function `from_str_radix` - && pathseg.ident.name.as_str() == "from_str_radix" + && pathseg.ident.name == sym::from_str_radix // check if the first part of the path is some integer primitive && let TyKind::Path(ty_qpath) = &ty.kind diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs index d2545e57652a8..4c17834c3adf9 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs @@ -10,10 +10,10 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::{Ty, TypeckResults}; use rustc_session::declare_lint_pass; use rustc_span::Span; -use rustc_span::symbol::sym; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet}; +use clippy_utils::sym; use clippy_utils::ty::is_type_diagnostic_item; declare_clippy_lint! { @@ -326,6 +326,7 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> { fn visit_expr(&mut self, e: &'tcx Expr<'_>) { if let ExprKind::Call(fun, args) = e.kind && let ExprKind::Path(QPath::TypeRelative(ty, method)) = fun.kind + && matches!(method.ident.name, sym::new | sym::with_capacity) && let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind && let Some(ty_did) = ty_path.res.opt_def_id() { @@ -333,10 +334,11 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> { return; } - if self.cx.tcx.is_diagnostic_item(sym::HashMap, ty_did) { - if method.ident.name == sym::new { + match (self.cx.tcx.get_diagnostic_name(ty_did), method.ident.name) { + (Some(sym::HashMap), sym::new) => { self.suggestions.insert(e.span, "HashMap::default()".to_string()); - } else if method.ident.name.as_str() == "with_capacity" { + }, + (Some(sym::HashMap), sym::with_capacity) => { self.suggestions.insert( e.span, format!( @@ -344,11 +346,11 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> { snippet(self.cx, args[0].span, "capacity"), ), ); - } - } else if self.cx.tcx.is_diagnostic_item(sym::HashSet, ty_did) { - if method.ident.name == sym::new { + }, + (Some(sym::HashSet), sym::new) => { self.suggestions.insert(e.span, "HashSet::default()".to_string()); - } else if method.ident.name.as_str() == "with_capacity" { + }, + (Some(sym::HashSet), sym::with_capacity) => { self.suggestions.insert( e.span, format!( @@ -356,7 +358,8 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> { snippet(self.cx, args[0].span, "capacity"), ), ); - } + }, + _ => {}, } } diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs index 427a1f8255553..c4e10837bf192 100644 --- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs +++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::higher; use clippy_utils::ty::{get_type_diagnostic_name, implements_trait}; +use clippy_utils::{higher, sym}; use rustc_hir::{BorrowKind, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does @@ -156,7 +155,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { .and(cap); } } - if method.ident.name.as_str() == "flat_map" + if method.ident.name == sym::flat_map && args.len() == 1 && let ExprKind::Closure(&Closure { body, .. }) = args[0].kind { @@ -224,7 +223,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { return MaybeInfinite.and(is_infinite(cx, receiver)); } } - if method.ident.name.as_str() == "last" && args.is_empty() { + if method.ident.name == sym::last && args.is_empty() { let not_double_ended = cx .tcx .get_diagnostic_item(sym::DoubleEndedIterator) @@ -232,7 +231,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { if not_double_ended { return is_infinite(cx, receiver); } - } else if method.ident.name.as_str() == "collect" { + } else if method.ident.name == sym::collect { let ty = cx.typeck_results().expr_ty(expr); if matches!( get_type_diagnostic_name(cx, ty), diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs index 173232c511a57..900b20aa9cfb7 100644 --- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs +++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs @@ -1,14 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::get_parent_as_impl; use clippy_utils::source::snippet; use clippy_utils::ty::{deref_chain, get_adt_inherent_method, implements_trait, make_normalized_projection}; +use clippy_utils::{get_parent_as_impl, sym}; use rustc_ast::Mutability; use rustc_errors::Applicability; use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -141,7 +140,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter { ty.peel_refs().is_slice() || get_adt_inherent_method(cx, ty, expected_method_name).is_some() }) && let Some(iter_assoc_span) = imp.items.iter().find_map(|item| { - if item.ident.name.as_str() == "IntoIter" { + if item.ident.name == sym::IntoIter { Some(cx.tcx.hir_impl_item(item.id).expect_type().span) } else { None diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 8c71d34c95f6d..aded31971cec0 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -2,7 +2,9 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the use clippy_utils::source::{SpanRangeExt, snippet_with_context}; use clippy_utils::sugg::{Sugg, has_enclosing_paren}; use clippy_utils::ty::implements_trait; -use clippy_utils::{fulfill_or_allowed, get_item_name, get_parent_as_impl, is_trait_method, peel_ref_operators, sym}; +use clippy_utils::{ + fulfill_or_allowed, get_parent_as_impl, is_trait_method, parent_item_name, peel_ref_operators, sym, +}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -533,9 +535,7 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_> if let (&ExprKind::MethodCall(method_path, receiver, [], _), ExprKind::Lit(lit)) = (&method.kind, &lit.kind) { // check if we are in an is_empty() method - if let Some(name) = get_item_name(cx, method) - && name.as_str() == "is_empty" - { + if parent_item_name(cx, method) == Some(sym::is_empty) { return; } diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 5fa8f6f4bf3d4..bc7fc60827a0b 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -729,6 +729,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_early_pass(|| Box::new(misc_early::MiscEarlyLints)); store.register_late_pass(|_| Box::new(redundant_closure_call::RedundantClosureCall)); store.register_early_pass(|| Box::new(unused_unit::UnusedUnit)); + store.register_late_pass(|_| Box::new(unused_unit::UnusedUnit)); store.register_late_pass(|_| Box::new(returns::Return)); store.register_late_pass(move |tcx| Box::new(collapsible_if::CollapsibleIf::new(tcx, conf))); store.register_late_pass(|_| Box::new(items_after_statements::ItemsAfterStatements)); diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs index 661b4b590d8fb..388034c39f522 100644 --- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs +++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::Msrv; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use clippy_utils::{msrvs, path_to_local, std_or_core}; +use clippy_utils::{msrvs, path_to_local, std_or_core, sym}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -11,7 +11,6 @@ use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_span::SyntaxContext; -use rustc_span::symbol::sym; /// Detects for loop pushing the same item into a Vec pub(super) fn check<'tcx>( @@ -187,8 +186,8 @@ fn get_vec_push<'tcx>( // Extract method being called and figure out the parameters for the method call && let ExprKind::MethodCall(path, self_expr, [pushed_item], _) = &semi_stmt.kind // Check that the method being called is push() on a Vec + && path.ident.name == sym::push && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec) - && path.ident.name.as_str() == "push" { return Some((self_expr, pushed_item, semi_stmt.span.ctxt())); } diff --git a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs index 444ecd5d2bb95..ed0cce754b954 100644 --- a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs +++ b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::{Sugg, has_enclosing_paren}; use clippy_utils::{SpanlessEq, sym}; use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp}; @@ -199,9 +199,9 @@ fn build_suggestion( } else { format!("{dividend_sugg_str}{type_suffix}") }; - let divisor_snippet = snippet_with_applicability(cx, rhs.span.source_callsite(), "..", applicability); + let divisor_snippet = snippet_with_context(cx, rhs.span, expr.span.ctxt(), "..", applicability); - let sugg = format!("{suggestion_before_div_ceil}.div_ceil({divisor_snippet})"); + let sugg = format!("{suggestion_before_div_ceil}.div_ceil({})", divisor_snippet.0); span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs index f71264a93ca84..b3ee45cc02098 100644 --- a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs +++ b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs @@ -3,12 +3,11 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanRangeExt; use clippy_utils::visitors::{is_local_used, local_used_once}; -use clippy_utils::{is_trait_method, path_to_local_id}; +use clippy_utils::{is_trait_method, path_to_local_id, sym}; use rustc_errors::Applicability; use rustc_hir::{BindingMode, ExprKind, LetStmt, Node, PatKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -66,7 +65,7 @@ impl LateLintPass<'_> for ManualHashOne { && let Some(init) = local.init && !init.span.from_expansion() && let ExprKind::MethodCall(seg, build_hasher, [], _) = init.kind - && seg.ident.name.as_str() == "build_hasher" + && seg.ident.name == sym::build_hasher && let Node::Stmt(local_stmt) = cx.tcx.parent_hir_node(local.hir_id) && let Node::Block(block) = cx.tcx.parent_hir_node(local_stmt.hir_id) @@ -94,7 +93,7 @@ impl LateLintPass<'_> for ManualHashOne { && let Node::Expr(finish_expr) = cx.tcx.parent_hir_node(path_expr.hir_id) && !finish_expr.span.from_expansion() && let ExprKind::MethodCall(seg, _, [], _) = finish_expr.kind - && seg.ident.name.as_str() == "finish" + && seg.ident.name == sym::finish && self.msrv.meets(cx, msrvs::BUILD_HASHER_HASH_ONE) { diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs index 8ab49bd2ea8ea..ac8c88f02057b 100644 --- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs +++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; -use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators}; +use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators, sym}; use rustc_ast::LitKind::{Byte, Char}; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; @@ -11,7 +11,7 @@ use rustc_hir::{Expr, ExprKind, Lit, Node, Param, PatExpr, PatExprKind, PatKind, use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { check_is_ascii(cx, macro_call.span, recv, &range, None); } } else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind - && path.ident.name.as_str() == "contains" + && path.ident.name == sym::contains && let Some(higher::Range { start: Some(start), end: Some(end), diff --git a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs index e4ad3953b671d..b365dbf088f58 100644 --- a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs +++ b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs @@ -1,14 +1,14 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::msrvs::Msrv; -use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs}; +use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs, sym}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Arm, Expr, ExprKind, LangItem, Pat, PatKind, QPath, is_range_literal}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -76,7 +76,7 @@ impl LateLintPass<'_> for ManualOptionAsSlice { } }, ExprKind::MethodCall(seg, callee, [], _) => { - if seg.ident.name.as_str() == "unwrap_or_default" { + if seg.ident.name == sym::unwrap_or_default { check_map(cx, callee, span, self.msrv); } }, diff --git a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs index e666f31217cc8..6d841853fbe5f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs +++ b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::{has_non_owning_mutable_access, implements_trait}; -use clippy_utils::{is_mutable, is_trait_method, path_to_local}; +use clippy_utils::{is_mutable, is_trait_method, path_to_local, sym}; use rustc_errors::Applicability; use rustc_hir::{Expr, Node, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty::Instance; -use rustc_span::{Span, sym}; +use rustc_span::Span; use super::DOUBLE_ENDED_ITERATOR_LAST; @@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Exp && let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args) // find the provided definition of Iterator::last && let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator) - && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name().as_str() == "last") + && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name() == sym::last) // if the resolved method is the same as the provided definition && fn_def.def_id() == last_def.def_id && let self_ty = cx.typeck_results().expr_ty(self_expr) diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs index da123f13d46fa..4dd54cf197450 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs @@ -233,12 +233,12 @@ impl<'tcx> OffendingFilterExpr<'tcx> { // the latter only calls `effect` once let side_effect_expr_span = receiver.can_have_side_effects().then_some(receiver.span); - if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name.as_str() == "is_some" { + if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name == sym::is_some { Some(Self::IsSome { receiver, side_effect_expr_span, }) - } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name.as_str() == "is_ok" { + } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name == sym::is_ok { Some(Self::IsOk { receiver, side_effect_expr_span, diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index ad374dee516cd..10f4637d08f66 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -4370,11 +4370,10 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// - /// Detect functions that end with `Option::and_then` or `Result::and_then`, and suggest using a question mark (`?`) instead. + /// Detect functions that end with `Option::and_then` or `Result::and_then`, and suggest using + /// the `?` operator instead. /// /// ### Why is this bad? - /// /// The `and_then` method is used to chain a computation that returns an `Option` or a `Result`. /// This can be replaced with the `?` operator, which is more concise and idiomatic. /// diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs index 743aacf058856..f528f7f065c6e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs @@ -9,7 +9,7 @@ use super::utils::get_last_chain_binding_hir_id; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths::CHAR_IS_ASCII; use clippy_utils::source::SpanRangeExt; -use clippy_utils::{match_def_path, path_to_local_id, peel_blocks}; +use clippy_utils::{match_def_path, path_to_local_id, peel_blocks, sym}; fn peels_expr_ref<'a, 'tcx>(mut expr: &'a Expr<'tcx>) -> &'a Expr<'tcx> { while let ExprKind::AddrOf(_, _, e) = expr.kind { @@ -32,7 +32,7 @@ fn handle_expr( // If we have `!is_ascii`, then only `.any()` should warn. And if the condition is // `is_ascii`, then only `.all()` should warn. if revert != is_all - && method.ident.name.as_str() == "is_ascii" + && method.ident.name == sym::is_ascii && path_to_local_id(receiver, first_param) && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() && *char_arg_ty.kind() == ty::Char @@ -102,7 +102,7 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, && let body = cx.tcx.hir_body(body) && let Some(first_param) = body.params.first() && let ExprKind::MethodCall(method, mut recv, [], _) = recv.kind - && method.ident.name.as_str() == "chars" + && method.ident.name == sym::chars && let str_ty = cx.typeck_results().expr_ty_adjusted(recv).peel_refs() && *str_ty.kind() == ty::Str { diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index 6efaba525e3ed..cd22583b8a253 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -9,7 +9,7 @@ use clippy_utils::ty::{ }; use clippy_utils::{ CaptureKind, can_move_expr_to_closure, fn_def_id, get_enclosing_block, higher, is_trait_method, path_to_local, - path_to_local_id, + path_to_local_id, sym, }; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, MultiSpan}; @@ -20,8 +20,8 @@ use rustc_hir::{ use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, AssocTag, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; +use rustc_span::Span; use rustc_span::symbol::Ident; -use rustc_span::{Span, sym}; const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed"; @@ -339,7 +339,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { // Check function calls on our collection if let ExprKind::MethodCall(method_name, recv, args, _) = &expr.kind { if args.is_empty() - && method_name.ident.name.as_str() == "collect" + && method_name.ident.name == sym::collect && is_trait_method(self.cx, expr, sym::Iterator) { self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv)); diff --git a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs index fe999a3b5f8f2..407f2e80aff25 100644 --- a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs +++ b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs @@ -1,17 +1,16 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::get_parent_expr; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_local_use_after_expr; +use clippy_utils::{get_parent_expr, sym}; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_span::sym; use super::READ_LINE_WITHOUT_TRIM; @@ -44,7 +43,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr< if let Some(parent) = get_parent_expr(cx, expr) { let data = if let ExprKind::MethodCall(segment, recv, args, span) = parent.kind { if args.is_empty() - && segment.ident.name.as_str() == "parse" + && segment.ident.name == sym::parse && let parse_result_ty = cx.typeck_results().expr_ty(parent) && is_type_diagnostic_item(cx, parse_result_ty, sym::Result) && let ty::Adt(_, substs) = parse_result_ty.kind() @@ -58,7 +57,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr< "calling `.parse()` on a string without trimming the trailing newline character", "checking", )) - } else if segment.ident.name.as_str() == "ends_with" + } else if segment.ident.name == sym::ends_with && recv.span == expr.span && let [arg] = args && expr_is_string_literal_without_trailing_newline(arg) diff --git a/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs b/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs index e8861935d4216..91643b0dfefde 100644 --- a/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs +++ b/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs @@ -55,7 +55,6 @@ pub(super) fn check<'tcx>( None => &body_snip, }; - let msg = "use the question mark operator instead of an `and_then` call"; let sugg = format!( "let {} = {}?;\n{}", arg_snip, @@ -63,5 +62,13 @@ pub(super) fn check<'tcx>( reindent_multiline(inner, false, indent_of(cx, expr.span)) ); - span_lint_and_sugg(cx, RETURN_AND_THEN, expr.span, msg, "try", sugg, applicability); + span_lint_and_sugg( + cx, + RETURN_AND_THEN, + expr.span, + "use the `?` operator instead of an `and_then` call", + "try", + sugg, + applicability, + ); } diff --git a/src/tools/clippy/clippy_lints/src/methods/str_split.rs b/src/tools/clippy/clippy_lints/src/methods/str_split.rs index 3586e11f56ab2..fb4ac7b3613dd 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_split.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_split.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; +use clippy_utils::sym; use clippy_utils::visitors::is_const_evaluatable; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -19,7 +20,7 @@ pub(super) fn check<'a>(cx: &LateContext<'a>, expr: &'_ Expr<'_>, split_recv: &' && !is_const_evaluatable(cx, trim_recv) && let ExprKind::Lit(split_lit) = split_arg.kind && (matches!(split_lit.node, LitKind::Char('\n')) - || matches!(split_lit.node, LitKind::Str(sym, _) if (sym.as_str() == "\n" || sym.as_str() == "\r\n"))) + || matches!(split_lit.node, LitKind::Str(sym::LF | sym::CRLF, _))) { let mut app = Applicability::MaybeIncorrect; span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs index f920f306bc1ed..79ed352193fd7 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -3,13 +3,12 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_copy; use clippy_utils::usage::mutated_variables; use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; -use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id}; +use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id, sym}; use core::ops::ControlFlow; use rustc_hir as hir; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::sym; use super::{UNNECESSARY_FILTER_MAP, UNNECESSARY_FIND_MAP}; @@ -95,7 +94,7 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc (true, true) }, hir::ExprKind::MethodCall(segment, recv, [arg], _) => { - if segment.ident.name.as_str() == "then_some" + if segment.ident.name == sym::then_some && cx.typeck_results().expr_ty(recv).is_bool() && path_to_local_id(arg, arg_id) { diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 206b0a8ae3cd6..87bb8d46a1d6a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -7,7 +7,7 @@ use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_ use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{ fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, is_expr_temporary_value, peel_middle_ty_refs, - return_ty, + return_ty, sym, }; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -20,7 +20,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::{ self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty, }; -use rustc_span::{Symbol, sym}; +use rustc_span::Symbol; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{Obligation, ObligationCause}; @@ -312,8 +312,7 @@ fn check_string_from_utf8<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, /// call of a `to_owned`-like function is unnecessary. fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool { if let Some(parent) = get_parent_expr(cx, expr) - && let Some((fn_name, argument_expr)) = get_fn_name_and_arg(cx, parent) - && fn_name.as_str() == "split" + && let Some((sym::split, argument_expr)) = get_fn_name_and_arg(cx, parent) && let Some(receiver_snippet) = receiver.span.get_source_text(cx) && let Some(arg_snippet) = argument_expr.span.get_source_text(cx) { @@ -614,8 +613,7 @@ fn has_lifetime(ty: Ty<'_>) -> bool { /// Returns true if the named method is `Iterator::cloned` or `Iterator::copied`. fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool { - (method_name.as_str() == "cloned" || method_name.as_str() == "copied") - && is_diag_trait_item(cx, method_def_id, sym::Iterator) + matches!(method_name, sym::cloned | sym::copied) && is_diag_trait_item(cx, method_def_id, sym::Iterator) } /// Returns true if the named method can be used to convert the receiver to its "owned" @@ -628,7 +626,7 @@ fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: /// Returns true if the named method is `Cow::into_owned`. fn is_cow_into_owned(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool { - method_name.as_str() == "into_owned" && is_diag_item_method(cx, method_def_id, sym::Cow) + method_name == sym::into_owned && is_diag_item_method(cx, method_def_id, sym::Cow) } /// Returns true if the named method is `ToString::to_string` and it's called on a type that diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs index ed89b3b34386f..64eafc0ebccdc 100644 --- a/src/tools/clippy/clippy_lints/src/minmax.rs +++ b/src/tools/clippy/clippy_lints/src/minmax.rs @@ -1,10 +1,9 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_trait_method; +use clippy_utils::{is_trait_method, sym}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; use std::cmp::Ordering::{Equal, Greater, Less}; declare_clippy_lint! { @@ -79,12 +78,10 @@ fn min_max<'a, 'tcx>(cx: &LateContext<'tcx>, expr: &'a Expr<'a>) -> Option<(MinM }, ExprKind::MethodCall(path, receiver, args @ [_], _) => { if cx.typeck_results().expr_ty(receiver).is_floating_point() || is_trait_method(cx, expr, sym::Ord) { - if path.ident.name.as_str() == "max" { - fetch_const(cx, Some(receiver), args, MinMax::Max) - } else if path.ident.name.as_str() == "min" { - fetch_const(cx, Some(receiver), args, MinMax::Min) - } else { - None + match path.ident.name { + sym::max => fetch_const(cx, Some(receiver), args, MinMax::Max), + sym::min => fetch_const(cx, Some(receiver), args, MinMax::Min), + _ => None, } } else { None diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs index 1932d2d5f9785..be7dd74fd62b9 100644 --- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs +++ b/src/tools/clippy/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::is_path_lang_item; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::{Visitable, for_each_expr}; +use clippy_utils::{is_path_lang_item, sym}; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; @@ -13,7 +13,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{Ty, TypeckResults}; use rustc_session::declare_lint_pass; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -116,7 +116,7 @@ fn should_lint<'tcx>( 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.as_str() == "finish_non_exhaustive" + } else if path.ident.name == sym::finish_non_exhaustive && is_type_diagnostic_item(cx, recv_ty, sym::DebugStruct) { has_finish_non_exhaustive = true; diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs index 0e08558596283..d9f4fb271fb4b 100644 --- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::macros::root_macro_call_first_node; -use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id}; +use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id, sym}; use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, LetStmt, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -136,7 +136,7 @@ impl<'tcx> DivergenceVisitor<'_, 'tcx> { fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) { if let Some(macro_call) = root_macro_call_first_node(self.cx, e) - && self.cx.tcx.item_name(macro_call.def_id).as_str() == "todo" + && self.cx.tcx.is_diagnostic_item(sym::todo_macro, macro_call.def_id) { return; } diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs index 90b27f5dbac82..7dd96f1f037fd 100644 --- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs @@ -3,12 +3,12 @@ use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Block, BlockCheckMode, Closure, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::Span; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::is_trait_method; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::has_iter_method; +use clippy_utils::{is_trait_method, sym}; declare_clippy_lint! { /// ### What it does @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { iter_recv.kind, ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::Path(..) ) - && method_name.ident.name.as_str() == "for_each" + && method_name.ident.name == sym::for_each && is_trait_method(cx, expr, sym::Iterator) // Checks the type of the `iter` method receiver is NOT a user defined type. && has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some() diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index 72b0a80260e9f..2a2160c3be2d1 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -1,6 +1,5 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::path_res; -use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Block, Body, Expr, ExprKind, LangItem, MatchSource, QPath}; @@ -9,52 +8,38 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does - /// Suggests alternatives for useless applications of `?` in terminating expressions + /// Suggests replacing `Ok(x?)` or `Some(x?)` with `x` in return positions where the `?` operator + /// is not needed to convert the type of `x`. /// /// ### Why is this bad? /// There's no reason to use `?` to short-circuit when execution of the body will end there anyway. /// /// ### Example /// ```no_run - /// struct TO { - /// magic: Option, + /// # use std::num::ParseIntError; + /// fn f(s: &str) -> Option { + /// Some(s.find('x')?) /// } /// - /// fn f(to: TO) -> Option { - /// Some(to.magic?) + /// fn g(s: &str) -> Result { + /// Ok(s.parse()?) /// } - /// - /// struct TR { - /// magic: Result, - /// } - /// - /// fn g(tr: Result) -> Result { - /// tr.and_then(|t| Ok(t.magic?)) - /// } - /// /// ``` /// Use instead: /// ```no_run - /// struct TO { - /// magic: Option, + /// # use std::num::ParseIntError; + /// fn f(s: &str) -> Option { + /// s.find('x') /// } /// - /// fn f(to: TO) -> Option { - /// to.magic - /// } - /// - /// struct TR { - /// magic: Result, - /// } - /// - /// fn g(tr: Result) -> Result { - /// tr.and_then(|t| t.magic) + /// fn g(s: &str) -> Result { + /// s.parse() /// } /// ``` #[clippy::version = "1.51.0"] pub NEEDLESS_QUESTION_MARK, complexity, - "Suggest `value.inner_option` instead of `Some(value.inner_option?)`. The same goes for `Result`." + "using `Ok(x?)` or `Some(x?)` where `x` would be equivalent" } declare_lint_pass!(NeedlessQuestionMark => [NEEDLESS_QUESTION_MARK]); @@ -111,10 +96,10 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Call(path, [arg]) = expr.kind && let Res::Def(DefKind::Ctor(..), ctor_id) = path_res(cx, path) && let Some(variant_id) = cx.tcx.opt_parent(ctor_id) - && let sugg_remove = if cx.tcx.lang_items().option_some_variant() == Some(variant_id) { - "Some()" + && let variant = if cx.tcx.lang_items().option_some_variant() == Some(variant_id) { + "Some" } else if cx.tcx.lang_items().result_ok_variant() == Some(variant_id) { - "Ok()" + "Ok" } else { return; } @@ -126,14 +111,25 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { && let inner_ty = cx.typeck_results().expr_ty(inner_expr) && expr_ty == inner_ty { - span_lint_and_sugg( + span_lint_hir_and_then( cx, NEEDLESS_QUESTION_MARK, + expr.hir_id, expr.span, - "question mark operator is useless here", - format!("try removing question mark and `{sugg_remove}`"), - format!("{}", snippet(cx, inner_expr.span, r#""...""#)), - Applicability::MachineApplicable, + format!("enclosing `{variant}` and `?` operator are unneeded"), + |diag| { + diag.multipart_suggestion( + format!("remove the enclosing `{variant}` and `?` operator"), + vec![ + (expr.span.until(inner_expr.span), String::new()), + ( + inner_expr.span.shrink_to_hi().to(expr.span.shrink_to_hi()), + String::new(), + ), + ], + Applicability::MachineApplicable, + ); + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs index 852c3885f5689..23a1622f30fff 100644 --- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs +++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{SpanRangeExt, snippet_with_applicability}; +use clippy_utils::sym; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -43,12 +43,12 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { match &expr.kind { ExprKind::MethodCall(path, func, [param], _) => { if let Some(adt) = cx.typeck_results().expr_ty(func).peel_refs().ty_adt_def() - && ((path.ident.name.as_str() == "mode" + && ((path.ident.name == sym::mode && matches!( cx.tcx.get_diagnostic_name(adt.did()), Some(sym::FsOpenOptions | sym::DirBuilder) )) - || (path.ident.name.as_str() == "set_mode" + || (path.ident.name == sym::set_mode && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did()))) && let ExprKind::Lit(_) = param.kind && param.span.eq_ctxt(expr.span) diff --git a/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs b/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs index 635f5678e2a65..1b8ab1bdedf8a 100644 --- a/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs +++ b/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; +use clippy_utils::sym; use rustc_ast::ast::BinOpKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does @@ -72,7 +72,7 @@ fn check_non_zero_conversion(cx: &LateContext<'_>, expr: &Expr<'_>, applicabilit && let ExprKind::Path(qpath) = &func.kind && let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() && let ExprKind::MethodCall(rcv_path, receiver, [], _) = &arg.kind - && rcv_path.ident.name.as_str() == "get" + && rcv_path.ident.name == sym::get { let fn_name = cx.tcx.item_name(def_id); let target_ty = cx.typeck_results().expr_ty(expr); diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs index 01dc6a27c33e3..ded161c8576a1 100644 --- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs +++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs @@ -1,7 +1,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::get_item_name; use clippy_utils::sugg::Sugg; +use clippy_utils::{parent_item_name, sym}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::LateContext; @@ -34,7 +34,7 @@ pub(crate) fn check<'tcx>( return; } - if let Some(name) = get_item_name(cx, expr) { + if let Some(name) = parent_item_name(cx, expr) { let name = name.as_str(); if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_") || name.ends_with("_eq") { return; @@ -106,7 +106,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } if let ExprKind::MethodCall(method_name, self_arg, [], _) = expr.kind - && method_name.ident.name.as_str() == "signum" + && method_name.ident.name == sym::signum // Check that the receiver of the signum() is a float (expressions[0] is the receiver of // the method call) { diff --git a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs index dc142b6e15771..da56a785007c4 100644 --- a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs +++ b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sym; 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; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -33,7 +33,7 @@ impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse { if let ExprKind::MethodCall(path, receiver, [arg], _) = &expr.kind && let ExprKind::Lit(lit) = &arg.kind && LitKind::Bool(false) == lit.node - && path.ident.name.as_str() == "set_readonly" + && path.ident.name == sym::set_readonly && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::FsPermissions) { span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 491961408adb8..9149406642d67 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -743,9 +743,9 @@ fn check_ptr_eq<'tcx>( } // Remove one level of usize conversion if any - let (left, right) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) { - (Some(lhs), Some(rhs)) => (lhs, rhs), - _ => (left, right), + let (left, right, usize_peeled) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) { + (Some(lhs), Some(rhs)) => (lhs, rhs, true), + _ => (left, right, false), }; // This lint concerns raw pointers @@ -754,7 +754,12 @@ fn check_ptr_eq<'tcx>( return; } - let (left_var, right_var) = (peel_raw_casts(cx, left, left_ty), peel_raw_casts(cx, right, right_ty)); + let ((left_var, left_casts_peeled), (right_var, right_casts_peeled)) = + (peel_raw_casts(cx, left, left_ty), peel_raw_casts(cx, right, right_ty)); + + if !(usize_peeled || left_casts_peeled || right_casts_peeled) { + return; + } let mut app = Applicability::MachineApplicable; let left_snip = Sugg::hir_with_context(cx, left_var, expr.span.ctxt(), "_", &mut app); @@ -787,8 +792,9 @@ fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_> } } -// Peel raw casts if the remaining expression can be coerced to it -fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: Ty<'tcx>) -> &'tcx Expr<'tcx> { +// Peel raw casts if the remaining expression can be coerced to it, and whether casts have been +// peeled or not. +fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: Ty<'tcx>) -> (&'tcx Expr<'tcx>, bool) { if !expr.span.from_expansion() && let ExprKind::Cast(inner, _) = expr.kind && let ty::RawPtr(target_ty, _) = expr_ty.kind() @@ -796,8 +802,8 @@ fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: && let ty::RawPtr(inner_target_ty, _) | ty::Ref(_, inner_target_ty, _) = inner_ty.kind() && target_ty == inner_target_ty { - peel_raw_casts(cx, inner, inner_ty) + (peel_raw_casts(cx, inner, inner_ty).0, true) } else { - expr + (expr, false) } } diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs index 7f74a2fff9f20..d8d813f9846d5 100644 --- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs +++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::SpanRangeExt; +use clippy_utils::sym; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; use std::fmt; declare_clippy_lint! { @@ -97,7 +97,7 @@ fn expr_as_ptr_offset_call<'tcx>( if path_segment.ident.name == sym::offset { return Some((arg_0, arg_1, Method::Offset)); } - if path_segment.ident.name.as_str() == "wrapping_offset" { + if path_segment.ident.name == sym::wrapping_offset { return Some((arg_0, arg_1, Method::WrappingOffset)); } } diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index d318897443da5..c02e5e0621c9f 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -10,7 +10,7 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{ eq_expr_value, higher, is_else_clause, is_in_const_context, is_lint_allowed, is_path_lang_item, is_res_lang_ctor, pat_and_expr_can_be_question_mark, path_res, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt, - span_contains_cfg, span_contains_comment, + span_contains_cfg, span_contains_comment, sym, }; use rustc_errors::Applicability; use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk}; @@ -22,15 +22,14 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::sym; use rustc_span::symbol::Symbol; declare_clippy_lint! { /// ### What it does - /// Checks for expressions that could be replaced by the question mark operator. + /// Checks for expressions that could be replaced by the `?` operator. /// /// ### Why is this bad? - /// Question mark usage is more idiomatic. + /// Using the `?` operator is shorter and more idiomatic. /// /// ### Example /// ```ignore @@ -47,7 +46,7 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub QUESTION_MARK, style, - "checks for expressions that could be replaced by the question mark operator" + "checks for expressions that could be replaced by the `?` operator" } pub struct QuestionMark { @@ -207,8 +206,8 @@ fn is_early_return(smbl: Symbol, cx: &LateContext<'_>, if_block: &IfBlockType<'_ is_type_diagnostic_item(cx, caller_ty, smbl) && expr_return_none_or_err(smbl, cx, if_then, caller, None) && match smbl { - sym::Option => call_sym.as_str() == "is_none", - sym::Result => call_sym.as_str() == "is_err", + sym::Option => call_sym == sym::is_none, + sym::Result => call_sym == sym::is_err, _ => false, } }, @@ -280,7 +279,7 @@ fn expr_return_none_or_err( /// } /// ``` /// -/// If it matches, it will suggest to use the question mark operator instead +/// If it matches, it will suggest to use the `?` operator instead fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr) && !is_else_clause(cx.tcx, expr) diff --git a/src/tools/clippy/clippy_lints/src/question_mark_used.rs b/src/tools/clippy/clippy_lints/src/question_mark_used.rs index 0a974bf9d2f71..96ea485d76936 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark_used.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark_used.rs @@ -7,10 +7,10 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does - /// Checks for expressions that use the question mark operator and rejects them. + /// Checks for expressions that use the `?` operator and rejects them. /// /// ### Why restrict this? - /// Sometimes code wants to avoid the question mark operator because for instance a local + /// Sometimes code wants to avoid the `?` operator because for instance a local /// block requires a macro to re-throw errors to attach additional information to the /// error. /// @@ -27,7 +27,7 @@ declare_clippy_lint! { #[clippy::version = "1.69.0"] pub QUESTION_MARK_USED, restriction, - "complains if the question mark operator is used" + "checks if the `?` operator is used" } declare_lint_pass!(QuestionMarkUsed => [QUESTION_MARK_USED]); @@ -40,15 +40,9 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMarkUsed { } #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] - span_lint_and_then( - cx, - QUESTION_MARK_USED, - expr.span, - "question mark operator was used", - |diag| { - diag.help("consider using a custom macro or match expression"); - }, - ); + span_lint_and_then(cx, QUESTION_MARK_USED, expr.span, "the `?` operator was used", |diag| { + diag.help("consider using a custom macro or match expression"); + }); } } } diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs index d26288adb3919..30a5fe4db27e1 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -3,14 +3,13 @@ use clippy_utils::macros::matching_root_macro_call; use clippy_utils::sugg::Sugg; use clippy_utils::{ SpanlessEq, get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id, - span_contains_comment, + span_contains_comment, sym, }; use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt}; use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does @@ -248,7 +247,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> { if self.initialization_found && let ExprKind::MethodCall(path, self_arg, [extend_arg], _) = expr.kind && path_to_local_id(self_arg, self.vec_alloc.local_id) - && path.ident.name.as_str() == "extend" + && path.ident.name == sym::extend && self.is_repeat_take(extend_arg) { self.slow_expression = Some(InitializationType::Extend(expr)); @@ -260,7 +259,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> { if self.initialization_found && let ExprKind::MethodCall(path, self_arg, [len_arg, fill_arg], _) = expr.kind && path_to_local_id(self_arg, self.vec_alloc.local_id) - && path.ident.name.as_str() == "resize" + && path.ident.name == sym::resize // Check that is filled with 0 && is_integer_literal(fill_arg, 0) { @@ -282,7 +281,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> { /// Returns `true` if give expression is `repeat(0).take(...)` fn is_repeat_take(&mut self, expr: &'tcx Expr<'tcx>) -> bool { if let ExprKind::MethodCall(take_path, recv, [len_arg], _) = expr.kind - && take_path.ident.name.as_str() == "take" + && take_path.ident.name == sym::take // Check that take is applied to `repeat(0)` && self.is_repeat_zero(recv) { diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 43a3e69610513..af4d0d541f176 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -286,7 +286,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { if !e.span.in_external_macro(cx.sess().source_map()) && let ExprKind::MethodCall(path, receiver, ..) = &e.kind - && path.ident.name.as_str() == "as_bytes" + && path.ident.name == sym::as_bytes && let ExprKind::Lit(lit) = &receiver.kind && let LitKind::Str(lit_content, _) = &lit.node { @@ -332,7 +332,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { } if let ExprKind::MethodCall(path, recv, [], _) = &e.kind - && path.ident.name.as_str() == "into_bytes" + && path.ident.name == sym::into_bytes && let ExprKind::MethodCall(path, recv, [], _) = &recv.kind && matches!(path.ident.name.as_str(), "to_owned" | "to_string") && let ExprKind::Lit(lit) = &recv.kind @@ -556,7 +556,7 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { let tyckres = cx.typeck_results(); if let ExprKind::MethodCall(path, split_recv, [], split_ws_span) = expr.kind - && path.ident.name.as_str() == "split_whitespace" + && path.ident.name == sym::split_whitespace && let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id) && cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id) && let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind diff --git a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs index 9993e6ae18b9d..bb969bc802fe5 100644 --- a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::match_def_path; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{match_def_path, sym}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; @@ -38,11 +38,11 @@ declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]); impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if let hir::ExprKind::MethodCall(is_some_path, to_digit_expr, [], _) = &expr.kind - && is_some_path.ident.name.as_str() == "is_some" + && is_some_path.ident.name == sym::is_some { let match_result = match &to_digit_expr.kind { hir::ExprKind::MethodCall(to_digits_path, char_arg, [radix_arg], _) => { - if to_digits_path.ident.name.as_str() == "to_digit" + if to_digits_path.ident.name == sym::to_digit && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg) && *char_arg_ty.kind() == ty::Char { diff --git a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs index 81c0a57083e80..1ccab62708b18 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_normalizable; -use clippy_utils::{eq_expr_value, path_to_local}; +use clippy_utils::{eq_expr_value, path_to_local, sym}; use rustc_abi::WrappingRange; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Node}; @@ -43,7 +43,7 @@ fn binops_with_local(cx: &LateContext<'_>, local_expr: &Expr<'_>, expr: &Expr<'_ binops_with_local(cx, local_expr, lhs) || binops_with_local(cx, local_expr, rhs) }, ExprKind::MethodCall(path, receiver, [arg], _) - if path.ident.name.as_str() == "contains" + if path.ident.name == sym::contains // ... `contains` called on some kind of range && let Some(receiver_adt) = cx.typeck_results().expr_ty(receiver).peel_refs().ty_adt_def() && let lang_items = cx.tcx.lang_items() @@ -81,7 +81,7 @@ pub(super) fn check<'tcx>( if let Some(then_some_call) = peel_parent_unsafe_blocks(cx, expr) && let ExprKind::MethodCall(path, receiver, [arg], _) = then_some_call.kind && cx.typeck_results().expr_ty(receiver).is_bool() - && path.ident.name.as_str() == "then_some" + && path.ident.name == sym::then_some && is_local_with_projections(transmutable) && binops_with_local(cx, transmutable, receiver) && is_normalizable(cx, cx.param_env, from_ty) diff --git a/src/tools/clippy/clippy_lints/src/types/vec_box.rs b/src/tools/clippy/clippy_lints/src/types/vec_box.rs index 769244c675e1b..f13042a6fa6bf 100644 --- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs +++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs @@ -19,61 +19,58 @@ pub(super) fn check<'tcx>( def_id: DefId, box_size_threshold: u64, ) -> bool { - if cx.tcx.is_diagnostic_item(sym::Vec, def_id) { - if let Some(last) = last_path_segment(qpath).args - // Get the _ part of Vec<_> - && let Some(GenericArg::Type(ty)) = last.args.first() - // extract allocator from the Vec for later - && let vec_alloc_ty = last.args.get(1) - // ty is now _ at this point - && let TyKind::Path(ref ty_qpath) = ty.kind - && let res = cx.qpath_res(ty_qpath, ty.hir_id) - && let Some(def_id) = res.opt_def_id() - && Some(def_id) == cx.tcx.lang_items().owned_box() - // At this point, we know ty is Box, now get T - && let Some(last) = last_path_segment(ty_qpath).args - && let Some(GenericArg::Type(boxed_ty)) = last.args.first() - // extract allocator from the Box for later - && let boxed_alloc_ty = last.args.get(1) - // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay - && let ty_ty = lower_ty(cx.tcx, boxed_ty.as_unambig_ty()) - && !ty_ty.has_escaping_bound_vars() - && ty_ty.is_sized(cx.tcx, cx.typing_env()) - && let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes()) - && ty_ty_size < box_size_threshold - // https://github.com/rust-lang/rust-clippy/issues/7114 - && match (vec_alloc_ty, boxed_alloc_ty) { - (None, None) => true, - // this is in the event that we have something like - // Vec<_, Global>, in which case is equivalent to - // Vec<_> - (None, Some(GenericArg::Type(inner))) | (Some(GenericArg::Type(inner)), None) => { - if let TyKind::Path(path) = inner.kind - && let Some(did) = cx.qpath_res(&path, inner.hir_id).opt_def_id() { - cx.tcx.lang_items().get(LangItem::GlobalAlloc) == Some(did) - } else { - false - } - }, - (Some(GenericArg::Type(l)), Some(GenericArg::Type(r))) => - // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay - lower_ty(cx.tcx, l.as_unambig_ty()) == lower_ty(cx.tcx, r.as_unambig_ty()), - _ => false - } - { - span_lint_and_sugg( - cx, - VEC_BOX, - hir_ty.span, - "`Vec` is already on the heap, the boxing is unnecessary", - "try", - format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")), - Applicability::Unspecified, - ); - true - } else { - false + if cx.tcx.is_diagnostic_item(sym::Vec, def_id) + && let Some(last) = last_path_segment(qpath).args + // Get the _ part of Vec<_> + && let Some(GenericArg::Type(ty)) = last.args.first() + // extract allocator from the Vec for later + && let vec_alloc_ty = last.args.get(1) + // ty is now _ at this point + && let TyKind::Path(ref ty_qpath) = ty.kind + && let res = cx.qpath_res(ty_qpath, ty.hir_id) + && let Some(def_id) = res.opt_def_id() + && Some(def_id) == cx.tcx.lang_items().owned_box() + // At this point, we know ty is Box, now get T + && let Some(last) = last_path_segment(ty_qpath).args + && let Some(GenericArg::Type(boxed_ty)) = last.args.first() + // extract allocator from the Box for later + && let boxed_alloc_ty = last.args.get(1) + // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay + && let ty_ty = lower_ty(cx.tcx, boxed_ty.as_unambig_ty()) + && !ty_ty.has_escaping_bound_vars() + && ty_ty.is_sized(cx.tcx, cx.typing_env()) + && let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes()) + && ty_ty_size < box_size_threshold + // https://github.com/rust-lang/rust-clippy/issues/7114 + && match (vec_alloc_ty, boxed_alloc_ty) { + (None, None) => true, + // this is in the event that we have something like + // Vec<_, Global>, in which case is equivalent to + // Vec<_> + (None, Some(GenericArg::Type(inner))) | (Some(GenericArg::Type(inner)), None) => { + if let TyKind::Path(path) = inner.kind + && let Some(did) = cx.qpath_res(&path, inner.hir_id).opt_def_id() { + cx.tcx.lang_items().get(LangItem::GlobalAlloc) == Some(did) + } else { + false + } + }, + (Some(GenericArg::Type(l)), Some(GenericArg::Type(r))) => + // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay + lower_ty(cx.tcx, l.as_unambig_ty()) == lower_ty(cx.tcx, r.as_unambig_ty()), + _ => false } + { + span_lint_and_sugg( + cx, + VEC_BOX, + hir_ty.span, + "`Vec` is already on the heap, the boxing is unnecessary", + "try", + format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")), + Applicability::Unspecified, + ); + true } else { false } diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs index 7803d5115c971..cee4a53f03cbe 100644 --- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs +++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty}; -use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while}; +use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while, sym}; use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::Span; // TODO: add `ReadBuf` (RFC 2930) in "How to fix" once it is available in std declare_clippy_lint! { @@ -187,7 +187,7 @@ fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt fn is_reserve(cx: &LateContext<'_>, path: &PathSegment<'_>, self_expr: &Expr<'_>) -> bool { is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), sym::Vec) - && path.ident.name.as_str() == "reserve" + && path.ident.name == sym::reserve } /// Returns self if the expression is `Vec::set_len()` @@ -209,7 +209,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt ExprKind::MethodCall(path, self_expr, [arg], _) => { let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs(); if is_type_diagnostic_item(cx, self_type, sym::Vec) - && path.ident.name.as_str() == "set_len" + && path.ident.name == sym::set_len && !is_integer_literal(arg, 0) { Some((self_expr, expr.span)) diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs index d0067b1a65e71..12da891a71b11 100644 --- a/src/tools/clippy/clippy_lints/src/unused_self.rs +++ b/src/tools/clippy/clippy_lints/src/unused_self.rs @@ -1,6 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::macros::root_macro_call_first_node; +use clippy_utils::sym; use clippy_utils::visitors::is_local_used; use rustc_hir::{Body, Impl, ImplItem, ImplItemKind, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -61,12 +62,10 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { let assoc_item = cx.tcx.associated_item(impl_item.owner_id); let contains_todo = |cx, body: &'_ Body<'_>| -> bool { clippy_utils::visitors::for_each_expr_without_closures(body.value, |e| { - if let Some(macro_call) = root_macro_call_first_node(cx, e) { - if cx.tcx.item_name(macro_call.def_id).as_str() == "todo" { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) - } + if let Some(macro_call) = root_macro_call_first_node(cx, e) + && cx.tcx.is_diagnostic_item(sym::todo_macro, macro_call.def_id) + { + ControlFlow::Break(()) } else { ControlFlow::Continue(()) } diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs index d5309aade7aac..9859ddfdf7bde 100644 --- a/src/tools/clippy/clippy_lints/src/unused_unit.rs +++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs @@ -1,11 +1,18 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{SpanRangeExt, position_before_rarrow}; -use rustc_ast::visit::FnKind; -use rustc_ast::{ClosureBinder, ast}; +use clippy_utils::{is_never_expr, is_unit_expr}; +use rustc_ast::{Block, StmtKind}; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{ + AssocItemConstraintKind, Body, Expr, ExprKind, FnDecl, FnRetTy, GenericArgsParentheses, Node, PolyTraitRef, Term, + Ty, TyKind, +}; +use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{BytePos, Span}; +use rustc_span::edition::Edition; +use rustc_span::{BytePos, Span, sym}; declare_clippy_lint! { /// ### What it does @@ -34,27 +41,89 @@ declare_clippy_lint! { declare_lint_pass!(UnusedUnit => [UNUSED_UNIT]); -impl EarlyLintPass for UnusedUnit { - fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, span: Span, _: ast::NodeId) { - if let ast::FnRetTy::Ty(ref ty) = kind.decl().output - && let ast::TyKind::Tup(ref vals) = ty.kind - && vals.is_empty() - && !ty.span.from_expansion() - && get_def(span) == get_def(ty.span) +impl<'tcx> LateLintPass<'tcx> for UnusedUnit { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + kind: FnKind<'tcx>, + decl: &'tcx FnDecl<'tcx>, + body: &'tcx Body<'tcx>, + span: Span, + def_id: LocalDefId, + ) { + if let FnRetTy::Return(hir_ty) = decl.output + && is_unit_ty(hir_ty) + && !hir_ty.span.from_expansion() + && get_def(span) == get_def(hir_ty.span) { // implicit types in closure signatures are forbidden when `for<...>` is present - if let FnKind::Closure(&ClosureBinder::For { .. }, ..) = kind { + if let FnKind::Closure = kind + && let Node::Expr(expr) = cx.tcx.hir_node_by_def_id(def_id) + && let ExprKind::Closure(closure) = expr.kind + && !closure.bound_generic_params.is_empty() + { + return; + } + + // unit never type fallback is no longer supported since Rust 2024. For more information, + // see + if cx.tcx.sess.edition() >= Edition::Edition2024 + && let ExprKind::Block(block, _) = body.value.kind + && let Some(expr) = block.expr + && is_never_expr(cx, expr).is_some() + { return; } - lint_unneeded_unit_return(cx, ty, span); + lint_unneeded_unit_return(cx, hir_ty.span, span); } } - fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) { - if let Some(stmt) = block.stmts.last() - && let ast::StmtKind::Expr(ref expr) = stmt.kind + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let ExprKind::Ret(Some(expr)) | ExprKind::Break(_, Some(expr)) = expr.kind && is_unit_expr(expr) + && !expr.span.from_expansion() + { + span_lint_and_sugg( + cx, + UNUSED_UNIT, + expr.span, + "unneeded `()`", + "remove the `()`", + String::new(), + Applicability::MachineApplicable, + ); + } + } + + fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>) { + let segments = &poly.trait_ref.path.segments; + + if segments.len() == 1 + && ["Fn", "FnMut", "FnOnce"].contains(&segments[0].ident.name.as_str()) + && let Some(args) = segments[0].args + && args.parenthesized == GenericArgsParentheses::ParenSugar + && let constraints = &args.constraints + && constraints.len() == 1 + && constraints[0].ident.name == sym::Output + && let AssocItemConstraintKind::Equality { term: Term::Ty(hir_ty) } = constraints[0].kind + && args.span_ext.hi() != poly.span.hi() + && !hir_ty.span.from_expansion() + && is_unit_ty(hir_ty) + { + lint_unneeded_unit_return(cx, hir_ty.span, poly.span); + } + } +} + +impl EarlyLintPass for UnusedUnit { + /// Check for unit expressions in blocks. This is left in the early pass because some macros + /// expand its inputs as-is, making it invisible to the late pass. See #4076. + fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) { + if let Some(stmt) = block.stmts.last() + && let StmtKind::Expr(expr) = &stmt.kind + && let rustc_ast::ExprKind::Tup(inner) = &expr.kind + && inner.is_empty() && let ctxt = block.span.ctxt() && stmt.span.ctxt() == ctxt && expr.span.ctxt() == ctxt @@ -72,39 +141,10 @@ impl EarlyLintPass for UnusedUnit { ); } } +} - fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { - match e.kind { - ast::ExprKind::Ret(Some(ref expr)) | ast::ExprKind::Break(_, Some(ref expr)) => { - if is_unit_expr(expr) && !expr.span.from_expansion() { - span_lint_and_sugg( - cx, - UNUSED_UNIT, - expr.span, - "unneeded `()`", - "remove the `()`", - String::new(), - Applicability::MachineApplicable, - ); - } - }, - _ => (), - } - } - - fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef) { - let segments = &poly.trait_ref.path.segments; - - if segments.len() == 1 - && ["Fn", "FnMut", "FnOnce"].contains(&segments[0].ident.name.as_str()) - && let Some(args) = &segments[0].args - && let ast::GenericArgs::Parenthesized(generic_args) = &**args - && let ast::FnRetTy::Ty(ty) = &generic_args.output - && ty.kind.is_unit() - { - lint_unneeded_unit_return(cx, ty, generic_args.span); - } - } +fn is_unit_ty(ty: &Ty<'_>) -> bool { + matches!(ty.kind, TyKind::Tup([])) } // get the def site @@ -117,24 +157,15 @@ fn get_def(span: Span) -> Option { } } -// is this expr a `()` unit? -fn is_unit_expr(expr: &ast::Expr) -> bool { - if let ast::ExprKind::Tup(ref vals) = expr.kind { - vals.is_empty() - } else { - false - } -} - -fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) { +fn lint_unneeded_unit_return(cx: &LateContext<'_>, ty_span: Span, span: Span) { let (ret_span, appl) = - span.with_hi(ty.span.hi()) + span.with_hi(ty_span.hi()) .get_source_text(cx) - .map_or((ty.span, Applicability::MaybeIncorrect), |src| { - position_before_rarrow(&src).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| { + .map_or((ty_span, Applicability::MaybeIncorrect), |src| { + position_before_rarrow(&src).map_or((ty_span, Applicability::MaybeIncorrect), |rpos| { ( #[expect(clippy::cast_possible_truncation)] - ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), + ty_span.with_lo(BytePos(span.lo().0 + rpos as u32)), Applicability::MachineApplicable, ) }) diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index ce82b56eb946f..ba140788bb54e 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -208,7 +208,7 @@ fn is_option_as_mut_use(tcx: TyCtxt<'_>, expr_id: HirId) -> bool { if let Node::Expr(mutating_expr) = tcx.parent_hir_node(expr_id) && let ExprKind::MethodCall(path, _, [], _) = mutating_expr.kind { - path.ident.name.as_str() == "as_mut" + path.ident.name == sym::as_mut } else { false } @@ -278,7 +278,7 @@ fn consume_option_as_ref<'tcx>(expr: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, Opt if let ExprKind::MethodCall(path, recv, [], _) = expr.kind { if path.ident.name == sym::as_ref { (recv, Some(AsRefKind::AsRef)) - } else if path.ident.name.as_str() == "as_mut" { + } else if path.ident.name == sym::as_mut { (recv, Some(AsRefKind::AsMut)) } else { (expr, None) diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index 11c14c1477764..f24c127c4521d 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -1,8 +1,8 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::is_in_test; use clippy_utils::macros::{FormatArgsStorage, MacroCall, format_arg_removal_span, root_macro_call_first_node}; use clippy_utils::source::{SpanRangeExt, expand_past_previous_comma}; +use clippy_utils::{is_in_test, sym}; use rustc_ast::token::LitKind; use rustc_ast::{ FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, @@ -12,7 +12,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; -use rustc_span::{BytePos, Span, sym}; +use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -359,7 +359,7 @@ fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool { } fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &MacroCall, name: &str) { - let Some(FormatArgsPiece::Literal(last)) = format_args.template.last() else { + let Some(&FormatArgsPiece::Literal(last)) = format_args.template.last() else { return; }; @@ -401,7 +401,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &Ma return; }; - if format_args.template.len() == 1 && last.as_str() == "\n" { + if format_args.template.len() == 1 && last == sym::LF { // print!("\n"), write!(f, "\n") diag.multipart_suggestion( @@ -427,9 +427,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &Ma } fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &MacroCall, name: &str) { - if let [FormatArgsPiece::Literal(literal)] = &format_args.template[..] - && literal.as_str() == "\n" - { + if let [FormatArgsPiece::Literal(sym::LF)] = &format_args.template[..] { let mut span = format_args.span; let lint = if name == "writeln" { diff --git a/src/tools/clippy/clippy_lints/src/zombie_processes.rs b/src/tools/clippy/clippy_lints/src/zombie_processes.rs index 39c1aab8967ad..09f1084fe7004 100644 --- a/src/tools/clippy/clippy_lints/src/zombie_processes.rs +++ b/src/tools/clippy/clippy_lints/src/zombie_processes.rs @@ -4,6 +4,7 @@ use clippy_utils::{fn_def_id, get_enclosing_block, path_to_local_id}; use rustc_ast::Mutability; use rustc_ast::visit::visit_opt; use rustc_errors::Applicability; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_local}; use rustc_hir::{Expr, ExprKind, HirId, LetStmt, Node, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -68,6 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for ZombieProcesses { let mut vis = WaitFinder { cx, local_id, + body_id: cx.tcx.hir_enclosing_body_owner(expr.hir_id), state: VisitorState::WalkUpToLocal, early_return: None, missing_wait_branch: None, @@ -129,6 +131,7 @@ struct MaybeWait(Span); struct WaitFinder<'a, 'tcx> { cx: &'a LateContext<'tcx>, local_id: HirId, + body_id: LocalDefId, state: VisitorState, early_return: Option, // When joining two if branches where one of them doesn't call `wait()`, stores its span for more targeted help @@ -186,7 +189,7 @@ impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> { } } else { match ex.kind { - ExprKind::Ret(e) => { + ExprKind::Ret(e) if self.cx.tcx.hir_enclosing_body_owner(ex.hir_id) == self.body_id => { visit_opt!(self, visit_expr, e); if self.early_return.is_none() { self.early_return = Some(ex.span); diff --git a/src/tools/clippy/clippy_lints_internal/src/lib.rs b/src/tools/clippy/clippy_lints_internal/src/lib.rs index 1c42f4112f9a1..b02d378619cab 100644 --- a/src/tools/clippy/clippy_lints_internal/src/lib.rs +++ b/src/tools/clippy/clippy_lints_internal/src/lib.rs @@ -2,6 +2,7 @@ #![allow( clippy::missing_docs_in_private_items, clippy::must_use_candidate, + clippy::symbol_as_str, rustc::diagnostic_outside_of_impl, rustc::untranslatable_diagnostic )] @@ -31,12 +32,12 @@ extern crate rustc_span; mod almost_standard_lint_formulation; mod collapsible_calls; -mod interning_literals; mod invalid_paths; mod lint_without_lint_pass; mod msrv_attr_impl; mod outer_expn_data_pass; mod produce_ice; +mod symbols; mod unnecessary_def_path; mod unsorted_clippy_utils_paths; @@ -45,7 +46,6 @@ use rustc_lint::{Lint, LintStore}; static LINTS: &[&Lint] = &[ almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION, collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS, - interning_literals::INTERNING_LITERALS, invalid_paths::INVALID_PATHS, lint_without_lint_pass::DEFAULT_LINT, lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE, @@ -54,6 +54,8 @@ static LINTS: &[&Lint] = &[ msrv_attr_impl::MISSING_MSRV_ATTR_IMPL, outer_expn_data_pass::OUTER_EXPN_EXPN_DATA, produce_ice::PRODUCE_ICE, + symbols::INTERNING_LITERALS, + symbols::SYMBOL_AS_STR, unnecessary_def_path::UNNECESSARY_DEF_PATH, unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS, ]; @@ -65,7 +67,7 @@ pub fn register_lints(store: &mut LintStore) { store.register_early_pass(|| Box::new(produce_ice::ProduceIce)); store.register_late_pass(|_| Box::new(collapsible_calls::CollapsibleCalls)); store.register_late_pass(|_| Box::new(invalid_paths::InvalidPaths)); - store.register_late_pass(|_| Box::::default()); + store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::new(outer_expn_data_pass::OuterExpnDataPass)); diff --git a/src/tools/clippy/clippy_lints_internal/src/interning_literals.rs b/src/tools/clippy/clippy_lints_internal/src/symbols.rs similarity index 52% rename from src/tools/clippy/clippy_lints_internal/src/interning_literals.rs rename to src/tools/clippy/clippy_lints_internal/src/symbols.rs index 6cee37442349c..c64e5821916bf 100644 --- a/src/tools/clippy/clippy_lints_internal/src/interning_literals.rs +++ b/src/tools/clippy/clippy_lints_internal/src/symbols.rs @@ -1,7 +1,7 @@ -use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::match_type; -use clippy_utils::{def_path_def_ids, paths}; +use clippy_utils::{def_path_def_ids, match_def_path, paths}; +use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -11,8 +11,8 @@ use rustc_lint_defs::declare_tool_lint; use rustc_middle::mir::ConstValue; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::sym; use rustc_span::symbol::Symbol; +use rustc_span::{Span, sym}; declare_tool_lint! { /// ### What it does @@ -36,15 +36,37 @@ declare_tool_lint! { report_in_external_macro: true } +declare_tool_lint! { + /// ### What it does + /// Checks for calls to `Symbol::as_str` + /// + /// ### Why is this bad? + /// It's faster and easier to use the symbol constant. If one doesn't exist it can be added to `clippy_utils/src/sym.rs` + /// + /// ### Example + /// ```rust,ignore + /// symbol.as_str() == "foo" + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// symbol == sym::foo + /// ``` + pub clippy::SYMBOL_AS_STR, + Warn, + "calls to `Symbol::as_str`", + report_in_external_macro: true +} + #[derive(Default)] -pub struct InterningDefinedSymbol { +pub struct Symbols { // Maps the symbol to the import path symbol_map: FxHashMap, } -impl_lint_pass!(InterningDefinedSymbol => [INTERNING_LITERALS]); +impl_lint_pass!(Symbols => [INTERNING_LITERALS, SYMBOL_AS_STR]); -impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { +impl<'tcx> LateLintPass<'tcx> for Symbols { fn check_crate(&mut self, cx: &LateContext<'_>) { let modules = [ ("kw", &paths::KW_MODULE[..]), @@ -77,7 +99,8 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { if let ExprKind::Call(func, [arg]) = &expr.kind && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind() && cx.tcx.is_diagnostic_item(sym::SymbolIntern, *def_id) - && let Some(Constant::Str(arg)) = ConstEvalCtxt::new(cx).eval_simple(arg) + && let ExprKind::Lit(lit) = arg.kind + && let LitKind::Str(name, _) = lit.node { span_lint_and_then( cx, @@ -85,18 +108,62 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { expr.span, "interning a string literal", |diag| { - let value = Symbol::intern(&arg).as_u32(); - let (message, path) = if let Some((prefix, name)) = self.symbol_map.get(&value) { - ("use the preinterned symbol", format!("{prefix}::{name}")) - } else { - ( - "add the symbol to `clippy_utils/src/sym.rs` and use it", - format!("sym::{}", arg.replace(|ch: char| !ch.is_alphanumeric(), "_")), - ) - }; + let (message, path) = suggestion(&mut self.symbol_map, name); diag.span_suggestion_verbose(expr.span, message, path, Applicability::MaybeIncorrect); }, ); } + + if let ExprKind::Binary(_, lhs, rhs) = expr.kind { + check_binary(cx, lhs, rhs, &mut self.symbol_map); + check_binary(cx, rhs, lhs, &mut self.symbol_map); + } + } +} + +fn check_binary( + cx: &LateContext<'_>, + lhs: &Expr<'_>, + rhs: &Expr<'_>, + symbols: &mut FxHashMap, +) { + if let Some(removal_span) = as_str_span(cx, lhs) + && let ExprKind::Lit(lit) = rhs.kind + && let LitKind::Str(name, _) = lit.node + { + span_lint_and_then(cx, SYMBOL_AS_STR, lhs.span, "converting a Symbol to a string", |diag| { + let (message, path) = suggestion(symbols, name); + diag.multipart_suggestion_verbose( + message, + vec![(removal_span, String::new()), (rhs.span, path)], + Applicability::MachineApplicable, + ); + }); + } +} + +fn suggestion(symbols: &mut FxHashMap, name: Symbol) -> (&'static str, String) { + if let Some((prefix, name)) = symbols.get(&name.as_u32()) { + ("use the preinterned symbol", format!("{prefix}::{name}")) + } else { + ( + "add the symbol to `clippy_utils/src/sym.rs` and use it", + format!("sym::{}", name.as_str().replace(|ch: char| !ch.is_alphanumeric(), "_")), + ) + } +} + +/// ```ignore +/// symbol.as_str() +/// // ^^^^^^^^ +/// ``` +fn as_str_span(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { + if let ExprKind::MethodCall(_, recv, [], _) = expr.kind + && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && match_def_path(cx, method_def_id, &paths::SYMBOL_AS_STR) + { + Some(recv.span.shrink_to_hi().to(expr.span.shrink_to_hi())) + } else { + None } } diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md index aceff14a1599c..66192f866fa0e 100644 --- a/src/tools/clippy/clippy_utils/README.md +++ b/src/tools/clippy/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2025-04-22 +nightly-2025-05-01 ``` diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs index d4e66ebd8e1fb..dbb993482902f 100644 --- a/src/tools/clippy/clippy_utils/src/higher.rs +++ b/src/tools/clippy/clippy_utils/src/higher.rs @@ -3,14 +3,14 @@ #![deny(clippy::missing_docs_in_private_items)] use crate::consts::{ConstEvalCtxt, Constant}; -use crate::is_expn_of; use crate::ty::is_type_diagnostic_item; +use crate::{is_expn_of, sym}; use rustc_ast::ast; use rustc_hir as hir; use rustc_hir::{Arm, Block, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath, StructTailExpr}; use rustc_lint::LateContext; -use rustc_span::{Span, sym, symbol}; +use rustc_span::{Span, symbol}; /// The essential nodes of a desugared for loop as well as the entire span: /// `for pat in arg { body }` becomes `(pat, arg, body)`. Returns `(pat, arg, body, span)`. @@ -474,7 +474,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) - return Some(VecInitKind::New); } else if name.ident.name == symbol::kw::Default { return Some(VecInitKind::Default); - } else if name.ident.name.as_str() == "with_capacity" { + } else if name.ident.name == sym::with_capacity { let arg = args.first()?; return match ConstEvalCtxt::new(cx).eval_simple(arg) { Some(Constant::Int(num)) => Some(VecInitKind::WithConstCapacity(num)), diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 17368a7530d75..c37231d093129 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1118,8 +1118,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_const_arg(e); }, TyPatKind::Or(variants) => { - for variant in variants.iter() { - self.hash_ty_pat(variant) + for variant in variants { + self.hash_ty_pat(variant); } }, TyPatKind::Err(_) => {}, diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 264b9b0406d0b..187dfa4dda845 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1412,7 +1412,7 @@ pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { } /// Gets the name of the item the expression is in, if available. -pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { +pub fn parent_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { let parent_id = cx.tcx.hir_get_parent_item(expr.hir_id).def_id; match cx.tcx.hir_node_by_def_id(parent_id) { Node::Item(item) => item.kind.ident().map(|ident| ident.name), @@ -2088,7 +2088,7 @@ pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool { let path = cx.get_def_path(did); // libc is meant to be used as a flat list of names, but they're all actually defined in different // modules based on the target platform. Ignore everything but crate name and the item name. - path.first().is_some_and(|s| s.as_str() == "libc") && path.last().is_some_and(|s| s.as_str() == name) + path.first().is_some_and(|s| *s == sym::libc) && path.last().is_some_and(|s| s.as_str() == name) } /// Returns the list of condition expressions and the list of blocks in a @@ -3101,7 +3101,7 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span { sm.span_take_while(span, |&ch| ch == ' ' || ch == ';') } -/// Returns whether the given let pattern and else body can be turned into a question mark +/// Returns whether the given let pattern and else body can be turned into the `?` operator /// /// For this example: /// ```ignore @@ -3124,8 +3124,7 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span { /// ``` /// /// We output `Some(a)` in the first instance, and `Some(FooBar { a, b })` in the second, because -/// the question mark operator is applicable here. Callers have to check whether we are in a -/// constant or not. +/// the `?` operator is applicable here. Callers have to check whether we are in a constant or not. pub fn pat_and_expr_can_be_question_mark<'a, 'hir>( cx: &LateContext<'_>, pat: &'a Pat<'hir>, diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs index 1a30b473d1063..38f077134c033 100644 --- a/src/tools/clippy/clippy_utils/src/sym.rs +++ b/src/tools/clippy/clippy_utils/src/sym.rs @@ -30,33 +30,75 @@ macro_rules! generate { } generate! { + abs, as_bytes, as_deref_mut, as_deref, as_mut, Binary, + build_hasher, + cargo_clippy: "cargo-clippy", Cargo_toml: "Cargo.toml", + cast, + chars, CLIPPY_ARGS, CLIPPY_CONF_DIR, + clone_into, cloned, + collect, contains, copied, + CRLF: "\r\n", Current, + ends_with, + exp, + extend, + finish_non_exhaustive, + finish, + flat_map, + for_each, + from_raw, + from_str_radix, get, insert, int_roundings, + into_bytes, + into_owned, IntoIter, + is_ascii, is_empty, + is_err, + is_none, is_ok, is_some, + last, + LF: "\n", LowerExp, LowerHex, + max, + min, + mode, msrv, Octal, or_default, + parse, + push, regex, + reserve, + resize, + restriction, rustfmt_skip, + set_len, + set_mode, + set_readonly, + signum, + split_whitespace, + split, Start, + take, + TBD, + then_some, + to_digit, to_owned, unused_extern_crates, unwrap_err, @@ -66,4 +108,6 @@ generate! { V4, V6, Weak, + with_capacity, + wrapping_offset, } diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml index d2f79da1a541b..39c7f0e4ad5a5 100644 --- a/src/tools/clippy/rust-toolchain.toml +++ b/src/tools/clippy/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-04-22" +channel = "nightly-2025-05-01" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/src/tools/clippy/tests/ui-internal/symbol_as_str.fixed b/src/tools/clippy/tests/ui-internal/symbol_as_str.fixed new file mode 100644 index 0000000000000..3e26732836ca8 --- /dev/null +++ b/src/tools/clippy/tests/ui-internal/symbol_as_str.fixed @@ -0,0 +1,21 @@ +#![feature(rustc_private)] + +extern crate rustc_span; + +use clippy_utils::sym; +use rustc_span::{Symbol, kw}; + +fn f(s: Symbol) { + s == sym::f32; + //~^ symbol_as_str + s == sym::proc_dash_macro; + //~^ symbol_as_str + s == kw::SelfLower; + //~^ symbol_as_str + s == sym::msrv; + //~^ symbol_as_str + s == sym::Cargo_toml; + //~^ symbol_as_str + sym::get == s; + //~^ symbol_as_str +} diff --git a/src/tools/clippy/tests/ui-internal/symbol_as_str.rs b/src/tools/clippy/tests/ui-internal/symbol_as_str.rs new file mode 100644 index 0000000000000..334c32d189837 --- /dev/null +++ b/src/tools/clippy/tests/ui-internal/symbol_as_str.rs @@ -0,0 +1,21 @@ +#![feature(rustc_private)] + +extern crate rustc_span; + +use clippy_utils::sym; +use rustc_span::{Symbol, kw}; + +fn f(s: Symbol) { + s.as_str() == "f32"; + //~^ symbol_as_str + s.as_str() == "proc-macro"; + //~^ symbol_as_str + s.as_str() == "self"; + //~^ symbol_as_str + s.as_str() == "msrv"; + //~^ symbol_as_str + s.as_str() == "Cargo.toml"; + //~^ symbol_as_str + "get" == s.as_str(); + //~^ symbol_as_str +} diff --git a/src/tools/clippy/tests/ui-internal/symbol_as_str.stderr b/src/tools/clippy/tests/ui-internal/symbol_as_str.stderr new file mode 100644 index 0000000000000..39f81f3833c49 --- /dev/null +++ b/src/tools/clippy/tests/ui-internal/symbol_as_str.stderr @@ -0,0 +1,76 @@ +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str.rs:9:5 + | +LL | s.as_str() == "f32"; + | ^^^^^^^^^^ + | + = note: `-D clippy::symbol-as-str` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::symbol_as_str)]` +help: use the preinterned symbol + | +LL - s.as_str() == "f32"; +LL + s == sym::f32; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str.rs:11:5 + | +LL | s.as_str() == "proc-macro"; + | ^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - s.as_str() == "proc-macro"; +LL + s == sym::proc_dash_macro; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str.rs:13:5 + | +LL | s.as_str() == "self"; + | ^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - s.as_str() == "self"; +LL + s == kw::SelfLower; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str.rs:15:5 + | +LL | s.as_str() == "msrv"; + | ^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - s.as_str() == "msrv"; +LL + s == sym::msrv; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str.rs:17:5 + | +LL | s.as_str() == "Cargo.toml"; + | ^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - s.as_str() == "Cargo.toml"; +LL + s == sym::Cargo_toml; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str.rs:19:14 + | +LL | "get" == s.as_str(); + | ^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - "get" == s.as_str(); +LL + sym::get == s; + | + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.rs b/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.rs new file mode 100644 index 0000000000000..635f28007e9af --- /dev/null +++ b/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.rs @@ -0,0 +1,15 @@ +//@no-rustfix: paths that don't exist yet +#![feature(rustc_private)] + +extern crate rustc_span; + +use rustc_span::Symbol; + +fn f(s: Symbol) { + s.as_str() == "xyz123"; + //~^ symbol_as_str + s.as_str() == "with-dash"; + //~^ symbol_as_str + s.as_str() == "with.dot"; + //~^ symbol_as_str +} diff --git a/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.stderr b/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.stderr new file mode 100644 index 0000000000000..5349983ca5196 --- /dev/null +++ b/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.stderr @@ -0,0 +1,40 @@ +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str_unfixable.rs:9:5 + | +LL | s.as_str() == "xyz123"; + | ^^^^^^^^^^ + | + = note: `-D clippy::symbol-as-str` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::symbol_as_str)]` +help: add the symbol to `clippy_utils/src/sym.rs` and use it + | +LL - s.as_str() == "xyz123"; +LL + s == sym::xyz123; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str_unfixable.rs:11:5 + | +LL | s.as_str() == "with-dash"; + | ^^^^^^^^^^ + | +help: add the symbol to `clippy_utils/src/sym.rs` and use it + | +LL - s.as_str() == "with-dash"; +LL + s == sym::with_dash; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str_unfixable.rs:13:5 + | +LL | s.as_str() == "with.dot"; + | ^^^^^^^^^^ + | +help: add the symbol to `clippy_utils/src/sym.rs` and use it + | +LL - s.as_str() == "with.dot"; +LL + s == sym::with_dot; + | + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed index e696896538e54..6ae5b0cb2f041 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed @@ -4,7 +4,6 @@ #![allow( unused, unnecessary_transmutes, - clippy::let_and_return, clippy::needless_if, clippy::missing_transmute_annotations )] diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.rs b/src/tools/clippy/tests/ui/blocks_in_conditions.rs index 8c8f3249b8a74..3fd060620728f 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.rs +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.rs @@ -4,7 +4,6 @@ #![allow( unused, unnecessary_transmutes, - clippy::let_and_return, clippy::needless_if, clippy::missing_transmute_annotations )] diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.stderr b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr index 41ff59c683e84..282c42a98bfc2 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.stderr +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr @@ -1,5 +1,5 @@ error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> tests/ui/blocks_in_conditions.rs:31:5 + --> tests/ui/blocks_in_conditions.rs:30:5 | LL | / if { LL | | @@ -20,13 +20,13 @@ LL ~ }; if res { | error: omit braces around single expression condition - --> tests/ui/blocks_in_conditions.rs:43:8 + --> tests/ui/blocks_in_conditions.rs:42:8 | LL | if { true } { 6 } else { 10 } | ^^^^^^^^ help: try: `true` error: this boolean expression can be simplified - --> tests/ui/blocks_in_conditions.rs:49:8 + --> tests/ui/blocks_in_conditions.rs:48:8 | LL | if true && x == 3 { 6 } else { 10 } | ^^^^^^^^^^^^^^ help: try: `x == 3` diff --git a/src/tools/clippy/tests/ui/equatable_if_let.fixed b/src/tools/clippy/tests/ui/equatable_if_let.fixed index 166b1387ba265..ce8b67f9ca7b0 100644 --- a/src/tools/clippy/tests/ui/equatable_if_let.fixed +++ b/src/tools/clippy/tests/ui/equatable_if_let.fixed @@ -103,3 +103,39 @@ fn main() { external!({ if let 2 = $a {} }); } + +mod issue8710 { + fn str_ref(cs: &[char]) { + if matches!(cs.iter().next(), Some('i')) { + //~^ equatable_if_let + } else { + todo!(); + } + } + + fn i32_ref(cs: &[i32]) { + if matches!(cs.iter().next(), Some(1)) { + //~^ equatable_if_let + } else { + todo!(); + } + } + + fn enum_ref() { + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] + enum MyEnum { + A(i32), + B, + } + + fn get_enum() -> Option<&'static MyEnum> { + todo!() + } + + if matches!(get_enum(), Some(MyEnum::B)) { + //~^ equatable_if_let + } else { + todo!(); + } + } +} diff --git a/src/tools/clippy/tests/ui/equatable_if_let.rs b/src/tools/clippy/tests/ui/equatable_if_let.rs index 09c2483ae6d43..ff09533f26519 100644 --- a/src/tools/clippy/tests/ui/equatable_if_let.rs +++ b/src/tools/clippy/tests/ui/equatable_if_let.rs @@ -103,3 +103,39 @@ fn main() { external!({ if let 2 = $a {} }); } + +mod issue8710 { + fn str_ref(cs: &[char]) { + if let Some('i') = cs.iter().next() { + //~^ equatable_if_let + } else { + todo!(); + } + } + + fn i32_ref(cs: &[i32]) { + if let Some(1) = cs.iter().next() { + //~^ equatable_if_let + } else { + todo!(); + } + } + + fn enum_ref() { + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] + enum MyEnum { + A(i32), + B, + } + + fn get_enum() -> Option<&'static MyEnum> { + todo!() + } + + if let Some(MyEnum::B) = get_enum() { + //~^ equatable_if_let + } else { + todo!(); + } + } +} diff --git a/src/tools/clippy/tests/ui/equatable_if_let.stderr b/src/tools/clippy/tests/ui/equatable_if_let.stderr index 81e0e15a5c747..dd1832ad68b28 100644 --- a/src/tools/clippy/tests/ui/equatable_if_let.stderr +++ b/src/tools/clippy/tests/ui/equatable_if_let.stderr @@ -85,5 +85,23 @@ error: this pattern matching can be expressed using equality LL | if let inline!("abc") = "abc" { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"abc" == inline!("abc")` -error: aborting due to 14 previous errors +error: this pattern matching can be expressed using `matches!` + --> tests/ui/equatable_if_let.rs:109:12 + | +LL | if let Some('i') = cs.iter().next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some('i'))` + +error: this pattern matching can be expressed using `matches!` + --> tests/ui/equatable_if_let.rs:117:12 + | +LL | if let Some(1) = cs.iter().next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some(1))` + +error: this pattern matching can be expressed using `matches!` + --> tests/ui/equatable_if_let.rs:135:12 + | +LL | if let Some(MyEnum::B) = get_enum() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(get_enum(), Some(MyEnum::B))` + +error: aborting due to 17 previous errors diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.fixed b/src/tools/clippy/tests/ui/manual_div_ceil.fixed index 57fe8917afe88..58ee6978fc125 100644 --- a/src/tools/clippy/tests/ui/manual_div_ceil.fixed +++ b/src/tools/clippy/tests/ui/manual_div_ceil.fixed @@ -1,5 +1,21 @@ #![warn(clippy::manual_div_ceil)] +macro_rules! y { + () => { + let x = 33u32; + let _ = x.div_ceil(8); + //~^ manual_div_ceil + let _ = x.div_ceil(8); + //~^ manual_div_ceil + }; +} + +macro_rules! eight { + () => { + 8 + }; +} + fn main() { let x = 7_u32; let y = 4_u32; @@ -32,6 +48,13 @@ fn main() { let _ = (z as i32 + (y_i - 1)) / y_i; let _ = (7_u32 as i32 + (y_i - 1)) / y_i; let _ = (7_u32 as i32 + (4 - 1)) / 4; + + // Test lint with macro + y!(); + + // Also test if RHS should be result of macro expansion + let _ = 33u32.div_ceil(eight!()); + //~^ manual_div_ceil } fn issue_13843() { diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.rs b/src/tools/clippy/tests/ui/manual_div_ceil.rs index ec343513e5ce3..aa0d81b22a0e2 100644 --- a/src/tools/clippy/tests/ui/manual_div_ceil.rs +++ b/src/tools/clippy/tests/ui/manual_div_ceil.rs @@ -1,5 +1,21 @@ #![warn(clippy::manual_div_ceil)] +macro_rules! y { + () => { + let x = 33u32; + let _ = (x + 7) / 8; + //~^ manual_div_ceil + let _ = (7 + x) / 8; + //~^ manual_div_ceil + }; +} + +macro_rules! eight { + () => { + 8 + }; +} + fn main() { let x = 7_u32; let y = 4_u32; @@ -32,6 +48,13 @@ fn main() { let _ = (z as i32 + (y_i - 1)) / y_i; let _ = (7_u32 as i32 + (y_i - 1)) / y_i; let _ = (7_u32 as i32 + (4 - 1)) / 4; + + // Test lint with macro + y!(); + + // Also test if RHS should be result of macro expansion + let _ = (33u32 + 7) / eight!(); + //~^ manual_div_ceil } fn issue_13843() { diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.stderr b/src/tools/clippy/tests/ui/manual_div_ceil.stderr index 8e14ab274269a..9be5a19bf391f 100644 --- a/src/tools/clippy/tests/ui/manual_div_ceil.stderr +++ b/src/tools/clippy/tests/ui/manual_div_ceil.stderr @@ -1,5 +1,5 @@ error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:9:13 + --> tests/ui/manual_div_ceil.rs:25:13 | LL | let _ = (x + (y - 1)) / y; | ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` @@ -8,94 +8,122 @@ LL | let _ = (x + (y - 1)) / y; = help: to override `-D warnings` add `#[allow(clippy::manual_div_ceil)]` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:11:13 + --> tests/ui/manual_div_ceil.rs:27:13 | LL | let _ = ((y - 1) + x) / y; | ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:13:13 + --> tests/ui/manual_div_ceil.rs:29:13 | LL | let _ = (x + y - 1) / y; | ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:16:13 + --> tests/ui/manual_div_ceil.rs:32:13 | LL | let _ = (7_u32 + (4 - 1)) / 4; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `7_u32.div_ceil(4)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:18:13 + --> tests/ui/manual_div_ceil.rs:34:13 | LL | let _ = (7_i32 as u32 + (4 - 1)) / 4; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(7_i32 as u32).div_ceil(4)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:39:13 + --> tests/ui/manual_div_ceil.rs:6:17 + | +LL | let _ = (x + 7) / 8; + | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` +... +LL | y!(); + | ---- in this macro invocation + | + = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:8:17 + | +LL | let _ = (7 + x) / 8; + | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` +... +LL | y!(); + | ---- in this macro invocation + | + = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:56:13 + | +LL | let _ = (33u32 + 7) / eight!(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `33u32.div_ceil(eight!())` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:62:13 | LL | let _ = (2048 + x - 1) / x; | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:43:13 + --> tests/ui/manual_div_ceil.rs:66:13 | LL | let _ = (2048usize + x - 1) / x; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048usize.div_ceil(x)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:47:13 + --> tests/ui/manual_div_ceil.rs:70:13 | LL | let _ = (2048_usize + x - 1) / x; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:51:13 + --> tests/ui/manual_div_ceil.rs:74:13 | LL | let _ = (x + 4 - 1) / 4; | ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(4)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:54:18 + --> tests/ui/manual_div_ceil.rs:77:18 | LL | let _: u32 = (2048 + 6 - 1) / 6; | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:56:20 + --> tests/ui/manual_div_ceil.rs:79:20 | LL | let _: usize = (2048 + 6 - 1) / 6; | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(6)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:58:18 + --> tests/ui/manual_div_ceil.rs:81:18 | LL | let _: u32 = (0x2048 + 0x6 - 1) / 0x6; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `0x2048_u32.div_ceil(0x6)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:61:13 + --> tests/ui/manual_div_ceil.rs:84:13 | LL | let _ = (2048 + 6u32 - 1) / 6u32; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6u32)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:64:13 + --> tests/ui/manual_div_ceil.rs:87:13 | LL | let _ = (1_000_000 + 6u32 - 1) / 6u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `1_000_000_u32.div_ceil(6u32)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:70:13 + --> tests/ui/manual_div_ceil.rs:93:13 | LL | let _ = (x + 7) / 8; | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:72:13 + --> tests/ui/manual_div_ceil.rs:95:13 | LL | let _ = (7 + x) / 8; | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` -error: aborting due to 16 previous errors +error: aborting due to 19 previous errors diff --git a/src/tools/clippy/tests/ui/needless_if.fixed b/src/tools/clippy/tests/ui/needless_if.fixed index 6208ca19b82b4..347dbff7c595c 100644 --- a/src/tools/clippy/tests/ui/needless_if.fixed +++ b/src/tools/clippy/tests/ui/needless_if.fixed @@ -46,9 +46,7 @@ fn main() { if let true = true && true {} - if true - && let true = true - {} + if true && let true = true {} // Can lint nested `if let`s ({ //~^ needless_if diff --git a/src/tools/clippy/tests/ui/needless_if.rs b/src/tools/clippy/tests/ui/needless_if.rs index b459ff877be61..5e0f2a14408bc 100644 --- a/src/tools/clippy/tests/ui/needless_if.rs +++ b/src/tools/clippy/tests/ui/needless_if.rs @@ -46,9 +46,7 @@ fn main() { if let true = true && true {} - if true - && let true = true - {} + if true && let true = true {} // Can lint nested `if let`s if { //~^ needless_if diff --git a/src/tools/clippy/tests/ui/needless_if.stderr b/src/tools/clippy/tests/ui/needless_if.stderr index eeb8d044526d3..62cdf2459448d 100644 --- a/src/tools/clippy/tests/ui/needless_if.stderr +++ b/src/tools/clippy/tests/ui/needless_if.stderr @@ -31,7 +31,7 @@ LL + }); | error: this `if` branch is empty - --> tests/ui/needless_if.rs:53:5 + --> tests/ui/needless_if.rs:51:5 | LL | / if { LL | | @@ -57,19 +57,19 @@ LL + } && true); | error: this `if` branch is empty - --> tests/ui/needless_if.rs:98:5 + --> tests/ui/needless_if.rs:96:5 | LL | if { maybe_side_effect() } {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() });` error: this `if` branch is empty - --> tests/ui/needless_if.rs:101:5 + --> tests/ui/needless_if.rs:99:5 | LL | if { maybe_side_effect() } && true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() } && true);` error: this `if` branch is empty - --> tests/ui/needless_if.rs:106:5 + --> tests/ui/needless_if.rs:104:5 | LL | if true {} | ^^^^^^^^^^ help: you can remove it: `true;` diff --git a/src/tools/clippy/tests/ui/needless_late_init.fixed b/src/tools/clippy/tests/ui/needless_late_init.fixed index 391d4bc3fcc74..f832752ccd798 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.fixed +++ b/src/tools/clippy/tests/ui/needless_late_init.fixed @@ -246,9 +246,7 @@ fn does_not_lint() { } let x; - if true - && let Some(n) = Some("let chains too") - { + if true && let Some(n) = Some("let chains too") { x = 1; } else { x = 2; diff --git a/src/tools/clippy/tests/ui/needless_late_init.rs b/src/tools/clippy/tests/ui/needless_late_init.rs index 6096e8300e1a1..a52fbf5292344 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.rs +++ b/src/tools/clippy/tests/ui/needless_late_init.rs @@ -246,9 +246,7 @@ fn does_not_lint() { } let x; - if true - && let Some(n) = Some("let chains too") - { + if true && let Some(n) = Some("let chains too") { x = 1; } else { x = 2; diff --git a/src/tools/clippy/tests/ui/needless_late_init.stderr b/src/tools/clippy/tests/ui/needless_late_init.stderr index e7c36136847b0..b24c127588162 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.stderr +++ b/src/tools/clippy/tests/ui/needless_late_init.stderr @@ -276,7 +276,7 @@ LL ~ }; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:302:5 + --> tests/ui/needless_late_init.rs:300:5 | LL | let r; | ^^^^^^ created here diff --git a/src/tools/clippy/tests/ui/needless_question_mark.stderr b/src/tools/clippy/tests/ui/needless_question_mark.stderr index 55da4f28976c1..8516cee48e679 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.stderr +++ b/src/tools/clippy/tests/ui/needless_question_mark.stderr @@ -1,100 +1,188 @@ -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:20:12 | LL | return Some(to.magic?); - | ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic` + | ^^^^^^^^^^^^^^^ | = note: `-D clippy::needless-question-mark` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_question_mark)]` +help: remove the enclosing `Some` and `?` operator + | +LL - return Some(to.magic?); +LL + return to.magic; + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:29:12 | LL | return Some(to.magic?) - | ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic` + | ^^^^^^^^^^^^^^^ + | +help: remove the enclosing `Some` and `?` operator + | +LL - return Some(to.magic?) +LL + return to.magic + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:35:5 | LL | Some(to.magic?) - | ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic` + | ^^^^^^^^^^^^^^^ + | +help: remove the enclosing `Some` and `?` operator + | +LL - Some(to.magic?) +LL + to.magic + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:41:21 | LL | to.and_then(|t| Some(t.magic?)) - | ^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `t.magic` + | ^^^^^^^^^^^^^^ + | +help: remove the enclosing `Some` and `?` operator + | +LL - to.and_then(|t| Some(t.magic?)) +LL + to.and_then(|t| t.magic) + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:51:9 | LL | Some(t.magic?) - | ^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `t.magic` + | ^^^^^^^^^^^^^^ + | +help: remove the enclosing `Some` and `?` operator + | +LL - Some(t.magic?) +LL + t.magic + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:57:12 | LL | return Ok(tr.magic?); - | ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic` + | ^^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - return Ok(tr.magic?); +LL + return tr.magic; + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:65:12 | LL | return Ok(tr.magic?) - | ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic` + | ^^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - return Ok(tr.magic?) +LL + return tr.magic + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:70:5 | LL | Ok(tr.magic?) - | ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic` + | ^^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - Ok(tr.magic?) +LL + tr.magic + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:75:21 | LL | tr.and_then(|t| Ok(t.magic?)) - | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic` + | ^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - tr.and_then(|t| Ok(t.magic?)) +LL + tr.and_then(|t| t.magic) + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:84:9 | LL | Ok(t.magic?) - | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic` + | ^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - Ok(t.magic?) +LL + t.magic + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:92:16 | LL | return Ok(t.magic?); - | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic` + | ^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - return Ok(t.magic?); +LL + return t.magic; + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:128:27 | LL | || -> Option<_> { Some(Some($expr)?) }() - | ^^^^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `Some($expr)` + | ^^^^^^^^^^^^^^^^^^ ... LL | let _x = some_and_qmark_in_macro!(x?); | ---------------------------- in this macro invocation | = note: this error originates in the macro `some_and_qmark_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info) +help: remove the enclosing `Some` and `?` operator + | +LL - || -> Option<_> { Some(Some($expr)?) }() +LL + || -> Option<_> { Some($expr) }() + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:140:5 | LL | Some(to.magic?) - | ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic` + | ^^^^^^^^^^^^^^^ + | +help: remove the enclosing `Some` and `?` operator + | +LL - Some(to.magic?) +LL + to.magic + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:149:5 | LL | Ok(s.magic?) - | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `s.magic` + | ^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - Ok(s.magic?) +LL + s.magic + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:154:7 | LL | { Some(a?) } - | ^^^^^^^^ help: try removing question mark and `Some()`: `a` + | ^^^^^^^^ + | +help: remove the enclosing `Some` and `?` operator + | +LL - { Some(a?) } +LL + { a } + | error: aborting due to 15 previous errors diff --git a/src/tools/clippy/tests/ui/ptr_eq.fixed b/src/tools/clippy/tests/ui/ptr_eq.fixed index 484ff30732392..9629b3eea5870 100644 --- a/src/tools/clippy/tests/ui/ptr_eq.fixed +++ b/src/tools/clippy/tests/ui/ptr_eq.fixed @@ -23,23 +23,25 @@ fn main() { //~^ ptr_eq let _ = std::ptr::eq(a, b); //~^ ptr_eq - let _ = std::ptr::eq(a.as_ptr(), b as *const _); - //~^ ptr_eq - let _ = std::ptr::eq(a.as_ptr(), b.as_ptr()); - //~^ ptr_eq - // Do not lint + // Do not lint: the rhs conversion is needed + let _ = a.as_ptr() == b as *const _; + // Do not lint: we have two raw pointers already + let _ = a.as_ptr() == b.as_ptr(); + + // Do not lint let _ = mac!(a, b); let _ = another_mac!(a, b); let a = &mut [1, 2, 3]; let b = &mut [1, 2, 3]; - let _ = std::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _); - //~^ ptr_eq - let _ = std::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr()); - //~^ ptr_eq + // Do not lint: the rhs conversion is needed + let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; + + // Do not lint: we have two raw pointers already + let _ = a.as_mut_ptr() == b.as_mut_ptr(); let _ = a == b; let _ = core::ptr::eq(a, b); @@ -51,8 +53,12 @@ fn main() { let _ = !std::ptr::eq(x, y); //~^ ptr_eq - #[allow(clippy::eq_op)] - let _issue14337 = std::ptr::eq(main as *const (), main as *const ()); + #[expect(clippy::eq_op)] + // Do not lint: casts are needed to not change type + let _issue14337 = main as *const () == main as *const (); + + // Do not peel the content of macros + let _ = std::ptr::eq(mac!(cast a), mac!(cast b)); //~^ ptr_eq // Do not peel the content of macros diff --git a/src/tools/clippy/tests/ui/ptr_eq.rs b/src/tools/clippy/tests/ui/ptr_eq.rs index f28707cc3e927..2b741d8df4684 100644 --- a/src/tools/clippy/tests/ui/ptr_eq.rs +++ b/src/tools/clippy/tests/ui/ptr_eq.rs @@ -23,23 +23,25 @@ fn main() { //~^ ptr_eq let _ = a as *const _ == b as *const _; //~^ ptr_eq + + // Do not lint: the rhs conversion is needed let _ = a.as_ptr() == b as *const _; - //~^ ptr_eq + + // Do not lint: we have two raw pointers already let _ = a.as_ptr() == b.as_ptr(); - //~^ ptr_eq // Do not lint - let _ = mac!(a, b); let _ = another_mac!(a, b); let a = &mut [1, 2, 3]; let b = &mut [1, 2, 3]; + // Do not lint: the rhs conversion is needed let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; - //~^ ptr_eq + + // Do not lint: we have two raw pointers already let _ = a.as_mut_ptr() == b.as_mut_ptr(); - //~^ ptr_eq let _ = a == b; let _ = core::ptr::eq(a, b); @@ -51,8 +53,12 @@ fn main() { let _ = x as *const u32 != y as *mut u32 as *const u32; //~^ ptr_eq - #[allow(clippy::eq_op)] + #[expect(clippy::eq_op)] + // Do not lint: casts are needed to not change type let _issue14337 = main as *const () == main as *const (); + + // Do not peel the content of macros + let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _; //~^ ptr_eq // Do not peel the content of macros diff --git a/src/tools/clippy/tests/ui/ptr_eq.stderr b/src/tools/clippy/tests/ui/ptr_eq.stderr index 906831b9e0312..e7340624b5950 100644 --- a/src/tools/clippy/tests/ui/ptr_eq.stderr +++ b/src/tools/clippy/tests/ui/ptr_eq.stderr @@ -14,52 +14,28 @@ LL | let _ = a as *const _ == b as *const _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)` error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:26:13 - | -LL | let _ = a.as_ptr() == b as *const _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_ptr(), b as *const _)` - -error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:28:13 - | -LL | let _ = a.as_ptr() == b.as_ptr(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_ptr(), b.as_ptr())` - -error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:39:13 - | -LL | let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _)` - -error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:41:13 - | -LL | let _ = a.as_mut_ptr() == b.as_mut_ptr(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr())` - -error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:48:13 + --> tests/ui/ptr_eq.rs:50:13 | LL | let _ = x as *const u32 == y as *mut u32 as *const u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(x, y)` error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:51:13 + --> tests/ui/ptr_eq.rs:53:13 | LL | let _ = x as *const u32 != y as *mut u32 as *const u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!std::ptr::eq(x, y)` error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:55:23 + --> tests/ui/ptr_eq.rs:61:13 | -LL | let _issue14337 = main as *const () == main as *const (); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(main as *const (), main as *const ())` +LL | let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(mac!(cast a), mac!(cast b))` error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:59:13 + --> tests/ui/ptr_eq.rs:65:13 | LL | let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(mac!(cast a), mac!(cast b))` -error: aborting due to 10 previous errors +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed b/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed index d8ee4ea88f843..48cbad62e1a36 100644 --- a/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed +++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed @@ -32,23 +32,25 @@ fn main() { //~^ ptr_eq let _ = core::ptr::eq(a, b); //~^ ptr_eq - let _ = core::ptr::eq(a.as_ptr(), b as *const _); - //~^ ptr_eq - let _ = core::ptr::eq(a.as_ptr(), b.as_ptr()); - //~^ ptr_eq - // Do not lint + // Do not lint: the rhs conversion is needed + let _ = a.as_ptr() == b as *const _; + + // Do not lint: we have two raw pointers already + let _ = a.as_ptr() == b.as_ptr(); + // Do not lint let _ = mac!(a, b); let _ = another_mac!(a, b); let a = &mut [1, 2, 3]; let b = &mut [1, 2, 3]; - let _ = core::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _); - //~^ ptr_eq - let _ = core::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr()); - //~^ ptr_eq + // Do not lint: the rhs conversion is needed + let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; + + // Do not lint: we have two raw pointers already + let _ = a.as_mut_ptr() == b.as_mut_ptr(); let _ = a == b; let _ = core::ptr::eq(a, b); diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.rs b/src/tools/clippy/tests/ui/ptr_eq_no_std.rs index a236314c29b77..3827178640eea 100644 --- a/src/tools/clippy/tests/ui/ptr_eq_no_std.rs +++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.rs @@ -32,23 +32,25 @@ fn main() { //~^ ptr_eq let _ = a as *const _ == b as *const _; //~^ ptr_eq + + // Do not lint: the rhs conversion is needed let _ = a.as_ptr() == b as *const _; - //~^ ptr_eq + + // Do not lint: we have two raw pointers already let _ = a.as_ptr() == b.as_ptr(); - //~^ ptr_eq // Do not lint - let _ = mac!(a, b); let _ = another_mac!(a, b); let a = &mut [1, 2, 3]; let b = &mut [1, 2, 3]; + // Do not lint: the rhs conversion is needed let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; - //~^ ptr_eq + + // Do not lint: we have two raw pointers already let _ = a.as_mut_ptr() == b.as_mut_ptr(); - //~^ ptr_eq let _ = a == b; let _ = core::ptr::eq(a, b); diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr b/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr index 5b8135dc8e8bc..8c7b1ff76661f 100644 --- a/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr +++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr @@ -13,29 +13,5 @@ error: use `core::ptr::eq` when comparing raw pointers LL | let _ = a as *const _ == b as *const _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a, b)` -error: use `core::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq_no_std.rs:35:13 - | -LL | let _ = a.as_ptr() == b as *const _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_ptr(), b as *const _)` - -error: use `core::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq_no_std.rs:37:13 - | -LL | let _ = a.as_ptr() == b.as_ptr(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_ptr(), b.as_ptr())` - -error: use `core::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq_no_std.rs:48:13 - | -LL | let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _)` - -error: use `core::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq_no_std.rs:50:13 - | -LL | let _ = a.as_mut_ptr() == b.as_mut_ptr(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr())` - -error: aborting due to 6 previous errors +error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed index 6bd071d07f523..507bc2b29d862 100644 --- a/src/tools/clippy/tests/ui/question_mark.fixed +++ b/src/tools/clippy/tests/ui/question_mark.fixed @@ -301,6 +301,11 @@ fn pattern() -> Result<(), PatternedError> { res } +fn expect_expr(a: Option) -> Option { + #[expect(clippy::needless_question_mark)] + Some(a?) +} + fn main() {} // `?` is not the same as `return None;` if inside of a try block diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs index dd093c9bf480c..64b51b849ede0 100644 --- a/src/tools/clippy/tests/ui/question_mark.rs +++ b/src/tools/clippy/tests/ui/question_mark.rs @@ -371,6 +371,11 @@ fn pattern() -> Result<(), PatternedError> { res } +fn expect_expr(a: Option) -> Option { + #[expect(clippy::needless_question_mark)] + Some(a?) +} + fn main() {} // `?` is not the same as `return None;` if inside of a try block diff --git a/src/tools/clippy/tests/ui/question_mark.stderr b/src/tools/clippy/tests/ui/question_mark.stderr index 8fe04b895cea2..d8ce4420aeeb6 100644 --- a/src/tools/clippy/tests/ui/question_mark.stderr +++ b/src/tools/clippy/tests/ui/question_mark.stderr @@ -198,7 +198,7 @@ LL | | } | |_____^ help: replace it with: `func_returning_result()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:390:13 + --> tests/ui/question_mark.rs:395:13 | LL | / if a.is_none() { LL | | @@ -208,7 +208,7 @@ LL | | } | |_____________^ help: replace it with: `a?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:451:5 + --> tests/ui/question_mark.rs:456:5 | LL | / let Some(v) = bar.foo.owned.clone() else { LL | | return None; @@ -216,7 +216,7 @@ LL | | }; | |______^ help: replace it with: `let v = bar.foo.owned.clone()?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:466:5 + --> tests/ui/question_mark.rs:471:5 | LL | / let Some(ref x) = foo.opt_x else { LL | | return None; @@ -224,7 +224,7 @@ LL | | }; | |______^ help: replace it with: `let x = foo.opt_x.as_ref()?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:476:5 + --> tests/ui/question_mark.rs:481:5 | LL | / let Some(ref mut x) = foo.opt_x else { LL | | return None; @@ -232,7 +232,7 @@ LL | | }; | |______^ help: replace it with: `let x = foo.opt_x.as_mut()?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:487:5 + --> tests/ui/question_mark.rs:492:5 | LL | / let Some(ref x @ ref y) = foo.opt_x else { LL | | return None; @@ -240,7 +240,7 @@ LL | | }; | |______^ help: replace it with: `let x @ y = foo.opt_x.as_ref()?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:491:5 + --> tests/ui/question_mark.rs:496:5 | LL | / let Some(ref x @ WrapperStructWithString(_)) = bar else { LL | | return None; @@ -248,7 +248,7 @@ LL | | }; | |______^ help: replace it with: `let x @ &WrapperStructWithString(_) = bar.as_ref()?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:495:5 + --> tests/ui/question_mark.rs:500:5 | LL | / let Some(ref mut x @ WrapperStructWithString(_)) = bar else { LL | | return None; @@ -256,7 +256,7 @@ LL | | }; | |______^ help: replace it with: `let x @ &mut WrapperStructWithString(_) = bar.as_mut()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:517:5 + --> tests/ui/question_mark.rs:522:5 | LL | / if arg.is_none() { LL | | @@ -265,7 +265,7 @@ LL | | } | |_____^ help: replace it with: `arg?;` error: this `match` expression can be replaced with `?` - --> tests/ui/question_mark.rs:521:15 + --> tests/ui/question_mark.rs:526:15 | LL | let val = match arg { | _______________^ @@ -276,7 +276,7 @@ LL | | }; | |_____^ help: try instead: `arg?` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:531:5 + --> tests/ui/question_mark.rs:536:5 | LL | / let Some(a) = *a else { LL | | return None; diff --git a/src/tools/clippy/tests/ui/question_mark_used.stderr b/src/tools/clippy/tests/ui/question_mark_used.stderr index 53cb59c021667..82f0d32504077 100644 --- a/src/tools/clippy/tests/ui/question_mark_used.stderr +++ b/src/tools/clippy/tests/ui/question_mark_used.stderr @@ -1,4 +1,4 @@ -error: question mark operator was used +error: the `?` operator was used --> tests/ui/question_mark_used.rs:11:5 | LL | other_function()?; diff --git a/src/tools/clippy/tests/ui/return_and_then.stderr b/src/tools/clippy/tests/ui/return_and_then.stderr index cc611c3dba679..a7acbe7b3401c 100644 --- a/src/tools/clippy/tests/ui/return_and_then.stderr +++ b/src/tools/clippy/tests/ui/return_and_then.stderr @@ -1,4 +1,4 @@ -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:5:9 | LL | / opt.and_then(|n| { @@ -20,7 +20,7 @@ LL + ret += n; LL + if n > 1 { Some(ret) } else { None } | -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:14:9 | LL | opt.and_then(|n| test_opt_block(Some(n))) @@ -32,7 +32,7 @@ LL ~ let n = opt?; LL + test_opt_block(Some(n)) | -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:19:9 | LL | gen_option(1).and_then(|n| test_opt_block(Some(n))) @@ -44,7 +44,7 @@ LL ~ let n = gen_option(1)?; LL + test_opt_block(Some(n)) | -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:24:9 | LL | opt.and_then(|n| if n > 1 { Ok(n + 1) } else { Err(n) }) @@ -56,7 +56,7 @@ LL ~ let n = opt?; LL + if n > 1 { Ok(n + 1) } else { Err(n) } | -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:29:9 | LL | opt.and_then(|n| test_res_block(Ok(n))) @@ -68,7 +68,7 @@ LL ~ let n = opt?; LL + test_res_block(Ok(n)) | -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:35:9 | LL | Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None }) @@ -80,7 +80,7 @@ LL ~ let x = Some("")?; LL + if x.len() > 2 { Some(3) } else { None } | -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:41:9 | LL | / Some(match (vec![1, 2, 3], vec![1, 2, 4]) { diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.fixed b/src/tools/clippy/tests/ui/unnecessary_cast.fixed index ba167e79a308b..91ff4b9ee7713 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_cast.fixed @@ -266,7 +266,21 @@ mod fixable { // Issue #11968: The suggestion for this lint removes the parentheses and leave the code as // `*x.pow(2)` which tries to dereference the return value rather than `x`. fn issue_11968(x: &usize) -> usize { - { *x }.pow(2) + (*x).pow(2) + //~^ unnecessary_cast + } + + #[allow(clippy::cast_lossless)] + fn issue_14640() { + let x = 5usize; + let vec: Vec = vec![1, 2, 3, 4, 5]; + assert_eq!(vec.len(), x); + //~^ unnecessary_cast + + let _ = (5i32 as i64).abs(); + //~^ unnecessary_cast + + let _ = 5i32 as i64; //~^ unnecessary_cast } } diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.rs b/src/tools/clippy/tests/ui/unnecessary_cast.rs index 0f90a8b05965a..5444a914db167 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.rs +++ b/src/tools/clippy/tests/ui/unnecessary_cast.rs @@ -269,4 +269,18 @@ mod fixable { (*x as usize).pow(2) //~^ unnecessary_cast } + + #[allow(clippy::cast_lossless)] + fn issue_14640() { + let x = 5usize; + let vec: Vec = vec![1, 2, 3, 4, 5]; + assert_eq!(vec.len(), x as usize); + //~^ unnecessary_cast + + let _ = (5i32 as i64 as i64).abs(); + //~^ unnecessary_cast + + let _ = 5i32 as i64 as i64; + //~^ unnecessary_cast + } } diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.stderr b/src/tools/clippy/tests/ui/unnecessary_cast.stderr index c83770c1a2992..3e3c5eb81c105 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_cast.stderr @@ -245,7 +245,25 @@ error: casting to the same type is unnecessary (`usize` -> `usize`) --> tests/ui/unnecessary_cast.rs:269:9 | LL | (*x as usize).pow(2) - | ^^^^^^^^^^^^^ help: try: `{ *x }` + | ^^^^^^^^^^^^^ help: try: `(*x)` -error: aborting due to 41 previous errors +error: casting to the same type is unnecessary (`usize` -> `usize`) + --> tests/ui/unnecessary_cast.rs:277:31 + | +LL | assert_eq!(vec.len(), x as usize); + | ^^^^^^^^^^ help: try: `x` + +error: casting to the same type is unnecessary (`i64` -> `i64`) + --> tests/ui/unnecessary_cast.rs:280:17 + | +LL | let _ = (5i32 as i64 as i64).abs(); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `(5i32 as i64)` + +error: casting to the same type is unnecessary (`i64` -> `i64`) + --> tests/ui/unnecessary_cast.rs:283:17 + | +LL | let _ = 5i32 as i64 as i64; + | ^^^^^^^^^^^^^^^^^^ help: try: `5i32 as i64` + +error: aborting due to 44 previous errors diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed b/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed new file mode 100644 index 0000000000000..93dd58b8e9d7b --- /dev/null +++ b/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed @@ -0,0 +1,146 @@ +//@revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 + +// The output for humans should just highlight the whole span without showing +// the suggested replacement, but we also want to test that suggested +// replacement only removes one set of parentheses, rather than naïvely +// stripping away any starting or ending parenthesis characters—hence this +// test of the JSON error format. + +#![feature(custom_inner_attributes)] +#![feature(closure_lifetime_binder)] +#![rustfmt::skip] + +#![deny(clippy::unused_unit)] +#![allow(dead_code)] +#![allow(clippy::from_over_into)] + +struct Unitter; +impl Unitter { + #[allow(clippy::no_effect)] + pub fn get_unit(&self, f: F, _g: G) + //~^ unused_unit + //~| unused_unit + where G: Fn() { + //~^ unused_unit + let _y: &dyn Fn() = &f; + //~^ unused_unit + (); // this should not lint, as it's not in return type position + } +} + +impl Into<()> for Unitter { + #[rustfmt::skip] + fn into(self) { + //~^ unused_unit + + //~^ unused_unit + } +} + +trait Trait { + fn redundant(&self, _f: F, _g: G, _h: H) + //~^ unused_unit + where + G: FnMut(), + //~^ unused_unit + H: Fn(); + //~^ unused_unit +} + +impl Trait for Unitter { + fn redundant(&self, _f: F, _g: G, _h: H) + //~^ unused_unit + where + G: FnMut(), + //~^ unused_unit + H: Fn() {} + //~^ unused_unit +} + +fn return_unit() { } +//~^ unused_unit +//~| unused_unit + +#[allow(clippy::needless_return)] +#[allow(clippy::never_loop)] +#[allow(clippy::unit_cmp)] +fn main() { + let u = Unitter; + assert_eq!(u.get_unit(|| {}, return_unit), u.into()); + return_unit(); + loop { + break; + //~^ unused_unit + } + return; + //~^ unused_unit +} + +// https://github.com/rust-lang/rust-clippy/issues/4076 +fn foo() { + macro_rules! foo { + (recv($r:expr) -> $res:pat => $body:expr) => { + $body + } + } + + foo! { + recv(rx) -> _x => () + } +} + +#[rustfmt::skip] +fn test(){} +//~^ unused_unit + +#[rustfmt::skip] +fn test2(){} +//~^ unused_unit + +#[rustfmt::skip] +fn test3(){} +//~^ unused_unit + +fn macro_expr() { + macro_rules! e { + () => (()); + } + e!() +} + +mod issue9748 { + fn main() { + let _ = for<'a> |_: &'a u32| -> () {}; + } +} + +mod issue9949 { + fn main() { + #[doc = "documentation"] + () + } +} + +mod issue14577 { + trait Unit {} + impl Unit for () {} + + fn run(f: impl FnOnce() -> R) { + f(); + } + + #[allow(dependency_on_unit_never_type_fallback)] + fn bar() { + run(|| { todo!() }); + //~[edition2021]^ unused_unit + } + + struct UnitStruct; + impl UnitStruct { + fn apply Fn(&'c mut Self)>(&mut self, f: F) { + todo!() + } + } +} \ No newline at end of file diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2021.stderr b/src/tools/clippy/tests/ui/unused_unit.edition2021.stderr new file mode 100644 index 0000000000000..13cc20d4d7adc --- /dev/null +++ b/src/tools/clippy/tests/ui/unused_unit.edition2021.stderr @@ -0,0 +1,128 @@ +error: unneeded unit expression + --> tests/ui/unused_unit.rs:37:9 + | +LL | () + | ^^ help: remove the final `()` + | +note: the lint level is defined here + --> tests/ui/unused_unit.rs:15:9 + | +LL | #![deny(clippy::unused_unit)] + | ^^^^^^^^^^^^^^^^^^^ + +error: unneeded unit expression + --> tests/ui/unused_unit.rs:62:26 + | +LL | fn return_unit() -> () { () } + | ^^ help: remove the final `()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:22:28 + | +LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:25:18 + | +LL | where G: Fn() -> () { + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:22:58 + | +LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:27:26 + | +LL | let _y: &dyn Fn() -> () = &f; + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:35:18 + | +LL | fn into(self) -> () { + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:43:29 + | +LL | fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:46:19 + | +LL | G: FnMut() -> (), + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:48:16 + | +LL | H: Fn() -> (); + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:53:29 + | +LL | fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:56:19 + | +LL | G: FnMut() -> (), + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:58:16 + | +LL | H: Fn() -> () {} + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:62:17 + | +LL | fn return_unit() -> () { () } + | ^^^^^^ help: remove the `-> ()` + +error: unneeded `()` + --> tests/ui/unused_unit.rs:74:14 + | +LL | break(); + | ^^ help: remove the `()` + +error: unneeded `()` + --> tests/ui/unused_unit.rs:77:11 + | +LL | return(); + | ^^ help: remove the `()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:95:10 + | +LL | fn test()->(){} + | ^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:99:11 + | +LL | fn test2() ->(){} + | ^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:103:11 + | +LL | fn test3()-> (){} + | ^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:136:15 + | +LL | run(|| -> () { todo!() }); + | ^^^^^^ help: remove the `-> ()` + +error: aborting due to 20 previous errors + diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed b/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed new file mode 100644 index 0000000000000..987d901b97df7 --- /dev/null +++ b/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed @@ -0,0 +1,146 @@ +//@revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 + +// The output for humans should just highlight the whole span without showing +// the suggested replacement, but we also want to test that suggested +// replacement only removes one set of parentheses, rather than naïvely +// stripping away any starting or ending parenthesis characters—hence this +// test of the JSON error format. + +#![feature(custom_inner_attributes)] +#![feature(closure_lifetime_binder)] +#![rustfmt::skip] + +#![deny(clippy::unused_unit)] +#![allow(dead_code)] +#![allow(clippy::from_over_into)] + +struct Unitter; +impl Unitter { + #[allow(clippy::no_effect)] + pub fn get_unit(&self, f: F, _g: G) + //~^ unused_unit + //~| unused_unit + where G: Fn() { + //~^ unused_unit + let _y: &dyn Fn() = &f; + //~^ unused_unit + (); // this should not lint, as it's not in return type position + } +} + +impl Into<()> for Unitter { + #[rustfmt::skip] + fn into(self) { + //~^ unused_unit + + //~^ unused_unit + } +} + +trait Trait { + fn redundant(&self, _f: F, _g: G, _h: H) + //~^ unused_unit + where + G: FnMut(), + //~^ unused_unit + H: Fn(); + //~^ unused_unit +} + +impl Trait for Unitter { + fn redundant(&self, _f: F, _g: G, _h: H) + //~^ unused_unit + where + G: FnMut(), + //~^ unused_unit + H: Fn() {} + //~^ unused_unit +} + +fn return_unit() { } +//~^ unused_unit +//~| unused_unit + +#[allow(clippy::needless_return)] +#[allow(clippy::never_loop)] +#[allow(clippy::unit_cmp)] +fn main() { + let u = Unitter; + assert_eq!(u.get_unit(|| {}, return_unit), u.into()); + return_unit(); + loop { + break; + //~^ unused_unit + } + return; + //~^ unused_unit +} + +// https://github.com/rust-lang/rust-clippy/issues/4076 +fn foo() { + macro_rules! foo { + (recv($r:expr) -> $res:pat => $body:expr) => { + $body + } + } + + foo! { + recv(rx) -> _x => () + } +} + +#[rustfmt::skip] +fn test(){} +//~^ unused_unit + +#[rustfmt::skip] +fn test2(){} +//~^ unused_unit + +#[rustfmt::skip] +fn test3(){} +//~^ unused_unit + +fn macro_expr() { + macro_rules! e { + () => (()); + } + e!() +} + +mod issue9748 { + fn main() { + let _ = for<'a> |_: &'a u32| -> () {}; + } +} + +mod issue9949 { + fn main() { + #[doc = "documentation"] + () + } +} + +mod issue14577 { + trait Unit {} + impl Unit for () {} + + fn run(f: impl FnOnce() -> R) { + f(); + } + + #[allow(dependency_on_unit_never_type_fallback)] + fn bar() { + run(|| -> () { todo!() }); + //~[edition2021]^ unused_unit + } + + struct UnitStruct; + impl UnitStruct { + fn apply Fn(&'c mut Self)>(&mut self, f: F) { + todo!() + } + } +} \ No newline at end of file diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2024.stderr b/src/tools/clippy/tests/ui/unused_unit.edition2024.stderr new file mode 100644 index 0000000000000..a79e70e066bd3 --- /dev/null +++ b/src/tools/clippy/tests/ui/unused_unit.edition2024.stderr @@ -0,0 +1,122 @@ +error: unneeded unit expression + --> tests/ui/unused_unit.rs:37:9 + | +LL | () + | ^^ help: remove the final `()` + | +note: the lint level is defined here + --> tests/ui/unused_unit.rs:15:9 + | +LL | #![deny(clippy::unused_unit)] + | ^^^^^^^^^^^^^^^^^^^ + +error: unneeded unit expression + --> tests/ui/unused_unit.rs:62:26 + | +LL | fn return_unit() -> () { () } + | ^^ help: remove the final `()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:22:28 + | +LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:25:18 + | +LL | where G: Fn() -> () { + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:22:58 + | +LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:27:26 + | +LL | let _y: &dyn Fn() -> () = &f; + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:35:18 + | +LL | fn into(self) -> () { + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:43:29 + | +LL | fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:46:19 + | +LL | G: FnMut() -> (), + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:48:16 + | +LL | H: Fn() -> (); + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:53:29 + | +LL | fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:56:19 + | +LL | G: FnMut() -> (), + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:58:16 + | +LL | H: Fn() -> () {} + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:62:17 + | +LL | fn return_unit() -> () { () } + | ^^^^^^ help: remove the `-> ()` + +error: unneeded `()` + --> tests/ui/unused_unit.rs:74:14 + | +LL | break(); + | ^^ help: remove the `()` + +error: unneeded `()` + --> tests/ui/unused_unit.rs:77:11 + | +LL | return(); + | ^^ help: remove the `()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:95:10 + | +LL | fn test()->(){} + | ^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:99:11 + | +LL | fn test2() ->(){} + | ^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:103:11 + | +LL | fn test3()-> (){} + | ^^^^^ help: remove the `-> ()` + +error: aborting due to 19 previous errors + diff --git a/src/tools/clippy/tests/ui/unused_unit.fixed b/src/tools/clippy/tests/ui/unused_unit.fixed index e3c02681c9fd7..6668bf90c0924 100644 --- a/src/tools/clippy/tests/ui/unused_unit.fixed +++ b/src/tools/clippy/tests/ui/unused_unit.fixed @@ -120,3 +120,24 @@ mod issue9949 { () } } + +#[clippy::msrv = "1.85"] +mod issue14577 { + trait Unit {} + impl Unit for () {} + + fn run(f: impl FnOnce() -> R) { + f(); + } + + fn bar() { + run(|| -> () { todo!() }); + } + + struct UnitStruct; + impl UnitStruct { + fn apply Fn(&'c mut Self)>(&mut self, f: F) { + todo!() + } + } +} \ No newline at end of file diff --git a/src/tools/clippy/tests/ui/unused_unit.rs b/src/tools/clippy/tests/ui/unused_unit.rs index 4353026c594c1..b7645f7b6a263 100644 --- a/src/tools/clippy/tests/ui/unused_unit.rs +++ b/src/tools/clippy/tests/ui/unused_unit.rs @@ -1,4 +1,6 @@ - +//@revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 // The output for humans should just highlight the whole span without showing // the suggested replacement, but we also want to test that suggested @@ -120,3 +122,25 @@ mod issue9949 { () } } + +mod issue14577 { + trait Unit {} + impl Unit for () {} + + fn run(f: impl FnOnce() -> R) { + f(); + } + + #[allow(dependency_on_unit_never_type_fallback)] + fn bar() { + run(|| -> () { todo!() }); + //~[edition2021]^ unused_unit + } + + struct UnitStruct; + impl UnitStruct { + fn apply Fn(&'c mut Self)>(&mut self, f: F) { + todo!() + } + } +} \ No newline at end of file diff --git a/src/tools/clippy/tests/ui/unused_unit.stderr b/src/tools/clippy/tests/ui/unused_unit.stderr index 172fe06550281..366f2142095ff 100644 --- a/src/tools/clippy/tests/ui/unused_unit.stderr +++ b/src/tools/clippy/tests/ui/unused_unit.stderr @@ -1,8 +1,8 @@ -error: unneeded unit return type - --> tests/ui/unused_unit.rs:20:58 +error: unneeded unit expression + --> tests/ui/unused_unit.rs:35:9 | -LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () - | ^^^^^^ help: remove the `-> ()` +LL | () + | ^^ help: remove the final `()` | note: the lint level is defined here --> tests/ui/unused_unit.rs:13:9 @@ -10,6 +10,12 @@ note: the lint level is defined here LL | #![deny(clippy::unused_unit)] | ^^^^^^^^^^^^^^^^^^^ +error: unneeded unit expression + --> tests/ui/unused_unit.rs:60:26 + | +LL | fn return_unit() -> () { () } + | ^^ help: remove the final `()` + error: unneeded unit return type --> tests/ui/unused_unit.rs:20:28 | @@ -22,6 +28,12 @@ error: unneeded unit return type LL | where G: Fn() -> () { | ^^^^^^ help: remove the `-> ()` +error: unneeded unit return type + --> tests/ui/unused_unit.rs:20:58 + | +LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () + | ^^^^^^ help: remove the `-> ()` + error: unneeded unit return type --> tests/ui/unused_unit.rs:25:26 | @@ -34,12 +46,6 @@ error: unneeded unit return type LL | fn into(self) -> () { | ^^^^^^ help: remove the `-> ()` -error: unneeded unit expression - --> tests/ui/unused_unit.rs:35:9 - | -LL | () - | ^^ help: remove the final `()` - error: unneeded unit return type --> tests/ui/unused_unit.rs:41:29 | @@ -82,12 +88,6 @@ error: unneeded unit return type LL | fn return_unit() -> () { () } | ^^^^^^ help: remove the `-> ()` -error: unneeded unit expression - --> tests/ui/unused_unit.rs:60:26 - | -LL | fn return_unit() -> () { () } - | ^^ help: remove the final `()` - error: unneeded `()` --> tests/ui/unused_unit.rs:72:14 | diff --git a/src/tools/clippy/tests/ui/zombie_processes.rs b/src/tools/clippy/tests/ui/zombie_processes.rs index 25bbc02ffb762..395f9dd2defb5 100644 --- a/src/tools/clippy/tests/ui/zombie_processes.rs +++ b/src/tools/clippy/tests/ui/zombie_processes.rs @@ -176,3 +176,25 @@ fn return_wait() -> ExitStatus { let mut x = Command::new("").spawn().unwrap(); return x.wait().unwrap(); } + +mod issue14677 { + use std::io; + use std::process::Command; + + fn do_something Result<(), ()>>(f: F) { + todo!() + } + + fn foo() { + let mut child = Command::new("true").spawn().unwrap(); + let some_condition = true; + do_something(|| { + if some_condition { + return Err(()); + } + Ok(()) + }); + child.kill().unwrap(); + child.wait().unwrap(); + } +} diff --git a/src/tools/clippy/util/etc/pre-commit.sh b/src/tools/clippy/util/etc/pre-commit.sh index 5dd2ba3d5f53b..528f8953b25d8 100755 --- a/src/tools/clippy/util/etc/pre-commit.sh +++ b/src/tools/clippy/util/etc/pre-commit.sh @@ -6,7 +6,6 @@ set -e # Update lints cargo dev update_lints git add clippy_lints/src/lib.rs -git add clippy_lints/src/lib.*.rs # Formatting: # Git will not automatically add the formatted code to the staged changes once