about summary refs log tree commit diff
path: root/clippy_lints/src
diff options
context:
space:
mode:
Diffstat (limited to 'clippy_lints/src')
-rw-r--r--clippy_lints/src/declared_lints.rs1
-rw-r--r--clippy_lints/src/manual_div_ceil.rs2
-rw-r--r--clippy_lints/src/methods/io_other_error.rs37
-rw-r--r--clippy_lints/src/methods/mod.rs25
4 files changed, 64 insertions, 1 deletions
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 1cc1a81f8ce..9df9a62438c 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -400,6 +400,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::methods::INEFFICIENT_TO_STRING_INFO,
     crate::methods::INSPECT_FOR_EACH_INFO,
     crate::methods::INTO_ITER_ON_REF_INFO,
+    crate::methods::IO_OTHER_ERROR_INFO,
     crate::methods::IS_DIGIT_ASCII_RADIX_INFO,
     crate::methods::ITERATOR_STEP_BY_ZERO_INFO,
     crate::methods::ITER_CLONED_COLLECT_INFO,
diff --git a/clippy_lints/src/manual_div_ceil.rs b/clippy_lints/src/manual_div_ceil.rs
index dd242c4168c..04357cdd8f6 100644
--- a/clippy_lints/src/manual_div_ceil.rs
+++ b/clippy_lints/src/manual_div_ceil.rs
@@ -59,7 +59,7 @@ impl_lint_pass!(ManualDivCeil => [MANUAL_DIV_CEIL]);
 
 impl<'tcx> LateLintPass<'tcx> for ManualDivCeil {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
-        if !self.msrv.meets(msrvs::DIV_CEIL) {
+        if !self.msrv.meets(msrvs::MANUAL_DIV_CEIL) {
             return;
         }
 
diff --git a/clippy_lints/src/methods/io_other_error.rs b/clippy_lints/src/methods/io_other_error.rs
new file mode 100644
index 00000000000..e0ce013ca7b
--- /dev/null
+++ b/clippy_lints/src/methods/io_other_error.rs
@@ -0,0 +1,37 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{IO_ERROR_OTHER, Msrv};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, QPath};
+use rustc_lint::LateContext;
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, path: &Expr<'_>, args: &[Expr<'_>], msrv: &Msrv) {
+    if let [error_kind, error] = args
+        && !expr.span.from_expansion()
+        && !error_kind.span.from_expansion()
+        && clippy_utils::is_expr_path_def_path(cx, path, &clippy_utils::paths::IO_ERROR_NEW)
+        && clippy_utils::is_expr_path_def_path(
+            cx,
+            clippy_utils::expr_or_init(cx, error_kind),
+            &clippy_utils::paths::IO_ERRORKIND_OTHER,
+        )
+        && let ExprKind::Path(QPath::TypeRelative(_, new_segment)) = path.kind
+        && msrv.meets(IO_ERROR_OTHER)
+    {
+        span_lint_and_then(
+            cx,
+            super::IO_OTHER_ERROR,
+            expr.span,
+            "this can be `std::io::Error::other(_)`",
+            |diag| {
+                diag.multipart_suggestion_verbose(
+                    "use `std::io::Error::other`",
+                    vec![
+                        (new_segment.ident.span, "other".to_owned()),
+                        (error_kind.span.until(error.span), String::new()),
+                    ],
+                    Applicability::MachineApplicable,
+                );
+            },
+        );
+    }
+}
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 7f421d09827..291ddc1ce17 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -36,6 +36,7 @@ mod implicit_clone;
 mod inefficient_to_string;
 mod inspect_for_each;
 mod into_iter_on_ref;
+mod io_other_error;
 mod is_digit_ascii_radix;
 mod is_empty;
 mod iter_cloned_collect;
@@ -4461,6 +4462,28 @@ declare_clippy_lint! {
     "unnecessary `iter().any()` on slices that can be replaced with `contains()`"
 }
 
+declare_clippy_lint! {
+    /// This lint warns on calling `io::Error::new(..)` with a kind of
+    /// `io::ErrorKind::Other`.
+    ///
+    /// ### Why is this bad?
+    /// Since Rust 1.74, there's the `io::Error::other(_)` shortcut.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// use std::io;
+    /// let _ = io::Error::new(io::ErrorKind::Other, "bad".to_string());
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let _ = std::io::Error::other("bad".to_string());
+    /// ```
+    #[clippy::version = "1.86.0"]
+    pub IO_OTHER_ERROR,
+    style,
+    "calling `std::io::Error::new(std::io::ErrorKind::Other, _)`"
+}
+
 #[expect(clippy::struct_excessive_bools)]
 pub struct Methods {
     avoid_breaking_exported_api: bool,
@@ -4637,6 +4660,7 @@ impl_lint_pass!(Methods => [
     RETURN_AND_THEN,
     UNBUFFERED_BYTES,
     MANUAL_CONTAINS,
+    IO_OTHER_ERROR,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -4666,6 +4690,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                 unnecessary_fallible_conversions::check_function(cx, expr, func);
                 manual_c_str_literals::check(cx, expr, func, args, &self.msrv);
                 useless_nonzero_new_unchecked::check(cx, expr, func, args, &self.msrv);
+                io_other_error::check(cx, expr, func, args, &self.msrv);
             },
             ExprKind::MethodCall(method_call, receiver, args, _) => {
                 let method_span = method_call.ident.span;