summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs')
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs68
1 files changed, 68 insertions, 0 deletions
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs
new file mode 100644
index 000000000..be5768c35
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs
@@ -0,0 +1,68 @@
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{diagnostics::span_lint_and_sugg, is_lang_ctor};
+use rustc_errors::Applicability;
+use rustc_hir::{lang_items::LangItem, Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::{sym, Span};
+
+use super::OR_THEN_UNWRAP;
+
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ unwrap_expr: &Expr<'_>,
+ recv: &'tcx Expr<'tcx>,
+ or_arg: &'tcx Expr<'_>,
+ or_span: Span,
+) {
+ let ty = cx.typeck_results().expr_ty(recv); // get type of x (we later check if it's Option or Result)
+ let title;
+ let or_arg_content: Span;
+
+ if is_type_diagnostic_item(cx, ty, sym::Option) {
+ title = "found `.or(Some(…)).unwrap()`";
+ if let Some(content) = get_content_if_ctor_matches(cx, or_arg, LangItem::OptionSome) {
+ or_arg_content = content;
+ } else {
+ return;
+ }
+ } else if is_type_diagnostic_item(cx, ty, sym::Result) {
+ title = "found `.or(Ok(…)).unwrap()`";
+ if let Some(content) = get_content_if_ctor_matches(cx, or_arg, LangItem::ResultOk) {
+ or_arg_content = content;
+ } else {
+ return;
+ }
+ } else {
+ // Someone has implemented a struct with .or(...).unwrap() chaining,
+ // but it's not an Option or a Result, so bail
+ return;
+ }
+
+ let mut applicability = Applicability::MachineApplicable;
+ let suggestion = format!(
+ "unwrap_or({})",
+ snippet_with_applicability(cx, or_arg_content, "..", &mut applicability)
+ );
+
+ span_lint_and_sugg(
+ cx,
+ OR_THEN_UNWRAP,
+ unwrap_expr.span.with_lo(or_span.lo()),
+ title,
+ "try this",
+ suggestion,
+ applicability,
+ );
+}
+
+fn get_content_if_ctor_matches(cx: &LateContext<'_>, expr: &Expr<'_>, item: LangItem) -> Option<Span> {
+ if let ExprKind::Call(some_expr, [arg]) = expr.kind
+ && let ExprKind::Path(qpath) = &some_expr.kind
+ && is_lang_ctor(cx, qpath, item)
+ {
+ Some(arg.span)
+ } else {
+ None
+ }
+}