#![warn(clippy::manual_rotate)]
#![allow(unused)]
fn main() {
    let (x_u8, x_u16, x_u32, x_u64) = (1u8, 1u16, 1u32, 1u64);
    let (x_i8, x_i16, x_i32, x_i64) = (1i8, 1i16, 1i32, 1i64);
    let a_u32 = 1u32;
    const N: u32 = 5;
    // True positives
    let y_u8 = x_u8.rotate_right(3);
    //~^ manual_rotate
    let y_u16 = x_u16.rotate_right(7);
    //~^ manual_rotate
    let y_u32 = x_u32.rotate_right(8);
    //~^ manual_rotate
    let y_u64 = x_u64.rotate_right(9);
    //~^ manual_rotate
    let y_i8 = x_i8.rotate_right(3);
    //~^ manual_rotate
    let y_i16 = x_i16.rotate_right(7);
    //~^ manual_rotate
    let y_i32 = x_i32.rotate_right(8);
    //~^ manual_rotate
    let y_i64 = x_i64.rotate_right(9);
    //~^ manual_rotate
    // Plus also works instead of |
    let y_u32_plus = x_u32.rotate_right(8);
    //~^ manual_rotate
    // Complex expression
    let y_u32_complex = (x_u32 | 3256).rotate_right(8);
    //~^ manual_rotate
    let y_u64_as = (x_u32 as u64).rotate_right(8);
    //~^ manual_rotate
    // shift by a const
    let _ = x_i64.rotate_right(N);
    //~^ manual_rotate

    // False positives - can't be replaced with a rotation
    let y_u8_false = (x_u8 >> 6) | (x_u8 << 3);
    let y_u32_false = (x_u32 >> 8) | (x_u32 >> 24);
    let y_u64_false2 = (x_u64 >> 9) & (x_u64 << 55);
    // Variable mismatch
    let y_u32_wrong_vars = (x_u32 >> 8) | (a_u32 << 24);
    // Has side effects and therefore should not be matched
    let mut l = vec![12_u8, 34];
    let y = (l.pop().unwrap() << 3) + (l.pop().unwrap() >> 5);
}

fn issue13028() {
    let s = 5;
    let u = 5;
    let x: u32 = 123456;

    let _ = x.rotate_left(s);
    //~^ manual_rotate
    let _ = x.rotate_left(s);
    //~^ manual_rotate
    // still works with consts
    let _ = x.rotate_right(9);
    //~^ manual_rotate

    // don't lint, because `s` and `u` are different variables, albeit with the same value
    let _ = (x << s) | (x >> (32 - u));
}

fn wrongly_unmangled_macros() {
    macro_rules! test_expr {
        ($val:expr) => {
            $val.inner
        };
    }

    struct Wrapper {
        inner: u32,
    }

    let x = Wrapper { inner: 42 };
    let _ = test_expr!(x).rotate_left(3);
    //~^ manual_rotate

    let y = Wrapper { inner: 100 };

    let _ = x.inner.rotate_left(test_expr!(y));
    //~^ manual_rotate

    let _ = (test_expr!(x) << 3) | (x.inner >> 29);
}
