Skip to content

Commit

Permalink
Fix FP on if_then_some_else_none when there is early return
Browse files Browse the repository at this point in the history
  • Loading branch information
dswij committed Nov 23, 2021
1 parent 57a8804 commit ec3d1c8
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 2 deletions.
13 changes: 11 additions & 2 deletions clippy_lints/src/if_then_some_else_none.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::snippet_with_macro_callsite;
use clippy_utils::{higher, is_else_clause, is_lang_ctor, meets_msrv, msrvs};
use clippy_utils::{contains_return, higher, is_else_clause, is_lang_ctor, meets_msrv, msrvs};
use if_chain::if_chain;
use rustc_hir::LangItem::{OptionNone, OptionSome};
use rustc_hir::{Expr, ExprKind};
use rustc_hir::{Expr, ExprKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_semver::RustcVersion;
Expand Down Expand Up @@ -82,6 +82,7 @@ impl LateLintPass<'_> for IfThenSomeElseNone {
if let Some(els_expr) = els_block.expr;
if let ExprKind::Path(ref qpath) = els_expr.kind;
if is_lang_ctor(cx, qpath, OptionNone);
if !stmts_contains_early_return(then_block.stmts);
then {
let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]");
let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) {
Expand Down Expand Up @@ -114,3 +115,11 @@ impl LateLintPass<'_> for IfThenSomeElseNone {

extract_msrv_attr!(LateContext);
}

fn stmts_contains_early_return(stmts: &[Stmt<'_>]) -> bool {
stmts.iter().any(|stmt| {
let Stmt { kind: StmtKind::Semi(e), .. } = stmt else { return false };

contains_return(e)
})
}
11 changes: 11 additions & 0 deletions tests/ui/if_then_some_else_none.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,14 @@ fn into_some<T>(v: T) -> Option<T> {
fn into_none<T>() -> Option<T> {
None
}

// Should not warn
fn f(b: bool, v: Option<()>) -> Option<()> {
if b {
v?; // This is a potential early return, is not equivalent with `bool::then`

Some(())
} else {
None
}
}

0 comments on commit ec3d1c8

Please sign in to comment.