// Source: https://github.com/rust-lang/rust-clippy/blob/c4b8c6d454c648ef2d7cb86ca1bc698da829e4bc/tests/ui/if_same_then_else.rs
// License: MIT OR Apache-2.0
// Note: verbatim copy of the rust-clippy UI test for the `clippy::if_same_then_else` lint pinned at master commit c4b8c6d454c648ef2d7cb86ca1bc698da829e4bc. Upstream line 25 (`if true {` inside `fn if_same_then_else`) is the first lint trigger per the matching .stderr; audit-corpus line 29 = upstream 25 + 4 (3-line header + 1 blank). FN against cntrdct clone-drift by docs/spec/clone-drift-v0.md F2 — cntrdct clone-drift v0 operates at top-level `fn` granularity only, so statement-block if/else clones (clippy's bug class) are out of scope by design. The file-level `#![allow(... unreachable_code ...)]` is preserved verbatim; cntrdct unreachable-after-terminator's SUPPRESSION_TOKEN scan therefore correctly skips this file, which is irrelevant here because the entry is labelled clone-drift.

#![warn(clippy::if_same_then_else)]
#![allow(
    clippy::disallowed_names,
    clippy::eq_op,
    clippy::never_loop,
    clippy::no_effect,
    clippy::unused_unit,
    clippy::zero_divided_by_zero,
    clippy::branches_sharing_code,
    dead_code,
    unreachable_code
)]

use std::ops::*;

struct Foo {
    bar: u8,
}

fn foo() -> bool {
    unimplemented!()
}

fn if_same_then_else() {
    if true {
        Foo { bar: 42 };
        0..10;
        ..;
        0..;
        ..10;
        0..=10;
        foo();
    } else {
        Foo { bar: 42 };
        0..10;
        ..;
        0..;
        ..10;
        0..=10;
        foo();
    }
    //~^^^^^^^^^^^^^^^^^ if_same_then_else

    if true {
        Foo { bar: 42 };
    } else {
        Foo { bar: 43 };
    }

    if true {
        ();
    } else {
        ()
    }

    if true {
        0..10;
    } else {
        0..=10;
    }

    if true {
        foo();
        foo();
    } else {
        foo();
    }

    let _ = if true { 0.0 } else { 0.0 };
    //~^ if_same_then_else

    let _ = if true { -0.0 } else { -0.0 };
    //~^ if_same_then_else

    let _ = if true { 0.0 } else { -0.0 };

    // Different NaNs
    let _ = if true { 0.0 / 0.0 } else { f32::NAN };

    if true {
        foo();
    }

    let _ = if true { 42 } else { 42 };
    //~^ if_same_then_else

    if true {
        let bar = if true { 42 } else { 43 };

        while foo() {
            break;
        }
        bar + 1;
    } else {
        let bar = if true { 42 } else { 43 };

        while foo() {
            break;
        }
        bar + 1;
    }
    //~^^^^^^^^^^^^^^^ if_same_then_else

    if true {
        let _ = match 42 {
            42 => 1,
            a if a > 0 => 2,
            10..=15 => 3,
            _ => 4,
        };
    } else if false {
        foo();
    } else if foo() {
        let _ = match 42 {
            42 => 1,
            a if a > 0 => 2,
            10..=15 => 3,
            _ => 4,
        };
    }
}

// Issue #2423. This was causing an ICE.
fn func() {
    if true {
        f(&[0; 62]);
        f(&[0; 4]);
        f(&[0; 3]);
    } else {
        f(&[0; 62]);
        f(&[0; 6]);
        f(&[0; 6]);
    }
}

fn f(val: &[u8]) {}

mod issue_8836 {
    fn do_not_lint() {
        if true {
            todo!()
        } else {
            todo!()
        }
        if true {
            todo!();
        } else {
            todo!();
        }
        if true {
            unimplemented!()
        } else {
            unimplemented!()
        }
        if true {
            unimplemented!();
        } else {
            unimplemented!();
        }

        if true {
            println!("FOO");
            todo!();
        } else {
            println!("FOO");
            todo!();
        }

        if true {
            println!("FOO");
            unimplemented!();
        } else {
            println!("FOO");
            unimplemented!();
        }

        if true {
            println!("FOO");
            todo!()
        } else {
            println!("FOO");
            todo!()
        }

        if true {
            println!("FOO");
            unimplemented!()
        } else {
            println!("FOO");
            unimplemented!()
        }
    }
}

mod issue_11213 {
    fn reproducer(x: bool) -> bool {
        if x {
            0_u8.is_power_of_two()
        } else {
            0_u16.is_power_of_two()
        }
    }

    // a more obvious reproducer that shows
    // why the code above is problematic:
    fn v2(x: bool) -> bool {
        trait Helper {
            fn is_u8(&self) -> bool;
        }
        impl Helper for u8 {
            fn is_u8(&self) -> bool {
                true
            }
        }
        impl Helper for u16 {
            fn is_u8(&self) -> bool {
                false
            }
        }

        // this is certainly not the same code in both branches
        // it returns a different bool depending on the branch.
        if x { 0_u8.is_u8() } else { 0_u16.is_u8() }
    }

    fn do_lint(x: bool) -> bool {
        // but do lint if the type of the literal is the same
        if x {
            0_u8.is_power_of_two()
        } else {
            0_u8.is_power_of_two()
        }
        //~^^^^^ if_same_then_else
    }
}

fn main() {}

fn issue16416<T>(x: bool, a: T, b: T)
where
    T: Add + Sub + Mul + Div + Rem + BitAnd + BitOr + BitXor + PartialEq + Eq + PartialOrd + Ord + Shr + Shl + Copy,
{
    // Non-guaranteed-commutative operators
    _ = if x { a * b } else { b * a };
    _ = if x { a + b } else { b + a };
    _ = if x { a - b } else { b - a };
    _ = if x { a / b } else { b / a };
    _ = if x { a % b } else { b % a };
    _ = if x { a << b } else { b << a };
    _ = if x { a >> b } else { b >> a };
    _ = if x { a & b } else { b & a };
    _ = if x { a ^ b } else { b ^ a };
    _ = if x { a | b } else { b | a };

    // Guaranteed commutative operators
    //~v if_same_then_else
    _ = if x { a == b } else { b == a };
    //~v if_same_then_else
    _ = if x { a != b } else { b != a };

    // Symetric operators
    //~v if_same_then_else
    _ = if x { a < b } else { b > a };
    //~v if_same_then_else
    _ = if x { a <= b } else { b >= a };
    //~v if_same_then_else
    _ = if x { a > b } else { b < a };
    //~v if_same_then_else
    _ = if x { a >= b } else { b <= a };
}

fn issue16416_prim(x: bool, a: u32, b: u32) {
    // Non-commutative operators
    _ = if x { a - b } else { b - a };
    _ = if x { a / b } else { b / a };
    _ = if x { a % b } else { b % a };
    _ = if x { a << b } else { b << a };
    _ = if x { a >> b } else { b >> a };

    // Commutative operators on primitive types
    //~v if_same_then_else
    _ = if x { a * b } else { b * a };
    //~v if_same_then_else
    _ = if x { a + b } else { b + a };
    //~v if_same_then_else
    _ = if x { a & b } else { b & a };
    //~v if_same_then_else
    _ = if x { a ^ b } else { b ^ a };
    //~v if_same_then_else
    _ = if x { a | b } else { b | a };

    // Always commutative operators
    //~v if_same_then_else
    _ = if x { a == b } else { b == a };
    //~v if_same_then_else
    _ = if x { a != b } else { b != a };

    // Symetric operators
    //~v if_same_then_else
    _ = if x { a < b } else { b > a };
    //~v if_same_then_else
    _ = if x { a <= b } else { b >= a };
    //~v if_same_then_else
    _ = if x { a > b } else { b < a };
    //~v if_same_then_else
    _ = if x { a >= b } else { b <= a };
}

mod issue16505 {
    macro_rules! foo {
        (< $hi:literal : $lo:literal > | $N:tt bits) => {{
            const NEW_N_: usize = $hi - $lo + 1;
            NEW_N_
        }};
    }

    fn bar(x: bool) {
        _ = if x {
            foo!(<2:0> | 3 bits) == foo!(<3:1> | 3 bits)
        } else {
            foo!(<3:1> | 3 bits) == foo!(<2:0> | 3 bits)
        };
    }
}
