+ "replace it with",
+ replacement_str,
+ applicability,
+ );
+ }
+ }
+ }
+ }
+
+ fn check_if_let_some_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>) {
+ if_chain! {
+ if let ExprKind::Match(subject, arms, source) = &expr.kind;
+ if *source == MatchSource::IfLetDesugar { contains_else_clause: true };
+ if Self::is_option(cx, subject);
+
+ if let PatKind::TupleStruct(path1, fields, None) = &arms[0].pat.kind;
+ if is_lang_ctor(cx, path1, OptionSome);
+ if let PatKind::Binding(annot, bind_id, _, _) = fields[0].kind;
+ let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut);
+
+ if let ExprKind::Block(block, None) = &arms[0].body.kind;
+ if block.stmts.is_empty();
+ if let Some(trailing_expr) = &block.expr;
+ if path_to_local_id(trailing_expr, bind_id);
+
+ if let PatKind::Wild = arms[1].pat.kind;
+ if Self::expression_returns_none(cx, arms[1].body);
+ then {
+ let mut applicability = Applicability::MachineApplicable;
+ let receiver_str = snippet_with_applicability(cx, subject.span, "..", &mut applicability);
+ let replacement = format!(
+ "{}{}?",
+ receiver_str,
+ if by_ref { ".as_ref()" } else { "" },
+ );
+
+ span_lint_and_sugg(
+ cx,
+ QUESTION_MARK,
+ expr.span,
+ "this if-let-else may be rewritten with the `?` operator",
+ "replace it with",
+ replacement,
+ applicability,
+ );