//@aux-build:proc_macros.rs
#![allow(
    clippy::needless_return,
    clippy::no_effect,
    clippy::unit_arg,
    clippy::useless_conversion,
    clippy::diverging_sub_expression,
    clippy::let_unit_value,
    unused
)]

#[macro_use]
extern crate proc_macros;

fn a() -> u32 {
    return 0;
}

fn b() -> Result<u32, u32> {
    return Err(0);
}

// Do not lint
fn c() -> Option<()> {
    return None?;
}

fn main() -> Result<(), ()> {
    Err(())?;
    //~^ needless_return_with_question_mark
    return Ok::<(), ()>(());
    Err(())?;
    Ok::<(), ()>(());
    return Err(().into());
    external! {
        return Err(())?;
    }
    with_span! {
        return Err(())?;
    }

    // Issue #11765
    // Should not lint
    let Some(s) = Some("") else {
        return Err(())?;
    };

    let Some(s) = Some("") else {
        let Some(s) = Some("") else {
            return Err(())?;
        };

        return Err(())?;
    };

    let Some(_): Option<()> = ({
        return Err(())?;
    }) else {
        panic!();
    };

    Err(())
}

fn issue11616() -> Result<(), ()> {
    let _x: String = {
        return Err(())?;
    };
    let _x: () = {
        Err(())?;
        //~^ ERROR: unneeded `return` statement with `?` operator
    };
    let _x = match 1 {
        1 => vec![1, 2],
        _ => {
            return Err(())?;
        },
    };
    Ok(())
}

fn issue11982() {
    mod bar {
        pub struct Error;
        pub fn foo(_: bool) -> Result<(), Error> {
            Ok(())
        }
    }

    pub struct Error;

    impl From<bar::Error> for Error {
        fn from(_: bar::Error) -> Self {
            Error
        }
    }

    fn foo(ok: bool) -> Result<(), Error> {
        if !ok {
            return bar::foo(ok).map(|_| Ok::<(), Error>(()))?;
        };
        Ok(())
    }
}

fn issue11982_no_conversion() {
    mod bar {
        pub struct Error;
        pub fn foo(_: bool) -> Result<(), Error> {
            Ok(())
        }
    }

    fn foo(ok: bool) -> Result<(), bar::Error> {
        if !ok {
            return bar::foo(ok).map(|_| Ok::<(), bar::Error>(()))?;
        };
        Ok(())
    }
}

fn general_return() {
    fn foo(ok: bool) -> Result<(), ()> {
        let bar = Result::Ok(Result::<(), ()>::Ok(()));
        if !ok {
            return bar?;
        };
        Ok(())
    }
}

async fn async_fn() -> Result<(), ()> {
    if true {
        Err(())?;
        //~^ needless_return_with_question_mark
    }
    Ok(())
}

async fn async_block() -> Result<(), ()> {
    async {
        if true {
            Err(())?;
            //~^ needless_return_with_question_mark
        }
        Ok(())
    }
    .await
}

async fn async_block_final_stmt() -> Result<(), ()> {
    async {
        return Err(())?;
    }
    .await
}
