//@aux-build:proc_macros.rs
//@aux-build:proc_macro_derive.rs
//@aux-build:macro_rules.rs
#![warn(clippy::double_parens)]
#![expect(clippy::eq_op, clippy::no_effect)]
#![feature(custom_inner_attributes)]
#![rustfmt::skip]

use proc_macros::{external, with_span};

fn dummy_fn<T>(_: T) {}

struct DummyStruct;

impl DummyStruct {
    fn dummy_method<T>(&self, _: T) {}
}

fn simple_double_parens() -> i32 {
    (0)
    //~^ double_parens
}

fn fn_double_parens() {
    dummy_fn(0);
    //~^ double_parens
}

fn method_double_parens(x: DummyStruct) {
    x.dummy_method(0);
    //~^ double_parens
}

fn tuple_double_parens() -> (i32, i32) {
    (1, 2)
    //~^ double_parens
}

#[allow(clippy::unused_unit)]
fn unit_double_parens() {
    ()
    //~^ double_parens
}

fn fn_tuple_ok() {
    dummy_fn((1, 2));
}

fn method_tuple_ok(x: DummyStruct) {
    x.dummy_method((1, 2));
}

fn fn_unit_ok() {
    dummy_fn(());
}

fn method_unit_ok(x: DummyStruct) {
    x.dummy_method(());
}

// Issue #3206
fn inside_macro() {
    assert_eq!((1, 2), (1, 2), "Error");
    assert_eq!((1, 2), (1, 2), "Error");
    //~^ double_parens
}

fn issue9000(x: DummyStruct) {
    macro_rules! foo {
        () => {(100)}
    }
    // don't lint: the inner paren comes from the macro expansion
    (foo!());
    dummy_fn(foo!());
    x.dummy_method(foo!());

    macro_rules! baz {
        ($n:literal) => {($n)}
    }
    // don't lint: don't get confused by the expression inside the inner paren
    // having the same `ctxt` as the overall expression
    // (this is a bug that happened during the development of the fix)
    (baz!(100));
    dummy_fn(baz!(100));
    x.dummy_method(baz!(100));

    // should lint: both parens are from inside the macro
    macro_rules! bar {
        () => {(100)}
        //~^ double_parens
    }
    bar!();

    // should lint: both parens are from outside the macro;
    // make sure to suggest the macro unexpanded
    (vec![1, 2]);
    //~^ double_parens
    dummy_fn(vec![1, 2]);
    //~^ double_parens
    x.dummy_method(vec![1, 2]);
    //~^ double_parens
}

fn issue15892() {
    use macro_rules::double_parens as double_parens_external;

    macro_rules! double_parens{
        ($a:expr, $b:expr, $c:expr, $d:expr) => {{
            let a = ($a);
            let a = ();
            //~^ double_parens
            let b = (5);
            //~^ double_parens
            let c = std::convert::identity(5);
            //~^ double_parens
            InterruptMask((($a.union($b).union($c).union($d)).into_bits()) as u32)
        }};
    }

    // Don't lint: external macro
    (external!((5)));
    external!(((5)));

    #[repr(transparent)]
    #[derive(Clone, Copy, PartialEq, Eq)]
    pub struct InterruptMask(u32);

    impl InterruptMask {
        pub const OE: InterruptMask = InterruptMask(1 << 10);
        pub const BE: InterruptMask = InterruptMask(1 << 9);
        pub const PE: InterruptMask = InterruptMask(1 << 8);
        pub const FE: InterruptMask = InterruptMask(1 << 7);
        // Lint: internal macro
        pub const E: InterruptMask = double_parens!((Self::OE), Self::BE, Self::PE, Self::FE);
        // Don't lint: external macro
        pub const F: InterruptMask = double_parens_external!((Self::OE), Self::BE, Self::PE, Self::FE);
        #[allow(clippy::unnecessary_cast)]
        pub const G: InterruptMask = external!(
            InterruptMask((((Self::OE.union(Self::BE).union(Self::PE).union(Self::FE))).into_bits()) as u32)
        );
        #[allow(clippy::unnecessary_cast)]
        // Don't lint: external proc-macro
        pub const H: InterruptMask = with_span!(span
            InterruptMask((((Self::OE.union(Self::BE).union(Self::PE).union(Self::FE))).into_bits()) as u32)
        );
        pub const fn into_bits(self) -> u32 {
            self.0
        }
        #[must_use]
        pub const fn union(self, rhs: Self) -> Self {
            InterruptMask(self.0 | rhs.0)
        }
    }
}

fn issue15940() {
    use proc_macro_derive::DoubleParens;

    #[derive(DoubleParens)]
    // Don't lint: external derive macro
    pub struct Person;
}

fn issue16224() {
    fn test() -> i32 { 42 }

    macro_rules! call {
        ($matcher:pat $(=> $result:expr)?) => {
            match test() {
                $matcher => Result::Ok(($($result),*)),
                _ => Result::Err("No match".to_string()),
            }
        };
    }

    let _: Result<(), String> = call!(_);
    let _: Result<i32, String> = call!(_ => 42);
}

fn main() {}
