diff options
| author | Philipp Krones <hello@philkrones.com> | 2025-06-13 10:17:14 +0200 |
|---|---|---|
| committer | Philipp Krones <hello@philkrones.com> | 2025-06-13 10:17:14 +0200 |
| commit | 85655d4a098be06080e4ec20360a5eb7feab3e3f (patch) | |
| tree | ac84391c2d14214eff463de30e5eaf55656b9fc7 /clippy_lints/src/methods | |
| parent | 507183d438e615dcc24eb488a6622b5591801058 (diff) | |
| parent | 6d7c16a3d6301c6a07b2aad768e2e4113b9d5f8f (diff) | |
Merge remote-tracking branch 'upstream/master' into rustup
Diffstat (limited to 'clippy_lints/src/methods')
| -rw-r--r-- | clippy_lints/src/methods/ip_constant.rs | 52 | ||||
| -rw-r--r-- | clippy_lints/src/methods/iter_kv_map.rs | 2 | ||||
| -rw-r--r-- | clippy_lints/src/methods/manual_saturating_arithmetic.rs | 6 | ||||
| -rw-r--r-- | clippy_lints/src/methods/mod.rs | 39 | ||||
| -rw-r--r-- | clippy_lints/src/methods/needless_collect.rs | 9 | ||||
| -rw-r--r-- | clippy_lints/src/methods/open_options.rs | 18 | ||||
| -rw-r--r-- | clippy_lints/src/methods/str_splitn.rs | 8 | ||||
| -rw-r--r-- | clippy_lints/src/methods/unnecessary_sort_by.rs | 3 |
8 files changed, 114 insertions, 23 deletions
diff --git a/clippy_lints/src/methods/ip_constant.rs b/clippy_lints/src/methods/ip_constant.rs new file mode 100644 index 00000000000..83803fba6a1 --- /dev/null +++ b/clippy_lints/src/methods/ip_constant.rs @@ -0,0 +1,52 @@ +use clippy_utils::consts::{ConstEvalCtxt, Constant}; +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, QPath, Ty, TyKind}; +use rustc_lint::LateContext; +use rustc_span::sym; +use smallvec::SmallVec; + +use super::IP_CONSTANT; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, func: &Expr<'_>, args: &[Expr<'_>]) { + if let ExprKind::Path(QPath::TypeRelative( + Ty { + kind: TyKind::Path(QPath::Resolved(_, func_path)), + .. + }, + p, + )) = func.kind + && p.ident.name == sym::new + && let Some(func_def_id) = func_path.res.opt_def_id() + && matches!( + cx.tcx.get_diagnostic_name(func_def_id), + Some(sym::Ipv4Addr | sym::Ipv6Addr) + ) + && let Some(args) = args + .iter() + .map(|arg| { + if let Some(Constant::Int(constant @ (0 | 1 | 127 | 255))) = ConstEvalCtxt::new(cx).eval(arg) { + u8::try_from(constant).ok() + } else { + None + } + }) + .collect::<Option<SmallVec<[u8; 8]>>>() + { + let constant_name = match args.as_slice() { + [0, 0, 0, 0] | [0, 0, 0, 0, 0, 0, 0, 0] => "UNSPECIFIED", + [127, 0, 0, 1] | [0, 0, 0, 0, 0, 0, 0, 1] => "LOCALHOST", + [255, 255, 255, 255] => "BROADCAST", + _ => return, + }; + + span_lint_and_then(cx, IP_CONSTANT, expr.span, "hand-coded well-known IP address", |diag| { + diag.span_suggestion_verbose( + expr.span.with_lo(p.ident.span.lo()), + "use", + constant_name, + Applicability::MachineApplicable, + ); + }); + } +} diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index c88462129af..cbb1b450e60 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -46,7 +46,7 @@ pub(super) fn check<'tcx>( if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind && let [local_ident] = path.segments - && local_ident.ident.as_str() == bound_ident.as_str() + && local_ident.ident.name == bound_ident.name { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index e2df8ce1513..c785b23bc9c 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -72,9 +72,9 @@ fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<MinMax> { if let hir::ExprKind::Call(func, []) = &expr.kind && let hir::ExprKind::Path(hir::QPath::TypeRelative(_, segment)) = &func.kind { - match segment.ident.as_str() { - "max_value" => return Some(MinMax::Max), - "min_value" => return Some(MinMax::Min), + match segment.ident.name { + sym::max_value => return Some(MinMax::Max), + sym::min_value => return Some(MinMax::Min), _ => {}, } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index bc159206985..347960e0003 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -37,6 +37,7 @@ mod inefficient_to_string; mod inspect_for_each; mod into_iter_on_ref; mod io_other_error; +mod ip_constant; mod is_digit_ascii_radix; mod is_empty; mod iter_cloned_collect; @@ -4528,6 +4529,42 @@ declare_clippy_lint! { "detect swap with a temporary value" } +declare_clippy_lint! { + /// ### What it does + /// Checks for IP addresses that could be replaced with predefined constants such as + /// `Ipv4Addr::new(127, 0, 0, 1)` instead of using the appropriate constants. + /// + /// ### Why is this bad? + /// Using specific IP addresses like `127.0.0.1` or `::1` is less clear and less maintainable than using the + /// predefined constants `Ipv4Addr::LOCALHOST` or `Ipv6Addr::LOCALHOST`. These constants improve code + /// readability, make the intent explicit, and are less error-prone. + /// + /// ### Example + /// ```no_run + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// // IPv4 loopback + /// let addr_v4 = Ipv4Addr::new(127, 0, 0, 1); + /// + /// // IPv6 loopback + /// let addr_v6 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + /// ``` + /// Use instead: + /// ```no_run + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// // IPv4 loopback + /// let addr_v4 = Ipv4Addr::LOCALHOST; + /// + /// // IPv6 loopback + /// let addr_v6 = Ipv6Addr::LOCALHOST; + /// ``` + #[clippy::version = "1.89.0"] + pub IP_CONSTANT, + pedantic, + "hardcoded localhost IP address" +} + #[expect(clippy::struct_excessive_bools)] pub struct Methods { avoid_breaking_exported_api: bool, @@ -4706,6 +4743,7 @@ impl_lint_pass!(Methods => [ MANUAL_CONTAINS, IO_OTHER_ERROR, SWAP_WITH_TEMPORARY, + IP_CONSTANT, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4738,6 +4776,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { useless_nonzero_new_unchecked::check(cx, expr, func, args, self.msrv); io_other_error::check(cx, expr, func, args, self.msrv); swap_with_temporary::check(cx, expr, func, args); + ip_constant::check(cx, expr, func, args); }, ExprKind::MethodCall(method_call, receiver, args, _) => { let method_span = method_call.ident.span; diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 2b75d6a8248..0075bf166cc 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -44,11 +44,10 @@ pub(super) fn check<'tcx>( if let ExprKind::MethodCall(name, _, args @ ([] | [_]), _) = parent.kind { let mut app = Applicability::MachineApplicable; - let name = name.ident.as_str(); let collect_ty = cx.typeck_results().expr_ty(collect_expr); - let sugg: String = match name { - "len" => { + let sugg: String = match name.ident.name { + sym::len => { if let Some(adt) = collect_ty.ty_adt_def() && matches!( cx.tcx.get_diagnostic_name(adt.did()), @@ -60,13 +59,13 @@ pub(super) fn check<'tcx>( return; } }, - "is_empty" + sym::is_empty if is_is_empty_sig(cx, parent.hir_id) && iterates_same_ty(cx, cx.typeck_results().expr_ty(iter_expr), collect_ty) => { "next().is_none()".into() }, - "contains" => { + sym::contains => { if is_contains_sig(cx, parent.hir_id, iter_expr) && let Some(arg) = args.first() { diff --git a/clippy_lints/src/methods/open_options.rs b/clippy_lints/src/methods/open_options.rs index bce314e64f0..fd368024177 100644 --- a/clippy_lints/src/methods/open_options.rs +++ b/clippy_lints/src/methods/open_options.rs @@ -1,14 +1,14 @@ use rustc_data_structures::fx::FxHashMap; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::paths; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{paths, sym}; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; +use rustc_span::Span; use rustc_span::source_map::Spanned; -use rustc_span::{Span, sym}; use super::{NONSENSICAL_OPEN_OPTIONS, SUSPICIOUS_OPEN_OPTIONS}; @@ -87,23 +87,23 @@ fn get_open_options( _ => Argument::Unknown, }; - match path.ident.as_str() { - "create" => { + match path.ident.name { + sym::create => { options.push((OpenOption::Create, argument_option, span)); }, - "create_new" => { + sym::create_new => { options.push((OpenOption::CreateNew, argument_option, span)); }, - "append" => { + sym::append => { options.push((OpenOption::Append, argument_option, span)); }, - "truncate" => { + sym::truncate => { options.push((OpenOption::Truncate, argument_option, span)); }, - "read" => { + sym::read => { options.push((OpenOption::Read, argument_option, span)); }, - "write" => { + sym::write => { options.push((OpenOption::Write, argument_option, span)); }, _ => { diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 6935ae1f391..6f78d6c6128 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -285,9 +285,9 @@ fn parse_iter_usage<'tcx>( let did = cx.typeck_results().type_dependent_def_id(e.hir_id)?; let iter_id = cx.tcx.get_diagnostic_item(sym::Iterator)?; - match (name.ident.as_str(), args) { - ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => (IterUsageKind::Nth(0), e.span), - ("next_tuple", []) => { + match (name.ident.name, args) { + (sym::next, []) if cx.tcx.trait_of_item(did) == Some(iter_id) => (IterUsageKind::Nth(0), e.span), + (sym::next_tuple, []) => { return if paths::ITERTOOLS_NEXT_TUPLE.matches(cx, did) && let ty::Adt(adt_def, subs) = cx.typeck_results().expr_ty(e).kind() && cx.tcx.is_diagnostic_item(sym::Option, adt_def.did()) @@ -303,7 +303,7 @@ fn parse_iter_usage<'tcx>( None }; }, - ("nth" | "skip", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => { + (sym::nth | sym::skip, [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => { if let Some(Constant::Int(idx)) = ConstEvalCtxt::new(cx).eval(idx_expr) { let span = if name.ident.as_str() == "nth" { e.span diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs index dbff08bc51c..edd4ecd2b4a 100644 --- a/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -5,7 +5,8 @@ use clippy_utils::{is_trait_method, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, GenericArgKind}; +use rustc_middle::ty; +use rustc_middle::ty::GenericArgKind; use rustc_span::sym; use rustc_span::symbol::Ident; use std::iter; |
