#![allow(
    clippy::missing_safety_doc,
    clippy::extra_unused_lifetimes,
    clippy::extra_unused_type_parameters,
    clippy::needless_lifetimes
)]
#![warn(clippy::new_without_default)]

pub struct Foo;

impl Default for Foo {
    fn default() -> Self {
        Self::new()
    }
}

impl Foo {
    pub fn new() -> Foo {
        //~^ new_without_default

        Foo
    }
}

pub struct Bar;

impl Default for Bar {
    fn default() -> Self {
        Self::new()
    }
}

impl Bar {
    pub fn new() -> Self {
        //~^ new_without_default

        Bar
    }
}

pub struct Ok;

impl Ok {
    pub fn new() -> Self {
        Ok
    }
}

impl Default for Ok {
    fn default() -> Self {
        Ok
    }
}

pub struct Params;

impl Params {
    pub fn new(_: u32) -> Self {
        Params
    }
}

pub struct GenericsOk<T> {
    bar: T,
}

impl<U> Default for GenericsOk<U> {
    fn default() -> Self {
        unimplemented!();
    }
}

impl<'c, V> GenericsOk<V> {
    pub fn new() -> GenericsOk<V> {
        unimplemented!()
    }
}

pub struct LtOk<'a> {
    foo: &'a bool,
}

impl<'b> Default for LtOk<'b> {
    fn default() -> Self {
        unimplemented!();
    }
}

impl<'c> LtOk<'c> {
    pub fn new() -> LtOk<'c> {
        unimplemented!()
    }
}

pub struct LtKo<'a> {
    foo: &'a bool,
}

impl<'c> Default for LtKo<'c> {
    fn default() -> Self {
        Self::new()
    }
}

impl<'c> LtKo<'c> {
    pub fn new() -> LtKo<'c> {
        //~^ new_without_default

        unimplemented!()
    }
}

struct Private;

impl Private {
    fn new() -> Private {
        unimplemented!()
    } // We don't lint private items
}

struct PrivateStruct;

impl PrivateStruct {
    pub fn new() -> PrivateStruct {
        unimplemented!()
    } // We don't lint public items on private structs
}

pub struct PrivateItem;

impl PrivateItem {
    fn new() -> PrivateItem {
        unimplemented!()
    } // We don't lint private items on public structs
}

pub struct Const;

impl Default for Const {
    fn default() -> Self {
        Self::new()
    }
}

impl Const {
    pub const fn new() -> Const {
        //~^ new_without_default
        Const
    } // While Default is not const, it can still call const functions, so we should lint this
}

pub struct IgnoreGenericNew;

impl IgnoreGenericNew {
    pub fn new<T>() -> Self {
        IgnoreGenericNew
    } // the derived Default does not make sense here as the result depends on T
}

pub trait TraitWithNew: Sized {
    fn new() -> Self {
        panic!()
    }
}

pub struct IgnoreUnsafeNew;

impl IgnoreUnsafeNew {
    pub unsafe fn new() -> Self {
        IgnoreUnsafeNew
    }
}

#[derive(Default)]
pub struct OptionRefWrapper<'a, T>(Option<&'a T>);

impl<'a, T> OptionRefWrapper<'a, T> {
    pub fn new() -> Self {
        OptionRefWrapper(None)
    }
}

pub struct Allow(Foo);

impl Allow {
    #[allow(clippy::new_without_default)]
    pub fn new() -> Self {
        unimplemented!()
    }
}

pub struct AllowDerive;

impl AllowDerive {
    #[allow(clippy::new_without_default)]
    pub fn new() -> Self {
        unimplemented!()
    }
}

pub struct NewNotEqualToDerive {
    foo: i32,
}

impl Default for NewNotEqualToDerive {
    fn default() -> Self {
        Self::new()
    }
}

impl NewNotEqualToDerive {
    // This `new` implementation is not equal to a derived `Default`, so do not suggest deriving.
    pub fn new() -> Self {
        //~^ new_without_default

        NewNotEqualToDerive { foo: 1 }
    }
}

// see #6933
pub struct FooGenerics<T>(std::marker::PhantomData<T>);
impl<T> Default for FooGenerics<T> {
    fn default() -> Self {
        Self::new()
    }
}

impl<T> FooGenerics<T> {
    pub fn new() -> Self {
        //~^ new_without_default

        Self(Default::default())
    }
}

pub struct BarGenerics<T>(std::marker::PhantomData<T>);
impl<T: Copy> Default for BarGenerics<T> {
    fn default() -> Self {
        Self::new()
    }
}

impl<T: Copy> BarGenerics<T> {
    pub fn new() -> Self {
        //~^ new_without_default

        Self(Default::default())
    }
}

pub mod issue7220 {
    pub struct Foo<T> {
        _bar: *mut T,
    }

    impl<T> Default for Foo<T> {
        fn default() -> Self {
            Self::new()
        }
    }

    impl<T> Foo<T> {
        pub fn new() -> Self {
            //~^ new_without_default

            todo!()
        }
    }
}

// see issue #8152
// This should not create any lints
pub struct DocHidden;
impl DocHidden {
    #[doc(hidden)]
    pub fn new() -> Self {
        DocHidden
    }
}

fn main() {}

pub struct IgnoreConstGenericNew(usize);
impl IgnoreConstGenericNew {
    pub fn new<const N: usize>() -> Self {
        Self(N)
    }
}

pub struct IgnoreLifetimeNew;
impl IgnoreLifetimeNew {
    pub fn new<'a>() -> Self {
        Self
    }
}

// From issue #11267

pub struct MyStruct<K, V>
where
    K: std::hash::Hash + Eq + PartialEq,
{
    _kv: Option<(K, V)>,
}

impl<K, V> Default for MyStruct<K, V>
where
    K: std::hash::Hash + Eq + PartialEq,
 {
    fn default() -> Self {
        Self::new()
    }
}

impl<K, V> MyStruct<K, V>
where
    K: std::hash::Hash + Eq + PartialEq,
{
    pub fn new() -> Self {
        //~^ new_without_default
        Self { _kv: None }
    }
}

// From issue #14552, but with `#[cfg]`s that are actually `true` in the uitest context

pub struct NewWithCfg;
#[cfg(not(test))]
impl Default for NewWithCfg {
    fn default() -> Self {
        Self::new()
    }
}

impl NewWithCfg {
    #[cfg(not(test))]
    pub fn new() -> Self {
        //~^ new_without_default
        unimplemented!()
    }
}

pub struct NewWith2Cfgs;
#[cfg(not(test))]
#[cfg(panic = "unwind")]
impl Default for NewWith2Cfgs {
    fn default() -> Self {
        Self::new()
    }
}

impl NewWith2Cfgs {
    #[cfg(not(test))]
    #[cfg(panic = "unwind")]
    pub fn new() -> Self {
        //~^ new_without_default
        unimplemented!()
    }
}

pub struct NewWithExtraneous;
impl Default for NewWithExtraneous {
    fn default() -> Self {
        Self::new()
    }
}

impl NewWithExtraneous {
    #[inline]
    pub fn new() -> Self {
        //~^ new_without_default
        unimplemented!()
    }
}

pub struct NewWithCfgAndExtraneous;
#[cfg(not(test))]
impl Default for NewWithCfgAndExtraneous {
    fn default() -> Self {
        Self::new()
    }
}

impl NewWithCfgAndExtraneous {
    #[cfg(not(test))]
    #[inline]
    pub fn new() -> Self {
        //~^ new_without_default
        unimplemented!()
    }
}

mod issue15778 {
    pub struct Foo(Vec<i32>);

    impl Foo {
        pub fn new() -> Self {
            Self(Vec::new())
        }
    }

    impl<'a> IntoIterator for &'a Foo {
        type Item = &'a i32;

        type IntoIter = std::slice::Iter<'a, i32>;

        fn into_iter(self) -> Self::IntoIter {
            self.0.as_slice().iter()
        }
    }
}

pub mod issue16255 {
    use std::fmt::Display;
    use std::marker::PhantomData;

    pub struct Foo<T> {
        marker: PhantomData<T>,
    }

    impl<T> Default for Foo<T>
    where
        T: Display,
        T: Clone,
     {
        fn default() -> Self {
            Self::new()
        }
    }

    impl<T> Foo<T>
    where
        T: Display,
    {
        pub fn new() -> Self
        //~^ new_without_default
        where
            T: Clone,
        {
            Self { marker: PhantomData }
        }
    }

    pub struct Bar<T> {
        marker: PhantomData<T>,
    }

    impl<T> Default for Bar<T>
    where
        T: Clone,
     {
        fn default() -> Self {
            Self::new()
        }
    }

    impl<T> Bar<T> {
        pub fn new() -> Self
        //~^ new_without_default
        where
            T: Clone,
        {
            Self { marker: PhantomData }
        }
    }
}
