diff options
| author | bors <bors@rust-lang.org> | 2024-08-06 19:01:41 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-08-06 19:01:41 +0000 |
| commit | 5ead90f13ae3e03f0c346aea3198f18298960d83 (patch) | |
| tree | 63dc560335f08e98dc7f32d2c5de71fc3c772a4a /clippy_lints/src | |
| parent | 9d9a0dcb64407cd68675470ea4e84f9022b389f3 (diff) | |
| parent | 182c26891e3c64931686e21758613f45a2f83463 (diff) | |
Auto merge of #12150 - ithinuel:add_misleading_use_of_ok, r=y21
Add lint for `unused_result_ok` This PR adds a lint to capture the use of `expr.ok();` when the result is not _really_ used. This could be interpreted as the result being checked (like it is with `unwrap()` or `expect`) but it actually only ignores the result. `let _ = expr;` expresses that intent better. This was also mentionned in #8994 (although not being the main topic of that issue). changelog: [`misleading_use_of_ok`]: Add new lint to capture `.ok();` when the result is not _really_ used.
Diffstat (limited to 'clippy_lints/src')
| -rw-r--r-- | clippy_lints/src/declared_lints.rs | 1 | ||||
| -rw-r--r-- | clippy_lints/src/lib.rs | 2 | ||||
| -rw-r--r-- | clippy_lints/src/unused_result_ok.rs | 59 |
3 files changed, 62 insertions, 0 deletions
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 69f7ca57554..3fb083dd833 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -739,6 +739,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::unused_async::UNUSED_ASYNC_INFO, crate::unused_io_amount::UNUSED_IO_AMOUNT_INFO, crate::unused_peekable::UNUSED_PEEKABLE_INFO, + crate::unused_result_ok::UNUSED_RESULT_OK_INFO, crate::unused_rounding::UNUSED_ROUNDING_INFO, crate::unused_self::UNUSED_SELF_INFO, crate::unused_unit::UNUSED_UNIT_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a0d77a58ad1..374fcd29783 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -370,6 +370,7 @@ mod unsafe_removed_from_name; mod unused_async; mod unused_io_amount; mod unused_peekable; +mod unused_result_ok; mod unused_rounding; mod unused_self; mod unused_unit; @@ -671,6 +672,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(missing_doc::MissingDoc::new(conf))); store.register_late_pass(|_| Box::new(missing_inline::MissingInline)); store.register_late_pass(move |_| Box::new(exhaustive_items::ExhaustiveItems)); + store.register_late_pass(|_| Box::new(unused_result_ok::UnusedResultOk)); store.register_late_pass(|_| Box::new(match_result_ok::MatchResultOk)); store.register_late_pass(|_| Box::new(partialeq_ne_impl::PartialEqNeImpl)); store.register_late_pass(|_| Box::new(unused_io_amount::UnusedIoAmount)); diff --git a/clippy_lints/src/unused_result_ok.rs b/clippy_lints/src/unused_result_ok.rs new file mode 100644 index 00000000000..297288db0a5 --- /dev/null +++ b/clippy_lints/src/unused_result_ok.rs @@ -0,0 +1,59 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_context; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_errors::Applicability; +use rustc_hir::{ExprKind, Stmt, StmtKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_session::declare_lint_pass; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Checks for calls to `Result::ok()` without using the returned `Option`. + /// + /// ### Why is this bad? + /// Using `Result::ok()` may look like the result is checked like `unwrap` or `expect` would do + /// but it only silences the warning caused by `#[must_use]` on the `Result`. + /// + /// ### Example + /// ```no_run + /// # fn some_function() -> Result<(), ()> { Ok(()) } + /// some_function().ok(); + /// ``` + /// Use instead: + /// ```no_run + /// # fn some_function() -> Result<(), ()> { Ok(()) } + /// let _ = some_function(); + /// ``` + #[clippy::version = "1.70.0"] + pub UNUSED_RESULT_OK, + restriction, + "Use of `.ok()` to silence `Result`'s `#[must_use]` is misleading. Use `let _ =` instead." +} +declare_lint_pass!(UnusedResultOk => [UNUSED_RESULT_OK]); + +impl LateLintPass<'_> for UnusedResultOk { + fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) { + if let StmtKind::Semi(expr) = stmt.kind + && let ExprKind::MethodCall(ok_path, recv, [], ..) = expr.kind //check is expr.ok() has type Result<T,E>.ok(, _) + && ok_path.ident.as_str() == "ok" + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result) + && !in_external_macro(cx.sess(), stmt.span) + { + let ctxt = expr.span.ctxt(); + let mut applicability = Applicability::MaybeIncorrect; + let snippet = snippet_with_context(cx, recv.span, ctxt, "", &mut applicability).0; + let sugg = format!("let _ = {snippet}"); + span_lint_and_sugg( + cx, + UNUSED_RESULT_OK, + expr.span, + "ignoring a result with `.ok()` is misleading", + "consider using `let _ =` and removing the call to `.ok()` instead", + sugg, + applicability, + ); + } + } +} |
